Inline functions to examine and change buffer intervals.
[bpt/emacs.git] / src / fileio.c
index 110977b..9fe7437 100644 (file)
@@ -1,6 +1,6 @@
 /* File IO for GNU Emacs.
 
-Copyright (C) 1985-1988, 1993-201 Free Software Foundation, Inc.
+Copyright (C) 1985-1988, 1993-2012 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -40,8 +40,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "lisp.h"
 #include "intervals.h"
-#include "buffer.h"
 #include "character.h"
+#include "buffer.h"
 #include "coding.h"
 #include "window.h"
 #include "blockinput.h"
@@ -62,7 +62,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #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
@@ -70,12 +70,13 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #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 "systime.h"
+#include <stat-time.h>
 
 #ifdef HPUX
 #include <netio.h>
@@ -83,18 +84,17 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "commands.h"
 
-#ifndef FILE_SYSTEM_CASE
-#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
@@ -108,7 +108,7 @@ static Lisp_Object Qauto_save_coding;
    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
@@ -144,7 +144,6 @@ Lisp_Object Qfile_name_history;
 
 static Lisp_Object Qcar_less_than_car;
 
-static Lisp_Object Fmake_symbolic_link (Lisp_Object, Lisp_Object, Lisp_Object);
 static int a_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t,
                     Lisp_Object *, struct coding_system *);
 static int e_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t,
@@ -160,8 +159,7 @@ report_file_error (const char *string, Lisp_Object data)
 
   synchronize_system_messages_locale ();
   str = strerror (errorno);
-  errstring = code_convert_string_norecord (make_unibyte_string (str,
-                                                                strlen (str)),
+  errstring = code_convert_string_norecord (build_unibyte_string (str),
                                            Vlocale_coding_system, 0);
 
   while (1)
@@ -325,11 +323,14 @@ 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
-  beg = (char *) alloca (SBYTES (filename) + 1);
+  beg = alloca (SBYTES (filename) + 1);
   memcpy (beg, SSDATA (filename), SBYTES (filename) + 1);
 #else
   beg = SSDATA (filename);
@@ -338,7 +339,7 @@ Given a Unix syntax file name, returns a string ending in slash.  */)
 
   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))
@@ -358,7 +359,7 @@ Given a Unix syntax file name, returns a string ending in slash.  */)
 
       if (p == beg + 4 && IS_DIRECTORY_SEP (*beg) && beg[1] == ':')
        {
-         strncpy (res, beg, 2);
+         memcpy (res, beg, 2);
          beg += 2;
          r += 2;
        }
@@ -394,14 +395,20 @@ 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);
 
   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))))
@@ -431,37 +438,42 @@ 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);
 }
 
-\f
-static char *
-file_name_as_directory (char *out, const char *in)
-{
-  ptrdiff_t len = strlen (in);
+/* Convert from file name SRC of length SRCLEN to directory name
+   in DST.  On UNIX, just make sure there is a terminating /.
+   Return the length of DST.  */
 
-  if (len == 0)
+static ptrdiff_t
+file_name_as_directory (char *dst, const char *src, ptrdiff_t srclen)
+{
+  if (srclen == 0)
     {
-      out[0] = '.';
-      out[1] = '/';
-      out[2] = 0;
-      return out;
+      dst[0] = '.';
+      dst[1] = '/';
+      dst[2] = '\0';
+      return 2;
     }
 
-  strcpy (out, in);
+  strcpy (dst, src);
 
-  /* For Unix syntax, Append a slash if necessary */
-  if (!IS_DIRECTORY_SEP (out[len - 1]))
+  if (!IS_DIRECTORY_SEP (dst[srclen - 1]))
     {
-      out[len] = DIRECTORY_SEP;
-      out[len + 1] = '\0';
+      dst[srclen] = DIRECTORY_SEP;
+      dst[srclen + 1] = '\0';
+      srclen++;
     }
 #ifdef DOS_NT
-  dostounix_filename (out);
+  dostounix_filename (dst);
 #endif
-  return out;
+  return srclen;
 }
 
 DEFUN ("file-name-as-directory", Ffile_name_as_directory,
@@ -475,6 +487,7 @@ For a Unix-syntax file name, just appends a slash.  */)
   (Lisp_Object file)
 {
   char *buf;
+  ptrdiff_t length;
   Lisp_Object handler;
 
   CHECK_STRING (file);
@@ -485,42 +498,43 @@ 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));
-  return make_specified_string (buf, -1, strlen (buf),
-                               STRING_MULTIBYTE (file));
+  buf = alloca (SBYTES (file) + 10);
+  length = file_name_as_directory (buf, SSDATA (file), SBYTES (file));
+  return make_specified_string (buf, -1, length, STRING_MULTIBYTE (file));
 }
 \f
