Convert (most) functions in src to standard C.
[bpt/emacs.git] / src / fileio.c
index 2544bd5..c81dc67 100644 (file)
@@ -1,7 +1,7 @@
 /* File IO for GNU Emacs.
    Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1996,
                  1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-                 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+                 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -28,6 +28,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <setjmp.h>
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
@@ -50,20 +51,11 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #endif
 
 #include <ctype.h>
-
-#ifdef VMS
-#include "vmsdir.h"
-#include <perror.h>
-#include <stddef.h>
-#include <string.h>
-#endif
-
 #include <errno.h>
 
-#ifndef vax11c
-#ifndef USE_CRT_DLL
-extern int errno;
-#endif
+#ifdef HAVE_LIBSELINUX
+#include <selinux/selinux.h>
+#include <selinux/context.h>
 #endif
 
 #include "lisp.h"
@@ -86,17 +78,11 @@ extern int errno;
 #ifdef MSDOS
 #include "msdos.h"
 #include <sys/param.h>
-#if __DJGPP__ >= 2
 #include <fcntl.h>
 #include <string.h>
 #endif
-#endif
 
 #ifdef DOS_NT
-#define CORRECT_DIR_SEPS(s) \
-  do { if ('/' == DIRECTORY_SEP) dostounix_filename (s); \
-       else unixtodos_filename (s); \
-  } while (0)
 /* On Windows, drive letters must be alphabetic - on DOS, the Netware
    redirector allows the six letters between 'Z' and 'a' as well. */
 #ifdef MSDOS
@@ -111,13 +97,6 @@ extern int errno;
 #define DRIVE_LETTER(x) (tolower (x))
 #endif
 
-#ifdef VMS
-#include <file.h>
-#include <rmsdef.h>
-#include <fab.h>
-#include <nam.h>
-#endif
-
 #include "systime.h"
 
 #ifdef HPUX
@@ -192,17 +171,24 @@ Lisp_Object Qafter_insert_file_set_coding;
 /* Functions to be called to create text property annotations for file.  */
 Lisp_Object Vwrite_region_annotate_functions;
 Lisp_Object Qwrite_region_annotate_functions;
+Lisp_Object Vwrite_region_post_annotation_function;
 
 /* During build_annotations, each time an annotation function is called,
    this holds the annotations made by the previous functions.  */
 Lisp_Object Vwrite_region_annotations_so_far;
 
+/* Each time an annotation function changes the buffer, the new buffer
+   is added here.  */
+Lisp_Object Vwrite_region_annotation_buffers;
+
 /* File name in which we write a list of all our auto save files.  */
 Lisp_Object Vauto_save_list_file_name;
 
-/* On VMS, nonzero means write new files with record format stmlf.
-   Zero means use var format.  */
-int vms_stmlf_recfm;
+/* Whether or not files are auto-saved into themselves.  */
+Lisp_Object Vauto_save_visited_file_name;
+
+/* Whether or not to continue auto-saving after a large deletion.  */
+Lisp_Object Vauto_save_include_big_deletions;
 
 /* On NT, specifies the directory separator character, used (eg.) when
    expanding file names.  This can be bound to / or \. */
@@ -214,12 +200,20 @@ int write_region_inhibit_fsync;
 #endif
 
 /* Non-zero means call move-file-to-trash in Fdelete_file or
-   Fdelete_directory.  */
+   Fdelete_directory_internal.  */
 int delete_by_moving_to_trash;
 
+Lisp_Object Qdelete_by_moving_to_trash;
+
 /* Lisp function for moving files to trash.  */
 Lisp_Object Qmove_file_to_trash;
 
+/* Lisp function for recursively copying directories.  */
+Lisp_Object Qcopy_directory;
+
+/* Lisp function for recursively deleting directories.  */
+Lisp_Object Qdelete_directory;
+
 extern Lisp_Object Vuser_login_name;
 
 #ifdef WINDOWSNT
@@ -230,8 +224,6 @@ extern int minibuf_level;
 
 extern int minibuffer_auto_raise;
 
-extern int history_delete_duplicates;
-
 /* These variables describe handlers that have "already" had a chance
    to handle the current operation.
 
@@ -248,15 +240,13 @@ Lisp_Object Qfile_name_history;
 
 Lisp_Object Qcar_less_than_car;
 
-static int a_write P_ ((int, Lisp_Object, int, int,
-                       Lisp_Object *, struct coding_system *));
-static int e_write P_ ((int, Lisp_Object, int, int, struct coding_system *));
+static int a_write (int, Lisp_Object, int, int,
+                    Lisp_Object *, struct coding_system *);
+static int e_write (int, Lisp_Object, int, int, struct coding_system *);
 
 \f
 void
-report_file_error (string, data)
-     const char *string;
-     Lisp_Object data;
+report_file_error (const char *string, Lisp_Object data)
 {
   Lisp_Object errstring;
   int errorno = errno;
@@ -276,9 +266,17 @@ report_file_error (string, data)
        break;
       default:
        /* System error messages are capitalized.  Downcase the initial
-          unless it is followed by a slash.  */
-       if (SREF (errstring, 1) != '/')
-         SSET (errstring, 0, DOWNCASE (SREF (errstring, 0)));
+          unless it is followed by a slash.  (The slash case caters to
+          error messages that begin with "I/O" or, in German, "E/A".)  */
+       if (STRING_MULTIBYTE (errstring)
+           && ! EQ (Faref (errstring, make_number (1)), make_number ('/')))
+         {
+           int c;
+
+           str = (char *) SDATA (errstring);
+           c = STRING_CHAR (str);
+           Faset (errstring, make_number (0), make_number (DOWNCASE (c)));
+         }
 
        xsignal (Qfile_error,
                 Fcons (build_string (string), Fcons (errstring, data)));
@@ -286,8 +284,7 @@ report_file_error (string, data)
 }
 
 Lisp_Object
-close_file_unwind (fd)
-     Lisp_Object fd;
+close_file_unwind (Lisp_Object fd)
 {
   emacs_close (XFASTINT (fd));
   return Qnil;
@@ -295,9 +292,8 @@ close_file_unwind (fd)
 
 /* Restore point, having saved it as a marker.  */
 
-static Lisp_Object
-restore_point_unwind (location)
-     Lisp_Object location;
+Lisp_Object
+restore_point_unwind (Lisp_Object location)
 {
   Fgoto_char (location);
   Fset_marker (location, Qnil, Qnil);
@@ -315,7 +311,7 @@ Lisp_Object Qfile_name_as_directory;
 Lisp_Object Qcopy_file;
 Lisp_Object Qmake_directory_internal;
 Lisp_Object Qmake_directory;
-Lisp_Object Qdelete_directory;
+Lisp_Object Qdelete_directory_internal;
 Lisp_Object Qdelete_file;
 Lisp_Object Qrename_file;
 Lisp_Object Qadd_name_to_file;
@@ -332,6 +328,8 @@ Lisp_Object Qfile_accessible_directory_p;
 Lisp_Object Qfile_modes;
 Lisp_Object Qset_file_modes;
 Lisp_Object Qset_file_times;
+Lisp_Object Qfile_selinux_context;
+Lisp_Object Qset_file_selinux_context;
 Lisp_Object Qfile_newer_than_file_p;
 Lisp_Object Qinsert_file_contents;
 Lisp_Object Qwrite_region;
@@ -404,8 +402,7 @@ DEFUN ("file-name-directory", Ffile_name_directory, Sfile_name_directory,
        doc: /* Return the directory component in file name FILENAME.
 Return nil if FILENAME does not include a directory.
 Otherwise return a directory name.
-Given a Unix syntax file name, returns a string ending in slash;
-on VMS, perhaps instead a string ending in `:', `]' or `>'.  */)
+Given a Unix syntax file name, returns a string ending in slash.  */)
      (filename)
      Lisp_Object filename;
 {
@@ -426,16 +423,15 @@ on VMS, perhaps instead a string ending in `:', `]' or `>'.  */)
     return call2 (handler, Qfile_name_directory, filename);
 
   filename = FILE_SYSTEM_CASE (filename);
-  beg = SDATA (filename);
 #ifdef DOS_NT
-  beg = strcpy (alloca (strlen (beg) + 1), beg);
+  beg = (unsigned char *) alloca (SBYTES (filename) + 1);
+  bcopy (SDATA (filename), beg, SBYTES (filename) + 1);
+#else
+  beg = SDATA (filename);
 #endif
   p = beg + SBYTES (filename);
 
   while (p != beg && !IS_DIRECTORY_SEP (p[-1])
-#ifdef VMS
-        && p[-1] != ':' && p[-1] != ']' && p[-1] != '>'
-#endif /* VMS */
 #ifdef DOS_NT
         /* only recognise drive specifier at the beginning */
         && !(p[-1] == ':'
@@ -470,7 +466,7 @@ on VMS, perhaps instead a string ending in `:', `]' or `>'.  */)
          p = beg + strlen (beg);
        }
     }
-  CORRECT_DIR_SEPS (beg);
+  dostounix_filename (beg);
 #endif /* DOS_NT */
 
   return make_specified_string (beg, -1, p - beg, STRING_MULTIBYTE (filename));
@@ -500,9 +496,6 @@ or the entire name if it contains no slash.  */)
   end = p = beg + SBYTES (filename);
 
   while (p != beg && !IS_DIRECTORY_SEP (p[-1])
-#ifdef VMS
-        && p[-1] != ':' && p[-1] != ']' && p[-1] != '>'
-#endif /* VMS */
 #ifdef DOS_NT
         /* only recognise drive specifier at beginning */
         && !(p[-1] == ':'
@@ -542,8 +535,7 @@ get a current directory to run processes in.  */)
 
 \f
 char *
-file_name_as_directory (out, in)
-     char *out, *in;
+file_name_as_directory (char *out, char *in)
 {
   int size = strlen (in) - 1;
 
@@ -557,75 +549,15 @@ file_name_as_directory (out, in)
       return out;
     }
 
-#ifdef VMS
-  /* Is it already a directory string? */
-  if (in[size] == ':' || in[size] == ']' || in[size] == '>')
-    return out;
-  /* Is it a VMS directory file name?  If so, hack VMS syntax.  */
-  else if (! index (in, '/')
-          && ((size > 3 && ! strcmp (&in[size - 3], ".DIR"))
-              || (size > 3 && ! strcmp (&in[size - 3], ".dir"))
-              || (size > 5 && (! strncmp (&in[size - 5], ".DIR", 4)
-                               || ! strncmp (&in[size - 5], ".dir", 4))
-                  && (in[size - 1] == '.' || in[size - 1] == ';')
-                  && in[size] == '1')))
-    {
-      register char *p, *dot;
-      char brack;
-
-      /* x.dir -> [.x]
-        dir:x.dir --> dir:[x]
-        dir:[x]y.dir --> dir:[x.y] */
-      p = in + size;
-      while (p != in && *p != ':' && *p != '>' && *p != ']') p--;
-      if (p != in)
-       {
-         strncpy (out, in, p - in);
-         out[p - in] = '\0';
-         if (*p == ':')
-           {
-             brack = ']';
-             strcat (out, ":[");
-           }
-         else
-           {
-             brack = *p;
-             strcat (out, ".");
-           }
-         p++;
-       }
-      else
-       {
-         brack = ']';
-         strcpy (out, "[.");
-       }
-      dot = index (p, '.');
-      if (dot)
-       {
-         /* blindly remove any extension */
-         size = strlen (out) + (dot - p);
-         strncat (out, p, dot - p);
-       }
-      else
-       {
-         strcat (out, p);
-         size = strlen (out);
-       }
-      out[size++] = brack;
-      out[size] = '\0';
-    }
-#else /* not VMS */
   /* For Unix syntax, Append a slash if necessary */
   if (!IS_DIRECTORY_SEP (out[size]))
     {
-      /* Cannot use DIRECTORY_SEP, which could have any value */
-      out[size + 1] = '/';
+      out[size + 1] = DIRECTORY_SEP;
       out[size + 2] = '\0';
     }
 #ifdef DOS_NT
-  CORRECT_DIR_SEPS (out);
+  dostounix_filename (out);
 #endif
-#endif /* not VMS */
   return out;
 }
 
@@ -636,8 +568,7 @@ This operation exists because a directory is also a file, but its name as
 a directory is different from its name as a file.
 The result can be used as the value of `default-directory'
 or passed as second argument to `expand-file-name'.
