diff options
| author | Romain Francoise | 2012-12-16 19:22:27 +0100 |
|---|---|---|
| committer | Romain Francoise | 2012-12-16 19:22:27 +0100 |
| commit | 7c3d167f48d6262ee4e5512aa50a07ee96bc1509 (patch) | |
| tree | 9d4c24c1c97ae0cb1763e51d6ab8e808283fb09b | |
| parent | a5e9740d8ecfd471ecbc1f02980b83b003c1a469 (diff) | |
| download | emacs-7c3d167f48d6262ee4e5512aa50a07ee96bc1509.tar.gz emacs-7c3d167f48d6262ee4e5512aa50a07ee96bc1509.zip | |
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'.
| -rw-r--r-- | ChangeLog | 6 | ||||
| -rw-r--r-- | configure.ac | 18 | ||||
| -rw-r--r-- | doc/lispref/ChangeLog | 7 | ||||
| -rw-r--r-- | doc/lispref/files.texi | 44 | ||||
| -rw-r--r-- | etc/NEWS | 24 | ||||
| -rw-r--r-- | lisp/ChangeLog | 10 | ||||
| -rw-r--r-- | lisp/files.el | 64 | ||||
| -rw-r--r-- | src/ChangeLog | 11 | ||||
| -rw-r--r-- | src/Makefile.in | 4 | ||||
| -rw-r--r-- | src/fileio.c | 154 |
10 files changed, 311 insertions, 31 deletions
| @@ -1,3 +1,9 @@ | |||
| 1 | 2012-12-16 Romain Francoise <romain@orebokech.com> | ||
| 2 | |||
| 3 | * configure.ac (acl): New option. | ||
| 4 | (HAVE_POSIX_ACL): Test for POSIX ACL support. This is typically | ||
| 5 | provided by libacl on GNU/Linux. | ||
| 6 | |||
| 1 | 2012-12-14 Paul Eggert <eggert@cs.ucla.edu> | 7 | 2012-12-14 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 8 | ||
| 3 | Fix permissions bugs with setgid directories etc. (Bug#13125) | 9 | Fix permissions bugs with setgid directories etc. (Bug#13125) |
diff --git a/configure.ac b/configure.ac index 1a7f78326eb..3c8be79e24c 100644 --- a/configure.ac +++ b/configure.ac | |||
| @@ -184,6 +184,7 @@ OPTION_DEFAULT_ON([dbus],[don't compile with D-Bus support]) | |||
| 184 | OPTION_DEFAULT_ON([gconf],[don't compile with GConf support]) | 184 | OPTION_DEFAULT_ON([gconf],[don't compile with GConf support]) |
| 185 | OPTION_DEFAULT_ON([gsettings],[don't compile with GSettings support]) | 185 | OPTION_DEFAULT_ON([gsettings],[don't compile with GSettings support]) |
| 186 | OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support]) | 186 | OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support]) |
| 187 | OPTION_DEFAULT_ON([acl],[don't compile with ACL support]) | ||
| 187 | OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support]) | 188 | OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support]) |
| 188 | OPTION_DEFAULT_ON([inotify],[don't compile with inotify (file-watch) support]) | 189 | OPTION_DEFAULT_ON([inotify],[don't compile with inotify (file-watch) support]) |
| 189 | 190 | ||
| @@ -2197,6 +2198,23 @@ if test "$ac_cv_func_inotify_init1" = yes; then | |||
| 2197 | AC_DEFINE(HAVE_INOTIFY, 1, [Define to 1 to use inotify.]) | 2198 | AC_DEFINE(HAVE_INOTIFY, 1, [Define to 1 to use inotify.]) |
| 2198 | fi | 2199 | fi |
| 2199 | 2200 | ||
| 2201 | dnl POSIX ACL support: provided by libacl on GNU/Linux, by libc on FreeBSD. | ||
| 2202 | HAVE_POSIX_ACL=no | ||
| 2203 | LIBACL_LIBS= | ||
| 2204 | if test "${with_acl}" = "yes"; then | ||
| 2205 | AC_CHECK_LIB([acl], [acl_set_file], HAVE_POSIX_ACL=yes, HAVE_POSIX_ACL=no) | ||
| 2206 | if test "$HAVE_POSIX_ACL" = yes; then | ||
| 2207 | AC_DEFINE(HAVE_POSIX_ACL, 1, [Define to 1 if using POSIX ACL support.]) | ||
| 2208 | LIBACL_LIBS=-lacl | ||
| 2209 | else | ||
| 2210 | AC_CHECK_FUNC(acl_set_file, HAVE_POSIX_ACL=yes, HAVE_POSIX_ACL=no) | ||
| 2211 | if test "$HAVE_POSIX_ACL" = yes; then | ||
| 2212 | AC_DEFINE(HAVE_POSIX_ACL, 1, [Define to 1 if using POSIX ACL support.]) | ||
| 2213 | fi | ||
| 2214 | fi | ||
| 2215 | fi | ||
| 2216 | AC_SUBST(LIBACL_LIBS) | ||
| 2217 | |||
| 2200 | dnl Do not put whitespace before the #include statements below. | 2218 | dnl Do not put whitespace before the #include statements below. |
| 2201 | dnl Older compilers (eg sunos4 cc) choke on it. | 2219 | dnl Older compilers (eg sunos4 cc) choke on it. |
| 2202 | HAVE_XAW3D=no | 2220 | HAVE_XAW3D=no |
diff --git a/doc/lispref/ChangeLog b/doc/lispref/ChangeLog index 8a99f8c9c40..922147844bd 100644 --- a/doc/lispref/ChangeLog +++ b/doc/lispref/ChangeLog | |||
| @@ -1,3 +1,10 @@ | |||
| 1 | 2012-12-16 Romain Francoise <romain@orebokech.com> | ||
| 2 | |||
| 3 | * files.texi (File Attributes): Document ACL support and new | ||
| 4 | `file-acl' function. | ||
| 5 | (Changing Files): Mention argument name change of `copy-file' and | ||
| 6 | document new function `set-file-acl'. | ||
| 7 | |||
| 1 | 2012-12-14 Paul Eggert <eggert@cs.ucla.edu> | 8 | 2012-12-14 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 9 | ||
| 3 | Fix permissions bugs with setgid directories etc. (Bug#13125) | 10 | Fix permissions bugs with setgid directories etc. (Bug#13125) |
diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index c0c2221a394..93bee961929 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi | |||
| @@ -1352,6 +1352,36 @@ not support SELinux, or if Emacs was not compiled with SELinux | |||
| 1352 | support, then the return value is @code{(nil nil nil nil)}. | 1352 | support, then the return value is @code{(nil nil nil nil)}. |
| 1353 | @end defun | 1353 | @end defun |
| 1354 | 1354 | ||
| 1355 | @cindex access control list | ||
| 1356 | @cindex ACL entries | ||
| 1357 | If Emacs has been compiled with @dfn{ACL} (access control list) | ||
| 1358 | support, you can use the function @code{file-acl} to retrieve a file's | ||
| 1359 | ACL entries. The format is platform-specific; on GNU/Linux and BSD, | ||
| 1360 | Emacs uses the POSIX ACL interface. For the function | ||
| 1361 | @code{set-file-acl}, see @ref{Changing Files}. | ||
| 1362 | |||
| 1363 | @defun file-acl filename | ||
| 1364 | This function returns the ACL entries of the file @var{filename}. | ||
| 1365 | The return value is a string containing the textual representation of | ||
| 1366 | the ACL entries, like the following: | ||
| 1367 | |||
| 1368 | @example | ||
| 1369 | @group | ||
| 1370 | user::rw- | ||
| 1371 | group::r-- | ||
| 1372 | group:gnu:rwx | ||
| 1373 | mask::rwx | ||
| 1374 | other::r-- | ||
| 1375 | @end group | ||
| 1376 | @end example | ||
| 1377 | |||
| 1378 | If the file does not exist or is inaccessible, or if Emacs was unable to | ||
| 1379 | determine the ACL entries, then the return value is @code{nil}. The | ||
| 1380 | latter can happen for local files if Emacs was not compiled with ACL | ||
| 1381 | support, or for remote files if the file handler returns nil for the | ||
| 1382 | file's ACL entries. | ||
| 1383 | @end defun | ||
| 1384 | |||
| 1355 | @node Locating Files | 1385 | @node Locating Files |
| 1356 | @subsection How to Locate Files in Standard Places | 1386 | @subsection How to Locate Files in Standard Places |
| 1357 | @cindex locate file in path | 1387 | @cindex locate file in path |
| @@ -1541,9 +1571,10 @@ non-@code{nil}, we attempt to copy the user and group ownership of the | |||
| 1541 | file. This works only on some operating systems, and only if you have | 1571 | file. This works only on some operating systems, and only if you have |
| 1542 | the correct permissions to do so. | 1572 | the correct permissions to do so. |
| 1543 | 1573 | ||
| 1544 | If the optional argument @var{preserve-selinux} is non-@code{nil}, and | 1574 | If the optional argument @var{preserve-extended-attributes} is |
| 1545 | Emacs has been compiled with SELinux support, this function attempts | 1575 | non-@code{nil}, and Emacs has been built with the appropriate support, |
| 1546 | to copy the file's SELinux context (@pxref{File Attributes}). | 1576 | this function attempts to copy the file's extended attributes, such as |
| 1577 | its SELinux context and ACL entries (@pxref{File Attributes}). | ||
| 1547 | @end deffn | 1578 | @end deffn |
| 1548 | 1579 | ||
| 1549 | @deffn Command make-symbolic-link filename newname &optional ok-if-exists | 1580 | @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 | |||
| 1684 | SELinux support. | 1715 | SELinux support. |
| 1685 | @end defun | 1716 | @end defun |
| 1686 | 1717 | ||
| 1718 | @defun set-file-acl filename acl-string | ||
| 1719 | This function sets the ACL entries of the file @var{filename} to | ||
| 1720 | @var{acl-string}. @xref{File Attributes}, for a brief description of | ||
| 1721 | ACLs. The @var{acl-string} argument should be a string containing the | ||
| 1722 | textual representation of the desired ACL entries. | ||
| 1723 | @end defun | ||
| 1724 | |||
| 1687 | @node File Names | 1725 | @node File Names |
| 1688 | @section File Names | 1726 | @section File Names |
| 1689 | @cindex file names | 1727 | @cindex file names |
| @@ -22,6 +22,12 @@ so we will look at it and add it to the manual. | |||
| 22 | 22 | ||
| 23 | 23 | ||
| 24 | * Installation Changes in Emacs 24.4 | 24 | * Installation Changes in Emacs 24.4 |
| 25 | |||
| 26 | ** Emacs can be compiled with POSIX ACL support. | ||
| 27 | This happens by default if a suitable support library is found at | ||
| 28 | build time, like libacl on GNU/Linux. To prevent this, use the | ||
| 29 | configure option `--without-acl'. | ||
| 30 | |||
| 25 | * Startup Changes in Emacs 24.4 | 31 | * Startup Changes in Emacs 24.4 |
| 26 | * Changes in Emacs 24.4 | 32 | * Changes in Emacs 24.4 |
| 27 | 33 | ||
| @@ -33,6 +39,14 @@ if there is one. | |||
| 33 | This unfinished feature was introduced by accident in Emacs 23.1; | 39 | This unfinished feature was introduced by accident in Emacs 23.1; |
| 34 | simply disabling Transient Mark mode does the same thing. | 40 | simply disabling Transient Mark mode does the same thing. |
| 35 | 41 | ||
| 42 | ** ACL support has been added. | ||
| 43 | +++ | ||
| 44 | *** Emacs preserves the ACL entries of files when backing up. | ||
| 45 | +++ | ||
| 46 | *** New functions `file-acl' and `set-file-acl' get and set the ACL | ||
| 47 | entries of a file. On GNU/Linux the POSIX ACL interface is used via | ||
| 48 | libacl. | ||
| 49 | |||
| 36 | * Editing Changes in Emacs 24.4 | 50 | * Editing Changes in Emacs 24.4 |
| 37 | 51 | ||
| 38 | ** New commands `toggle-frame-maximized' and `cycle-frame-maximized', | 52 | ** New commands `toggle-frame-maximized' and `cycle-frame-maximized', |
| @@ -149,6 +163,12 @@ special-forms any more. | |||
| 149 | VAR was bound to nil which was not tremendously useful and just lead to | 163 | VAR was bound to nil which was not tremendously useful and just lead to |
| 150 | spurious warnings about an unused var. | 164 | spurious warnings about an unused var. |
| 151 | 165 | ||
| 166 | ** The return value of `backup-buffer' has changed. | ||
| 167 | The second argument is no longer an SELinux context, instead it is an | ||
| 168 | alist of extended attributes as returned by the new function | ||
| 169 | `file-extended-attributes'. The attributes can be applied to another | ||
| 170 | file using `set-file-extended-attributes'. | ||
| 171 | |||
| 152 | * Lisp changes in Emacs 24.4 | 172 | * Lisp changes in Emacs 24.4 |
| 153 | 173 | ||
| 154 | ** Support for filesystem notifications. | 174 | ** Support for filesystem notifications. |
| @@ -186,6 +206,10 @@ used in place of the 9th element of `file-attributes'. | |||
| 186 | 206 | ||
| 187 | ** New functions `group-gid' and `group-real-gid'. | 207 | ** New functions `group-gid' and `group-real-gid'. |
| 188 | 208 | ||
| 209 | ** The 6th argument to `copy-file' has been renamed to | ||
| 210 | `preserve-extended-attributes' as it now handles both SELinux context | ||
| 211 | and ACL entries. | ||
| 212 | |||
| 189 | * Changes in Emacs 24.4 on non-free operating systems | 213 | * Changes in Emacs 24.4 on non-free operating systems |
| 190 | 214 | ||
| 191 | +++ | 215 | +++ |
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index e56b44ba525..0d65baebee2 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,13 @@ | |||
| 1 | 2012-12-16 Romain Francoise <romain@orebokech.com> | ||
| 2 | |||
| 3 | * files.el (file-extended-attributes) | ||
| 4 | (set-file-extended-attributes): New functions. | ||
| 5 | (backup-buffer): Use them to handle both SELinux context and ACL | ||
| 6 | entries. | ||
| 7 | (backup-buffer-copy): Work with an alist of extended attributes, | ||
| 8 | rather than an SELinux context. | ||
| 9 | (basic-save-buffer-2): Ditto. | ||
| 10 | |||
| 1 | 2012-12-16 Timo Myyrä <timo.myyra@gmail.com> | 11 | 2012-12-16 Timo Myyrä <timo.myyra@gmail.com> |
| 2 | 12 | ||
| 3 | * battery.el (battery-bsd-apm): New function. | 13 | * battery.el (battery-bsd-apm): New function. |
diff --git a/lisp/files.el b/lisp/files.el index 7974f73a248..3f29468e2d1 100644 --- a/lisp/files.el +++ b/lisp/files.el | |||
| @@ -3879,6 +3879,27 @@ Interactively, confirmation is required unless you supply a prefix argument." | |||
| 3879 | ;; the one at the old location. | 3879 | ;; the one at the old location. |
| 3880 | (vc-find-file-hook)) | 3880 | (vc-find-file-hook)) |
| 3881 | 3881 | ||
| 3882 | (defun file-extended-attributes (filename) | ||
| 3883 | "Return an alist of extended attributes of file FILENAME. | ||
| 3884 | |||
| 3885 | Extended attributes are platform-specific metadata about the file, | ||
| 3886 | such as SELinux context, list of ACL entries, etc." | ||
| 3887 | `((acl . ,(file-acl filename)) | ||
| 3888 | (selinux-context . ,(file-selinux-context filename)))) | ||
| 3889 | |||
| 3890 | (defun set-file-extended-attributes (filename attributes) | ||
| 3891 | "Set extended attributes of file FILENAME to ATTRIBUTES. | ||
| 3892 | |||
| 3893 | ATTRIBUTES must be an alist of file attributes as returned by | ||
| 3894 | `file-extended-attributes'." | ||
| 3895 | (dolist (elt attributes) | ||
| 3896 | (let ((attr (car elt)) | ||
| 3897 | (val (cdr elt))) | ||
| 3898 | (cond ((eq attr 'acl) | ||
| 3899 | (set-file-acl filename val)) | ||
| 3900 | ((eq attr 'selinux-context) | ||
| 3901 | (set-file-selinux-context filename val)))))) | ||
| 3902 | |||
| 3882 | (defun backup-buffer () | 3903 | (defun backup-buffer () |
| 3883 | "Make a backup of the disk file visited by the current buffer, if appropriate. | 3904 | "Make a backup of the disk file visited by the current buffer, if appropriate. |
| 3884 | This is normally done before saving the buffer the first time. | 3905 | 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 | |||
| 3888 | no longer accessible under its old name. | 3909 | no longer accessible under its old name. |
| 3889 | 3910 | ||
| 3890 | The value is non-nil after a backup was made by renaming. | 3911 | The value is non-nil after a backup was made by renaming. |
| 3891 | It has the form (MODES SELINUXCONTEXT BACKUPNAME). | 3912 | It has the form (MODES EXTENDED-ATTRIBUTES BACKUPNAME). |
| 3892 | MODES is the result of `file-modes' on the original | 3913 | MODES is the result of `file-modes' on the original |
| 3893 | file; this means that the caller, after saving the buffer, should change | 3914 | file; this means that the caller, after saving the buffer, should change |
| 3894 | the modes of the new file to agree with the old modes. | 3915 | the modes of the new file to agree with the old modes. |
| 3895 | SELINUXCONTEXT is the result of `file-selinux-context' on the original | 3916 | EXTENDED-ATTRIBUTES is the result of `file-extended-attributes' |
| 3896 | file; this means that the caller, after saving the buffer, should change | 3917 | on the original file; this means that the caller, after saving |
| 3897 | the SELinux context of the new file to agree with the old context. | 3918 | the buffer, should change the extended attributes of the new file |
| 3919 | to agree with the old attributes. | ||
| 3898 | BACKUPNAME is the backup file name, which is the old file renamed." | 3920 | BACKUPNAME is the backup file name, which is the old file renamed." |
| 3899 | (if (and make-backup-files (not backup-inhibited) | 3921 | (if (and make-backup-files (not backup-inhibited) |
| 3900 | (not buffer-backed-up) | 3922 | (not buffer-backed-up) |
| @@ -3923,7 +3945,8 @@ BACKUPNAME is the backup file name, which is the old file renamed." | |||
| 3923 | (y-or-n-p (format "Delete excess backup versions of %s? " | 3945 | (y-or-n-p (format "Delete excess backup versions of %s? " |
| 3924 | real-file-name))))) | 3946 | real-file-name))))) |
| 3925 | (modes (file-modes buffer-file-name)) | 3947 | (modes (file-modes buffer-file-name)) |
| 3926 | (context (file-selinux-context buffer-file-name))) | 3948 | (extended-attributes |
| 3949 | (file-extended-attributes buffer-file-name))) | ||
| 3927 | ;; Actually write the back up file. | 3950 | ;; Actually write the back up file. |
| 3928 | (condition-case () | 3951 | (condition-case () |
| 3929 | (if (or file-precious-flag | 3952 | (if (or file-precious-flag |
| @@ -3943,10 +3966,13 @@ BACKUPNAME is the backup file name, which is the old file renamed." | |||
| 3943 | (<= (nth 2 attr) backup-by-copying-when-privileged-mismatch))) | 3966 | (<= (nth 2 attr) backup-by-copying-when-privileged-mismatch))) |
| 3944 | (not (file-ownership-preserved-p | 3967 | (not (file-ownership-preserved-p |
| 3945 | real-file-name t)))))) | 3968 | real-file-name t)))))) |
| 3946 | (backup-buffer-copy real-file-name backupname modes context) | 3969 | (backup-buffer-copy real-file-name |
| 3970 | backupname modes | ||
| 3971 | extended-attributes) | ||
| 3947 | ;; rename-file should delete old backup. | 3972 | ;; rename-file should delete old backup. |
| 3948 | (rename-file real-file-name backupname t) | 3973 | (rename-file real-file-name backupname t) |
| 3949 | (setq setmodes (list modes context backupname))) | 3974 | (setq setmodes (list modes extended-attributes |
| 3975 | backupname))) | ||
| 3950 | (file-error | 3976 | (file-error |
| 3951 | ;; If trouble writing the backup, write it in | 3977 | ;; If trouble writing the backup, write it in |
| 3952 | ;; .emacs.d/%backup%. | 3978 | ;; .emacs.d/%backup%. |
| @@ -3954,7 +3980,8 @@ BACKUPNAME is the backup file name, which is the old file renamed." | |||
| 3954 | (message "Cannot write backup file; backing up in %s" | 3980 | (message "Cannot write backup file; backing up in %s" |
| 3955 | backupname) | 3981 | backupname) |
| 3956 | (sleep-for 1) | 3982 | (sleep-for 1) |
| 3957 | (backup-buffer-copy real-file-name backupname modes context))) | 3983 | (backup-buffer-copy real-file-name backupname |
| 3984 | modes extended-attributes))) | ||
| 3958 | (setq buffer-backed-up t) | 3985 | (setq buffer-backed-up t) |
| 3959 | ;; Now delete the old versions, if desired. | 3986 | ;; Now delete the old versions, if desired. |
| 3960 | (if delete-old-versions | 3987 | (if delete-old-versions |
| @@ -3966,7 +3993,7 @@ BACKUPNAME is the backup file name, which is the old file renamed." | |||
| 3966 | setmodes) | 3993 | setmodes) |
| 3967 | (file-error nil)))))) | 3994 | (file-error nil)))))) |
| 3968 | 3995 | ||
| 3969 | (defun backup-buffer-copy (from-name to-name modes context) | 3996 | (defun backup-buffer-copy (from-name to-name modes extended-attributes) |
| 3970 | (let ((umask (default-file-modes))) | 3997 | (let ((umask (default-file-modes))) |
| 3971 | (unwind-protect | 3998 | (unwind-protect |
| 3972 | (progn | 3999 | (progn |
| @@ -3994,8 +4021,8 @@ BACKUPNAME is the backup file name, which is the old file renamed." | |||
| 3994 | (set-default-file-modes umask))) | 4021 | (set-default-file-modes umask))) |
| 3995 | (and modes | 4022 | (and modes |
| 3996 | (set-file-modes to-name (logand modes #o1777))) | 4023 | (set-file-modes to-name (logand modes #o1777))) |
| 3997 | (and context | 4024 | (and extended-attributes |
| 3998 | (set-file-selinux-context to-name context))) | 4025 | (set-file-extended-attributes to-name extended-attributes))) |
| 3999 | 4026 | ||
| 4000 | (defvar file-name-version-regexp | 4027 | (defvar file-name-version-regexp |
| 4001 | "\\(?:~\\|\\.~[-[:alnum:]:#@^._]+\\(?:~[[:digit:]]+\\)?~\\)" | 4028 | "\\(?:~\\|\\.~[-[:alnum:]:#@^._]+\\(?:~[[:digit:]]+\\)?~\\)" |
| @@ -4593,7 +4620,8 @@ Before and after saving the buffer, this function runs | |||
| 4593 | (condition-case () | 4620 | (condition-case () |
| 4594 | (progn | 4621 | (progn |
| 4595 | (set-file-modes buffer-file-name (car setmodes)) | 4622 | (set-file-modes buffer-file-name (car setmodes)) |
| 4596 | (set-file-selinux-context buffer-file-name (nth 1 setmodes))) | 4623 | (set-file-extended-attributes buffer-file-name |
| 4624 | (nth 1 setmodes))) | ||
| 4597 | (error nil)))) | 4625 | (error nil)))) |
| 4598 | ;; If the auto-save file was recent before this command, | 4626 | ;; If the auto-save file was recent before this command, |
| 4599 | ;; delete it now. | 4627 | ;; delete it now. |
| @@ -4606,7 +4634,8 @@ Before and after saving the buffer, this function runs | |||
| 4606 | ;; This does the "real job" of writing a buffer into its visited file | 4634 | ;; This does the "real job" of writing a buffer into its visited file |
| 4607 | ;; and making a backup file. This is what is normally done | 4635 | ;; and making a backup file. This is what is normally done |
| 4608 | ;; but inhibited if one of write-file-functions returns non-nil. | 4636 | ;; but inhibited if one of write-file-functions returns non-nil. |
| 4609 | ;; It returns a value (MODES SELINUXCONTEXT BACKUPNAME), like backup-buffer. | 4637 | ;; It returns a value (MODES EXTENDED-ATTRIBUTES BACKUPNAME), like |
| 4638 | ;; backup-buffer. | ||
| 4610 | (defun basic-save-buffer-1 () | 4639 | (defun basic-save-buffer-1 () |
| 4611 | (prog1 | 4640 | (prog1 |
| 4612 | (if save-buffer-coding-system | 4641 | (if save-buffer-coding-system |
| @@ -4618,7 +4647,8 @@ Before and after saving the buffer, this function runs | |||
| 4618 | (setq buffer-file-coding-system-explicit | 4647 | (setq buffer-file-coding-system-explicit |
| 4619 | (cons last-coding-system-used nil))))) | 4648 | (cons last-coding-system-used nil))))) |
| 4620 | 4649 | ||
| 4621 | ;; This returns a value (MODES SELINUXCONTEXT BACKUPNAME), like backup-buffer. | 4650 | ;; This returns a value (MODES EXTENDED-ATTRIBUTES BACKUPNAME), like |
| 4651 | ;; backup-buffer. | ||
| 4622 | (defun basic-save-buffer-2 () | 4652 | (defun basic-save-buffer-2 () |
| 4623 | (let (tempsetmodes setmodes) | 4653 | (let (tempsetmodes setmodes) |
| 4624 | (if (not (file-writable-p buffer-file-name)) | 4654 | (if (not (file-writable-p buffer-file-name)) |
| @@ -4693,7 +4723,7 @@ Before and after saving the buffer, this function runs | |||
| 4693 | (setq setmodes (or setmodes | 4723 | (setq setmodes (or setmodes |
| 4694 | (list (or (file-modes buffer-file-name) | 4724 | (list (or (file-modes buffer-file-name) |
| 4695 | (logand ?\666 umask)) | 4725 | (logand ?\666 umask)) |
| 4696 | (file-selinux-context buffer-file-name) | 4726 | (file-extended-attributes buffer-file-name) |
| 4697 | buffer-file-name))) | 4727 | buffer-file-name))) |
| 4698 | ;; We succeeded in writing the temp file, | 4728 | ;; We succeeded in writing the temp file, |
| 4699 | ;; so rename it. | 4729 | ;; so rename it. |
| @@ -4705,10 +4735,10 @@ Before and after saving the buffer, this function runs | |||
| 4705 | (cond ((and tempsetmodes (not setmodes)) | 4735 | (cond ((and tempsetmodes (not setmodes)) |
| 4706 | ;; Change the mode back, after writing. | 4736 | ;; Change the mode back, after writing. |
| 4707 | (setq setmodes (list (file-modes buffer-file-name) | 4737 | (setq setmodes (list (file-modes buffer-file-name) |
| 4708 | (file-selinux-context buffer-file-name) | 4738 | (file-extended-attributes buffer-file-name) |
| 4709 | buffer-file-name)) | 4739 | buffer-file-name)) |
| 4710 | (set-file-modes buffer-file-name (logior (car setmodes) 128)) | 4740 | (set-file-modes buffer-file-name (logior (car setmodes) 128)) |
| 4711 | (set-file-selinux-context buffer-file-name (nth 1 setmodes))))) | 4741 | (set-file-extended-attributes buffer-file-name (nth 1 setmodes))))) |
| 4712 | (let (success) | 4742 | (let (success) |
| 4713 | (unwind-protect | 4743 | (unwind-protect |
| 4714 | (progn | 4744 | (progn |
diff --git a/src/ChangeLog b/src/ChangeLog index 54dcfca6fd5..3cf105c8003 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,14 @@ | |||
| 1 | 2012-12-16 Romain Francoise <romain@orebokech.com> | ||
| 2 | |||
| 3 | * fileio.c (Ffile_acl, Fset_file_acl): New functions. | ||
| 4 | (Fcopy_file): Change last arg to `preserve_extended_attributes' | ||
| 5 | and copy ACL entries of file in addition to SELinux context if | ||
| 6 | set. | ||
| 7 | (syms_of_fileio): Add `file-acl' and `set-file-acl'. | ||
| 8 | |||
| 9 | * Makefile.in (LIBACL_LIBS): New macro. | ||
| 10 | (LIBES): Use it. | ||
| 11 | |||
| 1 | 2012-12-15 Paul Eggert <eggert@cs.ucla.edu> | 12 | 2012-12-15 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 13 | ||
| 3 | * fileio.c (internal_delete_file): Use bool for boolean. | 14 | * fileio.c (internal_delete_file): Use bool for boolean. |
diff --git a/src/Makefile.in b/src/Makefile.in index 5f5fdfdc5eb..0e91eaecb17 100644 --- a/src/Makefile.in +++ b/src/Makefile.in | |||
| @@ -292,6 +292,8 @@ LIBSELINUX_LIBS = @LIBSELINUX_LIBS@ | |||
| 292 | LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@ | 292 | LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@ |
| 293 | LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@ | 293 | LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@ |
| 294 | 294 | ||
| 295 | LIBACL_LIBS = @LIBACL_LIBS@ | ||
| 296 | |||
| 295 | LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@ | 297 | LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@ |
| 296 | 298 | ||
| 297 | INTERVALS_H = dispextern.h intervals.h composite.h | 299 | INTERVALS_H = dispextern.h intervals.h composite.h |
| @@ -406,7 +408,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBX_BASE) $(LIBIMAGE) \ | |||
| 406 | $(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \ | 408 | $(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \ |
| 407 | $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \ | 409 | $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \ |
| 408 | $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \ | 410 | $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \ |
| 409 | $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(LIB_PTHREAD_SIGMASK) \ | 411 | $(LIBACL_LIBS) $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(LIB_PTHREAD_SIGMASK) \ |
| 410 | $(LIB_GCC) $(LIB_MATH) $(LIB_STANDARD) $(LIB_GCC) | 412 | $(LIB_GCC) $(LIB_MATH) $(LIB_STANDARD) $(LIB_GCC) |
| 411 | 413 | ||
| 412 | all: emacs$(EXEEXT) $(OTHER_FILES) | 414 | all: emacs$(EXEEXT) $(OTHER_FILES) |
diff --git a/src/fileio.c b/src/fileio.c index 90626c4af0e..f1cfe0eb625 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -36,6 +36,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 36 | #include <selinux/context.h> | 36 | #include <selinux/context.h> |
| 37 | #endif | 37 | #endif |
| 38 | 38 | ||
| 39 | #ifdef HAVE_POSIX_ACL | ||
| 40 | #include <sys/acl.h> | ||
| 41 | #endif | ||
| 42 | |||
| 39 | #include <c-ctype.h> | 43 | #include <c-ctype.h> |
| 40 | 44 | ||
| 41 | #include "lisp.h" | 45 | #include "lisp.h" |
| @@ -236,6 +240,8 @@ static Lisp_Object Qset_file_modes; | |||
| 236 | static Lisp_Object Qset_file_times; | 240 | static Lisp_Object Qset_file_times; |
| 237 | static Lisp_Object Qfile_selinux_context; | 241 | static Lisp_Object Qfile_selinux_context; |
| 238 | static Lisp_Object Qset_file_selinux_context; | 242 | static Lisp_Object Qset_file_selinux_context; |
| 243 | static Lisp_Object Qfile_acl; | ||
| 244 | static Lisp_Object Qset_file_acl; | ||
| 239 | static Lisp_Object Qfile_newer_than_file_p; | 245 | static Lisp_Object Qfile_newer_than_file_p; |
| 240 | Lisp_Object Qinsert_file_contents; | 246 | Lisp_Object Qinsert_file_contents; |
| 241 | Lisp_Object Qwrite_region; | 247 | Lisp_Object Qwrite_region; |
| @@ -1895,9 +1901,10 @@ A prefix arg makes KEEP-TIME non-nil. | |||
| 1895 | If PRESERVE-UID-GID is non-nil, we try to transfer the | 1901 | If PRESERVE-UID-GID is non-nil, we try to transfer the |
| 1896 | uid and gid of FILE to NEWNAME. | 1902 | uid and gid of FILE to NEWNAME. |
| 1897 | 1903 | ||
| 1898 | If PRESERVE-SELINUX-CONTEXT is non-nil and SELinux is enabled | 1904 | If PRESERVE-EXTENDED-ATTRIBUTES is non-nil, we try to copy additional |
| 1899 | on the system, we copy the SELinux context of FILE to NEWNAME. */) | 1905 | attributes of FILE to NEWNAME, such as its SELinux context and ACL |
| 1900 | (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) | 1906 | entries (depending on how Emacs was built). */) |
| 1907 | (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) | ||
| 1901 | { | 1908 | { |
| 1902 | int ifd, ofd; | 1909 | int ifd, ofd; |
| 1903 | int n; | 1910 | int n; |
| @@ -1911,6 +1918,9 @@ on the system, we copy the SELinux context of FILE to NEWNAME. */) | |||
| 1911 | security_context_t con; | 1918 | security_context_t con; |
| 1912 | int conlength = 0; | 1919 | int conlength = 0; |
| 1913 | #endif | 1920 | #endif |
| 1921 | #ifdef HAVE_POSIX_ACL | ||
| 1922 | acl_t acl = NULL; | ||
| 1923 | #endif | ||
| 1914 | 1924 | ||
| 1915 | encoded_file = encoded_newname = Qnil; | 1925 | encoded_file = encoded_newname = Qnil; |
| 1916 | GCPRO4 (file, newname, encoded_file, encoded_newname); | 1926 | GCPRO4 (file, newname, encoded_file, encoded_newname); |
| @@ -1933,7 +1943,7 @@ on the system, we copy the SELinux context of FILE to NEWNAME. */) | |||
| 1933 | if (!NILP (handler)) | 1943 | if (!NILP (handler)) |
| 1934 | RETURN_UNGCPRO (call7 (handler, Qcopy_file, file, newname, | 1944 | RETURN_UNGCPRO (call7 (handler, Qcopy_file, file, newname, |
| 1935 | ok_if_already_exists, keep_time, preserve_uid_gid, | 1945 | ok_if_already_exists, keep_time, preserve_uid_gid, |
| 1936 | preserve_selinux_context)); | 1946 | preserve_extended_attributes)); |
| 1937 | 1947 | ||
| 1938 | encoded_file = ENCODE_FILE (file); | 1948 | encoded_file = ENCODE_FILE (file); |
| 1939 | encoded_newname = ENCODE_FILE (newname); | 1949 | encoded_newname = ENCODE_FILE (newname); |
| @@ -1986,14 +1996,23 @@ on the system, we copy the SELinux context of FILE to NEWNAME. */) | |||
| 1986 | if (fstat (ifd, &st) != 0) | 1996 | if (fstat (ifd, &st) != 0) |
| 1987 | report_file_error ("Input file status", Fcons (file, Qnil)); | 1997 | report_file_error ("Input file status", Fcons (file, Qnil)); |
| 1988 | 1998 | ||
| 1989 | #if HAVE_LIBSELINUX | 1999 | if (!NILP (preserve_extended_attributes)) |
| 1990 | if (!NILP (preserve_selinux_context) && is_selinux_enabled ()) | ||
| 1991 | { | 2000 | { |
| 1992 | conlength = fgetfilecon (ifd, &con); | 2001 | #if HAVE_LIBSELINUX |
| 1993 | if (conlength == -1) | 2002 | if (is_selinux_enabled ()) |
| 1994 | report_file_error ("Doing fgetfilecon", Fcons (file, Qnil)); | 2003 | { |
| 1995 | } | 2004 | conlength = fgetfilecon (ifd, &con); |
| 2005 | if (conlength == -1) | ||
| 2006 | report_file_error ("Doing fgetfilecon", Fcons (file, Qnil)); | ||
| 2007 | } | ||
| 2008 | #endif | ||
| 2009 | |||
| 2010 | #ifdef HAVE_POSIX_ACL | ||
| 2011 | acl = acl_get_fd (ifd); | ||
| 2012 | if (acl == NULL && errno != ENOTSUP) | ||
| 2013 | report_file_error ("Getting ACL", Fcons (file, Qnil)); | ||
| 1996 | #endif | 2014 | #endif |
| 2015 | } | ||
| 1997 | 2016 | ||
| 1998 | if (out_st.st_mode != 0 | 2017 | if (out_st.st_mode != 0 |
| 1999 | && st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino) | 2018 | && 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. */) | |||
| 2075 | } | 2094 | } |
| 2076 | #endif | 2095 | #endif |
| 2077 | 2096 | ||
| 2097 | #ifdef HAVE_POSIX_ACL | ||
| 2098 | if (acl != NULL) | ||
| 2099 | { | ||
| 2100 | bool fail = acl_set_fd (ofd, acl) != 0; | ||
| 2101 | if (fail && errno != ENOTSUP) | ||
| 2102 | report_file_error ("Setting ACL", Fcons (newname, Qnil)); | ||
| 2103 | |||
| 2104 | acl_free (acl); | ||
| 2105 | } | ||
| 2106 | #endif | ||
| 2107 | |||
| 2078 | if (!NILP (keep_time)) | 2108 | if (!NILP (keep_time)) |
| 2079 | { | 2109 | { |
| 2080 | EMACS_TIME atime = get_stat_atime (&st); | 2110 | EMACS_TIME atime = get_stat_atime (&st); |
| @@ -2961,6 +2991,106 @@ compiled with SELinux support. */) | |||
| 2961 | return Qnil; | 2991 | return Qnil; |
| 2962 | } | 2992 | } |
| 2963 | 2993 | ||
| 2994 | DEFUN ("file-acl", Ffile_acl, Sfile_acl, 1, 1, 0, | ||
| 2995 | doc: /* Return ACL entries of file named FILENAME, as a string. | ||
| 2996 | Return nil if file does not exist or is not accessible, or if Emacs | ||
| 2997 | was unable to determine the ACL entries. The latter can happen for | ||
| 2998 | local files if Emacs was not compiled with ACL support, or for remote | ||
| 2999 | files if the file handler returns nil for the file's ACL entries. */) | ||
| 3000 | (Lisp_Object filename) | ||
| 3001 | { | ||
| 3002 | Lisp_Object absname; | ||
| 3003 | Lisp_Object handler; | ||
| 3004 | #ifdef HAVE_POSIX_ACL | ||
| 3005 | acl_t acl; | ||
| 3006 | Lisp_Object acl_string; | ||
| 3007 | char *str; | ||
| 3008 | #endif | ||
| 3009 | |||
| 3010 | absname = expand_and_dir_to_file (filename, | ||
| 3011 | BVAR (current_buffer, directory)); | ||
| 3012 | |||
| 3013 | /* If the file name has special constructs in it, | ||
| 3014 | call the corresponding file handler. */ | ||
| 3015 | handler = Ffind_file_name_handler (absname, Qfile_acl); | ||
| 3016 | if (!NILP (handler)) | ||
| 3017 | return call2 (handler, Qfile_acl, absname); | ||
| 3018 | |||
| 3019 | #ifdef HAVE_POSIX_ACL | ||
| 3020 | absname = ENCODE_FILE (absname); | ||
| 3021 | |||
| 3022 | acl = acl_get_file (SSDATA (absname), ACL_TYPE_ACCESS); | ||
| 3023 | if (acl == NULL) | ||
| 3024 | return Qnil; | ||
| 3025 | |||
| 3026 | str = acl_to_text (acl, NULL); | ||
| 3027 | if (str == NULL) | ||
| 3028 | { | ||
| 3029 | acl_free (acl); | ||
| 3030 | return Qnil; | ||
| 3031 | } | ||
| 3032 | |||
| 3033 | acl_string = build_string (str); | ||
| 3034 | acl_free (str); | ||
| 3035 | acl_free (acl); | ||
| 3036 | |||
| 3037 | return acl_string; | ||
| 3038 | #endif | ||
| 3039 | |||
| 3040 | return Qnil; | ||
| 3041 | } | ||
| 3042 | |||
| 3043 | DEFUN ("set-file-acl", Fset_file_acl, Sset_file_acl, | ||
| 3044 | 2, 2, 0, | ||
| 3045 | doc: /* Set ACL of file named FILENAME to ACL-STRING. | ||
| 3046 | ACL-STRING should contain the textual representation of the ACL | ||
| 3047 | entries in a format suitable for the platform. | ||
| 3048 | |||
| 3049 | Setting ACL for local files requires Emacs to be built with ACL | ||
| 3050 | support. */) | ||
| 3051 | (Lisp_Object filename, Lisp_Object acl_string) | ||
| 3052 | { | ||
| 3053 | Lisp_Object absname; | ||
| 3054 | Lisp_Object handler; | ||
| 3055 | #ifdef HAVE_POSIX_ACL | ||
| 3056 | Lisp_Object encoded_absname; | ||
| 3057 | acl_t acl; | ||
| 3058 | bool fail; | ||
| 3059 | #endif | ||
| 3060 | |||
| 3061 | absname = Fexpand_file_name (filename, BVAR (current_buffer, directory)); | ||
| 3062 | |||
| 3063 | /* If the file name has special constructs in it, | ||
| 3064 | call the corresponding file handler. */ | ||
| 3065 | handler = Ffind_file_name_handler (absname, Qset_file_acl); | ||
| 3066 | if (!NILP (handler)) | ||
| 3067 | return call3 (handler, Qset_file_acl, absname, acl_string); | ||
| 3068 | |||
| 3069 | #ifdef HAVE_POSIX_ACL | ||
| 3070 | if (STRINGP (acl_string)) | ||
| 3071 | { | ||
| 3072 | acl = acl_from_text (SSDATA (acl_string)); | ||
| 3073 | if (acl == NULL) | ||
| 3074 | { | ||
| 3075 | report_file_error ("Converting ACL", Fcons (absname, Qnil)); | ||
| 3076 | return Qnil; | ||
| 3077 | } | ||
| 3078 | |||
| 3079 | encoded_absname = ENCODE_FILE (absname); | ||
| 3080 | |||
| 3081 | fail = (acl_set_file (SSDATA (encoded_absname), ACL_TYPE_ACCESS, | ||
| 3082 | acl) | ||
| 3083 | != 0); | ||
| 3084 | if (fail && errno != ENOTSUP) | ||
| 3085 | report_file_error ("Setting ACL", Fcons (absname, Qnil)); | ||
| 3086 | |||
| 3087 | acl_free (acl); | ||
| 3088 | } | ||
| 3089 | #endif | ||
| 3090 | |||
| 3091 | return Qnil; | ||
| 3092 | } | ||
| 3093 | |||
| 2964 | DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0, | 3094 | DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0, |
| 2965 | doc: /* Return mode bits of file named FILENAME, as an integer. | 3095 | doc: /* Return mode bits of file named FILENAME, as an integer. |
| 2966 | Return nil, if file does not exist or is not accessible. */) | 3096 | Return nil, if file does not exist or is not accessible. */) |
| @@ -5630,6 +5760,8 @@ syms_of_fileio (void) | |||
| 5630 | DEFSYM (Qset_file_times, "set-file-times"); | 5760 | DEFSYM (Qset_file_times, "set-file-times"); |
| 5631 | DEFSYM (Qfile_selinux_context, "file-selinux-context"); | 5761 | DEFSYM (Qfile_selinux_context, "file-selinux-context"); |
| 5632 | DEFSYM (Qset_file_selinux_context, "set-file-selinux-context"); | 5762 | DEFSYM (Qset_file_selinux_context, "set-file-selinux-context"); |
| 5763 | DEFSYM (Qfile_acl, "file-acl"); | ||
| 5764 | DEFSYM (Qset_file_acl, "set-file-acl"); | ||
| 5633 | DEFSYM (Qfile_newer_than_file_p, "file-newer-than-file-p"); | 5765 | DEFSYM (Qfile_newer_than_file_p, "file-newer-than-file-p"); |
| 5634 | DEFSYM (Qinsert_file_contents, "insert-file-contents"); | 5766 | DEFSYM (Qinsert_file_contents, "insert-file-contents"); |
| 5635 | DEFSYM (Qwrite_region, "write-region"); | 5767 | DEFSYM (Qwrite_region, "write-region"); |
| @@ -5849,6 +5981,8 @@ This includes interactive calls to `delete-file' and | |||
| 5849 | defsubr (&Sset_file_modes); | 5981 | defsubr (&Sset_file_modes); |
| 5850 | defsubr (&Sset_file_times); | 5982 | defsubr (&Sset_file_times); |
| 5851 | defsubr (&Sfile_selinux_context); | 5983 | defsubr (&Sfile_selinux_context); |
| 5984 | defsubr (&Sfile_acl); | ||
| 5985 | defsubr (&Sset_file_acl); | ||
| 5852 | defsubr (&Sset_file_selinux_context); | 5986 | defsubr (&Sset_file_selinux_context); |
| 5853 | defsubr (&Sset_default_file_modes); | 5987 | defsubr (&Sset_default_file_modes); |
| 5854 | defsubr (&Sdefault_file_modes); | 5988 | defsubr (&Sdefault_file_modes); |