aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2019-09-15 22:15:04 -0700
committerPaul Eggert2019-09-15 22:15:28 -0700
commitbe828883475eddff0bb8cf6825f0d3383391c122 (patch)
treea187ddd00d189fea525498c07cf4c4e28768bb08
parent5711c076dc63ecc0907f2b9cfe04035e0bd6a0b4 (diff)
downloademacs-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.c86
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. */
135static Lisp_Object Vwrite_region_annotation_buffers; 135static Lisp_Object Vwrite_region_annotation_buffers;
136 136
137static Lisp_Object file_name_directory (Lisp_Object);
137static bool a_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, 138static bool a_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t,
138 Lisp_Object *, struct coding_system *); 139 Lisp_Object *, struct coding_system *);
139static bool e_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, 140static 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
366static Lisp_Object
367file_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
2384static bool 2385static int
2385file_name_case_insensitive_p (const char *filename) 2386file_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
2446DEFUN ("rename-file", Frename_file, Srename_file, 2, 3, 2460DEFUN ("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,