]> code.delx.au - gnu-emacs/blobdiff - src/fileio.c
Rework C source files to avoid ^(
[gnu-emacs] / src / fileio.c
index d4e12cbe277fb130f6a71c7c9c2ec39d28da3ffa..dfab3de9e94b36633aefe6253e93dcdd57bfdb3a 100644 (file)
@@ -1,13 +1,13 @@
 /* File IO for GNU Emacs.
 
-Copyright (C) 1985-1988, 1993-2015 Free Software Foundation, Inc.
+Copyright (C) 1985-1988, 1993-2016 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -36,14 +36,14 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <selinux/context.h>
 #endif
 
-#ifdef HAVE_ACL_SET_FILE
+#if USE_ACL && defined HAVE_ACL_SET_FILE
 #include <sys/acl.h>
 #endif
 
 #include <c-ctype.h>
 
 #include "lisp.h"
-#include "intervals.h"
+#include "composite.h"
 #include "character.h"
 #include "buffer.h"
 #include "coding.h"
@@ -51,7 +51,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "blockinput.h"
 #include "region-cache.h"
 #include "frame.h"
-#include "dispextern.h"
 
 #ifdef WINDOWSNT
 #define NOMINMAX 1
@@ -210,6 +209,22 @@ report_file_error (char const *string, Lisp_Object name)
   report_file_errno (string, name, errno);
 }
 
+/* Like report_file_error, but reports a file-notify-error instead.  */
+
+void
+report_file_notify_error (const char *string, Lisp_Object name)
+{
+  Lisp_Object data = CONSP (name) || NILP (name) ? name : list1 (name);
+  synchronize_system_messages_locale ();
+  char *str = strerror (errno);
+  Lisp_Object errstring
+    = code_convert_string_norecord (build_unibyte_string (str),
+                                   Vlocale_coding_system, 0);
+  Lisp_Object errdata = Fcons (errstring, data);
+
+  xsignal (Qfile_notify_error, Fcons (build_string (string), errdata));
+}
+
 void
 close_file_unwind (int fd)
 {
@@ -435,7 +450,7 @@ DEFUN ("unhandled-file-name-directory", Funhandled_file_name_directory,
 A `directly usable' directory name is one that may be used without the
 intervention of any file handler.
 If FILENAME is a directly usable file itself, return
-\(file-name-directory FILENAME).
+\(file-name-as-directory FILENAME).
 If FILENAME refers to a file which is not accessible from a local process,
 then this should return nil.
 The `call-process' and `start-process' functions use this function to
@@ -454,7 +469,7 @@ get a current directory to run processes in.  */)
       return STRINGP (handled_name) ? handled_name : Qnil;
     }
 
-  return Ffile_name_directory (filename);
+  return Ffile_name_as_directory (filename);
 }
 
 /* Maximum number of bytes that DST will be longer than SRC
@@ -867,11 +882,7 @@ filesystem tree, not (expand-file-name ".."  dirname).  */)
 #endif /* not DOS_NT */
        )
       {
-       struct gcpro gcpro1;
-
-       GCPRO1 (name);
        default_directory = Fexpand_file_name (default_directory, Qnil);
-       UNGCPRO;
       }
   }
   multibyte = STRING_MULTIBYTE (name);
