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
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
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
}
/* 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",