summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Dubois <jand@activestate.com>2006-02-15 09:19:29 -0800
committerRafael Garcia-Suarez <rgarciasuarez@gmail.com>2006-02-16 11:46:51 +0000
commit44221b20e58d7d2e060f57de5d83fc6fb49337bd (patch)
treebda7518f0617dc12945fa14f78a8d44eb4c1311f
parentce712ebb95d183e83e7dbbf4bab54d46504ec362 (diff)
downloadperl-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.c26
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;