@@ -1793,7 +1804,6 @@ barf_or_query_if_file_exists (Lisp_Object absname, bool known_to_exist,
 {
   Lisp_Object tem, encoded_filename;
   struct stat statbuf;
-  struct gcpro gcpro1;
 
   encoded_filename = ENCODE_FILE (absname);
 
@@ -1810,14 +1820,12 @@ barf_or_query_if_file_exists (Lisp_Object absname, bool known_to_exist,
       if (! interactive)
        xsignal2 (Qfile_already_exists,
                  build_string ("File already exists"), absname);
-      GCPRO1 (absname);
-      tem = format2 ("File %s already exists; %s anyway? ",
-                    absname, build_string (querystring));
+      AUTO_STRING (format, "File %s already exists; %s anyway? ");
+      tem = CALLN (Fformat, format, absname, build_string (querystring));
       if (quick)
        tem = call1 (intern ("y-or-n-p"), tem);
       else
        tem = do_yes_or_no_p (tem);
-      UNGCPRO;
       if (NILP (tem))
        xsignal2 (Qfile_already_exists,
                  build_string ("File already exists"), absname);
@@ -1858,7 +1866,6 @@ permissions.  */)
    Lisp_Object preserve_permissions)
 {
   Lisp_Object handler;
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
   ptrdiff_t count = SPECPDL_INDEX ();
   Lisp_Object encoded_file, encoded_newname;
 #if HAVE_LIBSELINUX
@@ -1871,13 +1878,10 @@ permissions.  */)
   bool already_exists = false;
   mode_t new_mask;
   int ifd, ofd;
-  int n;
-  char buf[16 * 1024];
   struct stat st;
 #endif
 
   encoded_file = encoded_newname = Qnil;
-  GCPRO4 (file, newname, encoded_file, encoded_newname);
   CHECK_STRING (file);
   CHECK_STRING (newname);
 
@@ -1895,9 +1899,9 @@ permissions.  */)
   if (NILP (handler))
     handler = Ffind_file_name_handler (newname, Qcopy_file);
   if (!NILP (handler))
-    RETURN_UNGCPRO (call7 (handler, Qcopy_file, file, newname,
-                          ok_if_already_exists, keep_time, preserve_uid_gid,
-                          preserve_permissions));
+    return call7 (handler, Qcopy_file, file, newname,
+                 ok_if_already_exists, keep_time, preserve_uid_gid,
+                 preserve_permissions);
 
   encoded_file = ENCODE_FILE (file);
   encoded_newname = ENCODE_FILE (newname);
@@ -1974,6 +1978,8 @@ permissions.  */)
 
   record_unwind_protect_int (close_file_unwind, ofd);
 
+  off_t oldsize = 0, newsize = 0;
+
   if (already_exists)
     {
       struct stat out_st;
@@ -1982,15 +1988,31 @@ permissions.  */)
       if (st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino)
        report_file_errno ("Input and output files are the same",
                           list2 (file, newname), 0);
-      if (ftruncate (ofd, 0) != 0)
-       report_file_error ("Truncating output file", newname);
+      if (S_ISREG (out_st.st_mode))
+       oldsize = out_st.st_size;
     }
 
   immediate_quit = 1;
   QUIT;
-  while ((n = emacs_read (ifd, buf, sizeof buf)) > 0)
-    if (emacs_write_sig (ofd, buf, n) != n)
-      report_file_error ("Write error", newname);
+  while (true)
+    {
+      char buf[MAX_ALLOCA];
+      ptrdiff_t n = emacs_read (ifd, buf, sizeof buf);
+      if (n < 0)
+       report_file_error ("Read error", file);
+      if (n == 0)
+       break;
+      if (emacs_write_sig (ofd, buf, n) != n)
+       report_file_error ("Write error", newname);
+      newsize += n;
+    }
+
+  /* Truncate any existing output file after writing the data.  This
+     is more likely to work than truncation before writing, if the
+     file system is out of space or the user is over disk quota.  */
+  if (newsize < oldsize && ftruncate (ofd, newsize) != 0)
+    report_file_error ("Truncating output file", newname);
+
   immediate_quit = 0;
 
 #ifndef MSDOS
@@ -2079,7 +2101,6 @@ permissions.  */)
   /* Discard the unwind protects.  */
   specpdl_ptr = specpdl + count;
 
-  UNGCPRO;
   return Qnil;
 }
 \f
@@ -2149,15 +2170,12 @@ With a prefix argument, TRASH is nil.  */)
 {
   Lisp_Object handler;
   Lisp_Object encoded_file;
-  struct gcpro gcpro1;
 
-  GCPRO1 (filename);
   if (!NILP (Ffile_directory_p (filename))
       && NILP (Ffile_symlink_p (filename)))
     xsignal2 (Qfile_error,
              build_string ("Removing old name: is a directory"),
              filename);
-  UNGCPRO;
   filename = Fexpand_file_name (filename, Qnil);
 
   handler = Ffind_file_name_handler (filename, Qdelete_file);
@@ -2204,11 +2222,9 @@ This is what happens in interactive use with M-x.  */)
   (Lisp_Object file, Lisp_Object newname, Lisp_Object ok_if_already_exists)
 {
   Lisp_Object handler;
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
   Lisp_Object encoded_file, encoded_newname, symlink_target;
 
   symlink_target = encoded_file = encoded_newname = Qnil;
-  GCPRO5 (file, newname, encoded_file, encoded_newname, symlink_target);
   CHECK_STRING (file);
   CHECK_STRING (newname);
   file = Fexpand_file_name (file, Qnil);
@@ -2234,8 +2250,8 @@ This is what happens in interactive use with M-x.  */)
   if (NILP (handler))
     handler = Ffind_file_name_handler (newname, Qrename_file);
   if (!NILP (handler))