-/*
- * Convert from directory name to filename.
- * On UNIX, it's simple: just make sure there isn't a terminating /
-
- * Value is nonzero if the string output is different from the input.
- */
+/* Convert from directory name SRC of length SRCLEN to
+   file name in DST.  On UNIX, just make sure there isn't
+   a terminating /.  Return the length of DST.  */
 
-static int
-directory_file_name (char *src, char *dst)
+static ptrdiff_t
+directory_file_name (char *dst, char *src, ptrdiff_t srclen)
 {
-  ptrdiff_t slen;
-
-  slen = strlen (src);
-
   /* Process as Unix format: just remove any final slash.
      But leave "/" unchanged; do not change it to "".  */
   strcpy (dst, src);
-  if (slen > 1
-      && IS_DIRECTORY_SEP (dst[slen - 1])
+  if (srclen > 1
+      && IS_DIRECTORY_SEP (dst[srclen - 1])
 #ifdef DOS_NT
-      && !IS_ANY_SEP (dst[slen - 2])
+      && !IS_ANY_SEP (dst[srclen - 2])
 #endif
       )
-    dst[slen - 1] = 0;
+    {
+      dst[srclen - 1] = 0;
+      srclen--;
+    }
 #ifdef DOS_NT
   dostounix_filename (dst);
 #endif
-  return 1;
+  return srclen;
 }
 
 DEFUN ("directory-file-name", Fdirectory_file_name, Sdirectory_file_name,
@@ -533,6 +547,7 @@ In Unix-syntax, this function just removes the final slash.  */)
   (Lisp_Object directory)
 {
   char *buf;
+  ptrdiff_t length;
   Lisp_Object handler;
 
   CHECK_STRING (directory);
@@ -544,12 +559,17 @@ 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);
-  return make_specified_string (buf, -1, strlen (buf),
-                               STRING_MULTIBYTE (directory));
+  buf = alloca (SBYTES (directory) + 20);
+  length = directory_file_name (buf, SSDATA (directory), SBYTES (directory));
+  return make_specified_string (buf, -1, length, STRING_MULTIBYTE (directory));
 }
 
 static const char make_temp_name_tbl[64] =
@@ -744,7 +764,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 +774,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 +807,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'");
+       }
     }
 
   {
@@ -822,7 +855,6 @@ filesystem tree, not (expand-file-name ".."  dirname).  */)
        UNGCPRO;
       }
   }
-  name = FILE_SYSTEM_CASE (name);
   multibyte = STRING_MULTIBYTE (name);
   if (multibyte != STRING_MULTIBYTE (default_directory))
     {
@@ -835,8 +867,8 @@ filesystem tree, not (expand-file-name ".."  dirname).  */)
        }
     }
 
-  /* Make a local copy of nm[] to protect it from GC in DECODE_FILE below. */
-  nm = (char *) alloca (SBYTES (name) + 1);
+  /* Make a local copy of nm[] to protect it from GC in DECODE_FILE below.  */
+  nm = alloca (SBYTES (name) + 1);
   memcpy (nm, SSDATA (name), SBYTES (name) + 1);
 
 #ifdef DOS_NT
@@ -863,7 +895,7 @@ filesystem tree, not (expand-file-name ".."  dirname).  */)
   if (drive && IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1]))
     nm++;
 
-  /* Discard any previous drive specifier if nm is now in UNC format. */
+  /* Discard any previous drive specifier if nm is now in UNC format.  */
   if (IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1]))
     {
       drive = 0;
@@ -928,7 +960,7 @@ filesystem tree, not (expand-file-name ".."  dirname).  */)
            }
          else
 #endif
-         /* drive must be set, so this is okay */
+         /* Drive must be set, so this is okay.  */
          if (strcmp (nm - 2, SSDATA (name)) != 0)
            {
              char temp[] = " :";
@@ -974,7 +1006,7 @@ filesystem tree, not (expand-file-name ".."  dirname).  */)
          if (!(newdir = egetenv ("HOME")))
            newdir = "";
          nm++;
-         /* egetenv may return a unibyte string, which will bite us since
+         /* `egetenv' may return a unibyte string, which will bite us since
             we expect the directory to be multibyte.  */
          tem = build_string (newdir);
          if (!STRING_MULTIBYTE (tem))
