summaryrefslogtreecommitdiff
path: root/dir.c
diff options
context:
space:
mode:
authorEli Zaretskii <eliz@gnu.org>2013-04-28 20:53:36 +0300
committerEli Zaretskii <eliz@gnu.org>2013-04-28 20:53:36 +0300
commit5667376edc9cc68c1ed40f985c6d2174dfaeb64c (patch)
tree1afc6587f7ccac619a3eb5379a3c6b5c3d384ba8 /dir.c
parent7f01830927969a8386050617385e59070fe9f34b (diff)
downloadgunmake-5667376edc9cc68c1ed40f985c6d2174dfaeb64c.tar.gz
Fix Savannah bug #37065 with $(wildcard foo/*/.) returning non-directories.
dir.c (local_stat) [WINDOWS32]: Use the wrapper on MS-Windows. If the argument ends in "dir/.", make sure the parent dir exists and is indeed a directory. Fixes Savannah bug #37065.
Diffstat (limited to 'dir.c')
-rw-r--r--dir.c22
1 files changed, 21 insertions, 1 deletions
diff --git a/dir.c b/dir.c
index 59b2a8c..dc0ef76 100644
--- a/dir.c
+++ b/dir.c
@@ -1185,8 +1185,11 @@ ansi_free (void *p)
/* On 64 bit ReliantUNIX (5.44 and above) in LFS mode, stat() is actually a
* macro for stat64(). If stat is a macro, make a local wrapper function to
* invoke it.
+ *
+ * On MS-Windows, stat() "succeeds" for foo/bar/. where foo/bar is a
+ * regular file; fix that here.
*/
-#ifndef stat
+#if !defined(stat) && !defined(WINDOWS32)
# ifndef VMS
int stat (const char *path, struct stat *sbuf);
# endif
@@ -1196,6 +1199,23 @@ static int
local_stat (const char *path, struct stat *buf)
{
int e;
+#ifdef WINDOWS32
+ size_t plen = strlen (path);
+
+ /* Make sure the parent of "." exists and is a directory, not a
+ file. This is because 'stat' on Windows normalizes the argument
+ foo/. => foo without checking first that foo is a directory. */
+ if (plen > 1 && path[plen - 1] == '.'
+ && (path[plen - 2] == '/' || path[plen - 2] == '\\'))
+ {
+ char parent[MAXPATHLEN];
+
+ strncpy (parent, path, plen - 2);
+ parent[plen - 2] = '\0';
+ if (stat (parent, buf) < 0 || !_S_ISDIR (buf->st_mode))
+ return -1;
+ }
+#endif
EINTRLOOP (e, stat (path, buf));
return e;