-    RETURN_UNGCPRO (call4 (handler, Qrename_file,
-                          file, newname, ok_if_already_exists));
+    return call4 (handler, Qrename_file,
+                 file, newname, ok_if_already_exists);
 
   encoded_file = ENCODE_FILE (file);
   encoded_newname = ENCODE_FILE (newname);
@@ -2281,7 +2297,7 @@ This is what happens in interactive use with M-x.  */)
       else
        report_file_errno ("Renaming", list2 (file, newname), rename_errno);
     }
-  UNGCPRO;
+
   return Qnil;
 }
 
@@ -2296,9 +2312,7 @@ This is what happens in interactive use with M-x.  */)
 {
   Lisp_Object handler;
   Lisp_Object encoded_file, encoded_newname;
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
 
-  GCPRO4 (file, newname, encoded_file, encoded_newname);
   encoded_file = encoded_newname = Qnil;
   CHECK_STRING (file);
   CHECK_STRING (newname);
@@ -2313,15 +2327,15 @@ This is what happens in interactive use with M-x.  */)
      call the corresponding file handler.  */
   handler = Ffind_file_name_handler (file, Qadd_name_to_file);
   if (!NILP (handler))
-    RETURN_UNGCPRO (call4 (handler, Qadd_name_to_file, file,
-                          newname, ok_if_already_exists));
+    return call4 (handler, Qadd_name_to_file, file,
+                 newname, ok_if_already_exists);
 
   /* If the new name has special constructs in it,
      call the corresponding file handler.  */
   handler = Ffind_file_name_handler (newname, Qadd_name_to_file);
   if (!NILP (handler))
-    RETURN_UNGCPRO (call4 (handler, Qadd_name_to_file, file,
-                          newname, ok_if_already_exists));
+    return call4 (handler, Qadd_name_to_file, file,
+                 newname, ok_if_already_exists);
 
   encoded_file = ENCODE_FILE (file);
   encoded_newname = ENCODE_FILE (newname);
@@ -2338,86 +2352,77 @@ This is what happens in interactive use with M-x.  */)
       report_file_errno ("Adding new name", list2 (file, newname), link_errno);
     }
 
-  UNGCPRO;
   return Qnil;
 }
 
 DEFUN ("make-symbolic-link", Fmake_symbolic_link, Smake_symbolic_link, 2, 3,
        "FMake symbolic link to file: \nGMake symbolic link to file %s: \np",
-       doc: /* Make a symbolic link to FILENAME, named LINKNAME.
+       doc: /* Make a symbolic link to TARGET, named LINKNAME.
 Both args must be strings.
 Signals a `file-already-exists' error if a file LINKNAME already exists
 unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.
 A number as third arg means request confirmation if LINKNAME already exists.
 This happens for interactive use with M-x.  */)
-  (Lisp_Object filename, Lisp_Object linkname, Lisp_Object ok_if_already_exists)
+  (Lisp_Object target, Lisp_Object linkname, Lisp_Object ok_if_already_exists)
 {
   Lisp_Object handler;
-  Lisp_Object encoded_filename, encoded_linkname;
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+  Lisp_Object encoded_target, encoded_linkname;
 
-  GCPRO4 (filename, linkname, encoded_filename, encoded_linkname);
-  encoded_filename = encoded_linkname = Qnil;
-  CHECK_STRING (filename);
+  encoded_target = encoded_linkname = Qnil;
+  CHECK_STRING (target);
   CHECK_STRING (linkname);
   /* If the link target has a ~, we must expand it to get
      a truly valid file name.  Otherwise, do not expand;
      we want to permit links to relative file names.  */
-  if (SREF (filename, 0) == '~')
-    filename = Fexpand_file_name (filename, Qnil);
+  if (SREF (target, 0) == '~')
+    target = Fexpand_file_name (target, Qnil);
 
   if (!NILP (Ffile_directory_p (linkname)))
-    linkname = Fexpand_file_name (Ffile_name_nondirectory (filename), linkname);
+    linkname = Fexpand_file_name (Ffile_name_nondirectory (target), linkname);
   else
     linkname = Fexpand_file_name (linkname, Qnil);
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename, Qmake_symbolic_link);
+  handler = Ffind_file_name_handler (target, Qmake_symbolic_link);
   if (!NILP (handler))