-For a Unix-syntax file name, just appends a slash.
-On VMS, converts \"[X]FOO.DIR\" to \"[X.FOO]\", etc.  */)
+For a Unix-syntax file name, just appends a slash.  */)
      (file)
      Lisp_Object file;
 {
@@ -662,143 +593,18 @@ On VMS, converts \"[X]FOO.DIR\" to \"[X.FOO]\", etc.  */)
 \f
 /*
  * Convert from directory name to filename.
- * On VMS:
- *       xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
- *       xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
  * 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.
  */
 
 int
-directory_file_name (src, dst)
-     char *src, *dst;
+directory_file_name (char *src, char *dst)
 {
   long slen;
-#ifdef VMS
-  long rlen;
-  char * ptr, * rptr;
-  char bracket;
-  struct FAB fab = cc$rms_fab;
-  struct NAM nam = cc$rms_nam;
-  char esa[NAM$C_MAXRSS];
-#endif /* VMS */
 
   slen = strlen (src);
-#ifdef VMS
-  if (! index (src, '/')
-      && (src[slen - 1] == ']'
-         || src[slen - 1] == ':'
-         || src[slen - 1] == '>'))
-    {
-      /* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */
-      fab.fab$l_fna = src;
-      fab.fab$b_fns = slen;
-      fab.fab$l_nam = &nam;
-      fab.fab$l_fop = FAB$M_NAM;
-
-      nam.nam$l_esa = esa;
-      nam.nam$b_ess = sizeof esa;
-      nam.nam$b_nop |= NAM$M_SYNCHK;
-
-      /* We call SYS$PARSE to handle such things as [--] for us. */
-      if (SYS$PARSE (&fab, 0, 0) == RMS$_NORMAL)
-       {
-         slen = nam.nam$b_esl;
-         if (esa[slen - 1] == ';' && esa[slen - 2] == '.')
-           slen -= 2;
-         esa[slen] = '\0';
-         src = esa;
-       }
-      if (src[slen - 1] != ']' && src[slen - 1] != '>')
-       {
-         /* what about when we have logical_name:???? */
-         if (src[slen - 1] == ':')
-           {                   /* Xlate logical name and see what we get */
-             ptr = strcpy (dst, src); /* upper case for getenv */
-             while (*ptr)
-               {
-                 if ('a' <= *ptr && *ptr <= 'z')
-                   *ptr -= 040;
-                 ptr++;
-               }
-             dst[slen - 1] = 0;        /* remove colon */
-             if (!(src = egetenv (dst)))
-               return 0;
-             /* should we jump to the beginning of this procedure?
-                Good points: allows us to use logical names that xlate
-                to Unix names,
-                Bad points: can be a problem if we just translated to a device
-                name...
-                For now, I'll punt and always expect VMS names, and hope for
-                the best! */
-             slen = strlen (src);
-             if (src[slen - 1] != ']' && src[slen - 1] != '>')
-               { /* no recursion here! */
-                 strcpy (dst, src);
-                 return 0;
-               }
-           }
-         else
-           {           /* not a directory spec */
-             strcpy (dst, src);
-             return 0;
-           }
-       }
-      bracket = src[slen - 1];
-
-      /* If bracket is ']' or '>', bracket - 2 is the corresponding
-        opening bracket.  */
-      ptr = index (src, bracket - 2);
-      if (ptr == 0)
-       { /* no opening bracket */
-         strcpy (dst, src);
-         return 0;
-       }
-      if (!(rptr = rindex (src, '.')))
-       rptr = ptr;
-      slen = rptr - src;
-      strncpy (dst, src, slen);
-      dst[slen] = '\0';
-      if (*rptr == '.')
-       {
-         dst[slen++] = bracket;
-         dst[slen] = '\0';
-       }
-      else
-       {
-         /* If we have the top-level of a rooted directory (i.e. xx:[000000]),
-            then translate the device and recurse. */
-         if (dst[slen - 1] == ':'
-             && dst[slen - 2] != ':'   /* skip decnet nodes */
-             && strcmp (src + slen, "[000000]") == 0)
-           {
-             dst[slen - 1] = '\0';
-             if ((ptr = egetenv (dst))
-                 && (rlen = strlen (ptr) - 1) > 0
-                 && (ptr[rlen] == ']' || ptr[rlen] == '>')
-                 && ptr[rlen - 1] == '.')
-               {
-                 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] = ':';
-           }
-         strcat (dst, "[000000]");
-         slen += 8;
-       }
-      rptr++;
-      rlen = strlen (rptr) - 1;
-      strncat (dst, rptr, rlen);
-      dst[slen + rlen] = '\0';
-      strcat (dst, ".DIR.1");
-      return 1;
-    }
-#endif /* VMS */
+
   /* Process as Unix format: just remove any final slash.
      But leave "/" unchanged; do not change it to "".  */
   strcpy (dst, src);
@@ -810,7 +616,7 @@ directory_file_name (src, dst)
       )
     dst[slen - 1] = 0;
 #ifdef DOS_NT
-  CORRECT_DIR_SEPS (dst);
+  dostounix_filename (dst);
 #endif
   return 1;
 }
@@ -821,9 +627,7 @@ DEFUN ("directory-file-name", Fdirectory_file_name, Sdirectory_file_name,
 This is the name of the file that holds the data for the directory DIRECTORY.
 This operation exists because a directory is also a file, but its name as
 a directory is different from its name as a file.
-In Unix-syntax, this function just removes the final slash.
-On VMS, given a VMS-syntax directory name such as \"[X.Y]\",
-it returns a file name such as \"[X]Y.DIR.1\".  */)
+In Unix-syntax, this function just removes the final slash.  */)
      (directory)
      Lisp_Object directory;
 {
@@ -841,20 +645,13 @@ it returns a file name such as \"[X]Y.DIR.1\".  */)
   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
-     chars long, so grab that much extra space...  - sss */
-  buf = (char *) alloca (SBYTES (directory) + 20 + 255);
-#else
   buf = (char *) alloca (SBYTES (directory) + 20);
-#endif
   directory_file_name (SDATA (directory), buf);
   return make_specified_string (buf, -1, strlen (buf),
                                STRING_MULTIBYTE (directory));
 }
 
-static char make_temp_name_tbl[64] =
+static const char make_temp_name_tbl[64] =
 {
   'A','B','C','D','E','F','G','H',
   'I','J','K','L','M','N','O','P',
@@ -885,9 +682,7 @@ static unsigned make_temp_name_count, make_temp_name_count_initialized_p;
    generated.  */
 
 Lisp_Object
-make_temp_name (prefix, base64_p)
-     Lisp_Object prefix;
-     int base64_p;
+make_temp_name (Lisp_Object prefix, int base64_p)
 {
   Lisp_Object val;
   int len, clen;
@@ -1025,27 +820,24 @@ note that these simplifications are done without checking the resulting
 file names in the file system.
 An initial `~/' expands to your home directory.
 An initial `~USER/' expands to USER's home directory.
-See also the function `substitute-in-file-name'.  */)
+See also the function `substitute-in-file-name'.
+
+For technical reasons, this function can return correct but
+non-intuitive results for the root directory; for instance,
+\(expand-file-name ".." "/") returns "/..".  For this reason, use
+(directory-file-name (file-name-directory dirname)) to traverse a
+filesystem tree, not (expand-file-name ".."  dirname).  */)
      (name, default_directory)
      Lisp_Object name, default_directory;
 {
   /* These point to SDATA and need to be careful with string-relocation
      during GC (via DECODE_FILE).  */
   unsigned char *nm, *newdir;
-  int nm_in_name;
   /* This should only point to alloca'd data.  */
   unsigned char *target;
 
   int tlen;
   struct passwd *pw;
-#ifdef VMS
-  unsigned char * colon = 0;
-  unsigned char * close = 0;
-  unsigned char * slash = 0;
-  unsigned char * brack = 0;
-  int lbrack = 0, rbrack = 0;
-  int dots = 0;
-#endif /* VMS */
 #ifdef DOS_NT
   int drive = 0;
   int collapse_newdir = 1;
@@ -1145,15 +937,11 @@ See also the function `substitute-in-file-name'.  */)
        }
     }
 
-  nm = SDATA (name);
-  nm_in_name = 1;
+  /* Make a local copy of nm[] to protect it from GC in DECODE_FILE below. */
+  nm = (unsigned char *) alloca (SBYTES (name) + 1);
+  bcopy (SDATA (name), nm, SBYTES (name) + 1);
 
 #ifdef DOS_NT
-  /* We will force directory separators to be either all \ or /, so make
-     a local copy to modify, even if there ends up being no change. */
-  nm = strcpy (alloca (strlen (nm) + 1), nm);
-  nm_in_name = 0;
-
   /* Note if special escape prefix is present, but remove for now.  */
   if (nm[0] == '/' && nm[1] == ':')
     {
@@ -1196,9 +984,6 @@ See also the function `substitute-in-file-name'.  */)
 #ifdef WINDOWSNT
       && (drive || IS_DIRECTORY_SEP (nm[1])) && !is_escaped
 #endif
-#ifdef VMS
-      || index (nm, ':')
-#endif /* VMS */
       )
     {
       /* If it turns out that the filename we want to return is just a
@@ -1229,97 +1014,14 @@ See also the function `substitute-in-file-name'.  */)
                   && IS_DIRECTORY_SEP (p[0])
                   && IS_DIRECTORY_SEP (p[1]))
            lose = 1;
-
-#ifdef VMS
-         if (p[0] == '\\')
-           lose = 1;
-         if (p[0] == '/') {
-           /* if dev:[dir]/, move nm to / */
-           if (!slash && p > nm && (brack || colon)) {
-             nm = (brack ? brack + 1 : colon + 1);
-             lbrack = rbrack = 0;
-             brack = 0;
-             colon = 0;
-           }
-           slash = p;
-         }
-         if (p[0] == '-')
-#ifdef NO_HYPHENS_IN_FILENAMES
-           if (lbrack == rbrack)
-             {
-                /* Avoid clobbering negative version numbers.  */
-                if (dots < 2)
-                 p[0] = '_';
-             }
-           else
-#endif /* NO_HYPHENS_IN_FILENAMES */
-             if (lbrack > rbrack
-                 && ((p[-1] == '.' || p[-1] == '[' || p[-1] == '<')
-                     && (p[1] == '.' || p[1] == ']' || p[1] == '>')))
-               lose = 1;
-#ifdef NO_HYPHENS_IN_FILENAMES
-             else
-               p[0] = '_';
-#endif /* NO_HYPHENS_IN_FILENAMES */
-         /* count open brackets, reset close bracket pointer */
-         if (p[0] == '[' || p[0] == '<')
-           lbrack++, brack = 0;
-         /* count close brackets, set close bracket pointer */
-         if (p[0] == ']' || p[0] == '>')
-           rbrack++, brack = p;
-         /* detect ][ or >< */
-         if ((p[0] == ']' || p[0] == '>') && (p[1] == '[' || p[1] == '<'))
-           lose = 1;
-         if ((p[0] == ':' || p[0] == ']' || p[0] == '>') && p[1] == '~')
-           nm = p + 1, lose = 1;
-         if (p[0] == ':' && (colon || slash))
-           /* if dev1:[dir]dev2:, move nm to dev2: */
-           if (brack)
-             {
-               nm = brack + 1;
-               brack = 0;
-             }
-           /* if /name/dev:, move nm to dev: */
-           else if (slash)
-             nm = slash + 1;
-           /* if node::dev:, move colon following dev */
-           else if (colon && colon[-1] == ':')
-             colon = p;
-           /* if dev1:dev2:, move nm to dev2: */
-           else if (colon && colon[-1] != ':')
-             {
-               nm = colon + 1;
-               colon = 0;
-             }
-         if (p[0] == ':' && !colon)
-           {
-             if (p[1] == ':')
-               p++;
-             colon = p;
-           }
-         if (lbrack == rbrack)
-           if (p[0] == ';')
-             dots = 2;
-           else if (p[0] == '.')
-             dots++;
-#endif /* VMS */
          p++;
        }
       if (!lose)
        {
-#ifdef VMS
-         if (index (nm, '/'))
-           {
-             nm = sys_translate_unix (nm);
-             nm_in_name = 0;
-             return make_specified_string (nm, -1, strlen (nm), multibyte);
-           }
-#endif /* VMS */
 #ifdef DOS_NT
-         /* Make sure directories are all separated with / or \ as
-            desired, but avoid allocation of a new string when not
-            required. */
-         CORRECT_DIR_SEPS (nm);
+         /* Make sure directories are all separated with /, but
+            avoid allocation of a new string when not required. */
+         dostounix_filename (nm);
 #ifdef WINDOWSNT
          if (IS_DIRECTORY_SEP (nm[1]))
            {
@@ -1339,7 +1041,7 @@ See also the function `substitute-in-file-name'.  */)
            }
          return name;
 #else /* not DOS_NT */
-         if (nm == SDATA (name))
+         if (strcmp (nm, SDATA (name)) == 0)
            return name;
          return make_specified_string (nm, -1, strlen (nm), multibyte);
 #endif /* not DOS_NT */
@@ -1367,9 +1069,6 @@ See also the function `substitute-in-file-name'.  */)
   if (nm[0] == '~')            /* prefix ~ */
     {
       if (IS_DIRECTORY_SEP (nm[1])
-#ifdef VMS
-         || nm[1] == ':'
-#endif /* VMS */
          || nm[1] == 0)        /* ~ by itself */
        {
          Lisp_Object tem;
@@ -1382,29 +1081,17 @@ See also the function `substitute-in-file-name'.  */)
          tem = build_string (newdir);
          if (!STRING_MULTIBYTE (tem))
            {
-             /* FIXME: DECODE_FILE may GC, which may move SDATA(name),
-                after which `nm' won't point to the right place any more.  */
-             int offset = nm - SDATA (name);
              hdir = DECODE_FILE (tem);
              newdir = SDATA (hdir);
-             if (nm_in_name)
-             nm = SDATA (name) + offset;
            }
 #ifdef DOS_NT
          collapse_newdir = 0;
 #endif
-#ifdef VMS
-         nm++;                 /* Don't leave the slash in nm.  */
-#endif /* VMS */
        }
       else                     /* ~user/filename */
        {
          unsigned char *o, *p;
-         for (p = nm; *p && (!IS_DIRECTORY_SEP (*p)
-#ifdef VMS
-                             && *p != ':'
-#endif /* VMS */
-                             ); p++);
+         for (p = nm; *p && (!IS_DIRECTORY_SEP (*p)); p++);
          o = alloca (p - nm + 1);
          bcopy ((char *) nm, o, p - nm);
          o [p - nm] = 0;
@@ -1415,14 +1102,10 @@ See also the function `substitute-in-file-name'.  */)
          if (pw)
            {
              newdir = (unsigned char *) pw -> pw_dir;
-#ifdef VMS
-             nm = p + 1;       /* skip the terminator */
-#else
              nm = p;
 #ifdef DOS_NT
              collapse_newdir = 0;
 #endif
-#endif /* VMS */
            }
 
          /* If we don't find a user of that name, leave the name
@@ -1464,9 +1147,6 @@ See also the function `substitute-in-file-name'.  */)
 #endif
 #ifdef WINDOWSNT
       && !(IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1]))
-#endif
-#ifdef VMS
-      && !index (nm, ':')
 #endif
       && !newdir)
     {
@@ -1588,7 +1268,6 @@ See also the function `substitute-in-file-name'.  */)
 
   if (newdir)
     {
-#ifndef VMS
       if (nm[0] == 0 || IS_DIRECTORY_SEP (nm[0]))
        {
 #ifdef DOS_NT
@@ -1603,69 +1282,19 @@ See also the function `substitute-in-file-name'.  */)
            strcpy (target, newdir);
        }
       else
-#endif
        file_name_as_directory (target, newdir);
     }
 
   strcat (target, nm);
-#ifdef VMS
-  if (index (target, '/'))
-    strcpy (target, sys_translate_unix (target));
-#endif /* VMS */
-
-  /* ASSERT (IS_DIRECTORY_SEP (target[0])) if not VMS */
 
   /* Now canonicalize by removing `//', `/.' and `/foo/..' if they
      appear.  */
