Include <config.h> instead of "config.h".
[bpt/emacs.git] / src / fileio.c
index 59a7c9e..347585f 100644 (file)
@@ -1,5 +1,5 @@
 /* File IO for GNU Emacs.
-   Copyright (C) 1985, 1986, 1987, 1988, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1987, 1988, 1993 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
-#include "config.h"
+#include <config.h>
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -35,8 +35,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <perror.h>
 #include <stddef.h>
 #include <string.h>
-#else
-#include <sys/dir.h>
 #endif
 
 #include <errno.h>
@@ -53,7 +51,16 @@ extern int sys_nerr;
 #include <sys/time.h>
 #endif
 
+#ifndef USG
+#ifndef VMS
+#ifndef BSD4_1
+#define HAVE_FSYNC
+#endif
+#endif
+#endif
+
 #include "lisp.h"
+#include "intervals.h"
 #include "buffer.h"
 #include "window.h"
 
@@ -69,9 +76,11 @@ extern int sys_nerr;
 #ifdef HPUX
 #include <netio.h>
 #ifndef HPUX8
+#ifndef HPUX9
 #include <errnet.h>
 #endif
 #endif
+#endif
 
 #ifndef O_WRONLY
 #define O_WRONLY 1
@@ -101,6 +110,8 @@ int vms_stmlf_recfm;
 
 Lisp_Object Qfile_error, Qfile_already_exists;
 
+Lisp_Object Qfile_name_history;
+
 report_file_error (string, data)
      char *string;
      Lisp_Object data;
@@ -128,6 +139,12 @@ close_file_unwind (fd)
   close (XFASTINT (fd));
 }
 \f
+Lisp_Object Qexpand_file_name;
+Lisp_Object Qdirectory_file_name;
+Lisp_Object Qfile_name_directory;
+Lisp_Object Qfile_name_nondirectory;
+Lisp_Object Qunhandled_file_name_directory;
+Lisp_Object Qfile_name_as_directory;
 Lisp_Object Qcopy_file;
 Lisp_Object Qmake_directory;
 Lisp_Object Qdelete_directory;
@@ -148,15 +165,21 @@ Lisp_Object Qfile_newer_than_file_p;
 Lisp_Object Qinsert_file_contents;
 Lisp_Object Qwrite_region;
 Lisp_Object Qverify_visited_file_modtime;
+Lisp_Object Qset_visited_file_modtime;
 
-/* If FILENAME is handled specially on account of its syntax,
-   return its handler function.  Otherwise, return nil.  */
-
-Lisp_Object
-find_file_handler (filename)
-     Lisp_Object filename;
+DEFUN ("find-file-name-handler", Ffind_file_name_handler, Sfind_file_name_handler, 1, 1, 0,
+  "Return FILENAME's handler function, if its syntax is handled specially.\n\
+Otherwise, return nil.\n\
+A file name is handled if one of the regular expressions in\n\
+`file-name-handler-alist' matches it.")
+  (filename)
+    Lisp_Object filename;
 {
+  /* This function must not munge the match data.  */
   Lisp_Object chain;
+
+  CHECK_STRING (filename, 0);
+
   for (chain = Vfile_name_handler_alist; XTYPE (chain) == Lisp_Cons;
        chain = XCONS (chain)->cdr)
     {
@@ -167,9 +190,11 @@ find_file_handler (filename)
          Lisp_Object string;
          string = XCONS (elt)->car;
          if (XTYPE (string) == Lisp_String
-             && fast_string_match (string, filename))
+             && fast_string_match (string, filename) >= 0)
            return XCONS (elt)->cdr;
        }
+
+      QUIT;
     }
   return Qnil;
 }
@@ -186,9 +211,16 @@ on VMS, perhaps instead a string ending in `:', `]' or `>'.")
 {
   register unsigned char *beg;
   register unsigned char *p;
+  Lisp_Object handler;
 
   CHECK_STRING (file, 0);
 
+  /* If the file name has special constructs in it,
+     call the corresponding file handler.  */
+  handler = Ffind_file_name_handler (file);
+  if (!NILP (handler))
+    return call2 (handler, Qfile_name_directory, file);
+
   beg = XSTRING (file)->data;
   p = beg + XSTRING (file)->size;
 
@@ -213,9 +245,16 @@ or the entire name if it contains no slash.")
      Lisp_Object file;
 {
   register unsigned char *beg, *p, *end;
+  Lisp_Object handler;
 
   CHECK_STRING (file, 0);
 
+  /* If the file name has special constructs in it,
+     call the corresponding file handler.  */
+  handler = Ffind_file_name_handler (file);
+  if (!NILP (handler))
+    return call2 (handler, Qfile_name_nondirectory, file);
+
   beg = XSTRING (file)->data;
   end = p = beg + XSTRING (file)->size;
 
@@ -227,6 +266,29 @@ or the entire name if it contains no slash.")
 
   return make_string (p, end - p);
 }
+
+DEFUN ("unhandled-file-name-directory", Funhandled_file_name_directory, Sunhandled_file_name_directory, 1, 1, 0,
+  "Return a directly usable directory name somehow associated with FILENAME.\n\
+A `directly usable' directory name is one that may be used without the\n\
+intervention of any file handler.\n\
+If FILENAME is a directly usable file itself, return\n\
+(file-name-directory FILENAME).\n\
+The `call-process' and `start-process' functions use this function to\n\
+get a current directory to run processes in.")
+  (filename)
+    Lisp_Object filename;
+{
+  Lisp_Object handler;
+
+  /* If the file name has special constructs in it,
+     call the corresponding file handler.  */
+  handler = Ffind_file_name_handler (filename);
+  if (!NILP (handler))
+    return call2 (handler, Qunhandled_file_name_directory, filename);
+
+  return Ffile_name_directory (filename);
+}
+
 \f
 char *
 file_name_as_directory (out, in)
@@ -314,10 +376,18 @@ On VMS, converts \"[X]FOO.DIR\" to \"[X.FOO]\", etc.")
      Lisp_Object file;
 {
   char *buf;
+  Lisp_Object handler;
 
   CHECK_STRING (file, 0);
   if (NILP (file))
     return Qnil;
+
+  /* If the file name has special constructs in it,
+     call the corresponding file handler.  */
+  handler = Ffind_file_name_handler (file);
+  if (!NILP (handler))
+    return call2 (handler, Qfile_name_as_directory, file);
+
   buf = (char *) alloca (XSTRING (file)->size + 10);
   return build_string (file_name_as_directory (buf, XSTRING (file)->data));
 }
@@ -440,9 +510,11 @@ directory_file_name (src, dst)
                  && (ptr[rlen] == ']' || ptr[rlen] == '>')
                  && ptr[rlen - 1] == '.')
                {
-                 ptr[rlen - 1] = ']';
-                 ptr[rlen] = '\0';
-                 return directory_file_name (ptr, dst);
+                 char * buf = (char *) alloca (strlen (ptr) + 1);
+                 strcpy (buf, ptr);
+                 buf[rlen - 1] = ']';
+                 buf[rlen] = '\0';
+                 return directory_file_name (buf, dst);
                }
              else
                dst[slen - 1] = ':';
