aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dired.c86
-rw-r--r--src/kqueue.c4
-rw-r--r--src/sysdep.c2
3 files changed, 67 insertions, 25 deletions
diff --git a/src/dired.c b/src/dired.c
index 288ba6b1038..128493aff28 100644
--- a/src/dired.c
+++ b/src/dired.c
@@ -51,7 +51,8 @@ extern int is_slow_fs (const char *);
51#endif 51#endif
52 52
53static ptrdiff_t scmp (const char *, const char *, ptrdiff_t); 53static ptrdiff_t scmp (const char *, const char *, ptrdiff_t);
54static Lisp_Object file_attributes (int, char const *, Lisp_Object); 54static Lisp_Object file_attributes (int, char const *, Lisp_Object,
55 Lisp_Object, Lisp_Object);
55 56
56/* Return the number of bytes in DP's name. */ 57/* Return the number of bytes in DP's name. */
57static ptrdiff_t 58static ptrdiff_t
@@ -161,7 +162,7 @@ read_dirent (DIR *dir, Lisp_Object dirname)
161/* Function shared by Fdirectory_files and Fdirectory_files_and_attributes. 162/* Function shared by Fdirectory_files and Fdirectory_files_and_attributes.
162 If not ATTRS, return a list of directory filenames; 163 If not ATTRS, return a list of directory filenames;
163 if ATTRS, return a list of directory filenames and their attributes. 164 if ATTRS, return a list of directory filenames and their attributes.
164 In the latter case, ID_FORMAT is passed to Ffile_attributes. */ 165 In the latter case, pass ID_FORMAT to file_attributes. */
165 166
166Lisp_Object 167Lisp_Object
167directory_files_internal (Lisp_Object directory, Lisp_Object full, 168directory_files_internal (Lisp_Object directory, Lisp_Object full,
@@ -225,7 +226,7 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
225 if (attrs) 226 if (attrs)
226 { 227 {
227 /* Do this only once to avoid doing it (in w32.c:stat) for each 228 /* Do this only once to avoid doing it (in w32.c:stat) for each
228 file in the directory, when we call Ffile_attributes below. */ 229 file in the directory, when we call file_attributes below. */
229 record_unwind_protect (directory_files_internal_w32_unwind, 230 record_unwind_protect (directory_files_internal_w32_unwind,
230 Vw32_get_true_file_attributes); 231 Vw32_get_true_file_attributes);
231 w32_save = Vw32_get_true_file_attributes; 232 w32_save = Vw32_get_true_file_attributes;
@@ -304,7 +305,7 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
304 if (attrs) 305 if (attrs)
305 { 306 {
306 Lisp_Object fileattrs 307 Lisp_Object fileattrs
307 = file_attributes (fd, dp->d_name, id_format); 308 = file_attributes (fd, dp->d_name, directory, name, id_format);
308 list = Fcons (Fcons (finalname, fileattrs), list); 309 list = Fcons (Fcons (finalname, fileattrs), list);
309 } 310 }
310 else 311 else
@@ -351,7 +352,7 @@ If NOSORT is non-nil, the list is not sorted--its order is unpredictable.
351 return call5 (handler, Qdirectory_files, directory, 352 return call5 (handler, Qdirectory_files, directory,
352 full, match, nosort); 353 full, match, nosort);
353 354
354 return directory_files_internal (directory, full, match, nosort, 0, Qnil); 355 return directory_files_internal (directory, full, match, nosort, false, Qnil);
355} 356}
356 357
357DEFUN ("directory-files-and-attributes", Fdirectory_files_and_attributes, 358DEFUN ("directory-files-and-attributes", Fdirectory_files_and_attributes,
@@ -379,7 +380,8 @@ which see. */)
379 return call6 (handler, Qdirectory_files_and_attributes, 380 return call6 (handler, Qdirectory_files_and_attributes,
380 directory, full, match, nosort, id_format); 381 directory, full, match, nosort, id_format);
381 382
382 return directory_files_internal (directory, full, match, nosort, 1, id_format); 383 return directory_files_internal (directory, full, match, nosort,
384 true, id_format);
383} 385}
384 386
385 387
@@ -923,14 +925,17 @@ so last access time will always be midnight of that day. */)
923 } 925 }
924 926
925 encoded = ENCODE_FILE (filename); 927 encoded = ENCODE_FILE (filename);
926 return file_attributes (AT_FDCWD, SSDATA (encoded), id_format); 928 return file_attributes (AT_FDCWD, SSDATA (encoded), Qnil, filename,
929 id_format);
927} 930}
928 931
929static Lisp_Object 932static Lisp_Object
930file_attributes (int fd, char const *name, Lisp_Object id_format) 933file_attributes (int fd, char const *name,
934 Lisp_Object dirname, Lisp_Object filename,
935 Lisp_Object id_format)
931{ 936{
937 ptrdiff_t count = SPECPDL_INDEX ();
932 struct stat s; 938 struct stat s;
933 int lstat_result;
934 939
935 /* An array to hold the mode string generated by filemodestring, 940 /* An array to hold the mode string generated by filemodestring,
936 including its terminating space and null byte. */ 941 including its terminating space and null byte. */
@@ -938,22 +943,60 @@ file_attributes (int fd, char const *name, Lisp_Object id_format)
938 943
939 char *uname = NULL, *gname = NULL; 944 char *uname = NULL, *gname = NULL;
940 945
941#ifdef WINDOWSNT 946 int err = EINVAL;
942 /* We usually don't request accurate owner and group info, because
943 it can be very expensive on Windows to get that, and most callers
944 of 'lstat' don't need that. But here we do want that information
945 to be accurate. */
946 w32_stat_get_owner_group = 1;
947#endif
948 947
949 lstat_result = fstatat (fd, name, &s, AT_SYMLINK_NOFOLLOW); 948#ifdef O_PATH
949 int namefd = openat (fd, name, O_PATH | O_CLOEXEC | O_NOFOLLOW);
950 if (namefd < 0)
951 err = errno;
952 else
953 {
954 record_unwind_protect_int (close_file_unwind, namefd);
955 if (fstat (namefd, &s) != 0)
956 err = errno;
957 else
958 {
959 err = 0;
960 fd = namefd;
961 name = "";
962 }
963 }
964#endif
950 965
966 if (err == EINVAL)
967 {
968#ifdef WINDOWSNT
969 /* We usually don't request accurate owner and group info,
970 because it can be expensive on Windows to get that, and most
971 callers of 'lstat' don't need that. But here we do want that
972 information to be accurate. */
973 w32_stat_get_owner_group = 1;
974#endif
975 if (fstatat (fd, name, &s, AT_SYMLINK_NOFOLLOW) == 0)
976 err = 0;
951#ifdef WINDOWSNT 977#ifdef WINDOWSNT
952 w32_stat_get_owner_group = 0; 978 w32_stat_get_owner_group = 0;
953#endif 979#endif
980 }
954 981
955 if (lstat_result < 0) 982 if (err != 0)
956 return Qnil; 983 return unbind_to (count, Qnil);
984
985 Lisp_Object file_type;
986 if (S_ISLNK (s.st_mode))
987 {
988 /* On systems lacking O_PATH support there is a race if the
989 symlink is replaced between the call to fstatat and the call
990 to emacs_readlinkat. Detect this race unless the replacement
991 is also a symlink. */
992 file_type = emacs_readlinkat (fd, name);
993 if (NILP (file_type))
994 return unbind_to (count, Qnil);
995 }
996 else
997 file_type = S_ISDIR (s.st_mode) ? Qt : Qnil;
998
999 unbind_to (count, Qnil);
957 1000
958 if (!(NILP (id_format) || EQ (id_format, Qinteger))) 1001 if (!(NILP (id_format) || EQ (id_format, Qinteger)))
959 { 1002 {
@@ -964,8 +1007,7 @@ file_attributes (int fd, char const *name, Lisp_Object id_format)
964 filemodestring (&s, modes); 1007 filemodestring (&s, modes);
965 1008
966 return CALLN (Flist, 1009 return CALLN (Flist,
967 (S_ISLNK (s.st_mode) ? emacs_readlinkat (fd, name) 1010 file_type,
968 : S_ISDIR (s.st_mode) ? Qt : Qnil),
969 make_number (s.st_nlink), 1011 make_number (s.st_nlink),
970 (uname 1012 (uname
971 ? DECODE_SYSTEM (build_unibyte_string (uname)) 1013 ? DECODE_SYSTEM (build_unibyte_string (uname))
diff --git a/src/kqueue.c b/src/kqueue.c
index a8eb4cb797c..30922ef28b1 100644
--- a/src/kqueue.c
+++ b/src/kqueue.c
@@ -130,7 +130,7 @@ kqueue_compare_dir_list (Lisp_Object watch_object)
130 return; 130 return;
131 } 131 }
132 new_directory_files = 132 new_directory_files =
133 directory_files_internal (dir, Qnil, Qnil, Qnil, 1, Qnil); 133 directory_files_internal (dir, Qnil, Qnil, Qnil, true, Qnil);
134 new_dl = kqueue_directory_listing (new_directory_files); 134 new_dl = kqueue_directory_listing (new_directory_files);
135 135
136 /* Parse through the old list. */ 136 /* Parse through the old list. */
@@ -453,7 +453,7 @@ only when the upper directory of the renamed file is watched. */)
453 if (NILP (Ffile_directory_p (file))) 453 if (NILP (Ffile_directory_p (file)))
454 watch_object = list4 (watch_descriptor, file, flags, callback); 454 watch_object = list4 (watch_descriptor, file, flags, callback);
455 else { 455 else {
456 dir_list = directory_files_internal (file, Qnil, Qnil, Qnil, 1, Qnil); 456 dir_list = directory_files_internal (file, Qnil, Qnil, Qnil, true, Qnil);
457 watch_object = list5 (watch_descriptor, file, flags, callback, dir_list); 457 watch_object = list5 (watch_descriptor, file, flags, callback, dir_list);
458 } 458 }
459 watch_list = Fcons (watch_object, watch_list); 459 watch_list = Fcons (watch_object, watch_list);
diff --git a/src/sysdep.c b/src/sysdep.c
index 12e9c83ee90..b66a7453172 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -2930,7 +2930,7 @@ list_system_processes (void)
2930 process. */ 2930 process. */
2931 procdir = build_string ("/proc"); 2931 procdir = build_string ("/proc");
2932 match = build_string ("[0-9]+"); 2932 match = build_string ("[0-9]+");
2933 proclist = directory_files_internal (procdir, Qnil, match, Qt, 0, Qnil); 2933 proclist = directory_files_internal (procdir, Qnil, match, Qt, false, Qnil);
2934 2934
2935 /* `proclist' gives process IDs as strings. Destructively convert 2935 /* `proclist' gives process IDs as strings. Destructively convert
2936 each string into a number. */ 2936 each string into a number. */