X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/5b76caa476d552e204adc3c1bf4af8e401ec5d42..fb7ada5f94a71d73bf6cfad5cc87fe7fb26125a5:/src/fileio.c diff --git a/src/fileio.c b/src/fileio.c index 009f35d2a7..3a74672b9a 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -1,6 +1,6 @@ /* File IO for GNU Emacs. -Copyright (C) 1985-1988, 1993-2011 Free Software Foundation, Inc. +Copyright (C) 1985-1988, 1993-2012 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -90,6 +90,9 @@ along with GNU Emacs. If not, see . */ /* Nonzero during writing of auto-save files */ static int auto_saving; +/* Nonzero umask during creation of auto-save directories */ +static int auto_saving_dir_umask; + /* Set by auto_save_1 to mode of original file so Fwrite_region will create a new file with the same mode as the original */ static int auto_save_mode_bits; @@ -325,7 +328,11 @@ Given a Unix syntax file name, returns a string ending in slash. */) call the corresponding file handler. */ handler = Ffind_file_name_handler (filename, Qfile_name_directory); if (!NILP (handler)) - return call2 (handler, Qfile_name_directory, filename); + { + Lisp_Object handled_name = call2 (handler, Qfile_name_directory, + filename); + return STRINGP (handled_name) ? handled_name : Qnil; + } filename = FILE_SYSTEM_CASE (filename); #ifdef DOS_NT @@ -394,7 +401,13 @@ or the entire name if it contains no slash. */) call the corresponding file handler. */ handler = Ffind_file_name_handler (filename, Qfile_name_nondirectory); if (!NILP (handler)) - return call2 (handler, Qfile_name_nondirectory, filename); + { + Lisp_Object handled_name = call2 (handler, Qfile_name_nondirectory, + filename); + if (STRINGP (handled_name)) + return handled_name; + error ("Invalid handler in `file-name-handler-alist'"); + } beg = SSDATA (filename); end = p = beg + SBYTES (filename); @@ -431,7 +444,11 @@ get a current directory to run processes in. */) call the corresponding file handler. */ handler = Ffind_file_name_handler (filename, Qunhandled_file_name_directory); if (!NILP (handler)) - return call2 (handler, Qunhandled_file_name_directory, filename); + { + Lisp_Object handled_name = call2 (handler, Qunhandled_file_name_directory, + filename); + return STRINGP (handled_name) ? handled_name : Qnil; + } return Ffile_name_directory (filename); } @@ -485,7 +502,13 @@ For a Unix-syntax file name, just appends a slash. */) call the corresponding file handler. */ handler = Ffind_file_name_handler (file, Qfile_name_as_directory); if (!NILP (handler)) - return call2 (handler, Qfile_name_as_directory, file); + { + Lisp_Object handled_name = call2 (handler, Qfile_name_as_directory, + file); + if (STRINGP (handled_name)) + return handled_name; + error ("Invalid handler in `file-name-handler-alist'"); + } buf = (char *) alloca (SBYTES (file) + 10); file_name_as_directory (buf, SSDATA (file)); @@ -544,7 +567,13 @@ In Unix-syntax, this function just removes the final slash. */) call the corresponding file handler. */ handler = Ffind_file_name_handler (directory, Qdirectory_file_name); if (!NILP (handler)) - return call2 (handler, Qdirectory_file_name, directory); + { + Lisp_Object handled_name = call2 (handler, Qdirectory_file_name, + directory); + if (STRINGP (handled_name)) + return handled_name; + error ("Invalid handler in `file-name-handler-alist'"); + } buf = (char *) alloca (SBYTES (directory) + 20); directory_file_name (SSDATA (directory), buf); @@ -744,7 +773,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) int is_escaped = 0; #endif /* DOS_NT */ ptrdiff_t length; - Lisp_Object handler, result; + Lisp_Object handler, result, handled_name; int multibyte; Lisp_Object hdir; @@ -754,7 +783,14 @@ filesystem tree, not (expand-file-name ".." dirname). */) call the corresponding file handler. */ handler = Ffind_file_name_handler (name, Qexpand_file_name); if (!NILP (handler)) - return call3 (handler, Qexpand_file_name, name, default_directory); + { + handled_name = call3 (handler, Qexpand_file_name, + name, default_directory); + if (STRINGP (handled_name)) + return handled_name; + error ("Invalid handler in `file-name-handler-alist'"); + } + /* Use the buffer's default-directory if DEFAULT_DIRECTORY is omitted. */ if (NILP (default_directory)) @@ -780,7 +816,13 @@ filesystem tree, not (expand-file-name ".." dirname). */) { handler = Ffind_file_name_handler (default_directory, Qexpand_file_name); if (!NILP (handler)) - return call3 (handler, Qexpand_file_name, name, default_directory); + { + handled_name = call3 (handler, Qexpand_file_name, + name, default_directory); + if (STRINGP (handled_name)) + return handled_name; + error ("Invalid handler in `file-name-handler-alist'"); + } } { @@ -1281,7 +1323,13 @@ filesystem tree, not (expand-file-name ".." dirname). */) to be expanded again. */ handler = Ffind_file_name_handler (result, Qexpand_file_name); if (!NILP (handler)) - return call3 (handler, Qexpand_file_name, result, default_directory); + { + handled_name = call3 (handler, Qexpand_file_name, + result, default_directory); + if (STRINGP (handled_name)) + return handled_name; + error ("Invalid handler in `file-name-handler-alist'"); + } return result; } @@ -1534,7 +1582,13 @@ those `/' is discarded. */) call the corresponding file handler. */ handler = Ffind_file_name_handler (filename, Qsubstitute_in_file_name); if (!NILP (handler)) - return call2 (handler, Qsubstitute_in_file_name, filename); + { + Lisp_Object handled_name = call2 (handler, Qsubstitute_in_file_name, + filename); + if (STRINGP (handled_name)) + return handled_name; + error ("Invalid handler in `file-name-handler-alist'"); + } /* Always work on a copy of the string, in case GC happens during decode of environment variables, causing the original Lisp_String @@ -2062,7 +2116,7 @@ DEFUN ("make-directory-internal", Fmake_directory_internal, #ifdef WINDOWSNT if (mkdir (dir) != 0) #else - if (mkdir (dir, 0777) != 0) + if (mkdir (dir, 0777 & ~auto_saving_dir_umask) != 0) #endif report_file_error ("Creating directory", list1 (directory)); @@ -2416,15 +2470,27 @@ check_writable (const char *filename) return (st.st_mode & S_IWRITE || S_ISDIR (st.st_mode)); #else /* not MSDOS */ #ifdef HAVE_EUIDACCESS - return (euidaccess (filename, 2) >= 0); -#else + int res = (euidaccess (filename, 2) >= 0); +#ifdef CYGWIN + /* euidaccess may have returned failure because Cygwin couldn't + determine the file's UID or GID; if so, we return success. */ + if (!res) + { + struct stat st; + if (stat (filename, &st) < 0) + return 0; + res = (st.st_uid == -1 || st.st_gid == -1); + } +#endif /* CYGWIN */ + return res; +#else /* not HAVE_EUIDACCESS */ /* Access isn't quite right because it uses the real uid and we really want to test with the effective uid. But Unix doesn't give us a right way to do it. Opening with O_WRONLY could work for an ordinary file, but would lose for directories. */ return (access (filename, 2) >= 0); -#endif +#endif /* not HAVE_EUIDACCESS */ #endif /* not MSDOS */ } @@ -2732,9 +2798,13 @@ See `file-symlink-p' to distinguish symlinks. */) 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 */) + doc: /* Return SELinux context of file named FILENAME. +The return value is a list (USER ROLE TYPE RANGE), where the list +elements are strings naming the user, role, type, and range of the +file's SELinux security context. + +Return (nil nil nil nil) if the file is nonexistent or inaccessible, +or if SELinux is disabled, or if Emacs lacks SELinux support. */) (Lisp_Object filename) { Lisp_Object absname; @@ -2787,9 +2857,12 @@ if file does not exist, is not accessible, or SELinux is disabled */) 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. */) + doc: /* Set SELinux context of file named FILENAME to CONTEXT. +CONTEXT should be a list (USER ROLE TYPE RANGE), where the list +elements are strings naming the components of a SELinux context. + +This function does nothing if SELinux is disabled, or if Emacs was not +compiled with SELinux support. */) (Lisp_Object filename, Lisp_Object context) { Lisp_Object absname; @@ -3686,7 +3759,7 @@ variable `last-coding-system-used' to the coding system actually used. */) int this_count = SPECPDL_INDEX (); int multibyte = ! NILP (BVAR (current_buffer, enable_multibyte_characters)); Lisp_Object conversion_buffer; - struct gcpro inner_gcpro1; + struct gcpro gcpro1; conversion_buffer = code_conversion_save (1, multibyte); @@ -3702,7 +3775,7 @@ variable `last-coding-system-used' to the coding system actually used. */) inserted = 0; /* Bytes put into CONVERSION_BUFFER so far. */ unprocessed = 0; /* Bytes not processed in previous loop. */ - GCPRO1_VAR (conversion_buffer, inner_gcpro); + GCPRO1 (conversion_buffer); while (how_much < total) { /* We read one bunch by one (READ_BUF_SIZE bytes) to allow @@ -4100,6 +4173,16 @@ variable `last-coding-system-used' to the coding system actually used. */) adjust_after_insert (PT, PT_BYTE, PT + inserted, PT_BYTE + inserted, inserted); + /* Call after-change hooks for the inserted text, aside from the case + of normal visiting (not with REPLACE), which is done in a new buffer + "before" the buffer is changed. */ + if (inserted > 0 && total > 0 + && (NILP (visit) || !NILP (replace))) + { + signal_after_change (PT, 0, inserted); + update_compositions (PT, PT, CHECK_BORDER); + } + /* Now INSERTED is measured in characters. */ handled: @@ -4176,7 +4259,7 @@ variable `last-coding-system-used' to the coding system actually used. */) /* If REPLACE is non-nil and we succeeded in not replacing the beginning or end of the buffer text with the file's contents, call format-decode with `point' positioned at the beginning - of the buffer and `inserted' equalling the number of + of the buffer and `inserted' equaling the number of characters in the buffer. Otherwise, format-decode might fail to correctly analyze the beginning or end of the buffer. Hence we temporarily save `point' and `inserted' here and @@ -4270,16 +4353,6 @@ variable `last-coding-system-used' to the coding system actually used. */) unbind_to (count1, Qnil); } - /* Call after-change hooks for the inserted text, aside from the case - of normal visiting (not with REPLACE), which is done in a new buffer - "before" the buffer is changed. */ - if (inserted > 0 && total > 0 - && (NILP (visit) || !NILP (replace))) - { - signal_after_change (PT, 0, inserted); - update_compositions (PT, PT, CHECK_BORDER); - } - if (!NILP (visit) && current_buffer->modtime == -1) { @@ -5193,16 +5266,18 @@ do_auto_save_unwind_1 (Lisp_Object value) /* used as unwind-protect function */ static Lisp_Object do_auto_save_make_dir (Lisp_Object dir) { - Lisp_Object mode; + Lisp_Object result; - call2 (Qmake_directory, dir, Qt); - XSETFASTINT (mode, 0700); - return Fset_file_modes (dir, mode); + auto_saving_dir_umask = 077; + result = call2 (Qmake_directory, dir, Qt); + auto_saving_dir_umask = 0; + return result; } static Lisp_Object do_auto_save_eh (Lisp_Object ignore) { + auto_saving_dir_umask = 0; return Qnil; } @@ -5270,7 +5345,7 @@ A non-nil CURRENT-ONLY argument means save only current buffer. */) dir = Ffile_name_directory (listfile); if (NILP (Ffile_directory_p (dir))) internal_condition_case_1 (do_auto_save_make_dir, - dir, Fcons (Fcons (Qfile_error, Qnil), Qnil), + dir, Qt, do_auto_save_eh); UNGCPRO; } @@ -5536,7 +5611,7 @@ syms_of_fileio (void) DEFSYM (Qexcl, "excl"); DEFVAR_LISP ("file-name-coding-system", Vfile_name_coding_system, - doc: /* *Coding system for encoding file names. + doc: /* Coding system for encoding file names. If it is nil, `default-file-name-coding-system' (which see) is used. */); Vfile_name_coding_system = Qnil; @@ -5572,18 +5647,25 @@ of file names regardless of the current language environment. */); make_pure_c_string ("Cannot set file date")); DEFVAR_LISP ("file-name-handler-alist", Vfile_name_handler_alist, - doc: /* *Alist of elements (REGEXP . HANDLER) for file names handled specially. -If a file name matches REGEXP, then all I/O on that file is done by calling -HANDLER. - -The first argument given to HANDLER is the name of the I/O primitive -to be handled; the remaining arguments are the arguments that were -passed to that primitive. For example, if you do - (file-exists-p FILENAME) -and FILENAME is handled by HANDLER, then HANDLER is called like this: - (funcall HANDLER 'file-exists-p FILENAME) -The function `find-file-name-handler' checks this list for a handler -for its argument. */); + doc: /* Alist of elements (REGEXP . HANDLER) for file names handled specially. +If a file name matches REGEXP, all I/O on that file is done by calling +HANDLER. If a file name matches more than one handler, the handler +whose match starts last in the file name gets precedence. The +function `find-file-name-handler' checks this list for a handler for +its argument. + +HANDLER should be a function. The first argument given to it is the +name of the I/O primitive to be handled; the remaining arguments are +the arguments that were passed to that primitive. For example, if you +do (file-exists-p FILENAME) and FILENAME is handled by HANDLER, then +HANDLER is called like this: + + (funcall HANDLER 'file-exists-p FILENAME) + +Note that HANDLER must be able to handle all I/O primitives; if it has +nothing special to do for a primitive, it should reinvoke the +primitive to handle the operation \"the usual way\". +See Info node `(elisp)Magic File Names' for more details. */); Vfile_name_handler_alist = Qnil; DEFVAR_LISP ("set-auto-coding-function", @@ -5683,7 +5765,7 @@ file is usually more useful if it contains the deleted text. */); #ifdef HAVE_FSYNC DEFVAR_BOOL ("write-region-inhibit-fsync", write_region_inhibit_fsync, - doc: /* *Non-nil means don't call fsync in `write-region'. + doc: /* Non-nil means don't call fsync in `write-region'. This variable affects calls to `write-region' as well as save commands. A non-nil value may result in data loss! */); write_region_inhibit_fsync = 0;