Classic Format Specification says: Header padding uses null (\x00) bytes

This commit is contained in:
Wei-keng Liao 2016-11-28 11:54:16 -06:00
parent 3889617a2a
commit 340f0d2a91
7 changed files with 188 additions and 48 deletions

View File

@ -301,11 +301,11 @@ static int
v1h_get_NC_string(v1hs *gsp, NC_string **ncstrpp)
{
int status;
size_t nchars = 0;
size_t padding, nchars = 0;
NC_string *ncstrp;
status = v1h_get_size_t(gsp, &nchars);
if(status != NC_NOERR)
if(status != NC_NOERR)
return status;
ncstrp = new_NC_string(nchars, NULL);
@ -314,7 +314,6 @@ v1h_get_NC_string(v1hs *gsp, NC_string **ncstrpp)
return NC_ENOMEM;
}
#if 0
/* assert(ncstrp->nchars == nchars || ncstrp->nchars - nchars < X_ALIGN); */
assert(ncstrp->nchars % X_ALIGN == 0);
@ -323,22 +322,33 @@ v1h_get_NC_string(v1hs *gsp, NC_string **ncstrpp)
status = check_v1hs(gsp, _RNDUP(ncstrp->nchars, X_ALIGN));
#endif
if(status != NC_NOERR)
if(status != NC_NOERR)
goto unwind_alloc;
status = ncx_pad_getn_text((const void **)(&gsp->pos),
nchars, ncstrp->cp);
if(status != NC_NOERR)
if(status != NC_NOERR)
goto unwind_alloc;
padding = _RNDUP(X_SIZEOF_CHAR * ncstrp->nchars, X_ALIGN)
- X_SIZEOF_CHAR * ncstrp->nchars;
if (padding > 0) {
/* CDF specification: Header padding uses null (\x00) bytes. */
char pad[X_ALIGN-1];
memset(pad, 0, X_ALIGN-1);
if (memcmp((char*)gsp->pos-padding, pad, padding) != 0) {
free_NC_string(ncstrp);
return NC_EINVAL;
}
}
*ncstrpp = ncstrp;
return NC_NOERR;
return NC_NOERR;
unwind_alloc:
free_NC_string(ncstrp);
return status;
}
/* End NC_string */
@ -575,6 +585,28 @@ ncx_len_NC_attr(const NC_attr *attrp, int version)
#undef MIN
#define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn))
/*----< ncmpix_len_nctype() >------------------------------------------------*/
/* return the length of external data type */
static int
ncmpix_len_nctype(nc_type type) {
switch(type) {
case NC_BYTE:
case NC_CHAR:
case NC_UBYTE: return X_SIZEOF_CHAR;
case NC_SHORT: return X_SIZEOF_SHORT;
case NC_USHORT: return X_SIZEOF_USHORT;
case NC_INT: return X_SIZEOF_INT;
case NC_UINT: return X_SIZEOF_UINT;
case NC_FLOAT: return X_SIZEOF_FLOAT;
case NC_DOUBLE: return X_SIZEOF_DOUBLE;
case NC_INT64: return X_SIZEOF_INT64;
case NC_UINT64: return X_SIZEOF_UINT64;
default: fprintf(stderr,"ncmpix_len_nctype bad type %d\n",type);
assert(0);
}
return 0;
}
/*
* Put the values of an attribute
* The loop is necessary since attrp->nelems
@ -587,7 +619,7 @@ v1h_put_NC_attrV(v1hs *psp, const NC_attr *attrp)
const size_t perchunk = psp->extent;
size_t remaining = attrp->xsz;
void *value = attrp->xvalue;
size_t nbytes;
size_t nbytes, padding;
assert(psp->extent % X_ALIGN == 0);
@ -595,18 +627,24 @@ v1h_put_NC_attrV(v1hs *psp, const NC_attr *attrp)
nbytes = MIN(perchunk, remaining);
status = check_v1hs(psp, nbytes);
if(status != NC_NOERR)
if(status != NC_NOERR)
return status;
(void) memcpy(psp->pos, value, nbytes);
psp->pos = (void *)((signed char *)psp->pos + nbytes);
value = (void *)((signed char *)value + nbytes);
remaining -= nbytes;
remaining -= nbytes;
} while(remaining != 0);
return NC_NOERR;
padding = attrp->xsz - ncmpix_len_nctype(attrp->type) * attrp->nelems;
if (padding > 0) {
/* CDF specification: Header padding uses null (\x00) bytes. */
memset((char*)psp->pos-padding, 0, padding);
}
return NC_NOERR;
}
/* Write a NC_attr to the header */
@ -647,24 +685,33 @@ v1h_get_NC_attrV(v1hs *gsp, NC_attr *attrp)
const size_t perchunk = gsp->extent;
size_t remaining = attrp->xsz;
void *value = attrp->xvalue;
size_t nget;
size_t nget, padding;
do {
nget = MIN(perchunk, remaining);
status = check_v1hs(gsp, nget);
if(status != NC_NOERR)
if(status != NC_NOERR)
return status;
(void) memcpy(value, gsp->pos, nget);
gsp->pos = (void *)((signed char *)gsp->pos + nget);
value = (void *)((signed char *)value + nget);
remaining -= nget;
remaining -= nget;
} while(remaining != 0);
return NC_NOERR;
padding = attrp->xsz - ncmpix_len_nctype(attrp->type) * attrp->nelems;
if (padding > 0) {
/* CDF specification: Header padding uses null (\x00) bytes. */
char pad[X_ALIGN-1];
memset(pad, 0, X_ALIGN-1);
if (memcmp((char*)gsp->pos-padding, pad, (size_t)padding) != 0)
return NC_EINVAL;
}
return NC_NOERR;
}

