diff options
Diffstat (limited to 'src/dired.c')
| -rw-r--r-- | src/dired.c | 149 |
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 | ||
| 81 | static DIR * | 81 | static DIR * |
| 82 | open_directory (Lisp_Object dirname, int *fdp) | 82 | open_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. | |||
| 329 | If NOSORT is non-nil, the list is not sorted--its order is unpredictable. | 297 | If 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. |
| 365 | On MS-Windows, performance depends on `w32-get-true-file-attributes', | 333 | On MS-Windows, performance depends on `w32-get-true-file-attributes', |
| 366 | which see. */) | 334 | which 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 | ||
| 851 | DEFUN ("file-attributes", Ffile_attributes, Sfile_attributes, 1, 2, 0, | 820 | DEFUN ("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. |
| 853 | Value is nil if specified file cannot be opened. | 822 | Value is nil if specified file does not exist. |
| 854 | 823 | ||
| 855 | ID-FORMAT specifies the preferred format of attributes uid and gid (see | 824 | ID-FORMAT specifies the preferred format of attributes uid and gid (see |
| 856 | below) - valid values are `string' and `integer'. The latter is the | 825 | below) - 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 | ||
| 1034 | DEFUN ("file-attributes-lessp", Ffile_attributes_lessp, Sfile_attributes_lessp, 2, 2, 0, | 1002 | DEFUN ("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. |
| 1036 | Comparison is in lexicographic order and case is significant. */) | 1005 | Comparison is in lexicographic order and case is significant. */) |
| 1037 | (Lisp_Object f1, Lisp_Object f2) | 1006 | (Lisp_Object f1, Lisp_Object f2) |