-    RETURN_UNGCPRO (call4 (handler, Qmake_symbolic_link, filename,
-                          linkname, ok_if_already_exists));
+    return call4 (handler, Qmake_symbolic_link, target,
+                 linkname, ok_if_already_exists);
 
   /* If the new link name has special constructs in it,
      call the corresponding file handler.  */
   handler = Ffind_file_name_handler (linkname, Qmake_symbolic_link);
   if (!NILP (handler))
-    RETURN_UNGCPRO (call4 (handler, Qmake_symbolic_link, filename,
-                          linkname, ok_if_already_exists));
+    return call4 (handler, Qmake_symbolic_link, target,
+                 linkname, ok_if_already_exists);
 
-  encoded_filename = ENCODE_FILE (filename);
+  encoded_target = ENCODE_FILE (target);
   encoded_linkname = ENCODE_FILE (linkname);
 
   if (NILP (ok_if_already_exists)
       || INTEGERP (ok_if_already_exists))
     barf_or_query_if_file_exists (linkname, false, "make it a link",
                                  INTEGERP (ok_if_already_exists), false);
-  if (symlink (SSDATA (encoded_filename), SSDATA (encoded_linkname)) < 0)
+  if (symlink (SSDATA (encoded_target), SSDATA (encoded_linkname)) < 0)
     {
       /* If we didn't complain already, silently delete existing file.  */
       int symlink_errno;
       if (errno == EEXIST)
        {
          unlink (SSDATA (encoded_linkname));
-         if (symlink (SSDATA (encoded_filename), SSDATA (encoded_linkname))
+         if (symlink (SSDATA (encoded_target), SSDATA (encoded_linkname))
              >= 0)
-           {
-             UNGCPRO;
-             return Qnil;
-           }
+           return Qnil;
        }
       if (errno == ENOSYS)
-       {
-         UNGCPRO;
-         xsignal1 (Qfile_error,
-                   build_string ("Symbolic links are not supported"));
-       }
+       xsignal1 (Qfile_error,
+                 build_string ("Symbolic links are not supported"));
 
       symlink_errno = errno;
-      report_file_errno ("Making symbolic link", list2 (filename, linkname),
+      report_file_errno ("Making symbolic link", list2 (target, linkname),
                         symlink_errno);
     }
-  UNGCPRO;
+
   return Qnil;
 }
 
@@ -2695,10 +2700,18 @@ bool
 file_accessible_directory_p (Lisp_Object file)
 {
 #ifdef DOS_NT
-  /* There's no need to test whether FILE is searchable, as the
-     searchable/executable bit is invented on DOS_NT platforms.  */
+# ifdef WINDOWSNT
+  /* We need a special-purpose test because (a) NTFS security data is
+     not reflected in Posix-style mode bits, and (b) the trick with
+     accessing "DIR/.", used below on Posix hosts, doesn't work on
+     Windows, because "DIR/." is normalized to just "DIR" before
+     hitting the disk.  */
+  return (SBYTES (file) == 0
+         || w32_accessible_directory_p (SSDATA (file), SBYTES (file)));
+# else /* MSDOS */
   return file_directory_p (SSDATA (file));
-#else
+# endif         /* MSDOS */
+#else   /* !DOS_NT */
   /* On POSIXish platforms, use just one system call; this avoids a
      race and is typically faster.  */
   const char *data = SSDATA (file);
@@ -2731,7 +2744,7 @@ file_accessible_directory_p (Lisp_Object file)
   SAFE_FREE ();
   errno = saved_errno;
   return ok;
-#endif
+#endif /* !DOS_NT */
 }
 
 DEFUN ("file-regular-p", Ffile_regular_p, Sfile_regular_p, 1, 1, 0,
@@ -2924,16 +2937,17 @@ Return nil if file does not exist or is not accessible, or if Emacs
 was unable to determine the ACL entries.  */)
   (Lisp_Object filename)
 {
+#if USE_ACL
   Lisp_Object absname;
   Lisp_Object handler;
-#ifdef HAVE_ACL_SET_FILE
+# ifdef HAVE_ACL_SET_FILE
   acl_t acl;
   Lisp_Object acl_string;
   char *str;
-# ifndef HAVE_ACL_TYPE_EXTENDED
+#  ifndef HAVE_ACL_TYPE_EXTENDED
   acl_type_t ACL_TYPE_EXTENDED = ACL_TYPE_ACCESS;
+#  endif
 # endif
-#endif
 
   absname = expand_and_dir_to_file (filename,
                                    BVAR (current_buffer, directory));
@@ -2944,7 +2958,7 @@ was unable to determine the ACL entries.  */)
   if (!NILP (handler))
     return call2 (handler, Qfile_acl, absname);
 
-#ifdef HAVE_ACL_SET_FILE
+# ifdef HAVE_ACL_SET_FILE
   absname = ENCODE_FILE (absname);
 
   acl = acl_get_file (SSDATA (absname), ACL_TYPE_EXTENDED);
@@ -2963,6 +2977,7 @@ was unable to determine the ACL entries.  */)
   acl_free (acl);
 
   return acl_string;
