diff options
| author | Ken Brown | 2016-11-12 19:00:35 -0500 |
|---|---|---|
| committer | Ken Brown | 2016-11-12 21:54:45 -0500 |
| commit | 2809012c8f9485d8dc54b186f989f289b2797892 (patch) | |
| tree | 6958ef0540eaada506c32f1546147a9fd26b8a3b /src | |
| parent | 462804da9ce5a2ffc8c6ad4887d97116cf868d13 (diff) | |
| download | emacs-2809012c8f9485d8dc54b186f989f289b2797892.tar.gz emacs-2809012c8f9485d8dc54b186f989f289b2797892.zip | |
Check case-sensitivity when renaming files
* src/fileio.c (file_name_case_insensitive_p)
(Ffile_name_case_insensitive_p): New functions.
(Frename_file): Allow renames that simply change case when the
FILE argument is on a case-insensitive filesystem. (Bug#24441)
* lisp/dired-aux.el (dired-do-create-files): Use
'file-name-case-insensitive-p' instead of 'system-type' to check
for case-insensitivity. (Bug#24441)
* doc/lispref/files.texi (Truenames): Document
'file-name-case-insensitive-p'.
Diffstat (limited to 'src')
| -rw-r--r-- | src/fileio.c | 97 |
1 files changed, 83 insertions, 14 deletions
diff --git a/src/fileio.c b/src/fileio.c index d3da0fb63d7..f3f8f421618 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -25,6 +25,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 25 | #include <sys/stat.h> | 25 | #include <sys/stat.h> |
| 26 | #include <unistd.h> | 26 | #include <unistd.h> |
| 27 | 27 | ||
| 28 | #ifdef DARWIN_OS | ||
| 29 | #include <sys/attr.h> | ||
| 30 | #endif | ||
| 31 | |||
| 28 | #ifdef HAVE_PWD_H | 32 | #ifdef HAVE_PWD_H |
| 29 | #include <pwd.h> | 33 | #include <pwd.h> |
| 30 | #endif | 34 | #endif |
| @@ -2232,6 +2236,72 @@ internal_delete_file (Lisp_Object filename) | |||
| 2232 | return NILP (tem); | 2236 | return NILP (tem); |
| 2233 | } | 2237 | } |
| 2234 | 2238 | ||
| 2239 | /* Filesystems are case-sensitive on all supported systems except | ||
| 2240 | MS-Windows, MS-DOS, Cygwin, and Mac OS X. They are always | ||
| 2241 | case-insensitive on the first two, but they may or may not be | ||
| 2242 | case-insensitive on Cygwin and OS X. The following function | ||
| 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 | |||
| 2247 | FIXME: Mounted filesystems on Posix hosts, like Samba shares or | ||
| 2248 | NFS-mounted Windows volumes, might be case-insensitive. Can we | ||
| 2249 | detect this? */ | ||
| 2250 | |||
| 2251 | static bool | ||
| 2252 | file_name_case_insensitive_p (const char *filename) | ||
| 2253 | { | ||
| 2254 | #ifdef DOS_NT | ||
| 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); | ||
| 2260 | if (res < 0) | ||
| 2261 | return 1; | ||
| 2262 | return res > 0; | ||
| 2263 | # else | ||
| 2264 | return 1; | ||
| 2265 | # endif | ||
| 2266 | #elif defined DARWIN_OS | ||
| 2267 | /* The following is based on | ||
| 2268 | http://lists.apple.com/archives/darwin-dev/2007/Apr/msg00010.html. */ | ||
| 2269 | struct attrlist alist; | ||
| 2270 | unsigned char buffer[sizeof (vol_capabilities_attr_t) + sizeof (size_t)]; | ||
| 2271 | |||
| 2272 | memset (&alist, 0, sizeof (alist)); | ||
| 2273 | alist.volattr = ATTR_VOL_CAPABILITIES; | ||
| 2274 | if (getattrlist (filename, &alist, buffer, sizeof (buffer), 0) | ||
| 2275 | || !(alist.volattr & ATTR_VOL_CAPABILITIES)) | ||
| 2276 | return 0; | ||
| 2277 | vol_capabilities_attr_t *vcaps = buffer; | ||
| 2278 | return !(vcaps->capabilities[0] & VOL_CAP_FMT_CASE_SENSITIVE); | ||
| 2279 | #else | ||
| 2280 | return 0; | ||
| 2281 | #endif | ||
| 2282 | } | ||
| 2283 | |||
| 2284 | DEFUN ("file-name-case-insensitive-p", Ffile_name_case_insensitive_p, | ||
| 2285 | Sfile_name_case_insensitive_p, 1, 1, 0, | ||
| 2286 | doc: /* Return t if file FILENAME is on a case-insensitive filesystem. | ||
| 2287 | The arg must be a string. */) | ||
| 2288 | (Lisp_Object filename) | ||
| 2289 | { | ||
| 2290 | Lisp_Object handler; | ||
| 2291 | |||
| 2292 | CHECK_STRING (filename); | ||
| 2293 | filename = Fexpand_file_name (filename, Qnil); | ||
| 2294 | |||
| 2295 | /* If the file name has special constructs in it, | ||
| 2296 | call the corresponding file handler. */ | ||
| 2297 | handler = Ffind_file_name_handler (filename, Qfile_name_case_insensitive_p); | ||
| 2298 | if (!NILP (handler)) | ||
| 2299 | return call2 (handler, Qfile_name_case_insensitive_p, filename); | ||
| 2300 | |||
| 2301 | filename = ENCODE_FILE (filename); | ||
| 2302 | return file_name_case_insensitive_p (SSDATA (filename)) ? Qt : Qnil; | ||
| 2303 | } | ||
| 2304 | |||
| 2235 | DEFUN ("rename-file", Frename_file, Srename_file, 2, 3, | 2305 | DEFUN ("rename-file", Frename_file, Srename_file, 2, 3, |
| 2236 | "fRename file: \nGRename %s to file: \np", | 2306 | "fRename file: \nGRename %s to file: \np", |
| 2237 | doc: /* Rename FILE as NEWNAME. Both args must be strings. | 2307 | doc: /* Rename FILE as NEWNAME. Both args must be strings. |
| @@ -2251,12 +2321,11 @@ This is what happens in interactive use with M-x. */) | |||
| 2251 | file = Fexpand_file_name (file, Qnil); | 2321 | file = Fexpand_file_name (file, Qnil); |
| 2252 | 2322 | ||
| 2253 | if ((!NILP (Ffile_directory_p (newname))) | 2323 | if ((!NILP (Ffile_directory_p (newname))) |
| 2254 | #ifdef DOS_NT | 2324 | /* If the filesystem is case-insensitive and the file names are |
| 2255 | /* If the file names are identical but for the case, | 2325 | identical but for the case, don't attempt to move directory |
| 2256 | don't attempt to move directory to itself. */ | 2326 | to itself. */ |
| 2257 | && (NILP (Fstring_equal (Fdowncase (file), Fdowncase (newname)))) | 2327 | && (NILP (Ffile_name_case_insensitive_p (file)) |
| 2258 | #endif | 2328 | || NILP (Fstring_equal (Fdowncase (file), Fdowncase (newname))))) |
| 2259 | ) | ||
| 2260 | { | 2329 | { |
| 2261 | Lisp_Object fname = (NILP (Ffile_directory_p (file)) | 2330 | Lisp_Object fname = (NILP (Ffile_directory_p (file)) |
| 2262 | ? file : Fdirectory_file_name (file)); | 2331 | ? file : Fdirectory_file_name (file)); |
| @@ -2277,14 +2346,12 @@ This is what happens in interactive use with M-x. */) | |||
| 2277 | encoded_file = ENCODE_FILE (file); | 2346 | encoded_file = ENCODE_FILE (file); |
| 2278 | encoded_newname = ENCODE_FILE (newname); | 2347 | encoded_newname = ENCODE_FILE (newname); |
| 2279 | 2348 | ||
| 2280 | #ifdef DOS_NT | 2349 | /* If the filesystem is case-insensitive and the file names are |
| 2281 | /* If the file names are identical but for the case, don't ask for | 2350 | identical but for the case, don't ask for confirmation: they |
| 2282 | confirmation: they simply want to change the letter-case of the | 2351 | simply want to change the letter-case of the file name. */ |
| 2283 | file name. */ | 2352 | if ((!(file_name_case_insensitive_p (SSDATA (encoded_file))) |
| 2284 | if (NILP (Fstring_equal (Fdowncase (file), Fdowncase (newname)))) | 2353 | || NILP (Fstring_equal (Fdowncase (file), Fdowncase (newname)))) |
| 2285 | #endif | 2354 | && ((NILP (ok_if_already_exists) || INTEGERP (ok_if_already_exists)))) |
| 2286 | if (NILP (ok_if_already_exists) | ||
| 2287 | || INTEGERP (ok_if_already_exists)) | ||
| 2288 | barf_or_query_if_file_exists (newname, false, "rename to it", | 2355 | barf_or_query_if_file_exists (newname, false, "rename to it", |
| 2289 | INTEGERP (ok_if_already_exists), false); | 2356 | INTEGERP (ok_if_already_exists), false); |
| 2290 | if (rename (SSDATA (encoded_file), SSDATA (encoded_newname)) < 0) | 2357 | if (rename (SSDATA (encoded_file), SSDATA (encoded_newname)) < 0) |
| @@ -5836,6 +5903,7 @@ syms_of_fileio (void) | |||
| 5836 | DEFSYM (Qmake_directory_internal, "make-directory-internal"); | 5903 | DEFSYM (Qmake_directory_internal, "make-directory-internal"); |
| 5837 | DEFSYM (Qmake_directory, "make-directory"); | 5904 | DEFSYM (Qmake_directory, "make-directory"); |
| 5838 | DEFSYM (Qdelete_file, "delete-file"); | 5905 | DEFSYM (Qdelete_file, "delete-file"); |
| 5906 | DEFSYM (Qfile_name_case_insensitive_p, "file-name-case-insensitive-p"); | ||
| 5839 | DEFSYM (Qrename_file, "rename-file"); | 5907 | DEFSYM (Qrename_file, "rename-file"); |
| 5840 | DEFSYM (Qadd_name_to_file, "add-name-to-file"); | 5908 | DEFSYM (Qadd_name_to_file, "add-name-to-file"); |
| 5841 | DEFSYM (Qmake_symbolic_link, "make-symbolic-link"); | 5909 | DEFSYM (Qmake_symbolic_link, "make-symbolic-link"); |
| @@ -6099,6 +6167,7 @@ This includes interactive calls to `delete-file' and | |||
| 6099 | defsubr (&Smake_directory_internal); | 6167 | defsubr (&Smake_directory_internal); |
| 6100 | defsubr (&Sdelete_directory_internal); | 6168 | defsubr (&Sdelete_directory_internal); |
| 6101 | defsubr (&Sdelete_file); | 6169 | defsubr (&Sdelete_file); |
| 6170 | defsubr (&Sfile_name_case_insensitive_p); | ||
| 6102 | defsubr (&Srename_file); | 6171 | defsubr (&Srename_file); |
| 6103 | defsubr (&Sadd_name_to_file); | 6172 | defsubr (&Sadd_name_to_file); |
| 6104 | defsubr (&Smake_symbolic_link); | 6173 | defsubr (&Smake_symbolic_link); |