@@ -479,11 +551,19 @@ it returns a file name such as \"[X]Y.DIR.1\".")
      Lisp_Object directory;
 {
   char *buf;
+  Lisp_Object handler;
 
   CHECK_STRING (directory, 0);
 
   if (NILP (directory))
     return Qnil;
+
+  /* If the file name has special constructs in it,
+     call the corresponding file handler.  */
+  handler = Ffind_file_name_handler (directory);
+  if (!NILP (handler))
+    return call2 (handler, Qdirectory_file_name, directory);
+
 #ifdef VMS
   /* 20 extra chars is insufficient for VMS, since we might perform a
      logical name translation. an equivalence string can be up to 255
@@ -530,7 +610,6 @@ See also the function `substitute-in-file-name'.")
   int tlen;
   unsigned char *target;
   struct passwd *pw;
-  int lose;
 #ifdef VMS
   unsigned char * colon = 0;
   unsigned char * close = 0;
@@ -539,9 +618,42 @@ See also the function `substitute-in-file-name'.")
   int lbrack = 0, rbrack = 0;
   int dots = 0;
 #endif /* VMS */
+  Lisp_Object handler;
   
   CHECK_STRING (name, 0);
 
+  /* If the file name has special constructs in it,
+     call the corresponding file handler.  */
+  handler = Ffind_file_name_handler (name);
+  if (!NILP (handler))
+    return call3 (handler, Qexpand_file_name, name, defalt);
+
+  /* Use the buffer's default-directory if DEFALT is omitted.  */
+  if (NILP (defalt))
+    defalt = current_buffer->directory;
+  CHECK_STRING (defalt, 1);
+
+  /* Make sure DEFALT is properly expanded.
+     It would be better to do this down below where we actually use
+     defalt.  Unfortunately, calling Fexpand_file_name recursively
+     could invoke GC, and the strings might be relocated.  This would
+     be annoying because we have pointers into strings lying around
+     that would need adjusting, and people would add new pointers to
+     the code and forget to adjust them, resulting in intermittent bugs.
+     Putting this call here avoids all that crud.
+
+     The EQ test avoids infinite recursion.  */
+  if (! NILP (defalt) && !EQ (defalt, name)
+      /* This saves time in a common case.  */
+      && XSTRING (defalt)->data[0] != '/')
+    {
+      struct gcpro gcpro1;
+
+      GCPRO1 (name);
+      defalt = Fexpand_file_name (defalt, Qnil);
+      UNGCPRO;
+    }
+
 #ifdef VMS
   /* Filenames on VMS are always upper case.  */
   name = Fupcase (name);
@@ -558,10 +670,22 @@ See also the function `substitute-in-file-name'.")
 #endif /* VMS */
       )
     {
+      /* If it turns out that the filename we want to return is just a
+        suffix of FILENAME, we don't need to go through and edit
+        things; we just need to construct a new string using data
+        starting at the middle of FILENAME.  If we set lose to a
+        non-zero value, that means we've discovered that we can't do
+        that cool trick.  */
+      int lose = 0;
+
       p = nm;
-      lose = 0;
       while (*p)
        {
+         /* Since we know the path is absolute, we can assume that each
+            element starts with a "/".  */
+
+         /* "//" anywhere isn't necessarily hairy; we just start afresh
+            with the second slash.  */
          if (p[0] == '/' && p[1] == '/'
 #ifdef APOLLO
              /* // at start of filename is meaningful on Apollo system */
@@ -569,11 +693,18 @@ See also the function `substitute-in-file-name'.")
 #endif /* APOLLO */
              )
            nm = p + 1;
+
+         /* "~" is hairy as the start of any path element.  */
          if (p[0] == '/' && p[1] == '~')
            nm = p + 1, lose = 1;
-         if (p[0] == '/' && p[1] == '.'
-             && (p[2] == '/' || p[2] == 0
-                 || (p[2] == '.' && (p[3] == '/' || p[3] == 0))))
+
+         /* "." and ".." are hairy.  */
+         if (p[0] == '/'
+             && p[1] == '.'
+             && (p[2] == '/'
+                 || p[2] == 0
+                 || (p[2] == '.' && (p[3] == '/'
+                                     || p[3] == 0))))
            lose = 1;
 #ifdef VMS
          if (p[0] == '\\')
@@ -667,44 +798,46 @@ See also the function `substitute-in-file-name'.")
   newdir = 0;
 
   if (nm[0] == '~')            /* prefix ~ */
-    if (nm[1] == '/'
+    {
+      if (nm[1] == '/'
 #ifdef VMS
-       || nm[1] == ':'
-#endif /* VMS */
-       || nm[1] == 0)/* ~ by itself */
-      {
-       if (!(newdir = (unsigned char *) egetenv ("HOME")))
-         newdir = (unsigned char *) "";
-       nm++;
+         || nm[1] == ':'
+#endif                         /* VMS */
+         || nm[1] == 0)        /* ~ by itself */
+       {
+         if (!(newdir = (unsigned char *) egetenv ("HOME")))
+           newdir = (unsigned char *) "";
+         nm++;
 #ifdef VMS
-       nm++;                   /* Don't leave the slash in nm.  */
-#endif /* VMS */
-      }
-    else                       /* ~user/filename */
-      {
-       for (p = nm; *p && (*p != '/'
+         nm++;                 /* Don't leave the slash in nm.  */
+#endif                         /* VMS */
+       }
+      else                     /* ~user/filename */
+       {
+         for (p = nm; *p && (*p != '/'
 #ifdef VMS
-                           && *p != ':'
-#endif /* VMS */
-                           ); p++);
-       o = (unsigned char *) alloca (p - nm + 1);
-       bcopy ((char *) nm, o, p - nm);
-       o [p - nm] = 0;
+                             && *p != ':'
+#endif                         /* VMS */
+                             ); p++);
+         o = (unsigned char *) alloca (p - nm + 1);
+         bcopy ((char *) nm, o, p - nm);
+         o [p - nm] = 0;
 
-       pw = (struct passwd *) getpwnam (o + 1);
-       if (pw)
-         {
-           newdir = (unsigned char *) pw -> pw_dir;
+         pw = (struct passwd *) getpwnam (o + 1);
+         if (pw)
+           {
+             newdir = (unsigned char *) pw -> pw_dir;
 #ifdef VMS
-           nm = p + 1;         /* skip the terminator */
+             nm = p + 1;       /* skip the terminator */
 #else
-           nm = p;
-#endif /* VMS */
-         }
+             nm = p;
+#endif                         /* VMS */
+           }
 
-       /* If we don't find a user of that name, leave the name
-          unchanged; don't move nm forward to p.  */
-      }
+         /* If we don't find a user of that name, leave the name
+            unchanged; don't move nm forward to p.  */
+       }
+    }
 
   if (nm[0] != '/'
 #ifdef VMS
@@ -712,9 +845,6 @@ See also the function `substitute-in-file-name'.")
 #endif /* not VMS */
       && !newdir)
     {
-      if (NILP (defalt))
-       defalt = current_buffer->directory;
-      CHECK_STRING (defalt, 1);
       newdir = XSTRING (defalt)->data;
     }
 
