Add support for preserving ACL entries of files.

* configure.ac (acl): New option.
	(HAVE_POSIX_ACL): Test for POSIX ACL support.  This is typically
	provided by libacl on GNU/Linux.

	* fileio.c (Ffile_acl, Fset_file_acl): New functions.
	(Fcopy_file): Change last arg to `preserve_extended_attributes'
	and copy ACL entries of file in addition to SELinux context if
	set.
	(syms_of_fileio): Add `file-acl' and `set-file-acl'.

	* Makefile.in (LIBACL_LIBS): New macro.
	(LIBES): Use it.

	* files.el (file-extended-attributes)
	(set-file-extended-attributes): New functions.
	(backup-buffer): Use them to handle both SELinux context and ACL
	entries.
	(backup-buffer-copy): Work with an alist of extended attributes,
	rather than an SELinux context.
	(basic-save-buffer-2): Ditto.

	* files.texi (File Attributes): Document ACL support and new
	`file-acl' function.
	(Changing Files): Mention argument name change of `copy-file' and
	document new function `set-file-acl'.
This commit is contained in:
Romain Francoise 2012-12-16 19:22:27 +01:00
parent a5e9740d8e
commit 7c3d167f48
10 changed files with 311 additions and 31 deletions

View file

@ -1,3 +1,9 @@
2012-12-16 Romain Francoise <romain@orebokech.com>
* configure.ac (acl): New option.
(HAVE_POSIX_ACL): Test for POSIX ACL support. This is typically
provided by libacl on GNU/Linux.
2012-12-14 Paul Eggert <eggert@cs.ucla.edu> 2012-12-14 Paul Eggert <eggert@cs.ucla.edu>
Fix permissions bugs with setgid directories etc. (Bug#13125) Fix permissions bugs with setgid directories etc. (Bug#13125)

View file

@ -184,6 +184,7 @@ OPTION_DEFAULT_ON([dbus],[don't compile with D-Bus support])
OPTION_DEFAULT_ON([gconf],[don't compile with GConf support]) OPTION_DEFAULT_ON([gconf],[don't compile with GConf support])
OPTION_DEFAULT_ON([gsettings],[don't compile with GSettings support]) OPTION_DEFAULT_ON([gsettings],[don't compile with GSettings support])
OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support]) OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support])
OPTION_DEFAULT_ON([acl],[don't compile with ACL support])
OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support]) OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support])
OPTION_DEFAULT_ON([inotify],[don't compile with inotify (file-watch) support]) OPTION_DEFAULT_ON([inotify],[don't compile with inotify (file-watch) support])
@ -2197,6 +2198,23 @@ if test "$ac_cv_func_inotify_init1" = yes; then
AC_DEFINE(HAVE_INOTIFY, 1, [Define to 1 to use inotify.]) AC_DEFINE(HAVE_INOTIFY, 1, [Define to 1 to use inotify.])
fi fi
dnl POSIX ACL support: provided by libacl on GNU/Linux, by libc on FreeBSD.
HAVE_POSIX_ACL=no
LIBACL_LIBS=
if test "${with_acl}" = "yes"; then
AC_CHECK_LIB([acl], [acl_set_file], HAVE_POSIX_ACL=yes, HAVE_POSIX_ACL=no)
if test "$HAVE_POSIX_ACL" = yes; then
AC_DEFINE(HAVE_POSIX_ACL, 1, [Define to 1 if using POSIX ACL support.])
LIBACL_LIBS=-lacl
else
AC_CHECK_FUNC(acl_set_file, HAVE_POSIX_ACL=yes, HAVE_POSIX_ACL=no)
if test "$HAVE_POSIX_ACL" = yes; then
AC_DEFINE(HAVE_POSIX_ACL, 1, [Define to 1 if using POSIX ACL support.])
fi
fi
fi
AC_SUBST(LIBACL_LIBS)
dnl Do not put whitespace before the #include statements below. dnl Do not put whitespace before the #include statements below.
dnl Older compilers (eg sunos4 cc) choke on it. dnl Older compilers (eg sunos4 cc) choke on it.
HAVE_XAW3D=no HAVE_XAW3D=no

View file

@ -1,3 +1,10 @@
2012-12-16 Romain Francoise <romain@orebokech.com>
* files.texi (File Attributes): Document ACL support and new
`file-acl' function.
(Changing Files): Mention argument name change of `copy-file' and
document new function `set-file-acl'.
2012-12-14 Paul Eggert <eggert@cs.ucla.edu> 2012-12-14 Paul Eggert <eggert@cs.ucla.edu>
Fix permissions bugs with setgid directories etc. (Bug#13125) Fix permissions bugs with setgid directories etc. (Bug#13125)

View file

@ -1352,6 +1352,36 @@ not support SELinux, or if Emacs was not compiled with SELinux
support, then the return value is @code{(nil nil nil nil)}. support, then the return value is @code{(nil nil nil nil)}.
@end defun @end defun
@cindex access control list
@cindex ACL entries
If Emacs has been compiled with @dfn{ACL} (access control list)
support, you can use the function @code{file-acl} to retrieve a file's
ACL entries. The format is platform-specific; on GNU/Linux and BSD,
Emacs uses the POSIX ACL interface. For the function
@code{set-file-acl}, see @ref{Changing Files}.
@defun file-acl filename
This function returns the ACL entries of the file @var{filename}.
The return value is a string containing the textual representation of
the ACL entries, like the following:
@example
@group
user::rw-
group::r--
group:gnu:rwx
mask::rwx
other::r--
@end group
@end example
If the file does not exist or is inaccessible, or if Emacs was unable to
determine the ACL entries, then the return value is @code{nil}. The
latter can happen for local files if Emacs was not compiled with ACL
support, or for remote files if the file handler returns nil for the
file's ACL entries.
@end defun
@node Locating Files @node Locating Files
@subsection How to Locate Files in Standard Places @subsection How to Locate Files in Standard Places
@cindex locate file in path @cindex locate file in path
@ -1541,9 +1571,10 @@ non-@code{nil}, we attempt to copy the user and group ownership of the
file. This works only on some operating systems, and only if you have file. This works only on some operating systems, and only if you have
the correct permissions to do so. the correct permissions to do so.
If the optional argument @var{preserve-selinux} is non-@code{nil}, and If the optional argument @var{preserve-extended-attributes} is
Emacs has been compiled with SELinux support, this function attempts non-@code{nil}, and Emacs has been built with the appropriate support,
to copy the file's SELinux context (@pxref{File Attributes}). this function attempts to copy the file's extended attributes, such as
its SELinux context and ACL entries (@pxref{File Attributes}).
@end deffn @end deffn
@deffn Command make-symbolic-link filename newname &optional ok-if-exists @deffn Command make-symbolic-link filename newname &optional ok-if-exists
@ -1684,6 +1715,13 @@ nothing if SELinux is disabled, or if Emacs was compiled without
SELinux support. SELinux support.
@end defun @end defun
@defun set-file-acl filename acl-string
This function sets the ACL entries of the file @var{filename} to
@var{acl-string}. @xref{File Attributes}, for a brief description of
ACLs. The @var{acl-string} argument should be a string containing the
textual representation of the desired ACL entries.
@end defun
@node File Names @node File Names
@section File Names @section File Names
@cindex file names @cindex file names

View file

@ -22,6 +22,12 @@ so we will look at it and add it to the manual.
* Installation Changes in Emacs 24.4 * Installation Changes in Emacs 24.4
** Emacs can be compiled with POSIX ACL support.
This happens by default if a suitable support library is found at
build time, like libacl on GNU/Linux. To prevent this, use the
configure option `--without-acl'.
* Startup Changes in Emacs 24.4 * Startup Changes in Emacs 24.4
* Changes in Emacs 24.4 * Changes in Emacs 24.4
@ -33,6 +39,14 @@ if there is one.
This unfinished feature was introduced by accident in Emacs 23.1; This unfinished feature was introduced by accident in Emacs 23.1;
simply disabling Transient Mark mode does the same thing. simply disabling Transient Mark mode does the same thing.
** ACL support has been added.
+++
*** Emacs preserves the ACL entries of files when backing up.
+++
*** New functions `file-acl' and `set-file-acl' get and set the ACL
entries of a file. On GNU/Linux the POSIX ACL interface is used via
libacl.
* Editing Changes in Emacs 24.4 * Editing Changes in Emacs 24.4
** New commands `toggle-frame-maximized' and `cycle-frame-maximized', ** New commands `toggle-frame-maximized' and `cycle-frame-maximized',
@ -149,6 +163,12 @@ special-forms any more.
VAR was bound to nil which was not tremendously useful and just lead to VAR was bound to nil which was not tremendously useful and just lead to
spurious warnings about an unused var. spurious warnings about an unused var.
** The return value of `backup-buffer' has changed.
The second argument is no longer an SELinux context, instead it is an
alist of extended attributes as returned by the new function
`file-extended-attributes'. The attributes can be applied to another
file using `set-file-extended-attributes'.
* Lisp changes in Emacs 24.4 * Lisp changes in Emacs 24.4
** Support for filesystem notifications. ** Support for filesystem notifications.
@ -186,6 +206,10 @@ used in place of the 9th element of `file-attributes'.
** New functions `group-gid' and `group-real-gid'. ** New functions `group-gid' and `group-real-gid'.
** The 6th argument to `copy-file' has been renamed to
`preserve-extended-attributes' as it now handles both SELinux context
and ACL entries.
* Changes in Emacs 24.4 on non-free operating systems * Changes in Emacs 24.4 on non-free operating systems
+++ +++

View file

@ -1,3 +1,13 @@
2012-12-16 Romain Francoise <romain@orebokech.com>
* files.el (file-extended-attributes)
(set-file-extended-attributes): New functions.
(backup-buffer): Use them to handle both SELinux context and ACL
entries.
(backup-buffer-copy): Work with an alist of extended attributes,
rather than an SELinux context.
(basic-save-buffer-2): Ditto.
2012-12-16 Timo Myyrä <timo.myyra@gmail.com> 2012-12-16 Timo Myyrä <timo.myyra@gmail.com>
* battery.el (battery-bsd-apm): New function. * battery.el (battery-bsd-apm): New function.

View file

@ -3879,6 +3879,27 @@ Interactively, confirmation is required unless you supply a prefix argument."
;; the one at the old location. ;; the one at the old location.
(vc-find-file-hook)) (vc-find-file-hook))
(defun file-extended-attributes (filename)
"Return an alist of extended attributes of file FILENAME.
Extended attributes are platform-specific metadata about the file,
such as SELinux context, list of ACL entries, etc."
`((acl . ,(file-acl filename))
(selinux-context . ,(file-selinux-context filename))))
(defun set-file-extended-attributes (filename attributes)
"Set extended attributes of file FILENAME to ATTRIBUTES.
ATTRIBUTES must be an alist of file attributes as returned by
`file-extended-attributes'."
(dolist (elt attributes)
(let ((attr (car elt))
(val (cdr elt)))
(cond ((eq attr 'acl)
(set-file-acl filename val))
((eq attr 'selinux-context)
(set-file-selinux-context filename val))))))
(defun backup-buffer () (defun backup-buffer ()
"Make a backup of the disk file visited by the current buffer, if appropriate. "Make a backup of the disk file visited by the current buffer, if appropriate.
This is normally done before saving the buffer the first time. This is normally done before saving the buffer the first time.
@ -3888,13 +3909,14 @@ variable `make-backup-files'. If it's done by renaming, then the file is
no longer accessible under its old name. no longer accessible under its old name.
The value is non-nil after a backup was made by renaming. The value is non-nil after a backup was made by renaming.
It has the form (MODES SELINUXCONTEXT BACKUPNAME). It has the form (MODES EXTENDED-ATTRIBUTES BACKUPNAME).
MODES is the result of `file-modes' on the original MODES is the result of `file-modes' on the original
file; this means that the caller, after saving the buffer, should change file; this means that the caller, after saving the buffer, should change
the modes of the new file to agree with the old modes. the modes of the new file to agree with the old modes.
SELINUXCONTEXT is the result of `file-selinux-context' on the original EXTENDED-ATTRIBUTES is the result of `file-extended-attributes'
file; this means that the caller, after saving the buffer, should change on the original file; this means that the caller, after saving
the SELinux context of the new file to agree with the old context. the buffer, should change the extended attributes of the new file
to agree with the old attributes.
BACKUPNAME is the backup file name, which is the old file renamed." BACKUPNAME is the backup file name, which is the old file renamed."
(if (and make-backup-files (not backup-inhibited) (if (and make-backup-files (not backup-inhibited)
(not buffer-backed-up) (not buffer-backed-up)
@ -3923,7 +3945,8 @@ BACKUPNAME is the backup file name, which is the old file renamed."
(y-or-n-p (format "Delete excess backup versions of %s? " (y-or-n-p (format "Delete excess backup versions of %s? "
real-file-name))))) real-file-name)))))
(modes (file-modes buffer-file-name)) (modes (file-modes buffer-file-name))
(context (file-selinux-context buffer-file-name))) (extended-attributes
(file-extended-attributes buffer-file-name)))
;; Actually write the back up file. ;; Actually write the back up file.
(condition-case () (condition-case ()
(if (or file-precious-flag (if (or file-precious-flag
@ -3943,10 +3966,13 @@ BACKUPNAME is the backup file name, which is the old file renamed."
(<= (nth 2 attr) backup-by-copying-when-privileged-mismatch))) (<= (nth 2 attr) backup-by-copying-when-privileged-mismatch)))
(not (file-ownership-preserved-p (not (file-ownership-preserved-p
real-file-name t)))))) real-file-name t))))))
(backup-buffer-copy real-file-name backupname modes context) (backup-buffer-copy real-file-name
backupname modes
extended-attributes)
;; rename-file should delete old backup. ;; rename-file should delete old backup.
(rename-file real-file-name backupname t) (rename-file real-file-name backupname t)
(setq setmodes (list modes context backupname))) (setq setmodes (list modes extended-attributes
backupname)))
(file-error (file-error
;; If trouble writing the backup, write it in ;; If trouble writing the backup, write it in
;; .emacs.d/%backup%. ;; .emacs.d/%backup%.
@ -3954,7 +3980,8 @@ BACKUPNAME is the backup file name, which is the old file renamed."
(message "Cannot write backup file; backing up in %s" (message "Cannot write backup file; backing up in %s"
backupname) backupname)
(sleep-for 1) (sleep-for 1)
(backup-buffer-copy real-file-name backupname modes context))) (backup-buffer-copy real-file-name backupname
modes extended-attributes)))
(setq buffer-backed-up t) (setq buffer-backed-up t)
;; Now delete the old versions, if desired. ;; Now delete the old versions, if desired.
(if delete-old-versions (if delete-old-versions
@ -3966,7 +3993,7 @@ BACKUPNAME is the backup file name, which is the old file renamed."
setmodes) setmodes)
(file-error nil)))))) (file-error nil))))))
(defun backup-buffer-copy (from-name to-name modes context) (defun backup-buffer-copy (from-name to-name modes extended-attributes)
(let ((umask (default-file-modes))) (let ((umask (default-file-modes)))
(unwind-protect (unwind-protect
(progn (progn
@ -3994,8 +4021,8 @@ BACKUPNAME is the backup file name, which is the old file renamed."
(set-default-file-modes umask))) (set-default-file-modes umask)))
(and modes (and modes
(set-file-modes to-name (logand modes #o1777))) (set-file-modes to-name (logand modes #o1777)))
(and context (and extended-attributes
(set-file-selinux-context to-name context))) (set-file-extended-attributes to-name extended-attributes)))
(defvar file-name-version-regexp (defvar file-name-version-regexp
"\\(?:~\\|\\.~[-[:alnum:]:#@^._]+\\(?:~[[:digit:]]+\\)?~\\)" "\\(?:~\\|\\.~[-[:alnum:]:#@^._]+\\(?:~[[:digit:]]+\\)?~\\)"
@ -4593,7 +4620,8 @@ Before and after saving the buffer, this function runs
(condition-case () (condition-case ()
(progn (progn
(set-file-modes buffer-file-name (car setmodes)) (set-file-modes buffer-file-name (car setmodes))
(set-file-selinux-context buffer-file-name (nth 1 setmodes))) (set-file-extended-attributes buffer-file-name
(nth 1 setmodes)))
(error nil)))) (error nil))))
;; If the auto-save file was recent before this command, ;; If the auto-save file was recent before this command,
;; delete it now. ;; delete it now.
@ -4606,7 +4634,8 @@ Before and after saving the buffer, this function runs
;; This does the "real job" of writing a buffer into its visited file ;; This does the "real job" of writing a buffer into its visited file
;; and making a backup file. This is what is normally done ;; and making a backup file. This is what is normally done
;; but inhibited if one of write-file-functions returns non-nil. ;; but inhibited if one of write-file-functions returns non-nil.
;; It returns a value (MODES SELINUXCONTEXT BACKUPNAME), like backup-buffer. ;; It returns a value (MODES EXTENDED-ATTRIBUTES BACKUPNAME), like
;; backup-buffer.
(defun basic-save-buffer-1 () (defun basic-save-buffer-1 ()
(prog1 (prog1
(if save-buffer-coding-system (if save-buffer-coding-system
@ -4618,7 +4647,8 @@ Before and after saving the buffer, this function runs
(setq buffer-file-coding-system-explicit (setq buffer-file-coding-system-explicit
(cons last-coding-system-used nil))))) (cons last-coding-system-used nil)))))
;; This returns a value (MODES SELINUXCONTEXT BACKUPNAME), like backup-buffer. ;; This returns a value (MODES EXTENDED-ATTRIBUTES BACKUPNAME), like
;; backup-buffer.
(defun basic-save-buffer-2 () (defun basic-save-buffer-2 ()
(let (tempsetmodes setmodes) (let (tempsetmodes setmodes)
(if (not (file-writable-p buffer-file-name)) (if (not (file-writable-p buffer-file-name))
@ -4693,7 +4723,7 @@ Before and after saving the buffer, this function runs
(setq setmodes (or setmodes (setq setmodes (or setmodes
(list (or (file-modes buffer-file-name) (list (or (file-modes buffer-file-name)
(logand ?\666 umask)) (logand ?\666 umask))
(file-selinux-context buffer-file-name) (file-extended-attributes buffer-file-name)
buffer-file-name))) buffer-file-name)))
;; We succeeded in writing the temp file, ;; We succeeded in writing the temp file,
;; so rename it. ;; so rename it.
@ -4705,10 +4735,10 @@ Before and after saving the buffer, this function runs
(cond ((and tempsetmodes (not setmodes)) (cond ((and tempsetmodes (not setmodes))
;; Change the mode back, after writing. ;; Change the mode back, after writing.
(setq setmodes (list (file-modes buffer-file-name) (setq setmodes (list (file-modes buffer-file-name)
(file-selinux-context buffer-file-name) (file-extended-attributes buffer-file-name)
buffer-file-name)) buffer-file-name))
(set-file-modes buffer-file-name (logior (car setmodes) 128)) (set-file-modes buffer-file-name (logior (car setmodes) 128))
(set-file-selinux-context buffer-file-name (nth 1 setmodes))))) (set-file-extended-attributes buffer-file-name (nth 1 setmodes)))))
(let (success) (let (success)
(unwind-protect (unwind-protect
(progn (progn

View file

@ -1,3 +1,14 @@
2012-12-16 Romain Francoise <romain@orebokech.com>
* fileio.c (Ffile_acl, Fset_file_acl): New functions.
(Fcopy_file): Change last arg to `preserve_extended_attributes'
and copy ACL entries of file in addition to SELinux context if
set.
(syms_of_fileio): Add `file-acl' and `set-file-acl'.
* Makefile.in (LIBACL_LIBS): New macro.
(LIBES): Use it.
2012-12-15 Paul Eggert <eggert@cs.ucla.edu> 2012-12-15 Paul Eggert <eggert@cs.ucla.edu>
* fileio.c (internal_delete_file): Use bool for boolean. * fileio.c (internal_delete_file): Use bool for boolean.

View file

@ -292,6 +292,8 @@ LIBSELINUX_LIBS = @LIBSELINUX_LIBS@
LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@ LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@
LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@ LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@
LIBACL_LIBS = @LIBACL_LIBS@
LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@ LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@
INTERVALS_H = dispextern.h intervals.h composite.h INTERVALS_H = dispextern.h intervals.h composite.h
@ -406,7 +408,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBX_BASE) $(LIBIMAGE) \
$(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \ $(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
$(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \ $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \
$(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \ $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
$(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(LIB_PTHREAD_SIGMASK) \ $(LIBACL_LIBS) $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(LIB_PTHREAD_SIGMASK) \
$(LIB_GCC) $(LIB_MATH) $(LIB_STANDARD) $(LIB_GCC) $(LIB_GCC) $(LIB_MATH) $(LIB_STANDARD) $(LIB_GCC)
all: emacs$(EXEEXT) $(OTHER_FILES) all: emacs$(EXEEXT) $(OTHER_FILES)

View file

@ -36,6 +36,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <selinux/context.h> #include <selinux/context.h>
#endif #endif
#ifdef HAVE_POSIX_ACL
#include <sys/acl.h>
#endif
#include <c-ctype.h> #include <c-ctype.h>
#include "lisp.h" #include "lisp.h"
@ -236,6 +240,8 @@ static Lisp_Object Qset_file_modes;
static Lisp_Object Qset_file_times; static Lisp_Object Qset_file_times;
static Lisp_Object Qfile_selinux_context; static Lisp_Object Qfile_selinux_context;
static Lisp_Object Qset_file_selinux_context; static Lisp_Object Qset_file_selinux_context;
static Lisp_Object Qfile_acl;
static Lisp_Object Qset_file_acl;
static Lisp_Object Qfile_newer_than_file_p; static Lisp_Object Qfile_newer_than_file_p;
Lisp_Object Qinsert_file_contents; Lisp_Object Qinsert_file_contents;
Lisp_Object Qwrite_region; Lisp_Object Qwrite_region;
@ -1895,9 +1901,10 @@ A prefix arg makes KEEP-TIME non-nil.
If PRESERVE-UID-GID is non-nil, we try to transfer the If PRESERVE-UID-GID is non-nil, we try to transfer the
uid and gid of FILE to NEWNAME. uid and gid of FILE to NEWNAME.
If PRESERVE-SELINUX-CONTEXT is non-nil and SELinux is enabled If PRESERVE-EXTENDED-ATTRIBUTES is non-nil, we try to copy additional
on the system, we copy the SELinux context of FILE to NEWNAME. */) attributes of FILE to NEWNAME, such as its SELinux context and ACL
(Lisp_Object file, Lisp_Object newname, Lisp_Object ok_if_already_exists, Lisp_Object keep_time, Lisp_Object preserve_uid_gid, Lisp_Object preserve_selinux_context) entries (depending on how Emacs was built). */)
(Lisp_Object file, Lisp_Object newname, Lisp_Object ok_if_already_exists, Lisp_Object keep_time, Lisp_Object preserve_uid_gid, Lisp_Object preserve_extended_attributes)
{ {
int ifd, ofd; int ifd, ofd;
int n; int n;
@ -1911,6 +1918,9 @@ on the system, we copy the SELinux context of FILE to NEWNAME. */)
security_context_t con; security_context_t con;
int conlength = 0; int conlength = 0;
#endif #endif
#ifdef HAVE_POSIX_ACL
acl_t acl = NULL;
#endif
encoded_file = encoded_newname = Qnil; encoded_file = encoded_newname = Qnil;
GCPRO4 (file, newname, encoded_file, encoded_newname); GCPRO4 (file, newname, encoded_file, encoded_newname);
@ -1933,7 +1943,7 @@ on the system, we copy the SELinux context of FILE to NEWNAME. */)
if (!NILP (handler)) if (!NILP (handler))
RETURN_UNGCPRO (call7 (handler, Qcopy_file, file, newname, RETURN_UNGCPRO (call7 (handler, Qcopy_file, file, newname,
ok_if_already_exists, keep_time, preserve_uid_gid, ok_if_already_exists, keep_time, preserve_uid_gid,
preserve_selinux_context)); preserve_extended_attributes));
encoded_file = ENCODE_FILE (file); encoded_file = ENCODE_FILE (file);
encoded_newname = ENCODE_FILE (newname); encoded_newname = ENCODE_FILE (newname);
@ -1986,15 +1996,24 @@ on the system, we copy the SELinux context of FILE to NEWNAME. */)
if (fstat (ifd, &st) != 0) if (fstat (ifd, &st) != 0)
report_file_error ("Input file status", Fcons (file, Qnil)); report_file_error ("Input file status", Fcons (file, Qnil));
#if HAVE_LIBSELINUX if (!NILP (preserve_extended_attributes))
if (!NILP (preserve_selinux_context) && is_selinux_enabled ())
{ {
conlength = fgetfilecon (ifd, &con); #if HAVE_LIBSELINUX
if (conlength == -1) if (is_selinux_enabled ())
report_file_error ("Doing fgetfilecon", Fcons (file, Qnil)); {
} conlength = fgetfilecon (ifd, &con);
if (conlength == -1)
report_file_error ("Doing fgetfilecon", Fcons (file, Qnil));
}
#endif #endif
#ifdef HAVE_POSIX_ACL
acl = acl_get_fd (ifd);
if (acl == NULL && errno != ENOTSUP)
report_file_error ("Getting ACL", Fcons (file, Qnil));
#endif
}
if (out_st.st_mode != 0 if (out_st.st_mode != 0
&& st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino) && st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino)
{ {
@ -2075,6 +2094,17 @@ on the system, we copy the SELinux context of FILE to NEWNAME. */)
} }
#endif #endif
#ifdef HAVE_POSIX_ACL
if (acl != NULL)
{
bool fail = acl_set_fd (ofd, acl) != 0;
if (fail && errno != ENOTSUP)
report_file_error ("Setting ACL", Fcons (newname, Qnil));
acl_free (acl);
}
#endif
if (!NILP (keep_time)) if (!NILP (keep_time))
{ {
EMACS_TIME atime = get_stat_atime (&st); EMACS_TIME atime = get_stat_atime (&st);
@ -2961,6 +2991,106 @@ compiled with SELinux support. */)
return Qnil; return Qnil;
} }
DEFUN ("file-acl", Ffile_acl, Sfile_acl, 1, 1, 0,
doc: /* Return ACL entries of file named FILENAME, as a string.
Return nil if file does not exist or is not accessible, or if Emacs
was unable to determine the ACL entries. The latter can happen for
local files if Emacs was not compiled with ACL support, or for remote
files if the file handler returns nil for the file's ACL entries. */)
(Lisp_Object filename)
{
Lisp_Object absname;
Lisp_Object handler;
#ifdef HAVE_POSIX_ACL
acl_t acl;
Lisp_Object acl_string;
char *str;
#endif
absname = expand_and_dir_to_file (filename,
BVAR (current_buffer, directory));
/* If the file name has special constructs in it,
call the corresponding file handler. */
handler = Ffind_file_name_handler (absname, Qfile_acl);
if (!NILP (handler))
return call2 (handler, Qfile_acl, absname);
#ifdef HAVE_POSIX_ACL
absname = ENCODE_FILE (absname);
acl = acl_get_file (SSDATA (absname), ACL_TYPE_ACCESS);
if (acl == NULL)
return Qnil;
str = acl_to_text (acl, NULL);
if (str == NULL)
{
acl_free (acl);
return Qnil;
}
acl_string = build_string (str);
acl_free (str);
acl_free (acl);
return acl_string;
#endif
return Qnil;
}
DEFUN ("set-file-acl", Fset_file_acl, Sset_file_acl,
2, 2, 0,
doc: /* Set ACL of file named FILENAME to ACL-STRING.
ACL-STRING should contain the textual representation of the ACL
entries in a format suitable for the platform.
Setting ACL for local files requires Emacs to be built with ACL
support. */)
(Lisp_Object filename, Lisp_Object acl_string)
{
Lisp_Object absname;
Lisp_Object handler;
#ifdef HAVE_POSIX_ACL
Lisp_Object encoded_absname;
acl_t acl;
bool fail;
#endif
absname = Fexpand_file_name (filename, BVAR (current_buffer, directory));
/* If the file name has special constructs in it,
call the corresponding file handler. */
handler = Ffind_file_name_handler (absname, Qset_file_acl);
if (!NILP (handler))
return call3 (handler, Qset_file_acl, absname, acl_string);
#ifdef HAVE_POSIX_ACL
if (STRINGP (acl_string))
{
acl = acl_from_text (SSDATA (acl_string));
if (acl == NULL)
{
report_file_error ("Converting ACL", Fcons (absname, Qnil));
return Qnil;
}
encoded_absname = ENCODE_FILE (absname);
fail = (acl_set_file (SSDATA (encoded_absname), ACL_TYPE_ACCESS,
acl)
!= 0);
if (fail && errno != ENOTSUP)
report_file_error ("Setting ACL", Fcons (absname, Qnil));
acl_free (acl);
}
#endif
return Qnil;
}
DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0, DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
doc: /* Return mode bits of file named FILENAME, as an integer. doc: /* Return mode bits of file named FILENAME, as an integer.
Return nil, if file does not exist or is not accessible. */) Return nil, if file does not exist or is not accessible. */)
@ -5630,6 +5760,8 @@ syms_of_fileio (void)
DEFSYM (Qset_file_times, "set-file-times"); DEFSYM (Qset_file_times, "set-file-times");
DEFSYM (Qfile_selinux_context, "file-selinux-context"); DEFSYM (Qfile_selinux_context, "file-selinux-context");
DEFSYM (Qset_file_selinux_context, "set-file-selinux-context"); DEFSYM (Qset_file_selinux_context, "set-file-selinux-context");
DEFSYM (Qfile_acl, "file-acl");
DEFSYM (Qset_file_acl, "set-file-acl");
DEFSYM (Qfile_newer_than_file_p, "file-newer-than-file-p"); DEFSYM (Qfile_newer_than_file_p, "file-newer-than-file-p");
DEFSYM (Qinsert_file_contents, "insert-file-contents"); DEFSYM (Qinsert_file_contents, "insert-file-contents");
DEFSYM (Qwrite_region, "write-region"); DEFSYM (Qwrite_region, "write-region");
@ -5849,6 +5981,8 @@ This includes interactive calls to `delete-file' and
defsubr (&Sset_file_modes); defsubr (&Sset_file_modes);
defsubr (&Sset_file_times); defsubr (&Sset_file_times);
defsubr (&Sfile_selinux_context); defsubr (&Sfile_selinux_context);
defsubr (&Sfile_acl);
defsubr (&Sset_file_acl);
defsubr (&Sset_file_selinux_context); defsubr (&Sset_file_selinux_context);
defsubr (&Sset_default_file_modes); defsubr (&Sset_default_file_modes);
defsubr (&Sdefault_file_modes); defsubr (&Sdefault_file_modes);