diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2022-09-03 18:22:34 -0500 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2022-09-03 18:23:11 -0500 |
commit | bc277c7069cdebb6a6140326636555267b142e0e (patch) | |
tree | 73707e333fa7d181ad86f1fa2d97fac6e1031811 /src/list.c | |
parent | f8e14746d2ca72804a4520c059d7bf65ca00c5ac (diff) | |
download | tar-bc277c7069cdebb6a6140326636555267b142e0e.tar.gz |
Fix data loss when acting as filter
This bug was introduced by the recent lseek-related changes.
* src/delete.c (delete_archive_members):
* src/update.c (update_archive):
Copy the member if acting as a filter, rather than lseeking over
it, which is possible if stdin is a regular file.
* src/list.c (skim_file, skim_member):
* src/sparse.c (sparse_skim_file):
New functions, for copying when a filter.
* src/list.c (skip_file): Remove; replaced with skim_file.
All callers changed.
(skip_member): Reimplement in terms of skim_member.
* src/sparse.c (sparse_skip_file):
Remove; replaced with sparse_skim_file. All callers changed.
* src/update.c (acting_as_filter): New static var.
(update_archive): Set it; this is like delete.c.
* tests/delete01.at (deleting a member after a big one):
* tests/delete02.at (deleting a member from stdin archive):
Also test filter case.
Diffstat (limited to 'src/list.c')
-rw-r--r-- | src/list.c | 22 |
1 files changed, 16 insertions, 6 deletions
@@ -416,7 +416,7 @@ read_header (union block **return_block, struct tar_stat_info *info, size_t next_long_name_blocks = 0; size_t next_long_link_blocks = 0; enum read_header status = HEADER_SUCCESS; - + while (1) { header = find_next_block (); @@ -1391,15 +1391,17 @@ print_for_mkdir (char *dirname, int length, mode_t mode) } } -/* Skip over SIZE bytes of data in blocks in the archive. */ +/* Skip over SIZE bytes of data in blocks in the archive. + This may involve copying the data. + If MUST_COPY, always copy instead of skipping. */ void -skip_file (off_t size) +skim_file (off_t size, bool must_copy) { union block *x; /* FIXME: Make sure mv_begin_read is always called before it */ - if (seekable_archive) + if (seekable_archive && !must_copy) { off_t nblk = seek_archive (size); if (nblk >= 0) @@ -1427,6 +1429,14 @@ skip_file (off_t size) void skip_member (void) { + skim_member (false); +} + +/* Skip the current member in the archive. + If MUST_COPY, always copy instead of skipping. */ +void +skim_member (bool must_copy) +{ if (!current_stat_info.skipped) { char save_typeflag = current_header->header.typeflag; @@ -1435,9 +1445,9 @@ skip_member (void) mv_begin_read (¤t_stat_info); if (current_stat_info.is_sparse) - sparse_skip_file (¤t_stat_info); + sparse_skim_file (¤t_stat_info, must_copy); else if (save_typeflag != DIRTYPE) - skip_file (current_stat_info.stat.st_size); + skim_file (current_stat_info.stat.st_size, must_copy); mv_end (); } |