@@ -722,6 +852,9 @@ See also the function `substitute-in-file-name'.")
     {
       /* Get rid of any slash at the end of newdir.  */
       int length = strlen (newdir);
+      /* Adding `length > 1 &&' makes ~ expand into / when homedir
+        is the root dir.  People disagree about whether that is right.
+        Anyway, we can't take the risk of this change now.  */
       if (newdir[length - 1] == '/')
        {
          unsigned char *temp = (unsigned char *) alloca (length);
@@ -746,7 +879,7 @@ See also the function `substitute-in-file-name'.")
        strcpy (target, newdir);
       else
 #endif
-      file_name_as_directory (target, newdir);
+       file_name_as_directory (target, newdir);
     }
 
   strcat (target, nm);
@@ -755,7 +888,7 @@ See also the function `substitute-in-file-name'.")
     strcpy (target, sys_translate_unix (target));
 #endif /* VMS */
 
-  /* Now canonicalize by removing /. and /foo/.. if they appear */
+  /* Now canonicalize by removing /. and /foo/.. if they appear */
 
   p = target;
   o = target;
@@ -818,9 +951,17 @@ See also the function `substitute-in-file-name'.")
          o = target;
          p++;
        }
-      else if (p[0] == '/' && p[1] == '.' &&
-              (p[2] == '/' || p[2] == 0))
-       p += 2;
+      else if (p[0] == '/'
+              && p[1] == '.'
+              && (p[2] == '/'
+                  || p[2] == 0))
+       {
+         /* If "/." is the entire filename, keep the "/".  Otherwise,
+            just delete the whole "/.".  */
+         if (o == target && p[2] == '\0')
+           *o++ = *p;
+         p += 2;
+       }
       else if (!strncmp (p, "/..", 3)
               /* `/../' is the "superroot" on certain file systems.  */
               && o != target
@@ -1364,6 +1505,9 @@ duplicates what `expand-file-name' does.")
 #endif /* not VMS */
 }
 \f
+/* A slightly faster and more convenient way to get
+   (directory-file-name (expand-file-name FOO)).  */
+
 Lisp_Object
 expand_and_dir_to_file (filename, defdir)
      Lisp_Object filename, defdir;
@@ -1382,11 +1526,8 @@ expand_and_dir_to_file (filename, defdir)
      stat behaves differently depending!  */
   if (XSTRING (abspath)->size > 1
       && XSTRING (abspath)->data[XSTRING (abspath)->size - 1] == '/')
-    {
-      if (EQ (abspath, filename))
-       abspath = Fcopy_sequence (abspath);
-      XSTRING (abspath)->data[XSTRING (abspath)->size - 1] = 0;
-    }
+    /* We cannot take shortcuts; they might be wrong for magic file names.  */
+    abspath = Fdirectory_file_name (abspath);
 #endif
   return abspath;
 }
@@ -1436,6 +1577,7 @@ A prefix arg makes KEEP-TIME non-nil.")
   Lisp_Object handler;
   struct gcpro gcpro1, gcpro2;
   int count = specpdl_ptr - specpdl;
+  Lisp_Object args[6];
 
   GCPRO2 (filename, newname);
   CHECK_STRING (filename, 0);
@@ -1443,11 +1585,15 @@ A prefix arg makes KEEP-TIME non-nil.")
   filename = Fexpand_file_name (filename, Qnil);
   newname = Fexpand_file_name (newname, Qnil);
 
-  /* If the file name has special constructs in it,
+  /* If the input file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = find_file_handler (filename);
+  handler = Ffind_file_name_handler (filename);
+  /* Likewise for output file name.  */
+  if (NILP (handler))
+    handler = Ffind_file_name_handler (newname);
   if (!NILP (handler))
-    return call3 (handler, Qcopy_file, filename, newname);
+    return call5 (handler, Qcopy_file, filename, newname,
+                 ok_if_already_exists, keep_date);
 
   if (NILP (ok_if_already_exists)
       || XTYPE (ok_if_already_exists) == Lisp_Int)
@@ -1504,7 +1650,8 @@ A prefix arg makes KEEP-TIME non-nil.")
   return Qnil;
 }
 
-DEFUN ("make-directory", Fmake_directory, Smake_directory, 1, 1, "FMake directory: ",
+DEFUN ("make-directory-internal", Fmake_directory_internal,
+       Smake_directory_internal, 1, 1, 0,
   "Create a directory.  One argument, a file name string.")
   (dirname)
      Lisp_Object dirname;
@@ -1515,10 +1662,10 @@ DEFUN ("make-directory", Fmake_directory, Smake_directory, 1, 1, "FMake director
   CHECK_STRING (dirname, 0);
   dirname = Fexpand_file_name (dirname, Qnil);
 
-  handler = find_file_handler (dirname);
+  handler = Ffind_file_name_handler (dirname);
   if (!NILP (handler))
-    return call2 (handler, Qmake_directory, dirname);
+    return call3 (handler, Qmake_directory, dirname, Qnil);
+
   dir = XSTRING (dirname)->data;
 
   if (mkdir (dir, 0777) != 0)
@@ -1539,7 +1686,7 @@ DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete
   dirname = Fexpand_file_name (dirname, Qnil);
   dir = XSTRING (dirname)->data;
 
-  handler = find_file_handler (dirname);
+  handler = Ffind_file_name_handler (dirname);
   if (!NILP (handler))
     return call2 (handler, Qdelete_directory, dirname);
 
@@ -1559,7 +1706,7 @@ If file has multiple names, it continues to exist with the other names.")
   CHECK_STRING (filename, 0);
   filename = Fexpand_file_name (filename, Qnil);
 
-  handler = find_file_handler (filename);
+  handler = Ffind_file_name_handler (filename);
   if (!NILP (handler))
     return call2 (handler, Qdelete_file, filename);
 
@@ -1593,9 +1740,12 @@ This is what happens in interactive use with M-x.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = find_file_handler (filename);
+  handler = Ffind_file_name_handler (filename);
+  if (NILP (handler))
+    handler = Ffind_file_name_handler (newname);
   if (!NILP (handler))
-    return call3 (handler, Qrename_file, filename, newname);
+    return call4 (handler, Qrename_file,
+                 filename, newname, ok_if_already_exists);
 
   if (NILP (ok_if_already_exists)
       || XTYPE (ok_if_already_exists) == Lisp_Int)
@@ -1610,7 +1760,10 @@ This is what happens in interactive use with M-x.")
     {
       if (errno == EXDEV)
        {
-         Fcopy_file (filename, newname, ok_if_already_exists, Qt);
+         Fcopy_file (filename, newname,
+                     /* We have already prompted if it was an integer,
+                        so don't have copy-file prompt again.  */
+                     NILP (ok_if_already_exists) ? Qnil : Qt, Qt);
          Fdelete_file (filename);
        }
       else
@@ -1652,9 +1805,10 @@ This is what happens in interactive use with M-x.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = find_file_handler (filename);
+  handler = Ffind_file_name_handler (filename);
   if (!NILP (handler))
-    return call3 (handler, Qadd_name_to_file, filename, newname);
+    return call4 (handler, Qadd_name_to_file, filename, newname,
+                 ok_if_already_exists);
 
   if (NILP (ok_if_already_exists)
       || XTYPE (ok_if_already_exists) == Lisp_Int)
@@ -1703,9 +1857,10 @@ This happens for interactive use with M-x.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = find_file_handler (filename);
+  handler = Ffind_file_name_handler (filename);
   if (!NILP (handler))
-    return call3 (handler, Qmake_symbolic_link, filename, linkname);
+    return call4 (handler, Qmake_symbolic_link, filename, linkname,
+                 ok_if_already_exists);
 
   if (NILP (ok_if_already_exists)
       || XTYPE (ok_if_already_exists) == Lisp_Int)
@@ -1716,7 +1871,7 @@ This happens for interactive use with M-x.")
       /* If we didn't complain already, silently delete existing file.  */
       if (errno == EEXIST)
        {
-         unlink (XSTRING (filename)->data);
+         unlink (XSTRING (linkname)->data);
          if (0 <= symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
            return Qnil;
        }
@@ -1820,16 +1975,16 @@ See also `file-readable-p' and `file-attributes'.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = find_file_handler (filename);
+  handler = Ffind_file_name_handler (abspath);
   if (!NILP (handler))
-    return call2 (handler, Qfile_exists_p, filename);
+    return call2 (handler, Qfile_exists_p, abspath);
 
   return (access (XSTRING (abspath)->data, 0) >= 0) ? Qt : Qnil;
 }
 
 DEFUN ("file-executable-p", Ffile_executable_p, Sfile_executable_p, 1, 1, 0,
   "Return t if FILENAME can be executed by you.\n\
-For directories this means you can change to that directory.")
+For a directory, this means you can access files in that directory.")
   (filename)
     Lisp_Object filename;
 
