Mercurial > emacs
diff src/fileio.c @ 109853:fe07c47cf7a7
merge and fixes
author | Joakim <joakim@localhost.localdomain> |
---|---|
date | Thu, 13 May 2010 15:13:52 +0200 |
parents | 973b5bc5fcfe |
children | 0f1244b4539c |
line wrap: on
line diff
--- a/src/fileio.c Wed May 12 14:32:06 2010 +0200 +++ b/src/fileio.c Thu May 13 15:13:52 2010 +0200 @@ -53,6 +53,11 @@ #include <ctype.h> #include <errno.h> +#ifdef HAVE_LIBSELINUX +#include <selinux/selinux.h> +#include <selinux/context.h> +#endif + #include "lisp.h" #include "intervals.h" #include "buffer.h" @@ -294,7 +299,7 @@ /* Restore point, having saved it as a marker. */ -static Lisp_Object +Lisp_Object restore_point_unwind (location) Lisp_Object location; { @@ -331,6 +336,8 @@ Lisp_Object Qfile_modes; Lisp_Object Qset_file_modes; Lisp_Object Qset_file_times; +Lisp_Object Qfile_selinux_context; +Lisp_Object Qset_file_selinux_context; Lisp_Object Qfile_newer_than_file_p; Lisp_Object Qinsert_file_contents; Lisp_Object Qwrite_region; @@ -1894,7 +1901,7 @@ return; } -DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 5, +DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 6, "fCopy file: \nGCopy %s to file: \np\nP", doc: /* Copy FILE to NEWNAME. Both args must be strings. If NEWNAME names a directory, copy FILE there. @@ -1916,10 +1923,13 @@ A prefix arg makes KEEP-TIME non-nil. If PRESERVE-UID-GID is non-nil, we try to transfer the -uid and gid of FILE to NEWNAME. */) - (file, newname, ok_if_already_exists, keep_time, preserve_uid_gid) +uid and gid of FILE to NEWNAME. + +If PRESERVE-SELINUX-CONTEXT is non-nil and SELinux is enabled +on the system, we copy the SELinux context of FILE to NEWNAME. */) + (file, newname, ok_if_already_exists, keep_time, preserve_uid_gid, preserve_selinux_context) Lisp_Object file, newname, ok_if_already_exists, keep_time; - Lisp_Object preserve_uid_gid; + Lisp_Object preserve_uid_gid, preserve_selinux_context; { int ifd, ofd, n; char buf[16 * 1024]; @@ -1929,6 +1939,10 @@ int count = SPECPDL_INDEX (); int input_file_statable_p; Lisp_Object encoded_file, encoded_newname; +#if HAVE_LIBSELINUX + security_context_t con; + int fail, conlength = 0; +#endif encoded_file = encoded_newname = Qnil; GCPRO4 (file, newname, encoded_file, encoded_newname); @@ -1949,8 +1963,9 @@ if (NILP (handler)) handler = Ffind_file_name_handler (newname, Qcopy_file); if (!NILP (handler)) - RETURN_UNGCPRO (call6 (handler, Qcopy_file, file, newname, - ok_if_already_exists, keep_time, preserve_uid_gid)); + RETURN_UNGCPRO (call7 (handler, Qcopy_file, file, newname, + ok_if_already_exists, keep_time, preserve_uid_gid, + preserve_selinux_context)); encoded_file = ENCODE_FILE (file); encoded_newname = ENCODE_FILE (newname); @@ -2004,6 +2019,15 @@ copyable by us. */ input_file_statable_p = (fstat (ifd, &st) >= 0); +#if HAVE_LIBSELINUX + if (!NILP (preserve_selinux_context) && is_selinux_enabled ()) + { + conlength = fgetfilecon (ifd, &con); + if (conlength == -1) + report_file_error ("Doing fgetfilecon", Fcons (file, Qnil)); + } +#endif + if (out_st.st_mode != 0 && st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino) { @@ -2061,6 +2085,18 @@ } #endif /* not MSDOS */ +#if HAVE_LIBSELINUX + if (conlength > 0) + { + /* Set the modified context back to the file. */ + fail = fsetfilecon (ofd, con); + if (fail) + report_file_error ("Doing fsetfilecon", Fcons (newname, Qnil)); + + freecon (con); + } +#endif + /* Closing the output clobbers the file times on some systems. */ if (emacs_close (ofd) < 0) report_file_error ("I/O error", Fcons (newname, Qnil)); @@ -2158,11 +2194,17 @@ return Qnil; } -DEFUN ("delete-file", Fdelete_file, Sdelete_file, 1, 1, "fDelete file: ", +DEFUN ("delete-file", Fdelete_file, Sdelete_file, 1, 2, "fDelete file: \nP", doc: /* Delete file named FILENAME. If it is a symlink, remove the symlink. -If file has multiple names, it continues to exist with the other names. */) - (filename) +If file has multiple names, it continues to exist with the other names. + +If optional arg FORCE is non-nil, really delete the file regardless of +`delete-by-moving-to-trash'. Otherwise, \"deleting\" actually moves +it to the system's trash can if `delete-by-moving-to-trash' is non-nil. +Interactively, FORCE is non-nil if called with a prefix arg. */) + (filename, force) Lisp_Object filename; + Lisp_Object force; { Lisp_Object handler; Lisp_Object encoded_file; @@ -2181,7 +2223,7 @@ if (!NILP (handler)) return call2 (handler, Qdelete_file, filename); - if (delete_by_moving_to_trash) + if (delete_by_moving_to_trash && NILP (force)) return call1 (Qmove_file_to_trash, filename); encoded_file = ENCODE_FILE (filename); @@ -2198,14 +2240,15 @@ return Qt; } -/* Delete file FILENAME, returning 1 if successful and 0 if failed. */ +/* Delete file FILENAME, returning 1 if successful and 0 if failed. + FORCE means to ignore `delete-by-moving-to-trash'. */ int -internal_delete_file (filename) - Lisp_Object filename; +internal_delete_file (Lisp_Object filename, Lisp_Object force) { Lisp_Object tem; - tem = internal_condition_case_1 (Fdelete_file, filename, + + tem = internal_condition_case_2 (Fdelete_file, filename, force, Qt, internal_delete_file_1); return NILP (tem); } @@ -2287,7 +2330,7 @@ have copy-file prompt again. */ Fcopy_file (file, newname, NILP (ok_if_already_exists) ? Qnil : Qt, - Qt, Qt); + Qt, Qt, Qt); count = SPECPDL_INDEX (); specbind (Qdelete_by_moving_to_trash, Qnil); @@ -2299,7 +2342,7 @@ ) call2 (Qdelete_directory, file, Qt); else - Fdelete_file (file); + Fdelete_file (file, Qt); unbind_to (count, Qnil); } else @@ -2844,6 +2887,140 @@ #endif } +DEFUN ("file-selinux-context", Ffile_selinux_context, + Sfile_selinux_context, 1, 1, 0, + doc: /* Return SELinux context of file named FILENAME, +as a list ("user", "role", "type", "range"). Return (nil, nil, nil, nil) +if file does not exist, is not accessible, or SELinux is disabled */) + (filename) + Lisp_Object filename; +{ + Lisp_Object absname; + Lisp_Object values[4]; + Lisp_Object handler; +#if HAVE_LIBSELINUX + security_context_t con; + int conlength; + context_t context; +#endif + + absname = expand_and_dir_to_file (filename, current_buffer->directory); + + /* If the file name has special constructs in it, + call the corresponding file handler. */ + handler = Ffind_file_name_handler (absname, Qfile_selinux_context); + if (!NILP (handler)) + return call2 (handler, Qfile_selinux_context, absname); + + absname = ENCODE_FILE (absname); + + values[0] = Qnil; + values[1] = Qnil; + values[2] = Qnil; + values[3] = Qnil; +#if HAVE_LIBSELINUX + if (is_selinux_enabled ()) + { + conlength = lgetfilecon (SDATA (absname), &con); + if (conlength > 0) + { + context = context_new (con); + if (context_user_get (context)) + values[0] = build_string (context_user_get (context)); + if (context_role_get (context)) + values[1] = build_string (context_role_get (context)); + if (context_type_get (context)) + values[2] = build_string (context_type_get (context)); + if (context_range_get (context)) + values[3] = build_string (context_range_get (context)); + context_free (context); + } + if (con) + freecon (con); + } +#endif + + return Flist (sizeof(values) / sizeof(values[0]), values); +} + +DEFUN ("set-file-selinux-context", Fset_file_selinux_context, + Sset_file_selinux_context, 2, 2, 0, + doc: /* Set SELinux context of file named FILENAME to CONTEXT +as a list ("user", "role", "type", "range"). Has no effect if SELinux +is disabled. */) + (filename, context) + Lisp_Object filename, context; +{ + Lisp_Object absname, encoded_absname; + Lisp_Object handler; + Lisp_Object user = CAR_SAFE (context); + Lisp_Object role = CAR_SAFE (CDR_SAFE (context)); + Lisp_Object type = CAR_SAFE (CDR_SAFE (CDR_SAFE (context))); + Lisp_Object range = CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (context)))); +#if HAVE_LIBSELINUX + security_context_t con; + int fail, conlength; + context_t parsed_con; +#endif + + absname = Fexpand_file_name (filename, 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_selinux_context); + if (!NILP (handler)) + return call3 (handler, Qset_file_selinux_context, absname, context); + + encoded_absname = ENCODE_FILE (absname); + +#if HAVE_LIBSELINUX + if (is_selinux_enabled ()) + { + /* Get current file context. */ + conlength = lgetfilecon (SDATA (encoded_absname), &con); + if (conlength > 0) + { + parsed_con = context_new (con); + /* Change the parts defined in the parameter.*/ + if (STRINGP (user)) + { + if (context_user_set (parsed_con, SDATA (user))) + error ("Doing context_user_set"); + } + if (STRINGP (role)) + { + if (context_role_set (parsed_con, SDATA (role))) + error ("Doing context_role_set"); + } + if (STRINGP (type)) + { + if (context_type_set (parsed_con, SDATA (type))) + error ("Doing context_type_set"); + } + if (STRINGP (range)) + { + if (context_range_set (parsed_con, SDATA (range))) + error ("Doing context_range_set"); + } + + /* Set the modified context back to the file. */ + fail = lsetfilecon (SDATA (encoded_absname), context_str (parsed_con)); + if (fail) + report_file_error ("Doing lsetfilecon", Fcons (absname, Qnil)); + + context_free (parsed_con); + } + else + report_file_error("Doing lgetfilecon", Fcons (absname, Qnil)); + + if (con) + freecon (con); + } +#endif + + return Qnil; +} + DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0, doc: /* Return mode bits of file named FILENAME, as an integer. Return nil, if file does not exist or is not accessible. */) @@ -5505,6 +5682,8 @@ Qfile_modes = intern_c_string ("file-modes"); Qset_file_modes = intern_c_string ("set-file-modes"); Qset_file_times = intern_c_string ("set-file-times"); + Qfile_selinux_context = intern_c_string("file-selinux-context"); + Qset_file_selinux_context = intern_c_string("set-file-selinux-context"); Qfile_newer_than_file_p = intern_c_string ("file-newer-than-file-p"); Qinsert_file_contents = intern_c_string ("insert-file-contents"); Qwrite_region = intern_c_string ("write-region"); @@ -5540,6 +5719,8 @@ staticpro (&Qfile_modes); staticpro (&Qset_file_modes); staticpro (&Qset_file_times); + staticpro (&Qfile_selinux_context); + staticpro (&Qset_file_selinux_context); staticpro (&Qfile_newer_than_file_p); staticpro (&Qinsert_file_contents); staticpro (&Qwrite_region); @@ -5773,6 +5954,8 @@ defsubr (&Sfile_modes); defsubr (&Sset_file_modes); defsubr (&Sset_file_times); + defsubr (&Sfile_selinux_context); + defsubr (&Sset_file_selinux_context); defsubr (&Sset_default_file_modes); defsubr (&Sdefault_file_modes); defsubr (&Sfile_newer_than_file_p);