Use full-read instead of safe-read

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.
This commit is contained in:
Sergey Poznyakoff
2023-07-15 18:06:27 +03:00
parent 31f68bbe2a
commit e7a5e12445
5 changed files with 60 additions and 29 deletions

View 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);
{
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;
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;