emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 697be62: Make file-accessible-directory-p reliable


From: Eli Zaretskii
Subject: [Emacs-diffs] master 697be62: Make file-accessible-directory-p reliable on MS-Windows
Date: Mon, 31 Aug 2015 14:49:26 +0000

branch: master
commit 697be62c5f2b86e8ad93dfcaa0df07890c24d989
Author: Eli Zaretskii <address@hidden>
Commit: Eli Zaretskii <address@hidden>

    Make file-accessible-directory-p reliable on MS-Windows
    
    * src/w32.c (w32_accessible_directory_p): New function.
    * src/w32.h (w32_accessible_directory_p): Add prototype.
    * src/fileio.c (file_accessible_directory_p) [WINDOWSNT]: Call
    w32_accessible_directory_p to test a directory for accessibility
    by the current user.  (Bug#21346)
    (Ffile_accessible_directory_p): Remove the w32 specific caveat
    from the doc string.
---
 src/fileio.c |   22 +++++++++++++---------
 src/w32.c    |   51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/w32.h    |    1 +
 3 files changed, 65 insertions(+), 9 deletions(-)

diff --git a/src/fileio.c b/src/fileio.c
index debd1f3..a36dfbc 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -2655,11 +2655,7 @@ and the directory must allow you to open files in it.  
In order to use a
 directory as a buffer's current directory, this predicate must return true.
 A directory name spec may be given instead; then the value is t
 if the directory so specified exists and really is a readable and
-searchable directory.
-
-The result might be a false positive on MS-Windows in some rare cases,
-i.e., this function could return t for a directory that is not
-accessible by the current user.  */)
+searchable directory.  */)
   (Lisp_Object filename)
 {
   Lisp_Object absname;
@@ -2689,10 +2685,18 @@ bool
 file_accessible_directory_p (Lisp_Object file)
 {
 #ifdef DOS_NT
-  /* There's no need to test whether FILE is searchable, as the
-     searchable/executable bit is invented on DOS_NT platforms.  */
+# ifdef WINDOWSNT
+  /* We need a special-purpose test because (a) NTFS security data is
+     not reflected in Posix-style mode bits, and (b) the trick with
+     accessing "DIR/.", used below on Posix hosts, doesn't work on
+     Windows, because "DIR/." is normalized to just "DIR" before
+     hitting the disk.  */
+  return (SBYTES (file) == 0
+         || w32_accessible_directory_p (SSDATA (file), SBYTES (file)));
+# else /* MSDOS */
   return file_directory_p (SSDATA (file));
-#else
+# endif         /* MSDOS */
+#else   /* !DOS_NT */
   /* On POSIXish platforms, use just one system call; this avoids a
      race and is typically faster.  */
   const char *data = SSDATA (file);
@@ -2725,7 +2729,7 @@ file_accessible_directory_p (Lisp_Object file)
   SAFE_FREE ();
   errno = saved_errno;
   return ok;
-#endif
+#endif /* !DOS_NT */
 }
 
 DEFUN ("file-regular-p", Ffile_regular_p, Sfile_regular_p, 1, 1, 0,
diff --git a/src/w32.c b/src/w32.c
index b421667..60fbe92 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -3847,6 +3847,57 @@ faccessat (int dirfd, const char * path, int mode, int 
flags)
   return 0;
 }
 
+/* A special test for DIRNAME being a directory accessible by the
+   current user.  This is needed because the security permissions in
+   directory's ACLs are not visible in the Posix-style mode bits
+   returned by 'stat' and in attributes returned by GetFileAttributes.
+   So a directory would seem like it's readable by the current user,
+   but will in fact error out with EACCES when they actually try.  */
+int
+w32_accessible_directory_p (const char *dirname, ptrdiff_t dirlen)
+{
+  char pattern[MAX_UTF8_PATH];
+  bool last_slash = dirlen > 0 && IS_DIRECTORY_SEP (dirname[dirlen - 1]);
+  HANDLE dh;
+
+  strcpy (pattern, map_w32_filename (dirname, NULL));
+
+  /* Note: No need to resolve symlinks in FILENAME, because FindFirst
+     opens the directory that is the target of a symlink.  */
+  if (w32_unicode_filenames)
+    {
+      wchar_t pat_w[MAX_PATH + 2];
+      WIN32_FIND_DATAW dfd_w;
+
+      filename_to_utf16 (pattern, pat_w);
+      if (!last_slash)
+       wcscat (pat_w, L"\\");
+      wcscat (pat_w, L"*");
+      dh = FindFirstFileW (pat_w, &dfd_w);
+    }
+  else
+    {
+      char pat_a[MAX_PATH + 2];
+      WIN32_FIND_DATAA dfd_a;
+
+      filename_to_ansi (pattern, pat_a);
+      if (!last_slash)
+       strcpy (pat_a, "\\");
+      strcat (pat_a, "*");
+      /* In case DIRNAME cannot be expressed in characters from the
+        current ANSI codepage.  */
+      if (_mbspbrk (pat_a, "?"))
+       dh = INVALID_HANDLE_VALUE;
+      else
+       dh = FindFirstFileA (pat_a, &dfd_a);
+    }
+
+  if (dh == INVALID_HANDLE_VALUE)
+    return 0;
+  FindClose (dh);
+  return 1;
+}
+
 /* A version of 'access' to be used locally with file names in
    locale-specific encoding.  Does not resolve symlinks and does not
    support file names on FAT12 and FAT16 volumes, but that's OK, since
diff --git a/src/w32.h b/src/w32.h
index 338cb06..2c71150 100644
--- a/src/w32.h
+++ b/src/w32.h
@@ -195,6 +195,7 @@ extern int  filename_to_utf16 (const char *, wchar_t *);
 extern int  codepage_for_filenames (CPINFO *);
 extern Lisp_Object ansi_encode_filename (Lisp_Object);
 extern int  w32_copy_file (const char *, const char *, int, int, int);
+extern int  w32_accessible_directory_p (const char *, ptrdiff_t);
 
 extern BOOL init_winsock (int load_now);
 extern void srandom (int);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]