emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master be82888: Fix some file-name-case-insensitive glitch


From: Paul Eggert
Subject: [Emacs-diffs] master be82888: Fix some file-name-case-insensitive glitches
Date: Mon, 16 Sep 2019 01:15:32 -0400 (EDT)

branch: master
commit be828883475eddff0bb8cf6825f0d3383391c122
Author: Paul Eggert <address@hidden>
Commit: Paul Eggert <address@hidden>

    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).
---
 src/fileio.c | 86 +++++++++++++++++++++++++++++++++++-------------------------
 1 file changed, 50 insertions(+), 36 deletions(-)

diff --git a/src/fileio.c b/src/fileio.c
index 34afbc2..c129f19 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -134,6 +134,7 @@ static dev_t timestamp_file_system;
    is added here.  */
 static Lisp_Object Vwrite_region_annotation_buffers;
 
+static Lisp_Object file_name_directory (Lisp_Object);
 static bool a_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t,
                     Lisp_Object *, struct coding_system *);
 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.  */)
       return STRINGP (handled_name) ? handled_name : Qnil;
     }
 
+  return file_name_directory (filename);
+}
+
+/* Return the directory component of FILENAME, or nil if FILENAME does
+   not contain a directory component.  */
+
+static Lisp_Object
+file_name_directory (Lisp_Object filename)
+{
   char *beg = SSDATA (filename);
   char const *p = beg + SBYTES (filename);
 
@@ -2369,41 +2379,48 @@ internal_delete_file (Lisp_Object filename)
   return NILP (tem);
 }
 
-/* Filesystems are case-sensitive on all supported systems except
-   MS-Windows, MS-DOS, Cygwin, and Mac OS X.  They are always
-   case-insensitive on the first two, but they may or may not be
-   case-insensitive on Cygwin and OS X.  The following function
-   attempts to provide a runtime test on those two systems.  If the
-   test is not conclusive, we assume case-insensitivity on Cygwin and
-   case-sensitivity on Mac OS X.
-
-   FIXME: Mounted filesystems on Posix hosts, like Samba shares or
-   NFS-mounted Windows volumes, might be case-insensitive.  Can we
-   detect this?  */
+/* Return -1 if FILE is a case-insensitive file name, 0 if not,
+   and a positive errno value if the result cannot be determined.  */
 
-static bool
-file_name_case_insensitive_p (const char *filename)
+static int
+file_name_case_insensitive_err (Lisp_Object file)
 {
-  /* Use pathconf with _PC_CASE_INSENSITIVE or _PC_CASE_SENSITIVE if
-     those flags are available.  As of this writing (2017-05-20),
+  /* Filesystems are case-sensitive on all supported systems except
+     MS-Windows, MS-DOS, Cygwin, and macOS.  They are always
+     case-insensitive on the first two, but they may or may not be
+     case-insensitive on Cygwin and macOS so do a runtime test on
+     those two systems.  If the test is not conclusive, assume
+     case-insensitivity on Cygwin and case-sensitivity on macOS.
+
+     FIXME: Mounted filesystems on Posix hosts, like Samba shares or
+     NFS-mounted Windows volumes, might be case-insensitive.  Can we
+     detect this?
+
+     Use pathconf with _PC_CASE_INSENSITIVE or _PC_CASE_SENSITIVE if
+     those flags are available.  As of this writing (2019-09-15),
      Cygwin is the only platform known to support the former (starting
      with Cygwin-2.6.1), and macOS is the only platform known to
      support the latter.  */
 
-#ifdef _PC_CASE_INSENSITIVE
+#if defined _PC_CASE_INSENSITIVE || defined _PC_CASE_SENSITIVE
+  char *filename = SSDATA (ENCODE_FILE (file));
+# ifdef _PC_CASE_INSENSITIVE
   long int res = pathconf (filename, _PC_CASE_INSENSITIVE);
   if (res >= 0)
-    return res > 0;
-#elif defined _PC_CASE_SENSITIVE
+    return - (res > 0);
+# else
   long int res = pathconf (filename, _PC_CASE_SENSITIVE);
   if (res >= 0)
-    return res == 0;
+    return - (res == 0);
+# endif
+  if (errno != EINVAL)
+    return errno;
 #endif
 
 #if defined CYGWIN || defined DOS_NT
-  return true;
+  return -1;
 #else
-  return false;
+  return 0;
 #endif
 }
 
@@ -2426,21 +2443,18 @@ The arg must be a string.  */)
 
   /* If the file doesn't exist, move up the filesystem tree until we
      reach an existing directory or the root.  */
-  if (NILP (Ffile_exists_p (filename)))
+  while (true)
     {
-      filename = Ffile_name_directory (filename);
-      while (NILP (Ffile_exists_p (filename)))
-       {
-         Lisp_Object newname = expand_and_dir_to_file (filename);
-         /* Avoid infinite loop if the root is reported as non-existing
-            (impossible?).  */
-         if (!NILP (Fstring_equal (newname, filename)))
-           break;
-         filename = newname;
-       }
+      int err = file_name_case_insensitive_err (filename);
+      if (! (err == ENOENT || err == ENOTDIR))
+       return err < 0 ? Qt : Qnil;
+      Lisp_Object parent = file_name_directory (filename);
+      /* Avoid infinite loop if the root is reported as non-existing
+        (impossible?).  */
+      if (!NILP (Fstring_equal (parent, filename)))
+       return Qnil;
+      filename = parent;
     }
-  filename = ENCODE_FILE (filename);
-  return file_name_case_insensitive_p (SSDATA (filename)) ? Qt : Qnil;
 }
 
 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,
   if (errno != ENOENT)
     return Qnil;
 
-  dir = Ffile_name_directory (absname);
+  dir = file_name_directory (absname);
   eassert (!NILP (dir));
 #ifdef MSDOS
   dir = Fdirectory_file_name (dir);
@@ -5822,7 +5836,7 @@ A non-nil CURRENT-ONLY argument means save only current 
buffer.  */)
       if (!NILP (Vrun_hooks))
        {
          Lisp_Object dir;
-         dir = Ffile_name_directory (listfile);
+         dir = file_name_directory (listfile);
          if (NILP (Ffile_directory_p (dir)))
            internal_condition_case_1 (do_auto_save_make_dir,
                                       dir, Qt,



reply via email to

[Prev in Thread] Current Thread [Next in Thread]