+# endif
 #endif
 
   return Qnil;
@@ -2980,13 +2995,14 @@ Setting ACL for local files requires Emacs to be built with ACL
 support.  */)
   (Lisp_Object filename, Lisp_Object acl_string)
 {
+#if USE_ACL
   Lisp_Object absname;
   Lisp_Object handler;
-#ifdef HAVE_ACL_SET_FILE
+# ifdef HAVE_ACL_SET_FILE
   Lisp_Object encoded_absname;
   acl_t acl;
   bool fail;
-#endif
+# endif
 
   absname = Fexpand_file_name (filename, BVAR (current_buffer, directory));
 
@@ -2996,7 +3012,7 @@ support.  */)
   if (!NILP (handler))
     return call3 (handler, Qset_file_acl, absname, acl_string);
 
-#ifdef HAVE_ACL_SET_FILE
+# ifdef HAVE_ACL_SET_FILE
   if (STRINGP (acl_string))
     {
       acl = acl_from_text (SSDATA (acl_string));
@@ -3017,6 +3033,7 @@ support.  */)
       acl_free (acl);
       return fail ? Qnil : Qt;
     }
+# endif
 #endif
 
   return Qnil;
@@ -3165,16 +3182,13 @@ otherwise, if FILE2 does not exist, the answer is t.  */)
   Lisp_Object absname1, absname2;
   struct stat st1, st2;
   Lisp_Object handler;
-  struct gcpro gcpro1, gcpro2;
 
   CHECK_STRING (file1);
   CHECK_STRING (file2);
 
   absname1 = Qnil;
-  GCPRO2 (absname1, file2);
   absname1 = expand_and_dir_to_file (file1, BVAR (current_buffer, directory));
   absname2 = expand_and_dir_to_file (file2, BVAR (current_buffer, directory));
-  UNGCPRO;
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
@@ -3184,10 +3198,8 @@ otherwise, if FILE2 does not exist, the answer is t.  */)
   if (!NILP (handler))
     return call3 (handler, Qfile_newer_than_file_p, absname1, absname2);
 
-  GCPRO2 (absname1, absname2);
   absname1 = ENCODE_FILE (absname1);
   absname2 = ENCODE_FILE (absname2);
-  UNGCPRO;
 
   if (stat (SSDATA (absname1), &st1) < 0)
     return Qnil;
@@ -3390,7 +3402,6 @@ by calling `format-decode', which see.  */)
   off_t beg_offset, end_offset;
   int unprocessed;
   ptrdiff_t count = SPECPDL_INDEX ();
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
   Lisp_Object handler, val, insval, orig_filename, old_undo;
   Lisp_Object p;
   ptrdiff_t total = 0;
@@ -3430,8 +3441,6 @@ by calling `format-decode', which see.  */)
   orig_filename = Qnil;
   old_undo = Qnil;
 
