* 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.
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;
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);
SAFE_FREE ();
errno = saved_errno;
return ok;
-#endif
+#endif /* !DOS_NT */
}
DEFUN ("file-regular-p", Ffile_regular_p, Sfile_regular_p, 1, 1, 0,
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
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);