@@ -1016,7 +1048,7 @@ filesystem tree, not (expand-file-name ".."  dirname).  */)
      use the drive's current directory as the prefix if needed.  */
   if (!newdir && drive)
     {
-      /* Get default directory if needed to make nm absolute. */
+      /* Get default directory if needed to make nm absolute.  */
       char *adir = NULL;
       if (!IS_DIRECTORY_SEP (nm[0]))
        {
@@ -1026,7 +1058,7 @@ filesystem tree, not (expand-file-name ".."  dirname).  */)
        }
       if (!adir)
        {
-         /* Either nm starts with /, or drive isn't mounted. */
+         /* Either nm starts with /, or drive isn't mounted.  */
          adir = alloca (4);
          adir[0] = DRIVE_LETTER (drive);
          adir[1] = ':';
@@ -1038,11 +1070,11 @@ filesystem tree, not (expand-file-name ".."  dirname).  */)
 #endif /* DOS_NT */
 
   /* Finally, if no prefix has been specified and nm is not absolute,
-     then it must be expanded relative to default_directory. */
+     then it must be expanded relative to default_directory.  */
 
   if (1
 #ifndef DOS_NT
-      /* /... alone is not absolute on DOS and Windows. */
+      /* /... alone is not absolute on DOS and Windows.  */
       && !IS_DIRECTORY_SEP (nm[0])
 #endif
 #ifdef WINDOWSNT
@@ -1064,7 +1096,7 @@ filesystem tree, not (expand-file-name ".."  dirname).  */)
 #ifdef DOS_NT
   if (newdir)
     {
-      /* First ensure newdir is an absolute name. */
+      /* First ensure newdir is an absolute name.  */
       if (
          /* Detect MSDOS file names with drive specifiers.  */
          ! (IS_DRIVE (newdir[0])
@@ -1079,7 +1111,7 @@ filesystem tree, not (expand-file-name ".."  dirname).  */)
             Because of the admonition against calling expand-file-name
             when we have pointers into lisp strings, we accomplish this
             indirectly by prepending newdir to nm if necessary, and using
-            cwd (or the wd of newdir's drive) as the new newdir. */
+            cwd (or the wd of newdir's drive) as the new newdir.  */
          char *adir;
          if (IS_DRIVE (newdir[0]) && IS_DEVICE_SEP (newdir[1]))
            {
@@ -1088,8 +1120,9 @@ filesystem tree, not (expand-file-name ".."  dirname).  */)
            }
          if (!IS_DIRECTORY_SEP (nm[0]))
            {
-             char * tmp = alloca (strlen (newdir) + strlen (nm) + 2);
-             file_name_as_directory (tmp, newdir);
+             ptrdiff_t newlen = strlen (newdir);
+             char *tmp = alloca (newlen + strlen (nm) + 2);
+             file_name_as_directory (tmp, newdir, newlen);
              strcat (tmp, nm);
              nm = tmp;
            }
@@ -1104,7 +1137,7 @@ filesystem tree, not (expand-file-name ".."  dirname).  */)
          newdir = adir;
        }
 
-      /* Strip off drive name from prefix, if present. */
+      /* Strip off drive name from prefix, if present.  */
       if (IS_DRIVE (newdir[0]) && IS_DEVICE_SEP (newdir[1]))
        {
          drive = newdir[0];
@@ -1138,32 +1171,36 @@ filesystem tree, not (expand-file-name ".."  dirname).  */)
       /* Get rid of any slash at the end of newdir, unless newdir is
         just / or // (an incomplete UNC name).  */
       length = strlen (newdir);
+      tlen = length + 1;
       if (length > 1 && IS_DIRECTORY_SEP (newdir[length - 1])
 #ifdef WINDOWSNT
          && !(length == 2 && IS_DIRECTORY_SEP (newdir[0]))
 #endif
          )
        {
-         char *temp = (char *) alloca (length);
+         char *temp = alloca (length);
          memcpy (temp, newdir, length - 1);
          temp[length - 1] = 0;
+         length--;
          newdir = temp;
        }
-      tlen = length + 1;
     }
   else
-    tlen = 0;
+    {
+      length = 0;
+      tlen = 0;
+    }
 
-  /* Now concatenate the directory and name to new space in the stack frame */
+  /* Now concatenate the directory and name to new space in the stack frame */
   tlen += strlen (nm) + 1;
 #ifdef DOS_NT
   /* Reserve space for drive specifier and escape prefix, since either
      or both may need to be inserted.  (The Microsoft x86 compiler
      produces incorrect code if the following two lines are combined.)  */
-  target = (char *) alloca (tlen + 4);
+  target = alloca (tlen + 4);
   target += 4;
 #else  /* not DOS_NT */
-  target = (char *) alloca (tlen);
+  target = alloca (tlen);
 #endif /* not DOS_NT */
   *target = 0;
 
@@ -1183,7 +1220,7 @@ filesystem tree, not (expand-file-name ".."  dirname).  */)
            strcpy (target, newdir);
        }
       else
-       file_name_as_directory (target, newdir);
+       file_name_as_directory (target, newdir, length);
     }
 
   strcat (target, nm);
@@ -1250,7 +1287,7 @@ filesystem tree, not (expand-file-name ".."  dirname).  */)
       }
 
 #ifdef DOS_NT
-    /* At last, set drive name. */
+    /* At last, set drive name.  */
 #ifdef WINDOWSNT
     /* Except for network file name.  */
     if (!(IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1])))