-
   {
     unsigned char *p = target;
     unsigned char *o = target;
 
     while (*p)
       {
-#ifdef VMS
-       if (*p != ']' && *p != '>' && *p != '-')
-         {
-           if (*p == '\\')
-             p++;
-           *o++ = *p++;
-         }
-       else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2)
-         /* brackets are offset from each other by 2 */
-         {
-           p += 2;
-           if (*p != '.' && *p != '-' && o[-1] != '.')
-             /* convert [foo][bar] to [bar] */
-             while (o[-1] != '[' && o[-1] != '<')
-               o--;
-           else if (*p == '-' && *o != '.')
-             *--p = '.';
-         }
-       else if (p[0] == '-' && o[-1] == '.'
-                && (p[1] == '.' || p[1] == ']' || p[1] == '>'))
-         /* flush .foo.- ; leave - if stopped by '[' or '<' */
-         {
-           do
-             o--;
-           while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<');
-           if (p[1] == '.')      /* foo.-.bar ==> bar.  */
-             p += 2;
-           else if (o[-1] == '.') /* '.foo.-]' ==> ']' */
-             p++, o--;
-           /* else [foo.-] ==> [-] */
-         }
-       else
-         {
-#ifdef NO_HYPHENS_IN_FILENAMES
-           if (*p == '-'
-               && o[-1] != '[' && o[-1] != '<' && o[-1] != '.'
-               && p[1] != ']' && p[1] != '>' && p[1] != '.')
-             *p = '_';
-#endif /* NO_HYPHENS_IN_FILENAMES */
-           *o++ = *p++;
-         }
-#else /* not VMS */
        if (!IS_DIRECTORY_SEP (*p))
          {
            *o++ = *p++;
@@ -1693,8 +1322,18 @@ See also the function `substitute-in-file-name'.  */)
 #endif
                 && (IS_DIRECTORY_SEP (p[3]) || p[3] == 0))
          {
+#ifdef WINDOWSNT
+           unsigned char *prev_o = o;
+#endif
            while (o != target && (--o) && !IS_DIRECTORY_SEP (*o))
              ;
+#ifdef WINDOWSNT
+           /* Don't go below server level in UNC filenames.  */
+           if (o == target + 1 && IS_DIRECTORY_SEP (*o)
+               && IS_DIRECTORY_SEP (*target))
+             o = prev_o;
+           else
+#endif
            /* Keep initial / only if this is the whole name.  */
            if (o == target && IS_ANY_SEP (*o) && p[3] == 0)
              ++o;
@@ -1707,7 +1346,6 @@ See also the function `substitute-in-file-name'.  */)
          {
            *o++ = *p++;
          }
-#endif /* not VMS */
       }
 
 #ifdef DOS_NT
@@ -1729,7 +1367,7 @@ See also the function `substitute-in-file-name'.  */)
        target[0] = '/';
        target[1] = ':';
       }
-    CORRECT_DIR_SEPS (target);
+    dostounix_filename (target);
 #endif /* DOS_NT */
 
     result = make_specified_string (target, -1, o - target, multibyte);
@@ -1755,8 +1393,9 @@ See also the function `substitute-in-file-name'.  */)
    bugs _are_ found, it might be of interest to look at the old code and
    see what did it do in the relevant situation.
 
-   Don't remove this code: it's true that it will be accessible via CVS,
-   but a few years from deletion, people will forget it is there.  */
+   Don't remove this code: it's true that it will be accessible
+   from the repository, but a few years from deletion, people will
+   forget it is there.  */
 
 /* Changed this DEFUN to a DEAFUN, so as not to confuse `make-docfile'.  */
 DEAFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0,
@@ -1777,32 +1416,13 @@ See also the function `substitute-in-file-name'.")
   unsigned char *target;
   struct passwd *pw;
   int lose;
-#ifdef VMS
-  unsigned char * colon = 0;
-  unsigned char * close = 0;
-  unsigned char * slash = 0;
-  unsigned char * brack = 0;
-  int lbrack = 0, rbrack = 0;
-  int dots = 0;
-#endif /* VMS */
 
   CHECK_STRING (name);
-
-#ifdef VMS
-  /* Filenames on VMS are always upper case.  */
-  name = Fupcase (name);
-#endif
-
   nm = SDATA (name);
 
   /* If nm is absolute, flush ...// and detect /./ and /../.
      If no /./ or /../ we can return right away.  */
-  if (
-      nm[0] == '/'
-#ifdef VMS
-      || index (nm, ':')
-#endif /* VMS */
-      )
+  if (nm[0] == '/')
     {
       p = nm;
       lose = 0;
@@ -1817,87 +1437,10 @@ See also the function `substitute-in-file-name'.")
              && (p[2] == '/' || p[2] == 0
                  || (p[2] == '.' && (p[3] == '/' || p[3] == 0))))
            lose = 1;
-#ifdef VMS
-         if (p[0] == '\\')
-           lose = 1;
-         if (p[0] == '/') {
-           /* if dev:[dir]/, move nm to / */
-           if (!slash && p > nm && (brack || colon)) {
-             nm = (brack ? brack + 1 : colon + 1);
-             lbrack = rbrack = 0;
-             brack = 0;
-             colon = 0;
-           }
-           slash = p;
-         }
-         if (p[0] == '-')
-#ifndef VMS4_4
-           /* VMS pre V4.4,convert '-'s in filenames. */
-           if (lbrack == rbrack)
-             {
-               if (dots < 2)   /* this is to allow negative version numbers */
-                 p[0] = '_';
-             }
-           else
-#endif /* VMS4_4 */
-             if (lbrack > rbrack
-                 && ((p[-1] == '.' || p[-1] == '[' || p[-1] == '<')
-                     && (p[1] == '.' || p[1] == ']' || p[1] == '>')))
-               lose = 1;
-#ifndef VMS4_4
-             else
-               p[0] = '_';
-#endif /* VMS4_4 */
-         /* count open brackets, reset close bracket pointer */
-         if (p[0] == '[' || p[0] == '<')
-           lbrack++, brack = 0;
-         /* count close brackets, set close bracket pointer */
-         if (p[0] == ']' || p[0] == '>')
-           rbrack++, brack = p;
-         /* detect ][ or >< */
-         if ((p[0] == ']' || p[0] == '>') && (p[1] == '[' || p[1] == '<'))
-           lose = 1;
-         if ((p[0] == ':' || p[0] == ']' || p[0] == '>') && p[1] == '~')
-           nm = p + 1, lose = 1;
-         if (p[0] == ':' && (colon || slash))
-           /* if dev1:[dir]dev2:, move nm to dev2: */
-           if (brack)
-             {
-               nm = brack + 1;
-               brack = 0;
-             }
-           /* If /name/dev:, move nm to dev: */
-           else if (slash)
-             nm = slash + 1;
-           /* If node::dev:, move colon following dev */
-           else if (colon && colon[-1] == ':')
-             colon = p;
-           /* If dev1:dev2:, move nm to dev2: */
-           else if (colon && colon[-1] != ':')
-             {
-               nm = colon + 1;
-               colon = 0;
-             }
-         if (p[0] == ':' && !colon)
-           {
-             if (p[1] == ':')
-               p++;
-             colon = p;
-           }
-         if (lbrack == rbrack)
-           if (p[0] == ';')
-             dots = 2;
-           else if (p[0] == '.')
-             dots++;
-#endif /* VMS */
          p++;
        }
       if (!lose)
        {
-#ifdef VMS
-         if (index (nm, '/'))
-           return build_string (sys_translate_unix (nm));
-#endif /* VMS */
          if (nm == SDATA (name))
            return name;
          return build_string (nm);
@@ -1909,18 +1452,11 @@ See also the function `substitute-in-file-name'.")
   newdir = 0;
 
   if (nm[0] == '~')             /* prefix ~ */
-    if (nm[1] == '/'
-#ifdef VMS
-       || nm[1] == ':'
-#endif /* VMS */
-       || nm[1] == 0)/* ~/filename */
+    if (nm[1] == '/' || nm[1] == 0)/* ~/filename */
       {
        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 */
       {
@@ -1929,11 +1465,6 @@ See also the function `substitute-in-file-name'.")
        /* Find end of name. */
        unsigned char *ptr = (unsigned char *) index (user, '/');
        int len = ptr ? ptr - user : strlen (user);
-#ifdef VMS
-       unsigned char *ptr1 = index (user, ':');
-       if (ptr1 != 0 && ptr1 - user < len)
-         len = ptr1 - user;
-#endif /* VMS */
        /* Copy the user name into temp storage. */
        o = (unsigned char *) alloca (len + 1);
        bcopy ((char *) user, o, len);
@@ -1952,11 +1483,7 @@ See also the function `substitute-in-file-name'.")
        nm += len;
       }
 
-  if (nm[0] != '/'
-#ifdef VMS
-      && !index (nm, ':')
-#endif /* not VMS */
-      && !newdir)
+  if (nm[0] != '/' && !newdir)
     {
       if (NILP (defalt))
        defalt = current_buffer->directory;
@@ -1972,19 +1499,13 @@ See also the function `substitute-in-file-name'.")
 
   if (newdir)
     {
-#ifndef VMS
       if (nm[0] == 0 || nm[0] == '/')
        strcpy (target, newdir);
       else
-#endif
       file_name_as_directory (target, newdir);
     }
 
   strcat (target, nm);
-#ifdef VMS
-  if (index (target, '/'))
-    strcpy (target, sys_translate_unix (target));
-#endif /* VMS */
 
   /* Now canonicalize by removing /. and /foo/.. if they appear */
 
@@ -1993,48 +1514,6 @@ See also the function `substitute-in-file-name'.")
 
   while (*p)
     {
-#ifdef VMS
-      if (*p != ']' && *p != '>' && *p != '-')
-       {
-         if (*p == '\\')
-           p++;
-         *o++ = *p++;
-       }
-      else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2)
-       /* brackets are offset from each other by 2 */
-       {
-         p += 2;
-         if (*p != '.' && *p != '-' && o[-1] != '.')
-           /* convert [foo][bar] to [bar] */
-           while (o[-1] != '[' && o[-1] != '<')
-             o--;
-         else if (*p == '-' && *o != '.')
-           *--p = '.';
-       }
-      else if (p[0] == '-' && o[-1] == '.'
-              && (p[1] == '.' || p[1] == ']' || p[1] == '>'))
-       /* flush .foo.- ; leave - if stopped by '[' or '<' */
-       {
-         do
-           o--;
-         while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<');
-         if (p[1] == '.')      /* foo.-.bar ==> bar.  */
-           p += 2;
-         else if (o[-1] == '.') /* '.foo.-]' ==> ']' */
-           p++, o--;
-         /* else [foo.-] ==> [-] */
-       }
-      else
-       {
-#ifndef VMS4_4
-         if (*p == '-'
-             && o[-1] != '[' && o[-1] != '<' && o[-1] != '.'
-             && p[1] != ']' && p[1] != '>' && p[1] != '.')
-           *p = '_';
-#endif /* VMS4_4 */
-         *o++ = *p++;
-       }
-#else /* not VMS */
       if (*p != '/')
        {
          *o++ = *p++;
@@ -2063,7 +1542,6 @@ See also the function `substitute-in-file-name'.")
        {
          *o++ = *p++;
        }
-#endif /* not VMS */
     }
 
   return make_string (target, o - target);
@@ -2072,18 +1550,10 @@ See also the function `substitute-in-file-name'.")
 \f
 /* If /~ or // appears, discard everything through first slash.  */
 static int
-file_name_absolute_p (filename)
-     const unsigned char *filename;
+file_name_absolute_p (const unsigned char *filename)
 {
   return
     (IS_DIRECTORY_SEP (*filename) || *filename == '~'
-#ifdef VMS
-     /* ??? This criterion is probably wrong for '<'.  */
-     || index (filename, ':') || index (filename, '<')
-     || (*filename == '[' && (filename[1] != '-'
-                             || (filename[2] != '.' && filename[2] != ']'))
-        && filename[1] != '.')
-#endif /* VMS */
 #ifdef DOS_NT
      || (IS_DRIVE (*filename) && IS_DEVICE_SEP (filename[1])
         && IS_DIRECTORY_SEP (filename[2]))
@@ -2092,17 +1562,13 @@ file_name_absolute_p (filename)
 }
 
 static unsigned char *
-search_embedded_absfilename (nm, endp)
-     unsigned char *nm, *endp;
+search_embedded_absfilename (unsigned char *nm, unsigned char *endp)
 {
   unsigned char *p, *s;
 
   for (p = nm + 1; p < endp; p++)
     {
       if ((0
-#ifdef VMS
-          || p[-1] == ':' || p[-1] == ']' || p[-1] == '>'
-#endif /* VMS */
           || IS_DIRECTORY_SEP (p[-1]))
          && file_name_absolute_p (p)
 #if defined (WINDOWSNT) || defined(CYGWIN)
@@ -2112,11 +1578,7 @@ search_embedded_absfilename (nm, endp)
 #endif /* not (WINDOWSNT || CYGWIN) */
              )
        {
-         for (s = p; *s && (!IS_DIRECTORY_SEP (*s)
-#ifdef VMS
-                             && *s != ':'
-#endif /* VMS */
-                             ); s++);
+         for (s = p; *s && (!IS_DIRECTORY_SEP (*s)); s++);
          if (p[0] == '~' && s > p + 1) /* we've got "/~something/" */
            {
              unsigned char *o = alloca (s - p + 1);
@@ -2147,10 +1609,10 @@ DEFUN ("substitute-in-file-name", Fsubstitute_in_file_name,
 the value of that variable.  The variable name should be terminated
 with a character not a letter, digit or underscore; otherwise, enclose
 the entire variable name in braces.
-If `/~' appears, all of FILENAME through that `/' is discarded.
 
