/*! \file Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 University Corporation for Atmospheric Research/Unidata. See \ref copyright file for more info. */ #include "config.h" #include #include #include #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_UNISTD_H #include "unistd.h" #endif #ifdef _WIN32 #include #include #endif #include "netcdf.h" #define CLEANUP #ifndef NC_NETCDF3 #define NC_NETCDF3 0 #endif #define FILE3D "file3d.nc" #define FILE3DP "file3dp.nc" #define FILE4D "file4d.nc" #define FILE4DP "file4dp.nc" /* Mnemonics */ #define RDONLY 1 #define RDWRITE 0 #ifdef _WIN32 #define RDONLYMODE (_S_IREAD) #define RDWRMODE (_S_IREAD|_S_IWRITE) #define CHMOD _chmod #define SLEEP(x) Sleep((x)*1000) #else #define RDONLYMODE (S_IRUSR|S_IRGRP|S_IROTH) #define RDWRMODE (RDONLY | S_IWUSR) #define CHMOD chmod #define SLEEP(x) sleep(x) #endif typedef enum OC { OPEN, CLOSE} OC; static int lineno = 0; static char* smode(int mode) { static char ms[8192]; ms[0] = '\0'; if(mode & NC_NETCDF4) strcat(ms,"NC_NETCDF4"); else strcat(ms,"NC_NETCDF3"); if(mode & NC_DISKLESS) strcat(ms,"|NC_DISKLESS"); if(mode & NC_WRITE) strcat(ms,"|NC_WRITE"); if(mode & NC_NOCLOBBER) strcat(ms,"|NC_NOCLOBBER"); if(mode & NC_INMEMORY) strcat(ms,"|NC_INMEMORY"); if(mode & NC_PERSIST) strcat(ms,"|NC_PERSIST"); if(mode & NC_MMAP) strcat(ms,"|NC_MMAP"); return ms; } /* Return 1 if file was changed else 0 */ static time_t getmodified(const char* path) { struct stat attr; stat(path, &attr); return attr.st_mtime; } static void changeaccess(int rdonly) { const char* p3 = FILE3DP; /* Keep Visual Studio happy */ const char* p4 = FILE4DP; int mode = (rdonly?RDONLYMODE:RDWRMODE); (void)CHMOD(p3,mode); (void)CHMOD(p4,mode); } static void cleanup() { changeaccess(RDWRITE); /* cleanup */ (void)unlink(FILE3DP); (void)unlink(FILE4DP); } static void fail(int ret) { if(ret != NC_NOERR) { fprintf(stderr,"*** Fail: line: %d: (%d) %s\n", lineno, ret, nc_strerror(ret)); fflush(stderr); #ifdef CLEANUP cleanup(); #endif exit(1); } } void exists(const char* file) { FILE* f = fopen(file,"r"); if(f == NULL) fail(NC_EPERM); fclose(f); } void notexists(const char* file) { FILE* f = fopen(file,"r"); if(f != NULL) {fclose(f); fail(NC_EEXIST);} } #define TESTCREATE(file,mode,exist) {lineno=__LINE__; testcreate(file,mode,exist);} #define TESTOPEN(file,mode,rw) {lineno=__LINE__; testopen(file,mode,rw);} static void testcreate(const char* file, int mode, int mustexist) { int ret = NC_NOERR; int ncid, dimid; printf("test: file=%s mode=%s\n",file,smode(mode)); fflush(stdout); if((ret = nc_create(file,mode,&ncid))) fail(ret); if((ret = nc_def_dim(ncid,"dim",5,&dimid))) fail(ret); if((ret = nc_close(ncid))) fail(ret); if(mustexist) exists(file); else notexists(file); } static void testopen(const char* file, int mode, int rdwrite) { int ret = NC_NOERR; int ncid, dimid; size_t len; time_t time1, time2; printf("test: file=%s mode=%s\n",file,smode(mode)); fflush(stdout); time1 = getmodified(file); SLEEP(1); /* Ensure that if modified, it will be reported */ if((ret = nc_open(file,mode,&ncid))) fail(ret); if(rdwrite) { /* Modify */ if((ret=nc_redef(ncid))) fail(ret); /* See if dim2 is already defined */ ret = nc_inq_dimid(ncid,"dim2",&dimid); if(ret == NC_NOERR) {/* defined */ if((ret = nc_def_dim(ncid,"dim3",3,&dimid))) fail(ret); } else if(ret == NC_EBADDIM) { /* not defined */ if((ret = nc_def_dim(ncid,"dim2",2,&dimid))) fail(ret); } else fail(ret); if((ret=nc_enddef(ncid))) fail(ret); } if((ret = nc_inq_dimid(ncid,"dim",&dimid))) fail(ret); if((ret = nc_inq_dimlen(ncid,dimid,&len))) fail(ret); ret = nc_close(ncid); if(ret != NC_NOERR && rdwrite) fail(ret); else if(ret == NC_NOERR && !rdwrite) fail(NC_EINVAL); time2 = getmodified(file); if(!rdwrite) { if(time2 != time1) { fprintf(stderr,"file modified: %s\n",file); fail(NC_EACCESS); } } } int main() { changeaccess(RDWRITE); cleanup(); /* Test various mode combinations */ /* Create and persist some files using diskless */ printf("*** Test create\n"); fflush(stdout); TESTCREATE(FILE3D,NC_NETCDF3|NC_DISKLESS,0); /* Not persisted */ TESTCREATE(FILE3DP,NC_NETCDF3|NC_DISKLESS|NC_PERSIST,1); /* persisted */ TESTCREATE(FILE4D,NC_NETCDF4|NC_DISKLESS,0); /* Not persisted */ TESTCREATE(FILE4DP,NC_NETCDF4|NC_DISKLESS|NC_PERSIST,1); /* persisted */ /* Of the above persisted files, re-read and modify and re-persist */ printf("*** Test open + modify + rdwrite\n"); fflush(stdout); TESTOPEN(FILE3DP,NC_NETCDF3|NC_DISKLESS|NC_PERSIST|NC_WRITE,1); /* re-persist */ TESTOPEN(FILE4DP,NC_NETCDF4|NC_DISKLESS|NC_PERSIST|NC_WRITE,1); /* re-persist */ /* Of the above modified files, re-read and modify but do not re-persist */ /* Test open + modify + rdonly; requires NC_DISKLESS*/ #if 0 /* Fails with hdf5, file must be writeable even if not persisted */ changeaccess(RDONLY); /* prevent re-persist */ #endif printf("*** Testopen modify + rdonly\n"); fflush(stdout); TESTOPEN(FILE3DP,NC_NETCDF3|NC_DISKLESS|NC_WRITE,1); TESTOPEN(FILE4DP,NC_NETCDF4|NC_DISKLESS|NC_WRITE,1); #ifdef CLEANUP cleanup(); #endif return 0; }