aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2020-02-23 16:19:42 -0800
committerPaul Eggert2020-02-23 16:45:50 -0800
commit9d626dffc6ba62c0d7a1a5c712f576ed8684fd66 (patch)
tree6cc8fbe8e5bc02c3bb74139710814a0400e91a8a /src
parentc4ca8219dd6b8f06e67a0b767475b1259653b8e0 (diff)
downloademacs-9d626dffc6ba62c0d7a1a5c712f576ed8684fd66.tar.gz
emacs-9d626dffc6ba62c0d7a1a5c712f576ed8684fd66.zip
Add 'nofollow' flag to set-file-modes etc.
This avoids some race conditions (Bug#39683). E.g., if some other program changes a file to a symlink between the time Emacs creates the file and the time it changes the file’s permissions, using the new flag prevents Emacs from inadvertently changing the permissions of a victim in some completely unrelated directory. * admin/merge-gnulib (GNULIB_MODULES): Add fchmodat. * doc/lispref/files.texi (Testing Accessibility, Changing Files): * doc/lispref/os.texi (File Notifications): * etc/NEWS: Adjust documentation accordingly. * lib/chmodat.c, lib/fchmodat.c, lib/lchmod.c, m4/fchmodat.m4: * m4/lchmod.m4: New files, copied from Gnulib. * lib/gnulib.mk.in: Regenerate. * lisp/dired-aux.el (dired-do-chmod): * lisp/doc-view.el (doc-view-make-safe-dir): * lisp/emacs-lisp/autoload.el (autoload--save-buffer): * lisp/emacs-lisp/bytecomp.el (byte-compile-file): * lisp/eshell/em-pred.el (eshell-pred-file-mode): * lisp/files.el (backup-buffer-copy, copy-directory): * lisp/gnus/mail-source.el (mail-source-movemail): * lisp/gnus/mm-decode.el (mm-display-external): * lisp/gnus/nnmail.el (nnmail-write-region): * lisp/net/tramp-adb.el (tramp-adb-handle-file-local-copy) (tramp-adb-handle-write-region): * lisp/net/tramp-sh.el (tramp-do-copy-or-rename-file-directly): * lisp/net/tramp-sudoedit.el (tramp-sudoedit-handle-write-region): * lisp/net/tramp.el (tramp-handle-write-region) (tramp-make-tramp-temp-file): * lisp/server.el (server-ensure-safe-dir): * lisp/url/url-util.el (url-make-private-file): When getting or setting file modes, avoid following symbolic links when the file is not supposed to be a symbolic link. * lisp/doc-view.el (doc-view-make-safe-dir): Omit no-longer-needed separate symlink test. * lisp/gnus/gnus-util.el (gnus-set-file-modes): * lisp/net/tramp.el (tramp-handle-file-modes): * lisp/net/tramp-gvfs.el (tramp-gvfs-handle-set-file-modes): * src/fileio.c (symlink_nofollow_flag): New function. (Ffile_modes, Fset_file_modes): Support an optional FLAG arg. All C callers changed. * lisp/net/ange-ftp.el (ange-ftp-set-file-modes): * lisp/net/tramp-adb.el (tramp-adb-handle-set-file-modes): * lisp/net/tramp-sh.el (tramp-sh-handle-set-file-modes): * lisp/net/tramp-smb.el (tramp-smb-handle-set-file-modes): * lisp/net/tramp-sudoedit.el (tramp-sudoedit-handle-set-file-modes): Accept an optional FLAG arg that is currently ignored, and add a FIXME comment for it. * m4/gnulib-comp.m4: Regenerate.
Diffstat (limited to 'src')
-rw-r--r--src/fileio.c46
1 files changed, 28 insertions, 18 deletions
diff --git a/src/fileio.c b/src/fileio.c
index 6b56c473abf..2532f5233c4 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -3332,50 +3332,60 @@ support. */)
3332 return Qnil; 3332 return Qnil;
3333} 3333}
3334 3334
3335DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0, 3335static int
3336symlink_nofollow_flag (Lisp_Object flag)
3337{
3338 /* For now, treat all non-nil FLAGs like 'nofollow'. */
3339 return !NILP (flag) ? AT_SYMLINK_NOFOLLOW : 0;
3340}
3341
3342DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 2, 0,
3336 doc: /* Return mode bits of file named FILENAME, as an integer. 3343 doc: /* Return mode bits of file named FILENAME, as an integer.
3337Return nil if FILENAME does not exist. */) 3344Return nil if FILENAME does not exist. If optional FLAG is `nofollow',
3338 (Lisp_Object filename) 3345do not follow FILENAME if it is a symbolic link. */)
3346 (Lisp_Object filename, Lisp_Object flag)
3339{ 3347{
3340 struct stat st; 3348 struct stat st;
3349 int nofollow = symlink_nofollow_flag (flag);
3341 Lisp_Object absname = expand_and_dir_to_file (filename); 3350 Lisp_Object absname = expand_and_dir_to_file (filename);
3342 3351
3343 /* If the file name has special constructs in it, 3352 /* If the file name has special constructs in it,
3344 call the corresponding file name handler. */ 3353 call the corresponding file name handler. */
3345 Lisp_Object handler = Ffind_file_name_handler (absname, Qfile_modes); 3354 Lisp_Object handler = Ffind_file_name_handler (absname, Qfile_modes);
3346 if (!NILP (handler)) 3355 if (!NILP (handler))
3347 return call2 (handler, Qfile_modes, absname); 3356 return call3 (handler, Qfile_modes, absname, flag);
3348 3357
3349 if (emacs_fstatat (AT_FDCWD, SSDATA (ENCODE_FILE (absname)), &st, 0) != 0) 3358 char *fname = SSDATA (ENCODE_FILE (absname));
3359 if (emacs_fstatat (AT_FDCWD, fname, &st, nofollow) != 0)
3350 return file_attribute_errno (absname, errno); 3360 return file_attribute_errno (absname, errno);
3351 return make_fixnum (st.st_mode & 07777); 3361 return make_fixnum (st.st_mode & 07777);
3352} 3362}
3353 3363
3354DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 2, 3364DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 3,
3355 "(let ((file (read-file-name \"File: \"))) \ 3365 "(let ((file (read-file-name \"File: \"))) \
3356 (list file (read-file-modes nil file)))", 3366 (list file (read-file-modes nil file)))",
3357 doc: /* Set mode bits of file named FILENAME to MODE (an integer). 3367 doc: /* Set mode bits of file named FILENAME to MODE (an integer).
3358Only the 12 low bits of MODE are used. 3368Only the 12 low bits of MODE are used. If optional FLAG is `nofollow',
3369do not follow FILENAME if it is a symbolic link.
3359 3370
3360Interactively, mode bits are read by `read-file-modes', which accepts 3371Interactively, mode bits are read by `read-file-modes', which accepts
3361symbolic notation, like the `chmod' command from GNU Coreutils. */) 3372symbolic notation, like the `chmod' command from GNU Coreutils. */)
3362 (Lisp_Object filename, Lisp_Object mode) 3373 (Lisp_Object filename, Lisp_Object mode, Lisp_Object flag)
3363{ 3374{
3364 Lisp_Object absname, encoded_absname;
3365 Lisp_Object handler;
3366
3367 absname = Fexpand_file_name (filename, BVAR (current_buffer, directory));
3368 CHECK_FIXNUM (mode); 3375 CHECK_FIXNUM (mode);
3376 int nofollow = symlink_nofollow_flag (flag);
3377 Lisp_Object absname = Fexpand_file_name (filename,
3378 BVAR (current_buffer, directory));
3369 3379
3370 /* If the file name has special constructs in it, 3380 /* If the file name has special constructs in it,
3371 call the corresponding file name handler. */ 3381 call the corresponding file name handler. */
3372 handler = Ffind_file_name_handler (absname, Qset_file_modes); 3382 Lisp_Object handler = Ffind_file_name_handler (absname, Qset_file_modes);
3373 if (!NILP (handler)) 3383 if (!NILP (handler))
3374 return call3 (handler, Qset_file_modes, absname, mode); 3384 return call4 (handler, Qset_file_modes, absname, mode, flag);
3375
3376 encoded_absname = ENCODE_FILE (absname);
3377 3385
3378 if (chmod (SSDATA (encoded_absname), XFIXNUM (mode) & 07777) < 0) 3386 char *fname = SSDATA (ENCODE_FILE (absname));
3387 mode_t imode = XFIXNUM (mode) & 07777;
3388 if (fchmodat (AT_FDCWD, fname, imode, nofollow) != 0)
3379 report_file_error ("Doing chmod", absname); 3389 report_file_error ("Doing chmod", absname);
3380 3390
3381 return Qnil; 3391 return Qnil;
@@ -5740,7 +5750,7 @@ auto_save_1 (void)
5740 == 0) 5750 == 0)
5741 /* But make sure we can overwrite it later! */ 5751 /* But make sure we can overwrite it later! */
5742 auto_save_mode_bits = (st.st_mode | 0600) & 0777; 5752 auto_save_mode_bits = (st.st_mode | 0600) & 0777;
5743 else if (modes = Ffile_modes (BVAR (current_buffer, filename)), 5753 else if (modes = Ffile_modes (BVAR (current_buffer, filename), Qnil),
5744 FIXNUMP (modes)) 5754 FIXNUMP (modes))
5745 /* Remote files don't cooperate with fstatat. */ 5755 /* Remote files don't cooperate with fstatat. */
5746 auto_save_mode_bits = (XFIXNUM (modes) | 0600) & 0777; 5756 auto_save_mode_bits = (XFIXNUM (modes) | 0600) & 0777;