-On VMS, `$' substitution is not done; this function does little and only
-duplicates what `expand-file-name' does.  */)
+If `/~' appears, all of FILENAME through that `/' is discarded.
+If `//' appears, everything up to and including the first of
+those `/' is discarded.  */)
      (filename)
      Lisp_Object filename;
 {
@@ -2160,21 +1622,28 @@ duplicates what `expand-file-name' does.  */)
   unsigned char *target = NULL;
   int total = 0;
   int substituted = 0;
+  int multibyte;
   unsigned char *xnm;
   Lisp_Object handler;
 
   CHECK_STRING (filename);
 
+  multibyte = STRING_MULTIBYTE (filename);
+
   /* If the file name has special constructs in it,
      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);
 
-  nm = SDATA (filename);
+  /* 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 = (unsigned char *) alloca (SBYTES (filename) + 1);
+  bcopy (SDATA (filename), nm, SBYTES (filename) + 1);
+
 #ifdef DOS_NT
-  nm = strcpy (alloca (strlen (nm) + 1), nm);
-  CORRECT_DIR_SEPS (nm);
+  dostounix_filename (nm);
   substituted = (strcmp (nm, SDATA (filename)) != 0);
 #endif
   endp = nm + SBYTES (filename);
@@ -2186,12 +1655,7 @@ duplicates what `expand-file-name' does.  */)
        again.  Important with filenames like "/home/foo//:/hello///there"
        which whould substitute to "/:/hello///there" rather than "/there".  */
     return Fsubstitute_in_file_name
-      (make_specified_string (p, -1, endp - p,
-                             STRING_MULTIBYTE (filename)));
-
-#ifdef VMS
-  return filename;
-#else
+      (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' */
@@ -2237,8 +1701,16 @@ duplicates what `expand-file-name' does.  */)
        /* Get variable value */
        o = (unsigned char *) egetenv (target);
        if (o)
-         { /* Eight-bit chars occupy upto 2 bytes in multibyte.  */
-           total += strlen (o) * (STRING_MULTIBYTE (filename) ? 2 : 1);
+         {
+           /* Don't try to guess a maximum length - UTF8 can use up to
+              four bytes per character.  This code is unlikely to run
+              in a situation that requires performance, so decoding the
+              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));
+           decoded = DECODE_FILE (orig);
+           total += SBYTES (decoded);
            substituted = 1;
          }
        else if (*p == '}')
@@ -2296,21 +1768,22 @@ duplicates what `expand-file-name' does.  */)
            *x++ = '$';
            strcpy (x, target); x+= strlen (target);
          }
-       else if (STRING_MULTIBYTE (filename))
-         {
-           /* If the original string is multibyte,
-              convert what we substitute into multibyte.  */
-           while (*o)
-             {
-               int c = *o++;
-               c = unibyte_char_to_multibyte (c);
-               x += CHAR_STRING (c, x);
-             }
-         }
        else
          {
-           strcpy (x, o);
-           x += strlen (o);
+           Lisp_Object orig, decoded;
+           int orig_length, decoded_length;
+           orig_length = strlen (o);
+           orig = make_unibyte_string (o, orig_length);
+           decoded = DECODE_FILE (orig);
+           decoded_length = SBYTES (decoded);
+           strncpy (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 (SDATA (decoded), o, orig_length))
+             multibyte = 1;
          }
       }
 
@@ -2323,7 +1796,7 @@ duplicates what `expand-file-name' does.  */)
        need to quote some $ to $$ first.  */
     xnm = p;
 
-  return make_specified_string (xnm, -1, x - xnm, STRING_MULTIBYTE (filename));
+  return make_specified_string (xnm, -1, x - xnm, multibyte);
 
  badsubst:
   error ("Bad format environment-variable substitution");
@@ -2333,7 +1806,6 @@ duplicates what `expand-file-name' does.  */)
   error ("Substituting nonexistent environment variable \"%s\"", target);
 
   /* NOTREACHED */
-#endif /* not VMS */
   return Qnil;
 }
 \f
@@ -2341,19 +1813,12 @@ duplicates what `expand-file-name' does.  */)
    (directory-file-name (expand-file-name FOO)).  */
 
 Lisp_Object
-expand_and_dir_to_file (filename, defdir)
-     Lisp_Object filename, defdir;
+expand_and_dir_to_file (Lisp_Object filename, Lisp_Object defdir)
 {
   register Lisp_Object absname;
 
   absname = Fexpand_file_name (filename, defdir);
-#ifdef VMS
-  {
-    register int c = SREF (absname, SBYTES (absname) - 1);
-    if (c == ':' || c == ']' || c == '>')
-      absname = Fdirectory_file_name (absname);
-  }
-#else
+
   /* Remove final slash, if any (unless this is the root dir).
      stat behaves differently depending!  */
   if (SCHARS (absname) > 1
@@ -2361,7 +1826,6 @@ expand_and_dir_to_file (filename, defdir)
       && !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);
-#endif
   return absname;
 }
 \f
@@ -2378,12 +1842,7 @@ expand_and_dir_to_file (filename, defdir)
    If QUICK is nonzero, we ask for y or n, not yes or no.  */
 
 void
-barf_or_query_if_file_exists (absname, querystring, interactive, statptr, quick)
-     Lisp_Object absname;
-     unsigned char *querystring;
-     int interactive;
-     struct stat *statptr;
-     int quick;
+barf_or_query_if_file_exists (Lisp_Object absname, unsigned char *querystring, int interactive, struct stat *statptr, int quick)
 {
   register Lisp_Object tem, encoded_filename;
   struct stat statbuf;
@@ -2420,7 +1879,7 @@ barf_or_query_if_file_exists (absname, querystring, interactive, statptr, quick)
   return;
 }
 
-DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 5,
+DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 6,
        "fCopy file: \nGCopy %s to file: \np\nP",
        doc: /* Copy FILE to NEWNAME.  Both args must be strings.
 If NEWNAME names a directory, copy FILE there.
@@ -2442,10 +1901,13 @@ last-modified time as the old one.  (This works on only some systems.)
 A prefix arg makes KEEP-TIME non-nil.
 
 If PRESERVE-UID-GID is non-nil, we try to transfer the
-uid and gid of FILE to NEWNAME.  */)
-  (file, newname, ok_if_already_exists, keep_time, preserve_uid_gid)
+uid and gid of FILE to NEWNAME.
+
+If PRESERVE-SELINUX-CONTEXT is non-nil and SELinux is enabled
+on the system, we copy the SELinux context of FILE to NEWNAME.  */)
+     (file, newname, ok_if_already_exists, keep_time, preserve_uid_gid, preserve_selinux_context)
      Lisp_Object file, newname, ok_if_already_exists, keep_time;
-     Lisp_Object preserve_uid_gid;
+     Lisp_Object preserve_uid_gid, preserve_selinux_context;
 {
   int ifd, ofd, n;
   char buf[16 * 1024];
@@ -2455,6 +1917,10 @@ uid and gid of FILE to NEWNAME.  */)
   int count = SPECPDL_INDEX ();
   int input_file_statable_p;
   Lisp_Object encoded_file, encoded_newname;
+#if HAVE_LIBSELINUX
+  security_context_t con;
+  int fail, conlength = 0;
+#endif
 
   encoded_file = encoded_newname = Qnil;
   GCPRO4 (file, newname, encoded_file, encoded_newname);
@@ -2475,8 +1941,9 @@ uid and gid of FILE to NEWNAME.  */)
   if (NILP (handler))
     handler = Ffind_file_name_handler (newname, Qcopy_file);
   if (!NILP (handler))
-    RETURN_UNGCPRO (call6 (handler, Qcopy_file, file, newname,
-                          ok_if_already_exists, keep_time, preserve_uid_gid));
+    RETURN_UNGCPRO (call7 (handler, Qcopy_file, file, newname,
+                          ok_if_already_exists, keep_time, preserve_uid_gid,
+                          preserve_selinux_context));
 
   encoded_file = ENCODE_FILE (file);
   encoded_newname = ENCODE_FILE (newname);
@@ -2530,7 +1997,15 @@ uid and gid of FILE to NEWNAME.  */)
      copyable by us. */
   input_file_statable_p = (fstat (ifd, &st) >= 0);
 
-#if !defined (MSDOS) || __DJGPP__ > 1
+#if HAVE_LIBSELINUX
+  if (!NILP (preserve_selinux_context) && is_selinux_enabled ())
+    {
+      conlength = fgetfilecon (ifd, &con);
+      if (conlength == -1)
+       report_file_error ("Doing fgetfilecon", Fcons (file, Qnil));
+    }
+#endif
+
   if (out_st.st_mode != 0
       && st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino)
     {
@@ -2538,7 +2013,6 @@ uid and gid of FILE to NEWNAME.  */)
       report_file_error ("Input and output files are the same",
                         Fcons (file, Fcons (newname, Qnil)));
     }
-#endif
 
 #if defined (S_ISREG) && defined (S_ISLNK)
   if (input_file_statable_p)
@@ -2554,10 +2028,6 @@ uid and gid of FILE to NEWNAME.  */)
     }
 #endif /* S_ISREG && S_ISLNK */
 
-#ifdef VMS
-  /* Create the copy file with the same record format as the input file */
-  ofd = sys_creat (SDATA (encoded_newname), 0666, ifd);
-#else
 #ifdef MSDOS
   /* System's default file type was set to binary by _fmode in emacs.c.  */
   ofd = emacs_open (SDATA (encoded_newname),
@@ -2570,7 +2040,6 @@ uid and gid of FILE to NEWNAME.  */)
                    | (NILP (ok_if_already_exists) ? O_EXCL : 0),
                    0666);
 #endif /* not MSDOS */
-#endif /* VMS */
   if (ofd < 0)
     report_file_error ("Opening output file", Fcons (newname, Qnil));
 
@@ -2594,6 +2063,18 @@ uid and gid of FILE to NEWNAME.  */)
     }
 #endif /* not MSDOS */
 
+#if HAVE_LIBSELINUX
+  if (conlength > 0)
+    {
+      /* Set the modified context back to the file. */
+      fail = fsetfilecon (ofd, con);
+      if (fail)
+       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));
@@ -2614,7 +2095,7 @@ uid and gid of FILE to NEWNAME.  */)
 
   emacs_close (ifd);
 
-#if defined (__DJGPP__) && __DJGPP__ > 1
+#ifdef MSDOS
   if (input_file_statable_p)
     {
       /* In DJGPP v2.0 and later, fstat usually returns true file mode bits,
@@ -2624,7 +2105,7 @@ uid and gid of FILE to NEWNAME.  */)
       if ((_djstat_flags & _STFAIL_WRITEBIT) == 0)
        chmod (SDATA (encoded_newname), st.st_mode & 07777);
     }
-#endif /* DJGPP version 2 or newer */
+#endif /* MSDOS */
 #endif /* not WINDOWSNT */
 
   /* Discard the unwind protects.  */
@@ -2665,7 +2146,8 @@ DEFUN ("make-directory-internal", Fmake_directory_internal,
   return Qnil;
 }
 
-DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete directory: ",
+DEFUN ("delete-directory-internal", Fdelete_directory_internal,
+       Sdelete_directory_internal, 1, 1, 0,
        doc: /* Delete the directory named DIRECTORY.  Does not follow symlinks.  */)
      (directory)
      Lisp_Object directory;
@@ -2676,16 +2158,7 @@ DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete
 
   CHECK_STRING (directory);
   directory = Fdirectory_file_name (Fexpand_file_name (directory, Qnil));
-
-  handler = Ffind_file_name_handler (directory, Qdelete_directory);
-  if (!NILP (handler))
-    return call2 (handler, Qdelete_directory, directory);
-
-  if (delete_by_moving_to_trash)
-    return call1 (Qmove_file_to_trash, directory);
-
   encoded_dir = ENCODE_FILE (directory);
-
   dir = SDATA (encoded_dir);
 
   if (rmdir (dir) != 0)
@@ -2694,11 +2167,22 @@ DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete
   return Qnil;
 }
 
-DEFUN ("delete-file", Fdelete_file, Sdelete_file, 1, 1, "fDelete file: ",
+DEFUN ("delete-file", Fdelete_file, Sdelete_file, 1, 2,
+       "(list (read-file-name \
+                (if (and delete-by-moving-to-trash (null current-prefix-arg)) \
+                    \"Move file to trash: \" \"Delete file: \") \
+                nil default-directory (confirm-nonexistent-file-or-buffer)) \
+              (null current-prefix-arg))",
        doc: /* Delete file named FILENAME.  If it is a symlink, remove the symlink.
-If file has multiple names, it continues to exist with the other names.  */)
-     (filename)
+If file has multiple names, it continues to exist with the other names.
+TRASH non-nil means to trash the file instead of deleting, provided
+`delete-by-moving-to-trash' is non-nil.
+
+When called interactively, TRASH is t if no prefix argument is given.
+With a prefix argument, TRASH is nil.  */)
+     (filename, trash)
      Lisp_Object filename;
+     Lisp_Object trash;
 {
   Lisp_Object handler;
   Lisp_Object encoded_file;
@@ -2715,9 +2199,9 @@ If file has multiple names, it continues to exist with the other names.  */)
 
   handler = Ffind_file_name_handler (filename, Qdelete_file);
   if (!NILP (handler))
-    return call2 (handler, Qdelete_file, filename);
+    return call3 (handler, Qdelete_file, filename, trash);
 
-  if (delete_by_moving_to_trash)
+  if (delete_by_moving_to_trash && !NILP (trash))
     return call1 (Qmove_file_to_trash, filename);
 
   encoded_file = ENCODE_FILE (filename);
@@ -2728,20 +2212,20 @@ If file has multiple names, it continues to exist with the other names.  */)
 }
 
 static Lisp_Object
-internal_delete_file_1 (ignore)
-     Lisp_Object ignore;
+internal_delete_file_1 (Lisp_Object ignore)
 {
   return Qt;
 }
 
-/* Delete file FILENAME, returning 1 if successful and 0 if failed.  */
+/* Delete file FILENAME, returning 1 if successful and 0 if failed.
+   This ignores `delete-by-moving-to-trash'.  */
 
 int
-internal_delete_file (filename)
-     Lisp_Object filename;
+internal_delete_file (Lisp_Object filename)
 {
   Lisp_Object tem;
-  tem = internal_condition_case_1 (Fdelete_file, filename,
+
+  tem = internal_condition_case_2 (Fdelete_file, filename, Qnil,
                                   Qt, internal_delete_file_1);
   return NILP (tem);
 }
@@ -2774,7 +2258,11 @@ This is what happens in interactive use with M-x.  */)
       && (NILP (Fstring_equal (Fdowncase (file), Fdowncase (newname))))
 #endif
       )
-    newname = Fexpand_file_name (Ffile_name_nondirectory (file), newname);
+    {
+      Lisp_Object fname = NILP (Ffile_directory_p (file))
+       ? file : Fdirectory_file_name (file);
+      newname = Fexpand_file_name (Ffile_name_nondirectory (fname), newname);
+    }
   else
     newname = Fexpand_file_name (newname, Qnil);
 
@@ -2804,6 +2292,7 @@ This is what happens in interactive use with M-x.  */)
     {
       if (errno == EXDEV)
        {
+          int count;
 #ifdef S_IFLNK
           symlink_target = Ffile_symlink_p (file);
           if (! NILP (symlink_target))
@@ -2811,13 +2300,27 @@ This is what happens in interactive use with M-x.  */)
                                  NILP (ok_if_already_exists) ? Qnil : Qt);
           else
 #endif
