From b950b46f514989442fdd9937a0e96d53a3affa88 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 13 Feb 2023 12:32:11 -0800 Subject: [PATCH] Fix insert-file-contents on /proc files This should fix Bug#9800 (2011-10-19). * src/fileio.c (Finsert_file_contents): Do not trust st_size even on regular files, as the file might be a Linux /proc file, or it might be growing. Instead, always read to EOF when END is nil. --- src/fileio.c | 57 +++++++++++++++++++++++----------------------------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/src/fileio.c b/src/fileio.c index ee30db8b49b..b80f8d61de4 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -3907,7 +3907,6 @@ by calling `format-decode', which see. */) struct timespec mtime; int fd; ptrdiff_t inserted = 0; - ptrdiff_t how_much; int unprocessed; specpdl_ref count = SPECPDL_INDEX (); Lisp_Object handler, val, insval, orig_filename, old_undo; @@ -3920,7 +3919,8 @@ by calling `format-decode', which see. */) bool replace_handled = false; bool set_coding_system = false; Lisp_Object coding_system; - bool read_quit = false; + /* Negative if read error, 0 if OK so far, positive if quit. */ + ptrdiff_t read_quit = 0; /* If the undo log only contains the insertion, there's no point keeping it. It's typically when we first fill a file-buffer. */ bool empty_undo_list_p @@ -4404,7 +4404,7 @@ by calling `format-decode', which see. */) ptrdiff_t bufpos; unsigned char *decoded; ptrdiff_t temp; - ptrdiff_t this = 0; + ptrdiff_t this; specpdl_ref this_count = SPECPDL_INDEX (); bool multibyte = ! NILP (BVAR (current_buffer, enable_multibyte_characters)); @@ -4580,8 +4580,12 @@ by calling `format-decode', which see. */) } move_gap_both (PT, PT_BYTE); - if (GAP_SIZE < total) - make_gap (total - GAP_SIZE); + + /* Ensure the gap is at least one byte larger than needed for the + estimated file size, so that in the usual case we read to EOF + without reallocating. */ + if (GAP_SIZE <= total) + make_gap (total - GAP_SIZE + 1); if (beg_offset != 0 || !NILP (replace)) { @@ -4589,12 +4593,6 @@ by calling `format-decode', which see. */) report_file_error ("Setting file position", orig_filename); } - /* In the following loop, HOW_MUCH contains the total bytes read so - far for a regular file, and not changed for a special file. But, - before exiting the loop, it is set to a negative value if I/O - error occurs. */ - how_much = 0; - /* Total bytes inserted. */ inserted = 0; @@ -4603,23 +4601,26 @@ by calling `format-decode', which see. */) { ptrdiff_t gap_size = GAP_SIZE; - while (how_much < total) + while (NILP (end) || inserted < total) { - /* `try' is reserved in some compilers (Microsoft C). */ - ptrdiff_t trytry = min (total - how_much, READ_BUF_SIZE); ptrdiff_t this; + if (gap_size == 0) + { + /* The size estimate was wrong. Make the gap 50% larger. */ + make_gap (GAP_SIZE >> 1); + gap_size = GAP_SIZE - inserted; + } + + /* 'try' is reserved in some compilers (Microsoft C). */ + ptrdiff_t trytry = min (gap_size, READ_BUF_SIZE); + if (!NILP (end)) + trytry = min (trytry, total - inserted); + if (!seekable && NILP (end)) { Lisp_Object nbytes; - /* Maybe make more room. */ - if (gap_size < trytry) - { - make_gap (trytry - gap_size); - gap_size = GAP_SIZE - inserted; - } - /* Read from the file, capturing `quit'. When an error occurs, end the loop, and arrange for a quit to be signaled after decoding the text we read. */ @@ -4630,7 +4631,7 @@ by calling `format-decode', which see. */) if (NILP (nbytes)) { - read_quit = true; + read_quit = 1; break; } @@ -4649,19 +4650,11 @@ by calling `format-decode', which see. */) if (this <= 0) { - how_much = this; + read_quit = this; break; } gap_size -= this; - - /* For a regular file, where TOTAL is the real size, - count HOW_MUCH to compare with it. - For a special file, where TOTAL is just a buffer size, - so don't bother counting in HOW_MUCH. - (INSERTED is where we count the number of characters inserted.) */ - if (seekable || !NILP (end)) - how_much += this; inserted += this; } } @@ -4682,7 +4675,7 @@ by calling `format-decode', which see. */) emacs_close (fd); clear_unwind_protect (fd_index); - if (how_much < 0) + if (read_quit < 0) report_file_error ("Read error", orig_filename); notfound: