]> git.eshelyaron.com Git - emacs.git/commitdiff
Improve case-insensitive checks (Bug#24441)
authorPaul Eggert <eggert@cs.ucla.edu>
Mon, 14 Nov 2016 17:08:06 +0000 (09:08 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Mon, 14 Nov 2016 17:09:48 +0000 (09:09 -0800)
* doc/lispref/files.texi (Truenames): Simplify documentation,
to avoid giving too much platform-specific information that
may not be accurate anyway.
* src/fileio.c (file_name_case_insensitive_p): Use pathconf with
_PC_CASE_SENSITIVE if _PC_CASE_INSENSITIVE is not available.
Otherwise if one approach fails (e.g., with errno == EINVAL), fall
back on an alternative rather than returning false.  Try skipping
the Darwin code, as it (1) no longer seems to be needed and (2)
does not seem to match the Apple documentation.  Leave in two
alternatives conditionally compiled based on
DARWIN_OS_CASE_SENSITIVE_FIXME in case (1) or (2) is incorrect.

doc/lispref/files.texi
src/fileio.c

index 70c7177e064a084255af759e6df006c5d26e6bb1..ab0dcae2d9c3e4337f92799927648e106b20aca7 100644 (file)
@@ -1144,17 +1144,9 @@ return value is unspecified.
 Sometimes file names or their parts need to be compared as strings, in
 which case it's important to know whether the underlying filesystem is
 case-insensitive.  This function returns @code{t} if file
-@var{filename} is on a case-insensitive filesystem.  It always returns
-@code{t} on MS-DOS and MS-Windows.  On Cygwin and Mac OS X,
-filesystems may or may not be case-insensitive, and the function tries
-to determine case-sensitivity by a runtime test.  If the test is
-inconclusive, the function returns @code{t} on Cygwin and @code{nil}
-on Mac OS X.
-
-Currently this function always returns @code{nil} on platforms other
-than MS-DOS, MS-Windows, Cygwin, and Mac OS X.  It does not detect
-case-insensitivity of mounted filesystems, such as Samba shares or
-NFS-mounted Windows volumes.
+@var{filename} is on a case-insensitive filesystem.  On platforms where
+this information is not available, this function guesses based on
+common practice.
 @end defun
 
 @defun file-in-directory-p file dir
index f3f8f4216180f67ecdb2e64b854090eff325673f..eec3591ff6e057e43abac4a483e29791af21656c 100644 (file)
@@ -2236,13 +2236,10 @@ internal_delete_file (Lisp_Object filename)
   return NILP (tem);
 }
 \f
-/* 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.
+/* Return true if FILENAME is on a case-insensitive file system.
+   Use a runtime test if available.  Otherwise, assume the file system
+   is case-insensitive on Microsoft-based platforms and case-sensitive
+   elsewhere.
 
    FIXME: Mounted filesystems on Posix hosts, like Samba shares or
    NFS-mounted Windows volumes, might be case-insensitive.  Can we
@@ -2251,33 +2248,65 @@ internal_delete_file (Lisp_Object filename)
 static bool
 file_name_case_insensitive_p (const char *filename)
 {
-#ifdef DOS_NT
-  return 1;
-#elif defined CYGWIN
-/* As of Cygwin-2.6.1, pathconf supports _PC_CASE_INSENSITIVE.  */
-# ifdef _PC_CASE_INSENSITIVE
+#ifdef _PC_CASE_INSENSITIVE
   int res = pathconf (filename, _PC_CASE_INSENSITIVE);
-  if (res < 0)
-    return 1;
-  return res > 0;
-# else
-  return 1;
+  if (0 < res)
+    return true;
+  if (res == 0 || errno != EINVAL)
+    return false;
+#elif defined _PC_CASE_SENSITIVE
+  int res = pathconf (filename, _PC_CASE_SENSITIVE);
+  if (res == 0)
+    return true;
+  if (0 < res || errno != EINVAL)
+    return false;
+#endif
+
+#ifdef DARWIN_OS
+  /* It is not clear whether this section is needed.  For now, rely on
+     pathconf and skip this section.  If pathconf does not work,
+     please recompile Emacs with -DDARWIN_OS_CASE_SENSITIVE_FIXME=1 or
+     -DDARWIN_OS_CASE_SENSITIVE_FIXME=2, and file a bug report saying
+     whether this fixed your problem.  */
+# ifndef DARWIN_OS_CASE_SENSITIVE_FIXME
+  int DARWIN_OS_CASE_SENSITIVE_FIXME = 0;
 # endif
-#elif defined DARWIN_OS
-  /* The following is based on
-     http://lists.apple.com/archives/darwin-dev/2007/Apr/msg00010.html.  */
-  struct attrlist alist;
-  unsigned char buffer[sizeof (vol_capabilities_attr_t) + sizeof (size_t)];
-
-  memset (&alist, 0, sizeof (alist));
-  alist.volattr = ATTR_VOL_CAPABILITIES;
-  if (getattrlist (filename, &alist, buffer, sizeof (buffer), 0)
-      || !(alist.volattr & ATTR_VOL_CAPABILITIES))
-    return 0;
-  vol_capabilities_attr_t *vcaps = buffer;
-  return !(vcaps->capabilities[0] & VOL_CAP_FMT_CASE_SENSITIVE);
+
+  if (DARWIN_OS_CASE_SENSITIVE_FIXME == 1)
+    {
+      /* This is based on developer.apple.com's getattrlist man page.  */
+      struct attrlist alist = {.volattr = ATTR_VOL_CAPABILITIES};
+      struct vol_capabilities_attr_t vcaps;
+      if (getattrlist (filename, &alist, &vcaps, sizeof vcaps, 0) == 0)
+       {
+         if (vcaps.valid[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_CASE_SENSITIVE)
+           return ! (vcaps.capabilities[VOL_CAPABILITIES_FORMAT]
+                     & VOL_CAP_FMT_CASE_SENSITIVE);
+       }
+      else if (errno != EINVAL)
+       return false;
+    }
+  else if (DARWIN_OS_CASE_SENSITIVE_FIXME == 2)
+    {
+      /* The following is based on
+        http://lists.apple.com/archives/darwin-dev/2007/Apr/msg00010.html.  */
+      struct attrlist alist;
+      unsigned char buffer[sizeof (vol_capabilities_attr_t) + sizeof (size_t)];
+
+      memset (&alist, 0, sizeof (alist));
+      alist.volattr = ATTR_VOL_CAPABILITIES;
+      if (getattrlist (filename, &alist, buffer, sizeof (buffer), 0)
+         || !(alist.volattr & ATTR_VOL_CAPABILITIES))
+       return 0;
+      vol_capabilities_attr_t *vcaps = buffer;
+      return !(vcaps->capabilities[0] & VOL_CAP_FMT_CASE_SENSITIVE);
+    }
+#endif
+
+#if defined CYGWIN || defined DOS_NT
+  return true;
 #else
-  return 0;
+  return false;
 #endif
 }
 
@@ -2349,7 +2378,7 @@ This is what happens in interactive use with M-x.  */)
   /* If the filesystem is case-insensitive and the file names are
      identical but for the case, don't ask for confirmation: they
      simply want to change the letter-case of the file name.  */
-  if ((!(file_name_case_insensitive_p (SSDATA (encoded_file)))
+  if ((! file_name_case_insensitive_p (SSDATA (encoded_file))
        || NILP (Fstring_equal (Fdowncase (file), Fdowncase (newname))))
       && ((NILP (ok_if_already_exists) || INTEGERP (ok_if_already_exists))))
     barf_or_query_if_file_exists (newname, false, "rename to it",