+         if (!NILP (Ffile_directory_p (file)))
+           call4 (Qcopy_directory, file, newname, Qt, Qnil);
+         else
+           /* We have already prompted if it was an integer, so don't
+              have copy-file prompt again.  */
            Fcopy_file (file, 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, Qt);
+                       Qt, Qt, Qt);
 
-         Fdelete_file (file);
+         count = SPECPDL_INDEX ();
+         specbind (Qdelete_by_moving_to_trash, Qnil);
+
+         if (!NILP (Ffile_directory_p (file))
+#ifdef S_IFLNK
+             && NILP (symlink_target)
+#endif
+             )
+           call2 (Qdelete_directory, file, Qt);
+         else
+           Fdelete_file (file, Qnil);
+         unbind_to (count, Qnil);
        }
       else
        report_file_error ("Renaming", list2 (file, newname));
@@ -2960,33 +2463,6 @@ This happens for interactive use with M-x.  */)
 #endif /* S_IFLNK */
 }
 
-#ifdef VMS
-
-DEFUN ("define-logical-name", Fdefine_logical_name, Sdefine_logical_name,
-       2, 2, "sDefine logical name: \nsDefine logical name %s as: ",
-       doc: /* Define the job-wide logical name NAME to have the value STRING.
-If STRING is nil or a null string, the logical name NAME is deleted.  */)
-     (name, string)
-     Lisp_Object name;
-     Lisp_Object string;
-{
-  CHECK_STRING (name);
-  if (NILP (string))
-    delete_logical_name (SDATA (name));
-  else
-    {
-      CHECK_STRING (string);
-
-      if (SCHARS (string) == 0)
-       delete_logical_name (SDATA (name));
-      else
-       define_logical_name (SDATA (name), SDATA (string));
-    }
-
-  return string;
-}
-#endif /* VMS */
-
 \f
 DEFUN ("file-name-absolute-p", Ffile_name_absolute_p, Sfile_name_absolute_p,
        1, 1, 0,
@@ -3002,8 +2478,7 @@ On Unix, this is a name starting with a `/' or a `~'.  */)
 /* Return nonzero if file FILENAME exists and can be executed.  */
 
 static int
-check_executable (filename)
-     char *filename;
+check_executable (char *filename)
 {
 #ifdef DOS_NT
   int len = strlen (filename);
@@ -3011,16 +2486,7 @@ check_executable (filename)
   struct stat st;
   if (stat (filename, &st) < 0)
     return 0;
-#if defined (WINDOWSNT) || (defined (MSDOS) && __DJGPP__ > 1)
   return ((st.st_mode & S_IEXEC) != 0);
-#else
-  return (S_ISREG (st.st_mode)
-         && len >= 5
-         && (xstrcasecmp ((suffix = filename + len-4), ".com") == 0
-             || xstrcasecmp (suffix, ".exe") == 0
-             || xstrcasecmp (suffix, ".bat") == 0)
-         || (st.st_mode & S_IFMT) == S_IFDIR);
-#endif /* not WINDOWSNT */
 #else /* not DOS_NT */
 #ifdef HAVE_EUIDACCESS
   return (euidaccess (filename, 1) >= 0);
@@ -3036,8 +2502,7 @@ check_executable (filename)
 /* Return nonzero if file FILENAME exists and can be written.  */
 
 static int
-check_writable (filename)
-     char *filename;
+check_writable (char *filename)
 {
 #ifdef MSDOS
   struct stat st;
@@ -3182,10 +2647,6 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
            ? Qt : Qnil);
 
   dir = Ffile_name_directory (absname);
-#ifdef VMS
-  if (!NILP (dir))
-    dir = Fdirectory_file_name (dir);
-#endif /* VMS */
 #ifdef MSDOS
   if (!NILP (dir))
     dir = Fdirectory_file_name (dir);
@@ -3401,6 +2862,140 @@ See `file-symlink-p' to distinguish symlinks.  */)
 #endif
 }
 \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 */)
+     (filename)
+     Lisp_Object filename;
+{
+  Lisp_Object absname;
+  Lisp_Object values[4];
+  Lisp_Object handler;
+#if HAVE_LIBSELINUX
+  security_context_t con;
+  int conlength;
+  context_t context;
+#endif
+
+  absname = expand_and_dir_to_file (filename, current_buffer->directory);
+
+  /* If the file name has special constructs in it,
+     call the corresponding file handler.  */
+  handler = Ffind_file_name_handler (absname, Qfile_selinux_context);
+  if (!NILP (handler))
+    return call2 (handler, Qfile_selinux_context, absname);
+
+  absname = ENCODE_FILE (absname);
+
+  values[0] = Qnil;
+  values[1] = Qnil;
+  values[2] = Qnil;
+  values[3] = Qnil;
+#if HAVE_LIBSELINUX
+  if (is_selinux_enabled ())
+    {
+      conlength = lgetfilecon (SDATA (absname), &con);
+      if (conlength > 0)
+       {
+         context = context_new (con);
+         if (context_user_get (context))
+           values[0] = build_string (context_user_get (context));
+         if (context_role_get (context))
+           values[1] = build_string (context_role_get (context));
+         if (context_type_get (context))
+           values[2] = build_string (context_type_get (context));
+         if (context_range_get (context))
+           values[3] = build_string (context_range_get (context));
+         context_free (context);
+       }
+      if (con)
+       freecon (con);
+    }
+#endif
+
+  return Flist (sizeof(values) / sizeof(values[0]), values);
+}
+\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. */)
+     (filename, context)
+     Lisp_Object filename, context;
+{
+  Lisp_Object absname, encoded_absname;
+  Lisp_Object handler;
+  Lisp_Object user = CAR_SAFE (context);
+  Lisp_Object role = CAR_SAFE (CDR_SAFE (context));
+  Lisp_Object type = CAR_SAFE (CDR_SAFE (CDR_SAFE (context)));
+  Lisp_Object range = CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (context))));
+#if HAVE_LIBSELINUX
+  security_context_t con;
+  int fail, conlength;
+  context_t parsed_con;
+#endif
+
+  absname = Fexpand_file_name (filename, current_buffer->directory);
+
+  /* If the file name has special constructs in it,
+     call the corresponding file handler.  */
+  handler = Ffind_file_name_handler (absname, Qset_file_selinux_context);
+  if (!NILP (handler))
+    return call3 (handler, Qset_file_selinux_context, absname, context);
+
+  encoded_absname = ENCODE_FILE (absname);
+
+#if HAVE_LIBSELINUX
+  if (is_selinux_enabled ())
+    {
+      /* Get current file context. */
+      conlength = lgetfilecon (SDATA (encoded_absname), &con);
+      if (conlength > 0)
+       {
+         parsed_con = context_new (con);
+         /* Change the parts defined in the parameter.*/
+         if (STRINGP (user))
+           {
+             if (context_user_set (parsed_con, SDATA (user)))
+               error ("Doing context_user_set");
+           }
+         if (STRINGP (role))
+           {
+             if (context_role_set (parsed_con, SDATA (role)))
+               error ("Doing context_role_set");
+           }
+         if (STRINGP (type))
+           {
+             if (context_type_set (parsed_con, SDATA (type)))
+               error ("Doing context_type_set");
+           }
+         if (STRINGP (range))
+           {
+             if (context_range_set (parsed_con, SDATA (range)))
+               error ("Doing context_range_set");
+           }
+
+         /* Set the modified context back to the file. */
+         fail = lsetfilecon (SDATA (encoded_absname), context_str (parsed_con));
+         if (fail)
+           report_file_error ("Doing lsetfilecon", Fcons (absname, Qnil));
+
+         context_free (parsed_con);
+       }
+      else
+       report_file_error("Doing lgetfilecon", Fcons (absname, Qnil));
+
+      if (con)
+       freecon (con);
+    }
+#endif
+
+  return Qnil;
+}
+\f
 DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
        doc: /* Return mode bits of file named FILENAME, as an integer.
 Return nil, if file does not exist or is not accessible.  */)
@@ -3423,10 +3018,6 @@ Return nil, if file does not exist or is not accessible.  */)
 
   if (stat (SDATA (absname), &st) < 0)
     return Qnil;
-#if defined (MSDOS) && __DJGPP__ < 2
-  if (check_executable (SDATA (absname)))
-    st.st_mode |= S_IEXEC;
-#endif /* MSDOS && __DJGPP__ < 2 */
 
   return make_number (st.st_mode & 07777);
 }
@@ -3435,7 +3026,10 @@ DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 2,
        "(let ((file (read-file-name \"File: \")))                      \
          (list file (read-file-modes nil file)))",
        doc: /* Set mode bits of file named FILENAME to MODE (an integer).
-Only the 12 low bits of MODE are used.  */)
+Only the 12 low bits of MODE are used.
+
+Interactively, mode bits are read by `read-file-modes', which accepts
+symbolic notation, like the `chmod' command from GNU Coreutils.  */)
   (filename, mode)
      Lisp_Object filename, mode;
 {
@@ -3488,7 +3082,7 @@ The value is an integer.  */)
   return value;
 }
 \f
-extern int lisp_time_argument P_ ((Lisp_Object, time_t *, int *));
+extern int lisp_time_argument (Lisp_Object, time_t *, int *);
 
 DEFUN ("set-file-times", Fset_file_times, Sset_file_times, 1, 2, 0,
        doc: /* Set times of file FILENAME to TIME.
@@ -3606,8 +3200,6 @@ Lisp_Object Qfind_buffer_file_type;
 #define READ_BUF_SIZE (64 << 10)
 #endif
 
-extern void adjust_markers_for_delete P_ ((int, int, int, int));
-
 /* This function is called after Lisp functions to decide a coding
    system are called, or when they cause an error.  Before they are
    called, the current buffer is set unibyte and it contains only a
@@ -3624,8 +3216,7 @@ extern void adjust_markers_for_delete P_ ((int, int, int, int));
        o set back the buffer multibyteness.  */
 
 static Lisp_Object
-decide_coding_unwind (unwind_data)
-     Lisp_Object unwind_data;
+decide_coding_unwind (Lisp_Object unwind_data)
 {
   Lisp_Object multibyte, undo_list, buffer;
 
@@ -3652,8 +3243,8 @@ decide_coding_unwind (unwind_data)
 /* Used to pass values from insert-file-contents to read_non_regular.  */
 
 static int non_regular_fd;
-static int non_regular_inserted;
-static int non_regular_nbytes;
+static EMACS_INT non_regular_inserted;
+static EMACS_INT non_regular_nbytes;
 
 
 /* Read from a non-regular file.
@@ -3662,9 +3253,9 @@ static int non_regular_nbytes;
    Value is the number of bytes read.  */
 
 static Lisp_Object
-read_non_regular ()
+read_non_regular (void)
 {
-  int nbytes;
+  EMACS_INT nbytes;
 
   immediate_quit = 1;
   QUIT;
@@ -3680,7 +3271,7 @@ read_non_regular ()
    in insert-file-contents.  */
 
 static Lisp_Object
-read_non_regular_quit ()
+read_non_regular_quit (void)
 {
   return Qnil;
 }
@@ -3714,15 +3305,15 @@ variable `last-coding-system-used' to the coding system actually used.  */)
 {
   struct stat st;
   register int fd;
-  int inserted = 0;
+  EMACS_INT inserted = 0;
   int nochange = 0;
-  register int how_much;
-  register int unprocessed;
+  register EMACS_INT how_much;
+  register EMACS_INT unprocessed;
   int count = SPECPDL_INDEX ();
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
   Lisp_Object handler, val, insval, orig_filename, old_undo;
   Lisp_Object p;
-  int total = 0;
+  EMACS_INT total = 0;
   int not_regular = 0;
   unsigned char read_buf[READ_BUF_SIZE];
   struct coding_system coding;
@@ -3733,6 +3324,7 @@ variable `last-coding-system-used' to the coding system actually used.  */)
   int read_quit = 0;
   Lisp_Object old_Vdeactivate_mark = Vdeactivate_mark;
   int we_locked_file = 0;
+  int deferred_remove_unwind_protect = 0;
 
   if (current_buffer->base_buffer && ! NILP (visit))
     error ("Cannot do file visiting in an indirect buffer");
@@ -3823,10 +3415,8 @@ variable `last-coding-system-used' to the coding system actually used.  */)
 
   record_unwind_protect (close_file_unwind, make_number (fd));
 
-  /* Supposedly happens on VMS.  */
   /* Can happen on any platform that uses long as type of off_t, but allows
-     file sizes to exceed 2Gb.  VMS is no longer officially supported, so
-     give a message suitable for the latter case.  */
+     file sizes to exceed 2Gb, so give a suitable message.  */
   if (! not_regular && st.st_size < 0)
     error ("Maximum buffer size exceeded");
 
@@ -3859,7 +3449,11 @@ variable `last-coding-system-used' to the coding system actually used.  */)
             overflow.  The calculations below double the file size
             twice, so check that it can be multiplied by 4 safely.  */
          if (XINT (end) != st.st_size
-             || st.st_size > INT_MAX / 4)
+             /* Actually, it should test either INT_MAX or LONG_MAX
+                depending on which one is used for EMACS_INT.  But in
+                any case, in practice, this test is redundant with the
+                one above.
+                || st.st_size > INT_MAX / 4 */)
            error ("Maximum buffer size exceeded");
 
          /* The file size returned from stat may be zero, but data
@@ -3895,7 +3489,7 @@ variable `last-coding-system-used' to the coding system actually used.  */)
                 We assume that the 1K-byte and 3K-byte for heading
                 and tailing respectively are sufficient for this
                 purpose.  */
-             int nread;
+             EMACS_INT nread;
 
              if (st.st_size <= (1024 * 4))
                nread = emacs_read (fd, read_buf, 1024 * 4);
@@ -4005,9 +3599,9 @@ variable `last-coding-system-used' to the coding system actually used.  */)
       /* same_at_start and same_at_end count bytes,
         because file access counts bytes
         and BEG and END count bytes.  */
-      int same_at_start = BEGV_BYTE;
-      int same_at_end = ZV_BYTE;
-      int overlap;
+      EMACS_INT same_at_start = BEGV_BYTE;
+      EMACS_INT same_at_end = ZV_BYTE;
+      EMACS_INT overlap;
       /* There is still a possibility we will find the need to do code
         conversion.  If that happens, we set this variable to 1 to
         give up on handling REPLACE in the optimized way.  */
@@ -4026,7 +3620,7 @@ variable `last-coding-system-used' to the coding system actually used.  */)
         match the text at the beginning of the buffer.  */
       while (1)
        {
-         int nread, bufpos;
+         EMACS_INT nread, bufpos;
 
          nread = emacs_read (fd, buffer, sizeof buffer);
          if (nread < 0)
@@ -4077,7 +3671,7 @@ variable `last-coding-system-used' to the coding system actually used.  */)
         already found that decoding is necessary, don't waste time.  */
       while (!giveup_match_end)
        {
-         int total_read, nread, bufpos, curpos, trial;
+         EMACS_INT total_read, nread, bufpos, curpos, trial;
 
          /* At what file position are we now scanning?  */
          curpos = XINT (end) - (ZV_BYTE - same_at_end);
@@ -4133,7 +3727,7 @@ variable `last-coding-system-used' to the coding system actually used.  */)
 
       if (! giveup_match_end)
        {
-         int temp;
+         EMACS_INT temp;
 
          /* We win!  We can handle REPLACE the optimized way.  */
 
@@ -4193,7 +3787,7 @@ variable `last-coding-system-used' to the coding system actually used.  */)
       EMACS_INT overlap;
       EMACS_INT bufpos;
       unsigned char *decoded;
-      int temp;
+      EMACS_INT temp;
       int this_count = SPECPDL_INDEX ();
       int multibyte = ! NILP (current_buffer->enable_multibyte_characters);
       Lisp_Object conversion_buffer;
@@ -4218,8 +3812,9 @@ 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) */
-         int trytry = min (total - how_much, READ_BUF_SIZE - unprocessed);
-         int this;
+         EMACS_INT trytry = min (total - how_much,
+                                 READ_BUF_SIZE - unprocessed);
+         EMACS_INT this;
 
          /* Allow quitting out of the actual I/O.  */
          immediate_quit = 1;
@@ -4247,6 +3842,11 @@ variable `last-coding-system-used' to the coding system actually used.  */)
       UNGCPRO;
       emacs_close (fd);
 
+      /* We should remove the unwind_protect calling
+        close_file_unwind, but other stuff has been added the stack,
+        so defer the removal till we reach the `handled' label.  */
+      deferred_remove_unwind_protect = 1;
+
       /* At this point, HOW_MUCH should equal TOTAL, or should be <= 0
         if we couldn't read the file.  */
 
@@ -4262,6 +3862,8 @@ variable `last-coding-system-used' to the coding system actually used.  */)
          coding.mode &= ~CODING_MODE_LAST_BLOCK;
        }
 
+      coding_system = CODING_ID_NAME (coding.id);
+      set_coding_system = 1;
       decoded = BUF_BEG_ADDR (XBUFFER (conversion_buffer));
       inserted = (BUF_Z_BYTE (XBUFFER (conversion_buffer))
                  - BUF_BEG_BYTE (XBUFFER (conversion_buffer)));
@@ -4279,7 +3881,6 @@ variable `last-coding-system-used' to the coding system actually used.  */)
 
       if (bufpos == inserted)
        {
-         specpdl_ptr--;
          /* Truncate the buffer to the size of the file.  */
          if (same_at_start == same_at_end)
            nochange = 1;
@@ -4417,13 +4018,13 @@ variable `last-coding-system-used' to the coding system actually used.  */)
   /* Here, we don't do code conversion in the loop.  It is done by
      decode_coding_gap after all data are read into the buffer.  */
   {
-    int gap_size = GAP_SIZE;
+    EMACS_INT gap_size = GAP_SIZE;
 
     while (how_much < total)
       {
        /* try is reserved in some compilers (Microsoft C) */
-       int trytry = min (total - how_much, READ_BUF_SIZE);
-       int this;
+       EMACS_INT trytry = min (total - how_much, READ_BUF_SIZE);
+       EMACS_INT this;
 
        if (not_regular)
          {
@@ -4629,6 +4230,11 @@ variable `last-coding-system-used' to the coding system actually used.  */)
 
  handled:
 
+  if (deferred_remove_unwind_protect)
+    /* If requested above, discard the unwind protect for closing the
+       file.  */
+    specpdl_ptr--;
+
   if (!NILP (visit))
     {
       if (!EQ (current_buffer->undo_list, Qt) && !nochange)
@@ -4637,11 +4243,12 @@ variable `last-coding-system-used' to the coding system actually used.  */)
       if (NILP (handler))
        {
          current_buffer->modtime = st.st_mtime;
+         current_buffer->modtime_size = st.st_size;
          current_buffer->filename = orig_filename;
        }
 
       SAVE_MODIFF = MODIFF;
-      current_buffer->auto_save_modified = MODIFF;
+      BUF_AUTOSAVE_MODIFF (current_buffer) = MODIFF;
       XSETFASTINT (current_buffer->save_length, Z - BEG);
 #ifdef CLASH_DETECTION
       if (NILP (handler))
@@ -4670,15 +4277,16 @@ variable `last-coding-system-used' to the coding system actually used.  */)
        }
     }
 
-  /* Decode file format */
+  /* Decode file format */
   if (inserted > 0)
     {
-      /* Don't run point motion or modification hooks when decoding. */
+      /* Don't run point motion or modification hooks when decoding.  */
       int count = SPECPDL_INDEX ();
+      EMACS_INT old_inserted = inserted;
       specbind (Qinhibit_point_motion_hooks, Qt);
       specbind (Qinhibit_modification_hooks, Qt);
 
-      /* Save old undo list and don't record undo for decoding. */
+      /* Save old undo list and don't record undo for decoding.  */
       old_undo = current_buffer->undo_list;
       current_buffer->undo_list = Qt;
 
@@ -4692,17 +4300,17 @@ variable `last-coding-system-used' to the coding system actually used.  */)
       else
        {
          /* 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 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 restore
-         `point' iff format-decode did not insert or delete any text.
-         Otherwise we leave `point' at point-min. */
-         int opoint = PT;
-         int opoint_byte = PT_BYTE;
-         int oinserted = ZV - BEGV;
+            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
+            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
+            restore `point' iff format-decode did not insert or delete
+            any text.  Otherwise we leave `point' at point-min.  */
+         EMACS_INT opoint = PT;
+         EMACS_INT opoint_byte = PT_BYTE;
+         EMACS_INT oinserted = ZV - BEGV;
          int ochars_modiff = CHARS_MODIFF;
 
          TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
@@ -4712,16 +4320,16 @@ variable `last-coding-system-used' to the coding system actually used.  */)
          if (ochars_modiff == CHARS_MODIFF)
            /* format_decode didn't modify buffer's characters => move
               point back to position before inserted text and leave
-              value of inserted alone. */
+              value of inserted alone.  */
            SET_PT_BOTH (opoint, opoint_byte);
          else
            /* format_decode modified buffer's characters => consider
-              entire buffer changed and leave point at point-min. */
+              entire buffer changed and leave point at point-min.  */
            inserted = XFASTINT (insval);
        }
 
       /* For consistency with format-decode call these now iff inserted > 0
-        (martin 2007-06-28) */
+        (martin 2007-06-28) */
       p = Vafter_insert_file_functions;
       while (CONSP (p))
        {
@@ -4736,10 +4344,11 @@ variable `last-coding-system-used' to the coding system actually used.  */)
            }
          else
            {
-             /* For the rationale of this see the comment on format-decode above. */
-             int opoint = PT;
-             int opoint_byte = PT_BYTE;
-             int oinserted = ZV - BEGV;
+             /* For the rationale of this see the comment on
+                format-decode above.  */
+             EMACS_INT opoint = PT;
+             EMACS_INT opoint_byte = PT_BYTE;
+             EMACS_INT oinserted = ZV - BEGV;
              int ochars_modiff = CHARS_MODIFF;
 
              TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
@@ -4751,12 +4360,12 @@ variable `last-coding-system-used' to the coding system actually used.  */)
                    /* after_insert_file_functions didn't modify
                       buffer's characters => move point back to
                       position before inserted text and leave value of
-                      inserted alone. */
+                      inserted alone.  */
                    SET_PT_BOTH (opoint, opoint_byte);
                  else
                    /* after_insert_file_functions did modify buffer's
                       characters => consider entire buffer changed and
-                      leave point at point-min. */
+                      leave point at point-min.  */
                    inserted = XFASTINT (insval);
                }
            }
@@ -4767,22 +4376,21 @@ variable `last-coding-system-used' to the coding system actually used.  */)
 
       if (NILP (visit))
        {
-         Lisp_Object lbeg, lend;
-         XSETINT (lbeg, PT);
-         XSETINT (lend, PT + inserted);
-         if (CONSP (old_undo))
+         current_buffer->undo_list = old_undo;
+         if (CONSP (old_undo) && inserted != old_inserted)
            {
+             /* Adjust the last undo record for the size change during
+                the format conversion.  */
              Lisp_Object tem = XCAR (old_undo);
-             if (CONSP (tem) && INTEGERP (XCAR (tem)) &&
-                 INTEGERP (XCDR (tem)) && EQ (XCAR (tem), lbeg))
-               /* In the non-visiting case record only the final insertion. */
-               current_buffer->undo_list =
-                 Fcons (Fcons (lbeg, lend), Fcdr (old_undo));
+             if (CONSP (tem) && INTEGERP (XCAR (tem))
+                 && INTEGERP (XCDR (tem))
+                 && XFASTINT (XCDR (tem)) == PT + old_inserted)
+               XSETCDR (tem, make_number (PT + inserted));
            }
        }
       else
        /* If undo_list was Qt before, keep it that way.
-          Otherwise start with an empty undo_list. */
+          Otherwise start with an empty undo_list.  */
        current_buffer->undo_list = EQ (old_undo, Qt) ? Qt : Qnil;
 
       unbind_to (count, Qnil);
@@ -4817,26 +4425,12 @@ variable `last-coding-system-used' to the coding system actually used.  */)
   RETURN_UNGCPRO (unbind_to (count, val));
 }
 \f
-static Lisp_Object build_annotations P_ ((Lisp_Object, Lisp_Object));
-
-/* If build_annotations switched buffers, switch back to BUF.
-   Kill the temporary buffer that was selected in the meantime.
-
-   Since this kill only the last temporary buffer, some buffers remain
-   not killed if build_annotations switched buffers more than once.
-   -- K.Handa */
+static Lisp_Object build_annotations (Lisp_Object, Lisp_Object);
 
 static Lisp_Object
-build_annotations_unwind (buf)
-     Lisp_Object buf;
+build_annotations_unwind (Lisp_Object arg)
 {
-  Lisp_Object tembuf;
-
-  if (XBUFFER (buf) == current_buffer)
-    return Qnil;
-  tembuf = Fcurrent_buffer ();
-  Fset_buffer (buf);
-  Fkill_buffer (tembuf);
+  Vwrite_region_annotation_buffers = arg;
   return Qnil;
 }
 
@@ -4983,7 +4577,10 @@ The optional seventh arg MUSTBENEW, if non-nil, insists on a check
 This does code conversion according to the value of
 `coding-system-for-write', `buffer-file-coding-system', or
 `file-coding-system-alist', and sets the variable
-`last-coding-system-used' to the coding system actually used.  */)
+`last-coding-system-used' to the coding system actually used.
+
+This calls `write-region-annotate-functions' at the start, and
+`write-region-post-annotation-function' at the end.  */)
      (start, end, filename, append, visit, lockname, mustbenew)
      Lisp_Object start, end, filename, append, visit, lockname, mustbenew;
 {
@@ -4994,9 +4591,6 @@ This does code conversion according to the value of
   struct stat st;
   int count = SPECPDL_INDEX ();
   int count1;
-#ifdef VMS
-  unsigned char *fname = 0;     /* If non-0, original filename (must rename) */
-#endif /* VMS */
   Lisp_Object handler;
   Lisp_Object visit_file;
   Lisp_Object annotations;
@@ -5070,7 +4664,9 @@ This does code conversion according to the value of
       Fwiden ();
     }
 
-  record_unwind_protect (build_annotations_unwind, Fcurrent_buffer ());
+  record_unwind_protect (build_annotations_unwind,
+                        Vwrite_region_annotation_buffers);
+  Vwrite_region_annotation_buffers = Fcons (Fcurrent_buffer (), Qnil);
   count1 = SPECPDL_INDEX ();
 
   given_buffer = current_buffer;
@@ -5106,16 +4702,7 @@ This does code conversion according to the value of
 
 #ifdef CLASH_DETECTION
   if (!auto_saving)
-    {
-#if 0  /* This causes trouble for GNUS.  */
-      /* If we've locked this file for some other buffer,
-        query before proceeding.  */
-      if (!visiting && EQ (Ffile_locked_p (lockname), Qt))
-       call2 (intern ("ask-user-about-lock"), filename, Vuser_login_name);
-#endif
-
-      lock_file (lockname);
-    }
+    lock_file (lockname);
 #endif /* CLASH_DETECTION */
 
   encoded_filename = ENCODE_FILE (filename);
@@ -5130,52 +4717,6 @@ This does code conversion according to the value of
 #endif /* not DOS_NT */
 
   if (desc < 0 && (NILP (append) || errno == ENOENT))
-#ifdef VMS
-    if (auto_saving)    /* Overwrite any previous version of autosave file */
-      {
-       vms_truncate (fn);      /* if fn exists, truncate to zero length */
-       desc = emacs_open (fn, O_RDWR, 0);
-       if (desc < 0)
-         desc = creat_copy_attrs (STRINGP (current_buffer->filename)
-                                  ? SDATA (current_buffer->filename) : 0,
-                                  fn);
-      }
-    else                /* Write to temporary name and rename if no errors */
-      {
-       Lisp_Object temp_name;
-       temp_name = Ffile_name_directory (filename);
-
-       if (!NILP (temp_name))
-         {
-           temp_name = Fmake_temp_name (concat2 (temp_name,
-                                                 build_string ("$$SAVE$$")));
-           fname = SDATA (filename);
-           fn = SDATA (temp_name);
-           desc = creat_copy_attrs (fname, fn);
-           if (desc < 0)
-             {
-               /* If we can't open the temporary file, try creating a new
-                  version of the original file.  VMS "creat" creates a
-                  new version rather than truncating an existing file. */
-               fn = fname;
-               fname = 0;
-               desc = creat (fn, 0666);
-#if 0 /* This can clobber an existing file and fail to replace it,
-        if the user runs out of space.  */
-               if (desc < 0)
-                 {
-                   /* We can't make a new version;
-                      try to truncate and rewrite existing version if any.  */
-                   vms_truncate (fn);
-                   desc = emacs_open (fn, O_RDWR, 0);
-                 }
-#endif
-             }
-         }
-       else
-         desc = creat (fn, 0666);
-      }
-#else /* not VMS */
 #ifdef DOS_NT
   desc = emacs_open (fn,
                     O_WRONLY | O_CREAT | buffer_file_type
@@ -5186,7 +4727,6 @@ This does code conversion according to the value of
                     | (EQ (mustbenew, Qexcl) ? O_EXCL : 0),
                     auto_saving ? auto_save_mode_bits : 0666);
 #endif /* not DOS_NT */
-#endif /* not VMS */
 
   if (desc < 0)
     {
@@ -5221,43 +4761,6 @@ This does code conversion according to the value of
 
   UNGCPRO;
 
-#ifdef VMS
-/*
- * Kludge Warning: The VMS C RTL likes to insert carriage returns
- * if we do writes that don't end with a carriage return. Furthermore
- * it cannot handle writes of more then 16K. The modified
- * version of "sys_write" in SYSDEP.C (see comment there) copes with
- * this EXCEPT for the last record (if it doesn't end with a carriage
- * return). This implies that if your buffer doesn't end with a carriage
- * return, you get one free... tough. However it also means that if
- * we make two calls to sys_write (a la the following code) you can
- * get one at the gap as well. The easiest way to fix this (honest)
- * is to move the gap to the next newline (or the end of the buffer).
- * Thus this change.
- *
- * Yech!
- */
-  if (GPT > BEG && GPT_ADDR[-1] != '\n')
-    move_gap (find_next_newline (GPT, 1));
-#else
-#if 0
-  /* The new encoding routine doesn't require the following.  */
-
-  /* Whether VMS or not, we must move the gap to the next of newline
-     when we must put designation sequences at beginning of line.  */
-  if (INTEGERP (start)
-      && coding.type == coding_type_iso2022
-      && coding.flags & CODING_FLAG_ISO_DESIGNATE_AT_BOL
-      && GPT > BEG && GPT_ADDR[-1] != '\n')
-    {
-      int opoint = PT, opoint_byte = PT_BYTE;
-      scan_newline (PT, PT_BYTE, ZV, ZV_BYTE, 1, 0);
-      move_gap_both (PT, PT_BYTE);
-      SET_PT_BOTH (opoint, opoint_byte);
-    }
-#endif
-#endif
-
   failure = 0;
   immediate_quit = 1;
 
@@ -5309,44 +4812,30 @@ This does code conversion according to the value of
     }
 #endif
 
-  /* Spurious "file has changed on disk" warnings have been
-     observed on Suns as well.
-     It seems that `close' can change the modtime, under nfs.
-
-     (This has supposedly been fixed in Sunos 4,
-     but who knows about all the other machines with NFS?)  */
-#if 0
-
-  /* On VMS, must do the stat after the close
-     since closing changes the modtime.  */
-#ifndef VMS
-  /* Recall that #if defined does not work on VMS.  */
-#define FOO
-  fstat (desc, &st);
-#endif
-#endif
-
   /* NFS can report a write failure now.  */
   if (emacs_close (desc) < 0)
     failure = 1, save_errno = errno;
 
-#ifdef VMS
-  /* If we wrote to a temporary name and had no errors, rename to real name. */
-  if (fname)
-    {
-      if (!failure)
-       failure = (rename (fn, fname) != 0), save_errno = errno;
-      fn = fname;
-    }
-#endif /* VMS */
-
-#ifndef FOO
   stat (fn, &st);
-#endif
+
   /* Discard the unwind protect for close_file_unwind.  */
   specpdl_ptr = specpdl + count1;
-  /* Restore the original current buffer.  */
-  visit_file = unbind_to (count, visit_file);
+
+  /* Call write-region-post-annotation-function. */
+  while (CONSP (Vwrite_region_annotation_buffers))
+    {
+      Lisp_Object buf = XCAR (Vwrite_region_annotation_buffers);
+      if (!NILP (Fbuffer_live_p (buf)))
+       {
+         Fset_buffer (buf);
+         if (FUNCTIONP (Vwrite_region_post_annotation_function))
+           call0 (Vwrite_region_post_annotation_function);
+       }
+      Vwrite_region_annotation_buffers
+       = XCDR (Vwrite_region_annotation_buffers);
+    }
+
+  unbind_to (count, Qnil);
 
 #ifdef CLASH_DETECTION
   if (!auto_saving)
@@ -5357,7 +4846,10 @@ This does code conversion according to the value of
      to avoid a "file has changed on disk" warning on
      next attempt to save.  */
   if (visiting)
-    current_buffer->modtime = st.st_mtime;
+    {
+      current_buffer->modtime = st.st_mtime;
+      current_buffer->modtime_size = st.st_size;
+    }
 
   if (failure)
     error ("IO error writing %s: %s", SDATA (filename),
@@ -5410,8 +4902,7 @@ DEFUN ("car-less-than-car", Fcar_less_than_car, Scar_less_than_car, 2, 2, 0,
    as save-excursion would do.  */
 
 static Lisp_Object
-build_annotations (start, end)
-     Lisp_Object start, end;
+build_annotations (Lisp_Object start, Lisp_Object end)
 {
   Lisp_Object annotations;
   Lisp_Object p, res;
@@ -5445,6 +4936,9 @@ build_annotations (start, end)
         been dealt with by this function.  */
       if (current_buffer != given_buffer)
        {
+         Vwrite_region_annotation_buffers
+           = Fcons (Fcurrent_buffer (),
+                    Vwrite_region_annotation_buffers);
          XSETFASTINT (start, BEGV);
          XSETFASTINT (end, ZV);
          annotations = Qnil;
@@ -5497,13 +4991,7 @@ build_annotations (start, end)
    The return value is negative in case of system call failure.  */
 
 static int
-a_write (desc, string, pos, nchars, annot, coding)
-     int desc;
-     Lisp_Object string;
-     register int nchars;
-     int pos;
-     Lisp_Object *annot;
-     struct coding_system *coding;
+a_write (int desc, Lisp_Object string, int pos, register int nchars, Lisp_Object *annot, struct coding_system *coding)
 {
   Lisp_Object tem;
   int nextpos;
@@ -5547,11 +5035,7 @@ a_write (desc, string, pos, nchars, annot, coding)
    are indexes to the string STRING.  */
 
 static int
-e_write (desc, string, start, end, coding)
-     int desc;
-     Lisp_Object string;
-     int start, end;
-     struct coding_system *coding;
+e_write (int desc, Lisp_Object string, int start, int end, struct coding_system *coding)
 {
   if (STRINGP (string))
     {
@@ -5663,11 +5147,13 @@ See Info node `(elisp)Modification Time' for more details.  */)
       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 == b->modtime + 1
-             || st.st_mtime == b->modtime - 1)))
+  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 == b->modtime + 1
+              || st.st_mtime == b->modtime - 1)))
+      && (st.st_size == b->modtime_size
+          || b->modtime_size < 0))
     return Qt;
   return Qnil;
 }
@@ -5679,6 +5165,7 @@ Next attempt to save will certainly not complain of a discrepancy.  */)
      ()
 {
   current_buffer->modtime = 0;
+  current_buffer->modtime_size = -1;
   return Qnil;
 }
 
@@ -5708,7 +5195,10 @@ An argument specifies the modification time value to use
      Lisp_Object time_list;
 {
   if (!NILP (time_list))
-    current_buffer->modtime = cons_to_long (time_list);
+    {
+      current_buffer->modtime = cons_to_long (time_list);
+      current_buffer->modtime_size = -1;
+    }
   else
     {
       register Lisp_Object filename;
@@ -5727,15 +5217,17 @@ An argument specifies the modification time value to use
       filename = ENCODE_FILE (filename);
 
       if (stat (SDATA (filename), &st) >= 0)
-       current_buffer->modtime = st.st_mtime;
+        {
+         current_buffer->modtime = st.st_mtime;
+          current_buffer->modtime_size = st.st_size;
+        }
     }
 
   return Qnil;
 }
 \f
 Lisp_Object
-auto_save_error (error)
-     Lisp_Object error;
+auto_save_error (Lisp_Object error)
 {
   Lisp_Object args[3], msg;
   int i, nbytes;
@@ -5771,7 +5263,7 @@ auto_save_error (error)
 }
 
 Lisp_Object
-auto_save_1 ()
+auto_save_1 (void)
 {
   struct stat st;
   Lisp_Object modes;
@@ -5791,14 +5283,14 @@ auto_save_1 ()
     }
 
   return
-    Fwrite_region (Qnil, Qnil,
-                  current_buffer->auto_save_file_name,
-                  Qnil, Qlambda, Qnil, Qnil);
+    Fwrite_region (Qnil, Qnil, current_buffer->auto_save_file_name, Qnil,
+                  NILP (Vauto_save_visited_file_name) ? Qlambda : Qt,
+                  Qnil, Qnil);
 }
 
 static Lisp_Object
-do_auto_save_unwind (arg)  /* used as unwind-protect function */
-     Lisp_Object arg;
+do_auto_save_unwind (Lisp_Object arg)  /* used as unwind-protect function */
+                     
 {
   FILE *stream = (FILE *) XSAVE_VALUE (arg)->pointer;
   auto_saving = 0;
@@ -5812,16 +5304,15 @@ do_auto_save_unwind (arg)  /* used as unwind-protect function */
 }
 
 static Lisp_Object
-do_auto_save_unwind_1 (value)  /* used as unwind-protect function */
-     Lisp_Object value;
+do_auto_save_unwind_1 (Lisp_Object value)  /* used as unwind-protect function */
+                       
 {
   minibuffer_auto_raise = XINT (value);
   return Qnil;
 }
 
 static Lisp_Object
-do_auto_save_make_dir (dir)
-     Lisp_Object dir;
+do_auto_save_make_dir (Lisp_Object dir)
 {
   Lisp_Object mode;
 
@@ -5831,8 +5322,7 @@ do_auto_save_make_dir (dir)
 }
 
 static Lisp_Object
-do_auto_save_eh (ignore)
-     Lisp_Object ignore;
+do_auto_save_eh (Lisp_Object ignore)
 {
   return Qnil;
 }
@@ -5965,7 +5455,7 @@ A non-nil CURRENT-ONLY argument means save only current buffer.  */)
           and file changed since last real save.  */
        if (STRINGP (b->auto_save_file_name)
            && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b)
-           && b->auto_save_modified < BUF_MODIFF (b)
+           && BUF_AUTOSAVE_MODIFF (b) < BUF_MODIFF (b)
            /* -1 means we've turned off autosaving for a while--see below.  */
            && XINT (b->save_length) >= 0
            && (do_handled_files
@@ -5981,8 +5471,10 @@ A non-nil CURRENT-ONLY argument means save only current buffer.  */)
                && EMACS_SECS (before_time) - b->auto_save_failure_time < 1200)
              continue;
 
-           if ((XFASTINT (b->save_length) * 10
-                > (BUF_Z (b) - BUF_BEG (b)) * 13)
+           set_buffer_internal (b);
+           if (NILP (Vauto_save_include_big_deletions)
+               && (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
@@ -6001,12 +5493,11 @@ A non-nil CURRENT-ONLY argument means save only current buffer.  */)
                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);
+           BUF_AUTOSAVE_MODIFF (b) = BUF_MODIFF (b);
            XSETFASTINT (current_buffer->save_length, Z - BEG);
            set_buffer_internal (old);
 
@@ -6051,7 +5542,9 @@ DEFUN ("set-buffer-auto-saved", Fset_buffer_auto_saved,
 No auto-save file will be written until the buffer changes again.  */)
      ()
 {
-  current_buffer->auto_save_modified = MODIFF;
+  /* FIXME: This should not be called in indirect buffers, since
+     they're not autosaved.  */
+  BUF_AUTOSAVE_MODIFF (current_buffer) = MODIFF;
   XSETFASTINT (current_buffer->save_length, Z - BEG);
   current_buffer->auto_save_failure_time = -1;
   return Qnil;
@@ -6074,7 +5567,9 @@ in the visited file.  If the buffer has no visited file,
 then any auto-save counts as "recent".  */)
      ()
 {
-  return (SAVE_MODIFF < current_buffer->auto_save_modified) ? Qt : Qnil;
+  /* FIXME: maybe we should return nil for indirect buffers since
+     they're never autosaved.  */
+  return (SAVE_MODIFF < BUF_AUTOSAVE_MODIFF (current_buffer) ? Qt : Qnil);
 }
 \f
 /* Reading and completing file names */
@@ -6083,10 +5578,10 @@ DEFUN ("next-read-file-uses-dialog-p", Fnext_read_file_uses_dialog_p,
        Snext_read_file_uses_dialog_p, 0, 0, 0,
        doc: /* Return t if a call to `read-file-name' will use a dialog.
 The return value is only relevant for a call to `read-file-name' that happens
-before any other event (mouse or keypress) is handeled.  */)
+before any other event (mouse or keypress) is handled.  */)
   ()
 {
-#if defined (USE_MOTIF) || defined (HAVE_NTGUI) || defined (USE_GTK) || defined (HAVE_CARBON)
+#if defined (USE_MOTIF) || defined (HAVE_NTGUI) || defined (USE_GTK)
   if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
       && use_dialog_box
       && use_file_dialog
@@ -6097,8 +5592,7 @@ before any other event (mouse or keypress) is handeled.  */)
 }
 
 Lisp_Object
-Fread_file_name (prompt, dir, default_filename, mustmatch, initial, predicate)
-     Lisp_Object prompt, dir, default_filename, mustmatch, initial, predicate;
+Fread_file_name (Lisp_Object prompt, Lisp_Object dir, Lisp_Object default_filename, Lisp_Object mustmatch, Lisp_Object initial, Lisp_Object predicate)
 {
   struct gcpro gcpro1, gcpro2;
   Lisp_Object args[7];
@@ -6116,50 +5610,44 @@ Fread_file_name (prompt, dir, default_filename, mustmatch, initial, predicate)
 
 \f
 void
-init_fileio_once ()
-{
-  /* Must be set before any path manipulation is performed.  */
-  XSETFASTINT (Vdirectory_sep_char, '/');
-}
-
-\f
-void
-syms_of_fileio ()
+syms_of_fileio (void)
 {
-  Qoperations = intern ("operations");
-  Qexpand_file_name = intern ("expand-file-name");
-  Qsubstitute_in_file_name = intern ("substitute-in-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_internal = intern ("make-directory-internal");
-  Qmake_directory = intern ("make-directory");
-  Qdelete_directory = intern ("delete-directory");
-  Qdelete_file = intern ("delete-file");
-  Qrename_file = intern ("rename-file");
-  Qadd_name_to_file = intern ("add-name-to-file");
-  Qmake_symbolic_link = intern ("make-symbolic-link");
-  Qfile_exists_p = intern ("file-exists-p");
-  Qfile_executable_p = intern ("file-executable-p");
-  Qfile_readable_p = intern ("file-readable-p");
-  Qfile_writable_p = intern ("file-writable-p");
-  Qfile_symlink_p = intern ("file-symlink-p");
-  Qaccess_file = intern ("access-file");
-  Qfile_directory_p = intern ("file-directory-p");
-  Qfile_regular_p = intern ("file-regular-p");
-  Qfile_accessible_directory_p = intern ("file-accessible-directory-p");
-  Qfile_modes = intern ("file-modes");
-  Qset_file_modes = intern ("set-file-modes");
-  Qset_file_times = intern ("set-file-times");
-  Qfile_newer_than_file_p = intern ("file-newer-than-file-p");
-  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");
-  Qauto_save_coding = intern ("auto-save-coding");
+  Qoperations = intern_c_string ("operations");
+  Qexpand_file_name = intern_c_string ("expand-file-name");
+  Qsubstitute_in_file_name = intern_c_string ("substitute-in-file-name");
+  Qdirectory_file_name = intern_c_string ("directory-file-name");
+  Qfile_name_directory = intern_c_string ("file-name-directory");
+  Qfile_name_nondirectory = intern_c_string ("file-name-nondirectory");
+  Qunhandled_file_name_directory = intern_c_string ("unhandled-file-name-directory");
+  Qfile_name_as_directory = intern_c_string ("file-name-as-directory");
+  Qcopy_file = intern_c_string ("copy-file");
+  Qmake_directory_internal = intern_c_string ("make-directory-internal");
+  Qmake_directory = intern_c_string ("make-directory");
+  Qdelete_directory_internal = intern_c_string ("delete-directory-internal");
+  Qdelete_file = intern_c_string ("delete-file");
+  Qrename_file = intern_c_string ("rename-file");
+  Qadd_name_to_file = intern_c_string ("add-name-to-file");
+  Qmake_symbolic_link = intern_c_string ("make-symbolic-link");
+  Qfile_exists_p = intern_c_string ("file-exists-p");
+  Qfile_executable_p = intern_c_string ("file-executable-p");
+  Qfile_readable_p = intern_c_string ("file-readable-p");
+  Qfile_writable_p = intern_c_string ("file-writable-p");
+  Qfile_symlink_p = intern_c_string ("file-symlink-p");
+  Qaccess_file = intern_c_string ("access-file");
+  Qfile_directory_p = intern_c_string ("file-directory-p");
+  Qfile_regular_p = intern_c_string ("file-regular-p");
+  Qfile_accessible_directory_p = intern_c_string ("file-accessible-directory-p");
+  Qfile_modes = intern_c_string ("file-modes");
+  Qset_file_modes = intern_c_string ("set-file-modes");
+  Qset_file_times = intern_c_string ("set-file-times");
+  Qfile_selinux_context = intern_c_string("file-selinux-context");
+  Qset_file_selinux_context = intern_c_string("set-file-selinux-context");
+  Qfile_newer_than_file_p = intern_c_string ("file-newer-than-file-p");
+  Qinsert_file_contents = intern_c_string ("insert-file-contents");
+  Qwrite_region = intern_c_string ("write-region");
+  Qverify_visited_file_modtime = intern_c_string ("verify-visited-file-modtime");
+  Qset_visited_file_modtime = intern_c_string ("set-visited-file-modtime");
+  Qauto_save_coding = intern_c_string ("auto-save-coding");
 
   staticpro (&Qoperations);
   staticpro (&Qexpand_file_name);
@@ -6172,7 +5660,7 @@ syms_of_fileio ()
   staticpro (&Qcopy_file);
   staticpro (&Qmake_directory_internal);
   staticpro (&Qmake_directory);
-  staticpro (&Qdelete_directory);
+  staticpro (&Qdelete_directory_internal);
   staticpro (&Qdelete_file);
   staticpro (&Qrename_file);
   staticpro (&Qadd_name_to_file);
@@ -6189,6 +5677,8 @@ syms_of_fileio ()
   staticpro (&Qfile_modes);
   staticpro (&Qset_file_modes);
   staticpro (&Qset_file_times);
+  staticpro (&Qfile_selinux_context);
+  staticpro (&Qset_file_selinux_context);
   staticpro (&Qfile_newer_than_file_p);
   staticpro (&Qinsert_file_contents);
   staticpro (&Qwrite_region);
@@ -6196,21 +5686,21 @@ syms_of_fileio ()
   staticpro (&Qset_visited_file_modtime);
   staticpro (&Qauto_save_coding);
 
-  Qfile_name_history = intern ("file-name-history");
+  Qfile_name_history = intern_c_string ("file-name-history");
   Fset (Qfile_name_history, Qnil);
   staticpro (&Qfile_name_history);
 
-  Qfile_error = intern ("file-error");
+  Qfile_error = intern_c_string ("file-error");
   staticpro (&Qfile_error);
-  Qfile_already_exists = intern ("file-already-exists");
+  Qfile_already_exists = intern_c_string ("file-already-exists");
   staticpro (&Qfile_already_exists);
-  Qfile_date_error = intern ("file-date-error");
+  Qfile_date_error = intern_c_string ("file-date-error");
   staticpro (&Qfile_date_error);
-  Qexcl = intern ("excl");
+  Qexcl = intern_c_string ("excl");
   staticpro (&Qexcl);
 
 #ifdef DOS_NT
-  Qfind_buffer_file_type = intern ("find-buffer-file-type");
+  Qfind_buffer_file_type = intern_c_string ("find-buffer-file-type");
   staticpro (&Qfind_buffer_file_type);
 #endif /* DOS_NT */
 
@@ -6230,39 +5720,30 @@ instead use `file-name-coding-system' to get a constant encoding
 of file names regardless of the current language environment.  */);
   Vdefault_file_name_coding_system = Qnil;
 
-  Qformat_decode = intern ("format-decode");
+  Qformat_decode = intern_c_string ("format-decode");
   staticpro (&Qformat_decode);
-  Qformat_annotate_function = intern ("format-annotate-function");
+  Qformat_annotate_function = intern_c_string ("format-annotate-function");
   staticpro (&Qformat_annotate_function);
-  Qafter_insert_file_set_coding = intern ("after-insert-file-set-coding");
+  Qafter_insert_file_set_coding = intern_c_string ("after-insert-file-set-coding");
   staticpro (&Qafter_insert_file_set_coding);
 
-  Qcar_less_than_car = intern ("car-less-than-car");
+  Qcar_less_than_car = intern_c_string ("car-less-than-car");
   staticpro (&Qcar_less_than_car);
 
   Fput (Qfile_error, Qerror_conditions,
-       list2 (Qfile_error, Qerror));
+       Fpurecopy (list2 (Qfile_error, Qerror)));
   Fput (Qfile_error, Qerror_message,
-       build_string ("File error"));
+       make_pure_c_string ("File error"));
 
   Fput (Qfile_already_exists, Qerror_conditions,
-       list3 (Qfile_already_exists, Qfile_error, Qerror));
+       Fpurecopy (list3 (Qfile_already_exists, Qfile_error, Qerror)));
   Fput (Qfile_already_exists, Qerror_message,
-       build_string ("File already exists"));
+       make_pure_c_string ("File already exists"));
 
   Fput (Qfile_date_error, Qerror_conditions,
-       list3 (Qfile_date_error, Qfile_error, Qerror));
+       Fpurecopy (list3 (Qfile_date_error, Qfile_error, Qerror)));
   Fput (Qfile_date_error, Qerror_message,
-       build_string ("Cannot set file date"));
-
-  DEFVAR_BOOL ("vms-stmlf-recfm", &vms_stmlf_recfm,
-              doc: /* *Non-nil means write new files with record format `stmlf'.
-nil means use format `var'.  This variable is meaningful only on VMS.  */);
-  vms_stmlf_recfm = 0;
-
-  DEFVAR_LISP ("directory-sep-char", &Vdirectory_sep_char,
-              doc: /* Directory separator character for built-in functions that return file names.
-The value is always ?/.  Don't use this variable, just use `/'.  */);
+       make_pure_c_string ("Cannot set file date"));
 
   DEFVAR_LISP ("file-name-handler-alist", &Vfile_name_handler_alist,
               doc: /* *Alist of elements (REGEXP . HANDLER) for file names handled specially.
@@ -6310,15 +5791,36 @@ for `write-region'.  The function should return a list of pairs
 of the form (POSITION . STRING), consisting of strings to be effectively
 inserted at the specified positions of the file being written (1 means to
 insert before the first byte written).  The POSITIONs must be sorted into
-increasing order.  If there are several functions in the list, the several
-lists are merged destructively.  Alternatively, the function can return
-with a different buffer current; in that case it should pay attention
-to the annotations returned by previous functions and listed in
-`write-region-annotations-so-far'.*/);
+increasing order.
+
+If there are several annotation functions, the lists returned by these
+functions are merged destructively.  As each annotation function runs,
+the variable `write-region-annotations-so-far' contains a list of all
+annotations returned by previous annotation functions.
+
+An annotation function can return with a different buffer current.
+Doing so removes the annotations returned by previous functions, and
+resets START and END to `point-min' and `point-max' of the new buffer.
+
+After `write-region' completes, Emacs calls the function stored in
+`write-region-post-annotation-function', once for each buffer that was
+current when building the annotations (i.e., at least once), with that
+buffer current.  */);
   Vwrite_region_annotate_functions = Qnil;
   staticpro (&Qwrite_region_annotate_functions);
   Qwrite_region_annotate_functions
-    = intern ("write-region-annotate-functions");
+    = intern_c_string ("write-region-annotate-functions");
+
+  DEFVAR_LISP ("write-region-post-annotation-function",
+              &Vwrite_region_post_annotation_function,
+              doc: /* Function to call after `write-region' completes.
+The function is called with no arguments.  If one or more of the
+annotation functions in `write-region-annotate-functions' changed the
+current buffer, the function stored in this variable is called for
+each of those additional buffers as well, in addition to the original
+buffer.  The relevant buffer is current during each function call.  */);
+  Vwrite_region_post_annotation_function = Qnil;
+  staticpro (&Vwrite_region_annotation_buffers);
 
   DEFVAR_LISP ("write-region-annotations-so-far",
               &Vwrite_region_annotations_so_far,
@@ -6343,6 +5845,18 @@ shortly after Emacs reads your `.emacs' file, if you have not yet given it
 a non-nil value.  */);
   Vauto_save_list_file_name = Qnil;
 
+  DEFVAR_LISP ("auto-save-visited-file-name", &Vauto_save_visited_file_name,
+              doc: /* Non-nil says auto-save a buffer in the file it is visiting, when practical.
+Normally auto-save files are written under other names.  */);
+  Vauto_save_visited_file_name = Qnil;
+
+  DEFVAR_LISP ("auto-save-include-big-deletions", &Vauto_save_include_big_deletions,
+              doc: /* If non-nil, auto-save even if a large part of the text is deleted.
+If nil, deleting a substantial portion of the text disables auto-save
+in the buffer; this is the default behavior, because the auto-save
+file is usually more useful if it contains the deleted text.  */);
+  Vauto_save_include_big_deletions = Qnil;
+
 #ifdef HAVE_FSYNC
   DEFVAR_BOOL ("write-region-inhibit-fsync", &write_region_inhibit_fsync,
               doc: /* *Non-nil means don't call fsync in `write-region'.
@@ -6353,11 +5867,18 @@ A non-nil value may result in data loss!  */);
 
   DEFVAR_BOOL ("delete-by-moving-to-trash", &delete_by_moving_to_trash,
                doc: /* Specifies whether to use the system's trash can.
-When non-nil, the function `move-file-to-trash' will be used by
-`delete-file' and `delete-directory'.  */);
+When non-nil, certain file deletion commands use the function
+`move-file-to-trash' instead of deleting files outright.
+This includes interactive calls to `delete-file' and
+`delete-directory' and the Dired deletion commands.  */);
   delete_by_moving_to_trash = 0;
-  Qmove_file_to_trash = intern ("move-file-to-trash");
+  Qdelete_by_moving_to_trash = intern_c_string ("delete-by-moving-to-trash");
+  Qmove_file_to_trash = intern_c_string ("move-file-to-trash");
   staticpro (&Qmove_file_to_trash);
+  Qcopy_directory = intern_c_string ("copy-directory");
+  staticpro (&Qcopy_directory);
+  Qdelete_directory = intern_c_string ("delete-directory");
+  staticpro (&Qdelete_directory);
 
   defsubr (&Sfind_file_name_handler);
   defsubr (&Sfile_name_directory);
@@ -6370,14 +5891,11 @@ When non-nil, the function `move-file-to-trash' will be used by
   defsubr (&Ssubstitute_in_file_name);
   defsubr (&Scopy_file);
   defsubr (&Smake_directory_internal);
-  defsubr (&Sdelete_directory);
+  defsubr (&Sdelete_directory_internal);
   defsubr (&Sdelete_file);
   defsubr (&Srename_file);
   defsubr (&Sadd_name_to_file);
   defsubr (&Smake_symbolic_link);
-#ifdef VMS
-  defsubr (&Sdefine_logical_name);
-#endif /* VMS */
   defsubr (&Sfile_name_absolute_p);
   defsubr (&Sfile_exists_p);
   defsubr (&Sfile_executable_p);
@@ -6391,6 +5909,8 @@ When non-nil, the function `move-file-to-trash' will be used by
   defsubr (&Sfile_modes);
   defsubr (&Sset_file_modes);
   defsubr (&Sset_file_times);
+  defsubr (&Sfile_selinux_context);
+  defsubr (&Sset_file_selinux_context);
   defsubr (&Sset_default_file_modes);
   defsubr (&Sdefault_file_modes);
   defsubr (&Sfile_newer_than_file_p);