diff options
| author | Paul Eggert | 2016-11-14 09:08:06 -0800 |
|---|---|---|
| committer | Paul Eggert | 2016-11-14 09:09:48 -0800 |
| commit | 2f5e0b1bf7b0ac4f450847db34d599a072020600 (patch) | |
| tree | f653be0ce0b66b4e8c507f4e57a6a0bbca3ae142 | |
| parent | 3625e6ce9352942a4db980dd203b590cdaf821df (diff) | |
| download | emacs-2f5e0b1bf7b0ac4f450847db34d599a072020600.tar.gz emacs-2f5e0b1bf7b0ac4f450847db34d599a072020600.zip | |
Improve case-insensitive checks (Bug#24441)
* 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.
| -rw-r--r-- | doc/lispref/files.texi | 14 | ||||
| -rw-r--r-- | src/fileio.c | 93 |
2 files changed, 64 insertions, 43 deletions
diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index 70c7177e064..ab0dcae2d9c 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi | |||
| @@ -1144,17 +1144,9 @@ return value is unspecified. | |||
| 1144 | Sometimes file names or their parts need to be compared as strings, in | 1144 | Sometimes file names or their parts need to be compared as strings, in |
| 1145 | which case it's important to know whether the underlying filesystem is | 1145 | which case it's important to know whether the underlying filesystem is |
| 1146 | case-insensitive. This function returns @code{t} if file | 1146 | case-insensitive. This function returns @code{t} if file |
| 1147 | @var{filename} is on a case-insensitive filesystem. It always returns | 1147 | @var{filename} is on a case-insensitive filesystem. On platforms where |
| 1148 | @code{t} on MS-DOS and MS-Windows. On Cygwin and Mac OS X, | 1148 | this information is not available, this function guesses based on |
| 1149 | filesystems may or may not be case-insensitive, and the function tries | 1149 | common practice. |
| 1150 | to determine case-sensitivity by a runtime test. If the test is | ||
| 1151 | inconclusive, the function returns @code{t} on Cygwin and @code{nil} | ||
| 1152 | on Mac OS X. | ||
| 1153 | |||
| 1154 | Currently this function always returns @code{nil} on platforms other | ||
| 1155 | than MS-DOS, MS-Windows, Cygwin, and Mac OS X. It does not detect | ||
| 1156 | case-insensitivity of mounted filesystems, such as Samba shares or | ||
| 1157 | NFS-mounted Windows volumes. | ||
| 1158 | @end defun | 1150 | @end defun |
| 1159 | 1151 | ||
| 1160 | @defun file-in-directory-p file dir | 1152 | @defun file-in-directory-p file dir |
diff --git a/src/fileio.c b/src/fileio.c index f3f8f421618..eec3591ff6e 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -2236,13 +2236,10 @@ internal_delete_file (Lisp_Object filename) | |||
| 2236 | return NILP (tem); | 2236 | return NILP (tem); |
| 2237 | } | 2237 | } |
| 2238 | 2238 | ||
| 2239 | /* Filesystems are case-sensitive on all supported systems except | 2239 | /* Return true if FILENAME is on a case-insensitive file system. |
| 2240 | MS-Windows, MS-DOS, Cygwin, and Mac OS X. They are always | 2240 | Use a runtime test if available. Otherwise, assume the file system |
| 2241 | case-insensitive on the first two, but they may or may not be | 2241 | is case-insensitive on Microsoft-based platforms and case-sensitive |
| 2242 | case-insensitive on Cygwin and OS X. The following function | 2242 | elsewhere. |
| 2243 | attempts to provide a runtime test on those two systems. If the | ||
| 2244 | test is not conclusive, we assume case-insensitivity on Cygwin and | ||
| 2245 | case-sensitivity on Mac OS X. | ||
| 2246 | 2243 | ||
| 2247 | FIXME: Mounted filesystems on Posix hosts, like Samba shares or | 2244 | FIXME: Mounted filesystems on Posix hosts, like Samba shares or |
| 2248 | NFS-mounted Windows volumes, might be case-insensitive. Can we | 2245 | NFS-mounted Windows volumes, might be case-insensitive. Can we |
| @@ -2251,33 +2248,65 @@ internal_delete_file (Lisp_Object filename) | |||
| 2251 | static bool | 2248 | static bool |
| 2252 | file_name_case_insensitive_p (const char *filename) | 2249 | file_name_case_insensitive_p (const char *filename) |
| 2253 | { | 2250 | { |
| 2254 | #ifdef DOS_NT | 2251 | #ifdef _PC_CASE_INSENSITIVE |
| 2255 | return 1; | ||
| 2256 | #elif defined CYGWIN | ||
| 2257 | /* As of Cygwin-2.6.1, pathconf supports _PC_CASE_INSENSITIVE. */ | ||
| 2258 | # ifdef _PC_CASE_INSENSITIVE | ||
| 2259 | int res = pathconf (filename, _PC_CASE_INSENSITIVE); | 2252 | int res = pathconf (filename, _PC_CASE_INSENSITIVE); |
| 2260 | if (res < 0) | 2253 | if (0 < res) |
| 2261 | return 1; | 2254 | return true; |
| 2262 | return res > 0; | 2255 | if (res == 0 || errno != EINVAL) |
| 2263 | # else | 2256 | return false; |
| 2264 | return 1; | 2257 | #elif defined _PC_CASE_SENSITIVE |
| 2258 | int res = pathconf (filename, _PC_CASE_SENSITIVE); | ||
| 2259 | if (res == 0) | ||
| 2260 | return true; | ||
| 2261 | if (0 < res || errno != EINVAL) | ||
| 2262 | return false; | ||
| 2263 | #endif | ||
| 2264 | |||
| 2265 | #ifdef DARWIN_OS | ||
| 2266 | /* It is not clear whether this section is needed. For now, rely on | ||
| 2267 | pathconf and skip this section. If pathconf does not work, | ||
| 2268 | please recompile Emacs with -DDARWIN_OS_CASE_SENSITIVE_FIXME=1 or | ||
| 2269 | -DDARWIN_OS_CASE_SENSITIVE_FIXME=2, and file a bug report saying | ||
| 2270 | whether this fixed your problem. */ | ||
| 2271 | # ifndef DARWIN_OS_CASE_SENSITIVE_FIXME | ||
| 2272 | int DARWIN_OS_CASE_SENSITIVE_FIXME = 0; | ||
| 2265 | # endif | 2273 | # endif |
| 2266 | #elif defined DARWIN_OS | 2274 | |
| 2267 | /* The following is based on | 2275 | if (DARWIN_OS_CASE_SENSITIVE_FIXME == 1) |
| 2268 | http://lists.apple.com/archives/darwin-dev/2007/Apr/msg00010.html. */ | 2276 | { |
| 2269 | struct attrlist alist; | 2277 | /* This is based on developer.apple.com's getattrlist man page. */ |
| 2270 | unsigned char buffer[sizeof (vol_capabilities_attr_t) + sizeof (size_t)]; | 2278 | struct attrlist alist = {.volattr = ATTR_VOL_CAPABILITIES}; |
| 2271 | 2279 | struct vol_capabilities_attr_t vcaps; | |
| 2272 | memset (&alist, 0, sizeof (alist)); | 2280 | if (getattrlist (filename, &alist, &vcaps, sizeof vcaps, 0) == 0) |
| 2273 | alist.volattr = ATTR_VOL_CAPABILITIES; | 2281 | { |
| 2274 | if (getattrlist (filename, &alist, buffer, sizeof (buffer), 0) | 2282 | if (vcaps.valid[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_CASE_SENSITIVE) |
| 2275 | || !(alist.volattr & ATTR_VOL_CAPABILITIES)) | 2283 | return ! (vcaps.capabilities[VOL_CAPABILITIES_FORMAT] |
| 2276 | return 0; | 2284 | & VOL_CAP_FMT_CASE_SENSITIVE); |
| 2277 | vol_capabilities_attr_t *vcaps = buffer; | 2285 | } |
| 2278 | return !(vcaps->capabilities[0] & VOL_CAP_FMT_CASE_SENSITIVE); | 2286 | else if (errno != EINVAL) |
| 2287 | return false; | ||
| 2288 | } | ||
| 2289 | else if (DARWIN_OS_CASE_SENSITIVE_FIXME == 2) | ||
| 2290 | { | ||
| 2291 | /* The following is based on | ||
| 2292 | http://lists.apple.com/archives/darwin-dev/2007/Apr/msg00010.html. */ | ||
| 2293 | struct attrlist alist; | ||
| 2294 | unsigned char buffer[sizeof (vol_capabilities_attr_t) + sizeof (size_t)]; | ||
| 2295 | |||
| 2296 | memset (&alist, 0, sizeof (alist)); | ||
| 2297 | alist.volattr = ATTR_VOL_CAPABILITIES; | ||
| 2298 | if (getattrlist (filename, &alist, buffer, sizeof (buffer), 0) | ||
| 2299 | || !(alist.volattr & ATTR_VOL_CAPABILITIES)) | ||
| 2300 | return 0; | ||
| 2301 | vol_capabilities_attr_t *vcaps = buffer; | ||
| 2302 | return !(vcaps->capabilities[0] & VOL_CAP_FMT_CASE_SENSITIVE); | ||
| 2303 | } | ||
| 2304 | #endif | ||
| 2305 | |||
| 2306 | #if defined CYGWIN || defined DOS_NT | ||
| 2307 | return true; | ||
| 2279 | #else | 2308 | #else |
| 2280 | return 0; | 2309 | return false; |
| 2281 | #endif | 2310 | #endif |
| 2282 | } | 2311 | } |
| 2283 | 2312 | ||
| @@ -2349,7 +2378,7 @@ This is what happens in interactive use with M-x. */) | |||
| 2349 | /* If the filesystem is case-insensitive and the file names are | 2378 | /* If the filesystem is case-insensitive and the file names are |
| 2350 | identical but for the case, don't ask for confirmation: they | 2379 | identical but for the case, don't ask for confirmation: they |
| 2351 | simply want to change the letter-case of the file name. */ | 2380 | simply want to change the letter-case of the file name. */ |
| 2352 | if ((!(file_name_case_insensitive_p (SSDATA (encoded_file))) | 2381 | if ((! file_name_case_insensitive_p (SSDATA (encoded_file)) |
| 2353 | || NILP (Fstring_equal (Fdowncase (file), Fdowncase (newname)))) | 2382 | || NILP (Fstring_equal (Fdowncase (file), Fdowncase (newname)))) |
| 2354 | && ((NILP (ok_if_already_exists) || INTEGERP (ok_if_already_exists)))) | 2383 | && ((NILP (ok_if_already_exists) || INTEGERP (ok_if_already_exists)))) |
| 2355 | barf_or_query_if_file_exists (newname, false, "rename to it", | 2384 | barf_or_query_if_file_exists (newname, false, "rename to it", |