aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2015-08-31 17:48:26 +0300
committerEli Zaretskii2015-08-31 17:48:26 +0300
commit697be62c5f2b86e8ad93dfcaa0df07890c24d989 (patch)
tree5e6b5d4ea9cd75bbc2eca0d7831b1364b6bc333a /src
parent8af8355c3f72500986f6f10b62714b228d6f35ee (diff)
downloademacs-697be62c5f2b86e8ad93dfcaa0df07890c24d989.tar.gz
emacs-697be62c5f2b86e8ad93dfcaa0df07890c24d989.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/fileio.c22
-rw-r--r--src/w32.c51
-rw-r--r--src/w32.h1
3 files changed, 65 insertions, 9 deletions
diff --git a/src/fileio.c b/src/fileio.c
index debd1f30a4f..a36dfbcfa36 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
2655directory as a buffer's current directory, this predicate must return true. 2655directory as a buffer's current directory, this predicate must return true.
2656A directory name spec may be given instead; then the value is t 2656A directory name spec may be given instead; then the value is t
2657if the directory so specified exists and really is a readable and 2657if the directory so specified exists and really is a readable and
2658searchable directory. 2658searchable directory. */)
2659
2660The result might be a false positive on MS-Windows in some rare cases,
2661i.e., this function could return t for a directory that is not
2662accessible by the current user. */)
2663 (Lisp_Object filename) 2659 (Lisp_Object filename)
2664{ 2660{
2665 Lisp_Object absname; 2661 Lisp_Object absname;
@@ -2689,10 +2685,18 @@ bool
2689file_accessible_directory_p (Lisp_Object file) 2685file_accessible_directory_p (Lisp_Object file)
2690{ 2686{
2691#ifdef DOS_NT 2687#ifdef DOS_NT
2692 /* There's no need to test whether FILE is searchable, as the 2688# ifdef WINDOWSNT
2693 searchable/executable bit is invented on DOS_NT platforms. */ 2689 /* We need a special-purpose test because (a) NTFS security data is
2690 not reflected in Posix-style mode bits, and (b) the trick with
2691 accessing "DIR/.", used below on Posix hosts, doesn't work on
2692 Windows, because "DIR/." is normalized to just "DIR" before
2693 hitting the disk. */
2694 return (SBYTES (file) == 0
2695 || w32_accessible_directory_p (SSDATA (file), SBYTES (file)));
2696# else /* MSDOS */
2694 return file_directory_p (SSDATA (file)); 2697 return file_directory_p (SSDATA (file));
2695#else 2698# endif /* MSDOS */
2699#else /* !DOS_NT */
2696 /* On POSIXish platforms, use just one system call; this avoids a 2700 /* On POSIXish platforms, use just one system call; this avoids a
2697 race and is typically faster. */ 2701 race and is typically faster. */
2698 const char *data = SSDATA (file); 2702 const char *data = SSDATA (file);
@@ -2725,7 +2729,7 @@ file_accessible_directory_p (Lisp_Object file)
2725 SAFE_FREE (); 2729 SAFE_FREE ();
2726 errno = saved_errno; 2730 errno = saved_errno;
2727 return ok; 2731 return ok;
2728#endif 2732#endif /* !DOS_NT */
2729} 2733}
2730 2734
2731DEFUN ("file-regular-p", Ffile_regular_p, Sfile_regular_p, 1, 1, 0, 2735DEFUN ("file-regular-p", Ffile_regular_p, Sfile_regular_p, 1, 1, 0,
diff --git a/src/w32.c b/src/w32.c
index b421667e241..60fbe92e082 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -3847,6 +3847,57 @@ faccessat (int dirfd, const char * path, int mode, int flags)
3847 return 0; 3847 return 0;
3848} 3848}
3849 3849
3850/* A special test for DIRNAME being a directory accessible by the
3851 current user. This is needed because the security permissions in
3852 directory's ACLs are not visible in the Posix-style mode bits
3853 returned by 'stat' and in attributes returned by GetFileAttributes.
3854 So a directory would seem like it's readable by the current user,
3855 but will in fact error out with EACCES when they actually try. */
3856int
3857w32_accessible_directory_p (const char *dirname, ptrdiff_t dirlen)
3858{
3859 char pattern[MAX_UTF8_PATH];
3860 bool last_slash = dirlen > 0 && IS_DIRECTORY_SEP (dirname[dirlen - 1]);
3861 HANDLE dh;
3862
3863 strcpy (pattern, map_w32_filename (dirname, NULL));
3864
3865 /* Note: No need to resolve symlinks in FILENAME, because FindFirst
3866 opens the directory that is the target of a symlink. */
3867 if (w32_unicode_filenames)
3868 {
3869 wchar_t pat_w[MAX_PATH + 2];
3870 WIN32_FIND_DATAW dfd_w;
3871
3872 filename_to_utf16 (pattern, pat_w);
3873 if (!last_slash)
3874 wcscat (pat_w, L"\\");
3875 wcscat (pat_w, L"*");
3876 dh = FindFirstFileW (pat_w, &dfd_w);
3877 }
3878 else
3879 {
3880 char pat_a[MAX_PATH + 2];
3881 WIN32_FIND_DATAA dfd_a;
3882
3883 filename_to_ansi (pattern, pat_a);
3884 if (!last_slash)
3885 strcpy (pat_a, "\\");
3886 strcat (pat_a, "*");
3887 /* In case DIRNAME cannot be expressed in characters from the
3888 current ANSI codepage. */
3889 if (_mbspbrk (pat_a, "?"))
3890 dh = INVALID_HANDLE_VALUE;
3891 else
3892 dh = FindFirstFileA (pat_a, &dfd_a);
3893 }
3894
3895 if (dh == INVALID_HANDLE_VALUE)
3896 return 0;
3897 FindClose (dh);
3898 return 1;
3899}
3900
3850/* A version of 'access' to be used locally with file names in 3901/* A version of 'access' to be used locally with file names in
3851 locale-specific encoding. Does not resolve symlinks and does not 3902 locale-specific encoding. Does not resolve symlinks and does not
3852 support file names on FAT12 and FAT16 volumes, but that's OK, since 3903 support file names on FAT12 and FAT16 volumes, but that's OK, since
diff --git a/src/w32.h b/src/w32.h
index 338cb06b193..2c711502593 100644
--- a/src/w32.h
+++ b/src/w32.h
@@ -195,6 +195,7 @@ extern int filename_to_utf16 (const char *, wchar_t *);
195extern int codepage_for_filenames (CPINFO *); 195extern int codepage_for_filenames (CPINFO *);
196extern Lisp_Object ansi_encode_filename (Lisp_Object); 196extern Lisp_Object ansi_encode_filename (Lisp_Object);
197extern int w32_copy_file (const char *, const char *, int, int, int); 197extern int w32_copy_file (const char *, const char *, int, int, int);
198extern int w32_accessible_directory_p (const char *, ptrdiff_t);
198 199
199extern BOOL init_winsock (int load_now); 200extern BOOL init_winsock (int load_now);
200extern void srandom (int); 201extern void srandom (int);