/* 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
#define FILE_SYSTEM_CASE(filename) (filename)
#endif
-/* Nonzero during writing of auto-save files */
+/* 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 */
+ a new file with the same mode as the original. */
static int auto_save_mode_bits;
-/* Set by auto_save_1 if an error occurred during the last auto-save. */
+/* Set by auto_save_1 if an error occurred during the last auto-save. */
static int auto_save_error_occurred;
/* The symbol bound to coding-system-for-read when
which gives a list of operations it handles.. */
static Lisp_Object Qoperations;
-/* Lisp functions for translating file formats */
+/* Lisp functions for translating file formats. */
static Lisp_Object Qformat_decode, Qformat_annotate_function;
/* Lisp function for setting buffer-file-coding-system and the
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
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'");
+ }
}
{
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);
Lisp_Object p;
EMACS_INT total = 0;
int not_regular = 0;
+ int save_errno = 0;
char read_buf[READ_BUF_SIZE];
struct coding_system coding;
char buffer[1 << 14];
#endif /* WINDOWSNT */
{
badopen:
+ save_errno = errno;
if (NILP (visit))
report_file_error ("Opening input file", Fcons (orig_filename, Qnil));
st.st_mtime = -1;
+ st.st_size = -1;
how_much = 0;
if (!NILP (Vcoding_system_for_read))
Fset (Qbuffer_file_coding_system, Vcoding_system_for_read);
immediate_quit = 0;
/* If the file matches the buffer completely,
there's no need to replace anything. */
- if (same_at_start - BEGV_BYTE == end_offset)
+ if (same_at_start - BEGV_BYTE == end_offset - beg_offset)
{
emacs_close (fd);
specpdl_ptr--;
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)
{
/* If visiting nonexistent file, return nil. */
+ errno = save_errno;
report_file_error ("Opening input file", Fcons (orig_filename, Qnil));
}
if (ret < 0)
{
#ifdef CLASH_DETECTION
+ save_errno = errno;
if (!auto_saving) unlock_file (lockname);
+ errno = save_errno;
#endif /* CLASH_DETECTION */
UNGCPRO;
report_file_error ("Lseek error", Fcons (filename, Qnil));
DEFUN ("visited-file-modtime", Fvisited_file_modtime,
Svisited_file_modtime, 0, 0, 0,
doc: /* Return the current buffer's recorded visited file modification time.
-The value is a list of the form (HIGH LOW), like the time values
-that `file-attributes' returns. If the current buffer has no recorded
-file modification time, this function returns 0.
+The value is a list of the form (HIGH LOW), like the time values that
+`file-attributes' returns. If the current buffer has no recorded file
+modification time, this function returns 0. If the visited file
+doesn't exist, HIGH will be -1.
See Info node `(elisp)Modification Time' for more details. */)
(void)
{
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;
}
EMACS_GET_TIME (before_time);
/* If we had a failure, don't try again for 20 minutes. */
- if (b->auto_save_failure_time >= 0
+ if (b->auto_save_failure_time > 0
&& EMACS_SECS (before_time) - b->auto_save_failure_time < 1200)
continue;
they're not autosaved. */
BUF_AUTOSAVE_MODIFF (current_buffer) = MODIFF;
XSETFASTINT (BVAR (current_buffer, save_length), Z - BEG);
- current_buffer->auto_save_failure_time = -1;
+ current_buffer->auto_save_failure_time = 0;
return Qnil;
}
doc: /* Clear any record of a recent auto-save failure in the current buffer. */)
(void)
{
- current_buffer->auto_save_failure_time = -1;
+ current_buffer->auto_save_failure_time = 0;
return Qnil;
}
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;
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",
#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;