diff options
| author | Eli Zaretskii | 2015-08-31 17:48:26 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2015-08-31 17:48:26 +0300 |
| commit | 697be62c5f2b86e8ad93dfcaa0df07890c24d989 (patch) | |
| tree | 5e6b5d4ea9cd75bbc2eca0d7831b1364b6bc333a /src | |
| parent | 8af8355c3f72500986f6f10b62714b228d6f35ee (diff) | |
| download | emacs-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.c | 22 | ||||
| -rw-r--r-- | src/w32.c | 51 | ||||
| -rw-r--r-- | src/w32.h | 1 |
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 | |||
| 2655 | directory as a buffer's current directory, this predicate must return true. | 2655 | directory as a buffer's current directory, this predicate must return true. |
| 2656 | A directory name spec may be given instead; then the value is t | 2656 | A directory name spec may be given instead; then the value is t |
| 2657 | if the directory so specified exists and really is a readable and | 2657 | if the directory so specified exists and really is a readable and |
| 2658 | searchable directory. | 2658 | searchable directory. */) |
| 2659 | |||
| 2660 | The result might be a false positive on MS-Windows in some rare cases, | ||
| 2661 | i.e., this function could return t for a directory that is not | ||
| 2662 | accessible 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 | |||
| 2689 | file_accessible_directory_p (Lisp_Object file) | 2685 | file_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 | ||
| 2731 | DEFUN ("file-regular-p", Ffile_regular_p, Sfile_regular_p, 1, 1, 0, | 2735 | DEFUN ("file-regular-p", Ffile_regular_p, Sfile_regular_p, 1, 1, 0, |
| @@ -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. */ | ||
| 3856 | int | ||
| 3857 | w32_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 |
| @@ -195,6 +195,7 @@ extern int filename_to_utf16 (const char *, wchar_t *); | |||
| 195 | extern int codepage_for_filenames (CPINFO *); | 195 | extern int codepage_for_filenames (CPINFO *); |
| 196 | extern Lisp_Object ansi_encode_filename (Lisp_Object); | 196 | extern Lisp_Object ansi_encode_filename (Lisp_Object); |
| 197 | extern int w32_copy_file (const char *, const char *, int, int, int); | 197 | extern int w32_copy_file (const char *, const char *, int, int, int); |
| 198 | extern int w32_accessible_directory_p (const char *, ptrdiff_t); | ||
| 198 | 199 | ||
| 199 | extern BOOL init_winsock (int load_now); | 200 | extern BOOL init_winsock (int load_now); |
| 200 | extern void srandom (int); | 201 | extern void srandom (int); |