diff options
| author | Paul Eggert | 2019-09-15 22:15:04 -0700 |
|---|---|---|
| committer | Paul Eggert | 2019-09-15 22:15:28 -0700 |
| commit | be828883475eddff0bb8cf6825f0d3383391c122 (patch) | |
| tree | a187ddd00d189fea525498c07cf4c4e28768bb08 | |
| parent | 5711c076dc63ecc0907f2b9cfe04035e0bd6a0b4 (diff) | |
| download | emacs-be828883475eddff0bb8cf6825f0d3383391c122.tar.gz emacs-be828883475eddff0bb8cf6825f0d3383391c122.zip | |
Fix some file-name-case-insensitive glitches
* src/fileio.c (file_name_directory): New static function,
broken out of Ffile_name_directory.
(file_name_case_insensitive_err, Ffile_writable_p, Fdo_auto_save):
Use it.
(file_name_case_insensitive_err): Rename from
file_name_case_insensitive_p. Accept an unencoded Lisp_Object
rather than an encoded char *, so that platforms other than
Cygwin and macOS need not encode the file name. Return an int
-1, 0, errno rather than a bool (setting errno if false),
so that the caller can distinguish an error from false.
All callers changed.
(Ffile_name_case_insensitive_p): Don’t issue system calls on
platforms other than Cygwin and macOS. Fix bug that broke the
attempt to move up the filesystem tree (it moved up only one
level).
| -rw-r--r-- | src/fileio.c | 86 |
1 files changed, 50 insertions, 36 deletions
diff --git a/src/fileio.c b/src/fileio.c index 34afbc23da7..c129f19872e 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -134,6 +134,7 @@ static dev_t timestamp_file_system; | |||
| 134 | is added here. */ | 134 | is added here. */ |
| 135 | static Lisp_Object Vwrite_region_annotation_buffers; | 135 | static Lisp_Object Vwrite_region_annotation_buffers; |
| 136 | 136 | ||
| 137 | static Lisp_Object file_name_directory (Lisp_Object); | ||
| 137 | static bool a_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, | 138 | static bool a_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, |
| 138 | Lisp_Object *, struct coding_system *); | 139 | Lisp_Object *, struct coding_system *); |
| 139 | static bool e_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, | 140 | static bool e_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, |
| @@ -356,6 +357,15 @@ Given a Unix syntax file name, returns a string ending in slash. */) | |||
| 356 | return STRINGP (handled_name) ? handled_name : Qnil; | 357 | return STRINGP (handled_name) ? handled_name : Qnil; |
| 357 | } | 358 | } |
| 358 | 359 | ||
| 360 | return file_name_directory (filename); | ||
| 361 | } | ||
| 362 | |||
| 363 | /* Return the directory component of FILENAME, or nil if FILENAME does | ||
| 364 | not contain a directory component. */ | ||
| 365 | |||
| 366 | static Lisp_Object | ||
| 367 | file_name_directory (Lisp_Object filename) | ||
| 368 | { | ||
| 359 | char *beg = SSDATA (filename); | 369 | char *beg = SSDATA (filename); |
| 360 | char const *p = beg + SBYTES (filename); | 370 | char const *p = beg + SBYTES (filename); |
| 361 | 371 | ||
| @@ -2369,41 +2379,48 @@ internal_delete_file (Lisp_Object filename) | |||
| 2369 | return NILP (tem); | 2379 | return NILP (tem); |
| 2370 | } | 2380 | } |
| 2371 | 2381 | ||
| 2372 | /* Filesystems are case-sensitive on all supported systems except | 2382 | /* Return -1 if FILE is a case-insensitive file name, 0 if not, |
| 2373 | MS-Windows, MS-DOS, Cygwin, and Mac OS X. They are always | 2383 | and a positive errno value if the result cannot be determined. */ |
| 2374 | case-insensitive on the first two, but they may or may not be | ||
| 2375 | case-insensitive on Cygwin and OS X. The following function | ||
| 2376 | attempts to provide a runtime test on those two systems. If the | ||
| 2377 | test is not conclusive, we assume case-insensitivity on Cygwin and | ||
| 2378 | case-sensitivity on Mac OS X. | ||
| 2379 | |||
| 2380 | FIXME: Mounted filesystems on Posix hosts, like Samba shares or | ||
| 2381 | NFS-mounted Windows volumes, might be case-insensitive. Can we | ||
| 2382 | detect this? */ | ||
| 2383 | 2384 | ||
| 2384 | static bool | 2385 | static int |
| 2385 | file_name_case_insensitive_p (const char *filename) | 2386 | file_name_case_insensitive_err (Lisp_Object file) |
| 2386 | { | 2387 | { |
| 2387 | /* Use pathconf with _PC_CASE_INSENSITIVE or _PC_CASE_SENSITIVE if | 2388 | /* Filesystems are case-sensitive on all supported systems except |
| 2388 | those flags are available. As of this writing (2017-05-20), | 2389 | MS-Windows, MS-DOS, Cygwin, and macOS. They are always |
| 2390 | case-insensitive on the first two, but they may or may not be | ||
| 2391 | case-insensitive on Cygwin and macOS so do a runtime test on | ||
| 2392 | those two systems. If the test is not conclusive, assume | ||
| 2393 | case-insensitivity on Cygwin and case-sensitivity on macOS. | ||
| 2394 | |||
| 2395 | FIXME: Mounted filesystems on Posix hosts, like Samba shares or | ||
| 2396 | NFS-mounted Windows volumes, might be case-insensitive. Can we | ||
| 2397 | detect this? | ||
| 2398 | |||
| 2399 | Use pathconf with _PC_CASE_INSENSITIVE or _PC_CASE_SENSITIVE if | ||
| 2400 | those flags are available. As of this writing (2019-09-15), | ||
| 2389 | Cygwin is the only platform known to support the former (starting | 2401 | Cygwin is the only platform known to support the former (starting |
| 2390 | with Cygwin-2.6.1), and macOS is the only platform known to | 2402 | with Cygwin-2.6.1), and macOS is the only platform known to |
| 2391 | support the latter. */ | 2403 | support the latter. */ |
| 2392 | 2404 | ||
| 2393 | #ifdef _PC_CASE_INSENSITIVE | 2405 | #if defined _PC_CASE_INSENSITIVE || defined _PC_CASE_SENSITIVE |
| 2406 | char *filename = SSDATA (ENCODE_FILE (file)); | ||
| 2407 | # ifdef _PC_CASE_INSENSITIVE | ||
| 2394 | long int res = pathconf (filename, _PC_CASE_INSENSITIVE); | 2408 | long int res = pathconf (filename, _PC_CASE_INSENSITIVE); |
| 2395 | if (res >= 0) | 2409 | if (res >= 0) |
| 2396 | return res > 0; | 2410 | return - (res > 0); |
| 2397 | #elif defined _PC_CASE_SENSITIVE | 2411 | # else |
| 2398 | long int res = pathconf (filename, _PC_CASE_SENSITIVE); | 2412 | long int res = pathconf (filename, _PC_CASE_SENSITIVE); |
| 2399 | if (res >= 0) | 2413 | if (res >= 0) |
| 2400 | return res == 0; | 2414 | return - (res == 0); |
| 2415 | # endif | ||
| 2416 | if (errno != EINVAL) | ||
| 2417 | return errno; | ||
| 2401 | #endif | 2418 | #endif |
| 2402 | 2419 | ||
| 2403 | #if defined CYGWIN || defined DOS_NT | 2420 | #if defined CYGWIN || defined DOS_NT |
| 2404 | return true; | 2421 | return -1; |
| 2405 | #else | 2422 | #else |
| 2406 | return false; | 2423 | return 0; |
| 2407 | #endif | 2424 | #endif |
| 2408 | } | 2425 | } |
| 2409 | 2426 | ||
| @@ -2426,21 +2443,18 @@ The arg must be a string. */) | |||
| 2426 | 2443 | ||
| 2427 | /* If the file doesn't exist, move up the filesystem tree until we | 2444 | /* If the file doesn't exist, move up the filesystem tree until we |
| 2428 | reach an existing directory or the root. */ | 2445 | reach an existing directory or the root. */ |
| 2429 | if (NILP (Ffile_exists_p (filename))) | 2446 | while (true) |
| 2430 | { | 2447 | { |
| 2431 | filename = Ffile_name_directory (filename); | 2448 | int err = file_name_case_insensitive_err (filename); |
| 2432 | while (NILP (Ffile_exists_p (filename))) | 2449 | if (! (err == ENOENT || err == ENOTDIR)) |
| 2433 | { | 2450 | return err < 0 ? Qt : Qnil; |
| 2434 | Lisp_Object newname = expand_and_dir_to_file (filename); | 2451 | Lisp_Object parent = file_name_directory (filename); |
| 2435 | /* Avoid infinite loop if the root is reported as non-existing | 2452 | /* Avoid infinite loop if the root is reported as non-existing |
| 2436 | (impossible?). */ | 2453 | (impossible?). */ |
| 2437 | if (!NILP (Fstring_equal (newname, filename))) | 2454 | if (!NILP (Fstring_equal (parent, filename))) |
| 2438 | break; | 2455 | return Qnil; |
| 2439 | filename = newname; | 2456 | filename = parent; |
| 2440 | } | ||
| 2441 | } | 2457 | } |
| 2442 | filename = ENCODE_FILE (filename); | ||
| 2443 | return file_name_case_insensitive_p (SSDATA (filename)) ? Qt : Qnil; | ||
| 2444 | } | 2458 | } |
| 2445 | 2459 | ||
| 2446 | DEFUN ("rename-file", Frename_file, Srename_file, 2, 3, | 2460 | DEFUN ("rename-file", Frename_file, Srename_file, 2, 3, |
| @@ -2790,7 +2804,7 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, | |||
| 2790 | if (errno != ENOENT) | 2804 | if (errno != ENOENT) |
| 2791 | return Qnil; | 2805 | return Qnil; |
| 2792 | 2806 | ||
| 2793 | dir = Ffile_name_directory (absname); | 2807 | dir = file_name_directory (absname); |
| 2794 | eassert (!NILP (dir)); | 2808 | eassert (!NILP (dir)); |
| 2795 | #ifdef MSDOS | 2809 | #ifdef MSDOS |
| 2796 | dir = Fdirectory_file_name (dir); | 2810 | dir = Fdirectory_file_name (dir); |
| @@ -5822,7 +5836,7 @@ A non-nil CURRENT-ONLY argument means save only current buffer. */) | |||
| 5822 | if (!NILP (Vrun_hooks)) | 5836 | if (!NILP (Vrun_hooks)) |
| 5823 | { | 5837 | { |
| 5824 | Lisp_Object dir; | 5838 | Lisp_Object dir; |
| 5825 | dir = Ffile_name_directory (listfile); | 5839 | dir = file_name_directory (listfile); |
| 5826 | if (NILP (Ffile_directory_p (dir))) | 5840 | if (NILP (Ffile_directory_p (dir))) |
| 5827 | internal_condition_case_1 (do_auto_save_make_dir, | 5841 | internal_condition_case_1 (do_auto_save_make_dir, |
| 5828 | dir, Qt, | 5842 | dir, Qt, |