@@ -1842,9 +1997,9 @@ For directories this means you can change to that directory.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = find_file_handler (filename);
+  handler = Ffind_file_name_handler (abspath);
   if (!NILP (handler))
-    return call2 (handler, Qfile_executable_p, filename);
+    return call2 (handler, Qfile_executable_p, abspath);
 
   return (access (XSTRING (abspath)->data, 1) >= 0) ? Qt : Qnil;
 }
@@ -1863,9 +2018,9 @@ See also `file-exists-p' and `file-attributes'.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = find_file_handler (filename);
+  handler = Ffind_file_name_handler (abspath);
   if (!NILP (handler))
-    return call2 (handler, Qfile_readable_p, filename);
+    return call2 (handler, Qfile_readable_p, abspath);
 
   return (access (XSTRING (abspath)->data, 4) >= 0) ? Qt : Qnil;
 }
@@ -1889,7 +2044,7 @@ Otherwise returns NIL.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = find_file_handler (filename);
+  handler = Ffind_file_name_handler (filename);
   if (!NILP (handler))
     return call2 (handler, Qfile_symlink_p, filename);
 
@@ -1901,22 +2056,46 @@ Otherwise returns NIL.")
       valsize = readlink (XSTRING (filename)->data, buf, bufsize);
       if (valsize < bufsize) break;
       /* Buffer was not long enough */
-      free (buf);
+      xfree (buf);
       bufsize *= 2;
     }
   if (valsize == -1)
     {
-      free (buf);
+      xfree (buf);
       return Qnil;
     }
   val = make_string (buf, valsize);
-  free (buf);
+  xfree (buf);
   return val;
 #else /* not S_IFLNK */
   return Qnil;
 #endif /* not S_IFLNK */
 }
 
+#ifdef SOLARIS_BROKEN_ACCESS
+/* In Solaris 2.1, the readonly-ness of the filesystem is not
+   considered by the access system call.  This is Sun's bug, but we
+   still have to make Emacs work.  */
+
+#include <sys/statvfs.h>
+
+static int
+ro_fsys (path)
+    char *path;
+{
+    struct statvfs statvfsb;
+
+    if (statvfs(path, &statvfsb))
+      return 1;  /* error from statvfs, be conservative and say not wrtable */
+    else
+      /* Otherwise, fsys is ro if bit is set.  */
+      return statvfsb.f_flag & ST_RDONLY;
+}
+#else
+/* But on every other os, access has already done the right thing.  */
+#define ro_fsys(path) 0
+#endif
+
 /* Having this before file-symlink-p mysteriously caused it to be forgotten
    on the RT/PC.  */
 DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
@@ -1932,18 +2111,21 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = find_file_handler (filename);
+  handler = Ffind_file_name_handler (abspath);
   if (!NILP (handler))
-    return call2 (handler, Qfile_writable_p, filename);
+    return call2 (handler, Qfile_writable_p, abspath);
 
   if (access (XSTRING (abspath)->data, 0) >= 0)
-    return (access (XSTRING (abspath)->data, 2) >= 0) ? Qt : Qnil;
+    return ((access (XSTRING (abspath)->data, 2) >= 0
+            && ! ro_fsys ((char *) XSTRING (abspath)->data))
+           ? Qt : Qnil);
   dir = Ffile_name_directory (abspath);
 #ifdef VMS
   if (!NILP (dir))
     dir = Fdirectory_file_name (dir);
 #endif /* VMS */
-  return (access (!NILP (dir) ? (char *) XSTRING (dir)->data : "", 2) >= 0
+  return ((access (!NILP (dir) ? (char *) XSTRING (dir)->data : "", 2) >= 0
+          && ! ro_fsys ((char *) XSTRING (dir)->data))
          ? Qt : Qnil);
 }
 
@@ -1962,9 +2144,9 @@ if the directory so specified exists and really is a directory.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = find_file_handler (filename);
+  handler = Ffind_file_name_handler (abspath);
   if (!NILP (handler))
-    return call2 (handler, Qfile_directory_p, filename);
+    return call2 (handler, Qfile_directory_p, abspath);
 
   if (stat (XSTRING (abspath)->data, &st) < 0)
     return Qnil;
@@ -1985,7 +2167,7 @@ searchable directory.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = find_file_handler (filename);
+  handler = Ffind_file_name_handler (filename);
   if (!NILP (handler))
     return call2 (handler, Qfile_accessible_directory_p, filename);
 
@@ -2009,9 +2191,9 @@ DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = find_file_handler (filename);
+  handler = Ffind_file_name_handler (abspath);
   if (!NILP (handler))
-    return call2 (handler, Qfile_modes, filename);
+    return call2 (handler, Qfile_modes, abspath);
 
   if (stat (XSTRING (abspath)->data, &st) < 0)
     return Qnil;
@@ -2032,9 +2214,9 @@ Only the 12 low bits of MODE are used.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = find_file_handler (filename);
+  handler = Ffind_file_name_handler (abspath);
   if (!NILP (handler))
-    return call3 (handler, Qset_file_modes, filename, mode);
+    return call3 (handler, Qset_file_modes, abspath, mode);
 
 #ifndef APOLLO
   if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
@@ -2070,35 +2252,33 @@ Only the 12 low bits of MODE are used.")
   return Qnil;
 }
 
-DEFUN ("set-umask", Fset_umask, Sset_umask, 1, 1, 0,
-    "Select which permission bits to disable in newly created files.\n\
-MASK should be an integer; if a permission's bit in MASK is 1,\n\
-subsequently created files will not have that permission enabled.\n\
-Only the low 9 bits are used.\n\
+DEFUN ("set-default-file-modes", Fset_default_file_modes, Sset_default_file_modes, 1, 1, 0,
+    "Set the file permission bits for newly created files.\n\
+The argument MODE should be an integer; only the low 9 bits are used.\n\
 This setting is inherited by subprocesses.")
-  (mask)
-     Lisp_Object mask;
+  (mode)
+     Lisp_Object mode;
 {
-  CHECK_NUMBER (mask, 0);
+  CHECK_NUMBER (mode, 0);
   
-  umask (XINT (mask) & 0777);
+  umask ((~ XINT (mode)) & 0777);
 
   return Qnil;
 }
 
