Fix Savannah bug #37065 with $(wildcard foo/*/.) returning non-directories.
authorEli Zaretskii <eliz@gnu.org>
Sun, 28 Apr 2013 17:53:36 +0000 (20:53 +0300)
committerEli Zaretskii <eliz@gnu.org>
Sun, 28 Apr 2013 17:53:36 +0000 (20:53 +0300)
 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.

ChangeLog
dir.c

index 91802ae3be4c2f49c4e67463c88557a4d316fc80..2c8275ada79b1c18883d6684abdf30492b7b5a5f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2013-04-28  Eli Zaretskii  <eliz@gnu.org>
+
+       * 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.
+
 2013-04-28  Paul Smith  <psmith@gnu.org>
 
        Implement a "per-job" output synchronization option.
diff --git a/dir.c b/dir.c
index 59b2a8c73ccdf12f6713eb6788297d4a1bfa5aa5..dc0ef76347c258e6ba1317f34d6097fe9d036422 100644 (file)
--- 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;