aboutsummaryrefslogtreecommitdiffstats
path: root/src/dired.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dired.c')
-rw-r--r--src/dired.c149
1 files changed, 59 insertions, 90 deletions
diff --git a/src/dired.c b/src/dired.c
index 7bc4b83fd77..3768b6dbb7c 100644
--- a/src/dired.c
+++ b/src/dired.c
@@ -79,9 +79,9 @@ dirent_type (struct dirent *dp)
79} 79}
80 80
81static DIR * 81static DIR *
82open_directory (Lisp_Object dirname, int *fdp) 82open_directory (Lisp_Object dirname, Lisp_Object encoded_dirname, int *fdp)
83{ 83{
84 char *name = SSDATA (dirname); 84 char *name = SSDATA (encoded_dirname);
85 DIR *d; 85 DIR *d;
86 int fd, opendir_errno; 86 int fd, opendir_errno;
87 87
@@ -167,38 +167,31 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
167 Lisp_Object match, Lisp_Object nosort, bool attrs, 167 Lisp_Object match, Lisp_Object nosort, bool attrs,
168 Lisp_Object id_format) 168 Lisp_Object id_format)
169{ 169{
170 ptrdiff_t directory_nbytes; 170 if (!NILP (match))
171 Lisp_Object list, dirfilename, encoded_directory; 171 CHECK_STRING (match);
172 bool needsep = 0;
173 ptrdiff_t count = SPECPDL_INDEX ();
174#ifdef WINDOWSNT
175 Lisp_Object w32_save = Qnil;
176#endif
177 172
178 /* Don't let the compiler optimize away all copies of DIRECTORY, 173 /* Don't let the compiler optimize away all copies of DIRECTORY,
179 which would break GC; see Bug#16986. */ 174 which would break GC; see Bug#16986. */
180 Lisp_Object volatile directory_volatile = directory; 175 Lisp_Object volatile directory_volatile = directory;
181 176
182 /* Because of file name handlers, these functions might call 177 Lisp_Object dirfilename = Fdirectory_file_name (directory);
183 Ffuncall, and cause a GC. */
184 list = encoded_directory = dirfilename = Qnil;
185 dirfilename = Fdirectory_file_name (directory);
186 178
187 /* Note: ENCODE_FILE and DECODE_FILE can GC because they can run 179 /* Note: ENCODE_FILE and DECODE_FILE can GC because they can run
188 run_pre_post_conversion_on_str which calls Lisp directly and 180 run_pre_post_conversion_on_str which calls Lisp directly and
189 indirectly. */ 181 indirectly. */
190 dirfilename = ENCODE_FILE (dirfilename); 182 Lisp_Object encoded_dirfilename = ENCODE_FILE (dirfilename);
191 encoded_directory = ENCODE_FILE (directory);
192 183
193 int fd; 184 int fd;
194 DIR *d = open_directory (dirfilename, &fd); 185 DIR *d = open_directory (dirfilename, encoded_dirfilename, &fd);
195 186
196 /* Unfortunately, we can now invoke expand-file-name and 187 /* Unfortunately, we can now invoke expand-file-name and
197 file-attributes on filenames, both of which can throw, so we must 188 file-attributes on filenames, both of which can throw, so we must
198 do a proper unwind-protect. */ 189 do a proper unwind-protect. */
190 ptrdiff_t count = SPECPDL_INDEX ();
199 record_unwind_protect_ptr (directory_files_internal_unwind, d); 191 record_unwind_protect_ptr (directory_files_internal_unwind, d);
200 192
201#ifdef WINDOWSNT 193#ifdef WINDOWSNT
194 Lisp_Object w32_save = Qnil;
202 if (attrs) 195 if (attrs)
203 { 196 {
204 /* Do this only once to avoid doing it (in w32.c:stat) for each 197 /* Do this only once to avoid doing it (in w32.c:stat) for each
@@ -210,7 +203,7 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
210 { 203 {
211 /* w32.c:stat will notice these bindings and avoid calling 204 /* w32.c:stat will notice these bindings and avoid calling
212 GetDriveType for each file. */ 205 GetDriveType for each file. */
213 if (is_slow_fs (SSDATA (dirfilename))) 206 if (is_slow_fs (SSDATA (encoded_dirfilename)))
214 Vw32_get_true_file_attributes = Qnil; 207 Vw32_get_true_file_attributes = Qnil;
215 else 208 else
216 Vw32_get_true_file_attributes = Qt; 209 Vw32_get_true_file_attributes = Qt;
@@ -218,88 +211,63 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
218 } 211 }
219#endif 212#endif
220 213
221 directory_nbytes = SBYTES (directory); 214 ptrdiff_t directory_nbytes = SBYTES (directory);
222 re_match_object = Qt; 215 re_match_object = Qt;
223 216
224 /* Decide whether we need to add a directory separator. */ 217 /* Decide whether we need to add a directory separator. */
225 if (directory_nbytes == 0 218 bool needsep = (directory_nbytes == 0
226 || !IS_ANY_SEP (SREF (directory, directory_nbytes - 1))) 219 || !IS_ANY_SEP (SREF (directory, directory_nbytes - 1)));
227 needsep = 1;
228 220
229 /* Windows users want case-insensitive wildcards. */ 221 /* Windows users want case-insensitive wildcards. */
230 Lisp_Object case_table = 222 Lisp_Object case_table = Qnil;
231#ifdef WINDOWSNT 223#ifdef WINDOWSNT
232 BVAR (&buffer_defaults, case_canon_table) 224 case_table = BVAR (&buffer_defaults, case_canon_table);
233#else
234 Qnil
235#endif 225#endif
236 ;
237 226
238 if (!NILP (match)) 227 /* Read directory entries and accumulate them into LIST. */
239 CHECK_STRING (match); 228 Lisp_Object list = Qnil;
240
241 /* Loop reading directory entries. */
242 for (struct dirent *dp; (dp = read_dirent (d, directory)); ) 229 for (struct dirent *dp; (dp = read_dirent (d, directory)); )
243 { 230 {
244 ptrdiff_t len = dirent_namelen (dp); 231 ptrdiff_t len = dirent_namelen (dp);
245 Lisp_Object name = make_unibyte_string (dp->d_name, len); 232 Lisp_Object name = make_unibyte_string (dp->d_name, len);
246 Lisp_Object finalname = name; 233 Lisp_Object finalname = name;
247 234
248 /* Note: DECODE_FILE can GC; it should protect its argument, 235 /* This can GC. */
249 though. */
250 name = DECODE_FILE (name); 236 name = DECODE_FILE (name);
251 len = SBYTES (name);
252 237
253 /* Now that we have unwind_protect in place, we might as well
254 allow matching to be interrupted. */
255 maybe_quit (); 238 maybe_quit ();
256 239
257 bool wanted = (NILP (match) || 240 if (!NILP (match)
258 fast_string_match_internal ( 241 && fast_string_match_internal (match, name, case_table) < 0)
259 match, name, case_table) >= 0); 242 continue;
260 243
261 if (wanted) 244 Lisp_Object fileattrs UNINIT;
245 if (attrs)
262 { 246 {
263 if (!NILP (full)) 247 fileattrs = file_attributes (fd, dp->d_name, directory, name,
264 { 248 id_format);
265 Lisp_Object fullname; 249 if (NILP (fileattrs))
266 ptrdiff_t nbytes = len + directory_nbytes + needsep; 250 continue;
267 ptrdiff_t nchars; 251 }
268
269 fullname = make_uninit_multibyte_string (nbytes, nbytes);
270 memcpy (SDATA (fullname), SDATA (directory),
271 directory_nbytes);
272
273 if (needsep)
274 SSET (fullname, directory_nbytes, DIRECTORY_SEP);
275
276 memcpy (SDATA (fullname) + directory_nbytes + needsep,
277 SDATA (name), len);
278
279 nchars = multibyte_chars_in_text (SDATA (fullname), nbytes);
280
281 /* Some bug somewhere. */
282 if (nchars > nbytes)
283 emacs_abort ();
284
285 STRING_SET_CHARS (fullname, nchars);
286 if (nchars == nbytes)
287 STRING_SET_UNIBYTE (fullname);
288
289 finalname = fullname;
290 }
291 else
292 finalname = name;
293 252
294 if (attrs) 253 if (!NILP (full))
295 { 254 {
296 Lisp_Object fileattrs 255 ptrdiff_t name_nbytes = SBYTES (name);
297 = file_attributes (fd, dp->d_name, directory, name, id_format); 256 ptrdiff_t nbytes = directory_nbytes + needsep + name_nbytes;
298 list = Fcons (Fcons (finalname, fileattrs), list); 257 ptrdiff_t nchars = SCHARS (directory) + needsep + SCHARS (name);
299 } 258 finalname = make_uninit_multibyte_string (nchars, nbytes);
300 else 259 if (nchars == nbytes)
301 list = Fcons (finalname, list); 260 STRING_SET_UNIBYTE (finalname);
261 memcpy (SDATA (finalname), SDATA (directory), directory_nbytes);
262 if (needsep)
263 SSET (finalname, directory_nbytes, DIRECTORY_SEP);
264 memcpy (SDATA (finalname) + directory_nbytes + needsep,
265 SDATA (name), name_nbytes);
302 } 266 }
267 else
268 finalname = name;
269
270 list = Fcons (attrs ? Fcons (finalname, fileattrs) : finalname, list);
303 } 271 }
304 272
305 closedir (d); 273 closedir (d);
@@ -329,14 +297,14 @@ If MATCH is non-nil, mention only file names that match the regexp MATCH.
329If NOSORT is non-nil, the list is not sorted--its order is unpredictable. 297If NOSORT is non-nil, the list is not sorted--its order is unpredictable.
330 Otherwise, the list returned is sorted with `string-lessp'. 298 Otherwise, the list returned is sorted with `string-lessp'.
331 NOSORT is useful if you plan to sort the result yourself. */) 299 NOSORT is useful if you plan to sort the result yourself. */)
332 (Lisp_Object directory, Lisp_Object full, Lisp_Object match, Lisp_Object nosort) 300 (Lisp_Object directory, Lisp_Object full, Lisp_Object match,
301 Lisp_Object nosort)
333{ 302{
334 Lisp_Object handler;
335 directory = Fexpand_file_name (directory, Qnil); 303 directory = Fexpand_file_name (directory, Qnil);
336 304
337 /* If the file name has special constructs in it, 305 /* If the file name has special constructs in it,
338 call the corresponding file name handler. */ 306 call the corresponding file name handler. */
339 handler = Ffind_file_name_handler (directory, Qdirectory_files); 307 Lisp_Object handler = Ffind_file_name_handler (directory, Qdirectory_files);
340 if (!NILP (handler)) 308 if (!NILP (handler))
341 return call5 (handler, Qdirectory_files, directory, 309 return call5 (handler, Qdirectory_files, directory,
342 full, match, nosort); 310 full, match, nosort);
@@ -364,14 +332,15 @@ ID-FORMAT specifies the preferred format of attributes uid and gid, see
364`file-attributes' for further documentation. 332`file-attributes' for further documentation.
365On MS-Windows, performance depends on `w32-get-true-file-attributes', 333On MS-Windows, performance depends on `w32-get-true-file-attributes',
366which see. */) 334which see. */)
367 (Lisp_Object directory, Lisp_Object full, Lisp_Object match, Lisp_Object nosort, Lisp_Object id_format) 335 (Lisp_Object directory, Lisp_Object full, Lisp_Object match,
336 Lisp_Object nosort, Lisp_Object id_format)
368{ 337{
369 Lisp_Object handler;
370 directory = Fexpand_file_name (directory, Qnil); 338 directory = Fexpand_file_name (directory, Qnil);
371 339
372 /* If the file name has special constructs in it, 340 /* If the file name has special constructs in it,
373 call the corresponding file name handler. */ 341 call the corresponding file name handler. */
374 handler = Ffind_file_name_handler (directory, Qdirectory_files_and_attributes); 342 Lisp_Object handler
343 = Ffind_file_name_handler (directory, Qdirectory_files_and_attributes);
375 if (!NILP (handler)) 344 if (!NILP (handler))
376 return call6 (handler, Qdirectory_files_and_attributes, 345 return call6 (handler, Qdirectory_files_and_attributes,
377 directory, full, match, nosort, id_format); 346 directory, full, match, nosort, id_format);
@@ -508,7 +477,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag,
508 } 477 }
509 } 478 }
510 int fd; 479 int fd;
511 DIR *d = open_directory (encoded_dir, &fd); 480 DIR *d = open_directory (dirname, encoded_dir, &fd);
512 record_unwind_protect_ptr (directory_files_internal_unwind, d); 481 record_unwind_protect_ptr (directory_files_internal_unwind, d);
513 482
514 /* Loop reading directory entries. */ 483 /* Loop reading directory entries. */
@@ -850,7 +819,7 @@ stat_gname (struct stat *st)
850 819
851DEFUN ("file-attributes", Ffile_attributes, Sfile_attributes, 1, 2, 0, 820DEFUN ("file-attributes", Ffile_attributes, Sfile_attributes, 1, 2, 0,
852 doc: /* Return a list of attributes of file FILENAME. 821 doc: /* Return a list of attributes of file FILENAME.
853Value is nil if specified file cannot be opened. 822Value is nil if specified file does not exist.
854 823
855ID-FORMAT specifies the preferred format of attributes uid and gid (see 824ID-FORMAT specifies the preferred format of attributes uid and gid (see
856below) - valid values are `string' and `integer'. The latter is the 825below) - valid values are `string' and `integer'. The latter is the
@@ -970,15 +939,14 @@ file_attributes (int fd, char const *name,
970 information to be accurate. */ 939 information to be accurate. */
971 w32_stat_get_owner_group = 1; 940 w32_stat_get_owner_group = 1;
972#endif 941#endif
973 if (fstatat (fd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) 942 err = fstatat (fd, name, &s, AT_SYMLINK_NOFOLLOW) == 0 ? 0 : errno;
974 err = 0;
975#ifdef WINDOWSNT 943#ifdef WINDOWSNT
976 w32_stat_get_owner_group = 0; 944 w32_stat_get_owner_group = 0;
977#endif 945#endif
978 } 946 }
979 947
980 if (err != 0) 948 if (err != 0)
981 return unbind_to (count, Qnil); 949 return unbind_to (count, file_attribute_errno (filename, err));
982 950
983 Lisp_Object file_type; 951 Lisp_Object file_type;
984 if (S_ISLNK (s.st_mode)) 952 if (S_ISLNK (s.st_mode))
@@ -987,7 +955,7 @@ file_attributes (int fd, char const *name,
987 symlink is replaced between the call to fstatat and the call 955 symlink is replaced between the call to fstatat and the call
988 to emacs_readlinkat. Detect this race unless the replacement 956 to emacs_readlinkat. Detect this race unless the replacement
989 is also a symlink. */ 957 is also a symlink. */
990 file_type = emacs_readlinkat (fd, name); 958 file_type = check_emacs_readlinkat (fd, filename, name);
991 if (NILP (file_type)) 959 if (NILP (file_type))
992 return unbind_to (count, Qnil); 960 return unbind_to (count, Qnil);
993 } 961 }
@@ -1031,7 +999,8 @@ file_attributes (int fd, char const *name,
1031 INT_TO_INTEGER (s.st_dev)); 999 INT_TO_INTEGER (s.st_dev));
1032} 1000}
1033 1001
1034DEFUN ("file-attributes-lessp", Ffile_attributes_lessp, Sfile_attributes_lessp, 2, 2, 0, 1002DEFUN ("file-attributes-lessp", Ffile_attributes_lessp,
1003 Sfile_attributes_lessp, 2, 2, 0,
1035 doc: /* Return t if first arg file attributes list is less than second. 1004 doc: /* Return t if first arg file attributes list is less than second.
1036Comparison is in lexicographic order and case is significant. */) 1005Comparison is in lexicographic order and case is significant. */)
1037 (Lisp_Object f1, Lisp_Object f2) 1006 (Lisp_Object f1, Lisp_Object f2)