summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libarchive/archive.h2
-rw-r--r--libarchive/archive_read_disk.33
-rw-r--r--libarchive/archive_read_disk_entry_from_file.c8
-rw-r--r--libarchive/archive_read_disk_windows.c16
-rw-r--r--libarchive/test/test_sparse_basic.c37
-rw-r--r--tar/bsdtar.111
-rw-r--r--tar/bsdtar.c8
-rw-r--r--tar/bsdtar.h4
-rw-r--r--tar/cmdline.c2
9 files changed, 78 insertions, 13 deletions
diff --git a/libarchive/archive.h b/libarchive/archive.h
index fbc96bfe..9fcb6302 100644
--- a/libarchive/archive.h
+++ b/libarchive/archive.h
@@ -1024,6 +1024,8 @@ __LA_DECL int archive_read_disk_set_atime_restored(struct archive *);
#define ARCHIVE_READDISK_NO_ACL (0x0020)
/* Default: File flags are read from disk. */
#define ARCHIVE_READDISK_NO_FFLAGS (0x0040)
+/* Default: Sparse file information is read from disk. */
+#define ARCHIVE_READDISK_NO_SPARSE (0x0080)
__LA_DECL int archive_read_disk_set_behavior(struct archive *,
int flags);
diff --git a/libarchive/archive_read_disk.3 b/libarchive/archive_read_disk.3
index da138539..8b568d7b 100644
--- a/libarchive/archive_read_disk.3
+++ b/libarchive/archive_read_disk.3
@@ -181,6 +181,9 @@ for more information on extended file attributes.
.It Cm ARCHIVE_READDISK_RESTORE_ATIME
Restore access time of traversed files.
By default, access time of traversed files is not restored.
+.It Cm ARCHIVE_READDISK_NO_SPARSE
+Do not read sparse file information.
+By default, sparse file information is read from disk.
.El
.It Xo
.Fn archive_read_disk_set_symlink_logical ,
diff --git a/libarchive/archive_read_disk_entry_from_file.c b/libarchive/archive_read_disk_entry_from_file.c
index 9c9cf38e..ab0270bc 100644
--- a/libarchive/archive_read_disk_entry_from_file.c
+++ b/libarchive/archive_read_disk_entry_from_file.c
@@ -303,9 +303,11 @@ archive_read_disk_entry_from_file(struct archive *_a,
if (r1 < r)
r = r1;
}
- r1 = setup_sparse(a, entry, &fd);
- if (r1 < r)
- r = r1;
+ if ((a->flags & ARCHIVE_READDISK_NO_SPARSE) == 0) {
+ r1 = setup_sparse(a, entry, &fd);
+ if (r1 < r)
+ r = r1;
+ }
/* If we opened the file earlier in this function, close it. */
if (initial_fd != fd)
diff --git a/libarchive/archive_read_disk_windows.c b/libarchive/archive_read_disk_windows.c
index 4838969d..7e9ea4f0 100644
--- a/libarchive/archive_read_disk_windows.c
+++ b/libarchive/archive_read_disk_windows.c
@@ -1090,9 +1090,11 @@ next_entry(struct archive_read_disk *a, struct tree *t,
}
/* Find sparse data from the disk. */
- if (archive_entry_hardlink(entry) == NULL &&
- (st->dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) != 0)
- r = setup_sparse_from_disk(a, entry, t->entry_fh);
+ if ((a->flags & ARCHIVE_READDISK_NO_SPARSE) == 0) {
+ if (archive_entry_hardlink(entry) == NULL &&
+ (st->dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) != 0)
+ r = setup_sparse_from_disk(a, entry, t->entry_fh);
+ }
}
return (r);
}
@@ -2371,9 +2373,11 @@ archive_read_disk_entry_from_file(struct archive *_a,
return (ARCHIVE_OK);
}
- r = setup_sparse_from_disk(a, entry, h);
- if (fd < 0)
- CloseHandle(h);
+ if ((a->flags & ARCHIVE_READDISK_NO_SPARSE) == 0) {
+ r = setup_sparse_from_disk(a, entry, h);
+ if (fd < 0)
+ CloseHandle(h);
+ }
return (r);
}
diff --git a/libarchive/test/test_sparse_basic.c b/libarchive/test/test_sparse_basic.c
index 43e87df5..133a8539 100644
--- a/libarchive/test/test_sparse_basic.c
+++ b/libarchive/test/test_sparse_basic.c
@@ -364,9 +364,10 @@ verify_sparse_file(struct archive *a, const char *path,
#if DEBUG
fprintf(stderr, " overlapping hole expected_offset=%d, size=%d\n", (int)expected_offset, (int)sparse->size);
#endif
- /* Must be a hole, overlap must be filled with '\0' */
- if (assert(sparse->type == HOLE)) {
+ if (sparse->type == HOLE) {
assertMemoryFilledWith(start, end - start, '\0');
+ } else if (assert(sparse->type == DATA)) {
+ assertMemoryFilledWith(start, end - start, ' ');
}
start = end;
expected_offset += sparse->size;
@@ -410,9 +411,10 @@ verify_sparse_file(struct archive *a, const char *path,
#if DEBUG
fprintf(stderr, " trailing overlap expected_offset=%d, size=%d\n", (int)expected_offset, (int)sparse->size);
#endif
- /* Must be a hole, overlap must be filled with '\0' */
- if (assert(sparse->type == HOLE)) {
+ if (sparse->type == HOLE) {
assertMemoryFilledWith(start, end - start, '\0');
+ } else if (assert(sparse->type == DATA)) {
+ assertMemoryFilledWith(start, end - start, ' ');
}
}
last_offset = offset + bytes_read;
@@ -615,6 +617,33 @@ DEFINE_TEST(test_sparse_basic)
verify_sparse_file2(a, "file0", sparse_file0, 5, 1);
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+
+ /*
+ * Test that setting ARCHIVE_READDISK_NO_SPARSE
+ * creates no sparse entries.
+ */
+ assert((a = archive_read_disk_new()) != NULL);
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_set_behavior(a,
+ ARCHIVE_READDISK_NO_SPARSE));
+
+ verify_sparse_file(a, "file0", sparse_file0, 0);
+ verify_sparse_file(a, "file1", sparse_file1, 0);
+ verify_sparse_file(a, "file2", sparse_file2, 0);
+ verify_sparse_file(a, "file3", sparse_file3, 0);
+ verify_sparse_file(a, "file4", sparse_file4, 0);
+
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+
+ assert((a = archive_read_disk_new()) != NULL);
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_set_behavior(a,
+ ARCHIVE_READDISK_NO_SPARSE));
+
+ verify_sparse_file2(a, "file0", sparse_file0, 0, 0);
+ verify_sparse_file2(a, "file0", sparse_file0, 0, 1);
+
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
free(cwd);
}
diff --git a/tar/bsdtar.1 b/tar/bsdtar.1
index 86a06bbd..b1504700 100644
--- a/tar/bsdtar.1
+++ b/tar/bsdtar.1
@@ -470,6 +470,11 @@ This is the reverse of
and the default behavior if
.Nm
is run as non-root in x mode.
+.It Fl Fl no-read-sparse
+(c, r, u modes only)
+Do not read sparse file information from disk.
+This is the reverse of
+.Fl Fl read-sparse .
.It Fl Fl no-safe-writes
(x mode only)
Do not create temporary files and use
@@ -730,6 +735,12 @@ By default, the archive is always read to the very end, since
there can be multiple entries with the same name and, by convention,
later entries overwrite earlier entries.
This option is provided as a performance optimization.
+.It Fl Fl read-sparse
+(c, r, u modes only)
+Read sparse file information from disk.
+This is the reverse of
+.Fl Fl no-read-sparse
+and the default behavior.
.It Fl S
(x mode only)
Extract files as sparse files.
diff --git a/tar/bsdtar.c b/tar/bsdtar.c
index af41be5e..df0930ae 100644
--- a/tar/bsdtar.c
+++ b/tar/bsdtar.c
@@ -542,6 +542,10 @@ main(int argc, char **argv)
bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_MAC_METADATA;
bsdtar->flags |= OPTFLAG_NO_MAC_METADATA;
break;
+ case OPTION_NO_READ_SPARSE:
+ bsdtar->readdisk_flags |= ARCHIVE_READDISK_NO_SPARSE;
+ bsdtar->flags |= OPTFLAG_NO_READ_SPARSE;
+ break;
case OPTION_NO_SAFE_WRITES:
bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_SAFE_WRITES;
break;
@@ -649,6 +653,10 @@ main(int argc, char **argv)
case 'r': /* SUSv2 */
set_mode(bsdtar, opt);
break;
+ case OPTION_READ_SPARSE:
+ bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_NO_SPARSE;
+ bsdtar->flags |= OPTFLAG_READ_SPARSE;
+ break;
case 'S': /* NetBSD pax-as-tar */
bsdtar->extract_flags |= ARCHIVE_EXTRACT_SPARSE;
break;
diff --git a/tar/bsdtar.h b/tar/bsdtar.h
index 89aa3aa9..8f9f79ab 100644
--- a/tar/bsdtar.h
+++ b/tar/bsdtar.h
@@ -129,6 +129,8 @@ struct bsdtar {
#define OPTFLAG_FFLAGS (0x00100000) /* --fflags */
#define OPTFLAG_NO_MAC_METADATA (0x00200000) /* --no-mac-metadata */
#define OPTFLAG_MAC_METADATA (0x00400000) /* --mac-metadata */
+#define OPTFLAG_NO_READ_SPARSE (0x00800000) /* --no-read-sparse */
+#define OPTFLAG_READ_SPARSE (0x01000000) /* --read-sparse */
/* Fake short equivalents for long options that otherwise lack them. */
enum {
@@ -164,6 +166,7 @@ enum {
OPTION_NO_ACLS,
OPTION_NO_FFLAGS,
OPTION_NO_MAC_METADATA,
+ OPTION_NO_READ_SPARSE,
OPTION_NO_SAFE_WRITES,
OPTION_NO_SAME_OWNER,
OPTION_NO_SAME_PERMISSIONS,
@@ -178,6 +181,7 @@ enum {
OPTION_OPTIONS,
OPTION_PASSPHRASE,
OPTION_POSIX,
+ OPTION_READ_SPARSE,
OPTION_SAFE_WRITES,
OPTION_SAME_OWNER,
OPTION_STRIP_COMPONENTS,
diff --git a/tar/cmdline.c b/tar/cmdline.c
index b80937ff..d49e5b0d 100644
--- a/tar/cmdline.c
+++ b/tar/cmdline.c
@@ -122,6 +122,7 @@ static const struct bsdtar_option {
{ "no-acls", 0, OPTION_NO_ACLS },
{ "no-fflags", 0, OPTION_NO_FFLAGS },
{ "no-mac-metadata", 0, OPTION_NO_MAC_METADATA },
+ { "no-read-sparse", 0, OPTION_NO_READ_SPARSE },
{ "no-recursion", 0, 'n' },
{ "no-safe-writes", 0, OPTION_NO_SAFE_WRITES },
{ "no-same-owner", 0, OPTION_NO_SAME_OWNER },
@@ -145,6 +146,7 @@ static const struct bsdtar_option {
{ "posix", 0, OPTION_POSIX },
{ "preserve-permissions", 0, 'p' },
{ "read-full-blocks", 0, 'B' },
+ { "read-sparse", 0, OPTION_READ_SPARSE },
{ "safe-writes", 0, OPTION_SAFE_WRITES },
{ "same-owner", 0, OPTION_SAME_OWNER },
{ "same-permissions", 0, 'p' },