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 /src | |
| 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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/fileio.c | 93 |
1 files changed, 61 insertions, 32 deletions
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", |