-  GCPRO5 (filename, val, p, orig_filename, old_undo);
-
   CHECK_STRING (filename);
   filename = Fexpand_file_name (filename, Qnil);
 
@@ -3464,7 +3473,11 @@ by calling `format-decode', which see.  */)
       mtime = time_error_value (save_errno);
       st.st_size = -1;
       if (!NILP (Vcoding_system_for_read))
-       Fset (Qbuffer_file_coding_system, Vcoding_system_for_read);
+       {
+         /* Don't let invalid values into buffer-file-coding-system.  */
+         CHECK_CODING_SYSTEM (Vcoding_system_for_read);
+         Fset (Qbuffer_file_coding_system, Vcoding_system_for_read);
+       }
       goto notfound;
     }
 
@@ -3882,7 +3895,6 @@ by calling `format-decode', which see.  */)
       bool multibyte
        = ! NILP (BVAR (current_buffer, enable_multibyte_characters));
       Lisp_Object conversion_buffer;
-      struct gcpro gcpro1;
 
       conversion_buffer = code_conversion_save (1, multibyte);
 
@@ -3895,7 +3907,6 @@ by calling `format-decode', which see.  */)
       inserted = 0;            /* Bytes put into CONVERSION_BUFFER so far.  */
       unprocessed = 0;         /* Bytes not processed in previous loop.  */
 
-      GCPRO1 (conversion_buffer);
       while (1)
        {
          /* Read at most READ_BUF_SIZE bytes at a time, to allow
@@ -3919,7 +3930,7 @@ by calling `format-decode', which see.  */)
          if (coding.carryover_bytes > 0)
            memcpy (read_buf, coding.carryover, unprocessed);
        }
-      UNGCPRO;
+
       if (this < 0)
        report_file_error ("Read error", orig_filename);
       emacs_close (fd);
@@ -4165,7 +4176,7 @@ by calling `format-decode', which see.  */)
       Vdeactivate_mark = old_Vdeactivate_mark;
     }
   else
-    Vdeactivate_mark = Qt;
+    Fset (Qdeactivate_mark, Qt);
 
   emacs_close (fd);
   clear_unwind_protect (fd_index);
@@ -4256,9 +4267,14 @@ by calling `format-decode', which see.  */)
       if (CODING_FOR_UNIBYTE (&coding)
          /* Can't do this if part of the buffer might be preserved.  */
          && NILP (replace))
-       /* Visiting a file with these coding system makes the buffer
-          unibyte.  */
-       bset_enable_multibyte_characters (current_buffer, Qnil);
+       {
+         /* Visiting a file with these coding system makes the buffer
+            unibyte.  */
+         if (inserted > 0)
+           bset_enable_multibyte_characters (current_buffer, Qnil);
+         else
+           Fset_buffer_multibyte (Qnil);
+       }
     }
 
   coding.dst_multibyte = ! NILP (BVAR (current_buffer, enable_multibyte_characters));
@@ -4491,7 +4507,7 @@ by calling `format-decode', which see.  */)
   if (NILP (val))
     val = list2 (orig_filename, make_number (inserted));
 
-  RETURN_UNGCPRO (unbind_to (count, val));
+  return unbind_to (count, val);
 }
 \f
 static Lisp_Object build_annotations (Lisp_Object, Lisp_Object);
@@ -4565,7 +4581,7 @@ choose_write_coding_system (Lisp_Object start, Lisp_Object end, Lisp_Object file
       if (NILP (val))
        {
          /* If we still have not decided a coding system, use the
-            default value of buffer-file-coding-system.  */
+            current buffer's value of buffer-file-coding-system.  */
          val = BVAR (current_buffer, buffer_file_coding_system);
          using_default_coding = 1;
        }
@@ -4574,6 +4590,7 @@ choose_write_coding_system (Lisp_Object start, Lisp_Object end, Lisp_Object file
        {
          Lisp_Object spec, attrs;
 
+         CHECK_CODING_SYSTEM (val);
          CHECK_CODING_SYSTEM_GET_SPEC (val, spec);
          attrs = AREF (spec, 0);
          if (EQ (CODING_ATTR_TYPE (attrs), Qraw_text))
@@ -4582,17 +4599,27 @@ choose_write_coding_system (Lisp_Object start, Lisp_Object end, Lisp_Object file
 
       if (!force_raw_text
          && !NILP (Ffboundp (Vselect_safe_coding_system_function)))
-       /* Confirm that VAL can surely encode the current region.  */
-       val = call5 (Vselect_safe_coding_system_function,
-                    start, end, val, Qnil, filename);
+       {
+         /* Confirm that VAL can surely encode the current region.  */
+         val = call5 (Vselect_safe_coding_system_function,
+                      start, end, val, Qnil, filename);
+         /* As the function specified by select-safe-coding-system-function
+            is out of our control, make sure we are not fed by bogus
+            values.  */
+         if (!NILP (val))
+           CHECK_CODING_SYSTEM (val);
+       }
 
       /* If the decided coding-system doesn't specify end-of-line
         format, we use that of
         `default-buffer-file-coding-system'.  */
