Fix infinite loop in file inferencing

re: Issue https://github.com/Unidata/netcdf-c/issues/2573

The file type inferencer in libdispatch/dinference.c has a simple
forward inference mechanism so that the occurrence of certain mode
values in a URL fragment implies inclusion of additional mode values.
This kind of inference is notorious for leading to cycles if not
careful. Unfortunately, this occurred in the one in dinference.c.

This was fixed by providing a more complicated, but more reliable inference
mechanism.

## Misc. Other Changes
* Found and fixed a couple of memory leaks.
* There is a recent problem in building HDF4 support on github actions. Fixed by using the internal HDF4 xdr capability.
* Some filter-related code was not being properly ifdef'd with ENABLE_NCZARRA_FILTERS.
This commit is contained in:
Dennis Heimbigner 2022-12-18 13:18:00 -07:00
parent 0fc2c817b2
commit a03bb5e601
10 changed files with 177 additions and 86 deletions

View File

@ -7,7 +7,7 @@
name: Run macOS-based netCDF Tests name: Run macOS-based netCDF Tests
on: [pull_request, workflow_dispatch] on: [pull_request,workflow_dispatch]
jobs: jobs:

View File

@ -4,7 +4,7 @@
name: Run Ubuntu/Linux netCDF Tests name: Run Ubuntu/Linux netCDF Tests
on: [pull_request, workflow_dispatch] on: [pull_request,workflow_dispatch]
jobs: jobs:
@ -42,7 +42,7 @@ jobs:
wget https://support.hdfgroup.org/ftp/HDF/releases/HDF4.2.15/src/hdf-4.2.15.tar.bz2 wget https://support.hdfgroup.org/ftp/HDF/releases/HDF4.2.15/src/hdf-4.2.15.tar.bz2
tar -jxf hdf-4.2.15.tar.bz2 tar -jxf hdf-4.2.15.tar.bz2
pushd hdf-4.2.15 pushd hdf-4.2.15
./configure --prefix=${HOME}/environments/${{ matrix.hdf5 }} --disable-static --enable-shared --disable-fortran --disable-netcdf --with-szlib ./configure --prefix=${HOME}/environments/${{ matrix.hdf5 }} --disable-static --enable-shared --disable-fortran --disable-netcdf --with-szlib --enable-hdf4-xdr
make -j make -j
make install -j make install -j
popd popd
@ -89,7 +89,7 @@ jobs:
wget https://support.hdfgroup.org/ftp/HDF/releases/HDF4.2.15/src/hdf-4.2.15.tar.bz2 wget https://support.hdfgroup.org/ftp/HDF/releases/HDF4.2.15/src/hdf-4.2.15.tar.bz2
tar -jxf hdf-4.2.15.tar.bz2 tar -jxf hdf-4.2.15.tar.bz2
pushd hdf-4.2.15 pushd hdf-4.2.15
CC=mpicc ./configure --prefix=${HOME}/environments/${{ matrix.hdf5 }} --disable-static --enable-shared --disable-fortran --disable-netcdf --with-szlib --enable-parallel CC=mpicc ./configure --prefix=${HOME}/environments/${{ matrix.hdf5 }} --disable-static --enable-shared --disable-fortran --disable-netcdf --with-szlib --enable-parallel --enable-hdf4-xdr
make -j make -j
make install -j make install -j
popd popd

View File

@ -1,6 +1,6 @@
name: Run Cygwin-based tests name: Run Cygwin-based tests
on: [pull_request, workflow_dispatch] on: [pull_request,workflow_dispatch]
env: env:
SHELLOPTS: igncr SHELLOPTS: igncr

View File

@ -9,7 +9,7 @@ name: Run MSYS2, MinGW64-based Tests
env: env:
CPPFLAGS: "-D_BSD_SOURCE" CPPFLAGS: "-D_BSD_SOURCE"
on: [pull_request, workflow_dispatch] on: [pull_request,workflow_dispatch]
jobs: jobs:

View File