-DEFUN ("umask", Fumask, Sumask, 0, 0, 0,
-    "Return the current umask value.\n\
-The umask value determines which permissions are enabled in newly\n\
-created files.  If a permission's bit in the umask is 1, subsequently\n\
-created files will not have that permission enabled.")
+DEFUN ("default-file-modes", Fdefault_file_modes, Sdefault_file_modes, 0, 0, 0,
+    "Return the default file protection for created files.\n\
+The value is an integer.")
   ()
 {
-  Lisp_Object mask;
+  int realmask;
+  Lisp_Object value;
 
-  XSET (mask, Lisp_Int, umask (0));
-  umask (XINT (mask));
+  realmask = umask (0);
+  umask (realmask);
 
-  return mask;
+  XSET (value, Lisp_Int, (~ realmask) & 0777);
+  return value;
 }
 
 #ifdef unix
@@ -2124,16 +2304,22 @@ otherwise, if FILE2 does not exist, the answer is t.")
   struct stat st;
   int mtime1;
   Lisp_Object handler;
+  struct gcpro gcpro1, gcpro2;
 
   CHECK_STRING (file1, 0);
   CHECK_STRING (file2, 0);
 
+  abspath1 = Qnil;
+  GCPRO2 (abspath1, file2);
   abspath1 = expand_and_dir_to_file (file1, current_buffer->directory);
   abspath2 = expand_and_dir_to_file (file2, current_buffer->directory);
+  UNGCPRO;
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = find_file_handler (abspath1);
+  handler = Ffind_file_name_handler (abspath1);
+  if (NILP (handler))
+    handler = Ffind_file_name_handler (abspath2);
   if (!NILP (handler))
     return call3 (handler, Qfile_newer_than_file_p, abspath1, abspath2);
 
@@ -2149,15 +2335,18 @@ otherwise, if FILE2 does not exist, the answer is t.")
 }
 \f
 DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
-  1, 2, 0,
+  1, 4, 0,
   "Insert contents of file FILENAME after point.\n\
-Returns list of absolute pathname and length of data inserted.\n\
+Returns list of absolute file name and length of data inserted.\n\
 If second argument VISIT is non-nil, the buffer's visited filename\n\
 and last save file modtime are set, and it is marked unmodified.\n\
 If visiting and the file does not exist, visiting is completed\n\
-before the error is signaled.")
-  (filename, visit)
-     Lisp_Object filename, visit;
+before the error is signaled.\n\n\
+The optional third and fourth arguments BEG and END\n\
+specify what portion of the file to insert.\n\
+If VISIT is non-nil, BEG and END must be nil.")
+  (filename, visit, beg, end)
+     Lisp_Object filename, visit, beg, end;
 {
   struct stat st;
   register int fd;
@@ -2166,6 +2355,7 @@ before the error is signaled.")
   int count = specpdl_ptr - specpdl;
   struct gcpro gcpro1;
   Lisp_Object handler, val;
+  int total;
 
   val = Qnil;
 
@@ -2178,10 +2368,10 @@ before the error is signaled.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = find_file_handler (filename);
+  handler = Ffind_file_name_handler (filename);
   if (!NILP (handler))
     {
-      val = call3 (handler, Qinsert_file_contents, filename, visit);
+      val = call5 (handler, Qinsert_file_contents, filename, visit, beg, end);
       st.st_mtime = 0;
       goto handled;
     }
@@ -2220,25 +2410,51 @@ before the error is signaled.")
   if (st.st_size < 0)
     error ("File size is negative");
 
+  if (!NILP (beg) || !NILP (end))
+    if (!NILP (visit))
+      error ("Attempt to visit less than an entire file");
+
+  if (!NILP (beg))
+    CHECK_NUMBER (beg, 0);
+  else
+    XFASTINT (beg) = 0;
+
+  if (!NILP (end))
+    CHECK_NUMBER (end, 0);
+  else
+    {
+      XSETINT (end, st.st_size);
+      if (XINT (end) != st.st_size)
+       error ("maximum buffer size exceeded");
+    }
+
+  total = XINT (end) - XINT (beg);
+
   {
     register Lisp_Object temp;
 
     /* Make sure point-max won't overflow after this insertion.  */
-    XSET (temp, Lisp_Int, st.st_size + Z);
-    if (st.st_size + Z != XINT (temp))
+    XSET (temp, Lisp_Int, total);
+    if (total != XINT (temp))
       error ("maximum buffer size exceeded");
   }
 
-  if (NILP (visit))
+  if (NILP (visit) && total > 0)
     prepare_to_modify_buffer (point, point);
 
   move_gap (point);
-  if (GAP_SIZE < st.st_size)
-    make_gap (st.st_size - GAP_SIZE);
-    
+  if (GAP_SIZE < total)
+    make_gap (total - GAP_SIZE);
+
+  if (XINT (beg) != 0)
+    {
+      if (lseek (fd, XINT (beg), 0) < 0)
+       report_file_error ("Setting file position", Fcons (filename, Qnil));
+    }
+
   while (1)
     {
-      int try = min (st.st_size - inserted, 64 << 10);
+      int try = min (total - inserted, 64 << 10);
       int this;
 
       /* Allow quitting out of the actual I/O.  */
@@ -2261,8 +2477,13 @@ before the error is signaled.")
     }
 
   if (inserted > 0)
-    MODIFF++;
-  record_insert (point, inserted);
+    {
+      record_insert (point, inserted);
+
+      /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
+      offset_intervals (current_buffer, point, inserted);
+      MODIFF++;
+    }
 
   close (fd);
 
@@ -2308,7 +2529,7 @@ before the error is signaled.")
                         Fcons (make_number (inserted),
                                Qnil)));
 }
-
+\f
 DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 5,
   "r\nFWrite region to file: ",
   "Write current region into specified file.\n\
@@ -2319,8 +2540,11 @@ Optional fourth argument APPEND if non-nil means\n\
 Optional fifth argument VISIT if t means\n\
   set the last-save-file-modtime of buffer to this file's modtime\n\
   and mark buffer not modified.\n\
-If VISIT is neither t nor nil, it means do not print\n\
-  the \"Wrote file\" message.\n\
+If VISIT is a string, it is a second file name;\n\
+  the output goes to FILENAME, but the buffer is marked as visiting VISIT.\n\
+  VISIT is also the file name to lock and unlock for clash detection.\n\
+If VISIT is neither t nor nil nor a string,\n\
+  that means do not print the \"Wrote file\" message.\n\
 Kludgy feature: if START is a string, then that string is written\n\
 to the file, instead of any buffer contents, and END is ignored.")
   (start, end, filename, append, visit)
@@ -2337,6 +2561,8 @@ to the file, instead of any buffer contents, and END is ignored.")
   unsigned char *fname = 0;    /* If non-0, original filename (must rename) */
 #endif /* VMS */
   Lisp_Object handler;
+  Lisp_Object visit_file;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
 
   /* Special kludge to simplify auto-saving */
   if (NILP (start))
@@ -2348,43 +2574,43 @@ to the file, instead of any buffer contents, and END is ignored.")
     validate_region (&start, &end);
 
   filename = Fexpand_file_name (filename, Qnil);
