diff options
Diffstat (limited to 'src/fileio.c')
-rw-r--r-- | src/fileio.c | 225 |
1 files changed, 108 insertions, 117 deletions
diff --git a/src/fileio.c b/src/fileio.c index c3566390130..a19fcd9f663 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -160,11 +160,16 @@ static bool e_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, /* Signal a file-access failure. STRING describes the failure, - DATA the file that was involved, and ERRORNO the errno value. */ + NAME the file involved, and ERRORNO the errno value. + + If NAME is neither null nor a pair, package it up as a singleton + list before reporting it; this saves report_file_errno's caller the + trouble of preserving errno before calling list1. */ void -report_file_errno (char const *string, Lisp_Object data, int errorno) +report_file_errno (char const *string, Lisp_Object name, int errorno) { + Lisp_Object data = CONSP (name) || NILP (name) ? name : list1 (name); Lisp_Object errstring; char *str; @@ -198,27 +203,37 @@ report_file_errno (char const *string, Lisp_Object data, int errorno) } } +/* Signal a file-access failure that set errno. STRING describes the + failure, NAME the file involved. When invoking this function, take + care to not use arguments such as build_string ("foo") that involve + side effects that may set errno. */ + void -report_file_error (char const *string, Lisp_Object data) +report_file_error (char const *string, Lisp_Object name) { - report_file_errno (string, data, errno); + report_file_errno (string, name, errno); } -Lisp_Object -close_file_unwind (Lisp_Object fd) +void +close_file_unwind (int fd) { - emacs_close (XFASTINT (fd)); - return Qnil; + emacs_close (fd); +} + +void +fclose_unwind (void *arg) +{ + FILE *stream = arg; + fclose (stream); } /* Restore point, having saved it as a marker. */ -Lisp_Object +void restore_point_unwind (Lisp_Object location) { Fgoto_char (location); Fset_marker (location, Qnil, Qnil); - return Qnil; } @@ -749,7 +764,7 @@ make_temp_name (Lisp_Object prefix, bool base64_p) dog-slow, but also useless since eventually nil would have to be returned anyway. */ report_file_error ("Cannot create temporary name for prefix", - Fcons (prefix, Qnil)); + prefix); /* not reached */ } } @@ -2019,7 +2034,7 @@ entries (depending on how Emacs was built). */) { acl = acl_get_file (SDATA (encoded_file), ACL_TYPE_ACCESS); if (acl == NULL && acl_errno_valid (errno)) - report_file_error ("Getting ACL", Fcons (file, Qnil)); + report_file_error ("Getting ACL", file); } if (!CopyFile (SDATA (encoded_file), SDATA (encoded_newname), @@ -2027,7 +2042,7 @@ entries (depending on how Emacs was built). */) { /* CopyFile doesn't set errno when it fails. By far the most "popular" reason is that the target is read-only. */ - report_file_errno ("Copying file", Fcons (file, Fcons (newname, Qnil)), + report_file_errno ("Copying file", list2 (file, newname), GetLastError () == 5 ? EACCES : EPERM); } /* CopyFile retains the timestamp by default. */ @@ -2058,7 +2073,7 @@ entries (depending on how Emacs was built). */) bool fail = acl_set_file (SDATA (encoded_newname), ACL_TYPE_ACCESS, acl) != 0; if (fail && acl_errno_valid (errno)) - report_file_error ("Setting ACL", Fcons (newname, Qnil)); + report_file_error ("Setting ACL", newname); acl_free (acl); } @@ -2068,12 +2083,12 @@ entries (depending on how Emacs was built). */) immediate_quit = 0; if (ifd < 0) - report_file_error ("Opening input file", Fcons (file, Qnil)); + report_file_error ("Opening input file", file); - record_unwind_protect (close_file_unwind, make_number (ifd)); + record_unwind_protect_int (close_file_unwind, ifd); if (fstat (ifd, &st) != 0) - report_file_error ("Input file status", Fcons (file, Qnil)); + report_file_error ("Input file status", file); if (!NILP (preserve_extended_attributes)) { @@ -2082,7 +2097,7 @@ entries (depending on how Emacs was built). */) { conlength = fgetfilecon (ifd, &con); if (conlength == -1) - report_file_error ("Doing fgetfilecon", Fcons (file, Qnil)); + report_file_error ("Doing fgetfilecon", file); } #endif } @@ -2090,11 +2105,11 @@ entries (depending on how Emacs was built). */) if (out_st.st_mode != 0 && st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino) report_file_errno ("Input and output files are the same", - Fcons (file, Fcons (newname, Qnil)), 0); + list2 (file, newname), 0); /* We can copy only regular files. */ if (!S_ISREG (st.st_mode)) - report_file_errno ("Non-regular file", Fcons (file, Qnil), + report_file_errno ("Non-regular file", file, S_ISDIR (st.st_mode) ? EISDIR : EINVAL); { @@ -2109,15 +2124,15 @@ entries (depending on how Emacs was built). */) new_mask); } if (ofd < 0) - report_file_error ("Opening output file", Fcons (newname, Qnil)); + report_file_error ("Opening output file", newname); - record_unwind_protect (close_file_unwind, make_number (ofd)); + record_unwind_protect_int (close_file_unwind, ofd); immediate_quit = 1; QUIT; while ((n = emacs_read (ifd, buf, sizeof buf)) > 0) if (emacs_write_sig (ofd, buf, n) != n) - report_file_error ("I/O error", Fcons (newname, Qnil)); + report_file_error ("Write error", newname); immediate_quit = 0; #ifndef MSDOS @@ -2145,8 +2160,8 @@ entries (depending on how Emacs was built). */) st.st_mode & mode_mask) : fchmod (ofd, st.st_mode & mode_mask)) { - case -2: report_file_error ("Copying permissions from", list1 (file)); - case -1: report_file_error ("Copying permissions to", list1 (newname)); + case -2: report_file_error ("Copying permissions from", file); + case -1: report_file_error ("Copying permissions to", newname); } } #endif /* not MSDOS */ @@ -2158,7 +2173,7 @@ entries (depending on how Emacs was built). */) bool fail = fsetfilecon (ofd, con) != 0; /* See http://debbugs.gnu.org/11245 for ENOTSUP. */ if (fail && errno != ENOTSUP) - report_file_error ("Doing fsetfilecon", Fcons (newname, Qnil)); + report_file_error ("Doing fsetfilecon", newname); freecon (con); } @@ -2174,7 +2189,7 @@ entries (depending on how Emacs was built). */) } if (emacs_close (ofd) < 0) - report_file_error ("I/O error", Fcons (newname, Qnil)); + report_file_error ("Write error", newname); emacs_close (ifd); @@ -2220,7 +2235,7 @@ DEFUN ("make-directory-internal", Fmake_directory_internal, #else if (mkdir (dir, 0777 & ~auto_saving_dir_umask) != 0) #endif - report_file_error ("Creating directory", list1 (directory)); + report_file_error ("Creating directory", directory); return Qnil; } @@ -2239,7 +2254,7 @@ DEFUN ("delete-directory-internal", Fdelete_directory_internal, dir = SSDATA (encoded_dir); if (rmdir (dir) != 0) - report_file_error ("Removing directory", list1 (directory)); + report_file_error ("Removing directory", directory); return Qnil; } @@ -2282,7 +2297,7 @@ With a prefix argument, TRASH is nil. */) encoded_file = ENCODE_FILE (filename); if (unlink (SSDATA (encoded_file)) < 0) - report_file_error ("Removing old name", list1 (filename)); + report_file_error ("Removing old name", filename); return Qnil; } @@ -2364,7 +2379,8 @@ This is what happens in interactive use with M-x. */) INTEGERP (ok_if_already_exists), 0, 0); if (rename (SSDATA (encoded_file), SSDATA (encoded_newname)) < 0) { - if (errno == EXDEV) + int rename_errno = errno; + if (rename_errno == EXDEV) { ptrdiff_t count; symlink_target = Ffile_symlink_p (file); @@ -2390,7 +2406,7 @@ This is what happens in interactive use with M-x. */) unbind_to (count, Qnil); } else - report_file_error ("Renaming", list2 (file, newname)); + report_file_errno ("Renaming", list2 (file, newname), rename_errno); } UNGCPRO; return Qnil; @@ -2444,7 +2460,10 @@ This is what happens in interactive use with M-x. */) unlink (SSDATA (newname)); if (link (SSDATA (encoded_file), SSDATA (encoded_newname)) < 0) - report_file_error ("Adding new name", list2 (file, newname)); + { + int link_errno = errno; + report_file_errno ("Adding new name", list2 (file, newname), link_errno); + } UNGCPRO; return Qnil; @@ -2503,6 +2522,7 @@ This happens for interactive use with M-x. */) if (symlink (SSDATA (encoded_filename), SSDATA (encoded_linkname)) < 0) { /* If we didn't complain already, silently delete existing file. */ + int symlink_errno; if (errno == EEXIST) { unlink (SSDATA (encoded_linkname)); @@ -2520,7 +2540,9 @@ This happens for interactive use with M-x. */) build_string ("Symbolic links are not supported")); } - report_file_error ("Making symbolic link", list2 (filename, linkname)); + symlink_errno = errno; + report_file_errno ("Making symbolic link", list2 (filename, linkname), + symlink_errno); } UNGCPRO; return Qnil; @@ -2719,7 +2741,7 @@ If there is no error, returns nil. */) encoded_filename = ENCODE_FILE (absname); if (faccessat (AT_FDCWD, SSDATA (encoded_filename), R_OK, AT_EACCESS) != 0) - report_file_error (SSDATA (string), Fcons (filename, Qnil)); + report_file_error (SSDATA (string), filename); return Qnil; } @@ -3054,14 +3076,14 @@ or if Emacs was not compiled with SELinux support. */) != 0); /* See http://debbugs.gnu.org/11245 for ENOTSUP. */ if (fail && errno != ENOTSUP) - report_file_error ("Doing lsetfilecon", Fcons (absname, Qnil)); + report_file_error ("Doing lsetfilecon", absname); context_free (parsed_con); freecon (con); return fail ? Qnil : Qt; } else - report_file_error ("Doing lgetfilecon", Fcons (absname, Qnil)); + report_file_error ("Doing lgetfilecon", absname); } #endif @@ -3151,7 +3173,7 @@ support. */) acl = acl_from_text (SSDATA (acl_string)); if (acl == NULL) { - report_file_error ("Converting ACL", Fcons (absname, Qnil)); + report_file_error ("Converting ACL", absname); return Qnil; } @@ -3161,7 +3183,7 @@ support. */) acl) != 0); if (fail && acl_errno_valid (errno)) - report_file_error ("Setting ACL", Fcons (absname, Qnil)); + report_file_error ("Setting ACL", absname); acl_free (acl); return fail ? Qnil : Qt; @@ -3221,7 +3243,7 @@ symbolic notation, like the `chmod' command from GNU Coreutils. */) encoded_absname = ENCODE_FILE (absname); if (chmod (SSDATA (encoded_absname), XINT (mode) & 07777) < 0) - report_file_error ("Doing chmod", Fcons (absname, Qnil)); + report_file_error ("Doing chmod", absname); return Qnil; } @@ -3287,7 +3309,7 @@ Use the current time if TIMESTAMP is nil. TIMESTAMP is in the format of if (file_directory_p (SSDATA (encoded_absname))) return Qnil; #endif - report_file_error ("Setting file times", Fcons (absname, Qnil)); + report_file_error ("Setting file times", absname); } } @@ -3369,7 +3391,7 @@ verify (READ_BUF_SIZE <= INT_MAX); o remove all text properties. o set back the buffer multibyteness. */ -static Lisp_Object +static void decide_coding_unwind (Lisp_Object unwind_data) { Lisp_Object multibyte, undo_list, buffer; @@ -3388,8 +3410,6 @@ decide_coding_unwind (Lisp_Object unwind_data) /* Now we are safe to change the buffer's multibyteness directly. */ bset_enable_multibyte_characters (current_buffer, multibyte); bset_undo_list (current_buffer, undo_list); - - return Qnil; } /* Read from a non-regular file. STATE is a Lisp_Save_Value @@ -3510,7 +3530,7 @@ by calling `format-decode', which see. */) && BEG == Z); Lisp_Object old_Vdeactivate_mark = Vdeactivate_mark; bool we_locked_file = 0; - bool deferred_remove_unwind_protect = 0; + ptrdiff_t fd_index; if (current_buffer->base_buffer && ! NILP (visit)) error ("Cannot do file visiting in an indirect buffer"); @@ -3553,7 +3573,7 @@ by calling `format-decode', which see. */) { save_errno = errno; if (NILP (visit)) - report_file_error ("Opening input file", Fcons (orig_filename, Qnil)); + report_file_error ("Opening input file", orig_filename); mtime = time_error_value (save_errno); st.st_size = -1; if (!NILP (Vcoding_system_for_read)) @@ -3561,14 +3581,15 @@ by calling `format-decode', which see. */) goto notfound; } + fd_index = SPECPDL_INDEX (); + record_unwind_protect_int (close_file_unwind, fd); + /* Replacement should preserve point as it preserves markers. */ if (!NILP (replace)) record_unwind_protect (restore_point_unwind, Fpoint_marker ()); - record_unwind_protect (close_file_unwind, make_number (fd)); - if (fstat (fd, &st) != 0) - report_file_error ("Input file status", Fcons (orig_filename, Qnil)); + report_file_error ("Input file status", orig_filename); mtime = get_stat_mtime (&st); /* This code will need to be changed in order to work on named @@ -3682,15 +3703,14 @@ by calling `format-decode', which see. */) int ntail; if (lseek (fd, - (1024 * 3), SEEK_END) < 0) report_file_error ("Setting file position", - Fcons (orig_filename, Qnil)); + orig_filename); ntail = emacs_read (fd, read_buf + nread, 1024 * 3); nread = ntail < 0 ? ntail : nread + ntail; } } if (nread < 0) - error ("IO error reading %s: %s", - SDATA (orig_filename), emacs_strerror (errno)); + report_file_error ("Read error", orig_filename); else if (nread > 0) { struct buffer *prev = current_buffer; @@ -3726,8 +3746,7 @@ by calling `format-decode', which see. */) /* Rewind the file for the actual read done later. */ if (lseek (fd, 0, SEEK_SET) < 0) - report_file_error ("Setting file position", - Fcons (orig_filename, Qnil)); + report_file_error ("Setting file position", orig_filename); } } @@ -3793,8 +3812,7 @@ by calling `format-decode', which see. */) if (beg_offset != 0) { if (lseek (fd, beg_offset, SEEK_SET) < 0) - report_file_error ("Setting file position", - Fcons (orig_filename, Qnil)); + report_file_error ("Setting file position", orig_filename); } immediate_quit = 1; @@ -3807,8 +3825,7 @@ by calling `format-decode', which see. */) nread = emacs_read (fd, read_buf, sizeof read_buf); if (nread < 0) - error ("IO error reading %s: %s", - SSDATA (orig_filename), emacs_strerror (errno)); + report_file_error ("Read error", orig_filename); else if (nread == 0) break; @@ -3866,16 +3883,14 @@ by calling `format-decode', which see. */) /* How much can we scan in the next step? */ trial = min (curpos, sizeof read_buf); if (lseek (fd, curpos - trial, SEEK_SET) < 0) - report_file_error ("Setting file position", - Fcons (orig_filename, Qnil)); + report_file_error ("Setting file position", orig_filename); total_read = nread = 0; while (total_read < trial) { nread = emacs_read (fd, read_buf + total_read, trial - total_read); if (nread < 0) - error ("IO error reading %s: %s", - SDATA (orig_filename), emacs_strerror (errno)); + report_file_error ("Read error", orig_filename); else if (nread == 0) break; total_read += nread; @@ -3987,8 +4002,7 @@ by calling `format-decode', which see. */) CONVERSION_BUFFER. */ if (lseek (fd, beg_offset, SEEK_SET) < 0) - report_file_error ("Setting file position", - Fcons (orig_filename, Qnil)); + report_file_error ("Setting file position", orig_filename); inserted = 0; /* Bytes put into CONVERSION_BUFFER so far. */ unprocessed = 0; /* Bytes not processed in previous loop. */ @@ -4018,16 +4032,10 @@ by calling `format-decode', which see. */) memcpy (read_buf, coding.carryover, unprocessed); } 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; - if (this < 0) - error ("IO error reading %s: %s", - SDATA (orig_filename), emacs_strerror (errno)); + report_file_error ("Read error", orig_filename); + emacs_close (fd); + clear_unwind_protect (fd_index); if (unprocessed > 0) { @@ -4168,8 +4176,7 @@ by calling `format-decode', which see. */) if (beg_offset != 0 || !NILP (replace)) { if (lseek (fd, beg_offset, SEEK_SET) < 0) - report_file_error ("Setting file position", - Fcons (orig_filename, Qnil)); + report_file_error ("Setting file position", orig_filename); } /* In the following loop, HOW_MUCH contains the total bytes read so @@ -4208,8 +4215,7 @@ by calling `format-decode', which see. */) to be signaled after decoding the text we read. */ nbytes = internal_condition_case_1 (read_non_regular, - make_save_value (SAVE_TYPE_INT_INT_INT, (ptrdiff_t) fd, - inserted, trytry), + make_save_int_int_int (fd, inserted, trytry), Qerror, read_non_regular_quit); if (NILP (nbytes)) @@ -4269,13 +4275,10 @@ by calling `format-decode', which see. */) Vdeactivate_mark = Qt; emacs_close (fd); - - /* Discard the unwind protect for closing the file. */ - specpdl_ptr--; + clear_unwind_protect (fd_index); if (how_much < 0) - error ("IO error reading %s: %s", - SDATA (orig_filename), emacs_strerror (errno)); + report_file_error ("Read error", orig_filename); /* Make the text read part of the buffer. */ GAP_SIZE -= inserted; @@ -4399,11 +4402,6 @@ by calling `format-decode', which see. */) handled: - if (deferred_remove_unwind_protect) - /* If requested above, discard the unwind protect for closing the - file. */ - specpdl_ptr--; - if (!NILP (visit)) { if (empty_undo_list_p) @@ -4574,8 +4572,7 @@ by calling `format-decode', which see. */) && EMACS_NSECS (current_buffer->modtime) == NONEXISTENT_MODTIME_NSECS) { /* If visiting nonexistent file, return nil. */ - report_file_errno ("Opening input file", Fcons (orig_filename, Qnil), - save_errno); + report_file_errno ("Opening input file", orig_filename, save_errno); } if (read_quit) @@ -4590,11 +4587,10 @@ by calling `format-decode', which see. */) static Lisp_Object build_annotations (Lisp_Object, Lisp_Object); -static Lisp_Object +static void build_annotations_unwind (Lisp_Object arg) { Vwrite_region_annotation_buffers = arg; - return Qnil; } /* Decide the coding-system to encode the data with. */ @@ -4631,7 +4627,7 @@ This function is for internal use only. It may prompt the user. */ ) && !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, Fcons (Qt, Fcons (val, Qnil)), + start, end, list2 (Qt, val), Qnil, filename); } else @@ -4834,7 +4830,7 @@ This calls `write-region-annotate-functions' at the start, and record_unwind_protect (build_annotations_unwind, Vwrite_region_annotation_buffers); - Vwrite_region_annotation_buffers = Fcons (Fcurrent_buffer (), Qnil); + Vwrite_region_annotation_buffers = list1 (Fcurrent_buffer ()); count1 = SPECPDL_INDEX (); given_buffer = current_buffer; @@ -4901,11 +4897,10 @@ This calls `write-region-annotate-functions' at the start, and if (!auto_saving) unlock_file (lockname); #endif /* CLASH_DETECTION */ UNGCPRO; - report_file_errno ("Opening output file", Fcons (filename, Qnil), - open_errno); + report_file_errno ("Opening output file", filename, open_errno); } - record_unwind_protect (close_file_unwind, make_number (desc)); + record_unwind_protect_int (close_file_unwind, desc); if (NUMBERP (append)) { @@ -4917,8 +4912,7 @@ This calls `write-region-annotate-functions' at the start, and if (!auto_saving) unlock_file (lockname); #endif /* CLASH_DETECTION */ UNGCPRO; - report_file_errno ("Lseek error", Fcons (filename, Qnil), - lseek_errno); + report_file_errno ("Lseek error", filename, lseek_errno); } } @@ -5071,8 +5065,7 @@ This calls `write-region-annotate-functions' at the start, and } if (! ok) - error ("IO error writing %s: %s", SDATA (filename), - emacs_strerror (save_errno)); + report_file_errno ("Write error", filename, save_errno); if (visiting) { @@ -5498,11 +5491,18 @@ auto_save_1 (void) Qnil, Qnil); } -static Lisp_Object -do_auto_save_unwind (Lisp_Object arg) /* used as unwind-protect function */ +struct auto_save_unwind +{ + FILE *stream; + bool auto_raise; +}; +static void +do_auto_save_unwind (void *arg) { - FILE *stream = XSAVE_POINTER (arg, 0); + struct auto_save_unwind *p = arg; + FILE *stream = p->stream; + minibuffer_auto_raise = p->auto_raise; auto_saving = 0; if (stream != NULL) { @@ -5510,15 +5510,6 @@ do_auto_save_unwind (Lisp_Object arg) /* used as unwind-protect function */ fclose (stream); unblock_input (); } - return Qnil; -} - -static Lisp_Object -do_auto_save_unwind_1 (Lisp_Object value) /* used as unwind-protect function */ - -{ - minibuffer_auto_raise = XINT (value); - return Qnil; } static Lisp_Object @@ -5561,6 +5552,7 @@ A non-nil CURRENT-ONLY argument means save only current buffer. */) ptrdiff_t count = SPECPDL_INDEX (); 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) @@ -5572,7 +5564,7 @@ A non-nil CURRENT-ONLY argument means save only current buffer. */) if (NILP (no_message)) { old_message_p = push_message (); - record_unwind_protect (pop_message_unwind, Qnil); + record_unwind_protect_void (pop_message_unwind); } /* Ordinarily don't quit within this function, @@ -5611,10 +5603,9 @@ A non-nil CURRENT-ONLY argument means save only current buffer. */) stream = emacs_fopen (SSDATA (listfile), "w"); } - record_unwind_protect (do_auto_save_unwind, - make_save_pointer (stream)); - record_unwind_protect (do_auto_save_unwind_1, - make_number (minibuffer_auto_raise)); + auto_save_unwind.stream = stream; + auto_save_unwind.auto_raise = minibuffer_auto_raise; + record_unwind_protect_ptr (do_auto_save_unwind, &auto_save_unwind); minibuffer_auto_raise = 0; auto_saving = 1; auto_save_error_occurred = 0; |