Fix completion on directory names on MS-DOS/MS-Windows
authorEli Zaretskii <eliz@gnu.org>
Sat, 12 Aug 2017 11:44:20 +0000 (14:44 +0300)
committerEli Zaretskii <eliz@gnu.org>
Sat, 12 Aug 2017 11:44:20 +0000 (14:44 +0300)
* src/msdos.c (faccessat):
* src/w32.c (faccessat): Support relative file names, and add D_OK
to 'mode' if the argument is a directory.  This unbreaks file-name
completion when the completion result is a directory.

src/msdos.c
src/w32.c

index 87b6f84148c6ee1a610f43e1f5aca48c46a17067..5b025753d98387e7e578515ccb9cab0c5e1e0b75 100644 (file)
@@ -3950,10 +3950,23 @@ faccessat (int dirfd, const char * path, int mode, int flags)
       && !(IS_DIRECTORY_SEP (path[0])
           || IS_DEVICE_SEP (path[1])))
     {
-      errno = EBADF;
-      return -1;
+      char lastc = dir_pathname[strlen (dir_pathname) - 1];
+
+      if (strlen (dir_pathname) + strlen (path) + IS_DIRECTORY_SEP (lastc)
+         >= MAXPATHLEN)
+       {
+         errno = ENAMETOOLONG;
+         return -1;
+       }
+
+      sprintf (fullname, "%s%s%s",
+              dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", path);
+      path = fullname;
     }
 
+  if ((mode & F_OK) != 0 && IS_DIRECTORY_SEP (path[strlen (path) - 1]))
+    mode |= D_OK;
+
   return access (path, mode);
 }
 
index bdeaed0675b23b41432508f18935203297836ca6..c5b51bb6b0e29a997c91536fe5167df2d293be7f 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -3887,15 +3887,30 @@ int
 faccessat (int dirfd, const char * path, int mode, int flags)
 {
   DWORD attributes;
+  char fullname[MAX_UTF8_PATH];
 
+  /* Rely on a hack: an open directory is modeled as file descriptor 0,
+     and its actual file name is stored in dir_pathname by opendir.
+     This is good enough for the current usage in Emacs, but is fragile.  */
   if (dirfd != AT_FDCWD
       && !(IS_DIRECTORY_SEP (path[0])
           || IS_DEVICE_SEP (path[1])))
     {
-      errno = EBADF;
-      return -1;
+      char lastc = dir_pathname[strlen (dir_pathname) - 1];
+
+      if (_snprintf (fullname, sizeof fullname, "%s%s%s",
+                    dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", path)
+         < 0)
+       {
+         errno = ENAMETOOLONG;
+         return -1;
+       }
+      path = fullname;
     }
 
+  if (IS_DIRECTORY_SEP (path[strlen (path) - 1]) && (mode & F_OK) != 0)
+    mode |= D_OK;
+
   /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
      newer versions blow up when passed D_OK.  */
   path = map_w32_filename (path, NULL);