@ -1839,19 +1839,16 @@ NC_create(const char *path0, int cmode, size_t initialsz,
TRACE(nc_create); TRACE(nc_create);
if(path0 == NULL) if(path0 == NULL)
return NC_EINVAL; {stat = NC_EINVAL; goto done;}
/* Check mode flag for sanity. */ /* Check mode flag for sanity. */
if ((stat = check_create_mode(cmode))) if ((stat = check_create_mode(cmode))) goto done;
return stat;
/* Initialize the library. The available dispatch tables /* Initialize the library. The available dispatch tables
* will depend on how netCDF was built * will depend on how netCDF was built
* (with/without netCDF-4, DAP, CDMREMOTE). */ * (with/without netCDF-4, DAP, CDMREMOTE). */
if(!NC_initialized) if(!NC_initialized) {
{ if ((stat = nc_initialize())) goto done;
if ((stat = nc_initialize()))
return stat;
} }
{ {
@ -1863,10 +1860,7 @@ NC_create(const char *path0, int cmode, size_t initialsz,
memset(&model,0,sizeof(model)); memset(&model,0,sizeof(model));
newpath = NULL; newpath = NULL;
if((stat = NC_infermodel(path,&cmode,1,useparallel,NULL,&model,&newpath))) { if((stat = NC_infermodel(path,&cmode,1,useparallel,NULL,&model,&newpath))) goto done;
nullfree(newpath);
goto done;
}
if(newpath) { if(newpath) {
nullfree(path); nullfree(path);
path = newpath; path = newpath;
@ -1918,7 +1912,7 @@ NC_create(const char *path0, int cmode, size_t initialsz,
dispatcher = NC3_dispatch_table; dispatcher = NC3_dispatch_table;
break; break;
default: default:
return NC_ENOTNC; {stat = NC_ENOTNC; goto done;}
} }
/* Create the NC* instance and insert its dispatcher and model */ /* Create the NC* instance and insert its dispatcher and model */
@ -1937,6 +1931,7 @@ NC_create(const char *path0, int cmode, size_t initialsz,
} }
done: done:
nullfree(path); nullfree(path);
nullfree(newpath);
return stat; return stat;
} }
@ -1980,12 +1975,12 @@ NC_open(const char *path0, int omode, int basepe, size_t *chunksizehintp,
TRACE(nc_open); TRACE(nc_open);
if(!NC_initialized) { if(!NC_initialized) {
stat = nc_initialize(); stat = nc_initialize();
if(stat) return stat; if(stat) goto done;
} }
/* Check inputs. */ /* Check inputs. */
if (!path0) if (!path0)
return NC_EINVAL; {stat = NC_EINVAL; goto done;}
/* Capture the inmemory related flags */ /* Capture the inmemory related flags */
mmap = ((omode & NC_MMAP) == NC_MMAP); mmap = ((omode & NC_MMAP) == NC_MMAP);

View File

@ -143,7 +143,15 @@ static const struct MACRODEF {
{NULL,NULL,{NULL}} {NULL,NULL,{NULL}}
}; };
/* Mode inferences: if mode contains key, then add the inference and infer again */ /*
Mode inferences: if mode contains key value, then add the inferred value;
Warning: be careful how this list is constructed to avoid infinite inferences.
In order to (mostly) avoid that consequence, any attempt to
infer a value that is already present will be ignored.
This effectively means that the inference graph
must be a DAG and may not have cycles.
You have been warned.
*/
static const struct MODEINFER { static const struct MODEINFER {
char* key; char* key;
char* inference; char* inference;
@ -151,6 +159,7 @@ static const struct MODEINFER {
{"zarr","nczarr"}, {"zarr","nczarr"},
{"xarray","zarr"}, {"xarray","zarr"},
{"noxarray","nczarr"}, {"noxarray","nczarr"},
{"noxarray","zarr"},
{NULL,NULL} {NULL,NULL}
}; };
@ -202,6 +211,7 @@ static int processmacros(NClist** fraglistp);
static char* envvlist2string(NClist* pairs, const char*); static char* envvlist2string(NClist* pairs, const char*);
static void set_default_mode(int* cmodep); static void set_default_mode(int* cmodep);
static int parseonchar(const char* s, int ch, NClist* segments); static int parseonchar(const char* s, int ch, NClist* segments);
static int mergelist(NClist** valuesp);
static int openmagic(struct MagicFile* file); static int openmagic(struct MagicFile* file);
static int readmagic(struct MagicFile* file, long pos, char* magic); static int readmagic(struct MagicFile* file, long pos, char* magic);
@ -217,8 +227,9 @@ static int parsepair(const char* pair, char** keyp, char** valuep);
static NClist* parsemode(const char* modeval); static NClist* parsemode(const char* modeval);
static const char* getmodekey(const NClist* envv); static const char* getmodekey(const NClist* envv);
static int replacemode(NClist* envv, const char* newval); static int replacemode(NClist* envv, const char* newval);
static int inferone(const char* mode, NClist* newmodes); static void infernext(NClist* current, NClist* next);
static int negateone(const char* mode, NClist* modes); static int negateone(const char* mode, NClist* modes);
static void cleanstringlist(NClist* strs, int caseinsensitive);
/* /*
If the path looks like a URL, then parse it, reformat it. If the path looks like a URL, then parse it, reformat it.
@ -416,28 +427,6 @@ envvlist2string(NClist* envv, const char* delim)
return result; return result;
} }
/* Convert a list into a comma'd string */
static char*
list2string(NClist* list)
{
int i;
NCbytes* buf = NULL;
char* result = NULL;
if(list == NULL || nclistlength(list)==0) return strdup("");
buf = ncbytesnew();
for(i=0;i<nclistlength(list);i++) {
const char* m = nclistget(list,i);
if(m == NULL || strlen(m) == 0) continue;
if(i > 0) ncbytescat(buf,",");
ncbytescat(buf,m);
}
result = ncbytesextract(buf);
ncbytesfree(buf);
if(result == NULL) result = strdup("");
return result;
}
/* Given a mode= argument, fill in the impl */ /* Given a mode= argument, fill in the impl */
static int static int
processmodearg(const char* arg, NCmodel* model) processmodearg(const char* arg, NCmodel* model)
@ -504,9 +493,10 @@ processinferences(NClist* fraglenv)
{ {
int stat = NC_NOERR; int stat = NC_NOERR;
const char* modeval = NULL; const char* modeval = NULL;
NClist* modes = NULL;
NClist* newmodes = nclistnew(); NClist* newmodes = nclistnew();
int i,inferred = 0; NClist* currentmodes = NULL;
NClist* nextmodes = nclistnew();
int i;
char* newmodeval = NULL; char* newmodeval = NULL;
if(fraglenv == NULL || nclistlength(fraglenv) == 0) goto done; if(fraglenv == NULL || nclistlength(fraglenv) == 0) goto done;
@ -515,22 +505,53 @@ processinferences(NClist* fraglenv)
if((modeval = getmodekey(fraglenv))==NULL) goto done; if((modeval = getmodekey(fraglenv))==NULL) goto done;
/* Get the mode as list */ /* Get the mode as list */
modes = parsemode(modeval); currentmodes = parsemode(modeval);
/* Repeatedly walk the mode list until no more new positive inferences */ #ifdef DEBUG
do { printlist(currentmodes,"processinferences: initial mode list");
for(i=0;i<nclistlength(modes);i++) { #endif
const char* mode = nclistget(modes,i);
inferred = inferone(mode,newmodes); /* Do what amounts to breadth first inferencing down the inference DAG. */
nclistpush(newmodes,strdup(mode)); /* keep key */
if(!inferred) nclistpush(newmodes,strdup(mode)); for(;;) {
NClist* tmp = NULL;
/* Compute the next set of inferred modes */
#ifdef DEBUG
printlist(currentmodes,"processinferences: current mode list");
#endif
infernext(currentmodes,nextmodes);
#ifdef DEBUG
printlist(nextmodes,"processinferences: next mode list");
#endif
/* move current modes into list of newmodes */
for(i=0;i<nclistlength(currentmodes);i++) {
nclistpush(newmodes,nclistget(currentmodes,i));
} }
} while(inferred); nclistsetlength(currentmodes,0); /* clear current mode list */
if(nclistlength(nextmodes) == 0) break; /* nothing more to do */
#ifdef DEBUG
printlist(newmodes,"processinferences: new mode list");
#endif
/* Swap current and next */
tmp = currentmodes;
currentmodes = nextmodes;
nextmodes = tmp;
tmp = NULL;
}
/* cleanup any unused elements in currenmodes */
nclistclearall(currentmodes);
/* Ensure no duplicates */
cleanstringlist(newmodes,1);
#ifdef DEBUG
printlist(newmodes,"processinferences: final inferred mode list");
#endif
/* Remove negative inferences */ /* Remove negative inferences */
for(i=0;i<nclistlength(modes);i++) { for(i=0;i<nclistlength(newmodes);i++) {
const char* mode = nclistget(modes,i); const char* mode = nclistget(newmodes,i);
inferred = negateone(mode,newmodes); negateone(mode,newmodes);
} }
/* Store new mode value */ /* Store new mode value */
@ -541,11 +562,13 @@ processinferences(NClist* fraglenv)
done: done:
nullfree(newmodeval); nullfree(newmodeval);
nclistfreeall(modes);
nclistfreeall(newmodes); nclistfreeall(newmodes);
nclistfreeall(currentmodes);
nclistfreeall(nextmodes);
return check(stat); return check(stat);
} }
static int static int
negateone(const char* mode, NClist* newmodes) negateone(const char* mode, NClist* newmodes)
{ {
@ -568,23 +591,28 @@ negateone(const char* mode, NClist* newmodes)
return changed; return changed;
} }
static int static void
inferone(const char* mode, NClist* newmodes) infernext(NClist* current, NClist* next)
{ {
const struct MODEINFER* tests = modeinferences; int i;
int changed = 0; for(i=0;i<nclistlength(current);i++) {
for(;tests->key;tests++) { const struct MODEINFER* tests = NULL;
if(strcasecmp(tests->key,mode)==0) { const char* cur = nclistget(current,i);
/* Append the inferred mode; dups removed later */ for(tests=modeinferences;tests->key;tests++) {
nclistpush(newmodes,strdup(tests->inference)); if(strcasecmp(tests->key,cur)==0) {
changed = 1; /* Append the inferred mode unless dup */
if(!nclistmatch(next,tests->inference,1))
nclistpush(next,strdup(tests->inference));
}
} }
} }
return changed;
} }
/*
Given a list of strings, remove nulls and duplicates
*/
static int static int
mergekey(NClist** valuesp) mergelist(NClist** valuesp)
{ {
int i,j; int i,j;
int stat = NC_NOERR; int stat = NC_NOERR;
@ -686,12 +714,12 @@ cleanfragments(NClist** fraglenvp)
/* collect all unique keys */ /* collect all unique keys */
collectallkeys(fraglenv,allkeys); collectallkeys(fraglenv,allkeys);
/* Collect all values for same key across all fragments */ /* Collect all values for same key across all fragment pairs */
for(i=0;i<nclistlength(allkeys);i++) { for(i=0;i<nclistlength(allkeys);i++) {
key = nclistget(allkeys,i); key = nclistget(allkeys,i);
collectvaluesbykey(fraglenv,key,tmp); collectvaluesbykey(fraglenv,key,tmp);
/* merge the key values, remove duplicate */ /* merge the key values, remove duplicate */
if((stat=mergekey(&tmp))) goto done; if((stat=mergelist(&tmp))) goto done;
/* Construct key,value pair and insert into newlist */ /* Construct key,value pair and insert into newlist */
key = strdup(key); key = strdup(key);
nclistpush(newlist,key); nclistpush(newlist,key);
@ -923,7 +951,7 @@ NC_infermodel(const char* path, int* omodep, int iscreate, int useparallel, void
} }
} else {/* Not URL */ } else {/* Not URL */
if(*newpathp) *newpathp = NULL; if(newpathp) *newpathp = NULL;
} }
/* Phase 8: mode inference from mode flags */ /* Phase 8: mode inference from mode flags */
@ -1101,6 +1129,71 @@ parsemode(const char* modeval)
return modes; return modes;
} }
/* Convert a list into a comma'd string */
static char*
list2string(NClist* list)
{
int i;
NCbytes* buf = NULL;
char* result = NULL;
if(list == NULL || nclistlength(list)==0) return strdup("");
buf = ncbytesnew();
for(i=0;i<nclistlength(list);i++) {
const char* m = nclistget(list,i);
if(m == NULL || strlen(m) == 0) continue;
if(i > 0) ncbytescat(buf,",");
ncbytescat(buf,m);
}
result = ncbytesextract(buf);
ncbytesfree(buf);
if(result == NULL) result = strdup("");
return result;
}
#if 0
/* Given a comma separated string, remove duplicates; mostly used to cleanup mode list */
static char*
cleancommalist(const char* commalist, int caseinsensitive)
{
NClist* tmp = nclistnew();
char* newlist = NULL;
if(commalist == NULL || strlen(commalist)==0) return nulldup(commalist);
(void)parseonchar(commalist,',',tmp);/* split on commas */
cleanstringlist(tmp,caseinsensitive);
newlist = list2string(tmp);
nclistfreeall(tmp);
return newlist;
}
#endif
/* Given a list of strings, remove nulls and duplicated */
static void
cleanstringlist(NClist* strs, int caseinsensitive)
{
int i,j;
if(nclistlength(strs) == 0) return;
/* Remove nulls */
for(i=nclistlength(strs)-1;i>=0;i--) {
if(nclistget(strs,i)==NULL) nclistremove(strs,i);
}
/* Remove duplicates*/
for(i=0;i<nclistlength(strs);i++) {
const char* value = nclistget(strs,i);
/* look ahead for duplicates */
for(j=nclistlength(strs)-1;j>i;j--) {
int match;
const char* candidate = nclistget(strs,j);
if(caseinsensitive)
match = (strcasecmp(value,candidate) == 0);
else
match = (strcmp(value,candidate) == 0);
if(match) {char* dup = nclistremove(strs,j); nullfree(dup);}
}
}
}
/**************************************************/ /**************************************************/
/** /**
* @internal Given an existing file, figure out its format and return * @internal Given an existing file, figure out its format and return
@ -1502,8 +1595,10 @@ printlist(NClist* list, const char* tag)
{ {
int i; int i;
fprintf(stderr,"%s:",tag); fprintf(stderr,"%s:",tag);
for(i=0;i<nclistlength(list);i++) for(i=0;i<nclistlength(list);i++) {
fprintf(stderr," %s",(char*)nclistget(list,i)); fprintf(stderr," %s",(char*)nclistget(list,i));
fprintf(stderr,"[%p]",(char*)nclistget(list,i));
}
fprintf(stderr,"\n"); fprintf(stderr,"\n");
dbgflush(); dbgflush();
} }

View File

@ -122,9 +122,7 @@ ncbytesappend(NCbytes* bb, char elem)
int int
ncbytescat(NCbytes* bb, const char* s) ncbytescat(NCbytes* bb, const char* s)
{ {
if(s == NULL) { if(s == NULL) return 1;
return 1;
}
ncbytesappendn(bb,(void*)s,strlen(s)+1); /* include trailing null*/ ncbytesappendn(bb,(void*)s,strlen(s)+1); /* include trailing null*/
/* back up over the trailing null*/ /* back up over the trailing null*/
if(bb->length == 0) return ncbytesfail(); if(bb->length == 0) return ncbytesfail();

View File

@ -183,6 +183,7 @@ nclistremove(NClist* l, size_t i)
return elem; return elem;
} }
/* Match on == */
int int
nclistcontains(NClist* l, void* elem) nclistcontains(NClist* l, void* elem)
{ {
@ -193,7 +194,7 @@ nclistcontains(NClist* l, void* elem)
return 0; return 0;
} }
/* Return 1/0 */ /* Match on str(case)cmp */
int int
nclistmatch(NClist* l, const char* elem, int casesensitive) nclistmatch(NClist* l, const char* elem, int casesensitive)
{ {
@ -230,7 +231,6 @@ nclistelemremove(NClist* l, void* elem)
return found; return found;
} }
/* Extends nclist to include a unique operator /* Extends nclist to include a unique operator
which remove duplicate values; NULL values removed which remove duplicate values; NULL values removed
return value is always 1. return value is always 1.

View File

@ -1429,6 +1429,7 @@ define_vars(NC_FILE_INFO_T* file, NC_GRP_INFO_T* grp, NClist* varnames)
char* varpath = NULL; char* varpath = NULL;
char* key = NULL; char* key = NULL;
NCZ_FILE_INFO_T* zinfo = NULL; NCZ_FILE_INFO_T* zinfo = NULL;
NC_VAR_INFO_T* var = NULL;
NCZ_VAR_INFO_T* zvar = NULL; NCZ_VAR_INFO_T* zvar = NULL;
NCZMAP* map = NULL; NCZMAP* map = NULL;
NCjson* jvar = NULL; NCjson* jvar = NULL;
@ -1460,7 +1461,6 @@ define_vars(NC_FILE_INFO_T* file, NC_GRP_INFO_T* grp, NClist* varnames)
/* Load each var in turn */ /* Load each var in turn */
for(i = 0; i < nclistlength(varnames); i++) { for(i = 0; i < nclistlength(varnames); i++) {
NC_VAR_INFO_T* var;
const char* varname = nclistget(varnames,i); const char* varname = nclistget(varnames,i);
if((stat = nc4_var_list_add2(grp, varname, &var))) if((stat = nc4_var_list_add2(grp, varname, &var)))
goto done; goto done;
@ -1477,10 +1477,6 @@ define_vars(NC_FILE_INFO_T* file, NC_GRP_INFO_T* grp, NClist* varnames)
/* Indicate we do not have quantizer yet */ /* Indicate we do not have quantizer yet */
var->quantize_mode = -1; var->quantize_mode = -1;
/* Set filter list */
assert(var->filters == NULL);
var->filters = (void*)nclistnew();
/* Construct var path */ /* Construct var path */
if((stat = NCZ_varkey(var,&varpath))) if((stat = NCZ_varkey(var,&varpath)))
goto done; goto done;
@ -1697,9 +1693,9 @@ define_vars(NC_FILE_INFO_T* file, NC_GRP_INFO_T* grp, NClist* varnames)
object MUST contain a "id" key identifying the codec to be used. */ object MUST contain a "id" key identifying the codec to be used. */
/* Do filters key before compressor key so final filter chain is in correct order */ /* Do filters key before compressor key so final filter chain is in correct order */
{ {
#ifdef ENABLE_NCZARR_FILTERS
if(var->filters == NULL) var->filters = (void*)nclistnew(); if(var->filters == NULL) var->filters = (void*)nclistnew();
if(zvar->incompletefilters == NULL) zvar->incompletefilters = (void*)nclistnew(); if(zvar->incompletefilters == NULL) zvar->incompletefilters = (void*)nclistnew();
#ifdef ENABLE_NCZARR_FILTERS
{ int k; { int k;
chainindex = 0; /* track location of filter in the chain */ chainindex = 0; /* track location of filter in the chain */
if((stat = NCZ_filter_initialize())) goto done; if((stat = NCZ_filter_initialize())) goto done;
@ -1722,8 +1718,8 @@ define_vars(NC_FILE_INFO_T* file, NC_GRP_INFO_T* grp, NClist* varnames)
/* From V2 Spec: A JSON object identifying the primary compression codec and providing /* From V2 Spec: A JSON object identifying the primary compression codec and providing
configuration parameters, or ``null`` if no compressor is to be used. */ configuration parameters, or ``null`` if no compressor is to be used. */
{ {
if(var->filters == NULL) var->filters = (void*)nclistnew();
#ifdef ENABLE_NCZARR_FILTERS #ifdef ENABLE_NCZARR_FILTERS
if(var->filters == NULL) var->filters = (void*)nclistnew();
if((stat = NCZ_filter_initialize())) goto done; if((stat = NCZ_filter_initialize())) goto done;
if((stat = NCJdictget(jvar,"compressor",&jfilter))) goto done; if((stat = NCJdictget(jvar,"compressor",&jfilter))) goto done;
if(jfilter != NULL && NCJsort(jfilter) != NCJ_NULL) { if(jfilter != NULL && NCJsort(jfilter) != NCJ_NULL) {
@ -1752,6 +1748,7 @@ define_vars(NC_FILE_INFO_T* file, NC_GRP_INFO_T* grp, NClist* varnames)
nullfree(shapes); shapes = NULL; nullfree(shapes); shapes = NULL;
if(formatv1) {NCJreclaim(jncvar); jncvar = NULL;} if(formatv1) {NCJreclaim(jncvar); jncvar = NULL;}
NCJreclaim(jvar); jvar = NULL; NCJreclaim(jvar); jvar = NULL;
var = NULL;
} }
done: done:

View File

@ -391,9 +391,11 @@ NCZ_def_var(int ncid, const char *name, nc_type xtype, int ndims,
var->meta_read = NC_TRUE; var->meta_read = NC_TRUE;
var->atts_read = NC_TRUE; var->atts_read = NC_TRUE;
#ifdef ENABLE_NCZARR_FILTERS
/* Set the filter list */ /* Set the filter list */
assert(var->filters == NULL); assert(var->filters == NULL);
var->filters = (void*)nclistnew(); var->filters = (void*)nclistnew();
#endif
/* Point to the type, and increment its ref. count */ /* Point to the type, and increment its ref. count */
var->type_info = type; var->type_info = type;
@ -558,10 +560,12 @@ ncz_def_var_extra(int ncid, int varid, int *shuffle, int *unused1,
/* Can't turn on parallel and deflate/fletcher32/szip/shuffle /* Can't turn on parallel and deflate/fletcher32/szip/shuffle
* before HDF5 1.10.3. */ * before HDF5 1.10.3. */
#ifdef ENABLE_NCZARR_FILTERS
#ifndef HDF5_SUPPORTS_PAR_FILTERS #ifndef HDF5_SUPPORTS_PAR_FILTERS
if (h5->parallel == NC_TRUE) if (h5->parallel == NC_TRUE)
if (nclistlength(((NClist*)var->filters)) > 0 || fletcher32 || shuffle) if (nclistlength(((NClist*)var->filters)) > 0 || fletcher32 || shuffle)
{retval = NC_EINVAL; goto done;} {retval = NC_EINVAL; goto done;}
#endif
#endif #endif
/* If the HDF5 dataset has already been created, then it is too /* If the HDF5 dataset has already been created, then it is too
@ -628,8 +632,10 @@ ncz_def_var_extra(int ncid, int varid, int *shuffle, int *unused1,
* no filters in use for this data. */ * no filters in use for this data. */
if (storage != NC_CHUNKED) if (storage != NC_CHUNKED)
{ {
#ifdef NCZARR_FILTERS
if (nclistlength(((NClist*)var->filters)) > 0) if (nclistlength(((NClist*)var->filters)) > 0)
{retval = NC_EINVAL; goto done;} {retval = NC_EINVAL; goto done;}
#endif
for (d = 0; d < var->ndims; d++) for (d = 0; d < var->ndims; d++)
if (var->dim[d]->unlimited) if (var->dim[d]->unlimited)
{retval = NC_EINVAL; goto done;} {retval = NC_EINVAL; goto done;}