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. On platforms where
-this information is not available, this function guesses based on
-common practice.
+@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.
@end defun
@defun file-in-directory-p file dir
return NILP (tem);
}
\f
-/* 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.
+/* 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
static bool
file_name_case_insensitive_p (const char *filename)
{
-#ifdef _PC_CASE_INSENSITIVE
+#ifdef DOS_NT
+ return 1;
+#elif defined CYGWIN
+/* As of Cygwin-2.6.1, pathconf supports _PC_CASE_INSENSITIVE. */
+# ifdef _PC_CASE_INSENSITIVE
int res = pathconf (filename, _PC_CASE_INSENSITIVE);
- 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;
+ if (res < 0)
+ return 1;
+ return res > 0;
+# else
+ return 1;
# endif
-
- 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;
+#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);
#else
- return false;
+ return 0;
#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",