-      if (! using_default_coding
-         && ! NILP (BVAR (&buffer_defaults, buffer_file_coding_system)))
-       val = (coding_inherit_eol_type
-              (val, BVAR (&buffer_defaults, buffer_file_coding_system)));
+      if (! using_default_coding)
+       {
+         Lisp_Object dflt = BVAR (&buffer_defaults, buffer_file_coding_system);
+
+         if (! NILP (dflt))
+           val = coding_inherit_eol_type (val, dflt);
+       }
 
       /* If we decide not to encode text, use `raw-text' or one of its
         subsidiaries.  */
@@ -4678,7 +4705,6 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename,
   bool visiting = (EQ (visit, Qt) || STRINGP (visit));
   bool quietly = !NILP (visit);
   bool file_locked = 0;
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
   struct buffer *given_buffer;
   struct coding_system coding;
 
@@ -4689,7 +4715,6 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename,
     validate_region (&start, &end);
 
   visit_file = Qnil;
-  GCPRO5 (start, filename, visit, visit_file, lockname);
 
   filename = Fexpand_file_name (filename, Qnil);
 
@@ -4725,7 +4750,7 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename,
          XSETFASTINT (BVAR (current_buffer, save_length), Z - BEG);
          bset_filename (current_buffer, visit_file);
        }
-      UNGCPRO;
+
       return val;
     }
 
@@ -4765,10 +4790,6 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename,
       XSETFASTINT (end, ZV);
     }
 
-  UNGCPRO;
-
-  GCPRO5 (start, filename, annotations, visit_file, lockname);
-
   /* Decide the coding-system to encode the data with.
      We used to make this choice before calling build_annotations, but that
      leads to problems when a write-annotate-function takes care of
@@ -4805,7 +4826,6 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename,
          int open_errno = errno;
          if (file_locked)
            unlock_file (lockname);
-         UNGCPRO;
          report_file_errno ("Opening output file", filename, open_errno);
        }
 
@@ -4821,13 +4841,10 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename,
          int lseek_errno = errno;
          if (file_locked)
            unlock_file (lockname);
-         UNGCPRO;
          report_file_errno ("Lseek error", filename, lseek_errno);
        }
     }
 
-  UNGCPRO;
-
   immediate_quit = 1;
 
   if (STRINGP (start))
@@ -5026,7 +5043,6 @@ build_annotations (Lisp_Object start, Lisp_Object end)
 {
   Lisp_Object annotations;
   Lisp_Object p, res;
-  struct gcpro gcpro1, gcpro2;
   Lisp_Object original_buffer;
   int i;
   bool used_global = false;
@@ -5035,7 +5051,6 @@ build_annotations (Lisp_Object start, Lisp_Object end)
 
   annotations = Qnil;
   p = Vwrite_region_annotate_functions;
-  GCPRO2 (annotations, p);
   while (CONSP (p))
     {
       struct buffer *given_buffer = current_buffer;
@@ -5095,7 +5110,6 @@ build_annotations (Lisp_Object start, Lisp_Object end)
        annotations = merge (annotations, res, Qcar_less_than_car);
     }
 
-  UNGCPRO;
   return annotations;
 }
 
@@ -5366,7 +5380,6 @@ auto_save_error (Lisp_Object error_val)
 {
   Lisp_Object msg;
   int i;
-  struct gcpro gcpro1;
 
   auto_save_error_occurred = 1;
 
@@ -5375,7 +5388,6 @@ auto_save_error (Lisp_Object error_val)
   AUTO_STRING (format, "Auto-saving %s: %s");
   msg = CALLN (Fformat, format, BVAR (current_buffer, name),
               Ferror_message_string (error_val));
-  GCPRO1 (msg);
 
   for (i = 0; i < 3; ++i)
     {
@@ -5386,7 +5398,6 @@ auto_save_error (Lisp_Object error_val)
       Fsleep_for (make_number (1), Qnil);
     }
 
-  UNGCPRO;
   return Qnil;
 }
 
@@ -5478,7 +5489,6 @@ A non-nil CURRENT-ONLY argument means save only current buffer.  */)
   bool orig_minibuffer_auto_raise = minibuffer_auto_raise;
   bool old_message_p = 0;
   struct auto_save_unwind auto_save_unwind;
