diff options
| author | Paul Eggert | 2017-08-11 01:04:30 -0700 |
|---|---|---|
| committer | Paul Eggert | 2017-08-11 01:07:31 -0700 |
| commit | a56e6e79613779895975b1762c311bf8fe46f551 (patch) | |
| tree | a5b61d84922996945ab52f2944b4d7538a626db0 /src | |
| parent | 179499cde921a28c82400b1674520da245b93bb9 (diff) | |
| download | emacs-a56e6e79613779895975b1762c311bf8fe46f551.tar.gz emacs-a56e6e79613779895975b1762c311bf8fe46f551.zip | |
Improve performance for rename-file etc.
Although this does not fix Bug#27986, it is a step forward.
I plan to propose a more-significant patch later.
* lisp/files.el (directory-name-p): Move from here ...
* src/fileio.c (Fdirectory_name_p): ... to here.
(directory_like, cp_like_target): New static functions.
(Fcopy_file, Frename_file, Fadd_name_to_file)
(Fmake_symbolic_link):
Use them, to avoid directory-testing syscalls on file names that
must be directories if they exist. Omit unnecessary
initializations and CHECK_STRING calls.
(Frename_file): Don't call file_name_case_insensitive_p
twice on the same file. Compare both file names expanded, instead
of the old name expanded and the new one unexpanded.
Diffstat (limited to 'src')
| -rw-r--r-- | src/fileio.c | 127 |
1 files changed, 66 insertions, 61 deletions
diff --git a/src/fileio.c b/src/fileio.c index 15845e39144..9aae7d997ee 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -267,9 +267,9 @@ Otherwise, return nil. | |||
| 267 | A file name is handled if one of the regular expressions in | 267 | A file name is handled if one of the regular expressions in |
| 268 | `file-name-handler-alist' matches it. | 268 | `file-name-handler-alist' matches it. |
| 269 | 269 | ||
| 270 | If OPERATION equals `inhibit-file-name-operation', then we ignore | 270 | If OPERATION equals `inhibit-file-name-operation', then ignore |
| 271 | any handlers that are members of `inhibit-file-name-handlers', | 271 | any handlers that are members of `inhibit-file-name-handlers', |
| 272 | but we still do run any other handlers. This lets handlers | 272 | but still do run any other handlers. This lets handlers |
| 273 | use the standard functions without calling themselves recursively. */) | 273 | use the standard functions without calling themselves recursively. */) |
| 274 | (Lisp_Object filename, Lisp_Object operation) | 274 | (Lisp_Object filename, Lisp_Object operation) |
| 275 | { | 275 | { |
| @@ -583,6 +583,38 @@ directory_file_name (char *dst, char *src, ptrdiff_t srclen, bool multibyte) | |||
| 583 | return srclen; | 583 | return srclen; |
| 584 | } | 584 | } |
| 585 | 585 | ||
| 586 | DEFUN ("directory-name-p", Fdirectory_name_p, Sdirectory_name_p, 1, 1, 0, | ||
| 587 | doc: /* Return non-nil if NAME ends with a directory separator character. */) | ||
| 588 | (Lisp_Object name) | ||
| 589 | { | ||
| 590 | CHECK_STRING (name); | ||
| 591 | ptrdiff_t namelen = SBYTES (name); | ||
| 592 | unsigned char c = namelen ? SREF (name, namelen - 1) : 0; | ||
| 593 | return IS_DIRECTORY_SEP (c) ? Qt : Qnil; | ||
| 594 | } | ||
| 595 | |||
| 596 | /* Return true if NAME must be that of a directory if it exists. | ||
| 597 | When NAME is a directory name, this avoids system calls compared to | ||
| 598 | just calling Ffile_directory_p. */ | ||
| 599 | |||
| 600 | static bool | ||
| 601 | directory_like (Lisp_Object name) | ||
| 602 | { | ||
| 603 | return !NILP (Fdirectory_name_p (name)) || !NILP (Ffile_directory_p (name)); | ||
| 604 | } | ||
| 605 | |||
| 606 | /* Return the expansion of NEWNAME, except that if NEWNAME is like a | ||
| 607 | directory then return the expansion of FILE's basename under | ||
| 608 | NEWNAME. This is like how 'cp FILE NEWNAME' works. */ | ||
| 609 | |||
| 610 | static Lisp_Object | ||
| 611 | expand_cp_target (Lisp_Object file, Lisp_Object newname) | ||
| 612 | { | ||
| 613 | return (directory_like (newname) | ||
| 614 | ? Fexpand_file_name (Ffile_name_nondirectory (file), newname) | ||
| 615 | : Fexpand_file_name (newname, Qnil)); | ||
| 616 | } | ||
| 617 | |||
| 586 | DEFUN ("directory-file-name", Fdirectory_file_name, Sdirectory_file_name, | 618 | DEFUN ("directory-file-name", Fdirectory_file_name, Sdirectory_file_name, |
| 587 | 1, 1, 0, | 619 | 1, 1, 0, |
| 588 | doc: /* Returns the file name of the directory named DIRECTORY. | 620 | doc: /* Returns the file name of the directory named DIRECTORY. |
| @@ -1874,9 +1906,9 @@ This function always sets the file modes of the output file to match | |||
| 1874 | the input file. | 1906 | the input file. |
| 1875 | 1907 | ||
| 1876 | The optional third argument OK-IF-ALREADY-EXISTS specifies what to do | 1908 | The optional third argument OK-IF-ALREADY-EXISTS specifies what to do |
| 1877 | if file NEWNAME already exists. If OK-IF-ALREADY-EXISTS is nil, we | 1909 | if file NEWNAME already exists. If OK-IF-ALREADY-EXISTS is nil, |
| 1878 | signal a `file-already-exists' error without overwriting. If | 1910 | signal a `file-already-exists' error without overwriting. If |
| 1879 | OK-IF-ALREADY-EXISTS is a number, we request confirmation from the user | 1911 | OK-IF-ALREADY-EXISTS is an integer, request confirmation from the user |
| 1880 | about overwriting; this is what happens in interactive use with M-x. | 1912 | about overwriting; this is what happens in interactive use with M-x. |
| 1881 | Any other value for OK-IF-ALREADY-EXISTS means to overwrite the | 1913 | Any other value for OK-IF-ALREADY-EXISTS means to overwrite the |
| 1882 | existing file. | 1914 | existing file. |
| @@ -1886,8 +1918,8 @@ last-modified time as the old one. (This works on only some systems.) | |||
| 1886 | 1918 | ||
| 1887 | A prefix arg makes KEEP-TIME non-nil. | 1919 | A prefix arg makes KEEP-TIME non-nil. |
| 1888 | 1920 | ||
| 1889 | If PRESERVE-UID-GID is non-nil, we try to transfer the | 1921 | If PRESERVE-UID-GID is non-nil, try to transfer the uid and gid of |
| 1890 | uid and gid of FILE to NEWNAME. | 1922 | FILE to NEWNAME. |
| 1891 | 1923 | ||
| 1892 | If PRESERVE-PERMISSIONS is non-nil, copy permissions of FILE to NEWNAME; | 1924 | If PRESERVE-PERMISSIONS is non-nil, copy permissions of FILE to NEWNAME; |
| 1893 | this includes the file modes, along with ACL entries and SELinux | 1925 | this includes the file modes, along with ACL entries and SELinux |
| @@ -1914,16 +1946,8 @@ permissions. */) | |||
| 1914 | struct stat st; | 1946 | struct stat st; |
| 1915 | #endif | 1947 | #endif |
| 1916 | 1948 | ||
| 1917 | encoded_file = encoded_newname = Qnil; | ||
| 1918 | CHECK_STRING (file); | ||
| 1919 | CHECK_STRING (newname); | ||
| 1920 | |||
| 1921 | if (!NILP (Ffile_directory_p (newname))) | ||
| 1922 | newname = Fexpand_file_name (Ffile_name_nondirectory (file), newname); | ||
| 1923 | else | ||
| 1924 | newname = Fexpand_file_name (newname, Qnil); | ||
| 1925 | |||
| 1926 | file = Fexpand_file_name (file, Qnil); | 1949 | file = Fexpand_file_name (file, Qnil); |
| 1950 | newname = expand_cp_target (file, newname); | ||
| 1927 | 1951 | ||
| 1928 | /* If the input file name has special constructs in it, | 1952 | /* If the input file name has special constructs in it, |
| 1929 | call the corresponding file handler. */ | 1953 | call the corresponding file handler. */ |
| @@ -2304,9 +2328,9 @@ DEFUN ("rename-file", Frename_file, Srename_file, 2, 3, | |||
| 2304 | "fRename file: \nGRename %s to file: \np", | 2328 | "fRename file: \nGRename %s to file: \np", |
| 2305 | doc: /* Rename FILE as NEWNAME. Both args must be strings. | 2329 | doc: /* Rename FILE as NEWNAME. Both args must be strings. |
| 2306 | If file has names other than FILE, it continues to have those names. | 2330 | If file has names other than FILE, it continues to have those names. |
| 2307 | Signals a `file-already-exists' error if a file NEWNAME already exists | 2331 | Signal a `file-already-exists' error if a file NEWNAME already exists |
| 2308 | unless optional third argument OK-IF-ALREADY-EXISTS is non-nil. | 2332 | unless optional third argument OK-IF-ALREADY-EXISTS is non-nil. |
| 2309 | A number as third arg means request confirmation if NEWNAME already exists. | 2333 | An integer third arg means request confirmation if NEWNAME already exists. |
| 2310 | This is what happens in interactive use with M-x. */) | 2334 | This is what happens in interactive use with M-x. */) |
| 2311 | (Lisp_Object file, Lisp_Object newname, Lisp_Object ok_if_already_exists) | 2335 | (Lisp_Object file, Lisp_Object newname, Lisp_Object ok_if_already_exists) |
| 2312 | { | 2336 | { |
| @@ -2314,24 +2338,22 @@ This is what happens in interactive use with M-x. */) | |||
| 2314 | Lisp_Object encoded_file, encoded_newname, symlink_target; | 2338 | Lisp_Object encoded_file, encoded_newname, symlink_target; |
| 2315 | int dirp = -1; | 2339 | int dirp = -1; |
| 2316 | 2340 | ||
| 2317 | symlink_target = encoded_file = encoded_newname = Qnil; | ||
| 2318 | CHECK_STRING (file); | ||
| 2319 | CHECK_STRING (newname); | ||
| 2320 | file = Fexpand_file_name (file, Qnil); | 2341 | file = Fexpand_file_name (file, Qnil); |
| 2321 | 2342 | ||
| 2322 | if ((!NILP (Ffile_directory_p (newname))) | 2343 | /* If the filesystem is case-insensitive and the file names are |
| 2323 | /* If the filesystem is case-insensitive and the file names are | 2344 | identical but for case, treat it as a change-case request, and do |
| 2324 | identical but for the case, don't attempt to move directory | 2345 | not worry whether NEWNAME exists or whether it is a directory, as |
| 2325 | to itself. */ | 2346 | it is already another name for FILE. */ |
| 2326 | && (NILP (Ffile_name_case_insensitive_p (file)) | 2347 | bool case_only_rename = false; |
| 2327 | || NILP (Fstring_equal (Fdowncase (file), Fdowncase (newname))))) | 2348 | if (!NILP (Ffile_name_case_insensitive_p (file))) |
| 2328 | { | 2349 | { |
| 2329 | dirp = !NILP (Ffile_directory_p (file)); | 2350 | newname = Fexpand_file_name (newname, Qnil); |
| 2330 | Lisp_Object fname = dirp ? Fdirectory_file_name (file) : file; | 2351 | case_only_rename = !NILP (Fstring_equal (Fdowncase (file), |
| 2331 | newname = Fexpand_file_name (Ffile_name_nondirectory (fname), newname); | 2352 | Fdowncase (newname))); |
| 2332 | } | 2353 | } |
| 2333 | else | 2354 | |
| 2334 | newname = Fexpand_file_name (newname, Qnil); | 2355 | if (!case_only_rename) |
| 2356 | newname = expand_cp_target (Fdirectory_file_name (file), newname); | ||
| 2335 | 2357 | ||
| 2336 | /* If the file name has special constructs in it, | 2358 | /* If the file name has special constructs in it, |
| 2337 | call the corresponding file handler. */ | 2359 | call the corresponding file handler. */ |
| @@ -2345,15 +2367,9 @@ This is what happens in interactive use with M-x. */) | |||
| 2345 | encoded_file = ENCODE_FILE (file); | 2367 | encoded_file = ENCODE_FILE (file); |
| 2346 | encoded_newname = ENCODE_FILE (newname); | 2368 | encoded_newname = ENCODE_FILE (newname); |
| 2347 | 2369 | ||
| 2348 | /* If the filesystem is case-insensitive and the file names are | 2370 | bool plain_rename = (case_only_rename |
| 2349 | identical but for the case, don't worry whether the destination | 2371 | || (!NILP (ok_if_already_exists) |
| 2350 | already exists: the caller simply wants to change the letter-case | 2372 | && !INTEGERP (ok_if_already_exists))); |
| 2351 | of the file name. */ | ||
| 2352 | bool plain_rename | ||
| 2353 | = ((!NILP (ok_if_already_exists) && !INTEGERP (ok_if_already_exists)) | ||
| 2354 | || (file_name_case_insensitive_p (SSDATA (encoded_file)) | ||
| 2355 | && ! NILP (Fstring_equal (Fdowncase (file), Fdowncase (newname))))); | ||
| 2356 | |||
| 2357 | int rename_errno; | 2373 | int rename_errno; |
| 2358 | if (!plain_rename) | 2374 | if (!plain_rename) |
| 2359 | { | 2375 | { |
| @@ -2395,7 +2411,7 @@ This is what happens in interactive use with M-x. */) | |||
| 2395 | else | 2411 | else |
| 2396 | { | 2412 | { |
| 2397 | if (dirp < 0) | 2413 | if (dirp < 0) |
| 2398 | dirp = !NILP (Ffile_directory_p (file)); | 2414 | dirp = directory_like (file); |
| 2399 | if (dirp) | 2415 | if (dirp) |
| 2400 | call4 (Qcopy_directory, file, newname, Qt, Qnil); | 2416 | call4 (Qcopy_directory, file, newname, Qt, Qnil); |
| 2401 | else | 2417 | else |
| @@ -2414,24 +2430,17 @@ This is what happens in interactive use with M-x. */) | |||
| 2414 | DEFUN ("add-name-to-file", Fadd_name_to_file, Sadd_name_to_file, 2, 3, | 2430 | DEFUN ("add-name-to-file", Fadd_name_to_file, Sadd_name_to_file, 2, 3, |
| 2415 | "fAdd name to file: \nGName to add to %s: \np", | 2431 | "fAdd name to file: \nGName to add to %s: \np", |
| 2416 | doc: /* Give FILE additional name NEWNAME. Both args must be strings. | 2432 | doc: /* Give FILE additional name NEWNAME. Both args must be strings. |
| 2417 | Signals a `file-already-exists' error if a file NEWNAME already exists | 2433 | Signal a `file-already-exists' error if a file NEWNAME already exists |
| 2418 | unless optional third argument OK-IF-ALREADY-EXISTS is non-nil. | 2434 | unless optional third argument OK-IF-ALREADY-EXISTS is non-nil. |
| 2419 | A number as third arg means request confirmation if NEWNAME already exists. | 2435 | An integer third arg means request confirmation if NEWNAME already exists. |
| 2420 | This is what happens in interactive use with M-x. */) | 2436 | This is what happens in interactive use with M-x. */) |
| 2421 | (Lisp_Object file, Lisp_Object newname, Lisp_Object ok_if_already_exists) | 2437 | (Lisp_Object file, Lisp_Object newname, Lisp_Object ok_if_already_exists) |
| 2422 | { | 2438 | { |
| 2423 | Lisp_Object handler; | 2439 | Lisp_Object handler; |
| 2424 | Lisp_Object encoded_file, encoded_newname; | 2440 | Lisp_Object encoded_file, encoded_newname; |
| 2425 | 2441 | ||
| 2426 | encoded_file = encoded_newname = Qnil; | ||
| 2427 | CHECK_STRING (file); | ||
| 2428 | CHECK_STRING (newname); | ||
| 2429 | file = Fexpand_file_name (file, Qnil); | 2442 | file = Fexpand_file_name (file, Qnil); |
| 2430 | 2443 | newname = expand_cp_target (file, newname); | |
| 2431 | if (!NILP (Ffile_directory_p (newname))) | ||
| 2432 | newname = Fexpand_file_name (Ffile_name_nondirectory (file), newname); | ||
| 2433 | else | ||
| 2434 | newname = Fexpand_file_name (newname, Qnil); | ||
| 2435 | 2444 | ||
| 2436 | /* If the file name has special constructs in it, | 2445 | /* If the file name has special constructs in it, |
| 2437 | call the corresponding file handler. */ | 2446 | call the corresponding file handler. */ |
| @@ -2471,28 +2480,23 @@ DEFUN ("make-symbolic-link", Fmake_symbolic_link, Smake_symbolic_link, 2, 3, | |||
| 2471 | "FMake symbolic link to file: \nGMake symbolic link to file %s: \np", | 2480 | "FMake symbolic link to file: \nGMake symbolic link to file %s: \np", |
| 2472 | doc: /* Make a symbolic link to TARGET, named LINKNAME. | 2481 | doc: /* Make a symbolic link to TARGET, named LINKNAME. |
| 2473 | Both args must be strings. | 2482 | Both args must be strings. |
| 2474 | Signals a `file-already-exists' error if a file LINKNAME already exists | 2483 | Signal a `file-already-exists' error if a file LINKNAME already exists |
| 2475 | unless optional third argument OK-IF-ALREADY-EXISTS is non-nil. | 2484 | unless optional third argument OK-IF-ALREADY-EXISTS is non-nil. |
| 2476 | A number as third arg means request confirmation if LINKNAME already exists. | 2485 | An integer third arg means request confirmation if LINKNAME already exists. |
| 2477 | This happens for interactive use with M-x. */) | 2486 | This happens for interactive use with M-x. */) |
| 2478 | (Lisp_Object target, Lisp_Object linkname, Lisp_Object ok_if_already_exists) | 2487 | (Lisp_Object target, Lisp_Object linkname, Lisp_Object ok_if_already_exists) |
| 2479 | { | 2488 | { |
| 2480 | Lisp_Object handler; | 2489 | Lisp_Object handler; |
| 2481 | Lisp_Object encoded_target, encoded_linkname; | 2490 | Lisp_Object encoded_target, encoded_linkname; |
| 2482 | 2491 | ||
| 2483 | encoded_target = encoded_linkname = Qnil; | ||
| 2484 | CHECK_STRING (target); | 2492 | CHECK_STRING (target); |
| 2485 | CHECK_STRING (linkname); | ||
| 2486 | /* If the link target has a ~, we must expand it to get | 2493 | /* If the link target has a ~, we must expand it to get |
| 2487 | a truly valid file name. Otherwise, do not expand; | 2494 | a truly valid file name. Otherwise, do not expand; |
| 2488 | we want to permit links to relative file names. */ | 2495 | we want to permit links to relative file names. */ |
| 2489 | if (SREF (target, 0) == '~') | 2496 | if (SREF (target, 0) == '~') |
| 2490 | target = Fexpand_file_name (target, Qnil); | 2497 | target = Fexpand_file_name (target, Qnil); |
| 2491 | 2498 | ||
| 2492 | if (!NILP (Ffile_directory_p (linkname))) | 2499 | linkname = expand_cp_target (target, linkname); |
| 2493 | linkname = Fexpand_file_name (Ffile_name_nondirectory (target), linkname); | ||
| 2494 | else | ||
| 2495 | linkname = Fexpand_file_name (linkname, Qnil); | ||
| 2496 | 2500 | ||
| 2497 | /* If the file name has special constructs in it, | 2501 | /* If the file name has special constructs in it, |
| 2498 | call the corresponding file handler. */ | 2502 | call the corresponding file handler. */ |
| @@ -5577,7 +5581,7 @@ and are changed since last auto-saved. | |||
| 5577 | Auto-saving writes the buffer into a file | 5581 | Auto-saving writes the buffer into a file |
| 5578 | so that your editing is not lost if the system crashes. | 5582 | so that your editing is not lost if the system crashes. |
| 5579 | This file is not the file you visited; that changes only when you save. | 5583 | This file is not the file you visited; that changes only when you save. |
| 5580 | Normally we run the normal hook `auto-save-hook' before saving. | 5584 | Normally, run the normal hook `auto-save-hook' before saving. |
| 5581 | 5585 | ||
| 5582 | A non-nil NO-MESSAGE argument means do not print any message if successful. | 5586 | A non-nil NO-MESSAGE argument means do not print any message if successful. |
| 5583 | A non-nil CURRENT-ONLY argument means save only current buffer. */) | 5587 | A non-nil CURRENT-ONLY argument means save only current buffer. */) |
| @@ -6111,7 +6115,7 @@ This applies only to the operation `inhibit-file-name-operation'. */); | |||
| 6111 | Vinhibit_file_name_operation = Qnil; | 6115 | Vinhibit_file_name_operation = Qnil; |
| 6112 | 6116 | ||
| 6113 | DEFVAR_LISP ("auto-save-list-file-name", Vauto_save_list_file_name, | 6117 | DEFVAR_LISP ("auto-save-list-file-name", Vauto_save_list_file_name, |
| 6114 | doc: /* File name in which we write a list of all auto save file names. | 6118 | doc: /* File name in which to write a list of all auto save file names. |
| 6115 | This variable is initialized automatically from `auto-save-list-file-prefix' | 6119 | This variable is initialized automatically from `auto-save-list-file-prefix' |
| 6116 | shortly after Emacs reads your init file, if you have not yet given it | 6120 | shortly after Emacs reads your init file, if you have not yet given it |
| 6117 | a non-nil value. */); | 6121 | a non-nil value. */); |
| @@ -6166,6 +6170,7 @@ This includes interactive calls to `delete-file' and | |||
| 6166 | defsubr (&Sfile_name_nondirectory); | 6170 | defsubr (&Sfile_name_nondirectory); |
| 6167 | defsubr (&Sunhandled_file_name_directory); | 6171 | defsubr (&Sunhandled_file_name_directory); |
| 6168 | defsubr (&Sfile_name_as_directory); | 6172 | defsubr (&Sfile_name_as_directory); |
| 6173 | defsubr (&Sdirectory_name_p); | ||
| 6169 | defsubr (&Sdirectory_file_name); | 6174 | defsubr (&Sdirectory_file_name); |
| 6170 | defsubr (&Smake_temp_name); | 6175 | defsubr (&Smake_temp_name); |
| 6171 | defsubr (&Sexpand_file_name); | 6176 | defsubr (&Sexpand_file_name); |