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 /src | |
| 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'.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 11 | ||||
| -rw-r--r-- | src/Makefile.in | 4 | ||||
| -rw-r--r-- | src/fileio.c | 154 |
3 files changed, 158 insertions, 11 deletions
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); |