-  fn = XSTRING (filename)->data;
+  if (XTYPE (visit) == Lisp_String)
+    visit_file = Fexpand_file_name (visit, Qnil);
+  else
+    visit_file = filename;
+
+  GCPRO4 (start, filename, visit, visit_file);
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = find_file_handler (filename);
+  handler = Ffind_file_name_handler (filename);
 
   if (!NILP (handler))
     {
-      Lisp_Object args[7];
       Lisp_Object val;
-      args[0] = handler;
-      args[1] = Qwrite_region;
-      args[2] = start;
-      args[3] = end;
-      args[4] = filename;
-      args[5] = append;
-      args[6] = visit;
-      val = Ffuncall (7, args);
+      val = call6 (handler, Qwrite_region, start, end,
+                  filename, append, visit);
 
       /* Do this before reporting IO error
         to avoid a "file has changed on disk" warning on
         next attempt to save.  */
-      if (EQ (visit, Qt))
+      if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String)
        {
          current_buffer->modtime = 0;
          current_buffer->save_modified = MODIFF;
          XFASTINT (current_buffer->save_length) = Z - BEG;
-         current_buffer->filename = filename;
+         current_buffer->filename = visit_file;
        }
+      UNGCPRO;
       return val;
     }
 
 #ifdef CLASH_DETECTION
   if (!auto_saving)
-    lock_file (filename);
+    lock_file (visit_file);
 #endif /* CLASH_DETECTION */
 
+  fn = XSTRING (filename)->data;
   desc = -1;
   if (!NILP (append))
     desc = open (fn, O_WRONLY);
@@ -2439,11 +2665,13 @@ to the file, instead of any buffer contents, and END is ignored.")
   desc = creat (fn, auto_saving ? auto_save_mode_bits : 0666);
 #endif /* not VMS */
 
+  UNGCPRO;
+
   if (desc < 0)
     {
 #ifdef CLASH_DETECTION
       save_errno = errno;
-      if (!auto_saving) unlock_file (filename);
+      if (!auto_saving) unlock_file (visit_file);
       errno = save_errno;
 #endif /* CLASH_DETECTION */
       report_file_error ("Opening output file", Fcons (filename, Qnil));
@@ -2455,7 +2683,7 @@ to the file, instead of any buffer contents, and END is ignored.")
     if (lseek (desc, 0, 2) < 0)
       {
 #ifdef CLASH_DETECTION
-       if (!auto_saving) unlock_file (filename);
+       if (!auto_saving) unlock_file (visit_file);
 #endif /* CLASH_DETECTION */
        report_file_error ("Lseek error", Fcons (filename, Qnil));
       }
@@ -2511,15 +2739,13 @@ to the file, instead of any buffer contents, and END is ignored.")
 
   immediate_quit = 0;
 
-#ifndef USG
-#ifndef VMS
-#ifndef BSD4_1
+#ifdef HAVE_FSYNC
   /* Note fsync appears to change the modtime on BSD4.2 (both vax and sun).
      Disk full in NFS may be reported here.  */
-  if (fsync (desc) < 0)
+  /* mib says that closing the file will try to write as fast as NFS can do
+     it, and that means the fsync here is not crucial for autosave files.  */
+  if (!auto_saving && fsync (desc) < 0)
     failure = 1, save_errno = errno;
-#endif
-#endif
 #endif
 
   /* Spurious "file has changed on disk" warnings have been 
@@ -2563,29 +2789,29 @@ to the file, instead of any buffer contents, and END is ignored.")
 
 #ifdef CLASH_DETECTION
   if (!auto_saving)
-    unlock_file (filename);
+    unlock_file (visit_file);
 #endif /* CLASH_DETECTION */
 
   /* Do this before reporting IO error
      to avoid a "file has changed on disk" warning on
      next attempt to save.  */
-  if (EQ (visit, Qt))
+  if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String)
     current_buffer->modtime = st.st_mtime;
 
   if (failure)
     error ("IO error writing %s: %s", fn, err_str (save_errno));
 
-  if (EQ (visit, Qt))
+  if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String)
     {
       current_buffer->save_modified = MODIFF;
       XFASTINT (current_buffer->save_length) = Z - BEG;
-      current_buffer->filename = filename;
+      current_buffer->filename = visit_file;
     }
   else if (!NILP (visit))
     return Qnil;
 
   if (!auto_saving)
-    message ("Wrote %s", fn);
+    message ("Wrote %s", XSTRING (visit_file)->data);
 
   return Qnil;
 }
@@ -2643,9 +2869,9 @@ This means that the file has not been changed since it was visited or saved.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = find_file_handler (b->filename);
+  handler = Ffind_file_name_handler (b->filename);
   if (!NILP (handler))
-    return call2 (handler, Qverify_visited_file_modtime, b->filename);
+    return call2 (handler, Qverify_visited_file_modtime, buf);
 
   if (stat (XSTRING (b->filename)->data, &st) < 0)
     {
@@ -2675,27 +2901,46 @@ Next attempt to save will certainly not complain of a discrepancy.")
   return Qnil;
 }
 
+DEFUN ("visited-file-modtime", Fvisited_file_modtime,
+  Svisited_file_modtime, 0, 0, 0,
+  "Return the current buffer's recorded visited file modification time.\n\
+The value is a list of the form (HIGH . LOW), like the time values\n\
+that `file-attributes' returns.")
+  ()
+{
+  return long_to_cons (current_buffer->modtime);
+}
+
 DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
-  Sset_visited_file_modtime, 0, 0, 0,
+  Sset_visited_file_modtime, 0, 1, 0,
   "Update buffer's recorded modification time from the visited file's time.\n\
 Useful if the buffer was not read from the file normally\n\
-or if the file itself has been changed for some known benign reason.")
-  ()
+or if the file itself has been changed for some known benign reason.\n\
+An argument specifies the modification time value to use\n\
+\(instead of that of the visited file), in the form of a list\n\
+\(HIGH . LOW) or (HIGH LOW).")
+  (time_list)
+     Lisp_Object time_list;
 {
-  register Lisp_Object filename;
-  struct stat st;
-  Lisp_Object handler;
-
-  filename = Fexpand_file_name (current_buffer->filename, Qnil);
-
-  /* If the file name has special constructs in it,
-     call the corresponding file handler.  */
-  handler = find_file_handler (filename);
-  if (!NILP (handler))
-    current_buffer->modtime = 0;
-  
-  else if (stat (XSTRING (filename)->data, &st) >= 0)
-    current_buffer->modtime = st.st_mtime;
+  if (!NILP (time_list))
+    current_buffer->modtime = cons_to_long (time_list);
+  else
+    {
+      register Lisp_Object filename;
+      struct stat st;
+      Lisp_Object handler;
+
+      filename = Fexpand_file_name (current_buffer->filename, Qnil);
+
+      /* If the file name has special constructs in it,
+        call the corresponding file handler.  */
+      handler = Ffind_file_name_handler (filename);
+      if (!NILP (handler))
+       /* The handler can find the file name the same way we did.  */
+       return call2 (handler, Qset_visited_file_modtime, Qnil);
+      else if (stat (XSTRING (filename)->data, &st) >= 0)
+       current_buffer->modtime = st.st_mtime;
+    }
 
   return Qnil;
 }
@@ -2743,74 +2988,97 @@ so that your editing is not lost if the system crashes.\n\
 This file is not the file you visited; that changes only when you save.\n\n\
 Non-nil first argument means do not print any message if successful.\n\
 Non-nil second argument means save only current buffer.")