@@ -1278,10 +1315,16 @@ filesystem tree, not (expand-file-name ".."  dirname).  */)
      and perhaps call the corresponding file handler.  This is needed
      for filenames such as "/foo/../user@host:/bar/../baz".  Expanding
      the ".." component gives us "/user@host:/bar/../baz" which needs
-     to be expanded again. */
+     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;
 }
@@ -1348,7 +1391,7 @@ See also the function `substitute-in-file-name'.")
        }
     }
 
-  /* Now determine directory to start with and put it in NEWDIR */
+  /* Now determine directory to start with and put it in NEWDIR */
 
   newdir = 0;
 
@@ -1361,17 +1404,17 @@ See also the function `substitute-in-file-name'.")
       }
     else  /* ~user/filename */
       {
-       /* Get past ~ to user */
+       /* Get past ~ to user */
        unsigned char *user = nm + 1;
-       /* Find end of name. */
+       /* Find end of name.  */
        unsigned char *ptr = (unsigned char *) strchr (user, '/');
        ptrdiff_t len = ptr ? ptr - user : strlen (user);
-       /* Copy the user name into temp storage. */
-       o = (unsigned char *) alloca (len + 1);
+       /* Copy the user name into temp storage.  */
+       o = alloca (len + 1);
        memcpy (o, user, len);
        o[len] = 0;
 
-       /* Look up the user name. */
+       /* Look up the user name.  */
        BLOCK_INPUT;
        pw = (struct passwd *) getpwnam (o + 1);
        UNBLOCK_INPUT;
@@ -1392,10 +1435,10 @@ See also the function `substitute-in-file-name'.")
       newdir = SDATA (defalt);
     }
 
-  /* Now concatenate the directory and name to new space in the stack frame */
+  /* Now concatenate the directory and name to new space in the stack frame */
 
   tlen = (newdir ? strlen (newdir) + 1 : 0) + strlen (nm) + 1;
-  target = (unsigned char *) alloca (tlen);
+  target = alloca (tlen);
   *target = 0;
 
   if (newdir)
@@ -1408,7 +1451,7 @@ See also the function `substitute-in-file-name'.")
 
   strcat (target, nm);
 
-  /* Now canonicalize by removing /. and /foo/.. if they appear */
+  /* Now canonicalize by removing /. and /foo/.. if they appear */
 
   p = target;
   o = target;
@@ -1480,7 +1523,7 @@ search_embedded_absfilename (char *nm, char *endp)
              )
        {
          for (s = p; *s && (!IS_DIRECTORY_SEP (*s)); s++);
-         if (p[0] == '~' && s > p + 1) /* we've got "/~something/" */
+         if (p[0] == '~' && s > p + 1) /* We've got "/~something/".  */
            {
              char *o = alloca (s - p + 1);
              struct passwd *pw;
@@ -1534,12 +1577,18 @@ 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
      data to be relocated.  */
-  nm = (char *) alloca (SBYTES (filename) + 1);
+  nm = alloca (SBYTES (filename) + 1);
   memcpy (nm, SDATA (filename), SBYTES (filename) + 1);
 
 #ifdef DOS_NT
@@ -1553,12 +1602,12 @@ those `/' is discarded.  */)
   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));
 
   /* See if any variables are substituted into the string
-     and find the total length of their values in `total' */
+     and find the total length of their values in `total' */
 
   for (p = nm; p != endp;)
     if (*p != '$')
@@ -1570,7 +1619,7 @@ those `/' is discarded.  */)
          goto badsubst;
        else if (*p == '$')
          {
-           /* "$$" means a single "$" */
+           /* "$$" means a single "$" */
            p++;
            total -= 1;
            substituted = 1;
@@ -1590,15 +1639,15 @@ those `/' is discarded.  */)
            s = p;
          }
 
-       /* Copy out the variable name */
-       target = (char *) alloca (s - o + 1);
-       strncpy (target, o, s - o);
+       /* Copy out the variable name */
+       target = alloca (s - o + 1);
+       memcpy (target, o, s - o);
        target[s - o] = 0;
 #ifdef DOS_NT
        strupr (target); /* $home == $HOME etc.  */
 #endif /* DOS_NT */
 
-       /* Get variable value */
+       /* Get variable value */
        o = egetenv (target);
        if (o)
          {
@@ -1608,7 +1657,7 @@ those `/' is discarded.  */)
               env variables twice should be acceptable. Note that
               decoding may cause a garbage collect.  */
            Lisp_Object orig, decoded;
-           orig = make_unibyte_string (o, strlen (o));
+           orig = build_unibyte_string (o);
            decoded = DECODE_FILE (orig);
            total += SBYTES (decoded);
            substituted = 1;
@@ -1620,12 +1669,12 @@ those `/' is discarded.  */)
   if (!substituted)
     return filename;
 
-  /* If substitution required, recopy the string and do it */
-  /* Make space in stack frame for the new copy */
-  xnm = (char *) alloca (SBYTES (filename) + total + 1);
+  /* If substitution required, recopy the string and do it */
+  /* Make space in stack frame for the new copy */
+  xnm = alloca (SBYTES (filename) + total + 1);
   x = xnm;
 
-  /* Copy the rest of the name through, replacing $ constructs with values */
+  /* Copy the rest of the name through, replacing $ constructs with values */
   for (p = nm; *p;)
     if (*p != '$')
       *x++ = *p++;
@@ -1653,15 +1702,15 @@ those `/' is discarded.  */)
            s = p;
          }
 
-       /* Copy out the variable name */
-       target = (char *) alloca (s - o + 1);
-       strncpy (target, o, s - o);
+       /* Copy out the variable name */
+       target = alloca (s - o + 1);
+       memcpy (target, o, s - o);
        target[s - o] = 0;
 #ifdef DOS_NT
        strupr (target); /* $home == $HOME etc.  */
 #endif /* DOS_NT */
 
-       /* Get variable value */
+       /* Get variable value */
        o = egetenv (target);
        if (!o)
          {
@@ -1676,13 +1725,13 @@ those `/' is discarded.  */)
            orig = make_unibyte_string (o, orig_length);
            decoded = DECODE_FILE (orig);
            decoded_length = SBYTES (decoded);
-           strncpy (x, SSDATA (decoded), decoded_length);
+           memcpy (x, SDATA (decoded), decoded_length);
            x += decoded_length;
 
            /* If environment variable needed decoding, return value
               needs to be multibyte.  */
            if (decoded_length != orig_length
-               || strncmp (SSDATA (decoded), o, orig_length))
+               || memcmp (SDATA (decoded), o, orig_length))
              multibyte = 1;
          }
       }
@@ -1723,7 +1772,7 @@ expand_and_dir_to_file (Lisp_Object filename, Lisp_Object defdir)
      stat behaves differently depending!  */
   if (SCHARS (absname) > 1
       && IS_DIRECTORY_SEP (SREF (absname, SBYTES (absname) - 1))
-      && !IS_DEVICE_SEP (SREF (absname, SBYTES (absname)-2)))
+      && !IS_DEVICE_SEP (SREF (absname, SBYTES (absname) - 2)))
     /* We cannot take shortcuts; they might be wrong for magic file names.  */
     absname = Fdirectory_file_name (absname);
   return absname;
@@ -1751,7 +1800,7 @@ barf_or_query_if_file_exists (Lisp_Object absname, const char *querystring,
 
   encoded_filename = ENCODE_FILE (absname);
 
-  /* stat is a good way to tell whether the file exists,
+  /* `stat' is a good way to tell whether the file exists,
      regardless of what access permissions it has.  */
   if (lstat (SSDATA (encoded_filename), &statbuf) >= 0)
     {
@@ -1871,13 +1920,13 @@ on the system, we copy the SELinux context of FILE to NEWNAME.  */)
       DWORD attributes;
       char * filename;
 
-      EMACS_GET_TIME (now);
       filename = SDATA (encoded_newname);
 
       /* Ensure file is writable while its modified time is set.  */
       attributes = GetFileAttributes (filename);
       SetFileAttributes (filename, attributes & ~FILE_ATTRIBUTE_READONLY);
-      if (set_file_times (filename, now, now))
+      now = current_emacs_time ();
+      if (set_file_times (-1, filename, now, now))
        {
          /* Restore original attributes.  */
          SetFileAttributes (filename, attributes);
@@ -1990,33 +2039,31 @@ on the system, we copy the SELinux context of FILE to NEWNAME.  */)
 #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);
     }
 #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));
-
   if (input_file_statable_p)
     {
       if (!NILP (keep_time))
        {
-         EMACS_TIME atime, mtime;
-         EMACS_SET_SECS_USECS (atime, st.st_atime, 0);
-         EMACS_SET_SECS_USECS (mtime, st.st_mtime, 0);
-         if (set_file_times (SSDATA (encoded_newname),
-                             atime, mtime))
+         EMACS_TIME atime = get_stat_atime (&st);
+         EMACS_TIME mtime = get_stat_mtime (&st);
+         if (set_file_times (ofd, SSDATA (encoded_newname), atime, mtime))
            xsignal2 (Qfile_date_error,
                      build_string ("Cannot set file date"), newname);
        }
     }
 
+  if (emacs_close (ofd) < 0)
+    report_file_error ("I/O error", Fcons (newname, Qnil));
+
   emacs_close (ifd);
 
 #ifdef MSDOS
@@ -2062,7 +2109,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 +2463,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 +2791,13 @@ See `file-symlink-p' to distinguish symlinks.  */)
 \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;
@@ -2787,9 +2850,12 @@ if file does not exist, is not accessible, or SELinux is disabled */)
 \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;
@@ -2844,10 +2910,11 @@ is disabled. */)
                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);
@@ -2939,8 +3006,10 @@ The value is an integer.  */)
   int realmask;
   Lisp_Object value;
 
+  BLOCK_INPUT;
   realmask = umask (0);
   umask (realmask);
+  UNBLOCK_INPUT;
 
   XSETINT (value, (~ realmask) & 0777);
   return value;
@@ -2957,11 +3026,7 @@ Use the current time if TIMESTAMP is nil.  TIMESTAMP is in the format of
 {
   Lisp_Object absname, encoded_absname;
   Lisp_Object handler;
-  time_t sec;
-  int usec;
-
-  if (! lisp_time_argument (timestamp, &sec, &usec))
-    error ("Invalid time specification");
+  EMACS_TIME t = lisp_time_argument (timestamp);
 
   absname = Fexpand_file_name (filename, BVAR (current_buffer, directory));
 
@@ -2974,12 +3039,7 @@ Use the current time if TIMESTAMP is nil.  TIMESTAMP is in the format of
   encoded_absname = ENCODE_FILE (absname);
 
   {
-    EMACS_TIME t;
-
-    EMACS_SET_SECS (t, sec);
-    EMACS_SET_USECS (t, usec);
-
-    if (set_file_times (SSDATA (encoded_absname), t, t))
+    if (set_file_times (-1, SSDATA (encoded_absname), t, t))
       {
 #ifdef DOS_NT
         struct stat st;
@@ -3014,8 +3074,7 @@ otherwise, if FILE2 does not exist, the answer is t.  */)
   (Lisp_Object file1, Lisp_Object file2)
 {
   Lisp_Object absname1, absname2;
-  struct stat st;
-  int mtime1;
+  struct stat st1, st2;
   Lisp_Object handler;
   struct gcpro gcpro1, gcpro2;
 
@@ -3041,15 +3100,14 @@ otherwise, if FILE2 does not exist, the answer is t.  */)
   absname2 = ENCODE_FILE (absname2);
   UNGCPRO;
 
-  if (stat (SSDATA (absname1), &st) < 0)
+  if (stat (SSDATA (absname1), &st1) < 0)
     return Qnil;
 
-  mtime1 = st.st_mtime;
-
-  if (stat (SSDATA (absname2), &st) < 0)
+  if (stat (SSDATA (absname2), &st2) < 0)
     return Qt;
 
-  return (mtime1 > st.st_mtime) ? Qt : Qnil;
+  return (EMACS_TIME_GT (get_stat_mtime (&st1), get_stat_mtime (&st2))
+         ? Qt : Qnil);
 }
 \f
 #ifndef READ_BUF_SIZE
@@ -3087,7 +3145,7 @@ decide_coding_unwind (Lisp_Object unwind_data)
     set_buffer_internal (XBUFFER (buffer));
   adjust_markers_for_delete (BEG, BEG_BYTE, Z, Z_BYTE);
   adjust_overlays_for_delete (BEG, Z - BEG);
-  BUF_INTERVALS (current_buffer) = 0;
+  buffer_set_intervals (current_buffer, NULL);
   TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
 
   /* Now we are safe to change the buffer's multibyteness directly.  */
@@ -3150,6 +3208,15 @@ emacs_lseek (int fd, EMACS_INT offset, int whence)
   return lseek (fd, offset, whence);
 }
 
+/* Return a special time value indicating the error number ERRNUM.  */
+static EMACS_TIME
+time_error_value (int errnum)
+{
+  int ns = (errnum == ENOENT || errnum == EACCES || errnum == ENOTDIR
+           ? NONEXISTENT_MODTIME_NSECS
+           : UNKNOWN_MODTIME_NSECS);
+  return make_emacs_time (0, ns);
+}
 
 DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
        1, 5, 0,
@@ -3177,6 +3244,8 @@ variable `last-coding-system-used' to the coding system actually used.  */)
   (Lisp_Object filename, Lisp_Object visit, Lisp_Object beg, Lisp_Object end, Lisp_Object replace)
 {
   struct stat st;
+  int file_status;
+  EMACS_TIME mtime;
   register int fd;
   ptrdiff_t inserted = 0;
   int nochange = 0;
@@ -3245,19 +3314,22 @@ variable `last-coding-system-used' to the coding system actually used.  */)
 
     /* Tell stat to use expensive method to get accurate info.  */
     Vw32_get_true_file_attributes = Qt;
-    total = stat (SSDATA (filename), &st);
+    file_status = stat (SSDATA (filename), &st);
     Vw32_get_true_file_attributes = tem;
   }
-  if (total < 0)
 #else
-  if (stat (SSDATA (filename), &st) < 0)
+  file_status = stat (SSDATA (filename), &st);
 #endif /* WINDOWSNT */
+
+  if (file_status == 0)
+    mtime = get_stat_mtime (&st);
+  else
     {
     badopen:
       save_errno = errno;
       if (NILP (visit))
        report_file_error ("Opening input file", Fcons (orig_filename, Qnil));
-      st.st_mtime = -1;
+      mtime = time_error_value (save_errno);
       st.st_size = -1;
       how_much = 0;
       if (!NILP (Vcoding_system_for_read))
@@ -3660,7 +3732,7 @@ variable `last-coding-system-used' to the coding system actually used.  */)
          /* If display currently starts at beginning of line,
             keep it that way.  */
          if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer)
-           XWINDOW (selected_window)->start_at_line_beg = Fbolp ();
+           XWINDOW (selected_window)->start_at_line_beg = !NILP (Fbolp ());
 
          replace_handled = 1;
        }
@@ -3689,6 +3761,7 @@ variable `last-coding-system-used' to the coding system actually used.  */)
       ptrdiff_t 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);
 
@@ -3709,7 +3782,7 @@ variable `last-coding-system-used' to the coding system actually used.  */)
        {
          /* 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).  */
          int trytry = min (total - how_much, READ_BUF_SIZE - unprocessed);
 
          /* Allow quitting out of the actual I/O.  */
@@ -3816,7 +3889,7 @@ variable `last-coding-system-used' to the coding system actually used.  */)
       /* If display currently starts at beginning of line,
         keep it that way.  */
       if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer)
-       XWINDOW (selected_window)->start_at_line_beg = Fbolp ();
+       XWINDOW (selected_window)->start_at_line_beg = !NILP (Fbolp ());
 
       /* Replace the chars that we need to replace,
         and update INSERTED to equal the number of bytes
@@ -4101,6 +4174,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:
@@ -4117,7 +4200,7 @@ variable `last-coding-system-used' to the coding system actually used.  */)
 
       if (NILP (handler))
        {
-         current_buffer->modtime = st.st_mtime;
+         current_buffer->modtime = mtime;
          current_buffer->modtime_size = st.st_size;
          BVAR (current_buffer, filename) = orig_filename;
        }
@@ -4179,7 +4262,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
@@ -4276,18 +4359,8 @@ 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)
+      && EMACS_NSECS (current_buffer->modtime) == NONEXISTENT_MODTIME_NSECS)
     {
       /* If visiting nonexistent file, return nil.  */
       errno = save_errno;
@@ -4725,7 +4798,7 @@ This calls `write-region-annotate-functions' at the start, and
      next attempt to save.  */
   if (visiting)
     {
-      current_buffer->modtime = st.st_mtime;
+      current_buffer->modtime = get_stat_mtime (&st);
       current_buffer->modtime_size = st.st_size;
     }
 
@@ -5002,6 +5075,7 @@ See Info node `(elisp)Modification Time' for more details.  */)
   struct stat st;
   Lisp_Object handler;
   Lisp_Object filename;
+  EMACS_TIME mtime, diff;
 
   if (NILP (buf))
     b = current_buffer;
@@ -5012,7 +5086,7 @@ See Info node `(elisp)Modification Time' for more details.  */)
     }
 
   if (!STRINGP (BVAR (b, filename))) return Qt;
-  if (b->modtime == 0) return Qt;
+  if (EMACS_NSECS (b->modtime) == UNKNOWN_MODTIME_NSECS) return Qt;
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
@@ -5023,20 +5097,16 @@ See Info node `(elisp)Modification Time' for more details.  */)
 
   filename = ENCODE_FILE (BVAR (b, filename));
 
-  if (stat (SSDATA (filename), &st) < 0)
-    {
-      /* If the file doesn't exist now and didn't exist before,
-        we say that it isn't modified, provided the error is a tame one.  */
-      if (errno == ENOENT || errno == EACCES || errno == ENOTDIR)
-       st.st_mtime = -1;
-      else
-       st.st_mtime = 0;
-    }
-  if ((st.st_mtime == b->modtime
-       /* If both are positive, accept them if they are off by one second.  */
-       || (st.st_mtime > 0 && b->modtime > 0
-          && (st.st_mtime - 1 == b->modtime
-              || st.st_mtime == b->modtime - 1)))
+  mtime = (stat (SSDATA (filename), &st) == 0
+          ? get_stat_mtime (&st)
+          : time_error_value (errno));
+  if ((EMACS_TIME_EQ (mtime, b->modtime)
+       /* If both exist, accept them if they are off by one second.  */
+       || (EMACS_TIME_VALID_P (mtime) && EMACS_TIME_VALID_P (b->modtime)
+          && ((diff = (EMACS_TIME_LT (mtime, b->modtime)
+                       ? sub_emacs_time (b->modtime, mtime)
+                       : sub_emacs_time (mtime, b->modtime))),
+              EMACS_TIME_LE (diff, make_emacs_time (1, 0)))))
       && (st.st_size == b->modtime_size
           || b->modtime_size < 0))
     return Qt;
@@ -5049,7 +5119,7 @@ DEFUN ("clear-visited-file-modtime", Fclear_visited_file_modtime,
 Next attempt to save will certainly not complain of a discrepancy.  */)
   (void)
 {
-  current_buffer->modtime = 0;
+  current_buffer->modtime = make_emacs_time (0, UNKNOWN_MODTIME_NSECS);
   current_buffer->modtime_size = -1;
   return Qnil;
 }
@@ -5057,16 +5127,16 @@ Next attempt to save will certainly not complain of a discrepancy.  */)
 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
+The value is a list of the form (HIGH LOW USEC PSEC), 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)
 {
-  if (! current_buffer->modtime)
+  if (EMACS_NSECS (current_buffer->modtime) < 0)
     return make_number (0);
-  return make_time (current_buffer->modtime);
+  return make_lisp_time (current_buffer->modtime);
 }
 
 DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
