diff options
| author | Paul Eggert | 2020-03-07 12:04:05 -0800 |
|---|---|---|
| committer | Paul Eggert | 2020-03-07 12:15:43 -0800 |
| commit | 5d4cf1fef85bc24bc4cd9705ebb14150263ad707 (patch) | |
| tree | af696ed3ba7d2d0ab31951eba9482443d36c1456 /src | |
| parent | 9f4b260c2b98ea05a02e0ab7213156ce2e60e5a9 (diff) | |
| download | emacs-5d4cf1fef85bc24bc4cd9705ebb14150263ad707.tar.gz emacs-5d4cf1fef85bc24bc4cd9705ebb14150263ad707.zip | |
Add ‘nofollow’ flag to set-file-times
This is a companion to the recent set-file-modes patch.
It adds support for a ‘nofollow’ flag to set-file-times (Bug#39773).
Like the set-file-modes patch, it needs work in the w32 port.
* admin/merge-gnulib (GNULIB_MODULES): Add futimens, utimensat.
Remove utimens.
* doc/lispref/files.texi (Changing Files):
* etc/NEWS: Mention the change.
* lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate.
* lisp/files.el (copy-directory):
* lisp/gnus/gnus-cloud.el (gnus-cloud-replace-file):
* lisp/net/tramp-adb.el (tramp-adb-handle-copy-file):
* lisp/net/tramp-smb.el (tramp-smb-handle-copy-file):
* lisp/tar-mode.el (tar-copy):
* test/lisp/filenotify-tests.el (file-notify-test03-events):
* test/lisp/files-tests.el:
(files-tests-file-name-non-special-set-file-times):
* test/lisp/net/tramp-tests.el (tramp-test22-file-times):
When setting file times, avoid following symbolic links
when the file is not supposed to be a symbolic link.
* lib/futimens.c, lib/utimensat.c, m4/futimens.m4, m4/utimensat.m4:
New files, copied from Gnulib.
* lisp/gnus/gnus-cloud.el (gnus-cloud-replace-file):
When creating a file that is not supposed to exist already,
use the excl flag to check this.
* lisp/net/tramp-adb.el (tramp-adb-handle-set-file-times):
* lisp/net/tramp-sh.el (tramp-sh-handle-set-file-times):
* lisp/net/tramp-sudoedit.el (tramp-sudoedit-handle-set-file-times):
Accept an optional FLAG arg that is currently ignored,
and add a FIXME comment for it.
* lisp/net/tramp-gvfs.el (tramp-gvfs-handle-set-file-times):
* src/fileio.c (Fset_file_times):
Support an optional FLAG arg.
* src/fileio.c (Fcopy_file): Use futimens instead of set_file_times,
as it’s simpler and is a POSIX API.
* src/sysdep.c (set_file_times): Move from here ...
* src/w32.c (set_file_times): ... to here, and make it static,
since it is now used only in w32.c. Presumably w32.c should also
add support for futimens and utimensat (the POSIX APIs, which
Emacs now uses) and it can remove fdutimens (the Gnulib API,
which Emacs no longer uses).
Diffstat (limited to 'src')
| -rw-r--r-- | src/fileio.c | 51 | ||||
| -rw-r--r-- | src/sysdep.c | 15 | ||||
| -rw-r--r-- | src/systime.h | 3 | ||||
| -rw-r--r-- | src/w32.c | 15 |
4 files changed, 41 insertions, 43 deletions
diff --git a/src/fileio.c b/src/fileio.c index 2532f5233c4..82fd7989206 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -2253,9 +2253,8 @@ permissions. */) | |||
| 2253 | 2253 | ||
| 2254 | if (!NILP (keep_time)) | 2254 | if (!NILP (keep_time)) |
| 2255 | { | 2255 | { |
| 2256 | struct timespec atime = get_stat_atime (&st); | 2256 | struct timespec ts[] = { get_stat_atime (&st), get_stat_mtime (&st) }; |
| 2257 | struct timespec mtime = get_stat_mtime (&st); | 2257 | if (futimens (ofd, ts) != 0) |
| 2258 | if (set_file_times (ofd, SSDATA (encoded_newname), atime, mtime) != 0) | ||
| 2259 | xsignal2 (Qfile_date_error, | 2258 | xsignal2 (Qfile_date_error, |
| 2260 | build_string ("Cannot set file date"), newname); | 2259 | build_string ("Cannot set file date"), newname); |
| 2261 | } | 2260 | } |
| @@ -3430,39 +3429,41 @@ The value is an integer. */) | |||
| 3430 | } | 3429 | } |
| 3431 | 3430 | ||
| 3432 | 3431 | ||
| 3433 | DEFUN ("set-file-times", Fset_file_times, Sset_file_times, 1, 2, 0, | 3432 | DEFUN ("set-file-times", Fset_file_times, Sset_file_times, 1, 3, 0, |
| 3434 | doc: /* Set times of file FILENAME to TIMESTAMP. | 3433 | doc: /* Set times of file FILENAME to TIMESTAMP. |
| 3435 | Set both access and modification times. | 3434 | If optional FLAG is `nofollow', do not follow FILENAME if it is a |
| 3436 | Return t on success, else nil. | 3435 | symbolic link. Set both access and modification times. Return t on |
| 3437 | Use the current time if TIMESTAMP is nil. TIMESTAMP is in the format of | 3436 | success, else nil. Use the current time if TIMESTAMP is nil. |
| 3438 | `current-time'. */) | 3437 | TIMESTAMP is in the format of `current-time'. */) |
| 3439 | (Lisp_Object filename, Lisp_Object timestamp) | 3438 | (Lisp_Object filename, Lisp_Object timestamp, Lisp_Object flag) |
| 3440 | { | 3439 | { |
| 3441 | Lisp_Object absname, encoded_absname; | 3440 | int nofollow = symlink_nofollow_flag (flag); |
| 3442 | Lisp_Object handler; | ||
| 3443 | struct timespec t = lisp_time_argument (timestamp); | ||
| 3444 | 3441 | ||
| 3445 | absname = Fexpand_file_name (filename, BVAR (current_buffer, directory)); | 3442 | struct timespec ts[2]; |
| 3443 | if (!NILP (timestamp)) | ||
| 3444 | ts[0] = ts[1] = lisp_time_argument (timestamp); | ||
| 3445 | else | ||
| 3446 | ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW; | ||
| 3446 | 3447 | ||
| 3447 | /* If the file name has special constructs in it, | 3448 | /* If the file name has special constructs in it, |
| 3448 | call the corresponding file name handler. */ | 3449 | call the corresponding file name handler. */ |
| 3449 | handler = Ffind_file_name_handler (absname, Qset_file_times); | 3450 | Lisp_Object |
| 3451 | absname = Fexpand_file_name (filename, BVAR (current_buffer, directory)), | ||
| 3452 | handler = Ffind_file_name_handler (absname, Qset_file_times); | ||
| 3450 | if (!NILP (handler)) | 3453 | if (!NILP (handler)) |
| 3451 | return call3 (handler, Qset_file_times, absname, timestamp); | 3454 | return call4 (handler, Qset_file_times, absname, timestamp, flag); |
| 3452 | 3455 | ||
| 3453 | encoded_absname = ENCODE_FILE (absname); | 3456 | Lisp_Object encoded_absname = ENCODE_FILE (absname); |
| 3454 | 3457 | ||
| 3455 | { | 3458 | if (utimensat (AT_FDCWD, SSDATA (encoded_absname), ts, nofollow) != 0) |
| 3456 | if (set_file_times (-1, SSDATA (encoded_absname), t, t) != 0) | 3459 | { |
| 3457 | { | ||
| 3458 | #ifdef MSDOS | 3460 | #ifdef MSDOS |
| 3459 | /* Setting times on a directory always fails. */ | 3461 | /* Setting times on a directory always fails. */ |
| 3460 | if (file_directory_p (encoded_absname)) | 3462 | if (file_directory_p (encoded_absname)) |
| 3461 | return Qnil; | 3463 | return Qnil; |
| 3462 | #endif | 3464 | #endif |
| 3463 | report_file_error ("Setting file times", absname); | 3465 | report_file_error ("Setting file times", absname); |
| 3464 | } | 3466 | } |
| 3465 | } | ||
| 3466 | 3467 | ||
| 3467 | return Qt; | 3468 | return Qt; |
| 3468 | } | 3469 | } |
diff --git a/src/sysdep.c b/src/sysdep.c index e8e8bbfb502..149d80f19ec 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -2752,21 +2752,6 @@ emacs_perror (char const *message) | |||
| 2752 | errno = err; | 2752 | errno = err; |
| 2753 | } | 2753 | } |
| 2754 | 2754 | ||
| 2755 | /* Set the access and modification time stamps of FD (a.k.a. FILE) to be | ||
| 2756 | ATIME and MTIME, respectively. | ||
| 2757 | FD must be either negative -- in which case it is ignored -- | ||
| 2758 | or a file descriptor that is open on FILE. | ||
| 2759 | If FD is nonnegative, then FILE can be NULL. */ | ||
| 2760 | int | ||
| 2761 | set_file_times (int fd, const char *filename, | ||
| 2762 | struct timespec atime, struct timespec mtime) | ||
| 2763 | { | ||
| 2764 | struct timespec timespec[2]; | ||
| 2765 | timespec[0] = atime; | ||
| 2766 | timespec[1] = mtime; | ||
| 2767 | return fdutimens (fd, filename, timespec); | ||
| 2768 | } | ||
| 2769 | |||
| 2770 | /* Rename directory SRCFD's entry SRC to directory DSTFD's entry DST. | 2755 | /* Rename directory SRCFD's entry SRC to directory DSTFD's entry DST. |
| 2771 | This is like renameat except that it fails if DST already exists, | 2756 | This is like renameat except that it fails if DST already exists, |
| 2772 | or if this operation is not supported atomically. Return 0 if | 2757 | or if this operation is not supported atomically. Return 0 if |
diff --git a/src/systime.h b/src/systime.h index 00ca4a1c58d..b59a3d1c690 100644 --- a/src/systime.h +++ b/src/systime.h | |||
| @@ -67,9 +67,6 @@ timespec_valid_p (struct timespec t) | |||
| 67 | return t.tv_nsec >= 0; | 67 | return t.tv_nsec >= 0; |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | /* defined in sysdep.c */ | ||
| 71 | extern int set_file_times (int, const char *, struct timespec, struct timespec); | ||
| 72 | |||
| 73 | /* defined in keyboard.c */ | 70 | /* defined in keyboard.c */ |
| 74 | extern void set_waiting_for_input (struct timespec *); | 71 | extern void set_waiting_for_input (struct timespec *); |
| 75 | 72 | ||
| @@ -3189,6 +3189,21 @@ fdutimens (int fd, char const *file, struct timespec const timespec[2]) | |||
| 3189 | } | 3189 | } |
| 3190 | } | 3190 | } |
| 3191 | 3191 | ||
| 3192 | /* Set the access and modification time stamps of FD (a.k.a. FILE) to be | ||
| 3193 | ATIME and MTIME, respectively. | ||
| 3194 | FD must be either negative -- in which case it is ignored -- | ||
| 3195 | or a file descriptor that is open on FILE. | ||
| 3196 | If FD is nonnegative, then FILE can be NULL. */ | ||
| 3197 | static int | ||
| 3198 | set_file_times (int fd, const char *filename, | ||
| 3199 | struct timespec atime, struct timespec mtime) | ||
| 3200 | { | ||
| 3201 | struct timespec timespec[2]; | ||
| 3202 | timespec[0] = atime; | ||
| 3203 | timespec[1] = mtime; | ||
| 3204 | return fdutimens (fd, filename, timespec); | ||
| 3205 | } | ||
| 3206 | |||
| 3192 | 3207 | ||
| 3193 | /* ------------------------------------------------------------------------- */ | 3208 | /* ------------------------------------------------------------------------- */ |
| 3194 | /* IO support and wrapper functions for the Windows API. */ | 3209 | /* IO support and wrapper functions for the Windows API. */ |