-  (nomsg)
-     Lisp_Object nomsg;
+  (no_message, current_only)
+     Lisp_Object no_message, current_only;
 {
   struct buffer *old = current_buffer, *b;
   Lisp_Object tail, buf;
   int auto_saved = 0;
   char *omessage = echo_area_glyphs;
-  extern minibuf_level;
+  extern int minibuf_level;
+  int do_handled_files;
+  Lisp_Object oquit;
+
+  /* Ordinarily don't quit within this function,
+     but don't make it impossible to quit (in case we get hung in I/O).  */
+  oquit = Vquit_flag;
+  Vquit_flag = Qnil;
 
   /* No GCPRO needed, because (when it matters) all Lisp_Object variables
      point to non-strings reached from Vbuffer_alist.  */
 
   auto_saving = 1;
   if (minibuf_level)
-    nomsg = Qt;
+    no_message = Qt;
 
   /* Vrun_hooks is nil before emacs is dumped, and inc-vers.el will
      eventually call do-auto-save, so don't err here in that case. */
   if (!NILP (Vrun_hooks))
     call1 (Vrun_hooks, intern ("auto-save-hook"));
 
-  for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons;
-       tail = XCONS (tail)->cdr)
-    {
-      buf = XCONS (XCONS (tail)->car)->cdr;
-      b = XBUFFER (buf);
-      /* Check for auto save enabled
-        and file changed since last auto save
-        and file changed since last real save.  */
-      if (XTYPE (b->auto_save_file_name) == Lisp_String
-         && b->save_modified < BUF_MODIFF (b)
-         && b->auto_save_modified < BUF_MODIFF (b))
-       {
-         if ((XFASTINT (b->save_length) * 10
-              > (BUF_Z (b) - BUF_BEG (b)) * 13)
-             /* A short file is likely to change a large fraction;
-                spare the user annoying messages.  */
-             && XFASTINT (b->save_length) > 5000
-             /* These messages are frequent and annoying for `*mail*'.  */
-             && !EQ (b->filename, Qnil))
-           {
-             /* It has shrunk too much; turn off auto-saving here.  */
-             message ("Buffer %s has shrunk a lot; auto save turned off there",
-                      XSTRING (b->name)->data);
-             /* User can reenable saving with M-x auto-save.  */
-             b->auto_save_file_name = Qnil;
-             /* Prevent warning from repeating if user does so.  */
-             XFASTINT (b->save_length) = 0;
-             Fsleep_for (make_number (1));
-             continue;
-           }
-         set_buffer_internal (b);
-         if (!auto_saved && NILP (nomsg))
-           message1 ("Auto-saving...");
-         internal_condition_case (auto_save_1, Qt, auto_save_error);
-         auto_saved++;
-         b->auto_save_modified = BUF_MODIFF (b);
-         XFASTINT (current_buffer->save_length) = Z - BEG;
-         set_buffer_internal (old);
-       }
-    }
+  /* First, save all files which don't have handlers.  If Emacs is
+     crashing, the handlers may tweak what is causing Emacs to crash
+     in the first place, and it would be a shame if Emacs failed to
+     autosave perfectly ordinary files because it couldn't handle some
+     ange-ftp'd file.  */
+  for (do_handled_files = 0; do_handled_files < 2; do_handled_files++)
+    for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons;
+        tail = XCONS (tail)->cdr)
+      {
+       buf = XCONS (XCONS (tail)->car)->cdr;
+       b = XBUFFER (buf);
+
+       if (!NILP (current_only)
+           && b != current_buffer)
+         continue;
+      
+       /* Check for auto save enabled
+          and file changed since last auto save
+          and file changed since last real save.  */
+       if (XTYPE (b->auto_save_file_name) == Lisp_String
+           && b->save_modified < BUF_MODIFF (b)
+           && b->auto_save_modified < BUF_MODIFF (b)
+           && (do_handled_files
+               || NILP (Ffind_file_name_handler (b->auto_save_file_name))))
+         {
+           if ((XFASTINT (b->save_length) * 10
+                > (BUF_Z (b) - BUF_BEG (b)) * 13)
+               /* A short file is likely to change a large fraction;
+                  spare the user annoying messages.  */
+               && XFASTINT (b->save_length) > 5000
+               /* These messages are frequent and annoying for `*mail*'.  */
+               && !EQ (b->filename, Qnil)
+               && NILP (no_message))
+             {
+               /* It has shrunk too much; turn off auto-saving here.  */
+               message ("Buffer %s has shrunk a lot; auto save turned off there",
+                        XSTRING (b->name)->data);
+               /* User can reenable saving with M-x auto-save.  */
+               b->auto_save_file_name = Qnil;
+               /* Prevent warning from repeating if user does so.  */
+               XFASTINT (b->save_length) = 0;
+               Fsleep_for (make_number (1), Qnil);
+               continue;
+             }
+           set_buffer_internal (b);
+           if (!auto_saved && NILP (no_message))
+             message1 ("Auto-saving...");
+           internal_condition_case (auto_save_1, Qt, auto_save_error);
+           auto_saved++;
+           b->auto_save_modified = BUF_MODIFF (b);
+           XFASTINT (current_buffer->save_length) = Z - BEG;
+           set_buffer_internal (old);
+         }
+      }
 
-  if (auto_saved)
-    record_auto_save ();
+  /* Prevent another auto save till enough input events come in.  */
+  record_auto_save ();
 
-  if (auto_saved && NILP (nomsg))
+  if (auto_saved && NILP (no_message))
     message1 (omessage ? omessage : "Auto-saving...done");
 
+  Vquit_flag = oquit;
+
   auto_saving = 0;
   return Qnil;
 }
@@ -2846,36 +3114,46 @@ DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_inte
      lambda for verify final value */
 {
   Lisp_Object name, specdir, realdir, val, orig_string;
+  int changed;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+
+  realdir = dir;
+  name = string;
+  orig_string = Qnil;
+  specdir = Qnil;
+  changed = 0;
+  /* No need to protect ACTION--we only compare it with t and nil.  */
+  GCPRO4 (string, realdir, name, specdir);
 
   if (XSTRING (string)->size == 0)
     {
-      orig_string = Qnil; 
-      name = string;
-      realdir = dir;
       if (EQ (action, Qlambda))
-       return Qnil;
+       {
+         UNGCPRO;
+         return Qnil;
+       }
     }
   else
     {
       orig_string = string;
       string = Fsubstitute_in_file_name (string);
+      changed = NILP (Fstring_equal (string, orig_string));
       name = Ffile_name_nondirectory (string);
-      realdir = Ffile_name_directory (string);
-      if (NILP (realdir))
-       realdir = dir;
-      else
-       realdir = Fexpand_file_name (realdir, dir);
+      val = Ffile_name_directory (string);
+      if (! NILP (val))
+       realdir = Fexpand_file_name (val, realdir);
     }
 
   if (NILP (action))
     {
       specdir = Ffile_name_directory (string);
       val = Ffile_name_completion (name, realdir);
+      UNGCPRO;
       if (XTYPE (val) != Lisp_String)
        {
-         if (NILP (Fstring_equal (string, orig_string)))
+         if (changed)
            return string;
-         return (val);
+         return val;
        }
 
       if (!NILP (specdir))
@@ -2907,8 +3185,9 @@ DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_inte
          }
       }
 #endif /* Not VMS */
-      return (val);
+      return val;
     }
+  UNGCPRO;
 
   if (EQ (action, Qt))
     return Ffile_name_all_completions (name, realdir);
