diff options
author | Jan Dubois <jand@activestate.com> | 2006-02-15 09:19:29 -0800 |
---|---|---|
committer | Rafael Garcia-Suarez <rgarciasuarez@gmail.com> | 2006-02-16 11:46:51 +0000 |
commit | 44221b20e58d7d2e060f57de5d83fc6fb49337bd (patch) | |
tree | bda7518f0617dc12945fa14f78a8d44eb4c1311f | |
parent | ce712ebb95d183e83e7dbbf4bab54d46504ec362 (diff) | |
download | perl-44221b20e58d7d2e060f57de5d83fc6fb49337bd.tar.gz |
stat() on Windows doesn't handle trailing slashes/backslashes correctly
From: "Jan Dubois" <jand@ActiveState.com>
Message-ID: <017901c63297$08e1e3f0$2217a8c0@candy>
p4raw-id: //depot/perl@27200
-rw-r--r-- | win32/win32.c | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/win32/win32.c b/win32/win32.c index 347bff317e..41b7045499 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -1169,21 +1169,31 @@ win32_stat(const char *path, Stat_t *sbuf) int res; HANDLE handle; int nlink = 1; + BOOL expect_dir = FALSE; if (l > 1) { switch(path[l - 1]) { /* FindFirstFile() and stat() are buggy with a trailing - * backslash, so change it to a forward slash :-( */ + * slashes, except for the root directory of a drive */ case '\\': - if (l >= sizeof(buffer)) { + case '/': + if (l > sizeof(buffer)) { errno = ENAMETOOLONG; return -1; } - strncpy(buffer, path, l-1); - buffer[l - 1] = '/'; - buffer[l] = '\0'; - path = buffer; + --l; + strncpy(buffer, path, l); + /* remove additional trailing slashes */ + while (l > 1 && (buffer[l-1] == '/' || buffer[l-1] == '\\')) + --l; + /* add back slash if we otherwise end up with just a drive letter */ + if (l == 2 && isALPHA(buffer[0]) && buffer[1] == ':') + buffer[l++] = '\\'; + buffer[l] = '\0'; + path = buffer; + expect_dir = TRUE; break; + /* FindFirstFile() is buggy with "x:", so add a dot :-( */ case ':': if (l == 2 && isALPHA(path[0])) { @@ -1245,6 +1255,10 @@ win32_stat(const char *path, Stat_t *sbuf) return -1; } } + if (expect_dir && !S_ISDIR(sbuf->st_mode)) { + errno = ENOTDIR; + return -1; + } #ifdef __BORLANDC__ if (S_ISDIR(sbuf->st_mode)) sbuf->st_mode |= S_IWRITE | S_IEXEC; |