From 6ada304ec2ed6db438977b3559b9f89892694de9 Mon Sep 17 00:00:00 2001 From: Kenneth J Davis Date: Thu, 19 Aug 2021 00:00:29 -0400 Subject: [PATCH] allow opening a character device prefixed with invalid drive letter (e.g. "@:NUL") but not with invalid path --- kernel/newstuff.c | 58 ++++++++++++++++++++++++++++++++++++++++- tests/opendev/opendev.c | 29 ++++++++++++--------- 2 files changed, 74 insertions(+), 13 deletions(-) diff --git a/kernel/newstuff.c b/kernel/newstuff.c index 4ecd5f4..9fbe142 100644 --- a/kernel/newstuff.c +++ b/kernel/newstuff.c @@ -304,7 +304,63 @@ COUNT truename(const char FAR * src, char * dest, COUNT mode) cdsEntry = get_cds(result); if (cdsEntry == NULL) { - return DE_PATHNOTFND; + /* If opening a character device, DOS allows device name + to be prefixed by [invalid] drive letter and/or optionally + \DEV\ directory prefix, however, any other directory + including root (\) is an invalid path if drive is not + valid and returns such. + Whereas truename always fails for invalid drive. + */ + if (dhp && (mode & CDS_MODE_CHECK_DEV_PATH) && (result >= lastdrive)) + { + /* Note: check for (result >= lastdrive) means invalid drive + was provided as otherwise we would have used default_drive + so we know src in the form of X:? + fail if anything other than no path or path is \DEV\ + */ + char drivesep[] = "\\/"; + const char FAR *s = src+2; + const char *d = strchr(drivesep, *s); /* ?path starts with \ or / */ + + /* could be 1 letter devicename, don't go scanning random memory */ + if (*(src+3) != '\0') + { + s = fstrchr(src+3, '\\'); /* ?is there \ or / other than immediately after drive: */ + if (s == NULL) s = fstrchr(src+3, '/'); + } + else + { + s = NULL; + } + + if (d == NULL) + { + /* either X:devicename or X:path\devicename */ + if (s != NULL) goto invalid_path; + } + else + { + /* either X:\devicename or X:\path\devicename + only X:\DEV\devicename is valid path + */ + if (s == NULL) goto invalid_path; + if (s != src+6) goto invalid_path; + if (fmemcmp(src+3, "DEV", 3) != 0) goto invalid_path; + s = fstrchr(src+7, '\\'); + if (s == NULL) s = fstrchr(src+7, '/'); + if (s != NULL) goto invalid_path; + } + + /* use CDS of current drive (MS-DOS may return drive P: for invalid drive.) */ + result = default_drive; + cdsEntry = get_cds(result); + if (cdsEntry == NULL) goto invalid_path; + } + else + { +invalid_path: + return DE_PATHNOTFND; + } } fmemcpy(&TempCDS, cdsEntry, sizeof(TempCDS)); diff --git a/tests/opendev/opendev.c b/tests/opendev/opendev.c index 7e96b22..f8a4ebc 100644 --- a/tests/opendev/opendev.c +++ b/tests/opendev/opendev.c @@ -81,29 +81,34 @@ int do_tests_on(const char *device_name) const char current_drive = (char)('A'+_getdrive()-1); sprintf(buffer, "%s", device_name); - if (!test_device('@', buffer,0)) status = FAILURE; - if (!test_device(current_drive, buffer,0)) status = FAILURE; + if (!test_device('@', buffer,0)) status = FAILURE; /* special, should succeed */ + if (!test_device(current_drive, buffer,0)) status = FAILURE; /* valid directory, should succeed */ /* DIREXIST should exist in the current directory */ sprintf(buffer, "DIREXIST\\%s", device_name); - if (!test_device('@', buffer,1)) status = FAILURE; /* drive does not exist, should fail */ - if (!test_device(current_drive, buffer,0)) status = FAILURE; /* valid drive, should succeed */ + if (!test_device('@', buffer,1)) status = FAILURE; /* directory does not exist, should fail */ + if (!test_device(current_drive, buffer,0)) status = FAILURE; /* valid directory, should succeed */ sprintf(buffer, "BAD_PATH\\%s", device_name); - if (!test_device('@', buffer,1)) status = FAILURE; - if (!test_device(current_drive, buffer,1)) status = FAILURE; + if (!test_device('@', buffer,1)) status = FAILURE; /* directory does not exist, should fail */ + if (!test_device(current_drive, buffer,1)) status = FAILURE; /* directory does not exist, should fail */ + + /* assumes DEV directory does not exist in current directory */ + sprintf(buffer, "DEV\\%s", device_name); + if (!test_device('@', buffer,1)) status = FAILURE; /* directory does not exist, should fail */ + if (!test_device(current_drive, buffer,1)) status = FAILURE; /* directory does not exist, should fail */ sprintf(buffer, "\\%s", device_name); - if (!test_device('@', buffer,1)) status = FAILURE; /* drive does not exist, should fail */ - if (!test_device(current_drive, buffer,0)) status = FAILURE; /* valid drive, should succeed */ + if (!test_device('@', buffer,1)) status = FAILURE; /* directory does not exist, should fail */ + if (!test_device(current_drive, buffer,0)) status = FAILURE; /* valid directory, should succeed */ sprintf(buffer, "\\BAD_PATH\\%s", device_name); - if (!test_device('@', buffer,1)) status = FAILURE; - if (!test_device(current_drive, buffer,1)) status = FAILURE; + if (!test_device('@', buffer,1)) status = FAILURE; /* directory does not exist, should fail */ + if (!test_device(current_drive, buffer,1)) status = FAILURE; /* directory does not exist, should fail */ sprintf(buffer, "\\DEV\\%s", device_name); - if (!test_device('@', buffer,0)) status = FAILURE; - if (!test_device(current_drive, buffer,0)) status = FAILURE; + if (!test_device('@', buffer,0)) status = FAILURE; /* special, should succeed */ + if (!test_device(current_drive, buffer,0)) status = FAILURE; /* special, should succeed */ return status; }