diff options
author | Jarkko Hietaniemi <jhi@iki.fi> | 2002-04-12 19:57:05 +0000 |
---|---|---|
committer | Jarkko Hietaniemi <jhi@iki.fi> | 2002-04-12 19:57:05 +0000 |
commit | bb27e7b65ce5dddfbcc195ca657661d5cc662d88 (patch) | |
tree | 9f4f7b192a3f2e507fcac0d699277413c502e772 /win32 | |
parent | 3241943182ef83e0280bc5b8b03b564dc33de822 (diff) | |
download | perl-bb27e7b65ce5dddfbcc195ca657661d5cc662d88.tar.gz |
Integrate change #15879 from maint-5.6;
Win32::GetLongPathName() did not return valid results if there
were "." and ".." components in the path; also fix a potential
buffer overflow if the long path happens to be longer than
MAX_PATH (this can presumably happen if they use \\?\... style
paths); add a rather limited testsuite that exercises just the
edge cases
p4raw-link: @15879 on //depot/maint-5.6/perl: a15439704ef1059bf178ec4b1820fee7b2af7173
p4raw-id: //depot/perl@15880
p4raw-branched: from //depot/maint-5.6/perl@15877 'branch in'
t/win32/longpath.t
p4raw-integrated: from //depot/maint-5.6/perl@15877 'ignore' MANIFEST
(@12747..) 'merge in' t/harness (@11427..) win32/win32.c
(@13145..)
Diffstat (limited to 'win32')
-rw-r--r-- | win32/win32.c | 89 |
1 files changed, 57 insertions, 32 deletions
diff --git a/win32/win32.c b/win32/win32.c index 31a1496fa0..fd44c5f10a 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -1284,6 +1284,18 @@ win32_stat(const char *path, struct stat *sbuf) return res; } +#define isSLASH(c) ((c) == '/' || (c) == '\\') +#define SKIP_SLASHES(s) \ + STMT_START { \ + while (*(s) && isSLASH(*(s))) \ + ++(s); \ + } STMT_END +#define COPY_NONSLASHES(d,s) \ + STMT_START { \ + while (*(s) && !isSLASH(*(s))) \ + *(d)++ = *(s)++; \ + } STMT_END + /* Find the longname of a given path. path is destructively modified. * It should have space for at least MAX_PATH characters. */ DllExport char * @@ -1299,61 +1311,74 @@ win32_longpath(char *path) return Nullch; /* drive prefix */ - if (isALPHA(path[0]) && path[1] == ':' && - (path[2] == '/' || path[2] == '\\')) - { + if (isALPHA(path[0]) && path[1] == ':') { start = path + 2; *tmpstart++ = path[0]; *tmpstart++ = ':'; } /* UNC prefix */ - else if ((path[0] == '/' || path[0] == '\\') && - (path[1] == '/' || path[1] == '\\')) - { + else if (isSLASH(path[0]) && isSLASH(path[1])) { start = path + 2; *tmpstart++ = path[0]; *tmpstart++ = path[1]; - /* copy machine name */ - while (*start && *start != '/' && *start != '\\') - *tmpstart++ = *start++; + SKIP_SLASHES(start); + COPY_NONSLASHES(tmpstart,start); /* copy machine name */ if (*start) { - *tmpstart++ = *start; - start++; - /* copy share name */ - while (*start && *start != '/' && *start != '\\') - *tmpstart++ = *start++; + *tmpstart++ = *start++; + SKIP_SLASHES(start); + COPY_NONSLASHES(tmpstart,start); /* copy share name */ } } - sep = *start++; - if (sep == '/' || sep == '\\') - *tmpstart++ = sep; *tmpstart = '\0'; - while (sep) { - /* walk up to slash */ - while (*start && *start != '/' && *start != '\\') - ++start; + while (*start) { + /* copy initial slash, if any */ + if (isSLASH(*start)) { + *tmpstart++ = *start++; + *tmpstart = '\0'; + SKIP_SLASHES(start); + } + + /* FindFirstFile() expands "." and "..", so we need to pass + * those through unmolested */ + if (*start == '.' + && (!start[1] || isSLASH(start[1]) + || (start[1] == '.' && (!start[2] || isSLASH(start[2]))))) + { + COPY_NONSLASHES(tmpstart,start); /* copy "." or ".." */ + *tmpstart = '\0'; + continue; + } + + /* if this is the end, bust outta here */ + if (!*start) + break; - /* discard doubled slashes */ - while (*start && (start[1] == '/' || start[1] == '\\')) + /* now we're at a non-slash; walk up to next slash */ + while (*start && !isSLASH(*start)) ++start; - sep = *start; /* stop and find full name of component */ + sep = *start; *start = '\0'; fhand = FindFirstFile(path,&fdata); + *start = sep; if (fhand != INVALID_HANDLE_VALUE) { - strcpy(tmpstart, fdata.cFileName); - tmpstart += strlen(fdata.cFileName); - if (sep) - *tmpstart++ = sep; - *tmpstart = '\0'; - *start++ = sep; - FindClose(fhand); + STRLEN len = strlen(fdata.cFileName); + if ((STRLEN)(tmpbuf + sizeof(tmpbuf) - tmpstart) > len) { + strcpy(tmpstart, fdata.cFileName); + tmpstart += len; + FindClose(fhand); + } + else { + FindClose(fhand); + errno = ERANGE; + return Nullch; + } } else { /* failed a step, just return without side effects */ /*PerlIO_printf(Perl_debug_log, "Failed to find %s\n", path);*/ - *start = sep; + errno = EINVAL; return Nullch; } } |