mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-22 07:09:54 +00:00
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.
This commit is contained in:
parent
c4ca8219dd
commit
9d626dffc6
@ -33,7 +33,7 @@ GNULIB_MODULES='
|
||||
crypto/md5-buffer crypto/sha1-buffer crypto/sha256-buffer crypto/sha512-buffer
|
||||
d-type diffseq dosname double-slash-root dtoastr dtotimespec dup2
|
||||
environ execinfo explicit_bzero faccessat
|
||||
fcntl fcntl-h fdopendir
|
||||
fchmodat fcntl fcntl-h fdopendir
|
||||
filemode filevercmp flexmember fpieee fstatat fsusage fsync
|
||||
getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog
|
||||
ieee754-h ignore-value intprops largefile lstat
|
||||
|
@ -928,7 +928,7 @@ also checks that the file's group would be unchanged.
|
||||
This function does not follow symbolic links.
|
||||
@end defun
|
||||
|
||||
@defun file-modes filename
|
||||
@defun file-modes filename &optional flag
|
||||
@cindex mode bits
|
||||
@cindex file permissions
|
||||
@cindex permissions, file
|
||||
@ -946,12 +946,19 @@ The highest possible value is 4095 (7777 octal), meaning that everyone
|
||||
has read, write, and execute permission, the @acronym{SUID} bit is set
|
||||
for both others and group, and the sticky bit is set.
|
||||
|
||||
By default this function follows symbolic links. However, if the
|
||||
optional argument @var{flag} is the symbol @code{nofollow}, this
|
||||
function does not follow @var{filename} if it is a symbolic link;
|
||||
this can help prevent inadvertently obtaining the mode bits of a file
|
||||
somewhere else, and is more consistent with @code{file-attributes}
|
||||
(@pxref{File Attributes}).
|
||||
|
||||
@xref{Changing Files}, for the @code{set-file-modes} function, which
|
||||
can be used to set these permissions.
|
||||
|
||||
@example
|
||||
@group
|
||||
(file-modes "~/junk/diffs")
|
||||
(file-modes "~/junk/diffs" 'nofollow)
|
||||
@result{} 492 ; @r{Decimal integer.}
|
||||
@end group
|
||||
@group
|
||||
@ -960,7 +967,7 @@ can be used to set these permissions.
|
||||
@end group
|
||||
|
||||
@group
|
||||
(set-file-modes "~/junk/diffs" #o666)
|
||||
(set-file-modes "~/junk/diffs" #o666 'nofollow)
|
||||
@result{} nil
|
||||
@end group
|
||||
|
||||
@ -1801,9 +1808,17 @@ See also @code{delete-directory} in @ref{Create/Delete Dirs}.
|
||||
@cindex file permissions, setting
|
||||
@cindex permissions, file
|
||||
@cindex file modes, setting
|
||||
@deffn Command set-file-modes filename mode
|
||||
@deffn Command set-file-modes filename mode &optional flag
|
||||
This function sets the @dfn{file mode} (or @dfn{permissions}) of
|
||||
@var{filename} to @var{mode}. This function follows symbolic links.
|
||||
@var{filename} to @var{mode}.
|
||||
|
||||
By default this function follows symbolic links. However, if the
|
||||
optional argument @var{flag} is the symbol @code{nofollow}, this
|
||||
function does not follow @var{filename} if it is a symbolic link;
|
||||
this can help prevent inadvertently changing the mode bits of a file
|
||||
somewhere else. On platforms that do not support changing mode bits
|
||||
on a symbolic link, this function signals an error when @var{filename}
|
||||
is a symbolic link and @var{flag} is @code{nofollow}.
|
||||
|
||||
If called non-interactively, @var{mode} must be an integer. Only the
|
||||
lowest 12 bits of the integer are used; on most systems, only the
|
||||
@ -1811,7 +1826,7 @@ lowest 9 bits are meaningful. You can use the Lisp construct for
|
||||
octal numbers to enter @var{mode}. For example,
|
||||
|
||||
@example
|
||||
(set-file-modes #o644)
|
||||
(set-file-modes "myfile" #o644 'nofollow)
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
|
@ -3127,7 +3127,7 @@ being reported. For example:
|
||||
@end group
|
||||
|
||||
@group
|
||||
(set-file-modes "/tmp/foo" (default-file-modes))
|
||||
(set-file-modes "/tmp/foo" (default-file-modes) 'nofollow)
|
||||
@result{} Event (35025468 attribute-changed "/tmp/foo")
|
||||
@end group
|
||||
@end example
|
||||
|
3
etc/NEWS
3
etc/NEWS
@ -198,6 +198,9 @@ called when the function object is garbage-collected. Use
|
||||
'set_function_finalizer' to set the finalizer and
|
||||
'get_function_finalizer' to retrieve it.
|
||||
|
||||
** 'file-modes' and 'set-file-modes' now have an optional argument
|
||||
specifying whether to follow symbolic links.
|
||||
|
||||
** 'parse-time-string' can now parse ISO 8601 format strings,
|
||||
such as "2020-01-15T16:12:21-08:00".
|
||||
|
||||
|
144
lib/fchmodat.c
Normal file
144
lib/fchmodat.c
Normal file
@ -0,0 +1,144 @@
|
||||
/* Change the protections of file relative to an open directory.
|
||||
Copyright (C) 2006, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* written by Jim Meyering and Paul Eggert */
|
||||
|
||||
/* If the user's config.h happens to include <sys/stat.h>, let it include only
|
||||
the system's <sys/stat.h> here, so that orig_fchmodat doesn't recurse to
|
||||
rpl_fchmodat. */
|
||||
#define __need_system_sys_stat_h
|
||||
#include <config.h>
|
||||
|
||||
/* Specification. */
|
||||
#include <sys/stat.h>
|
||||
#undef __need_system_sys_stat_h
|
||||
|
||||
#if HAVE_FCHMODAT
|
||||
static int
|
||||
orig_fchmodat (int dir, char const *file, mode_t mode, int flags)
|
||||
{
|
||||
return fchmodat (dir, file, mode, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __osf__
|
||||
/* Write "sys/stat.h" here, not <sys/stat.h>, otherwise OSF/1 5.1 DTK cc
|
||||
eliminates this include because of the preliminary #include <sys/stat.h>
|
||||
above. */
|
||||
# include "sys/stat.h"
|
||||
#else
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <intprops.h>
|
||||
|
||||
/* Invoke chmod or lchmod on FILE, using mode MODE, in the directory
|
||||
open on descriptor FD. If possible, do it without changing the
|
||||
working directory. Otherwise, resort to using save_cwd/fchdir,
|
||||
then (chmod|lchmod)/restore_cwd. If either the save_cwd or the
|
||||
restore_cwd fails, then give a diagnostic and exit nonzero.
|
||||
Note that an attempt to use a FLAG value of AT_SYMLINK_NOFOLLOW
|
||||
on a system without lchmod support causes this function to fail. */
|
||||
|
||||
#if HAVE_FCHMODAT
|
||||
int
|
||||
fchmodat (int dir, char const *file, mode_t mode, int flags)
|
||||
{
|
||||
# if NEED_FCHMODAT_NONSYMLINK_FIX
|
||||
if (flags == AT_SYMLINK_NOFOLLOW)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
# if defined O_PATH && defined AT_EMPTY_PATH
|
||||
/* Open a file descriptor with O_NOFOLLOW, to make sure we don't
|
||||
follow symbolic links, if /proc is mounted. O_PATH is used to
|
||||
avoid a failure if the file is not readable.
|
||||
Cf. <https://sourceware.org/bugzilla/show_bug.cgi?id=14578> */
|
||||
int fd = openat (dir, file, O_PATH | O_NOFOLLOW | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
/* Up to Linux 5.3 at least, when FILE refers to a symbolic link, the
|
||||
chmod call below will change the permissions of the symbolic link
|
||||
- which is undesired - and on many file systems (ext4, btrfs, jfs,
|
||||
xfs, ..., but not reiserfs) fail with error EOPNOTSUPP - which is
|
||||
misleading. Therefore test for a symbolic link explicitly.
|
||||
Use fstatat because fstat does not work on O_PATH descriptors
|
||||
before Linux 3.6. */
|
||||
if (fstatat (fd, "", &st, AT_EMPTY_PATH) != 0)
|
||||
{
|
||||
int stat_errno = errno;
|
||||
close (fd);
|
||||
errno = stat_errno;
|
||||
return -1;
|
||||
}
|
||||
if (S_ISLNK (st.st_mode))
|
||||
{
|
||||
close (fd);
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
# if defined __linux__ || defined __ANDROID__
|
||||
static char const fmt[] = "/proc/self/fd/%d";
|
||||
char buf[sizeof fmt - sizeof "%d" + INT_BUFSIZE_BOUND (int)];
|
||||
sprintf (buf, fmt, fd);
|
||||
int chmod_result = chmod (buf, mode);
|
||||
int chmod_errno = errno;
|
||||
close (fd);
|
||||
if (chmod_result == 0)
|
||||
return chmod_result;
|
||||
if (chmod_errno != ENOENT)
|
||||
{
|
||||
errno = chmod_errno;
|
||||
return chmod_result;
|
||||
}
|
||||
# endif
|
||||
/* /proc is not mounted or would not work as in GNU/Linux. */
|
||||
|
||||
# else
|
||||
int fstatat_result = fstatat (dir, file, &st, AT_SYMLINK_NOFOLLOW);
|
||||
if (fstatat_result != 0)
|
||||
return fstatat_result;
|
||||
if (S_ISLNK (st.st_mode))
|
||||
{
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
# endif
|
||||
|
||||
/* Fall back on orig_fchmodat with no flags, despite a possible race. */
|
||||
flags = 0;
|
||||
}
|
||||
# endif
|
||||
|
||||
return orig_fchmodat (dir, file, mode, flags);
|
||||
}
|
||||
#else
|
||||
# define AT_FUNC_NAME fchmodat
|
||||
# define AT_FUNC_F1 lchmod
|
||||
# define AT_FUNC_F2 chmod
|
||||
# define AT_FUNC_USE_F1_COND AT_SYMLINK_NOFOLLOW
|
||||
# define AT_FUNC_POST_FILE_PARAM_DECLS , mode_t mode, int flag
|
||||
# define AT_FUNC_POST_FILE_ARGS , mode
|
||||
# include "at-func.c"
|
||||
#endif
|
@ -95,6 +95,7 @@
|
||||
# execinfo \
|
||||
# explicit_bzero \
|
||||
# faccessat \
|
||||
# fchmodat \
|
||||
# fcntl \
|
||||
# fcntl-h \
|
||||
# fdopendir \
|
||||
@ -1082,6 +1083,7 @@ gl_GNULIB_ENABLED_dirfd = @gl_GNULIB_ENABLED_dirfd@
|
||||
gl_GNULIB_ENABLED_euidaccess = @gl_GNULIB_ENABLED_euidaccess@
|
||||
gl_GNULIB_ENABLED_getdtablesize = @gl_GNULIB_ENABLED_getdtablesize@
|
||||
gl_GNULIB_ENABLED_getgroups = @gl_GNULIB_ENABLED_getgroups@
|
||||
gl_GNULIB_ENABLED_lchmod = @gl_GNULIB_ENABLED_lchmod@
|
||||
gl_GNULIB_ENABLED_malloca = @gl_GNULIB_ENABLED_malloca@
|
||||
gl_GNULIB_ENABLED_open = @gl_GNULIB_ENABLED_open@
|
||||
gl_GNULIB_ENABLED_strtoll = @gl_GNULIB_ENABLED_strtoll@
|
||||
@ -1586,6 +1588,17 @@ EXTRA_libgnu_a_SOURCES += at-func.c faccessat.c
|
||||
endif
|
||||
## end gnulib module faccessat
|
||||
|
||||
## begin gnulib module fchmodat
|
||||
ifeq (,$(OMIT_GNULIB_MODULE_fchmodat))
|
||||
|
||||
|
||||
EXTRA_DIST += at-func.c fchmodat.c
|
||||
|
||||
EXTRA_libgnu_a_SOURCES += at-func.c fchmodat.c
|
||||
|
||||
endif
|
||||
## end gnulib module fchmodat
|
||||
|
||||
## begin gnulib module fcntl
|
||||
ifeq (,$(OMIT_GNULIB_MODULE_fcntl))
|
||||
|
||||
@ -1936,6 +1949,19 @@ EXTRA_DIST += inttypes.in.h
|
||||
endif
|
||||
## end gnulib module inttypes-incomplete
|
||||
|
||||
## begin gnulib module lchmod
|
||||
ifeq (,$(OMIT_GNULIB_MODULE_lchmod))
|
||||
|
||||
ifneq (,$(gl_GNULIB_ENABLED_lchmod))
|
||||
|
||||
endif
|
||||
EXTRA_DIST += lchmod.c
|
||||
|
||||
EXTRA_libgnu_a_SOURCES += lchmod.c
|
||||
|
||||
endif
|
||||
## end gnulib module lchmod
|
||||
|
||||
## begin gnulib module libc-config
|
||||
ifeq (,$(OMIT_GNULIB_MODULE_libc-config))
|
||||
|
||||
|
110
lib/lchmod.c
Normal file
110
lib/lchmod.c
Normal file
@ -0,0 +1,110 @@
|
||||
/* Implement lchmod on platforms where it does not work correctly.
|
||||
|
||||
Copyright 2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* written by Paul Eggert */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Specification. */
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __osf__
|
||||
/* Write "sys/stat.h" here, not <sys/stat.h>, otherwise OSF/1 5.1 DTK cc
|
||||
eliminates this include because of the preliminary #include <sys/stat.h>
|
||||
above. */
|
||||
# include "sys/stat.h"
|
||||
#else
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <intprops.h>
|
||||
|
||||
/* Work like chmod, except when FILE is a symbolic link.
|
||||
In that case, on systems where permissions on symbolic links are unsupported
|
||||
(such as Linux), set errno to EOPNOTSUPP and return -1. */
|
||||
|
||||
int
|
||||
lchmod (char const *file, mode_t mode)
|
||||
{
|
||||
#if defined O_PATH && defined AT_EMPTY_PATH
|
||||
/* Open a file descriptor with O_NOFOLLOW, to make sure we don't
|
||||
follow symbolic links, if /proc is mounted. O_PATH is used to
|
||||
avoid a failure if the file is not readable.
|
||||
Cf. <https://sourceware.org/bugzilla/show_bug.cgi?id=14578> */
|
||||
int fd = open (file, O_PATH | O_NOFOLLOW | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
/* Up to Linux 5.3 at least, when FILE refers to a symbolic link, the
|
||||
chmod call below will change the permissions of the symbolic link
|
||||
- which is undesired - and on many file systems (ext4, btrfs, jfs,
|
||||
xfs, ..., but not reiserfs) fail with error EOPNOTSUPP - which is
|
||||
misleading. Therefore test for a symbolic link explicitly.
|
||||
Use fstatat because fstat does not work on O_PATH descriptors
|
||||
before Linux 3.6. */
|
||||
struct stat st;
|
||||
if (fstatat (fd, "", &st, AT_EMPTY_PATH) != 0)
|
||||
{
|
||||
int stat_errno = errno;
|
||||
close (fd);
|
||||
errno = stat_errno;
|
||||
return -1;
|
||||
}
|
||||
if (S_ISLNK (st.st_mode))
|
||||
{
|
||||
close (fd);
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
# if defined __linux__ || defined __ANDROID__
|
||||
static char const fmt[] = "/proc/self/fd/%d";
|
||||
char buf[sizeof fmt - sizeof "%d" + INT_BUFSIZE_BOUND (int)];
|
||||
sprintf (buf, fmt, fd);
|
||||
int chmod_result = chmod (buf, mode);
|
||||
int chmod_errno = errno;
|
||||
close (fd);
|
||||
if (chmod_result == 0)
|
||||
return chmod_result;
|
||||
if (chmod_errno != ENOENT)
|
||||
{
|
||||
errno = chmod_errno;
|
||||
return chmod_result;
|
||||
}
|
||||
# endif
|
||||
/* /proc is not mounted or would not work as in GNU/Linux. */
|
||||
|
||||
#elif HAVE_LSTAT
|
||||
struct stat st;
|
||||
int lstat_result = lstat (file, &st);
|
||||
if (lstat_result != 0)
|
||||
return lstat_result;
|
||||
if (S_ISLNK (st.st_mode))
|
||||
{
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Fall back on chmod, despite a possible race. */
|
||||
return chmod (file, mode);
|
||||
}
|
@ -409,7 +409,8 @@ has no effect on MS-Windows."
|
||||
(set-file-modes
|
||||
file
|
||||
(if num-modes num-modes
|
||||
(file-modes-symbolic-to-number modes (file-modes file)))))
|
||||
(file-modes-symbolic-to-number modes (file-modes file 'nofollow)))
|
||||
'nofollow))
|
||||
(dired-do-redisplay arg)))
|
||||
|
||||
;;;###autoload
|
||||
|
@ -683,8 +683,6 @@ at the top edge of the page moves to the previous page."
|
||||
;; time-window of loose permissions otherwise.
|
||||
(with-file-modes #o0700 (make-directory dir))
|
||||
(file-already-exists
|
||||
(when (file-symlink-p dir)
|
||||
(error "Danger: %s points to a symbolic link" dir))
|
||||
;; In case it was created earlier with looser rights.
|
||||
;; We could check the mode info returned by file-attributes, but it's
|
||||
;; a pain to parse and it may not tell you what we want under
|
||||
@ -694,7 +692,7 @@ at the top edge of the page moves to the previous page."
|
||||
;; sure we have write-access to the directory and that we own it, thus
|
||||
;; closing a bunch of security holes.
|
||||
(condition-case error
|
||||
(set-file-modes dir #o0700)
|
||||
(set-file-modes dir #o0700 'nofollow)
|
||||
(file-error
|
||||
(error
|
||||
(format "Unable to use temporary directory %s: %s"
|
||||
|
@ -895,7 +895,7 @@ FILE's modification time."
|
||||
(cons (lambda () (ignore-errors (delete-file tempfile)))
|
||||
kill-emacs-hook)))
|
||||
(unless (= temp-modes desired-modes)
|
||||
(set-file-modes tempfile desired-modes))
|
||||
(set-file-modes tempfile desired-modes 'nofollow))
|
||||
(write-region (point-min) (point-max) tempfile nil 1)
|
||||
(backup-buffer)
|
||||
(rename-file tempfile buffer-file-name t))
|
||||
|
@ -2008,7 +2008,7 @@ The value is non-nil if there were no errors, nil if errors."
|
||||
(delete-file tempfile)))
|
||||
kill-emacs-hook)))
|
||||
(unless (= temp-modes desired-modes)
|
||||
(set-file-modes tempfile desired-modes))
|
||||
(set-file-modes tempfile desired-modes 'nofollow))
|
||||
(write-region (point-min) (point-max) tempfile nil 1)
|
||||
;; This has the intentional side effect that any
|
||||
;; hard-links to target-file continue to
|
||||
|
@ -478,7 +478,7 @@ that `ls -l' will show in the first column of its display."
|
||||
(defsubst eshell-pred-file-mode (mode)
|
||||
"Return a test which tests that MODE pertains to the file."
|
||||
`(lambda (file)
|
||||
(let ((modes (file-modes file)))
|
||||
(let ((modes (file-modes file 'nofollow)))
|
||||
(if modes
|
||||
(logand ,mode modes)))))
|
||||
|
||||
|
@ -4672,6 +4672,7 @@ BACKUPNAME is the backup file name, which is the old file renamed."
|
||||
;; Create temp files with strict access rights. It's easy to
|
||||
;; loosen them later, whereas it's impossible to close the
|
||||
;; time-window of loose permissions otherwise.
|
||||
(let (nofollow-flag)
|
||||
(with-file-modes ?\700
|
||||
(when (condition-case nil
|
||||
;; Try to overwrite old backup first.
|
||||
@ -4682,6 +4683,7 @@ BACKUPNAME is the backup file name, which is the old file renamed."
|
||||
(when (file-exists-p to-name)
|
||||
(delete-file to-name))
|
||||
(copy-file from-name to-name nil t t)
|
||||
(setq nofollow-flag 'nofollow)
|
||||
nil)
|
||||
(file-already-exists t))
|
||||
;; The file was somehow created by someone else between
|
||||
@ -4694,7 +4696,7 @@ BACKUPNAME is the backup file name, which is the old file renamed."
|
||||
(with-demoted-errors
|
||||
(set-file-extended-attributes to-name extended-attributes)))
|
||||
(and modes
|
||||
(set-file-modes to-name (logand modes #o1777)))))
|
||||
(set-file-modes to-name (logand modes #o1777) nofollow-flag)))))
|
||||
|
||||
(defvar file-name-version-regexp
|
||||
"\\(?:~\\|\\.~[-[:alnum:]:#@^._]+\\(?:~[[:digit:]]+\\)?~\\)"
|
||||
@ -5900,7 +5902,8 @@ into NEWNAME instead."
|
||||
;; If default-directory is a remote directory, make sure we find its
|
||||
;; copy-directory handler.
|
||||
(let ((handler (or (find-file-name-handler directory 'copy-directory)
|
||||
(find-file-name-handler newname 'copy-directory))))
|
||||
(find-file-name-handler newname 'copy-directory)))
|
||||
(follow parents))
|
||||
(if handler
|
||||
(funcall handler 'copy-directory directory
|
||||
newname keep-time parents copy-contents)
|
||||
@ -5920,7 +5923,8 @@ into NEWNAME instead."
|
||||
(or parents (not (file-directory-p newname)))
|
||||
(setq newname (concat newname
|
||||
(file-name-nondirectory directory))))
|
||||
(make-directory (directory-file-name newname) parents)))
|
||||
(make-directory (directory-file-name newname) parents))
|
||||
(t (setq follow t)))
|
||||
|
||||
;; Copy recursively.
|
||||
(dolist (file
|
||||
@ -5941,7 +5945,7 @@ into NEWNAME instead."
|
||||
(let ((modes (file-modes directory))
|
||||
(times (and keep-time (file-attribute-modification-time
|
||||
(file-attributes directory)))))
|
||||
(if modes (set-file-modes newname modes))
|
||||
(if modes (set-file-modes newname modes (unless follow 'nofollow)))
|
||||
(if times (set-file-times newname times))))))
|
||||
|
||||
|
||||
|
@ -1601,10 +1601,10 @@ empty directories from OLD-PATH."
|
||||
(file-truename
|
||||
(concat old-dir "..")))))))))
|
||||
|
||||
(defun gnus-set-file-modes (filename mode)
|
||||
(defun gnus-set-file-modes (filename mode &optional flag)
|
||||
"Wrapper for set-file-modes."
|
||||
(ignore-errors
|
||||
(set-file-modes filename mode)))
|
||||
(set-file-modes filename mode flag)))
|
||||
|
||||
(defun gnus-rescale-image (image size)
|
||||
"Rescale IMAGE to SIZE if possible.
|
||||
|
@ -695,7 +695,7 @@ Deleting old (> %s day(s)) incoming mail file `%s'." diff bfile)
|
||||
mail-source-movemail-program
|
||||
nil errors nil from to)))))
|
||||
(when (file-exists-p to)
|
||||
(set-file-modes to mail-source-default-file-modes))
|
||||
(set-file-modes to mail-source-default-file-modes 'nofollow))
|
||||
(if (and (or (not (buffer-modified-p errors))
|
||||
(zerop (buffer-size errors)))
|
||||
(and (numberp result)
|
||||
|
@ -948,7 +948,7 @@ external if displayed external."
|
||||
;; The file is deleted after the viewer exists. If the users edits
|
||||
;; the file, changes will be lost. Set file to read-only to make it
|
||||
;; clear.
|
||||
(set-file-modes file #o400)
|
||||
(set-file-modes file #o400 'nofollow)
|
||||
(message "Viewing with %s" method)
|
||||
(cond
|
||||
(needsterm
|
||||
|
@ -1958,7 +1958,7 @@ If TIME is nil, then return the cutoff time for oldness instead."
|
||||
(let ((coding-system-for-write nnmail-file-coding-system)
|
||||
(file-name-coding-system nnmail-pathname-coding-system))
|
||||
(write-region start end filename append visit lockname)
|
||||
(set-file-modes filename nnmail-default-file-modes)))
|
||||
(set-file-modes filename nnmail-default-file-modes 'nofollow)))
|
||||
|
||||
;;;
|
||||
;;; Status functions
|
||||
|
@ -4740,7 +4740,8 @@ NEWNAME should be the name to give the new compressed or uncompressed file.")
|
||||
(setq ange-ftp-ls-cache-file nil) ;Stop confusing Dired.
|
||||
0)
|
||||
|
||||
(defun ange-ftp-set-file-modes (filename mode)
|
||||
(defun ange-ftp-set-file-modes (filename mode &optional flag)
|
||||
flag ;; FIXME: Support 'nofollow'.
|
||||
(ange-ftp-call-chmod (list (format "%o" mode) filename)))
|
||||
|
||||
(defun ange-ftp-make-symbolic-link (&rest _arguments)
|
||||
|
@ -591,7 +591,8 @@ Emacs dired can't find files."
|
||||
(ignore-errors (delete-file tmpfile))
|
||||
(tramp-error
|
||||
v 'file-error "Cannot make local copy of file `%s'" filename))
|
||||
(set-file-modes tmpfile (logior (or (file-modes filename) 0) #o0400)))
|
||||
(set-file-modes tmpfile (logior (or (file-modes filename) 0) #o0400)
|
||||
'nofollow))
|
||||
tmpfile)))
|
||||
|
||||
(defun tramp-adb-handle-file-writable-p (filename)
|
||||
@ -636,7 +637,8 @@ But handle the case, if the \"test\" command is not available."
|
||||
(tmpfile (tramp-compat-make-temp-file filename)))
|
||||
(when (and append (file-exists-p filename))
|
||||
(copy-file filename tmpfile 'ok)
|
||||
(set-file-modes tmpfile (logior (or (file-modes tmpfile) 0) #o0600)))
|
||||
(set-file-modes tmpfile (logior (or (file-modes tmpfile) 0) #o0600)
|
||||
'nofollow))
|
||||
(tramp-run-real-handler
|
||||
#'write-region (list start end tmpfile append 'no-message lockname))
|
||||
(with-tramp-progress-reporter
|
||||
@ -665,8 +667,9 @@ But handle the case, if the \"test\" command is not available."
|
||||
(tramp-message v 0 "Wrote %s" filename))
|
||||
(run-hooks 'tramp-handle-write-region-hook))))
|
||||
|
||||
(defun tramp-adb-handle-set-file-modes (filename mode)
|
||||
(defun tramp-adb-handle-set-file-modes (filename mode &optional flag)
|
||||
"Like `set-file-modes' for Tramp files."
|
||||
flag ;; FIXME: Support 'nofollow'.
|
||||
(with-parsed-tramp-file-name filename nil
|
||||
(tramp-flush-file-properties v localname)
|
||||
(tramp-adb-send-command-and-check v (format "chmod %o %s" mode localname))))
|
||||
|
@ -1562,12 +1562,12 @@ If FILE-SYSTEM is non-nil, return file system attributes."
|
||||
(tramp-run-real-handler
|
||||
#'rename-file (list filename newname ok-if-already-exists))))
|
||||
|
||||
(defun tramp-gvfs-handle-set-file-modes (filename mode)
|
||||
(defun tramp-gvfs-handle-set-file-modes (filename mode &optional flag)
|
||||
"Like `set-file-modes' for Tramp files."
|
||||
(with-parsed-tramp-file-name filename nil
|
||||
(tramp-flush-file-properties v localname)
|
||||
(tramp-gvfs-send-command
|
||||
v "gvfs-set-attribute" "-t" "uint32"
|
||||
v "gvfs-set-attribute" (if flag "-nt" "-t") "uint32"
|
||||
(tramp-gvfs-url-file-name (tramp-make-tramp-file-name v))
|
||||
"unix::mode" (number-to-string mode))))
|
||||
|
||||
|
@ -1478,10 +1478,11 @@ of."
|
||||
;; only if that agrees with the buffer's record.
|
||||
(t (tramp-compat-time-equal-p mt tramp-time-doesnt-exist)))))))))
|
||||
|
||||
(defun tramp-sh-handle-set-file-modes (filename mode)
|
||||
(defun tramp-sh-handle-set-file-modes (filename mode &optional flag)
|
||||
"Like `set-file-modes' for Tramp files."
|
||||
(with-parsed-tramp-file-name filename nil
|
||||
(tramp-flush-file-properties v localname)
|
||||
flag ;; FIXME: Support 'nofollow'.
|
||||
;; FIXME: extract the proper text from chmod's stderr.
|
||||
(tramp-barf-unless-okay
|
||||
v
|
||||
@ -2279,7 +2280,7 @@ the uid and gid from FILENAME."
|
||||
;; We must change the ownership as local user.
|
||||
;; Since this does not work reliable, we also
|
||||
;; give read permissions.
|
||||
(set-file-modes tmpfile #o0777)
|
||||
(set-file-modes tmpfile #o0777 'nofollow)
|
||||
(tramp-set-file-uid-gid
|
||||
tmpfile
|
||||
(tramp-get-remote-uid v 'integer)
|
||||
@ -3221,7 +3222,8 @@ STDERR can also be a file name."
|
||||
(delete-file tmpfile2)))))
|
||||
|
||||
;; Set proper permissions.
|
||||
(set-file-modes tmpfile (tramp-default-file-modes filename))
|
||||
(set-file-modes tmpfile (tramp-default-file-modes filename)
|
||||
'nofollow)
|
||||
;; Set local user ownership.
|
||||
(tramp-set-file-uid-gid tmpfile))
|
||||
|
||||
@ -3320,7 +3322,7 @@ STDERR can also be a file name."
|
||||
;; handles permissions.
|
||||
;; Ensure that it is still readable.
|
||||
(when modes
|
||||
(set-file-modes tmpfile (logior (or modes 0) #o0400)))
|
||||
(set-file-modes tmpfile (logior (or modes 0) #o0400) 'nofollow))
|
||||
|
||||
;; This is a bit lengthy due to the different methods
|
||||
;; possible for file transfer. First, we check whether the
|
||||
|
@ -1464,8 +1464,9 @@ component is used as the target of the symlink."
|
||||
(tramp-flush-connection-property v "process-name")
|
||||
(tramp-flush-connection-property v "process-buffer")))))))
|
||||
|
||||
(defun tramp-smb-handle-set-file-modes (filename mode)
|
||||
(defun tramp-smb-handle-set-file-modes (filename mode &optional flag)
|
||||
"Like `set-file-modes' for Tramp files."
|
||||
flag ;; FIXME: Support 'nofollow'.
|
||||
(with-parsed-tramp-file-name filename nil
|
||||
(when (tramp-smb-get-cifs-capabilities v)
|
||||
(tramp-flush-file-properties v localname)
|
||||
|
@ -463,8 +463,9 @@ the result will be a local, non-Tramp, file name."
|
||||
(tramp-sudoedit-send-command
|
||||
v "test" "-r" (tramp-compat-file-name-unquote localname)))))
|
||||
|
||||
(defun tramp-sudoedit-handle-set-file-modes (filename mode)
|
||||
(defun tramp-sudoedit-handle-set-file-modes (filename mode &optional flag)
|
||||
"Like `set-file-modes' for Tramp files."
|
||||
flag ;; FIXME: Support 'nofollow'.
|
||||
(with-parsed-tramp-file-name filename nil
|
||||
(tramp-flush-file-properties v localname)
|
||||
(unless (tramp-sudoedit-send-command
|
||||
@ -735,7 +736,8 @@ ID-FORMAT valid values are `string' and `integer'."
|
||||
(file-attributes filename 'integer))
|
||||
gid))
|
||||
(tramp-set-file-uid-gid filename uid gid))
|
||||
(set-file-modes filename modes)))))
|
||||
(set-file-modes filename modes
|
||||
(when (eq mustbenew 'excl) 'nofollow))))))
|
||||
|
||||
|
||||
;; Internal functions.
|
||||
|
@ -3179,10 +3179,13 @@ User is always nil."
|
||||
(copy-file filename tmpfile 'ok-if-already-exists 'keep-time)
|
||||
tmpfile)))
|
||||
|
||||
(defun tramp-handle-file-modes (filename)
|
||||
(defun tramp-handle-file-modes (filename &optional flag)
|
||||
"Like `file-modes' for Tramp files."
|
||||
(when-let ((attrs (file-attributes (or (file-truename filename) filename))))
|
||||
(tramp-mode-string-to-int (tramp-compat-file-attribute-modes attrs))))
|
||||
(when-let ((attrs (file-attributes filename)))
|
||||
(let ((mode-string (tramp-compat-file-attribute-modes attrs)))
|
||||
(if (and (not flag) (eq ?l (aref mode-string 0)))
|
||||
(tramp-handle-file-modes (file-chase-links filename) 'nofollow)
|
||||
(tramp-mode-string-to-int mode-string)))))
|
||||
|
||||
;; Localname manipulation functions that grok Tramp localnames...
|
||||
(defun tramp-handle-file-name-as-directory (file)
|
||||
@ -3884,7 +3887,7 @@ of."
|
||||
;; renamed to the backup file. This case `save-buffer'
|
||||
;; handles permissions.
|
||||
;; Ensure that it is still readable.
|
||||
(set-file-modes tmpfile (logior (or modes 0) #o0400))
|
||||
(set-file-modes tmpfile (logior (or modes 0) #o0400) 'nofollow)
|
||||
;; We say `no-message' here because we don't want the visited file
|
||||
;; modtime data to be clobbered from the temp file. We call
|
||||
;; `set-visited-file-modtime' ourselves later on.
|
||||
@ -4664,7 +4667,7 @@ Return the local name of the temporary file."
|
||||
(setq result nil)
|
||||
;; This creates the file by side effect.
|
||||
(set-file-times result)
|
||||
(set-file-modes result #o0700)))
|
||||
(set-file-modes result #o0700 'nofollow)))
|
||||
|
||||
;; Return the local part.
|
||||
(tramp-file-local-name result)))
|
||||
|
@ -563,7 +563,7 @@ See variable `server-auth-dir' for details."
|
||||
(format "it is not owned by you (owner = %s (%d))"
|
||||
(user-full-name uid) uid))
|
||||
(w32 nil) ; on NTFS?
|
||||
((let ((modes (file-modes dir)))
|
||||
((let ((modes (file-modes dir 'nofollow)))
|
||||
(unless (zerop (logand (or modes 0) #o077))
|
||||
(format "it is accessible by others (%03o)" modes))))
|
||||
(t nil))))
|
||||
|
@ -615,9 +615,7 @@ Creates FILE and its parent directories if they do not exist."
|
||||
(with-temp-buffer
|
||||
(write-region (point-min) (point-max) file nil 'silent nil 'excl)))
|
||||
(file-already-exists
|
||||
(if (file-symlink-p file)
|
||||
(error "Danger: `%s' is a symbolic link" file))
|
||||
(set-file-modes file #o0600))))
|
||||
(set-file-modes file #o0600 'nofollow))))
|
||||
|
||||
(autoload 'puny-encode-domain "puny")
|
||||
(autoload 'url-domsuf-cookie-allowed-p "url-domsuf")
|
||||
|
82
m4/fchmodat.m4
Normal file
82
m4/fchmodat.m4
Normal file
@ -0,0 +1,82 @@
|
||||
# fchmodat.m4 serial 4
|
||||
dnl Copyright (C) 2004-2020 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# Written by Jim Meyering.
|
||||
|
||||
AC_DEFUN([gl_FUNC_FCHMODAT],
|
||||
[
|
||||
AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])
|
||||
AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
|
||||
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
|
||||
AC_CHECK_FUNCS_ONCE([fchmodat lchmod])
|
||||
if test $ac_cv_func_fchmodat != yes; then
|
||||
HAVE_FCHMODAT=0
|
||||
else
|
||||
AC_CACHE_CHECK(
|
||||
[whether fchmodat+AT_SYMLINK_NOFOLLOW works on non-symlinks],
|
||||
[gl_cv_func_fchmodat_works],
|
||||
[dnl This test fails on GNU/Linux with glibc 2.31 (but not on
|
||||
dnl GNU/kFreeBSD nor GNU/Hurd) and Cygwin 2.9.
|
||||
AC_RUN_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[
|
||||
AC_INCLUDES_DEFAULT[
|
||||
#include <fcntl.h>
|
||||
#ifndef S_IRUSR
|
||||
#define S_IRUSR 0400
|
||||
#endif
|
||||
#ifndef S_IWUSR
|
||||
#define S_IWUSR 0200
|
||||
#endif
|
||||
#ifndef S_IRWXU
|
||||
#define S_IRWXU 0700
|
||||
#endif
|
||||
#ifndef S_IRWXG
|
||||
#define S_IRWXG 0070
|
||||
#endif
|
||||
#ifndef S_IRWXO
|
||||
#define S_IRWXO 0007
|
||||
#endif
|
||||
]],
|
||||
[[
|
||||
int permissive = S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
int desired = S_IRUSR | S_IWUSR;
|
||||
static char const f[] = "conftest.fchmodat";
|
||||
struct stat st;
|
||||
if (creat (f, permissive) < 0)
|
||||
return 1;
|
||||
if (fchmodat (AT_FDCWD, f, desired, AT_SYMLINK_NOFOLLOW) != 0)
|
||||
return 1;
|
||||
if (stat (f, &st) != 0)
|
||||
return 1;
|
||||
return ! ((st.st_mode & permissive) == desired);
|
||||
]])],
|
||||
[gl_cv_func_fchmodat_works=yes],
|
||||
[gl_cv_func_fchmodat_works=no],
|
||||
[case "$host_os" in
|
||||
dnl Guess no on Linux with glibc and Cygwin, yes otherwise.
|
||||
linux-gnu* | cygwin*) gl_cv_func_fchmodat_works="guessing no" ;;
|
||||
*) gl_cv_func_fchmodat_works="$gl_cross_guess_normal" ;;
|
||||
esac
|
||||
])
|
||||
rm -f conftest.fchmodat])
|
||||
case $gl_cv_func_fchmodat_works in
|
||||
*yes) ;;
|
||||
*)
|
||||
AC_DEFINE([NEED_FCHMODAT_NONSYMLINK_FIX], [1],
|
||||
[Define to 1 if fchmodat+AT_SYMLINK_NOFOLLOW does not work right on non-symlinks.])
|
||||
REPLACE_FCHMODAT=1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
])
|
||||
|
||||
# Prerequisites of lib/fchmodat.c.
|
||||
AC_DEFUN([gl_PREREQ_FCHMODAT],
|
||||
[
|
||||
AC_CHECK_FUNCS_ONCE([lchmod])
|
||||
:
|
||||
])
|
@ -82,6 +82,7 @@ AC_DEFUN([gl_EARLY],
|
||||
# Code from module extensions:
|
||||
# Code from module extern-inline:
|
||||
# Code from module faccessat:
|
||||
# Code from module fchmodat:
|
||||
# Code from module fcntl:
|
||||
# Code from module fcntl-h:
|
||||
# Code from module fdopendir:
|
||||
@ -111,6 +112,7 @@ AC_DEFUN([gl_EARLY],
|
||||
# Code from module inttypes-incomplete:
|
||||
# Code from module largefile:
|
||||
AC_REQUIRE([AC_SYS_LARGEFILE])
|
||||
# Code from module lchmod:
|
||||
# Code from module libc-config:
|
||||
# Code from module limits-h:
|
||||
# Code from module localtime-buffer:
|
||||
@ -255,6 +257,12 @@ AC_DEFUN([gl_INIT],
|
||||
fi
|
||||
gl_MODULE_INDICATOR([faccessat])
|
||||
gl_UNISTD_MODULE_INDICATOR([faccessat])
|
||||
gl_FUNC_FCHMODAT
|
||||
if test $HAVE_FCHMODAT = 0 || test $REPLACE_FCHMODAT = 1; then
|
||||
AC_LIBOBJ([fchmodat])
|
||||
gl_PREREQ_FCHMODAT
|
||||
fi
|
||||
gl_SYS_STAT_MODULE_INDICATOR([fchmodat])
|
||||
gl_FUNC_FCNTL
|
||||
if test $HAVE_FCNTL = 0 || test $REPLACE_FCNTL = 1; then
|
||||
AC_LIBOBJ([fcntl])
|
||||
@ -468,6 +476,7 @@ AC_DEFUN([gl_INIT],
|
||||
gl_gnulib_enabled_getgroups=false
|
||||
gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36=false
|
||||
gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1=false
|
||||
gl_gnulib_enabled_lchmod=false
|
||||
gl_gnulib_enabled_21ee726a3540c09237a8e70c0baf7467=false
|
||||
gl_gnulib_enabled_2049e887c7e5308faad27b3f894bb8c9=false
|
||||
gl_gnulib_enabled_malloca=false
|
||||
@ -569,6 +578,18 @@ AC_DEFUN([gl_INIT],
|
||||
fi
|
||||
fi
|
||||
}
|
||||
func_gl_gnulib_m4code_lchmod ()
|
||||
{
|
||||
if ! $gl_gnulib_enabled_lchmod; then
|
||||
gl_FUNC_LCHMOD
|
||||
if test $HAVE_LCHMOD = 0; then
|
||||
AC_LIBOBJ([lchmod])
|
||||
gl_PREREQ_LCHMOD
|
||||
fi
|
||||
gl_SYS_STAT_MODULE_INDICATOR([lchmod])
|
||||
gl_gnulib_enabled_lchmod=true
|
||||
fi
|
||||
}
|
||||
func_gl_gnulib_m4code_21ee726a3540c09237a8e70c0baf7467 ()
|
||||
{
|
||||
if ! $gl_gnulib_enabled_21ee726a3540c09237a8e70c0baf7467; then
|
||||
@ -660,6 +681,15 @@ AC_DEFUN([gl_INIT],
|
||||
if test $HAVE_FACCESSAT = 0 || test $REPLACE_FACCESSAT = 1; then
|
||||
func_gl_gnulib_m4code_03e0aaad4cb89ca757653bd367a6ccb7
|
||||
fi
|
||||
if test $HAVE_FCHMODAT = 0; then
|
||||
func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b
|
||||
fi
|
||||
if test $HAVE_FCHMODAT = 0; then
|
||||
func_gl_gnulib_m4code_lchmod
|
||||
fi
|
||||
if test $HAVE_FCHMODAT = 0; then
|
||||
func_gl_gnulib_m4code_03e0aaad4cb89ca757653bd367a6ccb7
|
||||
fi
|
||||
if test $HAVE_FCNTL = 0 || test $REPLACE_FCNTL = 1; then
|
||||
func_gl_gnulib_m4code_getdtablesize
|
||||
fi
|
||||
@ -708,6 +738,7 @@ AC_DEFUN([gl_INIT],
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_getgroups], [$gl_gnulib_enabled_getgroups])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36], [$gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1], [$gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_lchmod], [$gl_gnulib_enabled_lchmod])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_21ee726a3540c09237a8e70c0baf7467], [$gl_gnulib_enabled_21ee726a3540c09237a8e70c0baf7467])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_2049e887c7e5308faad27b3f894bb8c9], [$gl_gnulib_enabled_2049e887c7e5308faad27b3f894bb8c9])
|
||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_malloca], [$gl_gnulib_enabled_malloca])
|
||||
@ -908,6 +939,7 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||
lib/execinfo.in.h
|
||||
lib/explicit_bzero.c
|
||||
lib/faccessat.c
|
||||
lib/fchmodat.c
|
||||
lib/fcntl.c
|
||||
lib/fcntl.in.h
|
||||
lib/fdopendir.c
|
||||
@ -946,6 +978,7 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||
lib/ignore-value.h
|
||||
lib/intprops.h
|
||||
lib/inttypes.in.h
|
||||
lib/lchmod.c
|
||||
lib/libc-config.h
|
||||
lib/limits.in.h
|
||||
lib/localtime-buffer.c
|
||||
@ -1058,6 +1091,7 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||
m4/extensions.m4
|
||||
m4/extern-inline.m4
|
||||
m4/faccessat.m4
|
||||
m4/fchmodat.m4
|
||||
m4/fcntl-o.m4
|
||||
m4/fcntl.m4
|
||||
m4/fcntl_h.m4
|
||||
@ -1083,6 +1117,7 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||
m4/include_next.m4
|
||||
m4/inttypes.m4
|
||||
m4/largefile.m4
|
||||
m4/lchmod.m4
|
||||
m4/limits-h.m4
|
||||
m4/localtime-buffer.m4
|
||||
m4/lstat.m4
|
||||
|
31
m4/lchmod.m4
Normal file
31
m4/lchmod.m4
Normal file
@ -0,0 +1,31 @@
|
||||
#serial 7
|
||||
|
||||
dnl Copyright (C) 2005-2006, 2008-2020 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
dnl From Paul Eggert.
|
||||
dnl Provide a replacement for lchmod on hosts that lack a working version.
|
||||
|
||||
AC_DEFUN([gl_FUNC_LCHMOD],
|
||||
[
|
||||
AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])
|
||||
|
||||
dnl Persuade glibc <sys/stat.h> to declare lchmod().
|
||||
AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
|
||||
|
||||
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
|
||||
|
||||
AC_CHECK_FUNCS_ONCE([lchmod lstat])
|
||||
if test "$ac_cv_func_lchmod" = no; then
|
||||
HAVE_LCHMOD=0
|
||||
fi
|
||||
])
|
||||
|
||||
# Prerequisites of lib/lchmod.c.
|
||||
AC_DEFUN([gl_PREREQ_LCHMOD],
|
||||
[
|
||||
AC_REQUIRE([AC_C_INLINE])
|
||||
:
|
||||
])
|
46
src/fileio.c
46
src/fileio.c
@ -3332,50 +3332,60 @@ support. */)
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
|
||||
static int
|
||||
symlink_nofollow_flag (Lisp_Object flag)
|
||||
{
|
||||
/* For now, treat all non-nil FLAGs like 'nofollow'. */
|
||||
return !NILP (flag) ? AT_SYMLINK_NOFOLLOW : 0;
|
||||
}
|
||||
|
||||
DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 2, 0,
|
||||
doc: /* Return mode bits of file named FILENAME, as an integer.
|
||||
Return nil if FILENAME does not exist. */)
|
||||
(Lisp_Object filename)
|
||||
Return nil if FILENAME does not exist. If optional FLAG is `nofollow',
|
||||
do not follow FILENAME if it is a symbolic link. */)
|
||||
(Lisp_Object filename, Lisp_Object flag)
|
||||
{
|
||||
struct stat st;
|
||||
int nofollow = symlink_nofollow_flag (flag);
|
||||
Lisp_Object absname = expand_and_dir_to_file (filename);
|
||||
|
||||
/* If the file name has special constructs in it,
|
||||
call the corresponding file name handler. */
|
||||
Lisp_Object handler = Ffind_file_name_handler (absname, Qfile_modes);
|
||||
if (!NILP (handler))
|
||||
return call2 (handler, Qfile_modes, absname);
|
||||
return call3 (handler, Qfile_modes, absname, flag);
|
||||
|
||||
if (emacs_fstatat (AT_FDCWD, SSDATA (ENCODE_FILE (absname)), &st, 0) != 0)
|
||||
char *fname = SSDATA (ENCODE_FILE (absname));
|
||||
if (emacs_fstatat (AT_FDCWD, fname, &st, nofollow) != 0)
|
||||
return file_attribute_errno (absname, errno);
|
||||
return make_fixnum (st.st_mode & 07777);
|
||||
}
|
||||
|
||||
DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 2,
|
||||
DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 3,
|
||||
"(let ((file (read-file-name \"File: \"))) \
|
||||
(list file (read-file-modes nil file)))",
|
||||
doc: /* Set mode bits of file named FILENAME to MODE (an integer).
|
||||
Only the 12 low bits of MODE are used.
|
||||
Only the 12 low bits of MODE are used. If optional FLAG is `nofollow',
|
||||
do not follow FILENAME if it is a symbolic link.
|
||||
|
||||
Interactively, mode bits are read by `read-file-modes', which accepts
|
||||
symbolic notation, like the `chmod' command from GNU Coreutils. */)
|
||||
(Lisp_Object filename, Lisp_Object mode)
|
||||
(Lisp_Object filename, Lisp_Object mode, Lisp_Object flag)
|
||||
{
|
||||
Lisp_Object absname, encoded_absname;
|
||||
Lisp_Object handler;
|
||||
|
||||
absname = Fexpand_file_name (filename, BVAR (current_buffer, directory));
|
||||
CHECK_FIXNUM (mode);
|
||||
int nofollow = symlink_nofollow_flag (flag);
|
||||
Lisp_Object absname = Fexpand_file_name (filename,
|
||||
BVAR (current_buffer, directory));
|
||||
|
||||
/* If the file name has special constructs in it,
|
||||
call the corresponding file name handler. */
|
||||
handler = Ffind_file_name_handler (absname, Qset_file_modes);
|
||||
Lisp_Object handler = Ffind_file_name_handler (absname, Qset_file_modes);
|
||||
if (!NILP (handler))
|
||||
return call3 (handler, Qset_file_modes, absname, mode);
|
||||
return call4 (handler, Qset_file_modes, absname, mode, flag);
|
||||
|
||||
encoded_absname = ENCODE_FILE (absname);
|
||||
|
||||
if (chmod (SSDATA (encoded_absname), XFIXNUM (mode) & 07777) < 0)
|
||||
char *fname = SSDATA (ENCODE_FILE (absname));
|
||||
mode_t imode = XFIXNUM (mode) & 07777;
|
||||
if (fchmodat (AT_FDCWD, fname, imode, nofollow) != 0)
|
||||
report_file_error ("Doing chmod", absname);
|
||||
|
||||
return Qnil;
|
||||
@ -5740,7 +5750,7 @@ auto_save_1 (void)
|
||||
== 0)
|
||||
/* But make sure we can overwrite it later! */
|
||||
auto_save_mode_bits = (st.st_mode | 0600) & 0777;
|
||||
else if (modes = Ffile_modes (BVAR (current_buffer, filename)),
|
||||
else if (modes = Ffile_modes (BVAR (current_buffer, filename), Qnil),
|
||||
FIXNUMP (modes))
|
||||
/* Remote files don't cooperate with fstatat. */
|
||||
auto_save_mode_bits = (XFIXNUM (modes) | 0600) & 0777;
|
||||
|
Loading…
Reference in New Issue
Block a user