@@ -5076,12 +5146,12 @@ Useful if the buffer was not read from the file normally
 or if the file itself has been changed for some known benign reason.
 An argument specifies the modification time value to use
 \(instead of that of the visited file), in the form of a list
-\(HIGH . LOW) or (HIGH LOW).  */)
+\(HIGH LOW USEC PSEC) as returned by `current-time'.  */)
   (Lisp_Object time_list)
 {
   if (!NILP (time_list))
     {
-      CONS_TO_INTEGER (time_list, time_t, current_buffer->modtime);
+      current_buffer->modtime = lisp_time_argument (time_list);
       current_buffer->modtime_size = -1;
     }
   else
@@ -5103,7 +5173,7 @@ An argument specifies the modification time value to use
 
       if (stat (SSDATA (filename), &st) >= 0)
         {
-         current_buffer->modtime = st.st_mtime;
+         current_buffer->modtime = get_stat_mtime (&st);
           current_buffer->modtime_size = st.st_size;
         }
     }
@@ -5130,7 +5200,7 @@ auto_save_error (Lisp_Object error_val)
   msg = Fformat (3, args);
   GCPRO1 (msg);
   nbytes = SBYTES (msg);
-  SAFE_ALLOCA (msgbuf, char *, nbytes);
+  msgbuf = SAFE_ALLOCA (nbytes);
   memcpy (msgbuf, SDATA (msg), nbytes);
 
   for (i = 0; i < 3; ++i)
@@ -5199,16 +5269,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;
 }
 
@@ -5276,7 +5348,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;
        }
@@ -5346,9 +5418,8 @@ A non-nil CURRENT-ONLY argument means save only current buffer.  */)
                || NILP (Ffind_file_name_handler (BVAR (b, auto_save_file_name),
                                                  Qwrite_region))))
          {
-           EMACS_TIME before_time, after_time;
-
-           EMACS_GET_TIME (before_time);
+           EMACS_TIME before_time = current_emacs_time ();
+           EMACS_TIME after_time;
 
            /* If we had a failure, don't try again for 20 minutes.  */
            if (b->auto_save_failure_time > 0
@@ -5385,7 +5456,7 @@ A non-nil CURRENT-ONLY argument means save only current buffer.  */)
            XSETFASTINT (BVAR (current_buffer, save_length), Z - BEG);
            set_buffer_internal (old);
 
-           EMACS_GET_TIME (after_time);
+           after_time = current_emacs_time ();
 
            /* If auto-save took more than 60 seconds,
               assume it was an NFS failure that got a timeout.  */
@@ -5542,7 +5613,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;
 
@@ -5565,31 +5636,38 @@ of file names regardless of the current language environment.  */);
   Fput (Qfile_error, Qerror_conditions,
        Fpurecopy (list2 (Qfile_error, Qerror)));
   Fput (Qfile_error, Qerror_message,
-       make_pure_c_string ("File error"));
+       build_pure_c_string ("File error"));
 
   Fput (Qfile_already_exists, Qerror_conditions,
        Fpurecopy (list3 (Qfile_already_exists, Qfile_error, Qerror)));
   Fput (Qfile_already_exists, Qerror_message,
-       make_pure_c_string ("File already exists"));
+       build_pure_c_string ("File already exists"));
 
   Fput (Qfile_date_error, Qerror_conditions,
        Fpurecopy (list3 (Qfile_date_error, Qfile_error, Qerror)));
   Fput (Qfile_date_error, Qerror_message,
-       make_pure_c_string ("Cannot set file date"));
+       build_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",
@@ -5689,7 +5767,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;