mirror of
https://github.com/Unidata/netcdf-c.git
synced 2025-02-23 16:59:54 +08:00
Merge branch 'master' into deflate.dmh
This commit is contained in:
commit
0b6f5c7a27
@ -834,7 +834,7 @@ IF(USE_HDF5)
|
||||
#option to include HDF5 High Level header file (hdf5_hl.h) in case we are not doing a make install
|
||||
INCLUDE_DIRECTORIES(${HDF5_HL_INCLUDE_DIR})
|
||||
|
||||
# Check to see if we have libcurl 7.66 or later
|
||||
# Check HDF5 version
|
||||
CHECK_C_SOURCE_COMPILES("
|
||||
#include <H5public.h>
|
||||
int main() {
|
||||
@ -942,6 +942,17 @@ OPTION(ENABLE_DAP_LONG_TESTS "Enable DAP long tests." OFF)
|
||||
OPTION(ENABLE_DAP_REMOTE_TESTS "Enable DAP remote tests." ON)
|
||||
SET(REMOTETESTSERVERS "remotetest.unidata.ucar.edu" CACHE STRING "test servers to use for remote test")
|
||||
|
||||
# See if we have libzip
|
||||
FIND_PACKAGE(Zip)
|
||||
|
||||
# Define a test flag for have curl library
|
||||
IF(Zip_FOUND)
|
||||
INCLUDE_DIRECTORIES(${Zip_INCLUDE_DIRS})
|
||||
SET(ENABLE_NCZARR_ZIP TRUE)
|
||||
ELSE()
|
||||
SET(ENABLE_NCZARR_ZIP FALSE)
|
||||
ENDIF()
|
||||
|
||||
# Enable some developer-only tests
|
||||
OPTION(ENABLE_EXTRA_TESTS "Enable Extra tests. Some may not work because of known issues. Developers only." OFF)
|
||||
IF(ENABLE_EXTRA_TESTS)
|
||||
@ -1017,6 +1028,10 @@ IF(NOT ENABLE_S3_SDK)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF(ENABLE_NCZARR_S3_TESTS)
|
||||
message(WARNING "**** DO NOT ENABLE_NCZARR_S3_TESTS UNLESS YOU HAVE ACCESS TO THE UNIDATA S3 BUCKET! ***")
|
||||
ENDIF()
|
||||
|
||||
# Start disabling if curl not found
|
||||
IF(NOT FOUND_CURL)
|
||||
IF(ENABLE_BYTERANGE)
|
||||
@ -1036,6 +1051,11 @@ IF(NOT FOUND_CURL)
|
||||
ENDIF()
|
||||
ENDIF(NOT FOUND_CURL)
|
||||
|
||||
IF(NOT ENABLE_BYTERANGE AND ENABLE_HDF5_ROS3)
|
||||
MESSAGE(WARNING "ROS3 support requires ENABLE_BYTERANGE=TRUE; disabling ROS3 support")
|
||||
SET(ENABLE_HDF5_ROS3 OFF CACHE BOOL "ROS3 support" FORCE)
|
||||
ENDIF()
|
||||
|
||||
##
|
||||
# Enable Tests
|
||||
##
|
||||
@ -2145,8 +2165,9 @@ is_enabled(ENABLE_ERANGE_FILL HAS_ERANGE_FILL)
|
||||
is_enabled(HAVE_H5Z_SZIP HAS_SZLIB)
|
||||
is_enabled(HDF5_HAS_PAR_FILTERS HAS_PAR_FILTERS)
|
||||
is_enabled(ENABLE_NCZARR HAS_NCZARR)
|
||||
is_enabled(ENABLE_NCZARR_S3_TESTS DO_S3_TESTS)
|
||||
is_enabled(ENABLE_NCZARR_S3_TESTS DO_NCZARR_S3_TESTS)
|
||||
is_enabled(ENABLE_MULTIFILTERS HAS_MULTIFILTERS)
|
||||
is_enabled(ENABLE_NCZARR_ZIP DO_NCZARR_ZIP_TESTS)
|
||||
|
||||
# Generate file from template.
|
||||
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/libnetcdf.settings.in"
|
||||
|
@ -8,6 +8,7 @@ This file contains a high-level description of this package's evolution. Release
|
||||
## 4.8.0 - TBD
|
||||
|
||||
* [Bug Fixes] The nccopy program was treating -d0 as turning deflation on rather than interpreting it as "turn off deflation". See [Github #1944](https://github.com/Unidata/netcdf-c/pull/1944) for more information.
|
||||
* [Enhancement] Add support for storing NCZarr data in zip files. See [Github #1942](https://github.com/Unidata/netcdf-c/pull/1942) for more information.
|
||||
* [Bug Fixes] Make fillmismatch the default for DAP2 and DAP4; too many servers ignore this requirement.
|
||||
* [Bug Fixes] Fix some memory leaks in NCZarr, fix a bug with long strides in NCZarr. See [Github #1913](https://github.com/Unidata/netcdf-c/pull/1913) for more information.
|
||||
* [Enhancement] Add some optimizations to NCZarr, dosome cleanup of code cruft, add some NCZarr test cases, add a performance test to NCZarr. See [Github #1908](https://github.com/Unidata/netcdf-c/pull/1908) for more information.
|
||||
|
64
cmake/modules/FindZip.cmake
Executable file
64
cmake/modules/FindZip.cmake
Executable file
@ -0,0 +1,64 @@
|
||||
# Searches for an installation of the zip library. On success, it sets the following variables:
|
||||
#
|
||||
# Zip_FOUND Set to true to indicate the zip library was found
|
||||
# Zip_INCLUDE_DIRS The directory containing the header file zip/zip.h
|
||||
# Zip_LIBRARIES The libraries needed to use the zip library
|
||||
#
|
||||
# To specify an additional directory to search, set Zip_ROOT.
|
||||
#
|
||||
# Author: Siddhartha Chaudhuri, 2009
|
||||
#
|
||||
|
||||
# Look for the header, first in the user-specified location and then in the system locations
|
||||
SET(Zip_INCLUDE_DOC "The directory containing the header file zip/zip.h")
|
||||
FIND_PATH(Zip_INCLUDE_DIRS NAMES zip.h zip/zip.h PATHS ${Zip_ROOT} ${Zip_ROOT}/include DOC ${Zip_INCLUDE_DOC} NO_DEFAULT_PATH)
|
||||
IF(NOT Zip_INCLUDE_DIRS) # now look in system locations
|
||||
FIND_PATH(Zip_INCLUDE_DIRS NAMES zip.h zip/zip.h DOC ${Zip_INCLUDE_DOC})
|
||||
ENDIF(NOT Zip_INCLUDE_DIRS)
|
||||
|
||||
SET(Zip_FOUND FALSE)
|
||||
|
||||
IF(Zip_INCLUDE_DIRS)
|
||||
SET(Zip_LIBRARY_DIRS ${Zip_INCLUDE_DIRS})
|
||||
|
||||
IF("${Zip_LIBRARY_DIRS}" MATCHES "/include$")
|
||||
# Strip off the trailing "/include" in the path.
|
||||
GET_FILENAME_COMPONENT(Zip_LIBRARY_DIRS ${Zip_LIBRARY_DIRS} PATH)
|
||||
ENDIF("${Zip_LIBRARY_DIRS}" MATCHES "/include$")
|
||||
|
||||
IF(EXISTS "${Zip_LIBRARY_DIRS}/lib")
|
||||
SET(Zip_LIBRARY_DIRS ${Zip_LIBRARY_DIRS}/lib)
|
||||
ENDIF(EXISTS "${Zip_LIBRARY_DIRS}/lib")
|
||||
|
||||
# Find Zip libraries
|
||||
FIND_LIBRARY(Zip_DEBUG_LIBRARY NAMES zipd zip_d libzipd libzip_d libzip
|
||||
PATH_SUFFIXES Debug ${CMAKE_LIBRARY_ARCHITECTURE} ${CMAKE_LIBRARY_ARCHITECTURE}/Debug
|
||||
PATHS ${Zip_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
FIND_LIBRARY(Zip_RELEASE_LIBRARY NAMES zip libzip
|
||||
PATH_SUFFIXES Release ${CMAKE_LIBRARY_ARCHITECTURE} ${CMAKE_LIBRARY_ARCHITECTURE}/Release
|
||||
PATHS ${Zip_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
|
||||
SET(Zip_LIBRARIES )
|
||||
IF(Zip_DEBUG_LIBRARY AND Zip_RELEASE_LIBRARY)
|
||||
SET(Zip_LIBRARIES debug ${Zip_DEBUG_LIBRARY} optimized ${Zip_RELEASE_LIBRARY})
|
||||
ELSEIF(Zip_DEBUG_LIBRARY)
|
||||
SET(Zip_LIBRARIES ${Zip_DEBUG_LIBRARY})
|
||||
ELSEIF(Zip_RELEASE_LIBRARY)
|
||||
SET(Zip_LIBRARIES ${Zip_RELEASE_LIBRARY})
|
||||
ENDIF(Zip_DEBUG_LIBRARY AND Zip_RELEASE_LIBRARY)
|
||||
|
||||
IF(Zip_LIBRARIES)
|
||||
SET(Zip_FOUND TRUE)
|
||||
ENDIF(Zip_LIBRARIES)
|
||||
ENDIF(Zip_INCLUDE_DIRS)
|
||||
|
||||
IF(Zip_FOUND)
|
||||
# IF(NOT Zip_FIND_QUIETLY)
|
||||
MESSAGE(STATUS "Found Zip: headers at ${Zip_INCLUDE_DIRS}, libraries at ${Zip_LIBRARY_DIRS}")
|
||||
MESSAGE(STATUS " library is ${Zip_LIBRARIES}")
|
||||
# ENDIF(NOT Zip_FIND_QUIETLY)
|
||||
ELSE(Zip_FOUND)
|
||||
IF(Zip_FIND_REQUIRED)
|
||||
MESSAGE(FATAL_ERROR "Zip library not found")
|
||||
ENDIF(Zip_FIND_REQUIRED)
|
||||
ENDIF(Zip_FOUND)
|
@ -156,6 +156,9 @@ are set when opening a binary file on Windows. */
|
||||
/* if true, enable S3 support */
|
||||
#cmakedefine ENABLE_NCZARR_S3 1
|
||||
|
||||
/* if true, enable nczarr zip support */
|
||||
#cmakedefine ENABLE_NCZARR_ZIP 1
|
||||
|
||||
/* if true, enable S3 testing*/
|
||||
#cmakedefine ENABLE_NCZARR_S3_TESTS 1
|
||||
|
||||
|
22
configure.ac
22
configure.ac
@ -629,6 +629,27 @@ if test "x$enable_nczarr_s3_tests" = xyes ; then
|
||||
fi
|
||||
AM_CONDITIONAL(ENABLE_NCZARR_S3_TESTS, [test "x$enable_nczarr_s3_tests" = xyes])
|
||||
|
||||
if test "x$enable_nczarr_s3_tests" = xyes ; then
|
||||
AC_MSG_WARN([*** DO NOT ENABLE_NCZARR_S3_TESTS UNLESS YOU HAVE ACCESS TO THE UNIDATA S3 BUCKET! ***])
|
||||
fi
|
||||
|
||||
# Set default
|
||||
# See if we have libzip
|
||||
AC_CHECK_LIB([zip],[zip_open],[have_zip=yes],[have_zip=no])
|
||||
if test "x$have_zip" = "xyes" ; then
|
||||
AC_SEARCH_LIBS([zip_open],[zip zip.dll cygzip.dll], [],
|
||||
[AC_MSG_ERROR([libzip search failed.])])
|
||||
fi
|
||||
AC_MSG_CHECKING([whether libzip library is available])
|
||||
AC_MSG_RESULT([${have_zip}])
|
||||
|
||||
enable_nczarr_zip=${have_zip} # alias
|
||||
|
||||
if test "x$enable_nczarr_zip" = xyes ; then
|
||||
AC_DEFINE([ENABLE_NCZARR_ZIP], [1], [If true, then libzip found])
|
||||
fi
|
||||
AM_CONDITIONAL(ENABLE_NCZARR_ZIP, [test "x$enable_nczarr_zip" = xyes])
|
||||
|
||||
# Did the user specify a default cache size for NCZarr?
|
||||
AC_MSG_CHECKING([whether a default file cache size for NCZarr was specified])
|
||||
AC_ARG_WITH([chunk-cache-size-nczarr],
|
||||
@ -1589,6 +1610,7 @@ AC_SUBST([HAS_PAR_FILTERS], [$hdf5_supports_par_filters])
|
||||
AC_SUBST(HAS_NCZARR,[$enable_nczarr])
|
||||
AC_SUBST(DO_NCZARR_S3_TESTS,[$enable_nczarr_s3_tests])
|
||||
AC_SUBST(HAS_MULTIFILTERS,[$has_multifilters])
|
||||
AC_SUBST(DO_NCZARR_ZIP_TESTS,[$enable_nczarr_zip])
|
||||
|
||||
# Include some specifics for netcdf on windows.
|
||||
#AH_VERBATIM([_WIN32_STRICMP],
|
||||
|
@ -73,7 +73,7 @@ clean-local: clean-local-check
|
||||
|
||||
clean-local-check:
|
||||
-rm -rf results results_test_parse results_test_data \
|
||||
results_test_hyrax results_test_meta
|
||||
results_test_hyrax results_test_meta results_test_raw
|
||||
-rm -f .dodsrc .daprc
|
||||
|
||||
# The shell file maketests.sh is used to build the testdata
|
||||
|
@ -21,12 +21,12 @@
|
||||
#endif
|
||||
|
||||
#include "netcdf.h"
|
||||
#include "netcdf_aux.h"
|
||||
#include "ncbytes.h"
|
||||
#include "ncpathmgr.h"
|
||||
|
||||
extern void NCD4_dumpbytes(size_t size, const void* data0, int swap);
|
||||
extern void NCD4_tagdump(size_t size, const void* data0, int swap, const char* tag);
|
||||
extern int NC_readfile(const char* filename, NCbytes* content);
|
||||
|
||||
static char* progname = NULL;
|
||||
|
||||
@ -42,7 +42,6 @@ main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
char* fname = NULL;
|
||||
NCbytes* contents = ncbytesnew();
|
||||
char* tag = NULL;
|
||||
size_t offset = 0;
|
||||
size_t len = 0;
|
||||
@ -81,12 +80,10 @@ main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
if(tag == NULL) tag = strdup(progname);
|
||||
if(NC_readfile(fname,contents)) usage();
|
||||
len = ncbyteslength(contents) - offset;
|
||||
data = (char*)ncbytescontents(contents);
|
||||
if(ncaux_readfile(fname,&len,&((void*)data))) usage();
|
||||
data += offset;
|
||||
NCD4_tagdump(len,data,swap,tag);
|
||||
|
||||
nullfree(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,20 +1,22 @@
|
||||
# Visual Studio
|
||||
|
||||
NCC="c:/tools/hdf5"
|
||||
#export SETX=1
|
||||
|
||||
NCC="c:/tools/hdf5-1.10.6"
|
||||
HDF5_DIR="$NCC/cmake/hdf5"
|
||||
AWSSDK_DIR="c:/tools/aws-cpp-sdk-all"
|
||||
|
||||
# Is netcdf-4 and/or DAP enabled?
|
||||
NCZARR=1
|
||||
HDF5=1
|
||||
DAP=1
|
||||
S3=1
|
||||
#S3TEST=1
|
||||
CDF5=1
|
||||
HDF4=1
|
||||
S3TEST=1
|
||||
#CDF5=1
|
||||
#HDF4=1
|
||||
|
||||
#TR=--trace
|
||||
|
||||
export SETX=1
|
||||
|
||||
for arg in "$@" ; do
|
||||
case "$arg" in
|
||||
vs|VS) VS=1 ;;
|
||||
@ -25,23 +27,13 @@ notest|nt) NOTEST=1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if test "x$VS" = x1 ; then
|
||||
if test "x$2" = xsetup ; then
|
||||
VSSETUP=1
|
||||
else
|
||||
unset VSSETUP
|
||||
fi
|
||||
fi
|
||||
|
||||
#TESTSERVERS="localhost:8080,remotetest.unidata.ucar.edu"
|
||||
|
||||
#export NCPATHDEBUG=1
|
||||
|
||||
if test "x$VSSETUP" = x1 ; then
|
||||
CFG="Debug"
|
||||
else
|
||||
#CFG="Debug"
|
||||
CFG="Release"
|
||||
fi
|
||||
|
||||
FLAGS=
|
||||
|
||||
@ -68,9 +60,9 @@ ignore=1
|
||||
#FLAGS="$FLAGS -DDEFAULT_API_VERSION:STRING=v110"
|
||||
#FLAGS="$FLAGS -DHDF5_ROOT=c:/tools/hdf5"
|
||||
#FLAGS="$FLAGS -DHDF5_ROOT_DIR_HINT=c:/tools/hdf5/cmake/hdf5/hdf5-config.cmake"
|
||||
FLAGS="$FLAGS -DHDF5_DIR=c:/tools/hdf5/cmake/hdf5"
|
||||
#FLAGS="$FLAGS -DHDF5_DIR=/home/dmh/tools/share/cmake/hdf5"
|
||||
#hdf5-config.cmake
|
||||
#FLAGS="-DHDF5_LIBRARIES=${NCC}/lib/hdf5 -DHDF5_HL_LIBRARY=${NCC}/lib/hdf5_hl -DHDF5_INCLUDE_DIR=${NCC}/include"
|
||||
#FLAGS="-DHDF5_C_LIBRARY=${NCC}/lib/libhdf5.so -DHDF5_HL_LIBRARY=${NCC}/lib/libhdf5_hl.so -DHDF5_INCLUDE_DIR=${NCC}/include"
|
||||
fi
|
||||
if test "x$CDF5" != x ; then
|
||||
FLAGS="$FLAGS -DENABLE_CDF5=true"
|
||||
@ -89,31 +81,28 @@ fi
|
||||
|
||||
if test "x$S3" != x ; then
|
||||
FLAGS="$FLAGS -DENABLE_NCZARR_S3=true"
|
||||
FLAGS="$FLAGS -DAWSSDK_DIR=${AWSSDK_DIR}"
|
||||
if test "x$S3TEST" != x ; then
|
||||
FLAGS="$FLAGS -DENABLE_NCZARR_S3_TESTS=true"
|
||||
fi
|
||||
else
|
||||
FLAGS="$FLAGS -DENABLE_S3_SDK=false"
|
||||
FLAGS="$FLAGS -DENABLE_S3_TESTS=false"
|
||||
FLAGS="$FLAGS -DENABLE_NCZARR_S3=false"
|
||||
FLAGS="$FLAGS -DENABLE_NCZARR_S3_TESTS=false"
|
||||
fi
|
||||
|
||||
# Enables
|
||||
# Misc.
|
||||
FLAGS="$FLAGS -DENABLE_DAP_REMOTE_TESTS=true"
|
||||
FLAGS="$FLAGS -DENABLE_LOGGING=true"
|
||||
#FLAGS="$FLAGS -DENABLE_DOXYGEN=true -DENABLE_INTERNAL_DOCS=true"
|
||||
#FLAGS="$FLAGS -DENABLE_LARGE_FILE_TESTS=true"
|
||||
FLAGS="$FLAGS -DENABLE_BENCHMARKS=true"
|
||||
#FLAGS="$FLAGS -DENABLE_FILTER_TESTING=true"
|
||||
|
||||
# Disables
|
||||
#FLAGS="$FLAGS -DENABLE_BENCHMARKS=true"
|
||||
FLAGS="$FLAGS -DENABLE_FILTER_TESTING=true"
|
||||
FLAGS="$FLAGS -DENABLE_BYTERANGE=true"
|
||||
FLAGS="$FLAGS -DBUILD_UTILITIES=true"
|
||||
FLAGS="$FLAGS -DENABLE_EXAMPLES=false"
|
||||
FLAGS="$FLAGS -DENABLE_CONVERSION_WARNINGS=false"
|
||||
#FLAGS="$FLAGS -DENABLE_TESTS=false"
|
||||
#FLAGS="$FLAGS -DENABLE_DISKLESS=false"
|
||||
FLAGS="$FLAGS -DBUILD_UTILITIES=true"
|
||||
FLAGS="$FLAGS -DENABLE_FILTER_TESTING=false"
|
||||
|
||||
FLAGS="$FLAGS -DCURL_NO_CURL_CMAKE=TRUE"
|
||||
FLAGS="$FLAGS -DENABLE_UNIT_TESTS=TRUE"
|
||||
|
||||
# Withs
|
||||
@ -124,6 +113,9 @@ mkdir build
|
||||
cd build
|
||||
|
||||
NCLIB=`pwd`
|
||||
NCCYGLIB=`cygpath -u ${NCLIB} |tr -d ''`
|
||||
NCCBIN=`cygpath -u "${NCC}/bin" |tr -d ''`
|
||||
AWSSDKBIN="/cygdrive/c/tools/aws-cpp-sdk-all/bin"
|
||||
|
||||
if test "x$VS" != x ; then
|
||||
|
||||
@ -131,6 +123,7 @@ if test "x$VS" != x ; then
|
||||
CFG="Release"
|
||||
NCLIB="${NCLIB}/liblib"
|
||||
export PATH="${NCLIB}:${PATH}"
|
||||
export LD_LIBRARY_PATH="${NCCBIN}:$LD_LIBRARY_PATH:${AWSSDKBIN}:${NCCYGLIB}"
|
||||
#G=
|
||||
#TR=--trace
|
||||
cmake ${TR} "$G" -DCMAKE_BUILD_TYPE=${CFG} $FLAGS ..
|
||||
@ -147,7 +140,7 @@ else
|
||||
NCLIB="${NCLIB}/build/liblib"
|
||||
#G="-GUnix Makefiles"
|
||||
#T="--trace-expand"
|
||||
cmake "${G}" $FLAGS ..
|
||||
cmake --loglevel=VERBOSE "${G}" $FLAGS ..
|
||||
if test "x$NOBUILD" = x ; then
|
||||
make all
|
||||
fi
|
||||
|
@ -209,7 +209,11 @@ main()
|
||||
hid_t file_typeid1[NUM_OBJ_1], native_typeid1[NUM_OBJ_1];
|
||||
hid_t file_typeid2, native_typeid2;
|
||||
hsize_t num_obj;
|
||||
#if H5_VERSION_GE(1,12,0)
|
||||
H5O_info2_t obj_info;
|
||||
#else
|
||||
H5O_info_t obj_info;
|
||||
#endif
|
||||
char obj_name[STR_LEN + 1];
|
||||
hsize_t dims[1] = {ATT_LEN}; /* netcdf attributes always 1-D. */
|
||||
|
||||
|
@ -480,6 +480,7 @@ by the desired type. */
|
||||
#define NC_ENCZARR (-137) /**< Error at NCZarr layer. */
|
||||
#define NC_ES3 (-138) /**< Generic S3 error */
|
||||
#define NC_EEMPTY (-139) /**< Attempt to read empty NCZarr map key */
|
||||
#define NC_EFOUND (-140) /**< Some object exists when it should not */
|
||||
|
||||
#define NC4_LAST_ERROR (-140) /**< @internal All netCDF errors > this. */
|
||||
|
||||
|
@ -69,6 +69,11 @@ EXTERNL int ncaux_h5filterspec_parselist(const char* txt0, int* formatp, size_t*
|
||||
EXTERNL void ncaux_h5filterspec_free(struct NC_H5_Filterspec* f);
|
||||
EXTERNL void ncaux_h5filterspec_fix8(unsigned char* mem, int decode);
|
||||
|
||||
/* Wrappers to export selected functions from libnetcdf */
|
||||
|
||||
EXTERNL int ncaux_readfile(const char* filename, size_t* sizep, void** content);
|
||||
EXTERNL int ncaux_writefile(const char* filename, size_t size, void* content);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
@ -27,6 +27,7 @@ See COPYRIGHT for license information.
|
||||
#include "netcdf_aux.h"
|
||||
#include "ncoffsets.h"
|
||||
#include "nclog.h"
|
||||
#include "ncrc.h"
|
||||
#include "netcdf_filter.h"
|
||||
|
||||
struct NCAUX_FIELD {
|
||||
@ -1049,3 +1050,24 @@ done:
|
||||
return stat;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**************************************************/
|
||||
/* Wrappers to export selected functions from libnetcdf */
|
||||
|
||||
EXTERNL int
|
||||
ncaux_readfile(const char* filename, size_t* sizep, void** contentp)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
NCbytes* content = ncbytesnew();
|
||||
stat = NC_readfile(filename,content);
|
||||
if(stat == NC_NOERR && contentp)
|
||||
*contentp = ncbytesextract(content);
|
||||
ncbytesfree(content);
|
||||
return stat;
|
||||
}
|
||||
|
||||
EXTERNL int
|
||||
ncaux_writefile(const char* filename, size_t size, void* content)
|
||||
{
|
||||
return NC_writefile(filename,size,content);
|
||||
}
|
||||
|
@ -277,6 +277,8 @@ const char *nc_strerror(int ncerr1)
|
||||
return "NetCDF: AWS S3 error";
|
||||
case NC_EEMPTY:
|
||||
return "NetCDF: Attempt to read empty NCZarr map key";
|
||||
case NC_EFOUND:
|
||||
return "NetCDF: Some object exists when it should not";
|
||||
default:
|
||||
#ifdef USE_PNETCDF
|
||||
/* The behavior of ncmpi_strerror here is to return
|
||||
|
@ -189,7 +189,9 @@ Send trace messages.
|
||||
int
|
||||
nctracelevel(int level)
|
||||
{
|
||||
int oldlevel = nclog_global.tracelevel;
|
||||
int oldlevel;
|
||||
if(!nclogginginitialized) ncloginit();
|
||||
oldlevel = nclog_global.tracelevel;
|
||||
if(level < 0) {
|
||||
nclog_global.tracelevel = level;
|
||||
ncsetlogging(0);
|
||||
@ -198,7 +200,6 @@ nctracelevel(int level)
|
||||
ncsetlogging(1);
|
||||
nclogopen(NULL); /* use stderr */
|
||||
}
|
||||
fprintf(stderr,"XXX: level=%d\n",nclog_global.tracelevel);
|
||||
return oldlevel;
|
||||
}
|
||||
|
||||
@ -260,7 +261,7 @@ ncuntrace(const char* fcn, int err, const char* fmt, ...)
|
||||
goto done;
|
||||
}
|
||||
if(frame->level <= nclog_global.tracelevel) {
|
||||
fprintf(nclog_global.nclogstream,"%s: (%d): %s: ","Exit",frame->depth,frame->fcn);
|
||||
fprintf(nclog_global.nclogstream,"%s: (%d): %s: ","Exit",frame->level,frame->fcn);
|
||||
if(err)
|
||||
fprintf(nclog_global.nclogstream,"err=(%d) '%s':",err,nc_strerror(err));
|
||||
if(fmt != NULL)
|
||||
|
@ -108,6 +108,10 @@ IF(ENABLE_PNETCDF AND PNETCDF)
|
||||
SET(TLL_LIBS ${TLL_LIBS} ${PNETCDF})
|
||||
ENDIF()
|
||||
|
||||
IF(ENABLE_NCZARR_ZIP)
|
||||
SET(TLL_LIBS ${TLL_LIBS} ${Zip_LIBRARIES})
|
||||
ENDIF()
|
||||
|
||||
IF(ENABLE_S3_SDK)
|
||||
TARGET_LINK_DIRECTORIES(netcdf PUBLIC ${AWSSDK_LIB_DIR})
|
||||
TARGET_LINK_LIBRARIES(netcdf ${AWSSDK_LINK_LIBRARIES})
|
||||
|
@ -24,8 +24,7 @@ zgrp.c
|
||||
zinternal.c
|
||||
zjson.c
|
||||
zmap.c
|
||||
zmap_nz4.c
|
||||
zmap_nzf.c
|
||||
zmap_file.c
|
||||
zodom.c
|
||||
zopen.c
|
||||
zprov.c
|
||||
@ -48,12 +47,17 @@ zprovenance.h
|
||||
zdebug.h
|
||||
)
|
||||
|
||||
IF(ENABLE_NCZARR_ZIP)
|
||||
SET(libnczarr_SOURCES ${libnczarr_SOURCES} zmap_zip.c)
|
||||
ENDIF()
|
||||
|
||||
IF(ENABLE_S3_SDK)
|
||||
SET(libnczarr_SOURCES ${libnczarr_SOURCES} zs3sdk.cpp zmap_s3sdk.c awsincludes.h zs3sdk.h)
|
||||
ENDIF()
|
||||
|
||||
# Build the Zarr dispatch layer as a library that will be included in
|
||||
# the netCDF library.
|
||||
|
||||
add_library(nczarr OBJECT ${libnczarr_SOURCES})
|
||||
|
||||
IF(MPI_C_INCLUDE_PATH)
|
||||
|
@ -43,8 +43,7 @@ zgrp.c \
|
||||
zinternal.c \
|
||||
zjson.c \
|
||||
zmap.c \
|
||||
zmap_nz4.c \
|
||||
zmap_nzf.c \
|
||||
zmap_file.c \
|
||||
zodom.c \
|
||||
zopen.c \
|
||||
zprov.c \
|
||||
@ -67,6 +66,10 @@ zodom.h \
|
||||
zprovenance.h \
|
||||
zdebug.h
|
||||
|
||||
if ENABLE_NCZARR_ZIP
|
||||
libnczarr_la_SOURCES += zmap_zip.c
|
||||
endif
|
||||
|
||||
if ENABLE_S3_SDK
|
||||
libnczarr_la_SOURCES += zmap_s3sdk.c
|
||||
libnczarr_la_SOURCES += zs3sdk.cpp awsincludes.h zs3sdk.h
|
||||
|
@ -52,6 +52,7 @@ static int parseurl(const char* path0, NCURI** urip);
|
||||
static void nc4ify(const char* zname, char* nc4name);
|
||||
static void zify(const char* nc4name, char* zname);
|
||||
static int testcontentbearing(int grpid);
|
||||
static int errno2ncerr(int err);
|
||||
|
||||
/* Define the Dataset level API */
|
||||
|
||||
@ -143,7 +144,7 @@ znc4open(const char *path, int mode, size64_t flags, void* parameters, NCZMAP**
|
||||
truepath = NULL;
|
||||
|
||||
if((stat=nc_open(local,mode,&ncid)))
|
||||
{stat = NC_EEMPTY; goto done;} /* could not open */
|
||||
goto done; /* could not open */
|
||||
z4map->ncid = ncid;
|
||||
|
||||
if(mapp) *mapp = (NCZMAP*)z4map;
|
||||
@ -153,7 +154,7 @@ done:
|
||||
nullfree(local);
|
||||
ncurifree(url);
|
||||
if(stat) znc4close((NCZMAP*)z4map,0);
|
||||
return (stat);
|
||||
return errno2ncerr(stat);
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
@ -340,7 +341,6 @@ znc4search(NCZMAP* map, const char* prefix, NClist* matches)
|
||||
int* vars = NULL;
|
||||
int i;
|
||||
NCbytes* key = ncbytesnew();
|
||||
int trailing = 0;
|
||||
|
||||
if((stat=nczm_split(prefix,segments)))
|
||||
goto done;
|
||||
@ -375,17 +375,13 @@ znc4search(NCZMAP* map, const char* prefix, NClist* matches)
|
||||
if((stat = nc_inq_grps(grpid,&ngrps,subgrps)))
|
||||
goto done;
|
||||
/* Add the subgroup keys to the list of matches (zified) */
|
||||
trailing = (prefix[strlen(prefix)-1] == '/'); /* does prefix end with '/' */
|
||||
for(i=0;i<ngrps;i++) {
|
||||
char gname[NC_MAX_NAME];
|
||||
char zname[NC_MAX_NAME];
|
||||
/* See if this group is content-bearing */
|
||||
if((stat = nc_inq_grpname(subgrps[i],gname))) goto done;
|
||||
zify(gname,zname);
|
||||
ncbytescat(key,prefix);
|
||||
if(!trailing) ncbytescat(key,"/");
|
||||
ncbytescat(key,zname);
|
||||
nclistpush(matches,ncbytesextract(key));
|
||||
nclistpush(matches,strdup(zname));
|
||||
}
|
||||
|
||||
done:
|
||||
@ -591,11 +587,26 @@ nc4ify(const char* zname, char* nc4name)
|
||||
if(nc4name[0] == NCZM_DOT) nc4name[0] = ZDOTNC4;
|
||||
}
|
||||
|
||||
/* Convert errno to closest NC_EXXX error */
|
||||
static int
|
||||
errno2ncerr(int err)
|
||||
{
|
||||
switch (err) {
|
||||
case ENOENT: err = NC_ENOTFOUND; break; /* File does not exist */
|
||||
case ENOTDIR: err = NC_EEMPTY; break; /* no content */
|
||||
case EACCES: err = NC_EAUTH; break; /* file permissions */
|
||||
case EPERM: err = NC_EAUTH; break; /* ditto */
|
||||
default: break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
/* External API objects */
|
||||
|
||||
NCZMAP_DS_API zmap_nz4 = {
|
||||
NCZM_NC4_V1,
|
||||
0,
|
||||
znc4create,
|
||||
znc4open,
|
||||
};
|
@ -76,9 +76,6 @@ ncz_create_dataset(NC_FILE_INFO_T* file, NC_GRP_INFO_T* root, const char** contr
|
||||
if((stat = nczmap_create(zinfo->features.mapimpl,nc->path,nc->mode,zinfo->features.flags,NULL,&zinfo->map)))
|
||||
goto done;
|
||||
|
||||
/* Create super block (NCZMETAROOT) */
|
||||
if((stat = ncz_create_superblock(zinfo))) goto done;
|
||||
|
||||
done:
|
||||
ncurifree(uri);
|
||||
NCJreclaim(json);
|
||||
@ -386,14 +383,9 @@ applycontrols(NCZ_FILE_INFO_T* zinfo)
|
||||
for(i=0;i<nclistlength(modelist);i++) {
|
||||
const char* p = nclistget(modelist,i);
|
||||
if(strcasecmp(p,PUREZARR)==0) zinfo->features.flags |= FLAG_PUREZARR;
|
||||
else if(strcasecmp(p,"bytes")==0) zinfo->features.flags |= FLAG_BYTERANGE;
|
||||
else if(strcasecmp(p,"zip")==0) zinfo->features.mapimpl = NCZM_ZIP;
|
||||
else if(strcasecmp(p,"file")==0) zinfo->features.mapimpl = NCZM_FILE;
|
||||
else if(strcasecmp(p,"s3")==0) zinfo->features.mapimpl = NCZM_S3;
|
||||
else if(strcasecmp(p,"nz4")==0) zinfo->features.mapimpl = NCZM_NC4;
|
||||
else if(strcasecmp(p,"nzf")==0) zinfo->features.mapimpl = NCZM_FILE;
|
||||
else if(strcasecmp(p,"nzrf")==0)
|
||||
{zinfo->features.mapimpl = NCZM_FILE; zinfo->features.flags |= FLAG_BYTERANGE;}
|
||||
else if(strcasecmp(p,"nzr4")==0)
|
||||
{zinfo->features.mapimpl = NCZM_NC4; zinfo->features.flags |= FLAG_BYTERANGE;}
|
||||
}
|
||||
/* Process other controls */
|
||||
if((value = controllookup((const char**)zinfo->controls,"log")) != NULL) {
|
||||
|
@ -32,7 +32,7 @@ extern int NCZ_stringconvert1(nc_type typid, char* src, char** strp);
|
||||
extern int NCZ_stringconvert(nc_type typid, size_t len, void* data0, NCjson** jdatap);
|
||||
|
||||
/* zsync.c */
|
||||
extern int ncz_sync_file(NC_FILE_INFO_T* file);
|
||||
extern int ncz_sync_file(NC_FILE_INFO_T* file, int isclose);
|
||||
extern int ncz_sync_grp(NC_FILE_INFO_T* file, NC_GRP_INFO_T* grp);
|
||||
extern int ncz_sync_atts(NC_FILE_INFO_T*, NC_OBJ* container, NCindex* attlist);
|
||||
extern int ncz_read_grp(NC_FILE_INFO_T* file, NC_GRP_INFO_T* grp);
|
||||
@ -64,6 +64,9 @@ extern int NCZ_swapatomicdata(size_t datalen, void* data, int typesize);
|
||||
extern char** NCZ_clonestringvec(size_t len, const char** vec);
|
||||
extern void NCZ_freestringvec(size_t len, char** vec);
|
||||
extern int NCZ_create_fill_chunk(size64_t chunksize, size_t typesize, void* fill, void** fillchunkp);
|
||||
extern int NCZ_s3clear(ZS3INFO* s3);
|
||||
/* Export */
|
||||
EXTERNL int NCZ_s3urlprocess(NCURI* url, ZS3INFO* s3);
|
||||
|
||||
/* zwalk.c */
|
||||
EXTERNL int NCZ_read_chunk(int ncid, int varid, size64_t* zindices, void* chunkdata);
|
||||
|
@ -454,7 +454,10 @@ put_chunk(NCZChunkCache* cache, const char* key, const NCZCacheEntry* entry)
|
||||
case NC_NOERR: break;
|
||||
case NC_EEMPTY:
|
||||
/* Create the chunk */
|
||||
if((stat = nczmap_defineobj(map,key))) goto done;
|
||||
switch (stat = nczmap_defineobj(map,key)) {
|
||||
case NC_NOERR: case NC_EFOUND: break;
|
||||
default: goto done;
|
||||
}
|
||||
/* write again */
|
||||
if((stat = nczmap_write(map,key,0,cache->chunksize,entry->data)))
|
||||
goto done;
|
||||
|
@ -49,8 +49,10 @@ ncz_create_file(const char *path, int cmode, size_t initialsz, const char** cont
|
||||
h5->mem.persist = ((cmode & NC_PERSIST) == NC_PERSIST);
|
||||
|
||||
/* Do format specific setup */
|
||||
|
||||
/* Should check if file already exists, and if NC_NOCLOBBER is specified,
|
||||
return an error */
|
||||
return an error; but defer to the map */
|
||||
|
||||
if((retval = ncz_create_dataset(h5,h5->root_grp,controls)))
|
||||
BAIL(retval);
|
||||
|
||||
|
@ -8,8 +8,8 @@
|
||||
#undef ZDEBUG /* general debug */
|
||||
#undef ZDEBUG1 /* detailed debug */
|
||||
|
||||
#define ZCATCH /* Warning: significant performance impact */
|
||||
#define ZTRACING /* Warning: significant performance impact */
|
||||
#undef ZCATCH /* Warning: significant performance impact */
|
||||
#undef ZTRACING /* Warning: significant performance impact */
|
||||
|
||||
#include "ncexternl.h"
|
||||
#include "nclog.h"
|
||||
@ -32,8 +32,9 @@ EXTERNL int zthrow(int err, const char* fname, const char* fcn, int line);
|
||||
#define ZUNTRACEX(e,fmt,...) ncuntrace(__func__,(e),fmt,##__VA_ARGS__)
|
||||
#else
|
||||
#define ZTRACE(level,fmt,...)
|
||||
#define ZUNTRACE(e)
|
||||
#define ZUNTRACEX(e,fmt,...)
|
||||
#define ZTRACEMORE(level,fmt,...)
|
||||
#define ZUNTRACE(e) (e)
|
||||
#define ZUNTRACEX(e,fmt,...) (e)
|
||||
#endif
|
||||
|
||||
/* printers */
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
/* Forward */
|
||||
static int NCZ_enddef(int ncid);
|
||||
static int ncz_sync_netcdf4_file(NC_FILE_INFO_T* file);
|
||||
static int ncz_sync_netcdf4_file(NC_FILE_INFO_T* file, int isclose);
|
||||
|
||||
/**
|
||||
* @internal Put the file back in redef mode. This is done
|
||||
@ -137,8 +137,8 @@ done:
|
||||
int
|
||||
NCZ_sync(int ncid)
|
||||
{
|
||||
NC_FILE_INFO_T* file = NULL;
|
||||
int stat = NC_NOERR;
|
||||
NC_FILE_INFO_T* file = NULL;
|
||||
|
||||
ZTRACE(0,"ncid=%d",ncid);
|
||||
|
||||
@ -157,7 +157,9 @@ NCZ_sync(int ncid)
|
||||
return stat;
|
||||
}
|
||||
|
||||
return ncz_sync_netcdf4_file(file);
|
||||
/* do not do this if file is writeonce */
|
||||
stat = ncz_sync_netcdf4_file(file,!ZCLOSE);
|
||||
return stat;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -244,7 +246,7 @@ ncz_closeorabort(NC_FILE_INFO_T* h5, void* params, int abort)
|
||||
if(h5->flags & NC_INDEF) h5->flags ^= NC_INDEF;
|
||||
/* Sync the file unless this is a read-only file. */
|
||||
if(!h5->no_write) {
|
||||
if((stat = ncz_sync_netcdf4_file(h5)))
|
||||
if((stat = ncz_sync_netcdf4_file(h5,ZCLOSE)))
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
@ -356,7 +358,7 @@ NCZ_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp)
|
||||
*/
|
||||
|
||||
static int
|
||||
ncz_sync_netcdf4_file(NC_FILE_INFO_T* file)
|
||||
ncz_sync_netcdf4_file(NC_FILE_INFO_T* file, int isclose)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
|
||||
@ -392,7 +394,7 @@ ncz_sync_netcdf4_file(NC_FILE_INFO_T* file)
|
||||
goto done;
|
||||
|
||||
/* Write all the metadata. */
|
||||
if((stat = ncz_sync_file(file)))
|
||||
if((stat = ncz_sync_file(file,isclose)))
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
@ -424,7 +426,7 @@ ncz_enddef_netcdf4_file(NC_FILE_INFO_T* file)
|
||||
/* Redef mode needs to be tracked separately for nc_abort. */
|
||||
file->redef = NC_FALSE;
|
||||
|
||||
return ncz_sync_netcdf4_file(file);
|
||||
return ncz_sync_netcdf4_file(file,!ZCLOSE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -53,6 +53,9 @@
|
||||
|
||||
#define PUREZARR "zarr"
|
||||
|
||||
/* Mnemonics */
|
||||
#define ZCLOSE 1 /* this is closeorabort as opposed to enddef */
|
||||
|
||||
/**************************************************/
|
||||
/* Forward */
|
||||
|
||||
@ -90,7 +93,6 @@ typedef struct NCZ_FILE_INFO {
|
||||
# define FLAG_PUREZARR 1
|
||||
# define FLAG_SHOWFETCH 2
|
||||
# define FLAG_LOGGING 4
|
||||
# define FLAG_BYTERANGE 8
|
||||
NCZM_IMPL mapimpl;
|
||||
} features;
|
||||
} NCZ_FILE_INFO_T;
|
||||
|
@ -295,7 +295,7 @@ NCJlex(NCJparser* parser)
|
||||
start = parser->pos;
|
||||
for(;;) {
|
||||
c = *parser->pos++;
|
||||
if(strchr(WORD,c) == NULL) break; /* end of word */
|
||||
if(c == '\0' || strchr(WORD,c) == NULL) break; /* end of word */
|
||||
}
|
||||
/* Pushback c if not whitespace */
|
||||
if(c > ' ' && c != '\177') parser->pos--;
|
||||
|
186
libnczarr/zmap.c
186
libnczarr/zmap.c
@ -4,18 +4,41 @@
|
||||
*/
|
||||
|
||||
#include "zincludes.h"
|
||||
#include <stdarg.h>
|
||||
#include "ncpathmgr.h"
|
||||
|
||||
/**************************************************/
|
||||
/* Import the current implementations */
|
||||
|
||||
extern NCZMAP_DS_API zmap_file;
|
||||
#ifdef USE_HDF5
|
||||
extern NCZMAP_DS_API zmap_nz4;
|
||||
extern NCZMAP_DS_API zmap_nzf;
|
||||
#endif
|
||||
#ifdef ENABLE_NCZARR_ZIP
|
||||
extern NCZMAP_DS_API zmap_zip;
|
||||
#endif
|
||||
#ifdef ENABLE_S3_SDK
|
||||
extern NCZMAP_DS_API zmap_s3sdk;
|
||||
#endif
|
||||
|
||||
/**************************************************/
|
||||
|
||||
NCZM_PROPERTIES
|
||||
nczmap_properties(NCZM_IMPL impl)
|
||||
{
|
||||
switch (impl) {
|
||||
case NCZM_FILE: return zmap_file.properties;
|
||||
#ifdef ENABLE_NCZARR_ZIP
|
||||
case NCZM_ZIP: return zmap_zip.properties;
|
||||
#endif
|
||||
#ifdef ENABLE_S3_SDK
|
||||
case NCZM_S3: return zmap_s3sdk.properties;
|
||||
#endif
|
||||
default: break;
|
||||
}
|
||||
return NCZM_UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
int
|
||||
nczmap_create(NCZM_IMPL impl, const char *path, int mode, size64_t flags, void* parameters, NCZMAP** mapp)
|
||||
{
|
||||
@ -29,14 +52,16 @@ nczmap_create(NCZM_IMPL impl, const char *path, int mode, size64_t flags, void*
|
||||
if(mapp) *mapp = NULL;
|
||||
|
||||
switch (impl) {
|
||||
case NCZM_NC4:
|
||||
stat = zmap_nz4.create(path, mode, flags, parameters, &map);
|
||||
if(stat) goto done;
|
||||
break;
|
||||
case NCZM_FILE:
|
||||
stat = zmap_nzf.create(path, mode, flags, parameters, &map);
|
||||
stat = zmap_file.create(path, mode, flags, parameters, &map);
|
||||
if(stat) goto done;
|
||||
break;
|
||||
#ifdef ENABLE_NCZARR_ZIP
|
||||
case NCZM_ZIP:
|
||||
stat = zmap_zip.create(path, mode, flags, parameters, &map);
|
||||
if(stat) goto done;
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_S3_SDK
|
||||
case NCZM_S3:
|
||||
stat = zmap_s3sdk.create(path, mode, flags, parameters, &map);
|
||||
@ -65,14 +90,16 @@ nczmap_open(NCZM_IMPL impl, const char *path, int mode, size64_t flags, void* pa
|
||||
if(mapp) *mapp = NULL;
|
||||
|
||||
switch (impl) {
|
||||
case NCZM_NC4:
|
||||
stat = zmap_nz4.open(path, mode, flags, parameters, &map);
|
||||
if(stat) goto done;
|
||||
break;
|
||||
case NCZM_FILE:
|
||||
stat = zmap_nzf.open(path, mode, flags, parameters, &map);
|
||||
stat = zmap_file.open(path, mode, flags, parameters, &map);
|
||||
if(stat) goto done;
|
||||
break;
|
||||
#ifdef ENABLE_NCZARR_ZIP
|
||||
case NCZM_ZIP:
|
||||
stat = zmap_zip.open(path, mode, flags, parameters, &map);
|
||||
if(stat) goto done;
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_S3_SDK
|
||||
case NCZM_S3:
|
||||
stat = zmap_s3sdk.open(path, mode, flags, parameters, &map);
|
||||
@ -115,12 +142,6 @@ nczmap_len(NCZMAP* map, const char* key, size64_t* lenp)
|
||||
return map->api->len(map, key, lenp);
|
||||
}
|
||||
|
||||
int
|
||||
nczmap_defineobj(NCZMAP* map, const char* key)
|
||||
{
|
||||
return map->api->defineobj(map, key);
|
||||
}
|
||||
|
||||
int
|
||||
nczmap_read(NCZMAP* map, const char* key, size64_t start, size64_t count, void* content)
|
||||
{
|
||||
@ -230,6 +251,26 @@ nczm_concat(const char* prefix, const char* suffix, char** pathp)
|
||||
return NC_NOERR;
|
||||
}
|
||||
|
||||
/* Concat multiple strings, but with no intervening separators */
|
||||
int
|
||||
nczm_appendn(char** resultp, int n, ...)
|
||||
{
|
||||
va_list args;
|
||||
NCbytes* buf = ncbytesnew();
|
||||
int i;
|
||||
|
||||
va_start(args, n);
|
||||
for(i=0;i<n;i++) {
|
||||
char* s = va_arg(args,char*);
|
||||
if(s != NULL) ncbytescat(buf,s);
|
||||
}
|
||||
ncbytesnull(buf);
|
||||
va_end(args);
|
||||
if(resultp) {*resultp = ncbytesextract(buf);}
|
||||
ncbytesfree(buf);
|
||||
return NC_NOERR;
|
||||
}
|
||||
|
||||
/* A segment is defined as a '/' plus characters following up
|
||||
to the end or upto the next '/'
|
||||
*/
|
||||
@ -340,8 +381,7 @@ nczm_localize(const char* path, char** localpathp, int localize)
|
||||
|
||||
/* Convert path0 to be:
|
||||
1. absolute -- including drive letters
|
||||
2. forward slashed -- we will convert back to back slash in
|
||||
nczm_fixpath
|
||||
2. forward slashed -- we will convert back to back slash in nczm_fixpath
|
||||
*/
|
||||
|
||||
int
|
||||
@ -366,3 +406,111 @@ done:
|
||||
nullfree(cpath);
|
||||
return THROW(ret);
|
||||
}
|
||||
|
||||
/* extract the first segment of a path */
|
||||
int
|
||||
nczm_segment1(const char* path, char** seg1p)
|
||||
{
|
||||
int ret = NC_NOERR;
|
||||
char* seg1 = NULL;
|
||||
const char* p = NULL;
|
||||
const char* q = NULL;
|
||||
ptrdiff_t delta;
|
||||
|
||||
if(path == NULL)
|
||||
{seg1 = NULL; goto done;}
|
||||
|
||||
p = path;
|
||||
if(*p == '/') p++; /* skip any leading '/' */
|
||||
q = strchr(p,'/');
|
||||
if(q == NULL) q = p+strlen(p); /* point to stop character */
|
||||
delta = (q-p);
|
||||
if((seg1 = (char*)malloc(delta+1))==NULL)
|
||||
{ret = NC_ENOMEM; goto done;}
|
||||
memcpy(seg1,p,delta);
|
||||
seg1[delta] = '\0';
|
||||
|
||||
if(seg1p) {*seg1p = seg1; seg1 = NULL;}
|
||||
done:
|
||||
nullfree(seg1);
|
||||
return THROW(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
Extract the basename from a path.
|
||||
Basename is last segment minus one extension.
|
||||
*/
|
||||
|
||||
int
|
||||
nczm_basename(const char* path, char** basep)
|
||||
{
|
||||
int ret = NC_NOERR;
|
||||
char* base = NULL;
|
||||
const char* p = NULL;
|
||||
const char* q = NULL;
|
||||
ptrdiff_t delta;
|
||||
|
||||
if(path == NULL)
|
||||
{base = NULL; goto done;}
|
||||
|
||||
p = strrchr(path,'/');
|
||||
if(p == NULL) p = path; else p++;
|
||||
q = strrchr(p,'.');
|
||||
if(q == NULL) q = p + strlen(p);
|
||||
|
||||
delta = (q-p);
|
||||
if((base = (char*)malloc(delta+1))==NULL)
|
||||
{ret = NC_ENOMEM; goto done;}
|
||||
memcpy(base,p,delta);
|
||||
base[delta] = '\0';
|
||||
|
||||
if(basep) {*basep = base; base = NULL;}
|
||||
done:
|
||||
nullfree(base);
|
||||
return THROW(ret);
|
||||
}
|
||||
|
||||
/* bubble sort a list of strings */
|
||||
void
|
||||
nczm_sortlist(NClist* l)
|
||||
{
|
||||
nczm_sortenvv(nclistlength(l),(char**)nclistcontents(l));
|
||||
}
|
||||
|
||||
/* bubble sort a list of strings */
|
||||
void
|
||||
nczm_sortenvv(int n, char** envv)
|
||||
{
|
||||
size_t i, switched;
|
||||
|
||||
if(n <= 1) return;
|
||||
do {
|
||||
switched = 0;
|
||||
for(i=0;i<n-1;i++) {
|
||||
char* ith = envv[i];
|
||||
char* ith1 = envv[i+1];
|
||||
if(strcmp(ith,ith1) > 0) {
|
||||
envv[i] = ith1;
|
||||
envv[i+1] = ith;
|
||||
switched = 1;
|
||||
}
|
||||
}
|
||||
} while(switched);
|
||||
#if 0
|
||||
for(i=0;i<n;i++)
|
||||
fprintf(stderr,"sorted: [%d] %s\n",i,(const char*)envv[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
NCZ_freeenvv(int n, char** envv)
|
||||
{
|
||||
int i;
|
||||
char** p;
|
||||
if(envv == NULL) return;
|
||||
if(n < 0)
|
||||
{for(n=0, p = envv; *p; n++); /* count number of strings */}
|
||||
for(i=0;i<n;i++)
|
||||
if(envv[i]) free(envv[i]);
|
||||
free(envv);
|
||||
}
|
||||
|
161
libnczarr/zmap.h
161
libnczarr/zmap.h
@ -20,7 +20,8 @@ separator for the segments of the path.
|
||||
|
||||
As with Unix, all keys have this BNF syntax:
|
||||
<pre>
|
||||
key: '/' | key segment ;
|
||||
key: '/' | keypath ;
|
||||
keypath: '/' segment | keypath '/' segment ;
|
||||
segment: <sequence of UTF-8 characters except control characters and '/'>
|
||||
</pre>
|
||||
|
||||
@ -30,7 +31,8 @@ Thus one key is "contained" (possibly transitively)
|
||||
by another if one key is a prefix (in the string sense) of the other.
|
||||
So in this sense the key "/x/y/z" is contained by the key "/x/y".
|
||||
|
||||
As with S3, a key refers to an "object" that can contain content.
|
||||
In this model all keys "exist" but only some keys refer to
|
||||
objects containing content -- content bearing.
|
||||
An important restriction is placed on the structure of the tree.
|
||||
Namely, keys are only defined for content-bearing objects.
|
||||
Further, all the leaves of the tree are these content-bearing objects.
|
||||
@ -39,17 +41,11 @@ be a prefix of any other key.
|
||||
|
||||
There several other concepts of note.
|
||||
1. Dataset - a dataset is the complete tree contained by the key defining
|
||||
the root of the dataset.
|
||||
the root of the dataset. Technically, the root of the tree is the key <dataset>/.nczarr,
|
||||
where .nczarr can be considered the superblock of the dataset.
|
||||
2. Object - equivalent of the S3 object; Each object has a unique key
|
||||
and "contains" data in the form of an arbitrary sequence of 8-bit bytes.
|
||||
|
||||
Notes:
|
||||
1. The search function is optional. It has two purposes:
|
||||
a. Support reading of pure zarr datasets (because they do not explicitly
|
||||
track their contents).
|
||||
b. Debugging to allow raw examination of the storage. See zdump
|
||||
for example.
|
||||
|
||||
The zmap API defined here isolates the key-value pair mapping code
|
||||
from the Zarr-based implementation of NetCDF-4.
|
||||
|
||||
@ -57,6 +53,40 @@ It wraps an internal C dispatch table manager
|
||||
for implementing an abstract data structure
|
||||
implementing the key/object model.
|
||||
|
||||
Search:
|
||||
The search function has two purposes:
|
||||
a. Support reading of pure zarr datasets (because they do not explicitly
|
||||
track their contents).
|
||||
b. Debugging to allow raw examination of the storage. See zdump
|
||||
for example.
|
||||
v
|
||||
The search function takes a prefix path which has a key syntax (see above).
|
||||
The set of legal keys is the set of keys such that the key references
|
||||
a content-bearing object -- e.g. /x/y/.zarray or /.zgroup. Essentially
|
||||
this is the set of keys pointing to the leaf objects of the tree of keys
|
||||
constituting a dataset. This set potentially limits the set of keys that need to be
|
||||
examined during search.
|
||||
|
||||
Ideally the search function would return
|
||||
the set of names that are immediate suffixes of a
|
||||
given prefix path. That is, if <prefix> is the prefix path,
|
||||
then search returns all <name> such that <prefix>/<name> is itself a prefix of a "legal" key.
|
||||
This could be used to implement glob style searches such as "/x/y/ *" or "/x/y/ **"
|
||||
|
||||
This semantics was chosen because it appears to be the minimum required to implement
|
||||
all other kinds of search using recursion. So for example
|
||||
1. Avoid returning keys that are not a prefix of some legal key.
|
||||
2. Avoid returning all the legal keys in the dataset because that set may be very large;
|
||||
although the implementation may still have to examine all legal keys to get the desired subset.
|
||||
3. Allow for use of partial read mechanisms such as iterators, if available.
|
||||
This can support processing a limited set of keys for each iteration. This is a
|
||||
straighforward tradeoff of space over time.
|
||||
|
||||
This is doable in S3 search using common prefixes with a delimiter of '/', although
|
||||
the implementation is a bit tricky. For the file system zmap implementation, the legal search keys can be obtained
|
||||
one level at a time, which directly implements the search semantics. For the zip file implementation,
|
||||
this semantics is not possible, so the whole tree must be obtained and searched.
|
||||
|
||||
Issues:
|
||||
1. S3 limits key lengths to 1024 bytes. Some deeply nested netcdf files
|
||||
will almost certainly exceed this limit.
|
||||
@ -81,12 +111,12 @@ this different than, say, a direvtory tree where a key will
|
||||
always lead to something: a directory or a file.
|
||||
|
||||
In any case, the zmap API returns two distinguished error code:
|
||||
1. NC_NOERR if a content bearing object is created or referenced.
|
||||
1. NC_NOERR if a operation succeeded
|
||||
2. NC_EEMPTY is returned when accessing a key that has no content.
|
||||
This does not preclude other errors being returned such NC_EACCESS or NC_EPERM or NC_EINVAL
|
||||
if there are permission errors or illegal function arguments, for example.
|
||||
It also does not preclude the use of other error codes internal to the zmap
|
||||
implementation. So zmap_nzf, for example, uses NC_ENOTFOUND internally
|
||||
implementation. So zmap_file, for example, uses NC_ENOTFOUND internally
|
||||
because it is possible to detect the existence of directories and files.
|
||||
This does not propagate to the API.
|
||||
|
||||
@ -95,6 +125,10 @@ caller asked for non-content-bearing key.
|
||||
|
||||
The current set of operations defined for zmaps are define with the
|
||||
generic nczm_xxx functions below.
|
||||
|
||||
Each zmap implementation has retrievable flags defining limitations
|
||||
of the implementation.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef ZMAP_H
|
||||
@ -115,13 +149,20 @@ typedef struct NCZMAP_API NCZMAP_API;
|
||||
/* Define the space of implemented (eventually) map implementations */
|
||||
typedef enum NCZM_IMPL {
|
||||
NCZM_UNDEF=0, /* In-memory implementation */
|
||||
NCZM_S3=1, /* Amazon S3 implementation */
|
||||
NCZM_NC4=2, /* Netcdf-4 file based implementation */
|
||||
NCZM_FILE=3, /* File system directory-based implementation */
|
||||
NCZM_FILE=1, /* File system directory-based implementation */
|
||||
NCZM_ZIP=2, /* Zip-file based implementation */
|
||||
NCZM_S3=3, /* Amazon S3 implementation */
|
||||
} NCZM_IMPL;
|
||||
|
||||
/* Define the default map implementation */
|
||||
#define NCZM_DEFAULT NCZM_NC4
|
||||
#define NCZM_DEFAULT NCZM_ZIP
|
||||
|
||||
/* Define the per-implementation limitations flags */
|
||||
typedef size64_t NCZM_PROPERTIES;
|
||||
/* powers of 2 */
|
||||
#define NCZM_UNIMPLEMENTED 1 /* Unknown/ unimplemented */
|
||||
#define NCZM_WRITEONCE 2 /* Objects can only be written once */
|
||||
#define NCZM_ZEROSTART 4 /* Objects can only be written using a start count of zero */
|
||||
|
||||
/*
|
||||
For each dataset, we create what amounts to a class
|
||||
@ -139,39 +180,62 @@ typedef struct NCZMAP {
|
||||
NCZM_IMPL format;
|
||||
char* url;
|
||||
int mode;
|
||||
size64_t flags;
|
||||
size64_t flags; /* Passed in by caller */
|
||||
struct NCZMAP_API* api;
|
||||
} NCZMAP;
|
||||
|
||||
/* zmap_s3sdk related-types and constants */
|
||||
|
||||
#define AWSHOST ".amazonaws.com"
|
||||
|
||||
enum URLFORMAT {UF_NONE=0, UF_VIRTUAL=1, UF_PATH=2, UF_OTHER=3};
|
||||
|
||||
typedef struct ZS3INFO {
|
||||
enum URLFORMAT urlformat;
|
||||
char* host; /* non-null if other*/
|
||||
char* region; /* region */
|
||||
char* bucket; /* bucket name */
|
||||
char* rootkey;
|
||||
} ZS3INFO;
|
||||
|
||||
/* Forward */
|
||||
struct NClist;
|
||||
|
||||
/* Define the object-level API */
|
||||
|
||||
struct NCZMAP_API {
|
||||
int version;
|
||||
|
||||
/* Map Operations */
|
||||
int (*close)(NCZMAP* map, int deleteit);
|
||||
/* Object Operations */
|
||||
int (*exists)(NCZMAP* map, const char* key);
|
||||
int (*len)(NCZMAP* map, const char* key, size64_t* sizep);
|
||||
int (*defineobj)(NCZMAP* map, const char* key);
|
||||
int (*read)(NCZMAP* map, const char* key, size64_t start, size64_t count, void* content);
|
||||
int (*write)(NCZMAP* map, const char* key, size64_t start, size64_t count, const void* content);
|
||||
int (*search)(NCZMAP* map, const char* prefix, NClist* matches);
|
||||
int (*search)(NCZMAP* map, const char* prefix, struct NClist* matches);
|
||||
};
|
||||
|
||||
/* Define the Dataset level API */
|
||||
typedef struct NCZMAP_DS_API {
|
||||
int version;
|
||||
int (*create)(const char *path, int mode, size64_t flags, void* parameters, NCZMAP** mapp);
|
||||
int (*open)(const char *path, int mode, size64_t flags, void* parameters, NCZMAP** mapp);
|
||||
NCZM_PROPERTIES properties;
|
||||
int (*create)(const char *path, int mode, size64_t constraints, void* parameters, NCZMAP** mapp);
|
||||
int (*open)(const char *path, int mode, size64_t constraints, void* parameters, NCZMAP** mapp);
|
||||
} NCZMAP_DS_API;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Get limitations of a particular implementation.
|
||||
@param impl -- the map implemenation type
|
||||
@param limitsp return limitation flags here
|
||||
@return NC_NOERR if the operation succeeded
|
||||
@return NC_EXXX if the operation failed for one of several possible reasons
|
||||
*/
|
||||
EXTERNL NCZM_PROPERTIES nczmap_properties(NCZM_IMPL);
|
||||
|
||||
/* Object API Wrappers; note that there are no group operations
|
||||
because group keys do not map to directories.
|
||||
*/
|
||||
@ -181,7 +245,7 @@ Check if a specified content-bearing object exists or not.
|
||||
@param map -- the containing map
|
||||
@param key -- the key specifying the content-bearing object
|
||||
@return NC_NOERR if the object exists
|
||||
@return NC_ENOTFOUND if the object does not exist
|
||||
@return NC_EEMPTY if the object is not content bearing.
|
||||
@return NC_EXXX if the operation failed for one of several possible reasons
|
||||
*/
|
||||
EXTERNL int nczmap_exists(NCZMAP* map, const char* key);
|
||||
@ -192,21 +256,11 @@ Return the current size of a specified content-bearing object exists or not.
|
||||
@param key -- the key specifying the content-bearing object
|
||||
@param sizep -- the object's size is returned thru this pointer.
|
||||
@return NC_NOERR if the object exists
|
||||
@return NC_ENOTFOUND if the object does not exist
|
||||
@return NC_EEMPTY if the object is not content bearing
|
||||
@return NC_EXXX if the operation failed for one of several possible reasons
|
||||
*/
|
||||
EXTERNL int nczmap_len(NCZMAP* map, const char* key, size64_t* sizep);
|
||||
|
||||
/**
|
||||
Create a specified content-bearing object.
|
||||
@param map -- the containing map
|
||||
@param key -- the key specifying the content-bearing object
|
||||
@return NC_NOERR if the object is created
|
||||
@return NC_ENOTFOUND if the object does not exist
|
||||
@return NC_EXXX if the operation failed for one of several possible reasons
|
||||
*/
|
||||
EXTERNL int nczmap_defineobj(NCZMAP* map, const char* key);
|
||||
|
||||
/**
|
||||
Read the content of a specified content-bearing object.
|
||||
@param map -- the containing map
|
||||
@ -215,7 +269,7 @@ Read the content of a specified content-bearing object.
|
||||
@param count -- number of bytes to read
|
||||
@param content -- read the data into this memory
|
||||
@return NC_NOERR if the operation succeeded
|
||||
@return NC_ENOTFOUND if the object does not exist
|
||||
@return NC_EEMPTY if the object is not content-bearing.
|
||||
@return NC_EXXX if the operation failed for one of several possible reasons
|
||||
*/
|
||||
EXTERNL int nczmap_read(NCZMAP* map, const char* key, size64_t start, size64_t count, void* content);
|
||||
@ -228,55 +282,57 @@ Write the content of a specified content-bearing object.
|
||||
@param count -- number of bytes to write
|
||||
@param content -- write the data from this memory
|
||||
@return NC_NOERR if the operation succeeded
|
||||
@return NC_ENOTFOUND if the object does not exist
|
||||
@return NC_EXXX if the operation failed for one of several possible reasons
|
||||
Note that this makes the key a content-bearing object.
|
||||
*/
|
||||
EXTERNL int nczmap_write(NCZMAP* map, const char* key, size64_t start, size64_t count, const void* content);
|
||||
|
||||
/**
|
||||
Return a vector of keys representing the content-bearing
|
||||
objects that are immediately contained by the prefix key.
|
||||
Return a vector of names (not keys) representing the
|
||||
next segment of legal objects that are immediately contained by the prefix key.
|
||||
@param map -- the containing map
|
||||
@param prefix -- the key into the tree where the search is to occur
|
||||
@param matches -- return the set of keys in this list
|
||||
@param matches -- return the set of names in this list; might be empty
|
||||
@return NC_NOERR if the operation succeeded
|
||||
@return NC_EXXX if the operation failed for one of several possible reasons
|
||||
*/
|
||||
EXTERNL int nczmap_search(NCZMAP* map, const char* prefix, NClist* matches);
|
||||
EXTERNL int nczmap_search(NCZMAP* map, const char* prefix, struct NClist* matches);
|
||||
|
||||
/**
|
||||
Close a map
|
||||
@param map -- the map to close
|
||||
@param deleteit-- if true, then delete the corresponding dataset
|
||||
@return NC_NOERR if the operation succeeded
|
||||
@return NC_ENOTFOUND if the object does not exist
|
||||
@return NC_EXXX if the operation failed for one of several possible reasons
|
||||
*/
|
||||
EXTERNL int nczmap_close(NCZMAP* map, int deleteit);
|
||||
|
||||
/* Create/open and control a dataset using a specific implementation */
|
||||
EXTERNL int nczmap_create(NCZM_IMPL impl, const char *path, int mode, size64_t flags, void* parameters, NCZMAP** mapp);
|
||||
EXTERNL int nczmap_open(NCZM_IMPL impl, const char *path, int mode, size64_t flags, void* parameters, NCZMAP** mapp);
|
||||
EXTERNL int nczmap_create(NCZM_IMPL impl, const char *path, int mode, size64_t constraints, void* parameters, NCZMAP** mapp);
|
||||
EXTERNL int nczmap_open(NCZM_IMPL impl, const char *path, int mode, size64_t constraints, void* parameters, NCZMAP** mapp);
|
||||
|
||||
/* Utility functions */
|
||||
|
||||
/** Split a path into pieces along '/' character; elide any leading '/' */
|
||||
EXTERNL int nczm_split(const char* path, NClist* segments);
|
||||
EXTERNL int nczm_split(const char* path, struct NClist* segments);
|
||||
|
||||
/* Split a path into pieces along some character; elide any leading char */
|
||||
EXTERNL int nczm_split_delim(const char* path, char delim, NClist* segments);
|
||||
EXTERNL int nczm_split_delim(const char* path, char delim, struct NClist* segments);
|
||||
|
||||
/* Convenience: Join all segments into a path using '/' character */
|
||||
EXTERNL int nczm_join(NClist* segments, char** pathp);
|
||||
EXTERNL int nczm_join(struct NClist* segments, char** pathp);
|
||||
|
||||
/* Convenience: Join all segments into a path using '/' character
|
||||
but taking possible lead windows drive letter into account
|
||||
*/
|
||||
EXTERNL int nczm_joinpath(NClist* segments, char** pathp);
|
||||
EXTERNL int nczm_joinpath(struct NClist* segments, char** pathp);
|
||||
|
||||
/* Convenience: concat two strings; caller frees */
|
||||
/* Convenience: concat two strings with '/' between; caller frees */
|
||||
EXTERNL int nczm_concat(const char* prefix, const char* suffix, char** pathp);
|
||||
|
||||
/* Convenience: concat multiple strings with no intermediate separators; caller frees */
|
||||
EXTERNL int nczm_appendn(char** resultp, int n, ...);
|
||||
|
||||
/* Break a key into prefix and suffix, where prefix is the first nsegs segments;
|
||||
nsegs can be negative to specify that suffix is |nsegs| long
|
||||
*/
|
||||
@ -290,7 +346,16 @@ EXTERNL int nczm_isabsolutepath(const char* path);
|
||||
|
||||
/* Convert forward to back slash if needed */
|
||||
EXTERNL int nczm_localize(const char* path, char** newpathp, int local);
|
||||
|
||||
EXTERNL int nczm_canonicalpath(const char* path, char** cpathp);
|
||||
EXTERNL int nczm_basename(const char* path, char** basep);
|
||||
EXTERNL int nczm_segment1(const char* path, char** seg1p);
|
||||
|
||||
/* bubble sorts (note arguments) */
|
||||
EXTERNL void nczm_sortlist(struct NClist* l);
|
||||
EXTERNL void nczm_sortenvv(int n, char** envv);
|
||||
EXTERNL void NCZ_freeenvv(int n, char** envv);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -122,7 +122,6 @@ static NCZMAP_API zapi;
|
||||
static int zfileclose(NCZMAP* map, int delete);
|
||||
static int zfcreategroup(ZFMAP*, const char* key, int nskip);
|
||||
static int zflookupobj(ZFMAP*, const char* key, FD* fd);
|
||||
static int zfcreateobj(ZFMAP*, const char* key,FD*);
|
||||
static int zfparseurl(const char* path0, NCURI** urip);
|
||||
static int zffullpath(ZFMAP* zfmap, const char* key, char**);
|
||||
static void zfrelease(ZFMAP* zfmap, FD* fd);
|
||||
@ -160,7 +159,7 @@ static void zfinitialize(void)
|
||||
if(sscanf(env,"%d",&perms) == 1) NC_DEFAULT_DIR_PERMS = perms;
|
||||
}
|
||||
zfinitialized = 1;
|
||||
ZUNTRACE(NC_NOERR);
|
||||
(void)ZUNTRACE(NC_NOERR);
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,9 +188,7 @@ zfilecreate(const char *path, int mode, size64_t flags, void* parameters, NCZMAP
|
||||
if(!zfinitialized) zfinitialize();
|
||||
|
||||
/* Fixup mode flags */
|
||||
mode = (NC_NETCDF4 | NC_WRITE | mode);
|
||||
if(flags & FLAG_BYTERANGE)
|
||||
mode &= ~(NC_CLOBBER | NC_WRITE);
|
||||
mode |= (NC_NETCDF4 | NC_WRITE);
|
||||
|
||||
if(!(mode & NC_WRITE))
|
||||
{stat = NC_EPERM; goto done;}
|
||||
@ -267,8 +264,6 @@ zfileopen(const char *path, int mode, size64_t flags, void* parameters, NCZMAP**
|
||||
|
||||
/* Fixup mode flags */
|
||||
mode = (NC_NETCDF4 | mode);
|
||||
if(flags & FLAG_BYTERANGE)
|
||||
mode &= ~(NC_CLOBBER | NC_WRITE);
|
||||
|
||||
/* path must be a url with file: protocol*/
|
||||
if((stat=zfparseurl(path,&url)))
|
||||
@ -292,12 +287,8 @@ zfileopen(const char *path, int mode, size64_t flags, void* parameters, NCZMAP**
|
||||
truepath = NULL;
|
||||
|
||||
/* Verify root dir exists */
|
||||
switch (stat = platformopendir(zfmap,zfmap->root)) {
|
||||
case NC_NOERR: break;
|
||||
case NC_ENOTFOUND: stat = NC_EEMPTY; /* fall thru */
|
||||
default:
|
||||
if((stat = platformopendir(zfmap,zfmap->root)))
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Dataset superblock will be read by higher layer */
|
||||
|
||||
@ -357,49 +348,13 @@ done:
|
||||
return ZUNTRACEX(stat,"len=%llu",(lenp?*lenp:777777777777));
|
||||
}
|
||||
|
||||
static int
|
||||
zfiledefineobj(NCZMAP* map, const char* key)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
FD fd = FDNUL;
|
||||
ZFMAP* zfmap = (ZFMAP*)map; /* cast to true type */
|
||||
|
||||
ZTRACE(5,"map=%s key=%s",map->url,key);
|
||||
|
||||
#ifdef VERIFY
|
||||
if(!verify(key,!FLAG_ISDIR))
|
||||
assert(!"expected file, have dir");
|
||||
#endif
|
||||
|
||||
/* Create the intermediate groups as directories */
|
||||
if((stat = zfcreategroup(zfmap,key,SKIPLAST)))
|
||||
goto done;
|
||||
stat = zflookupobj(zfmap,key,&fd);
|
||||
zfrelease(zfmap,&fd);
|
||||
switch (stat) {
|
||||
case NC_NOERR: /* Already exists */
|
||||
goto done;
|
||||
case NC_ENOTFOUND: stat = NC_EEMPTY; /* file does not exist */
|
||||
case NC_EEMPTY: /* empty */
|
||||
if((stat = zfcreateobj(zfmap,key,&fd)))
|
||||
goto done;
|
||||
break;
|
||||
default:
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
zfrelease(zfmap,&fd);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
static int
|
||||
zfileread(NCZMAP* map, const char* key, size64_t start, size64_t count, void* content)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
FD fd = FDNUL;
|
||||
ZFMAP* zfmap = (ZFMAP*)map; /* cast to true type */
|
||||
|
||||
|
||||
ZTRACE(5,"map=%s key=%s start=%llu count=%llu",map->url,key,start,count);
|
||||
|
||||
#ifdef VERIFY
|
||||
@ -428,6 +383,7 @@ zfilewrite(NCZMAP* map, const char* key, size64_t start, size64_t count, const v
|
||||
int stat = NC_NOERR;
|
||||
FD fd = FDNUL;
|
||||
ZFMAP* zfmap = (ZFMAP*)map; /* cast to true type */
|
||||
char* truepath = NULL;
|
||||
|
||||
ZTRACE(5,"map=%s key=%s start=%llu count=%llu",map->url,key,start,count);
|
||||
|
||||
@ -437,16 +393,24 @@ zfilewrite(NCZMAP* map, const char* key, size64_t start, size64_t count, const v
|
||||
#endif
|
||||
|
||||
switch (stat = zflookupobj(zfmap,key,&fd)) {
|
||||
case NC_ENOTFOUND:
|
||||
case NC_EEMPTY:
|
||||
/* Create the directories leading to this */
|
||||
if((stat = zfcreategroup(zfmap,key,SKIPLAST))) goto done;
|
||||
/* Create truepath */
|
||||
if((stat = zffullpath(zfmap,key,&truepath))) goto done;
|
||||
/* Create file */
|
||||
if((stat = platformcreatefile(zfmap,truepath,&fd))) goto done;
|
||||
/* Fall thru to write the object */
|
||||
case NC_NOERR:
|
||||
if((stat = platformseek(zfmap, &fd, SEEK_SET, &start))) goto done;
|
||||
if((stat = platformwrite(zfmap, &fd, count, content))) goto done;
|
||||
break;
|
||||
case NC_ENOTFOUND: stat = NC_EEMPTY;
|
||||
case NC_EEMPTY: break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
done:
|
||||
nullfree(truepath);
|
||||
zfrelease(zfmap,&fd);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
@ -473,7 +437,7 @@ zfileclose(NCZMAP* map, int delete)
|
||||
}
|
||||
|
||||
/*
|
||||
Return a list of keys immediately "below" a specified prefix key.
|
||||
Return a list of names immediately "below" a specified prefix key.
|
||||
In theory, the returned list should be sorted in lexical order,
|
||||
but it possible that it is not.
|
||||
The prefix key is not included.
|
||||
@ -482,21 +446,18 @@ int
|
||||
zfilesearch(NCZMAP* map, const char* prefixkey, NClist* matches)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
int i;
|
||||
ZFMAP* zfmap = (ZFMAP*)map;
|
||||
char* truepath = NULL;
|
||||
NClist* nextlevel = nclistnew();
|
||||
NCbytes* buf = ncbytesnew();
|
||||
int trailing;
|
||||
|
||||
ZTRACE(5,"map=%s prefixkey=%s",map->url,prefixkey);
|
||||
|
||||
/* Make the root path be true */
|
||||
if(prefixkey == NULL || strlen(prefixkey)==0 || strcmp(prefixkey,"/")==0)
|
||||
truepath = strdup(zfmap->root);
|
||||
truepath = strdup(zfmap->root);
|
||||
else if((stat = nczm_concat(zfmap->root,prefixkey,&truepath))) goto done;
|
||||
|
||||
trailing = (prefixkey[strlen(prefixkey)-1] == '/');
|
||||
/* get names of the next level path entries */
|
||||
switch (stat = platformdircontent(zfmap, truepath, nextlevel)) {
|
||||
case NC_NOERR: /* ok */
|
||||
@ -508,12 +469,9 @@ zfilesearch(NCZMAP* map, const char* prefixkey, NClist* matches)
|
||||
default:
|
||||
goto done;
|
||||
}
|
||||
for(i=0;i<nclistlength(nextlevel);i++) {
|
||||
const char* segment = nclistget(nextlevel,i);
|
||||
ncbytescat(buf,prefixkey);
|
||||
if(!trailing) ncbytescat(buf,"/");
|
||||
ncbytescat(buf,segment);
|
||||
nclistpush(matches,ncbytesextract(buf));
|
||||
while(nclistlength(nextlevel) > 0) {
|
||||
char* segment = nclistremove(nextlevel,0);
|
||||
nclistpush(matches,segment);
|
||||
}
|
||||
|
||||
done:
|
||||
@ -594,42 +552,15 @@ zfrelease(ZFMAP* zfmap, FD* fd)
|
||||
{
|
||||
ZTRACE(5,"map=%s fd=%d",zfmap->map.url,(fd?fd->fd:-1));
|
||||
platformrelease(zfmap,fd);
|
||||
ZUNTRACE(NC_NOERR);
|
||||
}
|
||||
|
||||
/* Create an object file corresponding to a key; create any
|
||||
necessary intermediate groups. Assumed that we actually
|
||||
want to create this as a file.
|
||||
*/
|
||||
static int
|
||||
zfcreateobj(ZFMAP* zfmap, const char* key, FD* fd)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
char* fullpath = NULL;
|
||||
|
||||
ZTRACE(5,"map=%s key=%s",zfmap->map.url,key);
|
||||
|
||||
#ifdef VERIFY
|
||||
if(!verify(key,!FLAG_ISDIR))
|
||||
assert(!"expected file, have dir");
|
||||
#endif
|
||||
|
||||
/* Create all the prefix groups as directories */
|
||||
if((stat = zfcreategroup(zfmap, key, SKIPLAST))) goto done;
|
||||
/* Create the final object */
|
||||
if((stat=zffullpath(zfmap,key,&fullpath))) goto done;
|
||||
if((stat = platformcreatefile(zfmap,fullpath,fd)))
|
||||
goto done;
|
||||
done:
|
||||
nullfree(fullpath);
|
||||
return ZUNTRACE(stat);
|
||||
(void)ZUNTRACE(NC_NOERR);
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
/* External API objects */
|
||||
|
||||
NCZMAP_DS_API zmap_nzf = {
|
||||
NCZMAP_DS_API zmap_file = {
|
||||
NCZM_FILE_V1,
|
||||
0,
|
||||
zfilecreate,
|
||||
zfileopen,
|
||||
};
|
||||
@ -639,7 +570,6 @@ static NCZMAP_API zapi = {
|
||||
zfileclose,
|
||||
zfileexists,
|
||||
zfilelen,
|
||||
zfiledefineobj,
|
||||
zfileread,
|
||||
zfilewrite,
|
||||
zfilesearch,
|
||||
@ -1224,7 +1154,7 @@ platformrelease(ZFMAP* zfmap, FD* fd)
|
||||
ZTRACE(6,"map=%s fd=%d",zfmap->map.url,(fd?fd->fd:-1));
|
||||
if(fd->fd >=0) NCclose(fd->fd);
|
||||
fd->fd = -1;
|
||||
ZUNTRACE(NC_NOERR);
|
||||
(void)ZUNTRACE(NC_NOERR);
|
||||
}
|
||||
|
||||
#if 0
|
@ -38,42 +38,25 @@ Notes:
|
||||
|
||||
#define NCZM_S3SDK_V1 1
|
||||
|
||||
#define AWSHOST ".amazonaws.com"
|
||||
|
||||
enum URLFORMAT {UF_NONE, UF_VIRTUAL, UF_PATH, UF_OTHER};
|
||||
#define ZS3_PROPERTIES (0)
|
||||
|
||||
/* Define the "subclass" of NCZMAP */
|
||||
typedef struct ZS3MAP {
|
||||
NCZMAP map;
|
||||
enum URLFORMAT urlformat;
|
||||
char* host; /* non-null if other*/
|
||||
char* region; /* region */
|
||||
ZS3INFO s3;
|
||||
void* s3config;
|
||||
void* s3client;
|
||||
char* errmsg;
|
||||
char* bucket; /* bucket name */
|
||||
char* rootkey;
|
||||
} ZS3MAP;
|
||||
|
||||
/* Forward */
|
||||
static NCZMAP_API nczs3sdkapi; // c++ will not allow static forward variables
|
||||
static int zs3exists(NCZMAP* map, const char* key);
|
||||
static int zs3len(NCZMAP* map, const char* key, size64_t* lenp);
|
||||
static int zs3defineobj(NCZMAP* map, const char* key);
|
||||
static int zs3read(NCZMAP* map, const char* key, size64_t start, size64_t count, void* content);
|
||||
static int zs3write(NCZMAP* map, const char* key, size64_t start, size64_t count, const void* content);
|
||||
static int zs3search(NCZMAP* map, const char* prefix, NClist* matches);
|
||||
|
||||
static int zs3close(NCZMAP* map, int deleteit);
|
||||
static int z3createobj(ZS3MAP*, const char* key);
|
||||
|
||||
static int processurl(ZS3MAP* z3map, NCURI* url);
|
||||
static int endswith(const char* s, const char* suffix);
|
||||
static void freevector(size_t nkeys, char** list);
|
||||
|
||||
static void zs3initialize(void);
|
||||
static int s3clear(ZS3MAP* z3map, const char* key);
|
||||
static int isLegalBucketName(const char* bucket);
|
||||
|
||||
static int maketruekey(const char* rootpath, const char* key, char** truekeyp);
|
||||
|
||||
@ -109,9 +92,12 @@ static int zs3initialized = 0;
|
||||
static void
|
||||
zs3initialize(void)
|
||||
{
|
||||
if(!zs3initialized)
|
||||
if(!zs3initialized) {
|
||||
ZTRACE(7,NULL);
|
||||
NCZ_s3sdkinitialize();
|
||||
zs3initialized = 1;
|
||||
zs3initialized = 1;
|
||||
(void)ZUNTRACE(NC_NOERR);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
@ -136,7 +122,7 @@ zs3create(const char *path, int mode, size64_t flags, void* parameters, NCZMAP**
|
||||
NC_UNUSED(flags);
|
||||
NC_UNUSED(parameters);
|
||||
|
||||
ZTRACE(1,"%s:",__func__);
|
||||
ZTRACE(6,"path=%s mode=%d flag=%llu",path,mode,flags);
|
||||
|
||||
if(!zs3initialized) zs3initialize();
|
||||
|
||||
@ -156,32 +142,35 @@ zs3create(const char *path, int mode, size64_t flags, void* parameters, NCZMAP**
|
||||
{stat = NC_EURL; goto done;}
|
||||
|
||||
/* Convert to canonical path-style */
|
||||
if((stat = processurl(z3map,url))) goto done;
|
||||
if((stat = NCZ_s3urlprocess(url,&z3map->s3))) goto done;
|
||||
/* Verify the root path */
|
||||
if(z3map->s3.rootkey == NULL)
|
||||
{stat = NC_EURL; goto done;}
|
||||
|
||||
if((stat=NCZ_s3sdkcreateconfig(z3map->host, z3map->region, &z3map->s3config))) goto done;
|
||||
if((stat=NCZ_s3sdkcreateconfig(z3map->s3.host, z3map->s3.region, &z3map->s3config))) goto done;
|
||||
if((stat = NCZ_s3sdkcreateclient(z3map->s3config,&z3map->s3client))) goto done;
|
||||
|
||||
{
|
||||
int exists = 0;
|
||||
/* Does bucket already exist */
|
||||
if((stat = NCZ_s3sdkbucketexists(z3map->s3client,z3map->bucket,&exists, &z3map->errmsg))) goto done;
|
||||
if((stat = NCZ_s3sdkbucketexists(z3map->s3client,z3map->s3.bucket,&exists, &z3map->errmsg))) goto done;
|
||||
if(!exists) {
|
||||
/* create it */
|
||||
if((stat = NCZ_s3sdkbucketcreate(z3map->s3client,z3map->region,z3map->bucket,&z3map->errmsg)))
|
||||
if((stat = NCZ_s3sdkbucketcreate(z3map->s3client,z3map->s3.region,z3map->s3.bucket,&z3map->errmsg)))
|
||||
goto done;
|
||||
}
|
||||
/* The root object should not exist */
|
||||
switch (stat = NCZ_s3sdkinfo(z3map->s3client,z3map->bucket,z3map->rootkey,NULL,&z3map->errmsg)) {
|
||||
switch (stat = NCZ_s3sdkinfo(z3map->s3client,z3map->s3.bucket,z3map->s3.rootkey,NULL,&z3map->errmsg)) {
|
||||
case NC_EEMPTY: /* no such object */
|
||||
stat = NC_NOERR; /* which is what we want */
|
||||
errclear(z3map);
|
||||
break;
|
||||
case NC_NOERR: stat = NC_EEXIST; goto done; /* already exists */
|
||||
case NC_NOERR: stat = NC_EFOUND; goto done; /* already exists */
|
||||
default: reporterr(z3map); goto done;
|
||||
}
|
||||
if(!stat) {
|
||||
/* Delete objects inside root object tree */
|
||||
s3clear(z3map,z3map->rootkey);
|
||||
s3clear(z3map,z3map->s3.rootkey);
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,7 +182,7 @@ done:
|
||||
nullfree(prefix);
|
||||
nullfree(truekey);
|
||||
if(stat) nczmap_close((NCZMAP*)z3map,1);
|
||||
return (stat);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
/* The problem with open is that there
|
||||
@ -212,7 +201,7 @@ zs3open(const char *path, int mode, size64_t flags, void* parameters, NCZMAP** m
|
||||
NC_UNUSED(flags);
|
||||
NC_UNUSED(parameters);
|
||||
|
||||
ZTRACE(1,"%s: ",__func__);
|
||||
ZTRACE(6,"path=%s mode=%d flags=%llu",path,mode,flags);
|
||||
|
||||
if(!zs3initialized) zs3initialize();
|
||||
|
||||
@ -232,21 +221,23 @@ zs3open(const char *path, int mode, size64_t flags, void* parameters, NCZMAP** m
|
||||
{stat = NC_EURL; goto done;}
|
||||
|
||||
/* Convert to canonical path-style */
|
||||
if((stat = processurl(z3map,url))) goto done;
|
||||
if((stat = NCZ_s3urlprocess(url,&z3map->s3))) goto done;
|
||||
/* Verify root path */
|
||||
if(z3map->s3.rootkey == NULL)
|
||||
{stat = NC_EURL; goto done;}
|
||||
|
||||
if((stat=NCZ_s3sdkcreateconfig(z3map->host,z3map->region,&z3map->s3config))) goto done;
|
||||
if((stat=NCZ_s3sdkcreateconfig(z3map->s3.host,z3map->s3.region,&z3map->s3config))) goto done;
|
||||
if((stat=NCZ_s3sdkcreateclient(z3map->s3config,&z3map->s3client))) goto done;
|
||||
|
||||
/* Search the root for content */
|
||||
content = nclistnew();
|
||||
if((stat = NCZ_s3sdkgetkeys(z3map->s3client,z3map->bucket,z3map->rootkey,&nkeys,NULL,&z3map->errmsg)))
|
||||
if((stat = NCZ_s3sdkgetkeys(z3map->s3client,z3map->s3.bucket,z3map->s3.rootkey,&nkeys,NULL,&z3map->errmsg)))
|
||||
goto done;
|
||||
if(nkeys == 0) {
|
||||
/* dataset does not actually exist */
|
||||
stat = NC_EEMPTY;
|
||||
/* dataset does not actually exist; we choose to return ENOTFOUND instead of EEMPTY */
|
||||
stat = NC_ENOTFOUND;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if(mapp) *mapp = (NCZMAP*)z3map;
|
||||
|
||||
done:
|
||||
@ -254,41 +245,12 @@ done:
|
||||
nclistfreeall(content);
|
||||
ncurifree(url);
|
||||
if(stat) nczmap_close((NCZMAP*)z3map,0);
|
||||
return (stat);
|
||||
}
|
||||
|
||||
static int
|
||||
isLegalBucketName(const char* bucket)
|
||||
{
|
||||
return 1; /*TBD*/
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
/* Object API */
|
||||
|
||||
static int
|
||||
zs3close(NCZMAP* map, int deleteit)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
ZS3MAP* z3map = (ZS3MAP*)map;
|
||||
|
||||
ZTRACE(1,"%s: ",__func__);
|
||||
if(deleteit)
|
||||
s3clear(z3map,z3map->rootkey);
|
||||
NCZ_s3sdkclose(z3map->s3client, z3map->s3config, z3map->bucket, z3map->rootkey, deleteit, &z3map->errmsg);
|
||||
reporterr(z3map);
|
||||
z3map->s3client = NULL;
|
||||
z3map->s3config = NULL;
|
||||
nullfree(z3map->bucket);
|
||||
nullfree(z3map->region);
|
||||
nullfree(z3map->host);
|
||||
nullfree(z3map->errmsg);
|
||||
nullfree(z3map->rootkey)
|
||||
nczm_clear(map);
|
||||
nullfree(map);
|
||||
return (stat);
|
||||
}
|
||||
|
||||
/*
|
||||
@return NC_NOERR if key points to a content-bearing object.
|
||||
@return NC_EEMPTY if object at key has no content.
|
||||
@ -297,7 +259,10 @@ zs3close(NCZMAP* map, int deleteit)
|
||||
static int
|
||||
zs3exists(NCZMAP* map, const char* key)
|
||||
{
|
||||
return zs3len(map,key,NULL);
|
||||
int stat = NC_NOERR;
|
||||
ZTRACE(6,"map=%s key=%s",map->url,key);
|
||||
stat = zs3len(map,key,NULL);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -312,11 +277,11 @@ zs3len(NCZMAP* map, const char* key, size64_t* lenp)
|
||||
ZS3MAP* z3map = (ZS3MAP*)map;
|
||||
char* truekey = NULL;
|
||||
|
||||
ZTRACE(1,"%s: ",__func__);
|
||||
ZTRACE(6,"map=%s key=%s",map->url,key);
|
||||
|
||||
if((stat = maketruekey(z3map->rootkey,key,&truekey))) goto done;
|
||||
if((stat = maketruekey(z3map->s3.rootkey,key,&truekey))) goto done;
|
||||
|
||||
switch (stat = NCZ_s3sdkinfo(z3map->s3client,z3map->bucket,truekey,lenp,&z3map->errmsg)) {
|
||||
switch (stat = NCZ_s3sdkinfo(z3map->s3client,z3map->s3.bucket,truekey,lenp,&z3map->errmsg)) {
|
||||
case NC_NOERR: break;
|
||||
case NC_EEMPTY:
|
||||
if(lenp) *lenp = 0;
|
||||
@ -327,36 +292,7 @@ zs3len(NCZMAP* map, const char* key, size64_t* lenp)
|
||||
done:
|
||||
nullfree(truekey);
|
||||
reporterr(z3map);
|
||||
return (stat);
|
||||
}
|
||||
|
||||
/*
|
||||
@return NC_NOERR if key points to a content-bearing object.
|
||||
@return NC_EEMPTY if object at key has no content, if so, then create
|
||||
a content-bearing object at that key.
|
||||
@return NC_EXXX return true error
|
||||
*/
|
||||
static int
|
||||
zs3defineobj(NCZMAP* map, const char* key)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
ZS3MAP* z3map = (ZS3MAP*)map; /* cast to true type */
|
||||
|
||||
ZTRACE(1,"%s: key=%s",__func__,key);
|
||||
|
||||
switch(stat = zs3exists(map,key)) {
|
||||
case NC_NOERR: goto done; /* Already exists */
|
||||
case NC_EEMPTY:
|
||||
if((stat = z3createobj(z3map,key)))
|
||||
goto done;
|
||||
break;
|
||||
default: /* Some other kind of failure */
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
reporterr(z3map);
|
||||
return (stat);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -371,12 +307,12 @@ zs3read(NCZMAP* map, const char* key, size64_t start, size64_t count, void* cont
|
||||
ZS3MAP* z3map = (ZS3MAP*)map; /* cast to true type */
|
||||
size64_t size = 0;
|
||||
char* truekey = NULL;
|
||||
|
||||
ZTRACE(1,"%s: key=%s",__func__,key);
|
||||
|
||||
if((stat = maketruekey(z3map->rootkey,key,&truekey))) goto done;
|
||||
|
||||
switch (stat=NCZ_s3sdkinfo(z3map->s3client, z3map->bucket, truekey, &size, &z3map->errmsg)) {
|
||||
ZTRACE(6,"map=%s key=%s start=%llu count=%llu",map->url,key,start,count);
|
||||
|
||||
if((stat = maketruekey(z3map->s3.rootkey,key,&truekey))) goto done;
|
||||
|
||||
switch (stat=NCZ_s3sdkinfo(z3map->s3client, z3map->s3.bucket, truekey, &size, &z3map->errmsg)) {
|
||||
case NC_NOERR: break;
|
||||
case NC_EEMPTY: goto done;
|
||||
default: goto done;
|
||||
@ -385,13 +321,13 @@ zs3read(NCZMAP* map, const char* key, size64_t start, size64_t count, void* cont
|
||||
if(start >= size || start+count > size)
|
||||
{stat = NC_EEDGE; goto done;}
|
||||
if(count > 0) {
|
||||
if((stat = NCZ_s3sdkread(z3map->s3client, z3map->bucket, truekey, start, count, content, &z3map->errmsg)))
|
||||
if((stat = NCZ_s3sdkread(z3map->s3client, z3map->s3.bucket, truekey, start, count, content, &z3map->errmsg)))
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
nullfree(truekey);
|
||||
reporterr(z3map);
|
||||
return (stat);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -404,54 +340,89 @@ zs3write(NCZMAP* map, const char* key, size64_t start, size64_t count, const voi
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
ZS3MAP* z3map = (ZS3MAP*)map; /* cast to true type */
|
||||
void* chunk = NULL;
|
||||
char* chunk = NULL; /* use char* so we can do arithmetic with it */
|
||||
size64_t objsize = 0;
|
||||
size64_t newsize = start+count;
|
||||
size64_t memsize = 0;
|
||||
size64_t endwrite = start+count; /* first pos just above overwritten data */
|
||||
char* truekey = NULL;
|
||||
int isempty = 0;
|
||||
|
||||
ZTRACE(1,"%s: key=%s",__func__,key);
|
||||
ZTRACE(6,"map=%s key=%s start=%llu count=%llu",map->url,key,start,count);
|
||||
|
||||
if(count == 0) {stat = NC_EEDGE; goto done;}
|
||||
|
||||
if((stat = maketruekey(z3map->rootkey,key,&truekey))) goto done;
|
||||
if((stat = maketruekey(z3map->s3.rootkey,key,&truekey))) goto done;
|
||||
|
||||
/* Apparently S3 has no write byterange operation, so we need to read the whole object,
|
||||
copy data, and then rewrite */
|
||||
switch (stat=NCZ_s3sdkinfo(z3map->s3client, z3map->bucket, truekey, &objsize, &z3map->errmsg)) {
|
||||
case NC_NOERR:
|
||||
newsize = (newsize > objsize ? newsize : objsize);
|
||||
switch (stat=NCZ_s3sdkinfo(z3map->s3client, z3map->s3.bucket, truekey, &objsize, &z3map->errmsg)) {
|
||||
case NC_NOERR: /* Figure out the memory size of the object */
|
||||
memsize = (endwrite > objsize ? endwrite : objsize);
|
||||
break;
|
||||
case NC_EEMPTY:
|
||||
newsize = newsize;
|
||||
memsize = endwrite;
|
||||
isempty = 1;
|
||||
break;
|
||||
default: reporterr(z3map); goto done;
|
||||
}
|
||||
chunk = malloc(newsize);
|
||||
|
||||
if(isempty)
|
||||
chunk = (char*)calloc(1,memsize); /* initialize it */
|
||||
else
|
||||
chunk = (char*)malloc(memsize);
|
||||
if(chunk == NULL)
|
||||
{stat = NC_ENOMEM; goto done;}
|
||||
if(objsize > 0) {
|
||||
if((stat = NCZ_s3sdkread(z3map->s3client, z3map->bucket, truekey, 0, objsize, chunk, &z3map->errmsg)))
|
||||
if(start > 0 && objsize > 0) { /* must read to preserve data before start */
|
||||
if((stat = NCZ_s3sdkread(z3map->s3client, z3map->s3.bucket, truekey, 0, objsize, (void*)chunk, &z3map->errmsg)))
|
||||
goto done;
|
||||
}
|
||||
#if 0
|
||||
if(newsize > objsize) {
|
||||
/* Zeroize the part of the object added */
|
||||
memset(((char*)chunk)+objsize,0,(newsize-objsize));
|
||||
objsize = newsize;
|
||||
}
|
||||
/* overwrite with the contents */
|
||||
memcpy(((char*)chunk)+start,content,count); /* remember there may be data above start+count */
|
||||
if((stat = NCZ_s3sdkwriteobject(z3map->s3client, z3map->bucket, truekey, objsize, chunk, &z3map->errmsg)))
|
||||
#endif
|
||||
/* overwrite the relevant part of the memory with the contents */
|
||||
if(count > 0)
|
||||
memcpy(((char*)chunk)+start,content,count); /* there may be data above start+count */
|
||||
/* (re-)write */
|
||||
if((stat = NCZ_s3sdkwriteobject(z3map->s3client, z3map->s3.bucket, truekey, memsize, (void*)chunk, &z3map->errmsg)))
|
||||
goto done;
|
||||
|
||||
done:
|
||||
nullfree(truekey);
|
||||
reporterr(z3map);
|
||||
nullfree(chunk);
|
||||
return (stat);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
static int
|
||||
zs3close(NCZMAP* map, int deleteit)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
ZS3MAP* z3map = (ZS3MAP*)map;
|
||||
|
||||
ZTRACE(6,"map=%s deleteit=%d",map->url, deleteit);
|
||||
|
||||
if(deleteit)
|
||||
s3clear(z3map,z3map->s3.rootkey);
|
||||
if(z3map->s3client && z3map->s3config && z3map->s3.bucket && z3map->s3.rootkey) {
|
||||
NCZ_s3sdkclose(z3map->s3client, z3map->s3config, z3map->s3.bucket, z3map->s3.rootkey, deleteit, &z3map->errmsg);
|
||||
}
|
||||
reporterr(z3map);
|
||||
z3map->s3client = NULL;
|
||||
z3map->s3config = NULL;
|
||||
nullfree(z3map->s3.bucket);
|
||||
nullfree(z3map->s3.region);
|
||||
nullfree(z3map->s3.host);
|
||||
nullfree(z3map->errmsg);
|
||||
nullfree(z3map->s3.rootkey)
|
||||
nczm_clear(map);
|
||||
nullfree(map);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
/*
|
||||
Return a list of keys immediately "below" a specified prefix,
|
||||
Return a list of full keys immediately "below" a specified prefix,
|
||||
but not including the prefix.
|
||||
In theory, the returned list should be sorted in lexical order,
|
||||
but it possible that it is not.
|
||||
@ -467,29 +438,27 @@ zs3search(NCZMAP* map, const char* prefix, NClist* matches)
|
||||
size_t nkeys;
|
||||
NClist* tmp = NULL;
|
||||
char* trueprefix = NULL;
|
||||
char* newkey = NULL;
|
||||
const char* p;
|
||||
|
||||
ZTRACE(1,"%s: prefix=%s",__func__,prefix);
|
||||
ZTRACE(6,"map=%s prefix0=%s",map->url,prefix);
|
||||
|
||||
if((stat = maketruekey(z3map->rootkey,prefix,&trueprefix))) goto done;
|
||||
if((stat = maketruekey(z3map->s3.rootkey,prefix,&trueprefix))) goto done;
|
||||
|
||||
if(*trueprefix != '/') return NC_EINTERNAL;
|
||||
if((stat = NCZ_s3sdkgetkeys(z3map->s3client,z3map->bucket,trueprefix,&nkeys,&list,&z3map->errmsg)))
|
||||
if((stat = NCZ_s3sdkgetkeys(z3map->s3client,z3map->s3.bucket,trueprefix,&nkeys,&list,&z3map->errmsg)))
|
||||
goto done;
|
||||
if(nkeys > 0) {
|
||||
size_t tplen = strlen(trueprefix);
|
||||
tmp = nclistnew();
|
||||
/* Remove the trueprefix from the front of all the returned keys */
|
||||
/* The returned keys may be of any depth, so capture and prune the keys */
|
||||
for(i=0;i<nkeys;i++) {
|
||||
char* newkey = NULL;
|
||||
if(memcmp(trueprefix,list[i],tplen)==0) {
|
||||
newkey = list[i];
|
||||
newkey = newkey+tplen; /* Point to start of suffix */
|
||||
const char* l = list[i];
|
||||
if(memcmp(trueprefix,l,tplen)==0) {
|
||||
p = l+tplen; /* Point to start of suffix */
|
||||
/* If the key is same as trueprefix, ignore it */
|
||||
if(*newkey == '\0') continue;
|
||||
newkey--; /* Point to trailing '/' */
|
||||
assert(newkey[0] == '/');
|
||||
newkey = strdup(newkey);
|
||||
if(*p == '\0') continue;
|
||||
if(nczm_segment1(p,&newkey)) goto done;
|
||||
nclistpush(tmp,newkey); newkey = NULL;
|
||||
}
|
||||
}
|
||||
@ -516,146 +485,17 @@ zs3search(NCZMAP* map, const char* prefix, NClist* matches)
|
||||
#endif
|
||||
|
||||
done:
|
||||
nullfree(newkey);
|
||||
nullfree(trueprefix);
|
||||
reporterr(z3map);
|
||||
nclistfreeall(tmp);
|
||||
freevector(nkeys,list);
|
||||
return THROW(stat);
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
/* Utilities */
|
||||
|
||||
static int
|
||||
processurl(ZS3MAP* z3map, NCURI* url)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
NClist* segments = NULL;
|
||||
NCbytes* buf = ncbytesnew();
|
||||
|
||||
if(url == NULL)
|
||||
{stat = NC_EURL; goto done;}
|
||||
/* do some verification */
|
||||
if(strcmp(url->protocol,"https") != 0)
|
||||
{stat = NC_EURL; goto done;}
|
||||
|
||||
/* Path better look absolute */
|
||||
if(!nczm_isabsolutepath(url->path))
|
||||
{stat = NC_EURL; goto done;}
|
||||
|
||||
/* Distinguish path-style from virtual-host style from other:
|
||||
Virtual: https://bucket-name.s3.Region.amazonaws.com/<root>
|
||||
Path: https://s3.Region.amazonaws.com/bucket-name/<root>
|
||||
Other: https://<host>/bucketname/<root>
|
||||
*/
|
||||
if(url->host == NULL || strlen(url->host) == 0)
|
||||
{stat = NC_EURL; goto done;}
|
||||
if(endswith(url->host,AWSHOST)) { /* Virtual or path */
|
||||
segments = nclistnew();
|
||||
/* split the hostname by "." */
|
||||
if((stat = nczm_split_delim(url->host,'.',segments))) goto done;
|
||||
switch (nclistlength(segments)) {
|
||||
default: stat = NC_EURL; goto done;
|
||||
case 4:
|
||||
if(strcasecmp(nclistget(segments,0),"s3")!=0)
|
||||
{stat = NC_EURL; goto done;}
|
||||
z3map->urlformat = UF_PATH;
|
||||
z3map->region = strdup(nclistget(segments,1));
|
||||
break;
|
||||
case 5:
|
||||
if(strcasecmp(nclistget(segments,1),"s3")!=0)
|
||||
{stat = NC_EURL; goto done;}
|
||||
z3map->urlformat = UF_VIRTUAL;
|
||||
z3map->region = strdup(nclistget(segments,2));
|
||||
z3map->bucket = strdup(nclistget(segments,0));
|
||||
break;
|
||||
}
|
||||
/* Rebuild host to look like path-style */
|
||||
ncbytescat(buf,"s3.");
|
||||
ncbytescat(buf,z3map->region);
|
||||
ncbytescat(buf,AWSHOST);
|
||||
z3map->host = ncbytesextract(buf);
|
||||
} else {
|
||||
z3map->urlformat = UF_OTHER;
|
||||
if((z3map->host = strdup(url->host))==NULL)
|
||||
{stat = NC_ENOMEM; goto done;}
|
||||
}
|
||||
/* Do fixups to make everything look like it was path style */
|
||||
switch (z3map->urlformat) {
|
||||
case UF_PATH:
|
||||
case UF_OTHER:
|
||||
/* We have to process the path to get the bucket, and remove it in the path */
|
||||
if(url->path != NULL && strlen(url->path) > 0) {
|
||||
/* split the path by "/" */
|
||||
nclistfreeall(segments);
|
||||
segments = nclistnew();
|
||||
if((stat = nczm_split_delim(url->path,'/',segments))) goto done;
|
||||
if(nclistlength(segments) == 0)
|
||||
{stat = NC_EURL; goto done;}
|
||||
z3map->bucket = ((char*)nclistremove(segments,0));
|
||||
if((stat = nczm_join(segments,&z3map->rootkey))) goto done;
|
||||
nclistfreeall(segments); segments = NULL;
|
||||
}
|
||||
break;
|
||||
case UF_VIRTUAL:
|
||||
z3map->rootkey = strdup(url->path);
|
||||
break;
|
||||
default: stat = NC_EURL; goto done;
|
||||
}
|
||||
/* Verify bucket name */
|
||||
if(z3map->bucket != NULL && !isLegalBucketName(z3map->bucket))
|
||||
{stat = NC_EURL; goto done;}
|
||||
/* Verify that this refers to an object that is below the bucket.
|
||||
That is, there must be at least one segment past the bucket in the path */
|
||||
nclistfreeall(segments);
|
||||
segments = nclistnew();
|
||||
if((stat = nczm_split_delim(z3map->rootkey,'/',segments))) goto done;
|
||||
if(nclistlength(segments) == 0)
|
||||
{stat = NC_EINTERNAL; goto done;} /* oops */
|
||||
|
||||
done:
|
||||
ncbytesfree(buf);
|
||||
nclistfreeall(segments);
|
||||
return stat;
|
||||
}
|
||||
|
||||
/* Create an object corresponding to a key
|
||||
@return NC_NOERR if key points to a content-bearing object already
|
||||
@return NC_EEMPTY if object at key has no content, if so, then create
|
||||
a content-bearing object at that key.
|
||||
@return NC_EXXX return true error
|
||||
*/
|
||||
static int
|
||||
z3createobj(ZS3MAP* z3map, const char* key)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
char* truekey = NULL;
|
||||
|
||||
if((stat = maketruekey(z3map->rootkey,key,&truekey))) goto done;
|
||||
stat = NCZ_s3sdkcreatekey(z3map->s3client, z3map->bucket, truekey, &z3map->errmsg);
|
||||
|
||||
done:
|
||||
nullfree(truekey);
|
||||
reporterr(z3map);
|
||||
return THROW(stat);
|
||||
return ZUNTRACEX(stat,"|matches|=%d",(int)nclistlength(matches));
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
/* S3 Utilities */
|
||||
|
||||
static int
|
||||
endswith(const char* s, const char* suffix)
|
||||
{
|
||||
ssize_t ls, lsf, delta;
|
||||
if(s == NULL || suffix == NULL) return 0;
|
||||
ls = strlen(s);
|
||||
lsf = strlen(suffix);
|
||||
delta = (ls - lsf);
|
||||
if(delta < 0) return 0;
|
||||
if(memcmp(s+delta,suffix,lsf)!=0) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Remove all objects with keys which have
|
||||
rootkey as prefix; rootkey is a truekey
|
||||
@ -668,17 +508,19 @@ s3clear(ZS3MAP* z3map, const char* rootkey)
|
||||
char** p;
|
||||
size_t nkeys = 0;
|
||||
|
||||
if((stat = NCZ_s3sdkgetkeys(z3map->s3client, z3map->bucket, rootkey, &nkeys, &list, &z3map->errmsg)))
|
||||
goto done;
|
||||
if(list != NULL) {
|
||||
for(p=list;*p;p++) {
|
||||
/* If the key is the rootkey, skip it */
|
||||
if(strcmp(rootkey,*p)==0) continue;
|
||||
if(z3map->s3client && z3map->s3.bucket && rootkey) {
|
||||
if((stat = NCZ_s3sdksearch(z3map->s3client, z3map->s3.bucket, rootkey, &nkeys, &list, &z3map->errmsg)))
|
||||
goto done;
|
||||
if(list != NULL) {
|
||||
for(p=list;*p;p++) {
|
||||
/* If the key is the rootkey, skip it */
|
||||
if(strcmp(rootkey,*p)==0) continue;
|
||||
#ifdef S3DEBUG
|
||||
fprintf(stderr,"s3clear: %s\n",*p);
|
||||
#endif
|
||||
if((stat = NCZ_s3sdkdeletekey(z3map->s3client, z3map->bucket, *p, &z3map->errmsg)))
|
||||
goto done;
|
||||
if((stat = NCZ_s3sdkdeletekey(z3map->s3client, z3map->s3.bucket, *p, &z3map->errmsg)))
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -736,6 +578,7 @@ freevector(size_t nkeys, char** list)
|
||||
NCZMAP_DS_API zmap_s3sdk;
|
||||
NCZMAP_DS_API zmap_s3sdk = {
|
||||
NCZM_S3SDK_V1,
|
||||
ZS3_PROPERTIES,
|
||||
zs3create,
|
||||
zs3open,
|
||||
};
|
||||
@ -746,7 +589,6 @@ nczs3sdkapi = {
|
||||
zs3close,
|
||||
zs3exists,
|
||||
zs3len,
|
||||
zs3defineobj,
|
||||
zs3read,
|
||||
zs3write,
|
||||
zs3search,
|
||||
|
769
libnczarr/zmap_zip.c
Executable file
769
libnczarr/zmap_zip.c
Executable file
@ -0,0 +1,769 @@
|
||||
/*
|
||||
* Copyright 2018, University Corporation for Atmospheric Research
|
||||
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
|
||||
*/
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
/* Not sure this has any effect */
|
||||
#define _LARGEFILE_SOURCE 1
|
||||
#define _LARGEFILE64_SOURCE 1
|
||||
|
||||
#include "zincludes.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <zip.h>
|
||||
|
||||
#include "fbits.h"
|
||||
#include "ncpathmgr.h"
|
||||
|
||||
#undef CACHESEARCH
|
||||
|
||||
#define VERIFY
|
||||
|
||||
/*Mnemonic*/
|
||||
#define FLAG_ISDIR 1
|
||||
#define FLAG_CREATE 1
|
||||
#define SKIPLAST 1
|
||||
#define WHOLEPATH 0
|
||||
|
||||
#define NCZM_ZIP_V1 1
|
||||
|
||||
#define ZIP_PROPERTIES (NCZM_WRITEONCE|NCZM_ZEROSTART)
|
||||
|
||||
/*
|
||||
Do a simple mapping of our simplified map model
|
||||
to a zip-file
|
||||
|
||||
Every dataset is assumed to be rooted at some directory in the
|
||||
zip file tree. So, its location is defined by some path to a
|
||||
zip file representing the dataset.
|
||||
|
||||
For the object API, the mapping is as follows:
|
||||
1. Every content-bearing object (e.g. .zgroup or .zarray) is mapped to a zip entry.
|
||||
This means that if a key points to a content bearing object then
|
||||
no other key can have that content bearing key as a suffix.
|
||||
2. The meta data containing files are assumed to contain
|
||||
UTF-8 character data.
|
||||
3. The chunk containing files are assumed to contain raw unsigned 8-bit byte data.
|
||||
4. The objects may or may not be compressed; this implementation writes uncompressed objects.
|
||||
*/
|
||||
|
||||
/* define the var name containing an objects content */
|
||||
#define ZCONTENT "data"
|
||||
|
||||
/* Define the "subclass" of NCZMAP */
|
||||
typedef struct ZZMAP {
|
||||
NCZMAP map;
|
||||
char* root;
|
||||
char* dataset; /* prefix for all keys in zip file */
|
||||
zip_t* archive;
|
||||
char** searchcache;
|
||||
} ZZMAP;
|
||||
|
||||
typedef zip_int64_t ZINDEX;;
|
||||
|
||||
/* Forward */
|
||||
static NCZMAP_API zapi;
|
||||
static int zipclose(NCZMAP* map, int delete);
|
||||
static int zzcreategroup(ZZMAP*, const char* key, int nskip);
|
||||
static int zzlookupobj(ZZMAP*, const char* key, ZINDEX* fd);
|
||||
static int zzlen(ZZMAP* zzmap, ZINDEX zindex, size64_t* lenp);
|
||||
static int zipmaperr(ZZMAP* zzmap);
|
||||
static int ziperr(zip_error_t* zerror);
|
||||
static int ziperrno(int zerror);
|
||||
static void freesearchcache(char** cache);
|
||||
|
||||
static int zzinitialized = 0;
|
||||
|
||||
static void
|
||||
zzinitialize(void)
|
||||
{
|
||||
if(!zzinitialized) {
|
||||
ZTRACE(7,NULL);
|
||||
zzinitialized = 1;
|
||||
(void)ZUNTRACE(NC_NOERR);
|
||||
}
|
||||
}
|
||||
|
||||
/* Define the Dataset level API */
|
||||
|
||||
/*
|
||||
@param datasetpath abs path in the file tree of the root of the dataset'
|
||||
might be a relative path.
|
||||
@param mode the netcdf-c mode flags
|
||||
@param flags extra flags
|
||||
@param flags extra parameters
|
||||
@param mapp return the map object in this
|
||||
*/
|
||||
|
||||
static int
|
||||
zipcreate(const char *path, int mode, size64_t flags, void* parameters, NCZMAP** mapp)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
char* truepath = NULL;
|
||||
char* dataset = NULL;
|
||||
ZZMAP* zzmap = NULL;
|
||||
NCURI* url = NULL;
|
||||
zip_flags_t zipflags = 0;
|
||||
int zerrno = ZIP_ER_OK;
|
||||
ZINDEX zindex = -1;
|
||||
|
||||
NC_UNUSED(parameters);
|
||||
ZTRACE(6,"path=%s mode=%d flag=%llu",path,mode,flags);
|
||||
|
||||
if(!zzinitialized) zzinitialize();
|
||||
|
||||
/* Fixup mode flags */
|
||||
mode = (NC_NETCDF4 | NC_WRITE | mode);
|
||||
|
||||
/* path must be a url with file: protocol*/
|
||||
ncuriparse(path,&url);
|
||||
if(url == NULL)
|
||||
{stat = NC_EURL; goto done;}
|
||||
if(strcasecmp(url->protocol,"file") != 0)
|
||||
{stat = NC_EURL; goto done;}
|
||||
|
||||
/* Canonicalize the root path */
|
||||
if((stat = nczm_canonicalpath(url->path,&truepath))) goto done;
|
||||
|
||||
/* Extract the dataset name */
|
||||
if((stat = nczm_basename(truepath,&dataset))) goto done;
|
||||
|
||||
/* Build the zz state */
|
||||
if((zzmap = calloc(1,sizeof(ZZMAP))) == NULL)
|
||||
{stat = NC_ENOMEM; goto done;}
|
||||
|
||||
zzmap->map.format = NCZM_ZIP;
|
||||
zzmap->map.url = ncuribuild(url,NULL,NULL,NCURIALL);
|
||||
zzmap->map.flags = flags;
|
||||
/* create => NC_WRITE */
|
||||
zzmap->map.mode = mode;
|
||||
zzmap->map.api = &zapi;
|
||||
zzmap->root = truepath;
|
||||
truepath = NULL;
|
||||
zzmap->dataset = dataset;
|
||||
dataset = NULL;
|
||||
|
||||
/* Set zip openflags */
|
||||
zipflags |= ZIP_CREATE;
|
||||
if(fIsSet(mode,NC_NOCLOBBER))
|
||||
zipflags |= ZIP_EXCL;
|
||||
else
|
||||
zipflags |= ZIP_TRUNCATE;
|
||||
|
||||
#ifdef VERIFY
|
||||
zipflags |= ZIP_CHECKCONS;
|
||||
#endif
|
||||
if((zzmap->archive = zip_open(zzmap->root,zipflags,&zerrno))==NULL)
|
||||
{stat = ziperrno(zerrno); goto done;}
|
||||
|
||||
/* Tell it about the dataset as a dir */
|
||||
if((zindex = zip_dir_add(zzmap->archive, zzmap->dataset, ZIP_FL_ENC_UTF_8))<0)
|
||||
{stat = zipmaperr(zzmap); goto done;}
|
||||
|
||||
/* Dataset superblock will be written by higher layer */
|
||||
|
||||
if(mapp) {*mapp = (NCZMAP*)zzmap; zzmap = NULL;}
|
||||
|
||||
done:
|
||||
ncurifree(url);
|
||||
nullfree(truepath);
|
||||
nullfree(dataset);
|
||||
if(zzmap) zipclose((NCZMAP*)zzmap,1);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
/*
|
||||
@param datasetpath abs path in the file tree of the root of the dataset'
|
||||
might be a relative path.
|
||||
@param mode the netcdf-c mode flags
|
||||
@param flags extra flags
|
||||
@param flags extra parameters
|
||||
@param mapp return the map object in this
|
||||
*/
|
||||
|
||||
static int
|
||||
zipopen(const char *path, int mode, size64_t flags, void* parameters, NCZMAP** mapp)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
char* truepath = NULL;
|
||||
char* dataset = NULL;
|
||||
ZZMAP* zzmap = NULL;
|
||||
NCURI*url = NULL;
|
||||
zip_flags_t zipflags = 0;
|
||||
int zerrno = ZIP_ER_OK;
|
||||
|
||||
NC_UNUSED(parameters);
|
||||
ZTRACE(6,"path=%s mode=%d flags=%llu",path,mode,flags);
|
||||
|
||||
if(!zzinitialized) zzinitialize();
|
||||
|
||||
/* Fixup mode flags */
|
||||
mode = (NC_NETCDF4 | mode);
|
||||
|
||||
/* path must be a url with file: protocol*/
|
||||
ncuriparse(path,&url);
|
||||
if(url == NULL)
|
||||
{stat = NC_EURL; goto done;}
|
||||
if(strcasecmp(url->protocol,"file") != 0)
|
||||
{stat = NC_EURL; goto done;}
|
||||
|
||||
/* Canonicalize the root path */
|
||||
if((stat = nczm_canonicalpath(url->path,&truepath))) goto done;
|
||||
|
||||
/* Build the zz state */
|
||||
if((zzmap = calloc(1,sizeof(ZZMAP))) == NULL)
|
||||
{stat = NC_ENOMEM; goto done;}
|
||||
|
||||
zzmap->map.format = NCZM_ZIP;
|
||||
zzmap->map.url = ncuribuild(url,NULL,NULL,NCURIALL);
|
||||
zzmap->map.flags = flags;
|
||||
zzmap->map.mode = mode;
|
||||
zzmap->map.api = (NCZMAP_API*)&zapi;
|
||||
zzmap->root = truepath;
|
||||
truepath = NULL;
|
||||
|
||||
/* Set zip open flags */
|
||||
zipflags |= ZIP_CHECKCONS;
|
||||
if(!fIsSet(mode,NC_WRITE))
|
||||
zipflags |= ZIP_RDONLY;
|
||||
|
||||
#ifdef VERIFY
|
||||
zipflags |= ZIP_CHECKCONS;
|
||||
#endif
|
||||
/* Open the file */
|
||||
if((zzmap->archive = zip_open(zzmap->root,zipflags,&zerrno))==NULL)
|
||||
{stat = ziperrno(zerrno); goto done;}
|
||||
|
||||
/* Use entry 0 to obtain the dataset name */
|
||||
{
|
||||
const char* name;
|
||||
zip_int64_t num_entries;
|
||||
|
||||
num_entries = zip_get_num_entries(zzmap->archive, (zip_flags_t)0);
|
||||
if(num_entries == 0) {stat = NC_EEMPTY; goto done;}
|
||||
/* get 0'th entry name */
|
||||
if((name = zip_get_name(zzmap->archive, 0, (zip_flags_t)0))==NULL)
|
||||
{stat = zipmaperr(zzmap); goto done;}
|
||||
if(name[0] == '\0' || name[0] == '/')
|
||||
{stat = NC_EBADID; goto done;}
|
||||
/* Extract the first segment as the dataset name */
|
||||
if((nczm_segment1(name,&zzmap->dataset))) goto done;
|
||||
}
|
||||
|
||||
/* Dataset superblock will be read by higher layer */
|
||||
|
||||
if(mapp) {*mapp = (NCZMAP*)zzmap; zzmap = NULL;}
|
||||
|
||||
done:
|
||||
ncurifree(url);
|
||||
nullfree(truepath);
|
||||
nullfree(dataset);
|
||||
if(zzmap) zipclose((NCZMAP*)zzmap,0);
|
||||
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
/* Object API */
|
||||
|
||||
static int
|
||||
zipexists(NCZMAP* map, const char* key)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
ZZMAP* zzmap = (ZZMAP*)map;
|
||||
ZINDEX zindex = -1;
|
||||
|
||||
ZTRACE(6,"map=%s key=%s",map->url,key);
|
||||
switch(stat=zzlookupobj(zzmap,key,&zindex)) {
|
||||
case NC_NOERR: break;
|
||||
case NC_ENOTFOUND: stat = NC_EEMPTY; break;
|
||||
case NC_EEMPTY: break;
|
||||
default: break;
|
||||
}
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
static int
|
||||
ziplen(NCZMAP* map, const char* key, size64_t* lenp)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
ZZMAP* zzmap = (ZZMAP*)map;
|
||||
size64_t len = 0;
|
||||
ZINDEX zindex = -1;
|
||||
|
||||
ZTRACE(6,"map=%s key=%s",map->url,key);
|
||||
|
||||
switch(stat = zzlookupobj(zzmap,key,&zindex)) {
|
||||
case NC_NOERR:
|
||||
if((stat = zzlen(zzmap,zindex,&len))) goto done;
|
||||
break;
|
||||
case NC_ENOTFOUND: stat = NC_EEMPTY; len = 0; break;
|
||||
case NC_EEMPTY: len = 0; break; /* |dir|==0 */
|
||||
default: goto done;
|
||||
}
|
||||
|
||||
if(lenp) *lenp = len;
|
||||
|
||||
done:
|
||||
return ZUNTRACEX(stat,"len=%llu",(lenp?*lenp:777777777777));
|
||||
}
|
||||
|
||||
static int
|
||||
zipread(NCZMAP* map, const char* key, size64_t start, size64_t count, void* content)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
ZZMAP* zzmap = (ZZMAP*)map; /* cast to true type */
|
||||
zip_file_t* zfile = NULL;
|
||||
ZINDEX zindex = -1;
|
||||
zip_flags_t zipflags = 0;
|
||||
int zerrno;
|
||||
size64_t endpoint;
|
||||
char* buffer = NULL;
|
||||
char* truekey = NULL;
|
||||
zip_int64_t red = 0;
|
||||
|
||||
ZTRACE(6,"map=%s key=%s start=%llu count=%llu",map->url,key,start,count);
|
||||
|
||||
switch(stat = zzlookupobj(zzmap,key,&zindex)) {
|
||||
case NC_NOERR: break;
|
||||
case NC_ENOTFOUND: stat = NC_EEMPTY; /* fall thru */
|
||||
case NC_EEMPTY: /* its a dir; fall thru*/
|
||||
default: goto done;
|
||||
}
|
||||
|
||||
/* Note, assume key[0] == '/' */
|
||||
if((stat = nczm_appendn(&truekey,2,zzmap->dataset,key)))
|
||||
goto done;
|
||||
|
||||
zfile = zip_fopen(zzmap->archive, truekey, zipflags);
|
||||
if(zfile == NULL)
|
||||
{stat = (zipmaperr(zzmap)); goto done;}
|
||||
|
||||
/* Ideally, we would like to seek to the start point,
|
||||
but that will fail if the file is compressed, so
|
||||
we need to read whole thing and extract what we need
|
||||
*/
|
||||
|
||||
/* read data starting at zero */
|
||||
if(start == 0) { /*optimize to read directly into content */
|
||||
if((red = zip_fread(zfile, content, (zip_uint64_t)count)) < 0)
|
||||
{stat = (zipmaperr(zzmap)); goto done;}
|
||||
if(red < count) {stat = NC_EINTERNAL; goto done;}
|
||||
} else {
|
||||
endpoint = start + count;
|
||||
if((buffer = malloc(endpoint))==NULL) /* consider caching this */
|
||||
{stat = NC_ENOMEM; goto done;}
|
||||
if((red = zip_fread(zfile, buffer, (zip_uint64_t)endpoint)) < 0)
|
||||
{stat = (zipmaperr(zzmap)); goto done;}
|
||||
if(red < endpoint) {stat = NC_EINTERNAL; goto done;}
|
||||
/* Extract what we need */
|
||||
memcpy(content,buffer+start,count);
|
||||
}
|
||||
|
||||
done:
|
||||
nullfree(truekey);
|
||||
nullfree(buffer);
|
||||
if(zfile != NULL && (zerrno=zip_fclose(zfile)) != 0)
|
||||
{stat = ziperrno(zerrno);}
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
static int
|
||||
zipwrite(NCZMAP* map, const char* key, size64_t start, size64_t count, const void* content)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
ZZMAP* zzmap = (ZZMAP*)map; /* cast to true type */
|
||||
char* truekey = NULL;
|
||||
zip_flags_t zflags = 0;
|
||||
zip_source_t* zs = NULL;
|
||||
ZINDEX zindex = -1;
|
||||
zip_int32_t compression = 0;
|
||||
zip_error_t zerror;
|
||||
void* localbuffer = NULL;
|
||||
|
||||
ZTRACE(6,"map=%s key=%s start=%llu count=%llu",map->url,key,start,count);
|
||||
|
||||
zip_error_init(&zerror);
|
||||
|
||||
if(start != 0 && (ZIP_PROPERTIES & NCZM_ZEROSTART))
|
||||
{stat = NC_EEDGE; goto done;}
|
||||
|
||||
/* Create directories */
|
||||
if((stat = zzcreategroup(zzmap,key,SKIPLAST))) goto done;
|
||||
|
||||
switch(stat = zzlookupobj(zzmap,key,&zindex)) {
|
||||
case NC_NOERR:
|
||||
stat = NC_EFOUND; //goto done; /* Zip files are write once */
|
||||
zflags |= ZIP_FL_OVERWRITE;
|
||||
break;
|
||||
case NC_ENOTFOUND: stat = NC_NOERR; break;
|
||||
case NC_EEMPTY: /* its a dir; fall thru */
|
||||
default: goto done;
|
||||
}
|
||||
|
||||
zflags |= ZIP_FL_ENC_UTF_8;
|
||||
compression = ZIP_CM_STORE;
|
||||
|
||||
/* prepend the dataset to get truekey */
|
||||
/* Note, assume key[0] == '/' */
|
||||
if((stat = nczm_appendn(&truekey,2,zzmap->dataset,key)))
|
||||
goto done;
|
||||
|
||||
if(count > 0) {
|
||||
/* Apparently, the buffer to be written needs to be around at zip_close
|
||||
so we need to make a local copy that will be freed by libzip after it is
|
||||
no longer needed */
|
||||
/* Duplicate the buffer */
|
||||
if((localbuffer = malloc((size_t)count))==NULL)
|
||||
{stat = NC_ENOMEM; goto done;}
|
||||
memcpy(localbuffer,content,count);
|
||||
}
|
||||
if((zs = zip_source_buffer(zzmap->archive, localbuffer, (zip_uint64_t)count, 1)) == NULL)
|
||||
{stat = zipmaperr(zzmap); goto done;}
|
||||
|
||||
if((zindex = zip_file_add(zzmap->archive, truekey, zs, zflags))<0)
|
||||
{stat = zipmaperr(zzmap); goto done;}
|
||||
|
||||
zs = NULL; localbuffer = NULL;
|
||||
|
||||
if(zip_set_file_compression(zzmap->archive, zindex, compression, 0) < 0)
|
||||
{stat = zipmaperr(zzmap); goto done;}
|
||||
|
||||
freesearchcache(zzmap->searchcache); zzmap->searchcache = NULL;
|
||||
|
||||
done:
|
||||
if(zs) zip_source_free(zs);
|
||||
nullfree(localbuffer);
|
||||
zip_error_fini(&zerror);
|
||||
nullfree(truekey);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
static int
|
||||
zipclose(NCZMAP* map, int delete)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
int zerrno = 0;
|
||||
ZZMAP* zzmap = (ZZMAP*)map;
|
||||
|
||||
if(zzmap == NULL) return NC_NOERR;
|
||||
|
||||
ZTRACE(6,"map=%s delete=%d",map->url,delete);
|
||||
|
||||
/* Close the zip */
|
||||
if(delete)
|
||||
zip_discard(zzmap->archive);
|
||||
else {
|
||||
if((zerrno=zip_close(zzmap->archive)))
|
||||
stat = ziperrno(zerrno);
|
||||
}
|
||||
if(delete)
|
||||
NCremove(zzmap->root);
|
||||
|
||||
zzmap->archive = NULL;
|
||||
nczm_clear(map);
|
||||
nullfree(zzmap->root);
|
||||
nullfree(zzmap->dataset);
|
||||
zzmap->root = NULL;
|
||||
freesearchcache(zzmap->searchcache);
|
||||
free(zzmap);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
/*
|
||||
Return a list of full keys immediately under a specified prefix key.
|
||||
In theory, the returned list should be sorted in lexical order,
|
||||
but it possible that it is not.
|
||||
Note that for zip, it is not possible to get just the keys of length n+1,
|
||||
so, this search must get all keys and process them one by one.
|
||||
@return NC_NOERR if success, even if no keys returned.
|
||||
@return NC_EXXX return true error
|
||||
*/
|
||||
int
|
||||
zipsearch(NCZMAP* map, const char* prefix0, NClist* matches)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
ZZMAP* zzmap = (ZZMAP*)map;
|
||||
char* trueprefix = NULL;
|
||||
size_t truelen;
|
||||
zip_int64_t num_entries, i;
|
||||
char** cache = NULL;
|
||||
size_t prefixlen;
|
||||
NClist* tmp = NULL;
|
||||
|
||||
ZTRACE(6,"map=%s prefix0=%s",map->url,prefix0);
|
||||
|
||||
/* prefix constraints:
|
||||
1. prefix is "/"
|
||||
2. or prefix has leading '/' and no trailing '/'
|
||||
*/
|
||||
|
||||
/* Fix up the prefix; including adding the dataset name to the front */
|
||||
if(prefix0 == NULL || strlen(prefix0)==0)
|
||||
prefix0 = "/";
|
||||
/* make sure that prefix0 has leading '/' */
|
||||
if(prefix0[0] != '/')
|
||||
{stat = NC_EINVAL; goto done;}
|
||||
prefixlen = strlen(prefix0);
|
||||
truelen = prefixlen+strlen(zzmap->dataset)+1; /* possible trailing '/'*/
|
||||
if((trueprefix = (char*)malloc(truelen+1+1))==NULL) /* nul term */
|
||||
{stat = NC_ENOMEM; goto done;}
|
||||
/* Build the true prefix */
|
||||
trueprefix[0] = '\0';
|
||||
strlcat(trueprefix,zzmap->dataset,truelen+1);
|
||||
strlcat(trueprefix,prefix0,truelen+1); /* recall prefix starts with '/' */
|
||||
/* If the prefix did not end in '/', then add it */
|
||||
if(prefixlen > 1 && prefix0[prefixlen-1] != '/')
|
||||
strlcat(trueprefix,"/",truelen+1);
|
||||
truelen = strlen(trueprefix);
|
||||
|
||||
/* Get number of entries */
|
||||
num_entries = zip_get_num_entries(zzmap->archive, (zip_flags_t)0);
|
||||
#ifdef CACHESEARCH
|
||||
if(num_entries > 0 && zzmap->searchcache == NULL) {
|
||||
/* Release the current cache */
|
||||
freesearchcache(zzmap->searchcache);
|
||||
zzmap->searchcache = NULL;
|
||||
/* Re-build the searchcache */
|
||||
if((cache = calloc(sizeof(char*),num_entries+1))==NULL)
|
||||
{stat = NC_ENOMEM; goto done;}
|
||||
for(i=0;i < num_entries; i++) {
|
||||
const char *name = NULL;
|
||||
/* get ith entry */
|
||||
name = zip_get_name(zzmap->archive, i, (zip_flags_t)0);
|
||||
/* Add to cache */
|
||||
if((cache[i] = strdup(name))==NULL)
|
||||
{stat = NC_ENOMEM; goto done;}
|
||||
}
|
||||
cache[num_entries] = NULL;
|
||||
zzmap->searchcache = cache; cache = NULL;
|
||||
}
|
||||
#endif
|
||||
#ifdef CACHESEARCH
|
||||
if(zzmap->searchcache != NULL)
|
||||
#endif
|
||||
{
|
||||
const char *key = NULL;
|
||||
size_t keylen = 0;
|
||||
char* match = NULL;
|
||||
const char* p;
|
||||
|
||||
tmp = nclistnew();
|
||||
/* Walk cache looking for names with prefix plus exactly one other segment */
|
||||
for(i=0;i < num_entries; i++) {
|
||||
/* get ith entry */
|
||||
#ifdef CACHESEARCH
|
||||
key = zzmap->searchcache[i];
|
||||
#else
|
||||
key = zip_get_name(zzmap->archive, i, (zip_flags_t)0);
|
||||
#endif
|
||||
keylen = strlen(key);
|
||||
/* Does this name begin with trueprefix? */
|
||||
if(keylen > 0
|
||||
&& (keylen <= truelen || strncmp(key,trueprefix,truelen) != 0))
|
||||
continue; /* no match */
|
||||
/* skip trueprefix and extract first segment */
|
||||
p = (key+truelen);
|
||||
if(*p == '\0') continue; /* key is all there is, so ignore it */
|
||||
/* get seg 1 */
|
||||
if((nczm_segment1(p,&match))) goto done;
|
||||
nclistpush(tmp,match); match = NULL;
|
||||
}
|
||||
/* Now remove duplicates */
|
||||
for(i=0;i<nclistlength(tmp);i++) {
|
||||
int j;
|
||||
int duplicate = 0;
|
||||
const char* is = nclistget(tmp,i);
|
||||
for(j=0;j<nclistlength(matches);j++) {
|
||||
const char* js = nclistget(matches,j);
|
||||
if(strcmp(js,is)==0) {duplicate = 1; break;} /* duplicate */
|
||||
}
|
||||
if(!duplicate)
|
||||
nclistpush(matches,strdup(is));
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
nclistfreeall(tmp);
|
||||
if(cache != NULL) freesearchcache(cache);
|
||||
nullfree(trueprefix);
|
||||
return ZUNTRACEX(stat,"|matches|=%d",(int)nclistlength(matches));
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
/* Utilities */
|
||||
|
||||
/* Guarantee existence of a group */
|
||||
static int
|
||||
zzcreategroup(ZZMAP* zzmap, const char* key, int nskip)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
int i, len;
|
||||
char* fullpath = NULL;
|
||||
NCbytes* path = ncbytesnew();
|
||||
NClist* segments = nclistnew();
|
||||
ZINDEX zindex;
|
||||
zip_flags_t zipflags = ZIP_FL_ENC_UTF_8;
|
||||
|
||||
ZTRACE(7,"map=%s key=%s nskip=%d",zzmap->map.url,key,nskip);
|
||||
if((stat=nczm_split(key,segments)))
|
||||
goto done;
|
||||
len = nclistlength(segments);
|
||||
len -= nskip; /* leave off last nskip segments */
|
||||
/* Start with the dataset */
|
||||
ncbytescat(path,zzmap->dataset);
|
||||
for(i=0;i<len;i++) {
|
||||
const char* seg = nclistget(segments,i);
|
||||
ncbytescat(path,"/");
|
||||
ncbytescat(path,seg);
|
||||
/* open and/or create the directory */
|
||||
if((zindex = zip_dir_add(zzmap->archive, ncbytescontents(path), zipflags))<0) {
|
||||
switch(stat = zipmaperr(zzmap)) {
|
||||
case NC_EFOUND: stat = NC_NOERR; break; /* ok */
|
||||
default:
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
done:
|
||||
nullfree(fullpath);
|
||||
ncbytesfree(path);
|
||||
nclistfreeall(segments);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
/* Lookup a key
|
||||
@return NC_NOERR if found and is a content-bearing object
|
||||
@return NC_ENOTFOUND if not found
|
||||
@return NC_EEMPTY if a dir
|
||||
*/
|
||||
static int
|
||||
zzlookupobj(ZZMAP* zzmap, const char* key, ZINDEX* zindex)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
char* zipfile = NULL;
|
||||
char* zipdir = NULL;
|
||||
|
||||
ZTRACE(7,"map=%s key=%s",zzmap->map.url,key);
|
||||
|
||||
if(key == NULL)
|
||||
{stat = NC_EINVAL; goto done;}
|
||||
|
||||
/* Note, assume key[0] == '/' */
|
||||
if((stat = nczm_appendn(&zipfile,2,zzmap->dataset,key)))
|
||||
goto done;
|
||||
|
||||
/* See if exists as a file */
|
||||
if((*zindex = zip_name_locate(zzmap->archive, zipfile, 0))<0) {
|
||||
/* do a second check to see if zippath as a dir */
|
||||
if((stat = nczm_appendn(&zipdir,2,zipfile,"/")))
|
||||
goto done;
|
||||
if((*zindex = zip_name_locate(zzmap->archive, zipdir, 0))<0)
|
||||
{stat = zipmaperr(zzmap); goto done;}
|
||||
stat = NC_EEMPTY; /* signal a directory */
|
||||
}
|
||||
|
||||
done:
|
||||
nullfree(zipfile);
|
||||
nullfree(zipdir);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
/* Get length given the index */
|
||||
static int
|
||||
zzlen(ZZMAP* zzmap, ZINDEX zindex, size64_t* lenp)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
size64_t len = 0;
|
||||
zip_stat_t statbuf;
|
||||
zip_flags_t zipflags = 0;
|
||||
|
||||
assert(zindex >= 0);
|
||||
|
||||
ZTRACE(6,"zzmap=%s index=%llu",zzmap,zindex);
|
||||
|
||||
zip_stat_init(&statbuf);
|
||||
if(zip_stat_index(zzmap->archive,zindex,zipflags,&statbuf) < 0)
|
||||
{stat = (zipmaperr(zzmap)); goto done;}
|
||||
assert(statbuf.valid & ZIP_STAT_SIZE);
|
||||
len = statbuf.size; /* Always return uncompressed size */
|
||||
|
||||
if(lenp) *lenp = len;
|
||||
|
||||
done:
|
||||
return ZUNTRACEX(stat,"len=%llu",(lenp?*lenp:777777777777));
|
||||
}
|
||||
|
||||
static void
|
||||
freesearchcache(char** cache)
|
||||
{
|
||||
char** p;
|
||||
if(cache == NULL) return;
|
||||
for(p=cache;*p;p++) {
|
||||
free(*p);
|
||||
}
|
||||
free(cache);
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
/* External API objects */
|
||||
|
||||
NCZMAP_DS_API zmap_zip = {
|
||||
NCZM_ZIP_V1,
|
||||
ZIP_PROPERTIES,
|
||||
zipcreate,
|
||||
zipopen,
|
||||
};
|
||||
|
||||
static NCZMAP_API zapi = {
|
||||
NCZM_ZIP_V1,
|
||||
zipclose,
|
||||
zipexists,
|
||||
ziplen,
|
||||
zipread,
|
||||
zipwrite,
|
||||
zipsearch,
|
||||
};
|
||||
|
||||
static int
|
||||
zipmaperr(ZZMAP* zzmap)
|
||||
{
|
||||
zip_error_t* zerr = (zip_error_t*)zip_get_error(zzmap->archive);
|
||||
return ziperr(zerr);
|
||||
}
|
||||
|
||||
static int
|
||||
ziperr(zip_error_t* zerror)
|
||||
{
|
||||
int zerrno = zip_error_code_zip(zerror);
|
||||
return ziperrno(zerrno);
|
||||
}
|
||||
|
||||
static int
|
||||
ziperrno(int zerror)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
switch (zerror) {
|
||||
case ZIP_ER_OK: stat = NC_NOERR; break;
|
||||
case ZIP_ER_EXISTS: stat = NC_EFOUND; break;
|
||||
case ZIP_ER_MEMORY: stat = NC_ENOMEM; break;
|
||||
case ZIP_ER_SEEK:
|
||||
case ZIP_ER_READ:
|
||||
case ZIP_ER_WRITE:
|
||||
case ZIP_ER_TMPOPEN:
|
||||
case ZIP_ER_CRC: stat = NC_EIO; break;
|
||||
case ZIP_ER_ZIPCLOSED: stat = NC_EBADID; break;
|
||||
case ZIP_ER_NOENT: stat = NC_ENOTFOUND; break;
|
||||
case ZIP_ER_OPEN: stat = NC_EACCESS; break;
|
||||
case ZIP_ER_INVAL: stat = NC_EINVAL; break;
|
||||
case ZIP_ER_INTERNAL: stat = NC_EINTERNAL; break;
|
||||
case ZIP_ER_REMOVE: stat = NC_ECANTREMOVE; break;
|
||||
case ZIP_ER_DELETED: stat = NC_ENOTFOUND; break;
|
||||
case ZIP_ER_RDONLY: stat = NC_EPERM; break;
|
||||
case ZIP_ER_CHANGED: stat = NC_EFOUND; break;
|
||||
default: stat = NC_ENCZARR; break;
|
||||
}
|
||||
return stat;
|
||||
}
|
@ -11,6 +11,7 @@
|
||||
#include <iostream>
|
||||
#include <streambuf>
|
||||
#include "netcdf.h"
|
||||
#include "zincludes.h"
|
||||
#include "zs3sdk.h"
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
@ -25,24 +26,27 @@ static Aws::SDKOptions zs3options;
|
||||
static Aws::S3::Model::BucketLocationConstraint s3findregion(const char* name);
|
||||
static int s3objectinfo1(const Aws::S3::Model::Object& s3_object, char** fullkeyp, size64_t* lenp);
|
||||
static int s3objectsinfo(Aws::Vector<Aws::S3::Model::Object> list, size_t*, char*** keysp, size64_t** lenp);
|
||||
static int s3commonprefixes(Aws::Vector<Aws::S3::Model::CommonPrefix> list, char*** keysp);
|
||||
static void freestringenvv(char** ss);
|
||||
static int makes3key(const char* pathkey, const char** keyp);
|
||||
static int makes3keydir(const char* prefix, char** prefixdirp);
|
||||
static char** mergekeysets(size_t nkeys1, char** keys1, size_t nkeys2, char** keys2);
|
||||
|
||||
#ifndef nullfree
|
||||
#define nullfree(x) {if(x) {free(x);}}
|
||||
#endif
|
||||
|
||||
void
|
||||
NCZ_s3sdkinitialize(void)
|
||||
{
|
||||
ZTRACE(11,NULL);
|
||||
// zs3options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Error;
|
||||
Aws::InitAPI(zs3options);
|
||||
ZUNTRACE(NC_NOERR);
|
||||
}
|
||||
|
||||
void
|
||||
NCZ_s3sdkfinalize(void)
|
||||
{
|
||||
ZTRACE(11,NULL);
|
||||
Aws::ShutdownAPI(zs3options);
|
||||
ZUNTRACE(NC_NOERR);
|
||||
}
|
||||
|
||||
static char*
|
||||
@ -65,6 +69,8 @@ int
|
||||
NCZ_s3sdkcreateconfig(const char* host, const char* region, void** configp)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
ZTRACE(11,"host=%s region=%s");
|
||||
|
||||
Aws::Client::ClientConfiguration *config = new Aws::Client::ClientConfiguration();
|
||||
config->scheme = Aws::Http::Scheme::HTTPS;
|
||||
config->connectTimeoutMs = 300000;
|
||||
@ -74,12 +80,13 @@ NCZ_s3sdkcreateconfig(const char* host, const char* region, void** configp)
|
||||
config->enableEndpointDiscovery = true;
|
||||
config->followRedirects = true;
|
||||
if(configp) * configp = config;
|
||||
return stat;
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
int
|
||||
NCZ_s3sdkcreateclient(void* config0, void** clientp)
|
||||
{
|
||||
ZTRACE(11,NULL);
|
||||
Aws::Client::ClientConfiguration* config = (Aws::Client::ClientConfiguration*) config0;
|
||||
Aws::S3::S3Client *s3client
|
||||
= new Aws::S3::S3Client(*config,
|
||||
@ -88,7 +95,7 @@ NCZ_s3sdkcreateclient(void* config0, void** clientp)
|
||||
Aws::S3::US_EAST_1_REGIONAL_ENDPOINT_OPTION::NOT_SET
|
||||
);
|
||||
if(clientp) *clientp = (void*)s3client;
|
||||
return NC_NOERR;
|
||||
return ZUNTRACE(NC_NOERR);
|
||||
}
|
||||
|
||||
int
|
||||
@ -97,7 +104,7 @@ NCZ_s3sdkbucketexists(void* s3client0, const char* bucket, int* existsp, char**
|
||||
int stat = NC_NOERR;
|
||||
int exists = 0;
|
||||
Aws::S3::S3Client* s3client = (Aws::S3::S3Client*)s3client0;
|
||||
|
||||
ZTRACE(11,"bucket=%s",bucket);
|
||||
if(errmsgp) *errmsgp = NULL;
|
||||
auto result = s3client->ListBuckets();
|
||||
if(!result.IsSuccess()) {
|
||||
@ -111,13 +118,15 @@ NCZ_s3sdkbucketexists(void* s3client0, const char* bucket, int* existsp, char**
|
||||
}
|
||||
}
|
||||
if(existsp) *existsp = exists;
|
||||
return stat;
|
||||
return ZUNTRACEX(stat,"exists=%d",*existsp);
|
||||
}
|
||||
|
||||
int
|
||||
NCZ_s3sdkbucketcreate(void* s3client0, const char* region, const char* bucket, char** errmsgp)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
|
||||
ZTRACE(11,"region=%s bucket=%s",region,bucket);
|
||||
Aws::S3::S3Client* s3client = (Aws::S3::S3Client*)s3client0;
|
||||
if(errmsgp) *errmsgp = NULL;
|
||||
const Aws::S3::Model::BucketLocationConstraint &awsregion = s3findregion(region);
|
||||
@ -143,13 +152,16 @@ NCZ_s3sdkbucketcreate(void* s3client0, const char* region, const char* bucket, c
|
||||
fprintf(stderr,"create bucket: %s\n",bucket); fflush(stderr);
|
||||
#endif
|
||||
|
||||
return stat;
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
int
|
||||
NCZ_s3sdkbucketdelete(void* s3client0, void* config0, const char* region, const char* bucket, char** errmsgp)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
|
||||
ZTRACE(11,"region=%s bucket=%s",region,bucket);
|
||||
|
||||
Aws::S3::S3Client* s3client = (Aws::S3::S3Client*)s3client0;
|
||||
Aws::Client::ClientConfiguration *config = (Aws::Client::ClientConfiguration*)config0;
|
||||
|
||||
@ -174,7 +186,7 @@ NCZ_s3sdkbucketdelete(void* s3client0, void* config0, const char* region, const
|
||||
fprintf(stderr,"delete bucket: %s\n",bucket); fflush(stderr);
|
||||
#endif
|
||||
|
||||
return stat;
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
@ -189,13 +201,15 @@ int
|
||||
NCZ_s3sdkinfo(void* s3client0, const char* bucket, const char* pathkey, size64_t* lenp, char** errmsgp)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
Aws::S3::S3Client* s3client = (Aws::S3::S3Client*)s3client0;
|
||||
Aws::S3::Model::HeadObjectRequest head_request;
|
||||
const char* key = NULL;
|
||||
|
||||
ZTRACE(11,"bucket=%s pathkey=%s",bucket,pathkey);
|
||||
|
||||
Aws::S3::S3Client* s3client = (Aws::S3::S3Client*)s3client0;
|
||||
Aws::S3::Model::HeadObjectRequest head_request;
|
||||
if(*pathkey != '/') return NC_EINTERNAL;
|
||||
/* extract the true s3 key*/
|
||||
if((stat = makes3key(pathkey,&key))) return stat;
|
||||
if((stat = makes3key(pathkey,&key))) return ZUNTRACE(stat);
|
||||
|
||||
if(errmsgp) *errmsgp = NULL;
|
||||
head_request.SetBucket(bucket);
|
||||
@ -205,6 +219,7 @@ NCZ_s3sdkinfo(void* s3client0, const char* bucket, const char* pathkey, size64_t
|
||||
long long l = head_outcome.GetResult().GetContentLength();
|
||||
if(lenp) *lenp = (size64_t)l;
|
||||
} else {
|
||||
if(lenp) *lenp = 0;
|
||||
/* Distinquish not-found from other errors */
|
||||
switch (head_outcome.GetError().GetErrorType()) {
|
||||
case Aws::S3::S3Errors::RESOURCE_NOT_FOUND:
|
||||
@ -219,33 +234,7 @@ NCZ_s3sdkinfo(void* s3client0, const char* bucket, const char* pathkey, size64_t
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (stat);
|
||||
}
|
||||
|
||||
/* Define object key
|
||||
@return NC_NOERR if success
|
||||
@return NC_EXXX if fail
|
||||
*/
|
||||
int
|
||||
NCZ_s3sdkcreatekey(void* s3client0, const char* bucket, const char* pathkey, char** errmsgp)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
const char* key = NULL;
|
||||
Aws::S3::S3Client* s3client = (Aws::S3::S3Client*)s3client0;
|
||||
Aws::S3::Model::PutObjectRequest put_request;
|
||||
|
||||
if(*pathkey != '/') return NC_EINTERNAL;
|
||||
if((stat = makes3key(pathkey,&key))) return stat;
|
||||
|
||||
if(errmsgp) *errmsgp = NULL;
|
||||
put_request.SetBucket(bucket);
|
||||
put_request.SetKey(key);
|
||||
auto put_result = s3client->PutObject(put_request);
|
||||
if(!put_result.IsSuccess()) {
|
||||
if(errmsgp) *errmsgp = makeerrmsg(put_result.GetError(),key);
|
||||
stat = NC_ES3;
|
||||
}
|
||||
return (stat);
|
||||
return ZUNTRACEX(stat,"len=%d",(int)(lenp?*lenp:-1));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -256,17 +245,24 @@ int
|
||||
NCZ_s3sdkread(void* s3client0, const char* bucket, const char* pathkey, size64_t start, size64_t count, void* content, char** errmsgp)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
Aws::S3::S3Client* s3client = (Aws::S3::S3Client*)s3client0;
|
||||
Aws::S3::Model::GetObjectRequest object_request;
|
||||
char range[1024];
|
||||
const char* key = NULL;
|
||||
size64_t rangeend;
|
||||
|
||||
ZTRACE(11,"bucket=%s pathkey=%s start=%llu count=%llu content=%p",bucket,pathkey,start,count,content);
|
||||
|
||||
Aws::S3::S3Client* s3client = (Aws::S3::S3Client*)s3client0;
|
||||
Aws::S3::Model::GetObjectRequest object_request;
|
||||
|
||||
if(count == 0) return ZUNTRACE(stat);
|
||||
|
||||
if(*pathkey != '/') return NC_EINTERNAL;
|
||||
if((stat = makes3key(pathkey,&key))) return stat;
|
||||
if((stat = makes3key(pathkey,&key))) return ZUNTRACE(stat);
|
||||
|
||||
object_request.SetBucket(bucket);
|
||||
object_request.SetKey(key);
|
||||
snprintf(range,sizeof(range),"bytes=%llu-%llu",start,(start+count)-1);
|
||||
rangeend = (start+count)-1;
|
||||
snprintf(range,sizeof(range),"bytes=%llu-%llu",start,rangeend);
|
||||
object_request.SetRange(range);
|
||||
auto get_object_result = s3client->GetObject(object_request);
|
||||
if(!get_object_result.IsSuccess()) {
|
||||
@ -283,7 +279,7 @@ NCZ_s3sdkread(void* s3client0, const char* bucket, const char* pathkey, size64_t
|
||||
if(content)
|
||||
memcpy(content,s,slen);
|
||||
}
|
||||
return (stat);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -295,11 +291,14 @@ NCZ_s3sdkwriteobject(void* s3client0, const char* bucket, const char* pathkey,
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
const char* key = NULL;
|
||||
|
||||
ZTRACE(11,"bucket=%s pathkey=%s count=%lld content=%p",bucket,pathkey,count,content);
|
||||
|
||||
Aws::S3::S3Client* s3client = (Aws::S3::S3Client*)s3client0;
|
||||
Aws::S3::Model::PutObjectRequest put_request;
|
||||
|
||||
if(*pathkey != '/') return NC_EINTERNAL;
|
||||
if((stat = makes3key(pathkey,&key))) return stat;
|
||||
if(*pathkey != '/') return ZUNTRACE(NC_EINTERNAL);
|
||||
if((stat = makes3key(pathkey,&key))) return ZUNTRACE(stat);
|
||||
|
||||
if(errmsgp) *errmsgp = NULL;
|
||||
put_request.SetBucket(bucket);
|
||||
@ -314,70 +313,16 @@ NCZ_s3sdkwriteobject(void* s3client0, const char* bucket, const char* pathkey,
|
||||
if(errmsgp) *errmsgp = makeerrmsg(put_result.GetError(),key);
|
||||
stat = NC_ES3;
|
||||
}
|
||||
return (stat);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
@return NC_NOERR if success
|
||||
@return NC_EXXX if fail
|
||||
*/
|
||||
int
|
||||
NCZ_s3sdkreadobject(void* s3client0, const char* bucket, const char* pathkey, size64_t* sizep, void** contentp, char** errmsgp)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
Aws::S3::S3Client* s3client = (Aws::S3::S3Client*)s3client0;
|
||||
Aws::S3::Model::GetObjectRequest object_request;
|
||||
size64_t size, red;
|
||||
void* content = NULL;
|
||||
const char* key = NULL;
|
||||
|
||||
if(*pathkey != '/') return NC_EINTERNAL;
|
||||
if((stat = makes3key(pathkey,&key))) return stat;
|
||||
|
||||
if(errmsgp) *errmsgp = NULL;
|
||||
object_request.SetBucket(bucket);
|
||||
object_request.SetKey(key);
|
||||
auto get_result = s3client->GetObject(object_request);
|
||||
if(!get_result.IsSuccess()) {
|
||||
if(errmsgp) *errmsgp = makeerrmsg(get_result.GetError(),key);
|
||||
stat = NC_ES3;
|
||||
} else {
|
||||
/* Get the size */
|
||||
size = (size64_t)get_result.GetResult().GetContentLength();
|
||||
/* Get the whole result */
|
||||
Aws::IOStream &result = get_result.GetResultWithOwnership().GetBody();
|
||||
#if 0
|
||||
std::string str((std::istreambuf_iterator<char>(result)),std::istreambuf_iterator<char>());
|
||||
red = str.length();
|
||||
if((content = malloc(red))==NULL)
|
||||
{stat = NC_ENOMEM; goto done;}
|
||||
memcpy(content,str.c_str(),red);
|
||||
#else
|
||||
red = result.rdbuf()->pubseekoff(0,std::ios::ios_base::end);
|
||||
result.rdbuf()->pubseekoff(0,std::ios::ios_base::beg); /* reset for reading */
|
||||
if((content = malloc(red))==NULL)
|
||||
stat = NC_ENOMEM;
|
||||
else
|
||||
result.rdbuf()->sgetn((char*)content,red);
|
||||
#endif
|
||||
if(!stat) {
|
||||
/* Verify actual result size */
|
||||
if(red != size) {stat = NC_ES3; goto done;}
|
||||
if(sizep) *sizep = red;
|
||||
if(contentp) {*contentp = content; content = NULL;}
|
||||
}
|
||||
}
|
||||
done:
|
||||
nullfree(content);
|
||||
return (stat);
|
||||
}
|
||||
#endif /*0*/
|
||||
|
||||
int
|
||||
NCZ_s3sdkclose(void* s3client0, void* config0, const char* bucket, const char* rootkey, int deleteit, char** errmsgp)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
|
||||
ZTRACE(11,"bucket=%s rootkey=%s deleteit=%d content=%p",bucket,rootkey,deleteit);
|
||||
|
||||
Aws::S3::S3Client* s3client = (Aws::S3::S3Client*)s3client0;
|
||||
Aws::Client::ClientConfiguration *config = (Aws::Client::ClientConfiguration*)config0;
|
||||
if(deleteit) {
|
||||
@ -390,53 +335,151 @@ NCZ_s3sdkclose(void* s3client0, void* config0, const char* bucket, const char* r
|
||||
}
|
||||
delete s3client;
|
||||
delete config;
|
||||
return (stat);
|
||||
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
/*
|
||||
Return a list of keys for objects "below" a specified rootkey.
|
||||
Return a list of names of legal objects immediately below a specified key.
|
||||
In theory, the returned list should be sorted in lexical order,
|
||||
but it possible that it is not.
|
||||
*/
|
||||
int
|
||||
NCZ_s3sdkgetkeys(void* s3client0, const char* bucket, const char* rootkey0, size_t* nkeysp, char*** keysp, char** errmsgp)
|
||||
NCZ_s3sdkgetkeys(void* s3client0, const char* bucket, const char* prefixkey0, size_t* nkeysp, char*** keysp, char** errmsgp)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
Aws::S3::S3Client* s3client = (Aws::S3::S3Client*)s3client0;
|
||||
size_t nkeys = 0;
|
||||
const char* rootkey = NULL;
|
||||
const char* prefix = NULL;
|
||||
char* prefixdir = NULL;
|
||||
char** realkeys = NULL;
|
||||
char** commonkeys = NULL;
|
||||
char** allkeys = NULL;
|
||||
|
||||
ZTRACE(11,"bucket=%s prefixkey0=%s",bucket,prefixkey0);
|
||||
|
||||
Aws::S3::S3Client* s3client = (Aws::S3::S3Client*)s3client0;
|
||||
Aws::S3::Model::ListObjectsV2Request objects_request;
|
||||
|
||||
if(*rootkey0 != '/') return NC_EINTERNAL;
|
||||
if((stat = makes3key(rootkey0,&rootkey))) return stat;
|
||||
if(*prefixkey0 != '/') return ZUNTRACE(NC_EINTERNAL);
|
||||
/* Make sure that the prefix ends with '/' */
|
||||
if((stat = makes3keydir(prefixkey0,&prefixdir))) return ZUNTRACE(stat);
|
||||
/* remove leading '/' */
|
||||
if((stat = makes3key(prefixdir,&prefix))) return ZUNTRACE(stat);
|
||||
|
||||
if(errmsgp) *errmsgp = NULL;
|
||||
objects_request.SetBucket(bucket);
|
||||
objects_request.SetPrefix(rootkey);
|
||||
objects_request.SetPrefix(prefix);
|
||||
objects_request.SetDelimiter("/"); /* Force return of common prefixes */
|
||||
auto objects_outcome = s3client->ListObjectsV2(objects_request);
|
||||
if(objects_outcome.IsSuccess()) {
|
||||
size_t nrealkeys = 0;
|
||||
size_t ncommonkeys = 0;
|
||||
Aws::Vector<Aws::S3::Model::Object> object_list =
|
||||
objects_outcome.GetResult().GetContents();
|
||||
nkeys = (size_t)object_list.size();
|
||||
if(nkeysp) *nkeysp = nkeys;
|
||||
stat = s3objectsinfo(object_list,NULL,keysp,NULL);
|
||||
nrealkeys = (size_t)object_list.size();
|
||||
stat = s3objectsinfo(object_list,NULL,&realkeys,NULL);
|
||||
/* Add common prefixes */
|
||||
Aws::Vector<Aws::S3::Model::CommonPrefix> common_list =
|
||||
objects_outcome.GetResult().GetCommonPrefixes();
|
||||
ncommonkeys = (size_t)common_list.size();
|
||||
stat = s3commonprefixes(common_list,&commonkeys);
|
||||
/* merge the two lists */
|
||||
if((allkeys=mergekeysets(nrealkeys, realkeys, ncommonkeys, commonkeys))==NULL)
|
||||
stat = NC_ENOMEM;
|
||||
if(stat == NC_NOERR) {
|
||||
if(nkeysp) {*nkeysp = nrealkeys + ncommonkeys;}
|
||||
if(keysp) {*keysp = allkeys; allkeys = NULL;}
|
||||
}
|
||||
freestringenvv(allkeys);
|
||||
freestringenvv(realkeys);
|
||||
freestringenvv(commonkeys);
|
||||
} else {
|
||||
if(errmsgp) *errmsgp = makeerrmsg(objects_outcome.GetError());
|
||||
stat = NC_ES3;
|
||||
}
|
||||
return stat;
|
||||
if(prefixdir) free(prefixdir);
|
||||
return ZUNTRACEX(stat,"nkeys=%u",(unsigned)*nkeysp);
|
||||
}
|
||||
|
||||
/*
|
||||
Return a list of full keys of legal objects immediately below a specified key.
|
||||
Not necessarily sorted.
|
||||
*/
|
||||
int
|
||||
NCZ_s3sdksearch(void* s3client0, const char* bucket, const char* prefixkey0, size_t* nkeysp, char*** keysp, char** errmsgp)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
size_t nkeys = 0;
|
||||
const char* prefix = NULL;
|
||||
char* prefixdir = NULL;
|
||||
char** keys = NULL;
|
||||
|
||||
ZTRACE(11,"bucket=%s prefixkey0=%s",bucket,prefixkey0);
|
||||
|
||||
Aws::S3::S3Client* s3client = (Aws::S3::S3Client*)s3client0;
|
||||
Aws::S3::Model::ListObjectsV2Request objects_request;
|
||||
|
||||
if(*prefixkey0 != '/') return ZUNTRACE(NC_EINTERNAL);
|
||||
/* Make sure that the prefix ends with '/' */
|
||||
if((stat = makes3keydir(prefixkey0,&prefixdir))) return ZUNTRACE(stat);
|
||||
/* remove leading '/' */
|
||||
if((stat = makes3key(prefixdir,&prefix))) return ZUNTRACE(stat);
|
||||
|
||||
if(errmsgp) *errmsgp = NULL;
|
||||
objects_request.SetBucket(bucket);
|
||||
objects_request.SetPrefix(prefix);
|
||||
/* Do not use delimiter so we get all full key paths */
|
||||
auto objects_outcome = s3client->ListObjectsV2(objects_request);
|
||||
if(objects_outcome.IsSuccess()) {
|
||||
size_t nkeys = 0;
|
||||
Aws::Vector<Aws::S3::Model::Object> object_list =
|
||||
objects_outcome.GetResult().GetContents();
|
||||
nkeys = (size_t)object_list.size();
|
||||
if((keys=(char**)calloc(sizeof(char*),(nkeys+1)))==NULL) /* NULL terminate list */
|
||||
stat = NC_ENOMEM;
|
||||
if(!stat) {
|
||||
int i;
|
||||
i = 0;
|
||||
for (auto const &s3obj : object_list) {
|
||||
const char* s;
|
||||
const Aws::String& name = s3obj.GetKey();
|
||||
s = name.c_str();
|
||||
if(s != NULL) {
|
||||
char* p;
|
||||
size_t slen = name.length();
|
||||
p = (char*)malloc(slen+1+1); /* nul plus leading '/' */
|
||||
if(s[0] != '/') {p[0] = '/'; memcpy(p+1,s,slen); slen++;} else {memcpy(p,s,slen);}
|
||||
p[slen] = '\0';
|
||||
keys[i++] = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(stat == NC_NOERR) {
|
||||
if(nkeysp) {*nkeysp = nkeys;}
|
||||
if(keysp) {*keysp = keys; keys = NULL;}
|
||||
}
|
||||
freestringenvv(keys);
|
||||
} else {
|
||||
if(errmsgp) *errmsgp = makeerrmsg(objects_outcome.GetError());
|
||||
stat = NC_ES3;
|
||||
}
|
||||
if(prefixdir) free(prefixdir);
|
||||
return ZUNTRACEX(stat,"nkeys=%u",(unsigned)*nkeysp);
|
||||
}
|
||||
|
||||
int
|
||||
NCZ_s3sdkdeletekey(void* s3client0, const char* bucket, const char* pathkey, char** errmsgp)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
Aws::S3::S3Client* s3client = (Aws::S3::S3Client*)s3client0;
|
||||
Aws::S3::Model::DeleteObjectRequest delete_request;
|
||||
const char* key = NULL;
|
||||
|
||||
ZTRACE(11,"bucket=%s pathkey=%s",bucket,pathkey);
|
||||
|
||||
Aws::S3::S3Client* s3client = (Aws::S3::S3Client*)s3client0;
|
||||
Aws::S3::Model::DeleteObjectRequest delete_request;
|
||||
|
||||
if(*pathkey != '/') return NC_EINTERNAL;
|
||||
if((stat = makes3key(pathkey,&key))) return stat;
|
||||
if((stat = makes3key(pathkey,&key))) return ZUNTRACE(stat);
|
||||
/* Delete this key object */
|
||||
delete_request.SetBucket(bucket);
|
||||
delete_request.SetKey(key);
|
||||
@ -445,7 +488,7 @@ NCZ_s3sdkdeletekey(void* s3client0, const char* bucket, const char* pathkey, cha
|
||||
if(errmsgp) *errmsgp = makeerrmsg(delete_result.GetError(),key);
|
||||
stat = NC_ES3;
|
||||
}
|
||||
return stat;
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -483,7 +526,7 @@ s3objectinfo1(const Aws::S3::Model::Object& s3_object, char** fullkeyp, size64_t
|
||||
if(!stat) {
|
||||
if(lenp) *lenp = (size64_t)s3_object.GetSize();
|
||||
}
|
||||
nullfree(cstr);
|
||||
if(cstr) free(cstr);
|
||||
return stat;
|
||||
}
|
||||
|
||||
@ -524,6 +567,39 @@ s3objectsinfo(Aws::Vector<Aws::S3::Model::Object> list, size_t* nkeysp, char***
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int
|
||||
s3commonprefixes(Aws::Vector<Aws::S3::Model::CommonPrefix> list, char*** keysp)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
char** keys = NULL;
|
||||
size_t nkeys;
|
||||
int i;
|
||||
|
||||
nkeys = list.size();
|
||||
if((keys=(char**)calloc(sizeof(char*),(nkeys+1)))==NULL)
|
||||
stat = NC_ENOMEM;
|
||||
if(!stat) {
|
||||
i = 0;
|
||||
for (auto const &s3prefix : list) {
|
||||
char* p; char* p1;
|
||||
size_t len;
|
||||
const Aws::String& prefix = s3prefix.GetPrefix();
|
||||
len = prefix.length();
|
||||
if((p = (char*) malloc(len+1+1))==NULL) /* for nul + leading '/' */
|
||||
stat = NC_ENOMEM;
|
||||
if(stat == NC_NOERR) {
|
||||
if(*p == '/') {p1 = p;} else {*p = '/'; p1 = p+1;}
|
||||
memcpy(p1,prefix.c_str(),len);
|
||||
p1[len] = '\0';
|
||||
keys[i++] = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(keysp) {keys[nkeys] = NULL; *keysp = keys; keys = NULL;}
|
||||
if(keys != NULL) freestringenvv(keys);
|
||||
return stat;
|
||||
}
|
||||
|
||||
static Aws::S3::Model::BucketLocationConstraint
|
||||
s3findregion(const char* name)
|
||||
{
|
||||
@ -543,7 +619,7 @@ freestringenvv(char** ss)
|
||||
char** p;
|
||||
if(ss != NULL) {
|
||||
for(p=ss;*p;p++)
|
||||
nullfree(*p);
|
||||
if(*p) free(*p);
|
||||
free(ss);
|
||||
}
|
||||
}
|
||||
@ -555,3 +631,41 @@ makes3key(const char* pathkey, const char** keyp)
|
||||
if(keyp) *keyp = pathkey+1;
|
||||
return NC_NOERR;
|
||||
}
|
||||
|
||||
static int
|
||||
makes3keydir(const char* prefix, char** prefixdirp)
|
||||
{
|
||||
size_t plen = strlen(prefix);
|
||||
char* prefixdir = (char*)malloc(plen+1+1); /* '/' + nul */
|
||||
if(prefixdir == NULL) return NC_ENOMEM;
|
||||
memcpy(prefixdir,prefix,plen);
|
||||
if(prefixdir[plen-1] != '/') {
|
||||
prefixdir[plen++] = '/';
|
||||
}
|
||||
prefixdir[plen] = '\0';
|
||||
*prefixdirp = prefixdir; prefixdir = NULL;
|
||||
return NC_NOERR;
|
||||
}
|
||||
|
||||
static char**
|
||||
mergekeysets(size_t nkeys1, char** keys1, size_t nkeys2, char** keys2)
|
||||
{
|
||||
char** merge = NULL;
|
||||
char** p1;
|
||||
char** p2;
|
||||
|
||||
merge = (char**)malloc(sizeof(char*)*(nkeys1+nkeys2+1));
|
||||
if(merge == NULL) return NULL;
|
||||
if(nkeys1 > 0) {
|
||||
memcpy(merge,keys1,sizeof(char*)*nkeys1);
|
||||
/* avoid double free */
|
||||
memset(keys1,0,sizeof(char*)*nkeys1);
|
||||
}
|
||||
if(nkeys2 > 0) {
|
||||
memcpy(merge+nkeys1,keys2,sizeof(char*)*nkeys2);
|
||||
/* avoid double free */
|
||||
memset(keys2,0,sizeof(char*)*nkeys2);
|
||||
}
|
||||
merge[nkeys1+nkeys2] = NULL;
|
||||
return merge;
|
||||
}
|
||||
|
@ -10,20 +10,20 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void NCZ_s3sdkinitialize(void);
|
||||
void NCZ_s3sdkfinalize(void);
|
||||
int NCZ_s3sdkcreateconfig(const char* host, const char* reqion, void** configp);
|
||||
int NCZ_s3sdkcreateclient(void* config, void** clientp);
|
||||
int NCZ_s3sdkbucketexists(void* s3client, const char* bucket, int* existsp, char** errmsgp);
|
||||
int NCZ_s3sdkbucketcreate(void* s3client, const char* region, const char* bucket, char** errmsgp);
|
||||
int NCZ_s3sdkbucketdelete(void* s3client, const char* region, const char* bucket, char** errmsgp);
|
||||
int NCZ_s3sdkinfo(void* client0, const char* bucket, const char* pathkey, unsigned long long* lenp, char** errmsgp);
|
||||
int NCZ_s3sdkread(void* client0, const char* bucket, const char* pathkey, unsigned long long start, unsigned long long count, void* content, char** errmsgp);
|
||||
int NCZ_s3sdkwriteobject(void* client0, const char* bucket, const char* pathkey, unsigned long long count, const void* content, char** errmsgp);
|
||||
int NCZ_s3sdkclose(void* s3client0, void* config0, const char* bucket, const char* rootkey, int deleteit, char** errmsgp);
|
||||
int NCZ_s3sdkgetkeys(void* s3client0, const char* bucket, const char* prefix, size_t* nkeysp, char*** keysp, char** errmsgp);
|
||||
int NCZ_s3sdkdeletekey(void* client0, const char* bucket, const char* pathkey, char** errmsgp);
|
||||
int NCZ_s3sdkcreatekey(void* s3client0, const char* bucket, const char* pathkey, char** errmsgp);
|
||||
EXTERNL void NCZ_s3sdkinitialize(void);
|
||||
EXTERNL void NCZ_s3sdkfinalize(void);
|
||||
EXTERNL int NCZ_s3sdkcreateconfig(const char* host, const char* reqion, void** configp);
|
||||
EXTERNL int NCZ_s3sdkcreateclient(void* config, void** clientp);
|
||||
EXTERNL int NCZ_s3sdkbucketexists(void* s3client, const char* bucket, int* existsp, char** errmsgp);
|
||||
EXTERNL int NCZ_s3sdkbucketcreate(void* s3client, const char* region, const char* bucket, char** errmsgp);
|
||||
EXTERNL int NCZ_s3sdkbucketdelete(void* s3client, const char* region, const char* bucket, char** errmsgp);
|
||||
EXTERNL int NCZ_s3sdkinfo(void* client0, const char* bucket, const char* pathkey, unsigned long long* lenp, char** errmsgp);
|
||||
EXTERNL int NCZ_s3sdkread(void* client0, const char* bucket, const char* pathkey, unsigned long long start, unsigned long long count, void* content, char** errmsgp);
|
||||
EXTERNL int NCZ_s3sdkwriteobject(void* client0, const char* bucket, const char* pathkey, unsigned long long count, const void* content, char** errmsgp);
|
||||
EXTERNL int NCZ_s3sdkclose(void* s3client0, void* config0, const char* bucket, const char* rootkey, int deleteit, char** errmsgp);
|
||||
EXTERNL int NCZ_s3sdkgetkeys(void* s3client0, const char* bucket, const char* prefix, size_t* nkeysp, char*** keysp, char** errmsgp);
|
||||
EXTERNL int NCZ_s3sdksearch(void* s3client0, const char* bucket, const char* prefixkey0, size_t* nkeysp, char*** keysp, char** errmsgp);
|
||||
EXTERNL int NCZ_s3sdkdeletekey(void* client0, const char* bucket, const char* pathkey, char** errmsgp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -51,20 +51,31 @@ that the recursion occurs in the caller's code.
|
||||
* @author Dennis Heimbigner
|
||||
*/
|
||||
int
|
||||
ncz_sync_file(NC_FILE_INFO_T* file)
|
||||
ncz_sync_file(NC_FILE_INFO_T* file, int isclose)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
NCjson* json = NULL;
|
||||
NCZ_FILE_INFO_T* zinfo = NULL;
|
||||
|
||||
NC_UNUSED(isclose);
|
||||
|
||||
LOG((3, "%s: file: %s", __func__, file->controller->path));
|
||||
ZTRACE(3,"file=%s isclose=%d",file->controller->path,isclose);
|
||||
|
||||
/* Write out root group recursively */
|
||||
if((stat = ncz_sync_grp(file, file->root_grp)))
|
||||
goto done;
|
||||
zinfo = (NCZ_FILE_INFO_T*)file->format_file_info;
|
||||
|
||||
/* Create super block (NCZMETAROOT) */
|
||||
{
|
||||
if((stat = ncz_create_superblock(zinfo))) goto done;
|
||||
|
||||
/* Write out root group recursively */
|
||||
if((stat = ncz_sync_grp(file, file->root_grp)))
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
NCJreclaim(json);
|
||||
return THROW(stat);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -485,7 +496,6 @@ ncz_write_var(NC_VAR_INFO_T* var)
|
||||
default: goto done; /* some other error */
|
||||
}
|
||||
/* If we reach here, then chunk does not exist, create it with fill */
|
||||
if((stat=nczmap_defineobj(map,key))) goto done;
|
||||
/* ensure fillchunk exists */
|
||||
if(zvar->cache->fillchunk == NULL) {
|
||||
nc_type typecode;
|
||||
@ -1846,6 +1856,8 @@ ncz_create_superblock(NCZ_FILE_INFO_T* zinfo)
|
||||
NCZMAP* map = NULL;
|
||||
char version[1024];
|
||||
|
||||
ZTRACE(4,"zinfo=%s",zinfo->common.file->controller->path);
|
||||
|
||||
map = zinfo->map;
|
||||
|
||||
/* create superblock json */
|
||||
@ -1872,5 +1884,5 @@ ncz_create_superblock(NCZ_FILE_INFO_T* zinfo)
|
||||
}
|
||||
done:
|
||||
NCJreclaim(json);
|
||||
return THROW(stat);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
@ -65,6 +65,8 @@ NCJ_INT, /*NC_INT64*/
|
||||
NCJ_INT, /*NC_UINT64*/
|
||||
};
|
||||
|
||||
/* Forward */
|
||||
static int endswith(const char* s, const char* suffix);
|
||||
|
||||
/**************************************************/
|
||||
|
||||
@ -213,24 +215,6 @@ done:
|
||||
return stat;
|
||||
}
|
||||
|
||||
/**
|
||||
@internal Create a specified object exists; do nothing if already exists.
|
||||
@param zmap - [in] controlling zarr map
|
||||
@param key - [in] .z... object to create
|
||||
|
||||
@return NC_NOERR
|
||||
@author Dennis Heimbigner
|
||||
*/
|
||||
int
|
||||
NCZ_createobject(NCZMAP* zmap, const char* key, size64_t size)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
|
||||
/* create the target */
|
||||
stat = nczmap_defineobj(zmap, key);
|
||||
return stat;
|
||||
}
|
||||
|
||||
/**
|
||||
@internal Upload a modified json tree to a .z... structure.
|
||||
@param zmap - [in] controlling zarr map
|
||||
@ -244,24 +228,24 @@ NCZ_uploadjson(NCZMAP* zmap, const char* key, NCjson* json)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
char* content = NULL;
|
||||
|
||||
ZTRACE(4,"zmap=%p key=%s",zmap,key);
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"uploadjson: %s\n",key); fflush(stderr);
|
||||
#endif
|
||||
/* Unparse the modified json tree */
|
||||
if((stat = NCJunparse(json,0,&content)))
|
||||
goto done;
|
||||
|
||||
/* create the target */
|
||||
if((stat = nczmap_defineobj(zmap, key)))
|
||||
goto done;
|
||||
|
||||
ZTRACEMORE(4,"\tjson=%s",content);
|
||||
|
||||
/* Write the metadata */
|
||||
if((stat = nczmap_write(zmap, key, 0, strlen(content), content)))
|
||||
goto done;
|
||||
|
||||
done:
|
||||
nullfree(content);
|
||||
return stat;
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
#if 0
|
||||
@ -473,30 +457,30 @@ NCZ_subobjects(NCZMAP* map, const char* prefix, const char* tag, NClist* objlist
|
||||
NClist* matches = nclistnew();
|
||||
NCbytes* path = ncbytesnew();
|
||||
|
||||
/* Get the list of object keys just below prefix */
|
||||
/* Get the list of names just below prefix */
|
||||
if((stat = nczmap_search(map,prefix,matches))) goto done;
|
||||
for(i=0;i<nclistlength(matches);i++) {
|
||||
const char* p;
|
||||
const char* key = nclistget(matches,i);
|
||||
size_t keylen = strlen(key);
|
||||
const char* name = nclistget(matches,i);
|
||||
size_t namelen= strlen(name);
|
||||
/* Ignore keys that start with .z or .nc or a potential chunk name */
|
||||
if(keylen >= 3 && key[0] == '.' && key[1] == 'n' && key[2] == 'c')
|
||||
if(namelen >= 3 && name[0] == '.' && name[1] == 'n' && name[2] == 'c')
|
||||
continue;
|
||||
if(keylen >= 2 && key[0] == '.' && key[1] == 'z')
|
||||
if(namelen >= 2 && name[0] == '.' && name[1] == 'z')
|
||||
continue;
|
||||
for(p=key;*p;p++) {
|
||||
for(p=name;*p;p++) {
|
||||
if(*p != '.' && strchr("0123456789",*p) == NULL) break;
|
||||
}
|
||||
if(*p == '\0') continue; /* looks like a chunk name */
|
||||
/* Create <prefix>/<key>/<tag> and see if it exists */
|
||||
/* Create <prefix>/<name>/<tag> and see if it exists */
|
||||
ncbytesclear(path);
|
||||
ncbytescat(path,prefix);
|
||||
ncbytescat(path,"/");
|
||||
ncbytescat(path,key);
|
||||
ncbytescat(path,name);
|
||||
ncbytescat(path,tag);
|
||||
/* See if this object exists */
|
||||
if((stat = nczmap_exists(map,ncbytescontents(path))) == NC_NOERR)
|
||||
nclistpush(objlist,key);
|
||||
nclistpush(objlist,name);
|
||||
}
|
||||
|
||||
done:
|
||||
@ -777,3 +761,120 @@ NCZ_create_fill_chunk(size64_t chunksize, size_t typesize, void* fill, void** fi
|
||||
return NC_NOERR;
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
/* S3 utilities */
|
||||
|
||||
EXTERNL int
|
||||
NCZ_s3urlprocess(NCURI* url, ZS3INFO* s3)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
NClist* segments = NULL;
|
||||
NCbytes* buf = ncbytesnew();
|
||||
|
||||
if(url == NULL)
|
||||
{stat = NC_EURL; goto done;}
|
||||
/* do some verification */
|
||||
if(strcmp(url->protocol,"https") != 0)
|
||||
{stat = NC_EURL; goto done;}
|
||||
|
||||
/* Path better look absolute */
|
||||
if(!nczm_isabsolutepath(url->path))
|
||||
{stat = NC_EURL; goto done;}
|
||||
|
||||
/* Distinguish path-style from virtual-host style from other:
|
||||
Virtual: https://bucket-name.s3.Region.amazonaws.com/<root>
|
||||
Path: https://s3.Region.amazonaws.com/bucket-name/<root>
|
||||
Other: https://<host>/bucketname/<root>
|
||||
*/
|
||||
if(url->host == NULL || strlen(url->host) == 0)
|
||||
{stat = NC_EURL; goto done;}
|
||||
if(endswith(url->host,AWSHOST)) { /* Virtual or path */
|
||||
segments = nclistnew();
|
||||
/* split the hostname by "." */
|
||||
if((stat = nczm_split_delim(url->host,'.',segments))) goto done;
|
||||
switch (nclistlength(segments)) {
|
||||
default: stat = NC_EURL; goto done;
|
||||
case 4:
|
||||
if(strcasecmp(nclistget(segments,0),"s3")!=0)
|
||||
{stat = NC_EURL; goto done;}
|
||||
s3->urlformat = UF_PATH;
|
||||
s3->region = strdup(nclistget(segments,1));
|
||||
break;
|
||||
case 5:
|
||||
if(strcasecmp(nclistget(segments,1),"s3")!=0)
|
||||
{stat = NC_EURL; goto done;}
|
||||
s3->urlformat = UF_VIRTUAL;
|
||||
s3->region = strdup(nclistget(segments,2));
|
||||
s3->bucket = strdup(nclistget(segments,0));
|
||||
break;
|
||||
}
|
||||
/* Rebuild host to look like path-style */
|
||||
ncbytescat(buf,"s3.");
|
||||
ncbytescat(buf,s3->region);
|
||||
ncbytescat(buf,AWSHOST);
|
||||
s3->host = ncbytesextract(buf);
|
||||
} else {
|
||||
s3->urlformat = UF_OTHER;
|
||||
if((s3->host = strdup(url->host))==NULL)
|
||||
{stat = NC_ENOMEM; goto done;}
|
||||
}
|
||||
/* Do fixups to make everything look like it was path style */
|
||||
switch (s3->urlformat) {
|
||||
case UF_PATH:
|
||||
case UF_OTHER:
|
||||
/* We have to process the path to get the bucket, and remove it in the path */
|
||||
if(url->path != NULL && strlen(url->path) > 0) {
|
||||
/* split the path by "/" */
|
||||
nclistfreeall(segments);
|
||||
segments = nclistnew();
|
||||
if((stat = nczm_split_delim(url->path,'/',segments))) goto done;
|
||||
if(nclistlength(segments) == 0)
|
||||
{stat = NC_EURL; goto done;}
|
||||
s3->bucket = ((char*)nclistremove(segments,0));
|
||||
if(nclistlength(segments) > 0) {
|
||||
if((stat = nczm_join(segments,&s3->rootkey))) goto done;
|
||||
} else
|
||||
s3->rootkey = NULL;
|
||||
nclistfreeall(segments); segments = NULL;
|
||||
}
|
||||
break;
|
||||
case UF_VIRTUAL:
|
||||
if(url->path == NULL || strlen(url->path) == 0)
|
||||
s3->rootkey = NULL;
|
||||
else
|
||||
s3->rootkey = strdup(url->path);
|
||||
break;
|
||||
default: stat = NC_EURL; goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
ncbytesfree(buf);
|
||||
nclistfreeall(segments);
|
||||
return stat;
|
||||
}
|
||||
|
||||
int
|
||||
NCZ_s3clear(ZS3INFO* s3)
|
||||
{
|
||||
if(s3) {
|
||||
nullfree(s3->host);
|
||||
nullfree(s3->region);
|
||||
nullfree(s3->bucket);
|
||||
nullfree(s3->rootkey);
|
||||
}
|
||||
return NC_NOERR;
|
||||
}
|
||||
|
||||
static int
|
||||
endswith(const char* s, const char* suffix)
|
||||
{
|
||||
ssize_t ls, lsf, delta;
|
||||
if(s == NULL || suffix == NULL) return 0;
|
||||
ls = strlen(s);
|
||||
lsf = strlen(suffix);
|
||||
delta = (ls - lsf);
|
||||
if(delta < 0) return 0;
|
||||
if(memcmp(s+delta,suffix,lsf)!=0) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -225,7 +225,7 @@ NCZ_transfer(struct Common* common, NCZSlice* slices)
|
||||
fprintf(stderr,"case: wholechunk: chunkindices: %s\n",nczprint_vector(common->rank,chunkindices));
|
||||
/* Read the chunk */
|
||||
switch ((stat = common->reader.read(common->reader.source, chunkindices, &chunkdata))) {
|
||||
case NC_ENOTFOUND: /* cache created the chunk */
|
||||
case NC_EEMPTY: /* cache created the chunk */
|
||||
if((stat = NCZ_fillchunk(chunkdata,common))) goto done;
|
||||
break;
|
||||
case NC_NOERR: break;
|
||||
@ -297,7 +297,7 @@ NCZ_transfer(struct Common* common, NCZSlice* slices)
|
||||
/* Read from cache */
|
||||
stat = common->reader.read(common->reader.source, chunkindices, &chunkdata);
|
||||
switch (stat) {
|
||||
case NC_ENOTFOUND: /* cache created the chunk */
|
||||
case NC_EEMPTY: /* cache created the chunk */
|
||||
if((stat = NCZ_fillchunk(chunkdata,common))) goto done;
|
||||
break;
|
||||
case NC_NOERR: break;
|
||||
@ -728,7 +728,7 @@ NCZ_transferscalar(struct Common* common)
|
||||
/* Read from single chunk from cache */
|
||||
chunkindices[0] = 0;
|
||||
switch ((stat = common->reader.read(common->reader.source, chunkindices, &chunkdata))) {
|
||||
case NC_ENOTFOUND: /* cache created the chunk */
|
||||
case NC_EEMPTY: /* cache created the chunk */
|
||||
if((stat = NCZ_fillchunk(chunkdata,common))) goto done;
|
||||
break;
|
||||
case NC_NOERR: break;
|
||||
|
@ -26,7 +26,6 @@
|
||||
/* Forward */
|
||||
static int get_chunk(NCZChunkCache* cache, NCZCacheEntry* entry);
|
||||
static int put_chunk(NCZChunkCache* cache, const NCZCacheEntry*);
|
||||
static int create_chunk(NCZChunkCache* cache, NCZCacheEntry* entry);
|
||||
static int makeroom(NCZChunkCache* cache);
|
||||
|
||||
/**************************************************/
|
||||
@ -195,6 +194,9 @@ void
|
||||
NCZ_free_chunk_cache(NCZChunkCache* cache)
|
||||
{
|
||||
if(cache == NULL) return;
|
||||
|
||||
ZTRACE(4,"cache.var=%s",cache->var->hdr.name);
|
||||
|
||||
/* Iterate over the entries */
|
||||
while(nclistlength(cache->mru) > 0) {
|
||||
void* ptr;
|
||||
@ -211,6 +213,7 @@ fprintf(stderr,"|cache.free|=%ld\n",nclistlength(cache->mru));
|
||||
cache->mru = NULL;
|
||||
nullfree(cache->fillchunk);
|
||||
nullfree(cache);
|
||||
(void)ZUNTRACE(NC_NOERR);
|
||||
}
|
||||
|
||||
size64_t
|
||||
@ -271,12 +274,8 @@ NCZ_read_cache_chunk(NCZChunkCache* cache, const size64_t* indices, void** datap
|
||||
switch (stat) {
|
||||
case NC_NOERR: break;
|
||||
case NC_EEMPTY:
|
||||
case NC_ENOTFOUND: /*signals the chunk needs to be created */
|
||||
/* If the file is read-only, then fake the chunk */
|
||||
entry->modified = (!file->no_write);
|
||||
if(!file->no_write) {
|
||||
if((stat = create_chunk(cache,entry))) goto done;
|
||||
}
|
||||
entry->modified = (file->no_write?0:1);
|
||||
#ifdef FILLONREAD
|
||||
/* apply fill value */
|
||||
memcpy(entry->data,cache->fillchunk,cache->chunksize);
|
||||
@ -295,9 +294,9 @@ fprintf(stderr,"|cache.read.lru|=%ld\n",nclistlength(cache->mru));
|
||||
#endif
|
||||
if(datap) *datap = entry->data;
|
||||
entry = NULL;
|
||||
if(created) stat = NC_ENOTFOUND;
|
||||
|
||||
|
||||
done:
|
||||
if(created && stat == NC_NOERR) stat = NC_EEMPTY; /* tell upper layers */
|
||||
if(entry) {nullfree(entry->data); nullfree(entry->key);}
|
||||
nullfree(entry);
|
||||
return THROW(stat);
|
||||
@ -375,6 +374,8 @@ NCZ_flush_chunk_cache(NCZChunkCache* cache)
|
||||
int stat = NC_NOERR;
|
||||
size_t i;
|
||||
|
||||
ZTRACE(4,"cache.var=%s |cache|=%d",cache->var->hdr.name,(int)nclistlength(cache->mru));
|
||||
|
||||
if(NCZ_cache_size(cache) == 0) goto done;
|
||||
|
||||
/* Iterate over the entries in hashmap */
|
||||
@ -389,7 +390,7 @@ NCZ_flush_chunk_cache(NCZChunkCache* cache)
|
||||
}
|
||||
|
||||
done:
|
||||
return THROW(stat);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
#if 0
|
||||
@ -478,6 +479,7 @@ put_chunk(NCZChunkCache* cache, const NCZCacheEntry* entry)
|
||||
NCZ_FILE_INFO_T* zfile = NULL;
|
||||
NCZMAP* map = NULL;
|
||||
|
||||
ZTRACE(5,"cache.var=%s entry.key=%s",cache->var->hdr.name,entry->key);
|
||||
LOG((3, "%s: var: %p", __func__, cache->var));
|
||||
|
||||
zfile = ((cache->var->container)->nc4_info)->format_file_info;
|
||||
@ -485,18 +487,13 @@ put_chunk(NCZChunkCache* cache, const NCZCacheEntry* entry)
|
||||
|
||||
stat = nczmap_write(map,entry->key,0,cache->chunksize,entry->data);
|
||||
switch(stat) {
|
||||
case NC_NOERR: break;
|
||||
case NC_EEMPTY:
|
||||
/* Create the chunk */
|
||||
if((stat = nczmap_defineobj(map,entry->key))) goto done;
|
||||
/* write again */
|
||||
if((stat = nczmap_write(map,entry->key,0,cache->chunksize,entry->data)))
|
||||
goto done;
|
||||
case NC_NOERR:
|
||||
break;
|
||||
case NC_EEMPTY:
|
||||
default: goto done;
|
||||
}
|
||||
done:
|
||||
return THROW(stat);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -517,6 +514,8 @@ get_chunk(NCZChunkCache* cache, NCZCacheEntry* entry)
|
||||
NC_FILE_INFO_T* file = NULL;
|
||||
NCZ_FILE_INFO_T* zfile = NULL;
|
||||
|
||||
ZTRACE(5,"cache.var=%s entry.key=%s",cache->var->hdr.name,entry->key);
|
||||
|
||||
LOG((3, "%s: file: %p", __func__, file));
|
||||
|
||||
file = (cache->var->container)->nc4_info;
|
||||
@ -526,29 +525,9 @@ get_chunk(NCZChunkCache* cache, NCZCacheEntry* entry)
|
||||
|
||||
stat = nczmap_read(map,entry->key,0,cache->chunksize,(char*)entry->data);
|
||||
|
||||
return THROW(stat);
|
||||
return ZUNTRACE(stat);
|
||||
}
|
||||
|
||||
static int
|
||||
create_chunk(NCZChunkCache* cache, NCZCacheEntry* entry)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
NC_FILE_INFO_T* file = NULL;
|
||||
NCZ_FILE_INFO_T* zfile = NULL;
|
||||
NCZMAP* map = NULL;
|
||||
|
||||
file = (cache->var->container)->nc4_info;
|
||||
zfile = file->format_file_info;
|
||||
map = zfile->map;
|
||||
|
||||
/* Create the chunk */
|
||||
if((stat = nczmap_defineobj(map,entry->key))) goto done;
|
||||
entry->modified = 1; /* mark as modified */
|
||||
/* let higher function decide on fill */
|
||||
|
||||
done:
|
||||
return THROW(stat);
|
||||
}
|
||||
|
||||
int
|
||||
NCZ_buildchunkpath(NCZChunkCache* cache, const size64_t* chunkindices, char** keyp)
|
||||
|
@ -40,7 +40,7 @@ IF(ENABLE_TESTS)
|
||||
BUILD_BIN_TEST(tst_zchunks ${COMMONSRC})
|
||||
BUILD_BIN_TEST(tst_zchunks2 ${COMMONSRC})
|
||||
BUILD_BIN_TEST(tst_zchunks3 ${COMMONSRC})
|
||||
BUILD_BIN_TEST(tst_fillonlyz)
|
||||
BUILD_BIN_TEST(tst_fillonlyz ${TSTCOMMONSRC})
|
||||
|
||||
TARGET_INCLUDE_DIRECTORIES(ut_map PUBLIC ../libnczarr)
|
||||
TARGET_INCLUDE_DIRECTORIES(ut_mapapi PUBLIC ../libnczarr)
|
||||
@ -50,6 +50,7 @@ IF(ENABLE_TESTS)
|
||||
TARGET_INCLUDE_DIRECTORIES(tst_zchunks PUBLIC ../libnczarr)
|
||||
TARGET_INCLUDE_DIRECTORIES(tst_zchunks2 PUBLIC ../libnczarr)
|
||||
TARGET_INCLUDE_DIRECTORIES(tst_zchunks3 PUBLIC ../libnczarr)
|
||||
TARGET_INCLUDE_DIRECTORIES(tst_fillonlyz PUBLIC ../libnczarr)
|
||||
|
||||
# Helper programs for testing
|
||||
BUILD_BIN_TEST(zmapio ${COMMONSRC})
|
||||
@ -59,6 +60,10 @@ IF(ENABLE_TESTS)
|
||||
TARGET_INCLUDE_DIRECTORIES(zisjson PUBLIC ../libnczarr)
|
||||
BUILD_BIN_TEST(zs3parse ${COMMONSRC})
|
||||
TARGET_INCLUDE_DIRECTORIES(zs3parse PUBLIC ../libnczarr)
|
||||
if(ENABLE_NCZARR_S3)
|
||||
BUILD_BIN_TEST(s3util ${COMMONSRC})
|
||||
TARGET_INCLUDE_DIRECTORIES(s3util PUBLIC ../libnczarr)
|
||||
endif()
|
||||
|
||||
SET(ncdumpchunks_SOURCE ncdumpchunks.c)
|
||||
IF(USE_X_GETOPT)
|
||||
@ -78,12 +83,13 @@ IF(ENABLE_TESTS)
|
||||
ENDIF()
|
||||
add_sh_test(nczarr_test run_ncgen4)
|
||||
|
||||
IF(FALSE) # Suppress for now
|
||||
BUILD_BIN_TEST(tst_chunkcases ${TSTCOMMONSRC})
|
||||
TARGET_INCLUDE_DIRECTORIES(tst_chunkcases PUBLIC ../libnczarr)
|
||||
add_sh_test(nczarr_test run_chunkcases)
|
||||
ENDIF()
|
||||
|
||||
if(ENABLE_NCZARR_S3)
|
||||
add_sh_test(nczarr_test run_s3_cleanup)
|
||||
ENDIF()
|
||||
ENDIF(BUILD_UTILITIES)
|
||||
|
||||
ENDIF(ENABLE_TESTS)
|
||||
|
@ -33,6 +33,7 @@ ut_mapapi_SOURCES = ut_mapapi.c ${commonsrc}
|
||||
ut_json_SOURCES = ut_json.c ${commonsrc}
|
||||
ut_projections_SOURCES = ut_projections.c ${commonsrc}
|
||||
ut_chunking_SOURCES = ut_chunking.c ${commonsrc}
|
||||
tst_fillonlyz_SOURCES = tst_fillonlyz.c ${tstcommonsrc}
|
||||
|
||||
check_PROGRAMS += tst_zchunks tst_zchunks2 tst_zchunks3 tst_fillonlyz
|
||||
|
||||
@ -50,19 +51,16 @@ endif
|
||||
|
||||
TESTS += run_ncgen4.sh
|
||||
|
||||
# Temporarily disable
|
||||
if AX_IGNORE
|
||||
check_PROGRAMS += tst_chunkcases
|
||||
tst_chunkcases_SOURCES = tst_chunkcases.c ${tstcommonsrc}
|
||||
TESTS += run_chunkcases.sh
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
if BUILD_BENCHMARKS
|
||||
if BUILD_UTILITIES
|
||||
|
||||
UTILSRC = bm_utils.c timer_utils.c
|
||||
UTILSRC = bm_utils.c timer_utils.c tst_utils.c
|
||||
|
||||
bm_chunks3_SOURCES = bm_chunks3.c ${UTILSRC}
|
||||
|
||||
@ -84,6 +82,12 @@ zisjson_SOURCES = zisjson.c
|
||||
noinst_PROGRAMS += zs3parse
|
||||
zs3parse_SOURCES = zs3parse.c
|
||||
|
||||
if ENABLE_NCZARR_S3
|
||||
noinst_PROGRAMS += s3util
|
||||
s3util_SOURCES = s3util.c
|
||||
TESTS += run_s3_cleanup.sh
|
||||
endif
|
||||
|
||||
# Given a netcdf4|NCZarr file, dump the actual chunk contents.
|
||||
# Used to validate nczarr chunking code.
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/libnczarr
|
||||
@ -92,38 +96,13 @@ ncdumpchunks_SOURCES = ncdumpchunks.c
|
||||
|
||||
EXTRA_DIST = CMakeLists.txt \
|
||||
run_ut_map.sh run_ut_mapapi.sh run_ut_misc.sh run_ut_chunk.sh run_ncgen4.sh \
|
||||
run_nccopyz.sh run_fillonlyz.sh run_chunkcases.sh test_nczarr.sh run_perf_chunks1.sh \
|
||||
ref_ut_map_readmeta_nzf.txt \
|
||||
ref_ut_map_writedata_nzf.cdl \
|
||||
ref_ut_map_writemeta_nzf.cdl \
|
||||
ref_ut_map_writemeta_nz4.cdl \
|
||||
ref_ut_map_writedata_nz4.cdl \
|
||||
ref_ut_map_write2meta_nzf.cdl \
|
||||
ref_ut_map_write2meta_nz4.cdl \
|
||||
ref_ut_map_search_nzf.txt \
|
||||
ref_ut_map_search_nz4.txt \
|
||||
ref_ut_map_readmeta_nz4.txt \
|
||||
ref_ut_map_readdata_nz4.txt \
|
||||
ref_ut_map_create_nz4.cdl \
|
||||
ref_ut_json_parse.txt \
|
||||
ref_ut_json_build.txt \
|
||||
ref_t_meta_var1.cdl \
|
||||
ref_t_meta_dim1.cdl \
|
||||
ref_ut_testmap_create_nz4.cdl \
|
||||
ref_ut_proj.txt \
|
||||
ref_ut_map_create_nzf.cdl \
|
||||
ref_ut_mapapi_create_nz4.cdl \
|
||||
ref_ut_mapapi_create_nzf.cdl \
|
||||
ref_ut_mapapi_create_s3.cdl \
|
||||
ref_ut_mapapi_data_nz4.cdl \
|
||||
ref_ut_mapapi_data_nzf.cdl \
|
||||
ref_ut_mapapi_data_s3.cdl \
|
||||
ref_ut_mapapi_meta_nz4.cdl \
|
||||
ref_ut_mapapi_meta_nzf.cdl \
|
||||
ref_ut_mapapi_meta_s3.cdl \
|
||||
ref_ut_mapapi_search_nz4.txt \
|
||||
ref_ut_mapapi_search_nzf.txt \
|
||||
ref_ut_mapapi_search_s3.txt \
|
||||
run_nccopyz.sh run_fillonlyz.sh run_chunkcases.sh test_nczarr.sh run_perf_chunks1.sh run_s3_cleanup.sh \
|
||||
ref_ut_map_create.cdl ref_ut_map_writedata.cdl ref_ut_map_writemeta2.cdl ref_ut_map_writemeta.cdl \
|
||||
ref_ut_map_readmeta.txt ref_ut_map_readmeta2.txt ref_ut_map_search.txt \
|
||||
ref_ut_mapapi_create.cdl ref_ut_mapapi_data.cdl ref_ut_mapapi_meta.cdl ref_ut_mapapi_search.txt \
|
||||
ref_t_meta_dim1.cdl ref_t_meta_var1.cdl \
|
||||
ref_ut_json_build.txt ref_ut_json_parse.txt \
|
||||
ref_ut_proj.txt ref_ut_testmap_create.cdl \
|
||||
ref_perdimspecs.cdl ref_fillonly.cdl \
|
||||
ref_whole.cdl ref_whole.txt \
|
||||
ref_skip.cdl ref_skip.txt ref_skipw.cdl \
|
||||
@ -131,13 +110,8 @@ ref_rem.cdl ref_rem.dmp ref_ndims.cdl ref_ndims.dmp \
|
||||
ref_misc1.cdl ref_misc1.dmp \
|
||||
ref_avail1.cdl ref_avail1.dmp ref_avail1.txt
|
||||
|
||||
CLEANFILES = test.nzf test.nz4 test.nz4 \
|
||||
testmap.nzf testmap.nz4 testmapapi.nzf testmapapi.nz4 \
|
||||
tst_chunks.nz4 tst_chunks2.nc.nz4 \
|
||||
ut_*.txt ut*.cdl tmp*.nc tmp*.cdl tmp*.txt tmp*.dmp test.nzf \
|
||||
tst_chunks3.nc
|
||||
CLEANFILES = ut_*.txt ut*.cdl tmp*.nc tmp*.cdl tmp*.txt tmp*.dmp tmp*.zip tmp*.nc
|
||||
|
||||
# Remove directories
|
||||
clean-local:
|
||||
rm -fr tst_chunks.nzf tst_chunks2.nzf tst_perdimspecs.nzf testmap.nzf test.nzf tmp*.nzf \
|
||||
test_mapapi.nzf test_mapapi.nz4 tmp*.nz4
|
||||
rm -fr tmp*.file results.file results.s3 results.zip
|
||||
|
@ -105,6 +105,7 @@ getoptions(int* argcp, char*** argvp, struct Options* opt)
|
||||
int tag;
|
||||
int argc = *argcp;
|
||||
char** argv = *argvp;
|
||||
const char* nczarr_s3_test_url = ncz_gets3testurl();
|
||||
|
||||
memset((void*)opt,0,sizeof(struct Options));
|
||||
if(argc <= 1) return NC_NOERR;
|
||||
@ -144,13 +145,15 @@ fprintf(stderr,"arg=%s value=%s\n",argv[optind-1],optarg);
|
||||
opt->pathtemplate = strdup(optarg);
|
||||
break;
|
||||
case OPT_FORMAT:
|
||||
if(strcasecmp(optarg,"nz4")==0)
|
||||
opt->format = NC_FORMATX_NC4;
|
||||
else if(strcasecmp(optarg,"nzf")==0)
|
||||
if(strcasecmp(optarg,"file")==0)
|
||||
opt->format = NC_FORMATX_NCZARR;
|
||||
opt->impl = NCZM_FILE;
|
||||
else if(strcasecmp(optarg,"zip")==0)
|
||||
opt->format = NC_FORMATX_NCZARR;
|
||||
opt->impl = NCZM_ZIP;
|
||||
else if(strcasecmp(optarg,"s3")==0) {
|
||||
opt->format = NC_FORMATX_NCZARR;
|
||||
opt->iss3 = 1;
|
||||
opt->impl = NCZM_S3;
|
||||
} else
|
||||
{fprintf(stderr,"illegal format\n"); return NC_EINVAL;}
|
||||
break;
|
||||
@ -190,10 +193,21 @@ fprintf(stderr,"arg=%s value=%s\n",argv[optind-1],optarg);
|
||||
switch(opt->format) {
|
||||
case NC_FORMATX_NCZARR:
|
||||
if(opt->pathtemplate == NULL) {
|
||||
if(opt->iss3)
|
||||
opt->pathtemplate = strdup("https://stratus.ucar.edu/unidata-netcdf-zarr-testing/%s.%s#mode=nczarr,s3");
|
||||
else
|
||||
opt->pathtemplate = strdup("file://%s.%s#mode=nczarr,nzf");
|
||||
size_t ptlen;
|
||||
switch (opt->impl) {
|
||||
case NCZM_S3:
|
||||
ptlen = strlen(nczarr_s3_test_url) + strlen("/netcdf-c/%s.%s#mode=nczarr,s3");
|
||||
opt->pathtemplate = (char*)calloc(1,ptlen+1);
|
||||
if(opt->template == NULL) return NC_ENOMEM;
|
||||
strlcat(opt->pathtemplate,nczarr_s3_test_url,ptlen+1);
|
||||
strlcat(opt->pathtemplate,"/netcdf-c/%s.%s#mode=nczarr,s3",ptlen+1);
|
||||
break;
|
||||
case NCZM_FILE:
|
||||
opt->pathtemplate = strdup("file://%s.%s#mode=nczarr,file");
|
||||
case NCZM_ZIP:
|
||||
opt->pathtemplate = strdup("file://%s.%s#mode=nczarr,zip");
|
||||
default: abort();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NC_FORMATX_NC4:
|
||||
@ -232,7 +246,13 @@ EXTERNL const char*
|
||||
formatname(const struct Options* o)
|
||||
{
|
||||
switch (o->format) {
|
||||
case NC_FORMATX_NCZARR: return (o->iss3?"s3":"nzf");
|
||||
case NC_FORMATX_NCZARR:
|
||||
switch (o->impl) {
|
||||
case NCZM_S3: return "s3";
|
||||
case NCZM_NC4: return "nz4";
|
||||
case NCZM_FILE: return "file";
|
||||
case NCZM_ZIP: return "zip";
|
||||
break;
|
||||
case NC_FORMATX_NC4: /* fall thru */
|
||||
return "nz4";
|
||||
default:
|
||||
|
@ -369,7 +369,7 @@ dump(Format* format)
|
||||
for(r=0;r<format->rank;r++) zindices[r] = (size64_t)odom->index[r];
|
||||
switch (stat=NCZ_read_chunk(ncid, varid, zindices, chunkdata)) {
|
||||
case NC_NOERR: break;
|
||||
case NC_ENOTFOUND: holechunk = 1; break;
|
||||
case NC_EEMPTY: holechunk = 1; break;
|
||||
default: usage(stat);
|
||||
}
|
||||
break;
|
||||
@ -418,8 +418,7 @@ dump(Format* format)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const char* urlexts[] = {"nzf", "nz4", NULL};
|
||||
static const char* urlexts[] = {"file", "zip", NULL};
|
||||
|
||||
static const char*
|
||||
filenamefor(const char* f0)
|
||||
|
1
nczarr_test/ref_ut_map_create.cdl
Normal file
1
nczarr_test/ref_ut_map_create.cdl
Normal file
@ -0,0 +1 @@
|
||||
[0] /.nczarr : (0) ||
|
@ -1,10 +0,0 @@
|
||||
netcdf testmap {
|
||||
|
||||
group: _nczarr {
|
||||
dimensions:
|
||||
data_dim = UNLIMITED ; // (0 currently)
|
||||
variables:
|
||||
ubyte data(data_dim) ;
|
||||
data:
|
||||
} // group _nczarr
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
testmap.nzf
|
||||
testmap.nzf/.nczarr : ||
|
4
nczarr_test/ref_ut_map_readmeta.txt
Normal file
4
nczarr_test/ref_ut_map_readmeta.txt
Normal file
@ -0,0 +1,4 @@
|
||||
/meta1/.zarray: |{
|
||||
"foo": 42,
|
||||
"bar": "apples",
|
||||
"baz": [1, 2, 3, 4]}|
|
5
nczarr_test/ref_ut_map_readmeta2.txt
Normal file
5
nczarr_test/ref_ut_map_readmeta2.txt
Normal file
@ -0,0 +1,5 @@
|
||||
/meta2/.nczvar: |{
|
||||
"foo": 42,
|
||||
"bar": "apples",
|
||||
"baz": [1, 2, 3, 4],
|
||||
"extra": 137}|
|
8
nczarr_test/ref_ut_map_search.txt
Normal file
8
nczarr_test/ref_ut_map_search.txt
Normal file
@ -0,0 +1,8 @@
|
||||
[0] /
|
||||
[1] /.nczarr
|
||||
[2] /data1
|
||||
[3] /data1/0
|
||||
[4] /meta1
|
||||
[5] /meta1/.zarray
|
||||
[6] /meta2
|
||||
[7] /meta2/.nczvar
|
@ -1,42 +0,0 @@
|
||||
netcdf testmap {
|
||||
|
||||
group: _nczarr {
|
||||
dimensions:
|
||||
data_dim = UNLIMITED ; // (0 currently)
|
||||
variables:
|
||||
ubyte data(data_dim) ;
|
||||
data:
|
||||
} // group _nczarr
|
||||
|
||||
group: meta1 {
|
||||
|
||||
group: _zarray {
|
||||
dimensions:
|
||||
data_dim = UNLIMITED ; // (50 currently)
|
||||
variables:
|
||||
ubyte data(data_dim) ;
|
||||
data:
|
||||
|
||||
data = 123, 10, 34, 102, 111, 111, 34, 58, 32, 52, 50, 44, 10, 34, 98,
|
||||
97, 114, 34, 58, 32, 34, 97, 112, 112, 108, 101, 115, 34, 44, 10, 34,
|
||||
98, 97, 122, 34, 58, 32, 91, 49, 44, 32, 50, 44, 32, 51, 44, 32, 52,
|
||||
93, 125 ;
|
||||
} // group _zarray
|
||||
} // group meta1
|
||||
|
||||
group: meta2 {
|
||||
|
||||
group: _nczvar {
|
||||
dimensions:
|
||||
data_dim = UNLIMITED ; // (64 currently)
|
||||
variables:
|
||||
ubyte data(data_dim) ;
|
||||
data:
|
||||
|
||||
data = 123, 10, 34, 102, 111, 111, 34, 58, 32, 52, 50, 44, 10, 34, 98,
|
||||
97, 114, 34, 58, 32, 34, 97, 112, 112, 108, 101, 115, 34, 44, 10, 34,
|
||||
98, 97, 122, 34, 58, 32, 91, 49, 44, 32, 50, 44, 32, 51, 44, 32, 52,
|
||||
93, 44, 10, 34, 101, 120, 116, 114, 97, 34, 58, 32, 49, 51, 55, 125 ;
|
||||
} // group _nczvar
|
||||
} // group meta2
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
testmap.nzf
|
||||
testmap.nzf/.nczarr : ||
|
||||
testmap.nzf/meta1
|
||||
testmap.nzf/meta1/.zarray : |{ "foo": 42, "bar": "apples", "baz": [1, 2, 3, 4]}|
|
||||
testmap.nzf/meta2
|
||||
testmap.nzf/meta2/.nczvar : |{ "foo": 42, "bar": "apples", "baz": [1, 2, 3, 4], "extra": 137}|
|
11
nczarr_test/ref_ut_map_writedata.cdl
Normal file
11
nczarr_test/ref_ut_map_writedata.cdl
Normal file
@ -0,0 +1,11 @@
|
||||
[0] /.nczarr : (0) ||
|
||||
[2] /data1/0 : (25) (int) |0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24|
|
||||
[4] /meta1/.zarray : (50) |{
|
||||
"foo": 42,
|
||||
"bar": "apples",
|
||||
"baz": [1, 2, 3, 4]}|
|
||||
[6] /meta2/.nczvar : (64) |{
|
||||
"foo": 42,
|
||||
"bar": "apples",
|
||||
"baz": [1, 2, 3, 4],
|
||||
"extra": 137}|
|
@ -1,59 +0,0 @@
|
||||
netcdf testmap {
|
||||
|
||||
group: _nczarr {
|
||||
dimensions:
|
||||
data_dim = UNLIMITED ; // (0 currently)
|
||||
variables:
|
||||
ubyte data(data_dim) ;
|
||||
data:
|
||||
} // group _nczarr
|
||||
|
||||
group: meta1 {
|
||||
|
||||
group: _zarray {
|
||||
dimensions:
|
||||
data_dim = UNLIMITED ; // (50 currently)
|
||||
variables:
|
||||
ubyte data(data_dim) ;
|
||||
data:
|
||||
|
||||
data = 123, 10, 34, 102, 111, 111, 34, 58, 32, 52, 50, 44, 10, 34, 98,
|
||||
97, 114, 34, 58, 32, 34, 97, 112, 112, 108, 101, 115, 34, 44, 10, 34,
|
||||
98, 97, 122, 34, 58, 32, 91, 49, 44, 32, 50, 44, 32, 51, 44, 32, 52,
|
||||
93, 125 ;
|
||||
} // group _zarray
|
||||
} // group meta1
|
||||
|
||||
group: meta2 {
|
||||
|
||||
group: _nczvar {
|
||||
dimensions:
|
||||
data_dim = UNLIMITED ; // (64 currently)
|
||||
variables:
|
||||
ubyte data(data_dim) ;
|
||||
data:
|
||||
|
||||
data = 123, 10, 34, 102, 111, 111, 34, 58, 32, 52, 50, 44, 10, 34, 98,
|
||||
97, 114, 34, 58, 32, 34, 97, 112, 112, 108, 101, 115, 34, 44, 10, 34,
|
||||
98, 97, 122, 34, 58, 32, 91, 49, 44, 32, 50, 44, 32, 51, 44, 32, 52,
|
||||
93, 44, 10, 34, 101, 120, 116, 114, 97, 34, 58, 32, 49, 51, 55, 125 ;
|
||||
} // group _nczvar
|
||||
} // group meta2
|
||||
|
||||
group: data1 {
|
||||
|
||||
group: \0 {
|
||||
dimensions:
|
||||
data_dim = UNLIMITED ; // (100 currently)
|
||||
variables:
|
||||
ubyte data(data_dim) ;
|
||||
data:
|
||||
|
||||
data = 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0,
|
||||
0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 9, 0, 0, 0, 10, 0, 0, 0,
|
||||
11, 0, 0, 0, 12, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 15, 0, 0, 0, 16,
|
||||
0, 0, 0, 17, 0, 0, 0, 18, 0, 0, 0, 19, 0, 0, 0, 20, 0, 0, 0, 21, 0,
|
||||
0, 0, 22, 0, 0, 0, 23, 0, 0, 0, 24, 0, 0, 0 ;
|
||||
} // group \0
|
||||
} // group data1
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
testmap.nzf
|
||||
testmap.nzf/.nczarr : ||
|
||||
testmap.nzf/data1
|
||||
testmap.nzf/data1/0 : |000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000|
|
||||
testmap.nzf/meta1
|
||||
testmap.nzf/meta1/.zarray : |{ "foo": 42, "bar": "apples", "baz": [1, 2, 3, 4]}|
|
||||
testmap.nzf/meta2
|
||||
testmap.nzf/meta2/.nczvar : |{ "foo": 42, "bar": "apples", "baz": [1, 2, 3, 4], "extra": 137}|
|
5
nczarr_test/ref_ut_map_writemeta.cdl
Normal file
5
nczarr_test/ref_ut_map_writemeta.cdl
Normal file
@ -0,0 +1,5 @@
|
||||
[0] /.nczarr : (0) ||
|
||||
[2] /meta1/.zarray : (50) |{
|
||||
"foo": 42,
|
||||
"bar": "apples",
|
||||
"baz": [1, 2, 3, 4]}|
|
10
nczarr_test/ref_ut_map_writemeta2.cdl
Normal file
10
nczarr_test/ref_ut_map_writemeta2.cdl
Normal file
@ -0,0 +1,10 @@
|
||||
[0] /.nczarr : (0) ||
|
||||
[2] /meta1/.zarray : (50) |{
|
||||
"foo": 42,
|
||||
"bar": "apples",
|
||||
"baz": [1, 2, 3, 4]}|
|
||||
[4] /meta2/.nczvar : (64) |{
|
||||
"foo": 42,
|
||||
"bar": "apples",
|
||||
"baz": [1, 2, 3, 4],
|
||||
"extra": 137}|
|
@ -1,26 +0,0 @@
|
||||
netcdf testmap {
|
||||
|
||||
group: _nczarr {
|
||||
dimensions:
|
||||
data_dim = UNLIMITED ; // (0 currently)
|
||||
variables:
|
||||
ubyte data(data_dim) ;
|
||||
data:
|
||||
} // group _nczarr
|
||||
|
||||
group: meta1 {
|
||||
|
||||
group: _zarray {
|
||||
dimensions:
|
||||
data_dim = UNLIMITED ; // (50 currently)
|
||||
variables:
|
||||
ubyte data(data_dim) ;
|
||||
data:
|
||||
|
||||
data = 123, 10, 34, 102, 111, 111, 34, 58, 32, 52, 50, 44, 10, 34, 98,
|
||||
97, 114, 34, 58, 32, 34, 97, 112, 112, 108, 101, 115, 34, 44, 10, 34,
|
||||
98, 97, 122, 34, 58, 32, 91, 49, 44, 32, 50, 44, 32, 51, 44, 32, 52,
|
||||
93, 125 ;
|
||||
} // group _zarray
|
||||
} // group meta1
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
testmap.nzf
|
||||
testmap.nzf/.nczarr : ||
|
||||
testmap.nzf/meta1
|
||||
testmap.nzf/meta1/.zarray : |{ "foo": 42, "bar": "apples", "baz": [1, 2, 3, 4]}|
|
1
nczarr_test/ref_ut_mapapi_create.cdl
Normal file
1
nczarr_test/ref_ut_mapapi_create.cdl
Normal file
@ -0,0 +1 @@
|
||||
[0] /.nczarr : (0) ||
|
@ -1 +0,0 @@
|
||||
[1] /.nczarr : (0) ||
|
@ -1 +0,0 @@
|
||||
[1] /.nczarr : (0) ||
|
@ -1 +0,0 @@
|
||||
[1] /.nczarr : (0) ||
|
@ -1,8 +1,8 @@
|
||||
[1] /.nczarr : (50) |{
|
||||
[0] /.nczarr : (50) |{
|
||||
"foo": 42,
|
||||
"bar": "apples",
|
||||
"baz": [1, 2, 3, 4]}|
|
||||
[2] /data1 : (100) (ubyte) |0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 9, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 12, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 15, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 18, 0, 0, 0, 19, 0, 0, 0, 20, 0, 0, 0, 21, 0, 0, 0, 22, 0, 0, 0, 23, 0, 0, 0, 24, 0, 0, 0|
|
||||
[1] /data1 : (100) (ubyte) |0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 9, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 12, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 15, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 18, 0, 0, 0, 19, 0, 0, 0, 20, 0, 0, 0, 21, 0, 0, 0, 22, 0, 0, 0, 23, 0, 0, 0, 24, 0, 0, 0|
|
||||
[3] /meta1/.zarray : (34) |{
|
||||
"shape": [1,2,3],
|
||||
"dtype": "<1"}|
|
@ -1,8 +0,0 @@
|
||||
[1] /.nczarr : (50) |{
|
||||
"foo": 42,
|
||||
"bar": "apples",
|
||||
"baz": [1, 2, 3, 4]}|
|
||||
[2] /data1 : (100) (ubyte) |0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 9, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 12, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 15, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 18, 0, 0, 0, 19, 0, 0, 0, 20, 0, 0, 0, 21, 0, 0, 0, 22, 0, 0, 0, 23, 0, 0, 0, 24, 0, 0, 0|
|
||||
[4] /meta1/.zarray : (34) |{
|
||||
"shape": [1,2,3],
|
||||
"dtype": "<1"}|
|
@ -1,8 +0,0 @@
|
||||
[1] /.nczarr : (50) |{
|
||||
"foo": 42,
|
||||
"bar": "apples",
|
||||
"baz": [1, 2, 3, 4]}|
|
||||
[2] /data1 : (100) (ubyte) |0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 9, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 12, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 15, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 18, 0, 0, 0, 19, 0, 0, 0, 20, 0, 0, 0, 21, 0, 0, 0, 22, 0, 0, 0, 23, 0, 0, 0, 24, 0, 0, 0|
|
||||
[4] /meta1/.zarray : (34) |{
|
||||
"shape": [1,2,3],
|
||||
"dtype": "<1"}|
|
@ -1,4 +1,4 @@
|
||||
[1] /.nczarr : (50) |{
|
||||
[0] /.nczarr : (50) |{
|
||||
"foo": 42,
|
||||
"bar": "apples",
|
||||
"baz": [1, 2, 3, 4]}|
|
@ -1,7 +0,0 @@
|
||||
[1] /.nczarr : (50) |{
|
||||
"foo": 42,
|
||||
"bar": "apples",
|
||||
"baz": [1, 2, 3, 4]}|
|
||||
[3] /meta1/.zarray : (34) |{
|
||||
"shape": [1,2,3],
|
||||
"dtype": "<1"}|
|
@ -1,7 +0,0 @@
|
||||
[1] /.nczarr : (50) |{
|
||||
"foo": 42,
|
||||
"bar": "apples",
|
||||
"baz": [1, 2, 3, 4]}|
|
||||
[3] /meta1/.zarray : (34) |{
|
||||
"shape": [1,2,3],
|
||||
"dtype": "<1"}|
|
5
nczarr_test/ref_ut_mapapi_search.txt
Normal file
5
nczarr_test/ref_ut_mapapi_search.txt
Normal file
@ -0,0 +1,5 @@
|
||||
[0] /
|
||||
[1] /.nczarr
|
||||
[2] /data1
|
||||
[3] /meta1
|
||||
[4] /meta1/.zarray
|
@ -28,8 +28,8 @@ ZM="${execdir}/zmapio -t int"
|
||||
remfile() {
|
||||
case "$zext" in
|
||||
nc4) rm -fr $1 ;;
|
||||
nz4) rm -fr $1 ;;
|
||||
nzf) rm -fr $1 ;;
|
||||
file) rm -fr $1 ;;
|
||||
zip) rm -fr $1 ;;
|
||||
s3) ;;
|
||||
*) echo "no such extension: $zext" ; exit 1;;
|
||||
esac
|
||||
@ -38,8 +38,8 @@ remfile() {
|
||||
remfile() {
|
||||
case "$zext" in
|
||||
nc4) rm -fr $1 ;;
|
||||
nz4) rm -fr $1 ;;
|
||||
nzf) rm -fr $1 ;;
|
||||
file) rm -fr $1 ;;
|
||||
zip) rm -fr $1 ;;
|
||||
s3) ;;
|
||||
*) echo "no such extension: $zext" ; exit 1;;
|
||||
esac
|
||||
@ -50,8 +50,8 @@ makefile() {
|
||||
remfile $file
|
||||
case "$zext" in
|
||||
nc4) F=$file;;
|
||||
nz4) F=$fileurl;;
|
||||
nzf) F=$fileurl;;
|
||||
file) F=$fileurl;;
|
||||
zip) F=$fileurl;;
|
||||
s3) F=$fileurl;;
|
||||
*) echo "no such extension: $zext" ; exit 1;;
|
||||
esac
|
||||
@ -84,7 +84,7 @@ ${NCDUMP} $F > tmp_whole_${zext}.cdl
|
||||
diff -b ${srcdir}/ref_whole.cdl tmp_whole_${zext}.cdl
|
||||
|
||||
# Test skipping whole chunks
|
||||
necho "Test chunk skipping during read"
|
||||
echo "Test chunk skipping during read"
|
||||
makefile tmp_skip
|
||||
rm -f tmp_skip_${zext}.txt tmp_skip_${zext}.cdl
|
||||
$TC -d 6,6 -c 2,2 -Ow $F
|
||||
@ -109,7 +109,7 @@ $TC -d 8,8 -c 3,3 -Ow $F
|
||||
${NCDUMP} $F > tmp_rem_${zext}.cdl
|
||||
diff -b ${srcdir}/ref_rem.cdl tmp_rem_${zext}.cdl
|
||||
${execdir}/ncdumpchunks -v v $F > tmp_rem_${zext}.txt
|
||||
diff -b ${srcdir}/ref_rem.txt tmp_rem_${zext}.txt
|
||||
diff -b ${srcdir}/ref_rem.dmp tmp_rem_${zext}.txt
|
||||
|
||||
echo "Test rank > 2"
|
||||
makefile tmp_ndims
|
||||
@ -117,8 +117,8 @@ rm -f tmp_ndims_${zext}.txt tmp_ndims_${zext}.cdl
|
||||
$TC -d 8,8,8,8 -c 3,3,4,4 -Ow $F
|
||||
${NCDUMP} $F > tmp_ndims_${zext}.cdl
|
||||
diff -b ${srcdir}/ref_ndims.cdl tmp_ndims_${zext}.cdl
|
||||
${execdir}/ncdumpchunks -v v $F > tmp_ndims_${zext}.txt
|
||||
diff -b ${srcdir}/ref_ndims.txt tmp_ndims_${zext}.txt
|
||||
${execdir}/ncdumpchunks -v v $F > tmp_ndims_${zext}.dmp
|
||||
diff -b ${srcdir}/ref_ndims.dmp tmp_ndims_${zext}.dmp
|
||||
|
||||
echo "Test miscellaneous 1"
|
||||
makefile tmp_misc1
|
||||
@ -126,11 +126,12 @@ rm -f tmp_misc1_${zext}.txt tmp_misc1_${zext}.cdl
|
||||
$TC -d 6,12,4 -c 2,3,1 -f 0,0,0 -e 6,1,4 -Ow $F
|
||||
${NCDUMP} $F > tmp_misc1_${zext}.cdl
|
||||
diff -b ${srcdir}/ref_misc1.cdl tmp_misc1_${zext}.cdl
|
||||
${execdir}/ncdumpchunks -v v $F > tmp_misc1_${zext}.txt
|
||||
diff -b ${srcdir}/ref_misc1.txt tmp_misc1_${zext}.txt
|
||||
${execdir}/ncdumpchunks -v v $F > tmp_misc1_${zext}.dmp
|
||||
diff -b ${srcdir}/ref_misc1.dmp tmp_misc1_${zext}.dmp
|
||||
|
||||
} # testcases()
|
||||
|
||||
testcases nzf
|
||||
if test "x$FEATURE_HDF5" = xyes ; then testcases nz4; fi
|
||||
testcases file
|
||||
if test "x$FEATURE_NCZARR_ZIP" = xyes ; then testcases zip; fi
|
||||
if test "x$FEATURE_S3TESTS" = xyes ; then testcases s3; fi
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
if test "x$srcdir" = x ; then srcdir=`pwd`; fi
|
||||
. ../test_common.sh
|
||||
|
||||
. "$srcdir/test_nczarr.sh"
|
||||
|
||||
# This shell script tests bug reported in github issue
|
||||
# https://github.com/Unidata/netcdf-c/issues/1826
|
||||
|
||||
@ -11,9 +13,16 @@ set -e
|
||||
echo ""
|
||||
echo "*** Testing data conversions when a variable has fill value but never written"
|
||||
|
||||
${NCGEN} -4 -b -o 'file://tmp_fillonly.nc#mode=nczarr,nzf' $srcdir/ref_fillonly.cdl
|
||||
${execdir}/tst_fillonlyz${ext}
|
||||
testcase() {
|
||||
zext=$1
|
||||
fileargs tmp_fillonly
|
||||
deletemap $zext $file
|
||||
${NCGEN} -4 -b -o "$fileurl" $srcdir/ref_fillonly.cdl
|
||||
${execdir}/tst_fillonlyz${ext} "$fileurl"
|
||||
}
|
||||
|
||||
rm -fr ./tmp_fillonly.nc
|
||||
testcase file
|
||||
if test "x$FEATURE_NCZARR_ZIP" = xyes ; then testcase zip; fi
|
||||
if test "x$FEATURE_S3TESTS" = xyes ; then testcase s3; fi
|
||||
|
||||
exit 0
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Run (tst_chunks,tst_chunks2) X (nzf,nc4,s3)
|
||||
# Run (tst_chunks,tst_chunks2) X (file,zip,s3)
|
||||
|
||||
|
||||
if test "x$srcdir" = x ; then srcdir=`pwd`; fi
|
||||
@ -19,9 +19,10 @@ ${execdir}/tst_chunks -e $1 $CLOUD
|
||||
${execdir}/tst_chunks2 -e $1 $CLOUD
|
||||
}
|
||||
|
||||
ittest nzf
|
||||
if test "xFEATURE_HDF5" = xyes ; then ittest nz4; fi
|
||||
if test "x$FEATURE_S3TESTS" = xyes ; then ittest s3 'https://stratus.ucar.edu/unidata-netcdf-zarr-testing'; fi
|
||||
ittest file
|
||||
if test "x$FEATURE_NCZARR_ZIP" = xyes ; then ittest zip; fi
|
||||
if test "x$FEATURE_S3TESTS" = xyes ; then ittest s3 "${NCZARR_S3_TEST_URL}/netcdf-c'; fi
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -3,13 +3,15 @@
|
||||
if test "x$srcdir" = x ; then srcdir=`pwd`; fi
|
||||
. ../test_common.sh
|
||||
|
||||
. "$srcdir/test_nczarr.sh"
|
||||
|
||||
set -e
|
||||
echo ""
|
||||
|
||||
#chunkclean src dst
|
||||
chunkclean() {
|
||||
rm -f ./$2
|
||||
cat ./$1 | sed -e '/:_Storage/d' | sed -e '/:_ChunkSizes/d' > ./$2
|
||||
cat ./$1 | sed -e "/:_Storage/d" | sed -e "/:_ChunkSizes/d" > ./$2
|
||||
}
|
||||
|
||||
#verifychunking cdl-file <chunkspec>...
|
||||
@ -17,51 +19,64 @@ verifychunking() {
|
||||
f=$1
|
||||
shift
|
||||
for t in "$@" ; do
|
||||
x=`cat $f | tr -d '\t \r' | sed -e "/$t/p" -ed`
|
||||
x=`cat $f | tr -d "\t \r" | sed -e "/$t/p" -ed`
|
||||
if test "x$x" = x ; then echo "$f: $t not found"; exit 1; fi
|
||||
done
|
||||
}
|
||||
|
||||
./tst_zchunks3 -e nzf
|
||||
testcase() {
|
||||
zext=$1
|
||||
fileargs tmp
|
||||
./tst_zchunks3 -e ${zext}
|
||||
echo "*** Test that nccopy -c can chunk files"
|
||||
${NCCOPY} -M0 tst_chunks3.nc 'file://tmp.nzf#mode=nczarr,nzf'
|
||||
${NCDUMP} -n tmp -sh 'file://tmp.nzf#mode=nczarr,nzf' > tmp.cdl
|
||||
verifychunking tmp.cdl 'ivar:_ChunkSizes=7,4,2,3,5,6,9;' 'fvar:_ChunkSizes=9,6,5,3,2,4,7;'
|
||||
${NCCOPY} -M0 tmp_chunks3.nc "$fileurl"
|
||||
${NCDUMP} -n tmp -sh "$fileurl" > tmp.cdl
|
||||
verifychunking tmp.cdl "ivar:_ChunkSizes=7,4,2,3,5,6,9;" "fvar:_ChunkSizes=9,6,5,3,2,4,7;"
|
||||
|
||||
${NCCOPY} -M0 -c dim0/,dim1/1,dim2/,dim3/1,dim4/,dim5/1,dim6/ tst_chunks3.nc 'file://tmp_chunked.nzf#mode=nczarr,nzf'
|
||||
${NCDUMP} -sh -n tmp 'file://tmp_chunked.nzf#mode=nczarr,nzf' > tmp_chunked.cdl
|
||||
verifychunking tmp_chunked.cdl 'ivar:_ChunkSizes=7,1,2,1,5,1,9;' 'fvar:_ChunkSizes=9,1,5,1,2,1,7;'
|
||||
fileargs tmp_chunked
|
||||
./tst_zchunks3 -e ${zext}
|
||||
${NCCOPY} -M0 -c dim0/,dim1/1,dim2/,dim3/1,dim4/,dim5/1,dim6/ tmp_chunks3.nc "$fileurl"
|
||||
${NCDUMP} -sh -n tmp "$fileurl" > tmp_chunked.cdl
|
||||
verifychunking tmp_chunked.cdl "ivar:_ChunkSizes=7,1,2,1,5,1,9;" "fvar:_ChunkSizes=9,1,5,1,2,1,7;"
|
||||
chunkclean tmp.cdl tmpx.cdl
|
||||
chunkclean tmp_chunked.cdl tmp_chunkedx.cdl
|
||||
diff tmpx.cdl tmp_chunkedx.cdl
|
||||
|
||||
# Note that unchunked means that there is only one chunk
|
||||
${NCCOPY} -M0 -c dim0/,dim1/,dim2/,dim3/,dim4/,dim5/,dim6/ 'file://tmp_chunked.nzf#mode=nczarr,nzf' 'file://tmp_unchunked.nzf#mode=nczarr,nzf'
|
||||
${NCDUMP} -sh -n tmp 'file://tmp_unchunked.nzf#mode=nczarr,nzf' > tmp_unchunked.cdl
|
||||
verifychunking tmp_unchunked.cdl 'ivar:_ChunkSizes=7,4,2,3,5,6,9;' 'fvar:_ChunkSizes=9,6,5,3,2,4,7;'
|
||||
SRC="$fileurl"
|
||||
fileargs tmp_unchunked
|
||||
${NCCOPY} -M0 -c dim0/,dim1/,dim2/,dim3/,dim4/,dim5/,dim6/ "$SRC" "$fileurl"
|
||||
${NCDUMP} -sh -n tmp "$fileurl" > tmp_unchunked.cdl
|
||||
verifychunking tmp_unchunked.cdl "ivar:_ChunkSizes=7,4,2,3,5,6,9;" "fvar:_ChunkSizes=9,6,5,3,2,4,7;"
|
||||
chunkclean tmp_unchunked.cdl tmp_unchunkedx.cdl
|
||||
diff tmpx.cdl tmp_unchunkedx.cdl
|
||||
|
||||
# Test -c /
|
||||
${NCCOPY} -M0 -c '/' 'file://tmp_chunked.nzf#mode=nczarr,nzf' 'file://tmp_unchunked2.nzf#mode=nczarr,nzf'
|
||||
${NCDUMP} -sh -n tmp 'file://tmp_unchunked2.nzf#mode=nczarr,nzf' > tmp_unchunked2.cdl
|
||||
verifychunking tmp_unchunked.cdl 'ivar:_ChunkSizes=7,4,2,3,5,6,9;' 'fvar:_ChunkSizes=9,6,5,3,2,4,7;'
|
||||
fileargs tmp_unchunked2
|
||||
${NCCOPY} -M0 -c "/" "$SRC" "$fileurl"
|
||||
${NCDUMP} -sh -n tmp "$fileurl" > tmp_unchunked2.cdl
|
||||
verifychunking tmp_unchunked.cdl "ivar:_ChunkSizes=7,4,2,3,5,6,9;" "fvar:_ChunkSizes=9,6,5,3,2,4,7;"
|
||||
chunkclean tmp_unchunked.cdl tmp_unchunkedx.cdl
|
||||
diff tmpx.cdl tmp_unchunkedx.cdl
|
||||
|
||||
echo "*** Test that nccopy -c dim/n is used "
|
||||
${NCGEN} -4 -b -o 'file://tst_perdimspecs.nzf#mode=nczarr,nzf' $srcdir/ref_perdimspecs.cdl
|
||||
${NCDUMP} -n tmp_perdimspecs -hs 'file://tst_perdimspecs.nzf#mode=nczarr,nzf' > tmp_perdimspecs.cdl
|
||||
${NCCOPY} -M0 -4 -c "time/10,lat/15,lon/20" 'file://tst_perdimspecs.nzf#mode=nczarr,nzf' 'file://tmppds.nzf#mode=nczarr,nzf'
|
||||
${NCDUMP} -n tmppds -hs 'file://tmppds.nzf#mode=nczarr,nzf' > tmppds.cdl
|
||||
STORAGE=`cat tmppds.cdl | sed -e '/tas:_Storage/p' -ed | tr -d '\t \r'`
|
||||
test "x$STORAGE" = 'xtas:_Storage="chunked";'
|
||||
CHUNKSIZES=`cat tmppds.cdl | sed -e '/tas:_ChunkSizes/p' -ed | tr -d '\t \r'`
|
||||
test "x$CHUNKSIZES" = 'xtas:_ChunkSizes=10,15,20;'
|
||||
fileargs tmp_perdimspecs
|
||||
${NCGEN} -4 -b -o "$fileurl" $srcdir/ref_perdimspecs.cdl
|
||||
${NCDUMP} -n tmp_perdimspecs -hs "$fileurl" > tmp_perdimspecs.cdl
|
||||
SRC=$fileurl
|
||||
fileargs tmp_pds
|
||||
|
||||
# Cleanup
|
||||
rm -fr tmp*.nc tmp*.cdl
|
||||
rm -fr tmp*.nzf
|
||||
${NCCOPY} -M0 -4 -c "time/10,lat/15,lon/20" "$SRC" "$fileurl"
|
||||
${NCDUMP} -n tmp_pds -hs "$fileurl" > tmp_pds.cdl
|
||||
STORAGE=`cat tmp_pds.cdl | sed -e "/tas:_Storage/p" -ed | tr '"' "'" | tr -d "\t \r"`
|
||||
test "x$STORAGE" = "xtas:_Storage='chunked';"
|
||||
CHUNKSIZES=`cat tmp_pds.cdl | sed -e "/tas:_ChunkSizes/p" -ed | tr -d "\t \r"`
|
||||
test "x$CHUNKSIZES" = "xtas:_ChunkSizes=10,15,20;"
|
||||
}
|
||||
|
||||
testcase file
|
||||
if test "x$FEATURE_NCZARR_ZIP" = xyes ; then testcase zip; fi
|
||||
if test "x$FEATURE_S3TESTS" = xyes ; then testcase s3; fi
|
||||
|
||||
echo "*** All nccopy nczarr tests passed!"
|
||||
exit 0
|
||||
|
@ -54,10 +54,8 @@ cd ..
|
||||
echo "*** PASSED: zext=${zext}"
|
||||
}
|
||||
|
||||
runtestset nzf
|
||||
if test "x$FEATURE_HDF5" = xyes ; then runtestset nz4; fi
|
||||
runtestset file
|
||||
if test "x$FEATURE_NCZARR_ZIP" = xyes ; then runtestset zip; fi
|
||||
if test "x$FEATURE_S3TESTS" = xyes ; then runtestset s3; fi
|
||||
|
||||
rm -rf ${RESULTSDIR}.nzf ${RESULTSDIR}.nz4 ${RESULTSDIR}.s3
|
||||
|
||||
echo "*** PASSED ***"
|
||||
|
@ -31,8 +31,8 @@ echo '*** SUCCESS!!!'
|
||||
}
|
||||
|
||||
|
||||
testcases nzf
|
||||
if test "x$FEATURE_HDF5" = xyes ; then testcases nz4; fi
|
||||
testcases file
|
||||
if test "x$FEATURE_NCZARR_ZIP" = xyes ; then testcases zip; fi
|
||||
if test "x$FEATURE_S3TESTS" = xyes ; then testcases s3; fi
|
||||
|
||||
exit 0
|
||||
|
19
nczarr_test/run_s3_cleanup.sh
Executable file
19
nczarr_test/run_s3_cleanup.sh
Executable file
@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
if test "x$srcdir" = x ; then srcdir=`pwd`; fi
|
||||
. ../test_common.sh
|
||||
|
||||
. "$srcdir/test_nczarr.sh"
|
||||
|
||||
set -e
|
||||
|
||||
echo ""
|
||||
echo "*** Remove /netcdf-c from S3 repository"
|
||||
|
||||
fileargs netcdf-c
|
||||
|
||||
if test "x$FEATURE_S3TESTS" = xyes ; then
|
||||
${execdir}/s3util -u "${NCZARR_S3_TEST_URL}" -k "/netcdf-c" clear
|
||||
fi
|
||||
|
||||
exit 0
|
@ -9,7 +9,7 @@ set -e
|
||||
|
||||
# Test those map implementations where
|
||||
# it is possible to look at the actual storage.
|
||||
# .ncz and .nzf specifically. Note that we
|
||||
# in some cases. Note that we
|
||||
# cannot easily look inside S3 storage
|
||||
# except using the aws-cli, if available
|
||||
|
||||
@ -21,15 +21,16 @@ testmapcreate() {
|
||||
echo ""; echo "*** Test zmap create -k $1"
|
||||
extfor "$1"
|
||||
tag="map"
|
||||
output="test$tag.$zext"
|
||||
output="tmp_$tag.$zext"
|
||||
|
||||
deletemap $1 $output
|
||||
|
||||
# Create the test file
|
||||
$CMD -k$1 -x create -o $output
|
||||
cdl="ut_${tag}_create_${zext}.cdl"
|
||||
ref="ref_ut_${tag}_create.cdl"
|
||||
dumpmap $zext $output ./$cdl
|
||||
diff -wb ${srcdir}/ref_$cdl ./$cdl
|
||||
diff -wb ${srcdir}/$ref ./$cdl
|
||||
# delete the test file
|
||||
$CMD -k$1 -x delete -f $output
|
||||
rm -f $cdl
|
||||
@ -45,34 +46,42 @@ testmapmeta() {
|
||||
echo ""; echo "*** Test zmap read/write meta -k $1"
|
||||
extfor "$1"
|
||||
tag="map"
|
||||
file="test$tag.$zext"
|
||||
file="tmp_$tag.$zext"
|
||||
|
||||
$CMD -k$1 -x writemeta -f $file
|
||||
cdl="ut_${tag}_writemeta_${zext}.cdl"
|
||||
ref="ref_ut_${tag}_writemeta.cdl"
|
||||
dumpmap $zext $file ./$cdl
|
||||
diff -wb ${srcdir}/ref_$cdl ./$cdl
|
||||
diff -wb ${srcdir}/$ref ./$cdl
|
||||
|
||||
$CMD -k$1 -x writemeta2 -o ./$file
|
||||
cdl="ut_${tag}_write2meta_${zext}.cdl"
|
||||
cdl="ut_${tag}_writemeta2_${zext}.cdl"
|
||||
ref="ref_ut_${tag}_writemeta2.cdl"
|
||||
dumpmap $zext $file ./$cdl
|
||||
diff -wb ${srcdir}/ref_$cdl ./$cdl
|
||||
diff -wb ${srcdir}/$ref ./$cdl
|
||||
|
||||
output="ut_${tag}_readmeta_$zext.txt"
|
||||
outref="ref_ut_${tag}_readmeta.txt"
|
||||
$CMD -k$1 -x readmeta -f $file > ./$output
|
||||
diff -wb ${srcdir}/ref_$output ./$output
|
||||
diff -wb ${srcdir}/$outref ./$output
|
||||
|
||||
output="ut_${tag}_readmeta2_$zext.txt"
|
||||
outref="ref_ut_${tag}_readmeta2.txt"
|
||||
$CMD -k$1 -x readmeta2 -f $file > ./$output
|
||||
diff -wb ${srcdir}/$outref ./$output
|
||||
}
|
||||
|
||||
testmapdata() {
|
||||
echo ""; echo "*** Test zmap read/write data -k $1"
|
||||
extfor "$1"
|
||||
tag="map"
|
||||
file="test$tag.$zext"
|
||||
file="tmp_$tag.$zext"
|
||||
|
||||
$CMD -k$1 -x "writedata" -f $file
|
||||
cdl="ut_${tag}_writedata_${zext}.cdl"
|
||||
ref="ref_ut_${tag}_writedata.cdl"
|
||||
dumpmap $zext $file ./$cdl
|
||||
diff -wb ${srcdir}/ref_$cdl ./$cdl
|
||||
|
||||
diff -wb ${srcdir}/$ref ./$cdl
|
||||
# readata is verification only
|
||||
$CMD -k$1 -x readdata -f $file
|
||||
}
|
||||
@ -81,24 +90,24 @@ testmapsearch() {
|
||||
echo ""; echo "*** Test zmap search -k $1"
|
||||
extfor "$1"
|
||||
tag="map"
|
||||
file="test$tag.$zext"
|
||||
|
||||
file="tmp_$tag.$zext"
|
||||
txt=ut_${tag}_search_$zext.txt
|
||||
ref=ref_ut_${tag}_search.txt
|
||||
rm -f $txt
|
||||
$CMD -k$1 -x "search" -f $file > $txt
|
||||
diff -wb ${srcdir}/ref_$txt ./$txt
|
||||
diff -wb ${srcdir}/$ref ./$txt
|
||||
}
|
||||
|
||||
echo ""
|
||||
|
||||
echo "*** Map Unit Testing"
|
||||
|
||||
echo ""; echo "*** Test zmap_nzf"
|
||||
testmapcreate nzf; testmapmeta nzf; testmapdata nzf; testmapsearch nzf
|
||||
echo ""; echo "*** Test zmap_file"
|
||||
testmapcreate file; testmapmeta file; testmapdata file; testmapsearch file
|
||||
|
||||
if test "x$FEATURE_HDF5" = xyes ; then
|
||||
echo ""; echo "*** Test zmap_nz4"
|
||||
testmapcreate nz4; testmapmeta nz4; testmapdata nz4; testmapsearch nz4
|
||||
if test "x$FEATURE_NCZARR_ZIP" = xyes ; then
|
||||
echo ""; echo "*** Test zmap_zip"
|
||||
testmapcreate zip; testmapmeta zip; testmapdata zip; testmapsearch zip
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
@ -6,6 +6,8 @@ if test "x$srcdir" = x ; then srcdir=`pwd`; fi
|
||||
|
||||
. "$srcdir/test_nczarr.sh"
|
||||
|
||||
TR="-T10"
|
||||
|
||||
set -e
|
||||
|
||||
# Test map implementations for consistency at the zmap API
|
||||
@ -20,22 +22,23 @@ testmapcreate() {
|
||||
echo ""; echo "*** Test zmap create -k $1"
|
||||
extfor "$1"
|
||||
tag=mapapi
|
||||
base="test_$tag"
|
||||
base="tmp_$tag"
|
||||
fileargs $base
|
||||
|
||||
deletemap $1 $file
|
||||
|
||||
# Create the test file
|
||||
$CMD -k$1 -x create -f $file
|
||||
$CMD $TR -k$1 -x create -f $file
|
||||
cdl="ut_${tag}_create_${zext}.cdl"
|
||||
ref="ref_ut_${tag}_create.cdl"
|
||||
${ZMD} $fileurl > ./$cdl
|
||||
diff -wb ${srcdir}/ref_$cdl ./$cdl
|
||||
diff -wb $srcdir/$ref ./$cdl
|
||||
# delete the test file
|
||||
$CMD -k$1 -x delete -f $file
|
||||
$CMD $TR -k$1 -x delete -f $file
|
||||
rm -f $cdl
|
||||
|
||||
mapexists $1
|
||||
if test mapexists = 0 ; then exit 1; fi
|
||||
mapstillexists $1
|
||||
if test mapstillexists = 0 ; then exit 1; fi
|
||||
# re-create the test file
|
||||
$CMD -k$1 -x create -o $file
|
||||
}
|
||||
@ -44,46 +47,49 @@ testmapmeta() {
|
||||
echo ""; echo "*** Test zmap read/write meta -k $1"
|
||||
extfor "$1"
|
||||
tag=mapapi
|
||||
base="test_$tag"
|
||||
base="tmp_$tag"
|
||||
fileargs $base
|
||||
$CMD -k$1 -x simplemeta -f $file
|
||||
$CMD $TR -k$1 -x simplemeta -f $file
|
||||
cdl="ut_${tag}_meta_${zext}.cdl"
|
||||
ref="ref_ut_${tag}_meta.cdl"
|
||||
${ZMD} $fileurl > ./$cdl
|
||||
diff -wb ${srcdir}/ref_$cdl ./$cdl
|
||||
diff -wb ${srcdir}/$ref ./$cdl
|
||||
}
|
||||
|
||||
testmapdata() {
|
||||
echo ""; echo "*** Test zmap read/write data -k $1"
|
||||
extfor "$1"
|
||||
tag=mapapi
|
||||
base="test_$tag"
|
||||
base="tmp_$tag"
|
||||
fileargs $base
|
||||
$CMD -k$1 -x "simpledata" -f $file
|
||||
$CMD $TR -k$1 -x "simpledata" -f $file
|
||||
cdl="ut_${tag}_data_${zext}.cdl"
|
||||
ref="ref_ut_${tag}_data.cdl"
|
||||
${ZMD} $fileurl > ./$cdl
|
||||
diff -wb ${srcdir}/ref_$cdl ./$cdl
|
||||
diff -wb ${srcdir}/$ref ./$cdl
|
||||
}
|
||||
|
||||
testmapsearch() {
|
||||
echo ""; echo "*** Test zmap search -k $1"
|
||||
extfor "$1"
|
||||
tag=mapapi
|
||||
base="test_$tag"
|
||||
base="tmp_$tag"
|
||||
fileargs $base
|
||||
txt=ut_${tag}_search_$zext.txt
|
||||
ref=ref_ut_${tag}_search.txt
|
||||
rm -f $txt
|
||||
$CMD -k$1 -x "search" -f $file > $txt
|
||||
diff -wb ${srcdir}/ref_$txt ./$txt
|
||||
$CMD $TR -k$1 -x "search" -f $file > $txt
|
||||
diff -wb ${srcdir}/$ref ./$txt
|
||||
}
|
||||
|
||||
main() {
|
||||
echo ""
|
||||
echo "*** Map Unit Testing"
|
||||
echo ""; echo "*** Test zmap_nzf"
|
||||
testmapcreate nzf; testmapmeta nzf; testmapdata nzf; testmapsearch nzf
|
||||
if test "x$FEATURE_HDF5" = xyes ; then
|
||||
echo ""; echo "*** Test zmap_nz4"
|
||||
testmapcreate nz4; testmapmeta nz4; testmapdata nz4; testmapsearch nz4
|
||||
echo ""; echo "*** Test zmap_file"
|
||||
testmapcreate file; testmapmeta file; testmapdata file; testmapsearch file
|
||||
if test "x$FEATURE_NCZARR_ZIP" = xyes ; then
|
||||
echo ""; echo "*** Test zmap_zip"
|
||||
testmapcreate zip; testmapmeta zip; testmapdata zip; testmapsearch zip
|
||||
fi
|
||||
if test "x$FEATURE_S3TESTS" = xyes ; then
|
||||
echo ""; echo "*** Test zmap_s3sdk"
|
||||
|
445
nczarr_test/s3util.c
Normal file
445
nczarr_test/s3util.c
Normal file
@ -0,0 +1,445 @@
|
||||
/*
|
||||
* Copyright 2018, University Corporation for Atmospheric Research
|
||||
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include "XGetopt.h"
|
||||
#endif
|
||||
|
||||
#include "zincludes.h"
|
||||
#include "zs3sdk.h"
|
||||
#include "ncpathmgr.h"
|
||||
#include "nclog.h"
|
||||
#include "ncuri.h"
|
||||
#include "netcdf_aux.h"
|
||||
|
||||
#undef NODELETE
|
||||
|
||||
#define DEBUG
|
||||
|
||||
#define DATANAME "data"
|
||||
|
||||
typedef enum S3op {
|
||||
S3OP_NONE=0,
|
||||
S3OP_LIST=1,
|
||||
S3OP_CLEAR=2,
|
||||
S3OP_PRINT=3,
|
||||
S3OP_UPLOAD=4,
|
||||
S3OP_DOWNLOAD=5,
|
||||
} S3op;
|
||||
|
||||
static struct S3ops {
|
||||
S3op s3op;
|
||||
const char* opnames[3];
|
||||
} s3ops[] = {
|
||||
{S3OP_LIST,{"list","l",NULL}},
|
||||
{S3OP_CLEAR,{"clear","c",NULL}},
|
||||
{S3OP_PRINT,{"print","p",NULL}},
|
||||
{S3OP_UPLOAD,{"upload","u",NULL}},
|
||||
{S3OP_DOWNLOAD,{"download","d",NULL}},
|
||||
{S3OP_NONE,{NULL,NULL,NULL}},
|
||||
};
|
||||
|
||||
/* Command line options */
|
||||
struct Dumpptions {
|
||||
int debug;
|
||||
S3op s3op;
|
||||
NCURI* url;
|
||||
char* key; /* via -k flag */
|
||||
char* rootkey; /* from url | key */
|
||||
nc_type nctype; /* for printing content */
|
||||
char* filename;
|
||||
} dumpoptions;
|
||||
|
||||
struct S3SDK {
|
||||
ZS3INFO s3;
|
||||
void* s3config;
|
||||
void* s3client;
|
||||
char* errmsg;
|
||||
} s3sdk;
|
||||
|
||||
/* Forward */
|
||||
static int s3list(void);
|
||||
static int s3clear(void);
|
||||
static int s3print(void);
|
||||
static int s3upload(void);
|
||||
static int s3download(void);
|
||||
static nc_type typefor(const char* t);
|
||||
static void printcontent(size64_t len, const char* content, nc_type nctype);
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr,"usage: s3util list|print|upload|download|clear -u <url> [-k <key.] [-f <filename>]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static S3op
|
||||
decodeop(const char* name)
|
||||
{
|
||||
struct S3ops* s3op = s3ops;
|
||||
const char** s = NULL;
|
||||
for(;s3op->opnames[0] != NULL;s3op++) {
|
||||
for(s=s3op->opnames;*s;s++) {
|
||||
if(strcasecmp(*s,name)==0) return s3op->s3op;
|
||||
}
|
||||
}
|
||||
return S3OP_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
s3initialize(void)
|
||||
{
|
||||
NCZ_s3sdkinitialize();
|
||||
}
|
||||
|
||||
static void
|
||||
s3finalize(void)
|
||||
{
|
||||
NCZ_s3sdkfinalize();
|
||||
}
|
||||
|
||||
static int
|
||||
s3setup(void)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
if((stat=NCZ_s3sdkcreateconfig(s3sdk.s3.host, s3sdk.s3.region, &s3sdk.s3config))) goto done;
|
||||
if((stat = NCZ_s3sdkcreateclient(s3sdk.s3config,&s3sdk.s3client))) goto done;
|
||||
done:
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int
|
||||
s3shutdown(int deleteit)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
stat = NCZ_s3sdkclose(s3sdk.s3client, s3sdk.s3config, s3sdk.s3.bucket, s3sdk.s3.rootkey, deleteit, &s3sdk.errmsg);
|
||||
return stat;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
int c;
|
||||
char* tmp = NULL;
|
||||
|
||||
memset((void*)&dumpoptions,0,sizeof(dumpoptions));
|
||||
|
||||
dumpoptions.nctype = NC_UBYTE; /* default */
|
||||
|
||||
while ((c = getopt(argc, argv, "df:k:u:vt:T:")) != EOF) {
|
||||
switch(c) {
|
||||
case 'd':
|
||||
dumpoptions.debug = 1;
|
||||
break;
|
||||
case 'f':
|
||||
dumpoptions.filename = strdup(optarg);
|
||||
break;
|
||||
case 'k': {
|
||||
size_t len = strlen(optarg);
|
||||
dumpoptions.key = (char*)malloc(len+1+1);
|
||||
if(*optarg != '/') {
|
||||
fprintf(stderr,"warning: -k option does not start with '/': %s",optarg);
|
||||
dumpoptions.key[0] = '/';
|
||||
memcpy(dumpoptions.key+1,optarg,len);
|
||||
len++;
|
||||
} else
|
||||
memcpy(dumpoptions.key,optarg,strlen(optarg));
|
||||
dumpoptions.key[len] = '\0';
|
||||
} break;
|
||||
case 't':
|
||||
dumpoptions.nctype = typefor(optarg);
|
||||
break;
|
||||
case 'u': {
|
||||
char* p = NCdeescape(optarg);
|
||||
ncuriparse(p,&dumpoptions.url);
|
||||
nullfree(p);
|
||||
if(dumpoptions.url == NULL) {
|
||||
fprintf(stderr,"malformed -f option: %s",optarg);
|
||||
stat = NC_EINVAL;
|
||||
goto done;
|
||||
}
|
||||
} break;
|
||||
case 'v':
|
||||
usage();
|
||||
goto done;
|
||||
case 'T':
|
||||
nctracelevel(atoi(optarg));
|
||||
break;
|
||||
case '?':
|
||||
fprintf(stderr,"unknown option\n");
|
||||
stat = NC_EINVAL;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* get command argument */
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc > 1) {
|
||||
fprintf(stderr, "s3util: only one command argument permitted\n");
|
||||
stat = NC_EINVAL;
|
||||
goto done;
|
||||
}
|
||||
if (argc == 0) {
|
||||
fprintf(stderr, "s3util: no command specified\n");
|
||||
stat = NC_EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
dumpoptions.s3op = decodeop(argv[0]);
|
||||
|
||||
memset(&s3sdk,0,sizeof(s3sdk));
|
||||
|
||||
if((stat = NCZ_s3urlprocess(dumpoptions.url, &s3sdk.s3))) goto done;
|
||||
if(s3sdk.s3.rootkey != NULL && dumpoptions.key != NULL) {
|
||||
size_t len = 0;
|
||||
/* Make the root key be the concatenation of rootkey+dumpoptions.key */
|
||||
len = strlen(s3sdk.s3.rootkey) + strlen(dumpoptions.key) + 1;
|
||||
if((tmp = (char*)malloc(len+1))==NULL) {stat = NC_ENOMEM; goto done;}
|
||||
tmp[0] = '\0';
|
||||
strcat(tmp,s3sdk.s3.rootkey);
|
||||
if(s3sdk.s3.rootkey[strlen(s3sdk.s3.rootkey)-1] != '/' && dumpoptions.key[0] != '/')
|
||||
strcat(tmp,"/");
|
||||
strcat(tmp,dumpoptions.key);
|
||||
nullfree(s3sdk.s3.rootkey);
|
||||
s3sdk.s3.rootkey = tmp; tmp = NULL;
|
||||
} else if(dumpoptions.key != NULL) {
|
||||
s3sdk.s3.rootkey = dumpoptions.key;
|
||||
dumpoptions.key = NULL;
|
||||
}
|
||||
if(s3sdk.s3.rootkey == NULL || strlen(s3sdk.s3.rootkey)==0)
|
||||
s3sdk.s3.rootkey = strdup("/");
|
||||
|
||||
s3initialize();
|
||||
|
||||
switch (dumpoptions.s3op) {
|
||||
default:
|
||||
fprintf(stderr,"Default action: list\n");
|
||||
/* fall thru */
|
||||
case S3OP_LIST:
|
||||
if((stat = s3list())) goto done;
|
||||
break;
|
||||
case S3OP_CLEAR:
|
||||
if((stat = s3clear())) goto done;
|
||||
break;
|
||||
case S3OP_PRINT:
|
||||
if((stat = s3print())) goto done;
|
||||
break;
|
||||
case S3OP_UPLOAD:
|
||||
if((stat = s3upload())) goto done;
|
||||
break;
|
||||
case S3OP_DOWNLOAD:
|
||||
if((stat = s3download())) goto done;
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
s3finalize();
|
||||
/* Reclaim dumpoptions */
|
||||
ncurifree(dumpoptions.url);
|
||||
nullfree(dumpoptions.rootkey);
|
||||
nullfree(tmp);
|
||||
if(stat)
|
||||
fprintf(stderr,"fail: %s\n",nc_strerror(stat));
|
||||
return (stat ? 1 : 0);
|
||||
}
|
||||
|
||||
static int
|
||||
s3list(void)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
size_t nkeys = 0;
|
||||
char** keys = NULL;
|
||||
|
||||
if(s3setup()) goto done;
|
||||
|
||||
stat = NCZ_s3sdksearch(s3sdk.s3client, s3sdk.s3.bucket, s3sdk.s3.rootkey, &nkeys, &keys, &s3sdk.errmsg);
|
||||
if(stat) goto done;
|
||||
|
||||
if(nkeys > 0) {
|
||||
size_t i;
|
||||
/* Sort the list -- shortest first */
|
||||
nczm_sortenvv(nkeys,keys);
|
||||
for(i=0;i<nkeys;i++) {
|
||||
printf("[%u] %s\n",(unsigned)i,keys[i]);
|
||||
}
|
||||
|
||||
} else
|
||||
printf("<empty>\n");
|
||||
|
||||
done:
|
||||
s3shutdown(0);
|
||||
NCZ_freeenvv(nkeys,keys);
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int
|
||||
s3clear(void)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
size_t nkeys = 0;
|
||||
char** keys = NULL;
|
||||
|
||||
if(s3setup()) goto done;
|
||||
|
||||
stat = NCZ_s3sdksearch(s3sdk.s3client, s3sdk.s3.bucket, s3sdk.s3.rootkey, &nkeys, &keys, &s3sdk.errmsg);
|
||||
if(stat) goto done;
|
||||
|
||||
if(nkeys > 0) {
|
||||
size_t i;
|
||||
/* Sort the list -- shortest first */
|
||||
nczm_sortenvv(nkeys,keys);
|
||||
printf("deleted keys:\n");
|
||||
for(i=0;i<nkeys;i++) {
|
||||
printf("\t%s\n",keys[i]);
|
||||
#ifndef NODELETE
|
||||
if((stat = NCZ_s3sdkdeletekey(s3sdk.s3client, s3sdk.s3.bucket, keys[i], &s3sdk.errmsg)))
|
||||
goto done;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
s3shutdown(0);
|
||||
NCZ_freeenvv(nkeys,keys);
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int
|
||||
s3print(void)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
size_t nkeys = 0;
|
||||
char** keys = NULL;
|
||||
size64_t count;
|
||||
char* content = NULL;
|
||||
|
||||
if(s3setup()) goto done;
|
||||
|
||||
if((stat = NCZ_s3sdkinfo(s3sdk.s3client, s3sdk.s3.bucket, s3sdk.s3.rootkey, &count,&s3sdk.errmsg)))
|
||||
goto done;
|
||||
|
||||
if((content = (char*)calloc(1,count+1))==NULL)
|
||||
{stat = NC_ENOMEM; goto done;}
|
||||
|
||||
if((stat = NCZ_s3sdkread(s3sdk.s3client, s3sdk.s3.bucket, s3sdk.s3.rootkey, 0, count, (void*) content, &s3sdk.errmsg)))
|
||||
goto done;
|
||||
|
||||
printcontent(count,content,dumpoptions.nctype);
|
||||
|
||||
done:
|
||||
if(content) free(content);
|
||||
s3shutdown(0);
|
||||
NCZ_freeenvv(nkeys,keys);
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int
|
||||
s3upload(void)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
size_t red = 0;
|
||||
void* content = NULL;
|
||||
|
||||
if(s3setup()) goto done;
|
||||
|
||||
if((stat = ncaux_readfile(dumpoptions.filename,&red,&content)))
|
||||
goto done;
|
||||
|
||||
if((stat = NCZ_s3sdkwriteobject(s3sdk.s3client, s3sdk.s3.bucket, s3sdk.s3.rootkey, red, content, &s3sdk.errmsg)))
|
||||
goto done;
|
||||
|
||||
done:
|
||||
if(content) free(content);
|
||||
s3shutdown(0);
|
||||
return stat;
|
||||
}
|
||||
|
||||
static int
|
||||
s3download(void)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
size64_t count;
|
||||
char* content = NULL;
|
||||
|
||||
if(s3setup()) goto done;
|
||||
|
||||
if((stat = NCZ_s3sdkinfo(s3sdk.s3client, s3sdk.s3.bucket, s3sdk.s3.rootkey, &count,&s3sdk.errmsg)))
|
||||
goto done;
|
||||
|
||||
if((content = (char*)calloc(1,count))==NULL)
|
||||
{stat = NC_ENOMEM; goto done;}
|
||||
|
||||
if((stat = NCZ_s3sdkread(s3sdk.s3client, s3sdk.s3.bucket, s3sdk.s3.rootkey, 0, count, (void*) content, &s3sdk.errmsg)))
|
||||
goto done;
|
||||
|
||||
if((stat = ncaux_writefile(dumpoptions.filename,count,content)))
|
||||
goto done;
|
||||
|
||||
done:
|
||||
if(content) free(content);
|
||||
s3shutdown(0);
|
||||
return stat;
|
||||
}
|
||||
|
||||
static void
|
||||
printcontent(size64_t len, const char* content, nc_type nctype)
|
||||
{
|
||||
size64_t i;
|
||||
|
||||
if(len == 0) {
|
||||
printf("<empty>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(nctype == NC_STRING) printf("|");
|
||||
for(i=0;i<len;i++) {
|
||||
if(nctype != NC_STRING && i > 0) printf(", ");
|
||||
switch(nctype) {
|
||||
case NC_BYTE: printf("%d",((char*)content)[i]); break;
|
||||
case NC_SHORT: printf("%d",((short*)content)[i]); break;
|
||||
case NC_INT: printf("%d",((int*)content)[i]); break;
|
||||
case NC_INT64: printf("%lld",((long long*)content)[i]); break;
|
||||
case NC_UBYTE: printf("%u",((unsigned char*)content)[i]); break;
|
||||
case NC_USHORT: printf("%u",((unsigned short*)content)[i]); break;
|
||||
case NC_UINT: printf("%u",((unsigned int*)content)[i]); break;
|
||||
case NC_UINT64: printf("%llu",((unsigned long long*)content)[i]); break;
|
||||
case NC_FLOAT: printf("%f",((float*)content)[i]); break;
|
||||
case NC_DOUBLE: printf("%lf",((double*)content)[i]); break;
|
||||
case NC_STRING: putc(content[i],stdout); break;
|
||||
default: abort();
|
||||
}
|
||||
}
|
||||
if(nctype == NC_STRING) printf("|\n");
|
||||
}
|
||||
|
||||
static nc_type
|
||||
typefor(const char* t)
|
||||
{
|
||||
if(strcmp(t,"NC_BYTE")==0) return NC_BYTE;
|
||||
else if(strcmp(t,"NC_SHORT")==0) return NC_SHORT;
|
||||
else if(strcmp(t,"NC_INT")==0) return NC_INT;
|
||||
else if(strcmp(t,"NC_INT64")==0) return NC_INT64;
|
||||
else if(strcmp(t,"NC_UBYTE")==0) return NC_UBYTE;
|
||||
else if(strcmp(t,"NC_USHORT")==0) return NC_USHORT;
|
||||
else if(strcmp(t,"NC_UINT")==0) return NC_UINT;
|
||||
else if(strcmp(t,"NC_UINT64")==0) return NC_UINT64;
|
||||
else if(strcmp(t,"NC_FLOAT")==0) return NC_FLOAT;
|
||||
else if(strcmp(t,"NC_DOUBLE")==0) return NC_DOUBLE;
|
||||
else if(strcmp(t,"NC_STRING")==0) return NC_STRING;
|
||||
return NC_NAT;
|
||||
}
|
@ -2,10 +2,20 @@
|
||||
|
||||
if test "x$SETX" != x; then set -x; fi
|
||||
|
||||
# Figure out which cloud repo to use
|
||||
if test "x$NCZARR_S3_TEST_HOST" = x ; then
|
||||
export NCZARR_S3_TEST_HOST=stratus.ucar.edu
|
||||
fi
|
||||
if test "x$NCZARR_S3_TEST_BUCKET" = x ; then
|
||||
export NCZARR_S3_TEST_BUCKET=unidata-netcdf-zarr-testing
|
||||
fi
|
||||
export NCZARR_S3_TEST_URL="https://${NCZARR_S3_TEST_HOST}/${NCZARR_S3_TEST_BUCKET}"
|
||||
|
||||
ZMD="${execdir}/zmapio"
|
||||
|
||||
awsdelete() {
|
||||
aws s3api delete-object --endpoint-url=https://stratus.ucar.edu --bucket=unidata-netcdf-zarr-testing --key="$1"
|
||||
${execdir}/s3util -u "${NCZARR_S3_TEST_URL}/" -k "$1" clear
|
||||
#aws s3api delete-object --endpoint-url=https://${NCZARR_S3_TEST_HOST} --bucket=${NCZARR_S3_TEST_BUCKET} --key="netcdf-c/$1"
|
||||
}
|
||||
|
||||
# Check settings
|
||||
@ -39,8 +49,8 @@ checkprops() {
|
||||
|
||||
extfor() {
|
||||
case "$1" in
|
||||
nz4) zext="nz4" ;;
|
||||
nzf) zext="nzf" ;;
|
||||
file) zext="file" ;;
|
||||
zip) zext="zip" ;;
|
||||
s3) zext="s3" ;;
|
||||
*) echo "unknown kind: $1" ; exit 1;;
|
||||
esac
|
||||
@ -48,25 +58,18 @@ extfor() {
|
||||
|
||||
deletemap() {
|
||||
case "$1" in
|
||||
nz4) rm -fr $2;;
|
||||
nzf) rm -fr $2;;
|
||||
file) rm -fr $2;;
|
||||
zip) rm -f $2;;
|
||||
s3) S3KEY=`${execdir}/zs3parse -k $2`; awsdelete $S3KEY;;
|
||||
*) echo "unknown kind: $1" ; exit 1;;
|
||||
esac
|
||||
}
|
||||
|
||||
mapexists() {
|
||||
mapexists=1
|
||||
case "$1" in
|
||||
nz4) if test -f $file; then mapexists=0; fi ;;
|
||||
nzf) if test -f $file; then mapexists=0; fi ;;
|
||||
s3)
|
||||
if "./zmapio $fileurl" ; then mapexists=1; else mapexists=0; fi
|
||||
;;
|
||||
*) echo unknown format: $1 : abort ; exit 1 ;;
|
||||
esac
|
||||
if test $mapexists = 1 ; then
|
||||
mapstillexists() {
|
||||
mapstillexists=0
|
||||
if "./zmapio $fileurl" ; then
|
||||
echo "delete failed: $1"
|
||||
mapstillexists=1
|
||||
fi
|
||||
}
|
||||
|
||||
@ -74,11 +77,7 @@ fileargs() {
|
||||
f="$1"
|
||||
case "$zext" in
|
||||
s3)
|
||||
if test "x$NCS3PATH" = x ; then
|
||||
S3PATH="https://stratus.ucar.edu/unidata-netcdf-zarr-testing"
|
||||
else
|
||||
S3PATH="${NCS3PATH}"
|
||||
fi
|
||||
S3PATH="${NCZARR_S3_TEST_URL}/netcdf-c"
|
||||
fileurl="${S3PATH}/${f}#mode=nczarr,$zext"
|
||||
file=$fileurl
|
||||
S3HOST=`${execdir}/zs3parse -h $S3PATH`
|
||||
@ -92,36 +91,11 @@ fileargs() {
|
||||
esac
|
||||
}
|
||||
|
||||
dumpmap1() {
|
||||
local ISJSON
|
||||
tmp=
|
||||
if test -f $1 ; then
|
||||
ISJSON=`${execdir}/zisjson <$1`
|
||||
if test "x$ISJSON" = x1 ; then
|
||||
tmp=`tr '\r\n' ' ' <$1`
|
||||
else
|
||||
tmp=`${execdir}/zhex <$1`
|
||||
fi
|
||||
echo "$1 : |$tmp|" >> $2
|
||||
else
|
||||
echo "$1" >> $2
|
||||
fi
|
||||
}
|
||||
|
||||
dumpmap() {
|
||||
case "$1" in
|
||||
nz4) rm -f $3 ; ${NCDUMP} $2 > $3 ;;
|
||||
nzf)
|
||||
rm -f $3
|
||||
export LC_ALL=C
|
||||
lr=`find $2 | sort| tr '\r\n' ' '`
|
||||
for f in $lr ; do dumpmap1 $f $3 ; done
|
||||
;;
|
||||
s3)
|
||||
aws s3api list-objects --endpoint-url=$S3HOST --bucket=$S3BUCKET
|
||||
;;
|
||||
*) echo "dumpmap failed" ; exit 1;
|
||||
esac
|
||||
zext=$1
|
||||
zbase=`basename $2 ".$zext"`
|
||||
fileargs $zbase
|
||||
${execdir}/zmapio -t int -x objdump $fileurl > $3
|
||||
}
|
||||
|
||||
difftest() {
|
||||
|
@ -66,8 +66,8 @@ static void
|
||||
setimpl(const char* name)
|
||||
{
|
||||
if(strcasecmp(name,"s3")==0) itoptions.impl = NCZM_S3;
|
||||
else if(strcasecmp(name,"nz4")==0) itoptions.impl = NCZM_NC4;
|
||||
else if(strcasecmp(name,"nzf")==0) itoptions.impl = NCZM_FILE;
|
||||
else if(strcasecmp(name,"file")==0) itoptions.impl = NCZM_FILE;
|
||||
else if(strcasecmp(name,"zip")==0) itoptions.impl = NCZM_ZIP;
|
||||
else test_usage();
|
||||
}
|
||||
|
||||
@ -76,8 +76,8 @@ implname(void)
|
||||
{
|
||||
switch (itoptions.impl) {
|
||||
case NCZM_S3: return "s3";
|
||||
case NCZM_NC4: return "nz4";
|
||||
case NCZM_FILE: return "nzf";
|
||||
case NCZM_FILE: return "file";
|
||||
case NCZM_ZIP: return "zip";
|
||||
default: test_usage();
|
||||
}
|
||||
return NULL;
|
||||
@ -88,7 +88,7 @@ buildpath(const char* target,NCZM_IMPL impl)
|
||||
{
|
||||
NCbytes* buf = ncbytesnew();
|
||||
switch(itoptions.impl) {
|
||||
case NCZM_NC4:
|
||||
case NCZM_ZIP:
|
||||
case NCZM_FILE:
|
||||
ncbytescat(buf,"file://");
|
||||
ncbytescat(buf,target);
|
||||
|
@ -2,19 +2,14 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <netcdf.h>
|
||||
#include <ncpathmgr.h>
|
||||
#include <nclist.h>
|
||||
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include "XGetopt.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_HDF5_H
|
||||
#include <hdf5.h>
|
||||
#include <H5DSpublic.h>
|
||||
|
@ -1,19 +1,27 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "netcdf.h"
|
||||
#include "nclist.h"
|
||||
|
||||
#include "zincludes.h"
|
||||
|
||||
#include "tst_utils.h"
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
static void
|
||||
nccheck(int ret)
|
||||
nccheck(int ret, int lineno)
|
||||
{
|
||||
if(ret == NC_NOERR) return;
|
||||
fprintf(stderr,"err=%s\n",nc_strerror(ret));
|
||||
exit(1);
|
||||
report(ret,lineno);
|
||||
}
|
||||
|
||||
#define NCCHECK(err) nccheck(err)
|
||||
#define NCCHECK(err) nccheck(err,__LINE__)
|
||||
|
||||
int
|
||||
main(int argc, char *argv[] )
|
||||
@ -22,11 +30,14 @@ main(int argc, char *argv[] )
|
||||
size_t dimlen[1];
|
||||
float *fdat;
|
||||
int *idat;
|
||||
const char* filename = "file://tmp_fillonly.nc#mode=nczarr,nzf";
|
||||
const char* filename = NULL;
|
||||
const char* varname = "f";
|
||||
const char* dimname = "x";
|
||||
size_t i;
|
||||
|
||||
NCCHECK(getoptions(&argc,&argv));
|
||||
filename = options->file;
|
||||
|
||||
NCCHECK(err = nc_open(filename,NC_NETCDF4,&ncid));
|
||||
NCCHECK(err = nc_inq_varid(ncid, varname, &varid));
|
||||
NCCHECK(err = nc_inq_dimid(ncid, dimname, dimid));
|
||||
@ -57,7 +68,6 @@ main(int argc, char *argv[] )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(fdat) free(fdat);
|
||||
if(idat) free(idat);
|
||||
return 0;
|
||||
|
@ -416,7 +416,7 @@ odom_printshort(Odometer* odom)
|
||||
return odom_print1(odom,1);
|
||||
}
|
||||
|
||||
static const char* urlexts[] = {"nzf", "nz4", NULL};
|
||||
static const char* urlexts[] = {"nzf", "zip", "nz4", NULL};
|
||||
|
||||
const char*
|
||||
filenamefor(const char* f0)
|
||||
@ -443,3 +443,25 @@ filenamefor(const char* f0)
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
static char s3testurl[8192];
|
||||
static char* s3testurlp = NULL;
|
||||
|
||||
const char*
|
||||
ncz_gets3testurl(void)
|
||||
{
|
||||
char* s;
|
||||
if(s3testurlp == NULL) {
|
||||
s3testurl[0] = '\0';
|
||||
strcat(s3testurl,"https://");
|
||||
s = getenv("NCZARR_S3_TEST_HOST");
|
||||
if(s == NULL) s = "stratus.ucar.edu";
|
||||
strcat(s3testurl,s);
|
||||
strcat(s3testurl,"/");
|
||||
s = getenv("NCZARR_S3_TEST_BUCKET");
|
||||
if(s == NULL) s = "unidata-netcdf-zarr-testing";
|
||||
strcat(s3testurl,s);
|
||||
s3testurlp = s3testurl;
|
||||
}
|
||||
return s3testurlp;
|
||||
}
|
||||
|
@ -76,6 +76,8 @@ EXTERNL void cleanup(void);
|
||||
|
||||
EXTERNL int nc__testurl(const char*,char**);
|
||||
|
||||
EXTERNL const char* ncz_gets3testurl(void);
|
||||
|
||||
static void
|
||||
report(int err, int lineno)
|
||||
{
|
||||
|
@ -11,7 +11,7 @@
|
||||
#define DEBUG
|
||||
|
||||
static int ret = NC_NOERR;
|
||||
#define FILE_NAME "tst_chunks3.nc"
|
||||
#define FILE_NAME "tmp_chunks3.nc"
|
||||
|
||||
#define VAR_RANK 7
|
||||
#define IVAR_NAME "ivar"
|
||||
@ -73,5 +73,6 @@ main(int argc, char** argv)
|
||||
if ((ret=nc_close(ncid))) LERR;
|
||||
|
||||
SUMMARIZE_ERR;
|
||||
FINAL_RESULTS;
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "zmap.h"
|
||||
|
||||
#include "netcdf.h"
|
||||
#include "nclist.h"
|
||||
#include "ncbytes.h"
|
||||
|
@ -30,6 +30,7 @@ static int simpledelete(void);
|
||||
static int writemeta(void);
|
||||
static int writemeta2(void);
|
||||
static int readmeta(void);
|
||||
static int readmeta2(void);
|
||||
static int writedata(void);
|
||||
static int readdata(void);
|
||||
static int search(void);
|
||||
@ -40,6 +41,7 @@ struct Test tests[] = {
|
||||
{"writemeta", writemeta},
|
||||
{"writemeta2", writemeta2},
|
||||
{"readmeta", readmeta},
|
||||
{"readmeta2", readmeta2},
|
||||
{"writedata", writedata},
|
||||
{"readdata", readdata},
|
||||
{"search", search},
|
||||
@ -77,13 +79,14 @@ simplecreate(void)
|
||||
|
||||
if((stat=nczm_concat(NULL,NCZMETAROOT,&path)))
|
||||
goto done;
|
||||
if((stat = nczmap_defineobj(map, path)))
|
||||
|
||||
/* Write empty metadata content */
|
||||
if((stat = nczmap_write(map, path, 0, 0, (const void*)"")))
|
||||
goto done;
|
||||
|
||||
/* Do not delete so we can look at it with ncdump */
|
||||
if((stat = nczmap_close(map,0)))
|
||||
goto done;
|
||||
done:
|
||||
/* Do not delete so we can look at it with ncdump */
|
||||
stat = nczmap_close(map,0);
|
||||
nullfree(path);
|
||||
return THROW(stat);
|
||||
}
|
||||
@ -111,19 +114,11 @@ writemeta(void)
|
||||
NCZMAP* map = NULL;
|
||||
char* path = NULL;
|
||||
|
||||
if((stat = nczmap_create(impl,url,0,0,NULL,&map)))
|
||||
if((stat = nczmap_open(impl,url,NC_WRITE,0,NULL,&map)))
|
||||
goto done;
|
||||
|
||||
if((stat=nczm_concat(NULL,NCZMETAROOT,&path)))
|
||||
goto done;
|
||||
if((stat = nczmap_defineobj(map, path)))
|
||||
goto done;
|
||||
free(path); path = NULL;
|
||||
|
||||
if((stat=nczm_concat(META1,ZARRAY,&path)))
|
||||
goto done;
|
||||
if((stat = nczmap_defineobj(map, path)))
|
||||
goto done;
|
||||
if((stat = nczmap_write(map, path, 0, strlen(metadata1), metadata1)))
|
||||
goto done;
|
||||
free(path); path = NULL;
|
||||
@ -147,8 +142,6 @@ writemeta2(void)
|
||||
|
||||
if((stat=nczm_concat(META2,NCZVAR,&path)))
|
||||
goto done;
|
||||
if((stat = nczmap_defineobj(map,path)))
|
||||
goto done;
|
||||
if((stat = nczmap_write(map, path, 0, strlen(metadata2), metadata2)))
|
||||
goto done;
|
||||
|
||||
@ -160,18 +153,14 @@ done:
|
||||
}
|
||||
|
||||
static int
|
||||
readmeta(void)
|
||||
readkey(NCZMAP* map, const char* prefix, const char* object)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
NCZMAP* map = NULL;
|
||||
char* path = NULL;
|
||||
size64_t olen;
|
||||
char* content = NULL;
|
||||
|
||||
if((stat = nczmap_open(impl,url,0,0,NULL,&map)))
|
||||
goto done;
|
||||
|
||||
if((stat=nczm_concat(META1,ZARRAY,&path)))
|
||||
if((stat=nczm_concat(prefix,object,&path)))
|
||||
goto done;
|
||||
|
||||
/* Get length */
|
||||
@ -191,12 +180,44 @@ readmeta(void)
|
||||
printf("%s: |%s|\n",path,content);
|
||||
|
||||
done:
|
||||
(void)nczmap_close(map,0);
|
||||
nullfree(content);
|
||||
nullfree(path);
|
||||
return THROW(stat);
|
||||
}
|
||||
|
||||
static int
|
||||
readmeta(void)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
NCZMAP* map = NULL;
|
||||
|
||||
if((stat = nczmap_open(impl,url,0,0,NULL,&map)))
|
||||
goto done;
|
||||
|
||||
if((stat = readkey(map,META1,ZARRAY))) goto done;
|
||||
|
||||
done:
|
||||
(void)nczmap_close(map,0);
|
||||
return THROW(stat);
|
||||
}
|
||||
|
||||
static int
|
||||
readmeta2(void)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
NCZMAP* map = NULL;
|
||||
|
||||
if((stat = nczmap_open(impl,url,0,0,NULL,&map)))
|
||||
goto done;
|
||||
|
||||
if((stat = readkey(map,META2,NCZVAR)))
|
||||
goto done;
|
||||
|
||||
done:
|
||||
(void)nczmap_close(map,0);
|
||||
return THROW(stat);
|
||||
}
|
||||
|
||||
static int
|
||||
writedata(void)
|
||||
{
|
||||
@ -207,6 +228,7 @@ writedata(void)
|
||||
int i;
|
||||
size64_t totallen;
|
||||
char* data1p = (char*)&data1[0]; /* byte level version of data1 */
|
||||
NCZM_PROPERTIES props;
|
||||
|
||||
/* Create the data */
|
||||
for(i=0;i<DATA1LEN;i++) data1[i] = i;
|
||||
@ -219,21 +241,23 @@ writedata(void)
|
||||
if((stat=nczm_concat(DATA1,"0",&path)))
|
||||
goto done;
|
||||
|
||||
if((stat = nczmap_defineobj(map,path)))
|
||||
goto done;
|
||||
|
||||
/* Write in 3 slices */
|
||||
for(i=0;i<3;i++) {
|
||||
size64_t start, count, third, last;
|
||||
third = (totallen+2) / 3; /* round up */
|
||||
start = i * third;
|
||||
last = start + third;
|
||||
if(last > totallen)
|
||||
last = totallen;
|
||||
count = last - start;
|
||||
|
||||
if((stat = nczmap_write(map, path, start, count, &data1p[start])))
|
||||
goto done;
|
||||
props = nczmap_properties(impl);
|
||||
if((NCZM_ZEROSTART & props) || (NCZM_WRITEONCE & props)) {
|
||||
if((stat = nczmap_write(map, path, 0, totallen, data1p)))
|
||||
goto done;
|
||||
} else {
|
||||
/* Write in 3 slices */
|
||||
for(i=0;i<3;i++) {
|
||||
size64_t start, count, third, last;
|
||||
third = (totallen+2) / 3; /* round up */
|
||||
start = i * third;
|
||||
last = start + third;
|
||||
if(last > totallen)
|
||||
last = totallen;
|
||||
count = last - start;
|
||||
if((stat = nczmap_write(map, path, start, count, &data1p[start])))
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
@ -299,28 +323,41 @@ done:
|
||||
}
|
||||
|
||||
static int
|
||||
searchR(NCZMAP* map, int depth, const char* prefix, NClist* objects)
|
||||
searchR(NCZMAP* map, int depth, const char* prefix0, NClist* objects)
|
||||
{
|
||||
int i,stat = NC_NOERR;
|
||||
NClist* matches = nclistnew();
|
||||
char prefix[4096]; /* only ok because we know testdata */
|
||||
size_t prefixlen;
|
||||
|
||||
/* add this prefix to object list */
|
||||
nclistpush(objects,strdup(prefix));
|
||||
/* get next level object keys **below** the prefix */
|
||||
nclistpush(objects,strdup(prefix0));
|
||||
|
||||
prefix[0] = '\0';
|
||||
strlcat(prefix,prefix0,sizeof(prefix));
|
||||
prefixlen = strlen(prefix);
|
||||
|
||||
/* get next level object keys **below** the prefix: should have form: <name> */
|
||||
switch (stat = nczmap_search(map, prefix, matches)) {
|
||||
case NC_NOERR: break;
|
||||
case NC_ENOTFOUND: stat = NC_NOERR; break;/* prefix is not a dir */
|
||||
default: goto done;
|
||||
}
|
||||
/* recurse */
|
||||
for(i=0;i<nclistlength(matches);i++) {
|
||||
const char* key = nclistget(matches,i);
|
||||
if((stat = searchR(map,depth+1,key,objects))) goto done;
|
||||
/* ensure trailing '/' */
|
||||
if(prefix[prefixlen-1] != '/')
|
||||
strlcat(prefix,"/",sizeof(prefix));
|
||||
strlcat(prefix,key,sizeof(prefix));
|
||||
if((stat = searchR(map,depth+1,prefix,objects))) goto done;
|
||||
/* restore prefix */
|
||||
prefix[prefixlen] = '\0';
|
||||
if(stat != NC_NOERR)
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
nclistfreeall(matches);
|
||||
return stat;
|
||||
return THROW(stat);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -85,13 +85,14 @@ simplecreate(void)
|
||||
printf("Pass: create: create: %s\n",url);
|
||||
|
||||
truekey = makekey(NCZMETAROOT);
|
||||
if((stat = nczmap_defineobj(map, truekey)))
|
||||
if((stat = nczmap_write(map, truekey, 0, 0, NULL)))
|
||||
goto done;
|
||||
printf("Pass: create: defineobj: %s\n",truekey);
|
||||
|
||||
/* Do not delete */
|
||||
if((stat = nczmap_close(map,0)))
|
||||
goto done;
|
||||
map = NULL;
|
||||
printf("Pass: create: close\n");
|
||||
|
||||
/* Reopen and see if exists */
|
||||
@ -106,6 +107,7 @@ simplecreate(void)
|
||||
/* close again */
|
||||
if((stat = nczmap_close(map,0)))
|
||||
goto done;
|
||||
map = NULL;
|
||||
printf("Pass: create: close\n");
|
||||
|
||||
done:
|
||||
@ -126,24 +128,24 @@ simpledelete(void)
|
||||
case NC_NOERR:
|
||||
report(PASS,"open",map);
|
||||
break;
|
||||
case NC_EEMPTY:
|
||||
{report(XFAIL,"open",map); stat = NC_NOERR; goto done;}
|
||||
default:
|
||||
{report(FAIL,"open",map); goto done;}
|
||||
}
|
||||
/* Delete dataset while closing */
|
||||
if((stat = nczmap_close(map,1))) goto done;
|
||||
map = NULL;
|
||||
report(PASS,"close: delete",map);
|
||||
|
||||
switch ((stat = nczmap_open(impl,url,0,0,NULL,&map))) {
|
||||
default:
|
||||
case NC_NOERR:
|
||||
report(FAIL,"open",map);
|
||||
break;
|
||||
case NC_EEMPTY:
|
||||
case NC_ENOTFOUND:
|
||||
report(XFAIL,"open",map);
|
||||
stat = NC_NOERR;
|
||||
break;
|
||||
case NC_EEMPTY:
|
||||
default: abort();
|
||||
}
|
||||
|
||||
done:
|
||||
@ -166,20 +168,21 @@ simplemeta(void)
|
||||
goto done;
|
||||
report(PASS,"open",map);
|
||||
|
||||
/* Make sure .nczarr exists (from simplecreate) */
|
||||
truekey = makekey(NCZMETAROOT);
|
||||
if((stat = nczmap_defineobj(map, truekey)))
|
||||
if((stat = nczmap_exists(map,truekey)))
|
||||
goto done;
|
||||
report(PASS,".nczarr: def",map);
|
||||
report(PASS,".nczarr: exists",map);
|
||||
free(truekey); truekey = NULL;
|
||||
|
||||
if((stat=nczm_concat(META1,ZARRAY,&key)))
|
||||
goto done;
|
||||
truekey = makekey(key);
|
||||
nullfree(key); key = NULL;
|
||||
if((stat = nczmap_defineobj(map, truekey)))
|
||||
if((stat = nczmap_write(map, truekey, 0, 0, NULL)))
|
||||
goto done;
|
||||
report(PASS,".zarray: def",map);
|
||||
free(truekey); key = NULL;
|
||||
free(truekey); truekey = NULL;
|
||||
|
||||
truekey = makekey(NCZMETAROOT);
|
||||
if((stat = nczmap_write(map, truekey, 0, strlen(metadata1), metadata1)))
|
||||
@ -199,6 +202,7 @@ simplemeta(void)
|
||||
|
||||
if((stat = nczmap_close(map,0)))
|
||||
goto done;
|
||||
map = NULL;
|
||||
report(PASS,"close",map);
|
||||
|
||||
if((stat = nczmap_open(impl,url,0,0,NULL,&map)))
|
||||
@ -251,9 +255,11 @@ simplemeta(void)
|
||||
|
||||
if((stat = nczmap_close(map,0)))
|
||||
goto done;
|
||||
map = NULL;
|
||||
report(PASS,"close",map);
|
||||
|
||||
done:
|
||||
if(map) nczmap_close(map,0);
|
||||
nullfree(content);
|
||||
nullfree(truekey);
|
||||
nullfree(key);
|
||||
@ -271,6 +277,7 @@ simpledata(void)
|
||||
int i;
|
||||
size64_t totallen, size;
|
||||
char* data1p = (char*)&data1[0]; /* byte level version of data1 */
|
||||
NCZM_PROPERTIES props;
|
||||
|
||||
title(__func__);
|
||||
|
||||
@ -283,26 +290,30 @@ simpledata(void)
|
||||
report(PASS,"open",map);
|
||||
|
||||
truekey = makekey(DATA1);
|
||||
if((stat = nczmap_defineobj(map, truekey)))
|
||||
goto done;
|
||||
report(PASS,DATA1": def",map);
|
||||
|
||||
/* Write in 3 slices */
|
||||
for(i=0;i<3;i++) {
|
||||
size64_t start, count, third, last;
|
||||
third = (totallen+2) / 3; /* round up */
|
||||
start = i * third;
|
||||
last = start + third;
|
||||
if(last > totallen)
|
||||
last = totallen;
|
||||
count = last - start;
|
||||
if((stat = nczmap_write(map, truekey, start, count, &data1p[start])))
|
||||
goto done;
|
||||
props = nczmap_properties(impl);
|
||||
if((NCZM_ZEROSTART & props) || (NCZM_WRITEONCE & props)) {
|
||||
if((stat = nczmap_write(map, truekey, 0, totallen, data1p)))
|
||||
goto done;
|
||||
} else {
|
||||
/* Write in 3 slices */
|
||||
for(i=0;i<3;i++) {
|
||||
size64_t start, count, third, last;
|
||||
third = (totallen+2) / 3; /* round up */
|
||||
start = i * third;
|
||||
last = start + third;
|
||||
if(last > totallen)
|
||||
last = totallen;
|
||||
count = last - start;
|
||||
if((stat = nczmap_write(map, truekey, start, count, &data1p[start])))
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
report(PASS,DATA1": write",map);
|
||||
|
||||
if((stat = nczmap_close(map,0)))
|
||||
goto done;
|
||||
map = NULL;
|
||||
report(PASS,"close",map);
|
||||
|
||||
if((stat = nczmap_open(impl,url,0,0,NULL,&map)))
|
||||
@ -328,32 +339,47 @@ simpledata(void)
|
||||
|
||||
done:
|
||||
/* Do not delete so we can look at it with ncdump */
|
||||
if((stat = nczmap_close(map,0)))
|
||||
if(map && (stat = nczmap_close(map,0)))
|
||||
goto done;
|
||||
nullfree(truekey);
|
||||
return THROW(stat);
|
||||
}
|
||||
|
||||
static int
|
||||
searchR(NCZMAP* map, int depth, const char* prefix, NClist* objects)
|
||||
searchR(NCZMAP* map, int depth, const char* prefix0, NClist* objects)
|
||||
{
|
||||
int i,stat = NC_NOERR;
|
||||
NClist* matches = nclistnew();
|
||||
char prefix[4096]; /* only ok because we know testdata */
|
||||
size_t prefixlen;
|
||||
|
||||
/* add this prefix to object list */
|
||||
nclistpush(objects,strdup(prefix));
|
||||
|
||||
/* get next level object keys **below** the prefix */
|
||||
if((stat = nczmap_search(map, prefix, matches)))
|
||||
goto done;
|
||||
nclistpush(objects,strdup(prefix0));
|
||||
|
||||
prefix[0] = '\0';
|
||||
strlcat(prefix,prefix0,sizeof(prefix));
|
||||
prefixlen = strlen(prefix);
|
||||
|
||||
/* get next level object keys **below** the prefix: should have form: <name> */
|
||||
switch (stat = nczmap_search(map, prefix, matches)) {
|
||||
case NC_NOERR: break;
|
||||
case NC_ENOTFOUND: stat = NC_NOERR; break;/* prefix is not a dir */
|
||||
default: goto done;
|
||||
}
|
||||
reportx(PASS,prefix,"search",map);
|
||||
|
||||
/* recurse */
|
||||
for(i=0;i<nclistlength(matches);i++) {
|
||||
const char* key = nclistget(matches,i);
|
||||
if((stat = searchR(map,depth+1,key,objects))) goto done;
|
||||
/* ensure trailing '/' */
|
||||
if(prefix[prefixlen-1] != '/')
|
||||
strlcat(prefix,"/",sizeof(prefix));
|
||||
strlcat(prefix,key,sizeof(prefix));
|
||||
if((stat = searchR(map,depth+1,prefix,objects))) goto done;
|
||||
/* restore prefix */
|
||||
prefix[prefixlen] = '\0';
|
||||
if(stat != NC_NOERR)
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
nclistfreeall(matches);
|
||||
return THROW(stat);
|
||||
@ -373,7 +399,7 @@ search(void)
|
||||
/* Do a recursive search on root to get all object keys */
|
||||
if((stat=searchR(map,0,"/",objects)))
|
||||
goto done;
|
||||
/* sort list */
|
||||
/* Sort */
|
||||
ut_sortlist(objects);
|
||||
/* Print out the list */
|
||||
for(i=0;i<nclistlength(objects);i++) {
|
||||
@ -383,8 +409,10 @@ search(void)
|
||||
|
||||
done:
|
||||
/* Do not delete so later tests can use it */
|
||||
(void)nczmap_close(map,0);
|
||||
report(PASS,"close",map);
|
||||
if(map) {
|
||||
(void)nczmap_close(map,0);
|
||||
report(PASS,"close",map);
|
||||
}
|
||||
nclistfreeall(objects);
|
||||
return THROW(stat);
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
/*
|
||||
* Copyright 2018, University Corporation for Atmospheric Research
|
||||
x * Copyright 2018, University Corporation for Atmospheric Research
|
||||
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
|
||||
*/
|
||||
|
||||
#include "ut_includes.h"
|
||||
#include "ncpathmgr.h"
|
||||
#include "nclog.h"
|
||||
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
@ -55,8 +56,11 @@ ut_init(int argc, char** argv, struct UTOptions * options)
|
||||
if(options != NULL) {
|
||||
options->dimdefs = nclistnew();
|
||||
options->vardefs = nclistnew();
|
||||
while ((c = getopt(argc, argv, "Dx:f:o:k:d:v:s:W:")) != EOF) {
|
||||
while ((c = getopt(argc, argv, "T:Dx:f:o:k:d:v:s:W:")) != EOF) {
|
||||
switch(c) {
|
||||
case 'T':
|
||||
nctracelevel(atoi(optarg));
|
||||
break;
|
||||
case 'D':
|
||||
options->debug = 1;
|
||||
break;
|
||||
@ -188,8 +192,8 @@ makeurl(const char* file, NCZM_IMPL impl)
|
||||
|
||||
if(file && strlen(file) > 0) {
|
||||
switch (impl) {
|
||||
case NCZM_NC4: /* fall thru */
|
||||
case NCZM_FILE:
|
||||
case NCZM_ZIP:
|
||||
/* Massage file to make it usable as URL path */
|
||||
if((path = NCurlpath(file))==NULL) return NULL;
|
||||
ncbytescat(buf,"file://");
|
||||
|
@ -361,8 +361,8 @@ NCZM_IMPL
|
||||
kind2impl(const char* kind)
|
||||
{
|
||||
if(strcasecmp("s3",kind)==0) return NCZM_S3;
|
||||
else if(strcasecmp("nz4",kind)==0) return NCZM_NC4;
|
||||
else if(strcasecmp("nzf",kind)==0) return NCZM_FILE;
|
||||
else if(strcasecmp("file",kind)==0) return NCZM_FILE;
|
||||
else if(strcasecmp("zip",kind)==0) return NCZM_ZIP;
|
||||
else return NCZM_UNDEF;
|
||||
}
|
||||
|
||||
@ -371,8 +371,8 @@ impl2kind(NCZM_IMPL impl)
|
||||
{
|
||||
switch (impl) {
|
||||
case NCZM_S3: return "s3";
|
||||
case NCZM_NC4: return "nz4";
|
||||
case NCZM_FILE: return "nzf";
|
||||
case NCZM_FILE: return "file";
|
||||
case NCZM_ZIP: return "zip";
|
||||
case NCZM_UNDEF: break;
|
||||
}
|
||||
return NULL;
|
||||
|
@ -21,9 +21,17 @@ main(int argc, char** argv)
|
||||
{
|
||||
unsigned char c;
|
||||
unsigned int c0,c1;
|
||||
FILE* f = NULL;
|
||||
|
||||
if(argc > 1) {
|
||||
/* use argv[1] as input */
|
||||
f = fopen(argv[1],"r");
|
||||
if(f == NULL) {fprintf(stderr,"No such file: %s\n",argv[1]); exit(1);}
|
||||
} else
|
||||
f = stdin;
|
||||
|
||||
for(;;) {
|
||||
int ret = fread(&c, 1, 1, stdin);
|
||||
int ret = fread(&c, 1, 1, f);
|
||||
if(ret != 1) break;
|
||||
c1 = c;
|
||||
c0 = c1 & 0xf;
|
||||
@ -32,5 +40,6 @@ main(int argc, char** argv)
|
||||
c1 = hex[c1];
|
||||
printf("%c%c",(char)c1,(char)c0);
|
||||
}
|
||||
if(f != stdin) fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
@ -29,11 +29,19 @@ main(int argc, char** argv)
|
||||
char text[MAXREAD+1];
|
||||
NCjson* json = NULL;
|
||||
int i, red;
|
||||
FILE* f = NULL;
|
||||
|
||||
if(argc > 1) {
|
||||
/* use argv[1] as input */
|
||||
f = fopen(argv[1],"r");
|
||||
if(f == NULL) {fprintf(stderr,"No such file: %s\n",argv[1]); exit(1);}
|
||||
} else
|
||||
f = stdin;
|
||||
|
||||
/* Read json from stdin */
|
||||
for(i=0;;i++) {
|
||||
unsigned char c;
|
||||
red = fread(&c, 1, 1, stdin);
|
||||
red = fread(&c, 1, 1, f);
|
||||
if(red != 1) break;
|
||||
if(i < MAXREAD) text[i] = (char)c;
|
||||
}
|
||||
@ -49,5 +57,6 @@ main(int argc, char** argv)
|
||||
NCJreclaim(json);
|
||||
}
|
||||
printf("%d",(stat==NC_NOERR?1:0)); /* parse success|failure */
|
||||
if(f != stdin) fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
#include "zincludes.h"
|
||||
#include "ncpathmgr.h"
|
||||
#include "nclog.h"
|
||||
#include "ncuri.h"
|
||||
|
||||
#define DEBUG
|
||||
|
||||
@ -33,7 +35,8 @@ MOP_CLEAR=2
|
||||
typedef enum OBJKIND {
|
||||
OK_NONE=0,
|
||||
OK_META=1,
|
||||
OK_CHUNK=2
|
||||
OK_CHUNK=2,
|
||||
OK_GROUP=3
|
||||
} OBJKIND;
|
||||
|
||||
static struct Mops {
|
||||
@ -78,7 +81,7 @@ struct Dumpptions {
|
||||
static int objdump(void);
|
||||
static NCZM_IMPL implfor(const char* path);
|
||||
static void printcontent(size64_t len, const char* content, OBJKIND kind);
|
||||
static int depthR(NCZMAP* map, char* key, NClist* stack);
|
||||
static int breadthfirst(NCZMAP* map, const char*, NClist* stack);
|
||||
static char* rootpathfor(const char* path);
|
||||
static OBJKIND keykind(const char* key);
|
||||
static void sortlist(NClist* l);
|
||||
@ -105,7 +108,7 @@ static Mapop
|
||||
decodeop(const char* name)
|
||||
{
|
||||
struct Mops* p = mapops;
|
||||
while(p->opname != NULL) {
|
||||
for(;p->opname != NULL;p++) {
|
||||
if(strcasecmp(p->opname,name)==0) return p->mapop;
|
||||
}
|
||||
return MOP_NONE;
|
||||
@ -129,7 +132,7 @@ main(int argc, char** argv)
|
||||
|
||||
memset((void*)&dumpoptions,0,sizeof(dumpoptions));
|
||||
|
||||
while ((c = getopt(argc, argv, "dvx:t:")) != EOF) {
|
||||
while ((c = getopt(argc, argv, "dvx:t:T:")) != EOF) {
|
||||
switch(c) {
|
||||
case 'd':
|
||||
dumpoptions.debug = 1;
|
||||
@ -145,6 +148,9 @@ main(int argc, char** argv)
|
||||
dumpoptions.mop = decodeop(optarg);
|
||||
if(dumpoptions.mop == MOP_NONE) zmapusage();
|
||||
break;
|
||||
case 'T':
|
||||
nctracelevel(atoi(optarg));
|
||||
break;
|
||||
case '?':
|
||||
fprintf(stderr,"unknown option\n");
|
||||
goto fail;
|
||||
@ -219,8 +225,8 @@ implfor(const char* path)
|
||||
NCCHECK(nczm_split_delim(mode,',',segments));
|
||||
for(i=0;i<nclistlength(segments);i++) {
|
||||
const char* value = nclistget(segments,i);
|
||||
if(strcmp(value,"nz4")==0) {impl = NCZM_NC4; goto done;}
|
||||
if(strcmp(value,"nzf")==0) {impl = NCZM_FILE; goto done;}
|
||||
if(strcmp(value,"file")==0) {impl = NCZM_FILE; goto done;}
|
||||
if(strcmp(value,"zip")==0) {impl = NCZM_ZIP; goto done;}
|
||||
if(strcmp(value,"s3")==0) {impl = NCZM_S3; goto done;}
|
||||
}
|
||||
done:
|
||||
@ -242,7 +248,7 @@ rootpathfor(const char* path)
|
||||
if(uri == NULL) goto done;
|
||||
switch (dumpoptions.impl) {
|
||||
case NCZM_FILE:
|
||||
case NCZM_NC4:
|
||||
case NCZM_ZIP:
|
||||
rootpath = strdup("/"); /*constant*/
|
||||
break;
|
||||
case NCZM_S3:
|
||||
@ -272,7 +278,6 @@ objdump(void)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
NCZMAP* map = NULL;
|
||||
NClist* matches = nclistnew();
|
||||
NClist* stack = nclistnew();
|
||||
char* obj = NULL;
|
||||
char* content = NULL;
|
||||
@ -281,11 +286,8 @@ objdump(void)
|
||||
if((stat=nczmap_open(dumpoptions.impl, dumpoptions.infile, NC_NOCLOBBER, 0, NULL, &map)))
|
||||
goto done;
|
||||
|
||||
|
||||
/* Depth first walk all the groups to get all keys */
|
||||
obj = strdup("/");
|
||||
if((stat = depthR(map,obj,stack))) goto done;
|
||||
obj = NULL; /* its now in the stack */
|
||||
if((stat = breadthfirst(map,"/",stack))) goto done;
|
||||
|
||||
if(dumpoptions.debug) {
|
||||
int i;
|
||||
@ -298,6 +300,7 @@ objdump(void)
|
||||
OBJKIND kind = 0;
|
||||
int hascontent = 0;
|
||||
obj = nclistremove(stack,0); /* zero pos is always top of stack */
|
||||
kind = keykind(obj);
|
||||
/* Now print info for this obj key */
|
||||
switch (stat=nczmap_len(map,obj,&len)) {
|
||||
case NC_NOERR: hascontent = 1; break;
|
||||
@ -316,7 +319,6 @@ objdump(void)
|
||||
if(hascontent) {
|
||||
if(len > 0) {
|
||||
assert(content != NULL);
|
||||
kind = keykind(obj);
|
||||
if(kind == OK_CHUNK) len /= dumpoptions.nctype->typesize;
|
||||
printf("[%d] %s : (%llu)",depth,obj,len);
|
||||
if(kind == OK_CHUNK) printf(" (%s)",dumpoptions.nctype->typename);
|
||||
@ -337,32 +339,60 @@ done:
|
||||
nullfree(obj);
|
||||
nullfree(content);
|
||||
nczmap_close(map,0);
|
||||
nclistfreeall(matches);
|
||||
nclistfreeall(stack);
|
||||
return stat;
|
||||
}
|
||||
|
||||
/* Depth first walk all the groups to get all keys */
|
||||
static int
|
||||
depthR(NCZMAP* map, char* key, NClist* stack)
|
||||
breadthfirstR(NCZMAP* map, NCbytes* prefix, NClist* stack)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
NClist* nextlevel = nclistnew();
|
||||
size_t mark;
|
||||
const char* content;
|
||||
int isroot = 0;
|
||||
|
||||
nclistpush(stack,key);
|
||||
if((stat=nczmap_search(map,key,nextlevel))) goto done;
|
||||
content = ncbytescontents(prefix);
|
||||
if(content[0] == '/' && content[1] == '\0') isroot = 1;
|
||||
if((stat=nczmap_search(map,content,nextlevel))) goto done;
|
||||
/* Sort nextlevel */
|
||||
sortlist(nextlevel);
|
||||
/* Push new names onto the stack and recurse */
|
||||
mark = ncbyteslength(prefix); /* save this position */
|
||||
while(nclistlength(nextlevel) > 0) {
|
||||
char* subkey = nclistremove(nextlevel,0);
|
||||
if((stat = depthR(map,subkey,stack))) goto done;
|
||||
if(!isroot) ncbytescat(prefix,"/");
|
||||
ncbytescat(prefix,subkey);
|
||||
nullfree(subkey);
|
||||
nclistpush(stack,ncbytesdup(prefix));
|
||||
if((stat = breadthfirstR(map,prefix,stack))) goto done;
|
||||
ncbytessetlength(prefix,mark); ncbytesnull(prefix);
|
||||
}
|
||||
done:
|
||||
nclistfreeall(nextlevel);
|
||||
return stat;
|
||||
}
|
||||
|
||||
/* Depth first walk all the groups to get all keys */
|
||||
static int
|
||||
breadthfirst(NCZMAP* map, const char* key, NClist* stack)
|
||||
{
|
||||
int stat = NC_NOERR;
|
||||
NCbytes* prefix = ncbytesnew();
|
||||
|
||||
if(key == NULL || key[0] == '\0')
|
||||
key = "/";
|
||||
ncbytescat(prefix,key);
|
||||
if(strlen(key) > 1 && key[strlen(key)-1]=='/') {
|
||||
ncbytessetlength(prefix,ncbyteslength(prefix)-1); /* remove trailing '/' */
|
||||
ncbytesnull(prefix);
|
||||
}
|
||||
stat = breadthfirstR(map,prefix,stack);
|
||||
ncbytesfree(prefix);
|
||||
return stat;
|
||||
}
|
||||
|
||||
static char hex[16] = "0123456789abcdef";
|
||||
|
||||
static void
|
||||
@ -417,6 +447,8 @@ keykind(const char* key)
|
||||
kind = OK_NONE;
|
||||
else if(suffix[1] == '.')
|
||||
kind = OK_META;
|
||||
else if(suffix[strlen(suffix)-1] == '/')
|
||||
kind = OK_GROUP;
|
||||
else {
|
||||
char* p = suffix+1;
|
||||
for(;*p;p++) {
|
||||
@ -455,7 +487,7 @@ fprintf(stderr,"sorted: [%d] %s\n",i,(const char*)nclistget(l,i));
|
||||
#endif
|
||||
}
|
||||
|
||||
static const char* urlexts[] = {"nzf", "nz4", NULL};
|
||||
static const char* urlexts[] = {"nzf", "zip", "nz4", NULL};
|
||||
|
||||
static const char*
|
||||
filenamefor(const char* f0)
|
||||
@ -463,22 +495,26 @@ filenamefor(const char* f0)
|
||||
static char result[4096];
|
||||
const char** extp;
|
||||
char* p;
|
||||
NCURI* uri = NULL;
|
||||
|
||||
strcpy(result,f0); /* default */
|
||||
if(nc__testurl(f0,NULL)) goto done;
|
||||
/* Not a URL */
|
||||
p = strrchr(f0,'.'); /* look at the extension, if any */
|
||||
if(p == NULL) goto done; /* No extension */
|
||||
p++;
|
||||
for(extp=urlexts;*extp;extp++) {
|
||||
if(strcmp(p,*extp)==0) break;
|
||||
ncuriparse(f0,&uri);
|
||||
if(uri == NULL) {
|
||||
/* Not a URL */
|
||||
p = strrchr(f0,'.'); /* look at the extension, if any */
|
||||
if(p == NULL) goto done; /* No extension */
|
||||
p++;
|
||||
for(extp=urlexts;*extp;extp++) {
|
||||
if(strcmp(p,*extp)==0) break;
|
||||
}
|
||||
if(*extp == NULL) goto done; /* not found */
|
||||
/* Assemble the url */
|
||||
strcpy(result,"file://");
|
||||
strcat(result,f0); /* core path */
|
||||
strcat(result,"#mode=nczarr,");
|
||||
strcat(result,*extp);
|
||||
}
|
||||
if(*extp == NULL) goto done; /* not found */
|
||||
/* Assemble the url */
|
||||
strcpy(result,"file://");
|
||||
strcat(result,f0); /* core path */
|
||||
strcat(result,"#mode=nczarr,");
|
||||
strcat(result,*extp);
|
||||
done:
|
||||
ncurifree(uri);
|
||||
return result;
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ TOPBUILDDIR='@abs_top_builddir@'
|
||||
# Define selected features of the build
|
||||
FEATURE_HDF5=@HAS_HDF5@
|
||||
FEATURE_S3TESTS=@DO_NCZARR_S3_TESTS@
|
||||
FEATURE_NCZARR_ZIP=@DO_NCZARR_ZIP_TESTS@
|
||||
|
||||
set -e
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user