diff --git a/kernel/dosfns.c b/kernel/dosfns.c index 7fbd112e..8d214888 100644 --- a/kernel/dosfns.c +++ b/kernel/dosfns.c @@ -501,6 +501,44 @@ const char FAR *get_basename(__XFAR(const char)fname) return fname; } +/* Extracts the device name from a path for IsDevice() validation. + * Preserves names with an optional trailing colon, while leaving + * bare drive specifications untouched. + * + * Examples: + * "NUL:" -> "NUL:" + * "C:\DIR\NUL:" -> "NUL:" + * "C:NUL:" -> "NUL:" + * "NUL" -> "NUL" + * "C:" -> "" + * "C:\DIR\FILE" -> "FILE" + */ +const char FAR *get_devname(__XFAR(const char) fname) +{ + const char FAR *froot = get_basename(fname); + const char FAR *name_start; + + /* If a valid basename was found, or the path doesn't end in ':', we're done */ + if (*froot != '\0' || froot == fname || *(froot - 1) != ':') + return froot; + + /* Walk back before the trailing ':' to find the start of the device token */ + name_start = froot - 1; + while (name_start > fname && + name_start[-1] != '/' && + name_start[-1] != '\\' && + name_start[-1] != ':') + { + name_start--; + } + + /* Single-character prefixes before the colon (e.g., "C:") are bare drive specs */ + if ((froot - 1) - name_start < 2) + return froot; + + return name_start; +} + STATIC void ConvertPathNameToFCBName(char *FCBName, const char FAR *PathName) { ConvertNameSZToName83(FCBName, get_basename(PathName)); @@ -1423,7 +1461,7 @@ COUNT DosLockUnlock(COUNT hndl, LONG pos, LONG len, COUNT unlock) struct dhdr FAR *IsDevice(__XFAR(const char)fname) { struct dhdr FAR *dhp; - const char FAR *froot = get_basename(fname); + const char FAR *froot = get_devname(fname); int i; /* /// BUG!!! This is absolutely wrong. A filename of "NUL.LST" must be @@ -1464,8 +1502,9 @@ struct dhdr FAR *IsDevice(__XFAR(const char)fname) for (i = 0; i < FNAME_SIZE; i++) { unsigned char c1 = (unsigned char)froot[i]; - /* ignore extensions and handle filenames shorter than FNAME_SIZE */ - if (c1 == '.' || c1 == '\0') + /* ignore extensions and handle filenames shorter than FNAME_SIZE; + a trailing colon ("NUL:") also ends the name */ + if (c1 == '.' || c1 == '\0' || c1 == ':') { /* check if remainder of device name consists of spaces or nulls */ for (; i < FNAME_SIZE; i++) diff --git a/kernel/newstuff.c b/kernel/newstuff.c index 221bf394..61760edb 100644 --- a/kernel/newstuff.c +++ b/kernel/newstuff.c @@ -373,7 +373,7 @@ COUNT truename(__XFAR(const char) src, char FAR *dest, COUNT mode) dest[2] = '\\'; if (result & IS_DEVICE) { - froot = get_basename(src); + froot = get_devname(src); if (froot == src || froot == src + 5) { if (froot == src + 5) @@ -528,6 +528,9 @@ COUNT truename(__XFAR(const char) src, char FAR *dest, COUNT mode) while(*src != '/' && *src != '\\' && *src != '\0') { char c = *src++; + /* "NUL:" - ignore the colon that follows a device name */ + if (c == ':' && *src == '\0' && (result & IS_DEVICE)) + break; if (c == '*') { /* register the wildcard, even if no '?' is appended */ diff --git a/kernel/proto.h b/kernel/proto.h index 55f41e40..52077788 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -82,6 +82,7 @@ __FAR(sft)get_sft(UCOUNT); /* dosfns.c */ __FAR(const char)get_basename(__XFAR(const char)); +__FAR(const char)get_devname(__XFAR(const char)); BOOL check_break(void); UCOUNT GenericReadSft(__FAR(sft) sftp, UCOUNT n,__FAR(void) bp, COUNT * err, BOOL force_binary);