-  struct gcpro gcpro1, gcpro2;
 
   if (max_specpdl_size < specpdl_size + 40)
     max_specpdl_size = specpdl_size + 40;
@@ -5497,9 +5507,6 @@ A non-nil CURRENT-ONLY argument means save only current buffer.  */)
   oquit = Vquit_flag;
   Vquit_flag = Qnil;
 
-  /* No GCPRO needed, because (when it matters) all Lisp_Object variables
-     point to non-strings reached from Vbuffer_alist.  */
-
   hook = intern ("auto-save-hook");
   safe_run_hooks (hook);
 
@@ -5515,14 +5522,11 @@ A non-nil CURRENT-ONLY argument means save only current buffer.  */)
       if (!NILP (Vrun_hooks))
        {
          Lisp_Object dir;
-         dir = Qnil;
-         GCPRO2 (dir, listfile);
          dir = Ffile_name_directory (listfile);
          if (NILP (Ffile_directory_p (dir)))
            internal_condition_case_1 (do_auto_save_make_dir,
                                       dir, Qt,
                                       do_auto_save_eh);
-         UNGCPRO;
        }
 
       stream = emacs_fopen (SSDATA (listfile), "w");
@@ -5803,7 +5807,6 @@ syms_of_fileio (void)
   DEFSYM (Qcopy_file, "copy-file");
   DEFSYM (Qmake_directory_internal, "make-directory-internal");
   DEFSYM (Qmake_directory, "make-directory");
-  DEFSYM (Qdelete_directory_internal, "delete-directory-internal");
   DEFSYM (Qdelete_file, "delete-file");
   DEFSYM (Qrename_file, "rename-file");
   DEFSYM (Qadd_name_to_file, "add-name-to-file");
@@ -5851,7 +5854,7 @@ syms_of_fileio (void)
 If it is nil, `default-file-name-coding-system' (which see) is used.
 
 On MS-Windows, the value of this variable is largely ignored if
-\`w32-unicode-filenames' (which see) is non-nil.  Emacs on Windows
+`w32-unicode-filenames' (which see) is non-nil.  Emacs on Windows
 behaves as if file names were encoded in `utf-8'.  */);
   Vfile_name_coding_system = Qnil;
 
@@ -5866,7 +5869,7 @@ instead use `file-name-coding-system' to get a constant encoding
 of file names regardless of the current language environment.
 
 On MS-Windows, the value of this variable is largely ignored if
-\`w32-unicode-filenames' (which see) is non-nil.  Emacs on Windows
+`w32-unicode-filenames' (which see) is non-nil.  Emacs on Windows
 behaves as if file names were encoded in `utf-8'.  */);
   Vdefault_file_name_coding_system = Qnil;
 
@@ -5914,7 +5917,7 @@ the arguments that were passed to that primitive.  For example, if you
 do (file-exists-p FILENAME) and FILENAME is handled by HANDLER, then
 HANDLER is called like this:
 
-  (funcall HANDLER 'file-exists-p FILENAME)
+  (funcall HANDLER \\='file-exists-p FILENAME)
 
 Note that HANDLER must be able to handle all I/O primitives; if it has
 nothing special to do for a primitive, it should reinvoke the