View File

@ -156,7 +156,7 @@ main(int argc, char *argv[])
/* Initialize global variables defining test file */
init_gvars();
/* Write the test file, needed for the read-only tests below. */
/* Write the test file, needed for the read-only tests below. */
write_file(testfile);
/* delete any existing scratch netCDF file */
@ -355,6 +355,8 @@ main(int argc, char *argv[])
NC_TEST(nc_copy_att);
NC_TEST(nc_rename_att);
NC_TEST(nc_del_att);
NC_TEST(nc_against_pnetcdf);
/* keep below the last test, as it changes the default file format */
NC_TEST(nc_set_default_format);
}

View File

@ -10,7 +10,7 @@ dnl
* Copyright (C) 2003, Northwestern University and Argonne National Laboratory
* See COPYRIGHT notice in top-level directory.
*/
/* $Id: test_put.m4 2630 2016-11-17 06:35:10Z wkliao $ */
/* $Id: test_put.m4 2655 2016-11-25 21:03:48Z wkliao $ */
dnl
dnl The command-line m4 macro "PNETCDF" is to differentiate PnetCDF and netCDF
@ -112,11 +112,11 @@ define(`HASH',dnl
* ensure hash value within range for internal TYPE
*/
$1
hash_$1(const int cdf_format,
const nc_type type,
const int rank,
const IntType *index,
const nct_itype itype)
hash_$1(const int cdf_format,
const nc_type type,
const int rank,
const IntType *index,
const nct_itype itype)
{
double value;

View File

@ -10,7 +10,7 @@ dnl
* Copyright (C) 2003, Northwestern University and Argonne National Laboratory
* See COPYRIGHT notice in top-level directory.
*/
/* $Id: test_read.m4 2616 2016-11-14 09:19:14Z wkliao $ */
/* $Id: test_read.m4 2640 2016-11-18 21:08:08Z wkliao $ */
dnl
dnl The command-line m4 macro "PNETCDF" is to differentiate PnetCDF and netCDF
@ -20,9 +20,11 @@ dnl types.
dnl
#include <sys/types.h> /* open() */
#include <sys/stat.h> /* open() */
#include <fcntl.h> /* open() */
#include <unistd.h> /* unlink(), write() */
#include <sys/stat.h> /* open() */
#include <fcntl.h> /* open() */
#include <unistd.h> /* unlink(), write() */
#include <errno.h> /* errno, strerror() */
#include "tests.h"
define(`EXPECT_ERR',`error("expecting $1 but got %s",nc_err_code_name($2));')dnl
@ -168,9 +170,14 @@ ifdef(`PNETCDF',
ifdef(`PNETCDF', ``#'if 1', ``#'if 0')
/* create a not-nc file */
fd = open(NOT_NC_FILE, O_CREAT|O_WRONLY, 0600);
w_len = write(fd, "0123456789abcdefghijklmnopqrstuvwxyz", 36);
assert(w_len >= 0);
close(fd);
IF (fd == -1) {
error("Error: creating a non-CDF file (%s)", strerror(errno));
}
else {
w_len = write(fd, "0123456789abcdefghijklmnopqrstuvwxyz", 36);
assert(w_len >= 0);
close(fd);
}
/* Open a file that is not a netCDF file. */
err = FileOpen(NOT_NC_FILE, NC_NOWRITE, &ncid); /* should fail */

View File

@ -10,7 +10,7 @@ dnl
* Copyright (C) 2003, Northwestern University and Argonne National Laboratory
* See COPYRIGHT notice in top-level directory.
*/
/* $Id: test_write.m4 2633 2016-11-17 22:06:42Z wkliao $ */
/* $Id: test_write.m4 2655 2016-11-25 21:03:48Z wkliao $ */
dnl
dnl The command-line m4 macro "PNETCDF" is to differentiate PnetCDF and netCDF
@ -179,14 +179,16 @@ TestFunc(redef)(AttVarArgs)
error("close: %s", APIFunc(strerror)(err));
/* tests using scratch file */
err = FileCreate(scratch, NC_NOCLOBBER, &ncid);
ifdef(`PNETCDF',`dnl
err = FileCreate(scratch, NC_NOCLOBBER, &ncid);',`dnl
err = file__create(scratch, NC_NOCLOBBER, 0, &sizehint, &ncid);')
IF (err != NC_NOERR) {
error("create: %s", APIFunc(strerror)(err));
return nok;
}
ifdef(`PNETCDF',,`dnl
/* limit for ncio implementations which have infinite chunksize */
if(sizehint > 32768)
sizehint = 16384;
if(sizehint > 32768) sizehint = 16384;')
def_dims(ncid);
Def_Vars(ncid, numVars);
Put_Atts(ncid, numGatts, numVars);
@ -2380,18 +2382,17 @@ APIFunc(get_file_version)(char *path, int *version)
if (fd == -1) return errno;
read_len = read(fd, magic, MAGIC_NUM_LEN);
if (read_len == -1) {
close(fd);
if (-1 == close(fd)) return errno;
if (read_len == -1)
return errno;
}
if (read_len != MAGIC_NUM_LEN) {
printf("Error: reading NC magic string unexpected short read\n");
close(fd);
return 0;
}
if (strncmp(magic, "CDF", MAGIC_NUM_LEN-1)==0)
{
if (strncmp(magic, "CDF", MAGIC_NUM_LEN-1)==0) {
if (magic[MAGIC_NUM_LEN-1] == NC_FORMAT_CLASSIC ||
magic[MAGIC_NUM_LEN-1] == NC_FORMAT_64BIT_OFFSET ||
magic[MAGIC_NUM_LEN-1] == NC_FORMAT_CDF5)
@ -2457,11 +2458,13 @@ TestFunc(set_default_format)(void)
if (err != NC_NOERR)
error("bad file version = %d", err);
if (version != i) {
#if 0
if (i == 4) {
if (version == 3) continue;
printf("expect version 3 but got %d (file=%s)",version,scratch);
continue;
}
#endif
printf("expect version %d but got %d (file=%s)",i,version,scratch);
error("bad file version = %d", version);
}

View File

@ -480,6 +480,7 @@ extern int test_nc_rename_att(void);
extern int test_nc_del_att(void);
extern int test_nc_set_fill(void);
extern int test_nc_set_default_format(void);
extern int test_nc_against_pnetcdf(void);
void print_nok(int nok);
@ -565,6 +566,8 @@ void check_file(char *filename);
int file_create(const char *filename, int cmode, int *ncid);
int file__create(const char *filename, int cmode, size_t initialsz, size_t *bufrsizehintp, int *ncid);
int file_open(const char *filename, int omode, int *ncid);
char* nc_err_code_name(int err);

View File

@ -1016,9 +1016,9 @@ check_vars(int ncid)
IF (err)
error("nc_get_var1_text: %s", nc_strerror(err));
IF (text != (char)expect) {
error("Var %s value read 0x%02x not that expected 0x%02x ",
var_name[i], text, (char)expect);
print_n_size_t(var_rank[i], index);
error("Var %s [%lu] value read %hhd not that expected %g ",
var_name[i], j, text, expect);
print_n_size_t(var_rank[i], index);
} else {
nok++;
}
@ -1029,10 +1029,8 @@ check_vars(int ncid)
error("nc_get_var1_double: %s", nc_strerror(err));
} else {
IF (!equal(value,expect,var_type[i], NCT_DOUBLE)) {
value = 0;
err = nc_get_var1_double(ncid, i, index, &value);
error("Var %s value read % 12.5e not that expected % 12.7e ",
var_name[i], value, expect);
error("Var %s [%lu] value read %g not that expected %g ",
var_name[i], j, value, expect);
print_n_size_t(var_rank[i], index);
} else {
nok++;
@ -1156,13 +1154,13 @@ int file_create(const char *filename, int cmode, int *ncid)
{
int err;
#ifdef USE_PNETCDF
/* get the default file format */
int default_format;
nc_set_default_format(NC_FORMAT_CLASSIC, &default_format);
/* set it back to the default */
nc_set_default_format(default_format, NULL);
#ifdef USE_PNETCDF
if (default_format == NC_FORMAT_CLASSIC ||
default_format == NC_FORMAT_64BIT_OFFSET ||
default_format == NC_FORMAT_64BIT_DATA)
@ -1174,17 +1172,43 @@ int file_create(const char *filename, int cmode, int *ncid)
return err;
}
int file_open(const char *filename, int omode, int *ncid)
int file__create(const char *filename,
int cmode,
size_t initialsz,
size_t *bufrsizehintp,
int *ncid)
{
int err;
#ifdef USE_PNETCDF
/* get the default file format */
int default_format;
err = nc_set_default_format(NC_FORMAT_CLASSIC, &default_format);
/* set it back to the default */
err = nc_set_default_format(default_format, NULL);
if (default_format == NC_FORMAT_CLASSIC ||
default_format == NC_FORMAT_64BIT_OFFSET ||
default_format == NC_FORMAT_64BIT_DATA)
err = nc_create_par(filename, cmode|NC_PNETCDF, MPI_COMM_WORLD, MPI_INFO_NULL, ncid);
else
#endif
err = nc__create(filename, cmode, initialsz, bufrsizehintp, ncid);
return err;
}
int file_open(const char *filename, int omode, int *ncid)
{
int err;
#ifdef USE_PNETCDF
/* get the default file format */
int default_format;
err = nc_set_default_format(NC_FORMAT_CLASSIC, &default_format);
/* set it back to the default */
err = nc_set_default_format(default_format, NULL);
if (default_format == NC_FORMAT_CLASSIC ||
default_format == NC_FORMAT_64BIT_OFFSET ||
default_format == NC_FORMAT_64BIT_DATA)
@ -1379,3 +1403,57 @@ char* nc_err_code_name(int err)
return unknown_str;
}
int
test_nc_against_pnetcdf(void)
{
#ifdef USE_PNETCDF
int ncid; /* netCDF id */
int err; /* status */
/* Using netCDF library to create file */
err = nc_create(scratch, NC_CLOBBER, &ncid);
IF (err != NC_NOERR) error("nc_create: %s", nc_strerror(err));
def_dims(ncid);
def_vars(ncid);
put_atts(ncid);
err = nc_enddef(ncid);
IF (err != NC_NOERR) error("nc_enddef: %s", nc_strerror(err));
put_vars(ncid);
err = nc_close (ncid);
IF (err != NC_NOERR) error("nc_close: %s", nc_strerror(err));
/* Using PnetCDF library to check file */
err = nc_open_par(scratch, NC_NOWRITE|NC_PNETCDF, MPI_COMM_WORLD, MPI_INFO_NULL, &ncid);
IF (err != NC_NOERR) error("nc_open_par: %s", nc_strerror(err));
check_dims(ncid);
check_vars(ncid);
check_atts(ncid);
err = nc_close (ncid);
IF (err != NC_NOERR) error("nc_close: %s", nc_strerror(err));
/* Using PnetCDF library to create file */
err = nc_create_par(scratch, NC_PNETCDF, MPI_COMM_WORLD, MPI_INFO_NULL, &ncid);
IF (err != NC_NOERR) error("nc_create_par: %s", nc_strerror(err));
def_dims(ncid);
def_vars(ncid);
put_atts(ncid);
err = nc_enddef(ncid);
IF (err != NC_NOERR) error("nc_enddef: %s", nc_strerror(err));
put_vars(ncid);
err = nc_close (ncid);
IF (err != NC_NOERR) error("nc_close: %s", nc_strerror(err));
/* Using NetCDF library to check file */
err = nc_open(scratch, NC_NOWRITE, &ncid);
IF (err != NC_NOERR) error("nc_open: %s", nc_strerror(err));
check_dims(ncid);
check_vars(ncid);
check_atts(ncid);
err = nc_close (ncid);
IF (err != NC_NOERR) error("nc_close: %s", nc_strerror(err));
err = nc_delete(scratch);
IF (err != NC_NOERR) error("remove of %s failed", scratch);
#endif
return 1;
}