Charlie Zender noted that we forgot to define what happens for
various netcdf API attribute operations, notably nc_inq_att()
and nc_get_att().
So, I added a list of legal and illegal api calls for the provenance
attributes in docs/attribute_conventions.md.
I also added more test cases to ncdump/tst_fileinfo.c to verify
and fixed resultant errors.
This commit is contained in:
Dennis Heimbigner 2016-05-15 18:03:04 -06:00
parent f8117f150f
commit 4fa1470241
4 changed files with 98 additions and 23 deletions

View File

@ -131,17 +131,34 @@ It is strongly recommended that applicable conventions be followed unless there
These attributes can occur in netCDF enhanced (netcdf-4) files beginning
with version 4.4.1. They all are associated with the root group as
global attributes. They are hidden in the sense that they can only be
accessed thru the netcdf-C api calls via the name. They have no
attribute number and will not be counted in the number of global
attributes in the root group. The simplest way to view these attributes
is to use the -s flag to the ncdump command.
global attributes. They are hidden in the sense that they have no
attribute number, so they can only be accessed thru the netcdf-C api
calls via the name. Additionally, these attributes will not be counted
in the number of global attributes in the root group.
The simplest way to view these attributes is to use the -s flag to the
ncdump command. Alternatively, one can use the following API calls to
obtain information.
- nc_inq_att
- nc_inq_atttype
- nc_inq_attlen
- nc_get_att (and derivatives)
Using the following API calls will fail.
- nc_inq_attid
- nc_inq_attname
- nc_copy_att
- nc_rename_att
- nc_del_att
- nc_put_att (and derivatives)
`_NCProperties`
> This attribute is persistent in the file, but hidden. It is inserted in the file at creation time and is never modified after that point. It specifies the following.
> - The version for the netcdf library used at creation time.
> - The version for the HDF5 library used at creation time.
> - The type of this attribute is NC_CHAR.
> Its format is: `name=value|name=value ...`<br>
> Occurrences of '|' in the name or value are disallowed.
@ -155,6 +172,7 @@ is to use the -s flag to the ncdump command.
> This attribute is ephemeral in that it is computed by looking at the file's HDF5 superblock.
> It has this form: `_SuperBlockVersion = 0|1|2|3|...`
> The type of this attribute is NC_INT.
`_IsNetcdf4`
@ -162,6 +180,7 @@ is to use the -s flag to the ncdump command.
> The _IsNetcdf4 attribute has the form: `_IsNetcdf4 = 0|1`
> where 1 means the file has various tags indicating it was produced thru the netcdf-4 API.
> The type of this attribute is NC_INT.
> This attribute is computed by using the HDF5 API to walk the file to look for attributes specific to netcdf-4. False negatives are possible for a small subset of netcdf-4 files, especially those not containing dimensions. False positives are only possible by deliberate modifications to an existing HDF5 file thru the HDF5 API. For files with the _NCProperties attribute, this attribute is redundant. For files created prior to the introduction of the _NCProperties attribute, this may be a useful indicator of the provenance of the file.

View File

