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 /src/fileio.c | |
| 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).
Diffstat (limited to 'src/fileio.c')
| -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, |