/* 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.
#ifdef DOS_NT
/* On Windows, drive letters must be alphabetic - on DOS, the Netware
- redirector allows the six letters between 'Z' and 'a' as well. */
+ redirector allows the six letters between 'Z' and 'a' as well. */
#ifdef MSDOS
#define IS_DRIVE(x) ((x) >= 'A' && (x) <= 'z')
#endif
#define IS_DRIVE(x) isalpha ((unsigned char) (x))
#endif
/* Need to lower-case the drive letter, or else expanded
- filenames will sometimes compare inequal, because
+ filenames will sometimes compare unequal, because
`expand-file-name' doesn't always down-case the drive letter. */
#define DRIVE_LETTER(x) (tolower ((unsigned char) (x)))
#endif
#include "commands.h"
-#ifndef FILE_SYSTEM_CASE
-#define FILE_SYSTEM_CASE(filename) (filename)
-#endif
-
/* 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;
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
beg = (char *) alloca (SBYTES (filename) + 1);
memcpy (beg, SSDATA (filename), SBYTES (filename) + 1);
while (p != beg && !IS_DIRECTORY_SEP (p[-1])
#ifdef DOS_NT
- /* only recognise drive specifier at the beginning */
+ /* only recognize drive specifier at the beginning */
&& !(p[-1] == ':'
/* handle the "/:d:foo" and "/:foo" cases correctly */
&& ((p == beg + 2 && !IS_DIRECTORY_SEP (*beg))
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);
while (p != beg && !IS_DIRECTORY_SEP (p[-1])
#ifdef DOS_NT
- /* only recognise drive specifier at beginning */
+ /* only recognize drive specifier at beginning */
&& !(p[-1] == ':'
/* handle the "/:d:foo" case correctly */
&& (p == beg + 2 || (p == beg + 4 && IS_DIRECTORY_SEP (*beg))))
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);
}
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));
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);
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;
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))
{
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'");
+ }
}
{
UNGCPRO;
}
}
- name = FILE_SYSTEM_CASE (name);
multibyte = STRING_MULTIBYTE (name);
if (multibyte != STRING_MULTIBYTE (default_directory))
{
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;
}
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
if (p)
/* Start over with the new string, so we check the file-name-handler
again. Important with filenames like "/home/foo//:/hello///there"
- which whould substitute to "/:/hello///there" rather than "/there". */
+ which would substitute to "/:/hello///there" rather than "/there". */
return Fsubstitute_in_file_name
(make_specified_string (p, -1, endp - p, multibyte));
#if HAVE_LIBSELINUX
if (conlength > 0)
{
- /* Set the modified context back to the file. */
+ /* Set the modified context back to the file. */
fail = fsetfilecon (ofd, con);
- if (fail)
+ /* See http://debbugs.gnu.org/11245 for ENOTSUP. */
+ if (fail && errno != ENOTSUP)
report_file_error ("Doing fsetfilecon", Fcons (newname, Qnil));
freecon (con);
#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));
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 */
}
\f
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;
\f
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;
error ("Doing context_range_set");
}
- /* Set the modified context back to the file. */
+ /* Set the modified context back to the file. */
fail = lsetfilecon (SSDATA (encoded_absname),
context_str (parsed_con));
- if (fail)
+ /* See http://debbugs.gnu.org/11245 for ENOTSUP. */
+ if (fail && errno != ENOTSUP)
report_file_error ("Doing lsetfilecon", Fcons (absname, Qnil));
context_free (parsed_con);
int this_count = SPECPDL_INDEX ();
int multibyte = ! NILP (BVAR (current_buffer, enable_multibyte_characters));
Lisp_Object conversion_buffer;
+ struct gcpro gcpro1;
conversion_buffer = code_conversion_save (1, multibyte);
{
/* We read one bunch by one (READ_BUF_SIZE bytes) to allow
quitting while reading a huge while. */
- /* try is reserved in some compilers (Microsoft C) */
+ /* `try'' is reserved in some compilers (Microsoft C). */
EMACS_INT trytry = min (total - how_much,
READ_BUF_SIZE - unprocessed);
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:
/* 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
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)
{
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;
}
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;
}
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",