]> git.ipfire.org Git - thirdparty/tar.git/commitdiff
Use full-read instead of safe-read
authorSergey Poznyakoff <gray@gnu.org>
Sat, 15 Jul 2023 15:06:27 +0000 (18:06 +0300)
committerSergey Poznyakoff <gray@gnu.org>
Mon, 17 Jul 2023 14:07:12 +0000 (17:07 +0300)
This helps handle archiving on certain filesystems where read()
returns less bytes than requested when reading from a regular
file.

References:

  https://savannah.gnu.org/bugs/index.php?64426
  https://lists.gnu.org/archive/html/bug-tar/2021-07/msg00001.html

* gnulib.modules: Add full-read.
* src/common.h: Include full-read.h
* src/misc.c: Use full_read.
* src/sparse.c: Likewise.
* src/update.c: Likewise.

gnulib.modules
src/common.h
src/misc.c
src/sparse.c
src/update.c

index 064f934971ae641465f3606f6dd783a088afe820..09300e2972c72f05a14cb944b2c58f89d006bdca 100644 (file)
@@ -79,7 +79,7 @@ readlinkat
 renameat
 root-uid
 rpmatch
-safe-read
+full-read
 savedir
 selinux-at
 setenv
index c79b3b63a1b0115fefa223a2517cf957ab08bf01..9451e13287df9fdf274b865240f6079dbb7fb954 100644 (file)
@@ -58,6 +58,7 @@
 #include <modechange.h>
 #include <quote.h>
 #include <safe-read.h>
+#include <full-read.h>
 #include <stat-time.h>
 #include <timespec.h>
 #define obstack_chunk_alloc xmalloc
index b7b99e5f8a1d6bb3139b09511d7d81bc43248e0e..73c046461a37ffda977074510332a0be270bdfa8 100644 (file)
@@ -821,7 +821,7 @@ deref_stat (char const *name, struct stat *buf)
 size_t
 blocking_read (int fd, void *buf, size_t count)
 {
-  size_t bytes = safe_read (fd, buf, count);
+  size_t bytes = full_read (fd, buf, count);
 
 #if defined F_SETFL && O_NONBLOCK
   if (bytes == SAFE_READ_ERROR && errno == EAGAIN)
@@ -829,10 +829,12 @@ blocking_read (int fd, void *buf, size_t count)
       int flags = fcntl (fd, F_GETFL);
       if (0 <= flags && flags & O_NONBLOCK
          && fcntl (fd, F_SETFL, flags & ~O_NONBLOCK) != -1)
-       bytes = safe_read (fd, buf, count);
+       bytes = full_read (fd, buf, count);
     }
 #endif
 
+  if (bytes == 0 && errno != 0)
+    bytes = SAFE_READ_ERROR;
   return bytes;
 }
 
index ec7152a6f00bcf3a3922ea2d2de0e77e14251b8c..ec19636c579b345bf2e130be7a24198dc94ea504 100644 (file)
@@ -415,7 +415,7 @@ sparse_dump_region (struct tar_sparse_file *file, size_t i)
       size_t bytes_read;
 
       blk = find_next_block ();
-      bytes_read = safe_read (file->fd, blk->buffer, bufsize);
+      bytes_read = full_read (file->fd, blk->buffer, bufsize);
       if (bytes_read == SAFE_READ_ERROR)
        {
           read_diag_details (file->stat_info->orig_file_name,
@@ -427,27 +427,39 @@ sparse_dump_region (struct tar_sparse_file *file, size_t i)
        }
       else if (bytes_read == 0)
        {
-         char buf[UINTMAX_STRSIZE_BOUND];
-         struct stat st;
-         size_t n;
-         if (fstat (file->fd, &st) == 0)
-           n = file->stat_info->stat.st_size - st.st_size;
+         if (errno != 0)
+           {
+             read_diag_details (file->stat_info->orig_file_name,
+                                (file->stat_info->sparse_map[i].offset
+                                 + file->stat_info->sparse_map[i].numbytes
+                                 - bytes_left),
+                                bufsize);
+             return false;
+           }
          else
-           n = file->stat_info->stat.st_size
-             - (file->stat_info->sparse_map[i].offset
-                + file->stat_info->sparse_map[i].numbytes
-                - bytes_left);
-
-         WARNOPT (WARN_FILE_SHRANK,
-                  (0, 0,
-                   ngettext ("%s: File shrank by %s byte; padding with zeros",
-                             "%s: File shrank by %s bytes; padding with zeros",
-                             n),
-                   quotearg_colon (file->stat_info->orig_file_name),
-                   STRINGIFY_BIGINT (n, buf)));
-         if (! ignore_failed_read_option)
-           set_exit_status (TAREXIT_DIFFERS);
-         return false;
+           {
+             char buf[UINTMAX_STRSIZE_BOUND];
+             struct stat st;
+             size_t n;
+             if (fstat (file->fd, &st) == 0)
+               n = file->stat_info->stat.st_size - st.st_size;
+             else
+               n = file->stat_info->stat.st_size
+                 - (file->stat_info->sparse_map[i].offset
+                    + file->stat_info->sparse_map[i].numbytes
+                    - bytes_left);
+
+             WARNOPT (WARN_FILE_SHRANK,
+                      (0, 0,
+                       ngettext ("%s: File shrank by %s byte; padding with zeros",
+                                 "%s: File shrank by %s bytes; padding with zeros",
+                                 n),
+                       quotearg_colon (file->stat_info->orig_file_name),
+                       STRINGIFY_BIGINT (n, buf)));
+             if (! ignore_failed_read_option)
+               set_exit_status (TAREXIT_DIFFERS);
+             return false;
+           }
        }
 
       memset (blk->buffer + bytes_read, 0, BLOCKSIZE - bytes_read);
@@ -615,7 +627,7 @@ check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end)
       size_t rdsize = BLOCKSIZE < end - beg ? BLOCKSIZE : end - beg;
       char diff_buffer[BLOCKSIZE];
 
-      bytes_read = safe_read (file->fd, diff_buffer, rdsize);
+      bytes_read = full_read (file->fd, diff_buffer, rdsize);
       if (bytes_read == SAFE_READ_ERROR)
        {
           read_diag_details (file->stat_info->orig_file_name,
@@ -625,7 +637,12 @@ check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end)
        }
       else if (bytes_read == 0)
        {
-         report_difference (file->stat_info, _("Size differs"));
+         if (errno != 0)
+           read_diag_details (file->stat_info->orig_file_name,
+                              beg,
+                              rdsize);
+         else
+           report_difference (file->stat_info, _("Size differs"));
          return false;
        }
 
@@ -668,7 +685,7 @@ check_data_region (struct tar_sparse_file *file, size_t i)
        }
       set_next_block_after (blk);
       file->dumped_size += BLOCKSIZE;
-      bytes_read = safe_read (file->fd, diff_buffer, rdsize);
+      bytes_read = full_read (file->fd, diff_buffer, rdsize);
       if (bytes_read == SAFE_READ_ERROR)
        {
           read_diag_details (file->stat_info->orig_file_name,
@@ -680,7 +697,14 @@ check_data_region (struct tar_sparse_file *file, size_t i)
        }
       else if (bytes_read == 0)
        {
-         report_difference (&current_stat_info, _("Size differs"));
+         if (errno != 0)
+           read_diag_details (file->stat_info->orig_file_name,
+                              (file->stat_info->sparse_map[i].offset
+                               + file->stat_info->sparse_map[i].numbytes
+                               - size_left),
+                              rdsize);
+         else
+           report_difference (&current_stat_info, _("Size differs"));
          return false;
        }
       size_left -= bytes_read;
index 0d3b45a3b8b3daffddd77cdaf1dfd7a343a3b3ae..dc5e5acab07e3ca2df559fa59cf8141cf5236098 100644 (file)
@@ -60,10 +60,14 @@ append_file (char *file_name)
   while (true)
     {
       union block *start = find_next_block ();
-      size_t status = safe_read (handle, start->buffer,
+      size_t status = full_read (handle, start->buffer,
                                 available_space_after (start));
       if (status == 0)
-       break;
+       {
+         if (errno == 0)
+           break;
+         read_fatal (file_name);
+       }
       if (status == SAFE_READ_ERROR)
        read_fatal (file_name);
       if (status % BLOCKSIZE)