From 24c830696527566742f1c8cac70d53086afca599 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 3 Nov 2022 23:07:11 -0700 Subject: Fix -Af F bug when F is not a regular file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem reported by Boris Gjenero in: https://lists.gnu.org/r/bug-tar/2022-11/msg00001.html * src/update.c (append_file): Don’t assume that FILE_NAME is a regular file whose size can be determined before reading. Instead, simply read from the file until its end is reached. --- src/update.c | 49 ++++++++++++------------------------------------- 1 file changed, 12 insertions(+), 37 deletions(-) diff --git a/src/update.c b/src/update.c index 5424e2ce..44ab229d 100644 --- a/src/update.c +++ b/src/update.c @@ -50,7 +50,6 @@ static void append_file (char *file_name) { int handle = openat (chdir_fd, file_name, O_RDONLY | O_BINARY); - struct stat stat_data; if (handle < 0) { @@ -58,43 +57,19 @@ append_file (char *file_name) return; } - if (fstat (handle, &stat_data) != 0) - stat_error (file_name); - else + while (true) { - off_t bytes_left = stat_data.st_size; - - while (bytes_left > 0) - { - union block *start = find_next_block (); - size_t buffer_size = available_space_after (start); - size_t status; - char buf[UINTMAX_STRSIZE_BOUND]; - - if (bytes_left < buffer_size) - { - buffer_size = bytes_left; - status = buffer_size % BLOCKSIZE; - if (status) - memset (start->buffer + bytes_left, 0, BLOCKSIZE - status); - } - - status = safe_read (handle, start->buffer, buffer_size); - if (status == SAFE_READ_ERROR) - read_fatal_details (file_name, stat_data.st_size - bytes_left, - buffer_size); - if (status == 0) - FATAL_ERROR ((0, 0, - ngettext ("%s: File shrank by %s byte", - "%s: File shrank by %s bytes", - bytes_left), - quotearg_colon (file_name), - STRINGIFY_BIGINT (bytes_left, buf))); - - bytes_left -= status; - - set_next_block_after (start + (status - 1) / BLOCKSIZE); - } + union block *start = find_next_block (); + size_t status = safe_read (handle, start->buffer, + available_space_after (start)); + if (status == 0) + break; + if (status == SAFE_READ_ERROR) + read_fatal (file_name); + if (status % BLOCKSIZE) + memset (start->buffer + status - status % BLOCKSIZE, 0, + BLOCKSIZE - status % BLOCKSIZE); + set_next_block_after (start + (status - 1) / BLOCKSIZE); } if (close (handle) != 0) -- cgit v1.2.1