@ -22,7 +22,8 @@ conditions.
#endif
#ifdef ENABLE_FILEINFO
static int nc4_get_att_special(NC_HDF5_FILE_INFO_T*, const char*, nc_type, int, void*, size_t*, int*);
static int nc4_get_att_special(NC_HDF5_FILE_INFO_T*, const char*,
nc_type*, nc_type, size_t*, int*, int, void*);
#endif
int nc4typelen(nc_type type);
@ -70,7 +71,7 @@ nc4_get_att(int ncid, NC *nc, int varid, const char *name,
const char** sp;
for(sp = NC_RESERVED_SPECIAL_LIST;*sp;sp++) {
if(strcmp(name,*sp)==0) {
return nc4_get_att_special(h5, norm_name, mem_type, is_long, data, lenp, attnum);
return nc4_get_att_special(h5, norm_name, xtype, mem_type, lenp, attnum, is_long, data);
}
}
}
@ -546,8 +547,8 @@ nc4_put_att(int ncid, NC *nc, int varid, const char *name,
return NC_NOERR;
}
/* Learn about an att. All the nc4 nc_inq_ functions just call
* add_meta_get to get the metadata on an attribute. */
/* Learn about an att. All the nc4 nc_inq_ functions just call
* nc4_get_att to get the metadata on an attribute. */
int
NC4_inq_att(int ncid, int varid, const char *name, nc_type *xtypep, size_t *lenp)
{
@ -578,7 +579,7 @@ NC4_inq_att(int ncid, int varid, const char *name, nc_type *xtypep, size_t *lenp
#endif /* USE_PNETCDF */
/* Handle netcdf-4 files. */
return nc4_get_att(ncid, nc, varid, name, xtypep, NC_UBYTE, lenp, NULL, 0, NULL);
return nc4_get_att(ncid, nc, varid, name, xtypep, NC_NAT, lenp, NULL, 0, NULL);
}
/* Learn an attnum, given a name. */
@ -587,6 +588,7 @@ NC4_inq_attid(int ncid, int varid, const char *name, int *attnump)
{
NC *nc;
NC_HDF5_FILE_INFO_T *h5;
int stat;
LOG((2, "nc_inq_attid: ncid 0x%x varid %d name %s", ncid, varid, name));
@ -605,8 +607,9 @@ NC4_inq_attid(int ncid, int varid, const char *name, int *attnump)
#endif /* USE_PNETCDF */
/* Handle netcdf-4 files. */
return nc4_get_att(ncid, nc, varid, name, NULL, NC_UBYTE,
stat = nc4_get_att(ncid, nc, varid, name, NULL, NC_NAT,
NULL, attnump, 0, NULL);
return stat;
}
@ -950,24 +953,33 @@ nc4_put_att_tc(int ncid, int varid, const char *name, nc_type file_type,
#ifdef ENABLE_FILEINFO
static int
nc4_get_att_special(NC_HDF5_FILE_INFO_T *h5, const char* name, nc_type mem_type, int islong, void* data, size_t* lenp, int* idp)
nc4_get_att_special(NC_HDF5_FILE_INFO_T* h5, const char* name,
nc_type* filetypep, nc_type mem_type, size_t* lenp,
int* attnump, int is_long, void* data)
{
/* Always make the attr id be -1 */
if(idp) *idp = -1;
/* Fail if asking for att id */
if(attnump)
return NC_EATTMETA;
if(strcmp(name,NCPROPS)==0) {
if(h5->fileinfo->propattr.version == 0)
return NC_ENOTATT;
if(mem_type == NC_NAT) mem_type = NC_CHAR;
if(mem_type != NC_CHAR)
return NC_ECHAR;
if(filetypep) *filetypep = NC_CHAR;
if(lenp) *lenp = strlen(h5->fileinfo->propattr.text);
if(data) strcpy((char*)data,h5->fileinfo->propattr.text);
} else if(strcmp(name,ISNETCDF4ATT)==0
|| strcmp(name,SUPERBLOCKATT)==0) {
unsigned long long iv = 0;
if(filetypep) *filetypep = NC_INT;
if(lenp) *lenp = 1;
if(strcmp(name,SUPERBLOCKATT)==0)
iv = (unsigned long long)h5->fileinfo->superblockversion;
else /* strcmp(name,ISNETCDF4ATT)==0 */
iv = NC4_isnetcdf4(h5);
if(lenp) *lenp = 1;
if(mem_type == NC_NAT) mem_type = NC_INT;
if(data)
switch (mem_type) {
case NC_BYTE: *((char*)data) = (char)iv; break;

View File

@ -71,14 +71,16 @@ main(int argc, char **argv)
}
{
int root, grpid, varid, stat, natts;
int root, grpid, varid, stat, natts, id;
int data = 17;
const char* sdata = "text";
char ncprops[8192];
size_t len;
int dimid;
nc_type xtype;
char name[NC_MAX_NAME];
printf("*** creating netcdf-4 test file using netCDF %s...", NC4FILE);
printf("\n*** creating netcdf-4 test file using netCDF %s...", NC4FILE);
if(nc_create(NC4FILE,NC_WRITE|NC_CLOBBER|NC_NETCDF4,&root)!=0) ERR;
/* Create global attribute */
@ -107,9 +109,24 @@ main(int argc, char **argv)
/* Now, fiddle with the NCPROPS attribute */
/* Get its value */
if(nc_inq_att(root,NC_GLOBAL,NCPROPS,NULL,&len)!=0) ERR;
/* Get its metadata */
if(nc_inq_att(root,NC_GLOBAL,NCPROPS,&xtype,&len)!=0) ERR;
if(xtype != NC_CHAR) ERR;
/* Read in two ways */
if(nc_get_att_text(root,NC_GLOBAL,NCPROPS,ncprops)!=0) ERR;
if(strlen(ncprops) != len) ERR;
/* Attempt to get attribute metadata piecemeal; some will fail */
id = -1;
stat = nc_inq_attid(root,NC_GLOBAL,NCPROPS,&id);
if(stat == NC_NOERR) ERR;
stat = nc_inq_attname(root,NC_GLOBAL,id,name);
if(stat == NC_NOERR) ERR;
if(nc_inq_atttype(root,NC_GLOBAL,NCPROPS,&xtype)!=0) ERR;
if(xtype != NC_CHAR) ERR;
if(nc_inq_attlen(root,NC_GLOBAL,NCPROPS,&len)!=0) ERR;
if(len != strlen(ncprops)) ERR;
/*Overwrite _NCProperties root attribute; should fail */
stat = nc_put_att_text(root,NC_GLOBAL,NCPROPS,strlen(sdata),sdata);
@ -121,11 +138,23 @@ main(int argc, char **argv)
/* Ditto _SuperblockVersion */
/* Get its value */
if(nc_inq_att(root,NC_GLOBAL,SUPERBLOCKATT,NULL,&len)!=0) ERR;
/* Get its metadata */
if(nc_inq_att(root,NC_GLOBAL,SUPERBLOCKATT,&xtype,&len)!=0) ERR;
if(xtype != NC_INT) ERR;
if(len != 1) ERR;
if(nc_get_att_int(root,NC_GLOBAL,SUPERBLOCKATT,&data)!=0) ERR;
/* Attempt to get attribute metadata piecemeal */
stat = nc_inq_attid(root,NC_GLOBAL,SUPERBLOCKATT,&id);
if(stat == NC_NOERR) ERR;
stat = nc_inq_attname(root,NC_GLOBAL,id,name);
if(stat == NC_NOERR) ERR;
if(nc_inq_atttype(root,NC_GLOBAL,SUPERBLOCKATT,&xtype)!=0) ERR;
if(xtype != NC_INT) ERR;
if(nc_inq_attlen(root,NC_GLOBAL,SUPERBLOCKATT,&len)!=0) ERR;
if(len != 1) ERR;
/*Overwrite; should fail */
stat = nc_put_att_int(root,NC_GLOBAL,NCPROPS,NC_INT,1,&data);
if(stat == NC_NOERR) ERR;
@ -136,11 +165,23 @@ main(int argc, char **argv)
/* Ditto _IsNetcdf4 */
/* Get its value */
if(nc_inq_att(root,NC_GLOBAL,ISNETCDF4ATT,NULL,&len)!=0) ERR;
/* Get its metadata */
if(nc_inq_att(root,NC_GLOBAL,ISNETCDF4ATT,&xtype,&len)!=0) ERR;
if(xtype != NC_INT) ERR;
if(len != 1) ERR;
if(nc_get_att_int(root,NC_GLOBAL,ISNETCDF4ATT,&data)!=0) ERR;
/* Attempt to get attribute metadata piecemeal */
stat = nc_inq_attid(root,NC_GLOBAL,ISNETCDF4ATT,&id);
if(stat == NC_NOERR) ERR;
stat = nc_inq_attname(root,NC_GLOBAL,id,name);
if(stat == NC_NOERR) ERR;
if(nc_inq_atttype(root,NC_GLOBAL,ISNETCDF4ATT,&xtype)!=0) ERR;
if(xtype != NC_INT) ERR;
if(nc_inq_attlen(root,NC_GLOBAL,ISNETCDF4ATT,&len)!=0) ERR;
if(len != 1) ERR;
/*Overwrite; should fail */
stat = nc_put_att_int(root,NC_GLOBAL,ISNETCDF4ATT,NC_INT,1,&data);
if(stat == NC_NOERR) ERR;

View File

@ -698,6 +698,9 @@ test_ncattcopy(path1, path2)
error("%s: ncendef failed", pname);
ncclose(cdfid); return ++nerrs;
}
if(strcmp(path1, "nctest_netcdf4.nc")==0) {
int x=0;
}
/* first (source) netcdf is in data mode */
/* create second netCDF to copy attributes to */
if ((cdfid2 = nccreate(path2, NC_CLOBBER)) == -1) {