@@ -2934,7 +3213,7 @@ DIR defaults to current buffer's directory default.")
   (prompt, dir, defalt, mustmatch, initial)
      Lisp_Object prompt, dir, defalt, mustmatch, initial;
 {
-  Lisp_Object val, insdef, tem, backup_n;
+  Lisp_Object val, insdef, insdef1, tem;
   struct gcpro gcpro1, gcpro2;
   register char *homedir;
   int count;
@@ -2959,23 +3238,20 @@ DIR defaults to current buffer's directory default.")
   if (insert_default_directory)
     {
       insdef = dir;
+      insdef1 = dir;
       if (!NILP (initial))
        {
-         Lisp_Object args[2];
+         Lisp_Object args[2], pos;
 
          args[0] = insdef;
          args[1] = initial;
          insdef = Fconcat (2, args);
-         backup_n = make_number (- (XSTRING (initial)->size));
+         pos = make_number (XSTRING (dir)->size);
+         insdef1 = Fcons (insdef, pos);
        }
-      else
-       backup_n = Qnil;
     }
   else
-    {
-      insdef = build_string ("");
-      backup_n = Qnil;
-    }
+    insdef = Qnil, insdef1 = Qnil;
 
 #ifdef VMS
   count = specpdl_ptr - specpdl;
@@ -2984,8 +3260,8 @@ DIR defaults to current buffer's directory default.")
 
   GCPRO2 (insdef, defalt);
   val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
-                         dir, mustmatch,
-                         insert_default_directory ? insdef : Qnil, backup_n);
+                         dir, mustmatch, insdef1,
+                         Qfile_name_history);
 
 #ifdef VMS
   unbind_to (count, Qnil);
@@ -2997,6 +3273,8 @@ DIR defaults to current buffer's directory default.")
   tem = Fstring_equal (val, insdef);
   if (!NILP (tem) && !NILP (defalt))
     return defalt;
+  if (XSTRING (val)->size == 0 && NILP (insdef))
+    return defalt;
   return Fsubstitute_in_file_name (val);
 }
 
@@ -3050,7 +3328,8 @@ DIR defaults to current buffer's directory default.")
   GCPRO2 (insdef, defalt);
   val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
                          dir, mustmatch,
-                         insert_default_directory ? insdef : Qnil, Qnil);
+                         insert_default_directory ? insdef : Qnil,
+                         Qfile_name_history);
 
 #ifdef VMS
   unbind_to (count, Qnil);
@@ -3068,6 +3347,12 @@ DIR defaults to current buffer's directory default.")
 \f
 syms_of_fileio ()
 {
+  Qexpand_file_name = intern ("expand-file-name");
+  Qdirectory_file_name = intern ("directory-file-name");
+  Qfile_name_directory = intern ("file-name-directory");
+  Qfile_name_nondirectory = intern ("file-name-nondirectory");
+  Qunhandled_file_name_directory = intern ("unhandled-file-name-directory");
+  Qfile_name_as_directory = intern ("file-name-as-directory");
   Qcopy_file = intern ("copy-file");
   Qmake_directory = intern ("make-directory");
   Qdelete_directory = intern ("delete-directory");
@@ -3088,6 +3373,38 @@ syms_of_fileio ()
   Qinsert_file_contents = intern ("insert-file-contents");
   Qwrite_region = intern ("write-region");
   Qverify_visited_file_modtime = intern ("verify-visited-file-modtime");
+  Qset_visited_file_modtime = intern ("set-visited-file-modtime");
+
+  staticpro (&Qexpand_file_name);
+  staticpro (&Qdirectory_file_name);
+  staticpro (&Qfile_name_directory);
+  staticpro (&Qfile_name_nondirectory);
+  staticpro (&Qunhandled_file_name_directory);
+  staticpro (&Qfile_name_as_directory);
+  staticpro (&Qcopy_file);
+  staticpro (&Qmake_directory);
+  staticpro (&Qdelete_directory);
+  staticpro (&Qdelete_file);
+  staticpro (&Qrename_file);
+  staticpro (&Qadd_name_to_file);
+  staticpro (&Qmake_symbolic_link);
+  staticpro (&Qfile_exists_p);
+  staticpro (&Qfile_executable_p);
+  staticpro (&Qfile_readable_p);
+  staticpro (&Qfile_symlink_p);
+  staticpro (&Qfile_writable_p);
+  staticpro (&Qfile_directory_p);
+  staticpro (&Qfile_accessible_directory_p);
+  staticpro (&Qfile_modes);
+  staticpro (&Qset_file_modes);
+  staticpro (&Qfile_newer_than_file_p);
+  staticpro (&Qinsert_file_contents);
+  staticpro (&Qwrite_region);
+  staticpro (&Qverify_visited_file_modtime);
+
+  Qfile_name_history = intern ("file-name-history");
+  Fset (Qfile_name_history, Qnil);
+  staticpro (&Qfile_name_history);
 
   Qfile_error = intern ("file-error");
   staticpro (&Qfile_error);
@@ -3124,16 +3441,22 @@ to be handled; the remaining arguments are the arguments that were\n\
 passed to that primitive.  For example, if you do\n\
     (file-exists-p FILENAME)\n\
 and FILENAME is handled by HANDLER, then HANDLER is called like this:\n\
-    (funcall HANDLER FILENAME)");
+    (funcall HANDLER 'file-exists-p FILENAME)\n\
+The function `find-file-name-handler' checks this list for a handler\n\
+for its argument.");
+  Vfile_name_handler_alist = Qnil;
+
+  defsubr (&Sfind_file_name_handler);
   defsubr (&Sfile_name_directory);
   defsubr (&Sfile_name_nondirectory);
+  defsubr (&Sunhandled_file_name_directory);
   defsubr (&Sfile_name_as_directory);
   defsubr (&Sdirectory_file_name);
   defsubr (&Smake_temp_name);
   defsubr (&Sexpand_file_name);
   defsubr (&Ssubstitute_in_file_name);
   defsubr (&Scopy_file);
-  defsubr (&Smake_directory);
+  defsubr (&Smake_directory_internal);
   defsubr (&Sdelete_directory);
   defsubr (&Sdelete_file);
   defsubr (&Srename_file);
@@ -3157,13 +3480,14 @@ and FILENAME is handled by HANDLER, then HANDLER is called like this:\n\
   defsubr (&Sfile_accessible_directory_p);
   defsubr (&Sfile_modes);
   defsubr (&Sset_file_modes);
-  defsubr (&Sset_umask);
-  defsubr (&Sumask);
+  defsubr (&Sset_default_file_modes);
+  defsubr (&Sdefault_file_modes);
   defsubr (&Sfile_newer_than_file_p);
   defsubr (&Sinsert_file_contents);
   defsubr (&Swrite_region);
   defsubr (&Sverify_visited_file_modtime);
   defsubr (&Sclear_visited_file_modtime);
+  defsubr (&Svisited_file_modtime);
   defsubr (&Sset_visited_file_modtime);
   defsubr (&Sdo_auto_save);
   defsubr (&Sset_buffer_auto_saved);
@@ -3172,5 +3496,7 @@ and FILENAME is handled by HANDLER, then HANDLER is called like this:\n\
   defsubr (&Sread_file_name_internal);
   defsubr (&Sread_file_name);
 
+#ifdef unix
   defsubr (&Sunix_sync);
+#endif
 }