Skip to content

Commit

Permalink
Merge pull request #2065 from DennisHeimbigner/netpath.dmh
Browse files Browse the repository at this point in the history
Support Windows network paths: \\svc\x\y...
  • Loading branch information
WardF authored Aug 10, 2021
2 parents 0b5b484 + 01487ec commit a193b44
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 22 deletions.
1 change: 1 addition & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This file contains a high-level description of this package's evolution. Release

## 4.8.1 - TBD

* [Enhancement] Support windows network paths (e.g. \\svc\...). See [Github #2065](https://github.com/Unidata/netcdf-c/issues/2065).
* [Enhancement] Convert to a new representation of the NCZarr meta-data extensions: version 2. Read-only backward compatibility is provided. See [Github #2032](https://github.com/Unidata/netcdf-c/issues/2032).
* [Bug Fix] Fix dimension_separator bug in libnczarr. See [Github #2035](https://github.com/Unidata/netcdf-c/issues/2035).
* [Bug Fix] Fix bugs in libdap4. See [Github #2005](https://github.com/Unidata/netcdf-c/issues/2005).
Expand Down
17 changes: 12 additions & 5 deletions include/ncpathmgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,12 @@ Assumptions about Input path:
1. It is a relative or absolute path
2. It is not a URL
3. It conforms to the format expected by one of the following:
Linux (/x/y/...), Cygwin (/cygdrive/D/...),
Windows (D:/...), or MSYS (/D/...), or relative (x/y...)
Linux (/x/y/...),
Cygwin (/cygdrive/D/...),
Windows (D:\...),
Windows network path (\\mathworks\...)
MSYS (/D/...),
or relative (x/y...)
4. It is encoded in the local platform character set.
Note that for most systems, this is utf-8. But for Windows,
the encoding is most likely some form of ANSI code page, probably
Expand Down Expand Up @@ -107,14 +111,17 @@ that has some desirable properties:
the user is responsible for getting this right.
To this end we choose the linux/cygwin format as our standard canonical form.
If the path has a windows drive letter, then it is represented
in the cygwin "/cygdrive/<drive-letter>" form. If it is on *nix* platform,
then this sequence will never appear and the canonical path will look
like a standard *nix* path.
in the cygwin "/cygdrive/<drive-letter>" form.
If it is a windows network path, then it starts with "//".
If it is on *nix* platform, then this sequence will never appear
and the canonical path will look like a standard *nix* path.
*/
EXTERNL int NCpathcanonical(const char* srcpath, char** canonp);

EXTERNL int NChasdriveletter(const char* path);

EXTERNL int NCisnetworkpath(const char* path);

/* Canonicalize and make absolute by prefixing the current working directory */
EXTERNL char* NCpathabsolute(const char* name);

Expand Down
65 changes: 53 additions & 12 deletions libdispatch/dpathmgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,17 @@ for Windows. Other cases will be added as needed.
2. a leading '/cygdrive/X' will be converted to
a drive letter X if X is alpha-char.
3. a leading D:/... is treated as a windows drive letter
4. a leading // is a windows network path and is converted
to a drive letter using the fake drive letter "@".
5. If any of the above is encountered, then forward slashes
will be converted to backslashes.
All other cases are passed thru unchanged
*/

/* Define legal windows drive letters */
static const char* windrive = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
static const char* windrive = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@";

static const char netdrive = '@';

static const size_t cdlen = 10; /* strlen("/cygdrive/") */

Expand Down Expand Up @@ -600,6 +604,27 @@ NChasdriveletter(const char* path)
return hasdl;
}

EXTERNL int
NCisnetworkpath(const char* path)
{
int stat = NC_NOERR;
int isnp = 0;
struct Path canon = empty;

if(!pathinitialized) pathinit();

if((stat = parsepath(path,&canon))) goto done;
if(canon.kind == NCPD_REL) {
clearPath(&canon);
/* Get the drive letter (if any) from the local wd */
canon.drive = wdpath.drive;
}
isnp = (canon.drive == netdrive);
done:
clearPath(&canon);
return isnp;
}

/**************************************************/
/* Utilities */

Expand All @@ -626,15 +651,27 @@ parsepath(const char* inpath, struct Path* path)
/* Convert to forward slash */
for(p=tmp1;*p;p++) {if(*p == '\\') *p = '/';}

/* parse all paths to 2-parts:
/* parse all paths to 2 parts:
1. drive letter (optional)
2. path after drive letter
*/

len = strlen(tmp1);

/* 1. look for MSYS path /D/... */
if(len >= 2
/* 1. look for Windows network path //... */
if(len >= 2 && (tmp1[0] == '/') && (tmp1[1] == '/')) {
path->drive = netdrive;
/* Remainder */
if(tmp1[2] == '\0')
path->path = NULL;
else
path->path = strdup(tmp1+1); /*keep first '/' */
if(path == NULL)
{stat = NC_ENOMEM; goto done;}
path->kind = NCPD_WIN;
}
/* 2. look for MSYS path /D/... */
else if(len >= 2
&& (tmp1[0] == '/')
&& strchr(windrive,tmp1[1]) != NULL
&& (tmp1[2] == '/' || tmp1[2] == '\0')) {
Expand All @@ -649,7 +686,7 @@ parsepath(const char* inpath, struct Path* path)
{stat = NC_ENOMEM; goto done;}
path->kind = NCPD_MSYS;
}
/* 2. Look for leading /cygdrive/D where D is a single-char drive letter */
/* 3. Look for leading /cygdrive/D where D is a single-char drive letter */
else if(len >= (cdlen+1)
&& memcmp(tmp1,"/cygdrive/",cdlen)==0
&& strchr(windrive,tmp1[cdlen]) != NULL
Expand All @@ -666,7 +703,7 @@ parsepath(const char* inpath, struct Path* path)
{stat = NC_ENOMEM; goto done;}
path->kind = NCPD_CYGWIN;
}
/* 3. Look for windows path: D:/... where D is a single-char
/* 4. Look for windows path: D:/... where D is a single-char
drive letter */
else if(len >= 2
&& strchr(windrive,tmp1[0]) != NULL
Expand All @@ -683,14 +720,14 @@ parsepath(const char* inpath, struct Path* path)
{stat = NC_ENOMEM; goto done;}
path->kind = NCPD_WIN;
}
/* look for *nix path */
/* 5. look for *nix path */
else if(len >= 1 && tmp1[0] == '/') {
/* Assume this is a *nix path */
path->drive = 0; /* no drive letter */
/* Remainder */
path->path = tmp1; tmp1 = NULL;
path->kind = NCPD_NIX;
} else {/* Relative path of unknown type */
} else {/* 6. Relative path of unknown type */
path->kind = NCPD_REL;
path->path = tmp1; tmp1 = NULL;
}
Expand Down Expand Up @@ -748,13 +785,17 @@ unparsepath(struct Path* xp, char** pathp)
break;
case NCPD_WIN:
if(xp->drive == 0) {xp->drive = wdpath.drive;} /*requires a drive */
len = nulllen(xp->path)+2+1;
len = nulllen(xp->path)+2+1+1;
if((path = (char*)malloc(len))==NULL)
{stat = NC_ENOMEM; goto done;}
path[0] = '\0';
sdrive[0] = xp->drive;
strlcat(path,sdrive,len);
strlcat(path,":",len);
if(xp->drive == netdrive)
strlcat(path,"/",len); /* second slash will come from path */
else {
sdrive[0] = xp->drive;
strlcat(path,sdrive,len);
strlcat(path,":",len);
}
if(xp->path)
strlcat(path,xp->path,len);
/* Convert forward to back */
Expand Down
16 changes: 11 additions & 5 deletions unit_test/test_pathcvt.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ static Test PATHTESTS[] = {
#ifndef _WIN32
/* Test utf8 path */
{"/海/海",{ "/海/海", "/c/海/海", "/cygdrive/c/海/海", "c:\\海\\海"}},
/* Test network path */
{"//git/netcdf-c/dap4_test",{
"/@/git/netcdf-c/dap4_test",
"/@/git/netcdf-c/dap4_test",
"/cygdrive/@/git/netcdf-c/dap4_test",
"\\\\git\\netcdf-c\\dap4_test"}},
#endif
{NULL, {NULL, NULL, NULL, NULL}}
};
Expand All @@ -62,11 +68,11 @@ main(int argc, char** argv)

nc_initialize();

/* Test localkind X path kind */
for(k=0;k<NKINDS;k++) {
int kind = kinds[k];
/* Iterate over the test paths */
for(test=PATHTESTS;test->test;test++) {
/* Test localkind X path-kind */
for(test=PATHTESTS;test->test;test++) {
/* Iterate over the test paths */
for(k=0;k<NKINDS;k++) {
int kind = kinds[k];
/* Compare output for the localkind */
if(test->expected[k] == NULL) {
#ifdef DEBUG
Expand Down

0 comments on commit a193b44

Please sign in to comment.