diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 692f83c3ae..995a481008 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -6,6 +6,7 @@ Release Notes {#RELEASE_NOTES} This file contains a high-level description of this package's evolution. Releases are in reverse chronological order (most recent first). Note that, as of netcdf 4.2, the `netcdf-c++` and `netcdf-fortran` libraries have been separated into their own libraries. ## 4.8.1 - TBD +* [Bug Fix] Fix hack for handling failure of shell programs to properly handle escape characters. See [Github #1989](https://github.com/Unidata/netcdf-c/issues/1989). * [Bug Fix] Allow some primitive type names to be used as identifiers depending on the file format. See [Github #1984](https://github.com/Unidata/netcdf-c/issues/1984). * [Enhancement] Add support for reading/writing pure Zarr storage format that supports the XArray _ARRAY_DIMENSIONS attribute. See [Github #1952](https://github.com/Unidata/netcdf-c/pull/1952) for more information. * [Update] Updated version of bzip2 used in filter testing/functionality, in support of [Github #1969](https://github.com/Unidata/netcdf-c/issues/1969). diff --git a/include/ncpathmgr.h b/include/ncpathmgr.h index 44a8b8b490..3cd27a9256 100644 --- a/include/ncpathmgr.h +++ b/include/ncpathmgr.h @@ -168,5 +168,6 @@ EXTERNL void printutf8hex(const char* s, char* sx); /* From dutil.c */ EXTERNL char* NC_backslashEscape(const char* s); EXTERNL char* NC_backslashUnescape(const char* esc); +EXTERNL char* NC_shellUnescape(const char* esc); #endif /* _NCPATHMGR_H_ */ diff --git a/libdispatch/dutil.c b/libdispatch/dutil.c index d3163bddfd..21509ab94a 100644 --- a/libdispatch/dutil.c +++ b/libdispatch/dutil.c @@ -164,6 +164,37 @@ NC_entityescape(const char* s) return escaped; } +char* +/* +Depending on the platform, the shell will sometimes +pass an escaped octotherpe character without removing +the backslash. So this function is appropriate to be called +on possible url paths to unescape such cases. See e.g. ncgen. +*/ +NC_shellUnescape(const char* esc) +{ + size_t len; + char* s; + const char* p; + char* q; + + if(esc == NULL) return NULL; + len = strlen(esc); + s = (char*)malloc(len+1); + if(s == NULL) return NULL; + for(p=esc,q=s;*p;) { + switch (*p) { + case '\\': + if(p[1] == '#') + p++; + /* fall thru */ + default: *q++ = *p++; break; + } + } + *q = '\0'; + return s; +} + /** Wrap mktmp and return the generated path, or null if failed. @@ -371,3 +402,4 @@ int isnan(double x) } #endif /*APPLE*/ + diff --git a/ncdump/nccopy.c b/ncdump/nccopy.c index 3fcf9b837a..bf9b6dd5e9 100644 --- a/ncdump/nccopy.c +++ b/ncdump/nccopy.c @@ -2412,8 +2412,8 @@ main(int argc, char**argv) error("one input file and one output file required"); } /* Canonicalize the input and output files names */ - inputfile = NC_backslashUnescape(argv[0]); /* Remove shell added escapes */ - outputfile = NC_backslashUnescape(argv[1]); + inputfile = NC_shellUnescape(argv[0]); /* Remove shell added escapes */ + outputfile = NC_shellUnescape(argv[1]); if(strcmp(inputfile, outputfile) == 0) { error("output would overwrite input"); } diff --git a/ncdump/ncdump.c b/ncdump/ncdump.c index d333cc37b7..b6981a53cb 100644 --- a/ncdump/ncdump.c +++ b/ncdump/ncdump.c @@ -2335,7 +2335,7 @@ main(int argc, char *argv[]) /* We need to look for escape characters because the argument may have come in via a shell script */ - path = NC_backslashUnescape(argv[i]); + path = NC_shellUnescape(argv[i]); if(path == NULL) { snprintf(errmsg,sizeof(errmsg),"out of memory un-escaping argument %s", argv[i]); goto fail; diff --git a/ncgen/main.c b/ncgen/main.c index b411501664..9ed31d47e9 100644 --- a/ncgen/main.c +++ b/ncgen/main.c @@ -351,7 +351,7 @@ main( break; case 'o': /* to explicitly specify output name */ if(netcdf_name) efree(netcdf_name); - netcdf_name = NC_backslashUnescape(optarg); + netcdf_name = NC_shellUnescape(optarg); break; case 'P': /* diskless with persistence */ diskless = 1; @@ -460,7 +460,7 @@ main( } } - cdlname = NC_backslashUnescape(argv[0]); + cdlname = NC_shellUnescape(argv[0]); if(cdlname != NULL) { if(strlen(cdlname) > NC_MAX_NAME) cdlname[NC_MAX_NAME] = '\0'; diff --git a/nczarr_test/ncdumpchunks.c b/nczarr_test/ncdumpchunks.c index a6fff5fb86..2eecc42509 100755 --- a/nczarr_test/ncdumpchunks.c +++ b/nczarr_test/ncdumpchunks.c @@ -485,7 +485,7 @@ main(int argc, char** argv) } { - char* s = NC_backslashUnescape(argv[0]); + char* s = NC_shellUnescape(argv[0]); strcpy(format.file_name,filenamefor(s)); nullfree(s); } diff --git a/nczarr_test/s3util.c b/nczarr_test/s3util.c index e17631fe30..b90078380d 100644 --- a/nczarr_test/s3util.c +++ b/nczarr_test/s3util.c @@ -163,7 +163,7 @@ main(int argc, char** argv) dumpoptions.nctype = typefor(optarg); break; case 'u': { - char* p = NC_backslashUnescape(optarg); + char* p = NC_shellUnescape(optarg); ncuriparse(p,&dumpoptions.url); nullfree(p); if(dumpoptions.url == NULL) { diff --git a/nczarr_test/tst_utils.c b/nczarr_test/tst_utils.c index ad2d56e6c7..1891429f75 100644 --- a/nczarr_test/tst_utils.c +++ b/nczarr_test/tst_utils.c @@ -129,7 +129,7 @@ getoptions(int* argcp, char*** argvp) *argvp += optind; if(*argcp > 0) { - char* p = NC_backslashUnescape((*argvp)[0]); + char* p = NC_shellUnescape((*argvp)[0]); strcpy(options->file,filenamefor(p)); nullfree(p); } diff --git a/nczarr_test/zmapio.c b/nczarr_test/zmapio.c index 4f935b13d3..80d0714269 100644 --- a/nczarr_test/zmapio.c +++ b/nczarr_test/zmapio.c @@ -177,7 +177,7 @@ main(int argc, char** argv) } { - char* p = NC_backslashUnescape(argv[0]); + char* p = NC_shellUnescape(argv[0]); strcpy(dumpoptions.infile,filenamefor(p)); if(p) free(p); } diff --git a/unit_test/test_pathcvt.c b/unit_test/test_pathcvt.c index 772e140c55..e1725aa637 100644 --- a/unit_test/test_pathcvt.c +++ b/unit_test/test_pathcvt.c @@ -27,6 +27,7 @@ typedef struct Test { static Test PATHTESTS[] = { {"/xxx/a/b",{"/xxx/a/b", "/c/xxx/a/b", "/cygdrive/c/xxx/a/b", "c:\\xxx\\a\\b"}}, {"d:/x/y",{ "/d/x/y", "/d/x/y", "/cygdrive/d/x/y", "d:\\x\\y"}}, +{"d:\\x\\y",{ "/d/x/y", "/d/x/y", "/cygdrive/d/x/y", "d:\\x\\y"}}, {"/cygdrive/d/x/y",{ "/d/x/y", "/d/x/y", "/cygdrive/d/x/y", "d:\\x\\y"}}, {"/d/x/y",{ "/d/x/y", "/d/x/y", "/cygdrive/d/x/y", "d:\\x\\y"}}, {"/cygdrive/d",{ "/d", "/d", "/cygdrive/d", "d:"}}, @@ -38,6 +39,7 @@ static Test PATHTESTS[] = { "d:\\git\\netcdf-c\\dap4_test\\test_anon_dim.2.syn"}}, /* Test relative path */ {"x/y",{ "x/y", "x/y", "x/y", "x\\y"}}, +{"x\\y",{ "x/y", "x/y", "x/y", "x\\y"}}, #ifndef _WIN32 /* Test utf8 path */ {"/海/海",{ "/海/海", "/c/海/海", "/cygdrive/c/海/海", "c:\\海\\海"}}, @@ -54,6 +56,7 @@ main(int argc, char** argv) Test* test; int failcount = 0; char* cvt = NULL; + char* unescaped = NULL; int k; int drive = 'c'; @@ -71,7 +74,9 @@ main(int argc, char** argv) #endif continue; } - cvt = NCpathcvt_test(test->test,kind,drive); + /* ensure that NC_shellUnescape does not affect result */ + unescaped = NC_shellUnescape(test->test); + cvt = NCpathcvt_test(unescaped,kind,drive); #ifdef DEBUG fprintf(stderr,"TEST local=%s: input: |%s| expected=|%s| actual=|%s|: ", kind2string(kind),test->test,test->expected[k],cvt); @@ -95,10 +100,11 @@ main(int argc, char** argv) #ifdef DEBUG fprintf(stderr,"\n"); #endif + nullfree(unescaped); unescaped = NULL; nullfree( cvt); cvt = NULL; } } - nullfree(cvt); + nullfree(cvt); nullfree(unescaped); fprintf(stderr,"%s test_pathcvt\n",failcount > 0 ? "***FAIL":"***PASS"); nc_finalize(); return (failcount > 0 ? 1 : 0);