From: Matteo Croce <teknora...@meta.com> Add a --offset option which allows to extract an archive which is embedded in another file or it's not at the start of the device. --- doc/tar.1 | 4 ++++ src/buffer.c | 19 +++++++++++++++++++ src/common.h | 3 +++ src/tar.c | 11 +++++++++++ 4 files changed, 37 insertions(+)
diff --git a/doc/tar.1 b/doc/tar.1 index 3f43db5c..9a8e3ca9 100644 --- a/doc/tar.1 +++ b/doc/tar.1 @@ -296,6 +296,10 @@ following subcommands: \fB\-\-delete\fR, \fB\-\-diff\fR, either on the command line or via the \fB\-T\fR option. The default \fIN\fR is \fB1\fR. .TP +\fB\-\-offset\fR[=\fINUMBER\fR] +Skip \fINUMBER\fR bytes in the input archive. Used when the archive +is embedded in another file or it's not at the start of the device. +.TP \fB\-\-restrict\fR Disable the use of some potentially harmful options. .TP diff --git a/src/buffer.c b/src/buffer.c index 570c8666..43544ab7 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -444,6 +444,9 @@ open_compressed_archive (void) if (archive < 0) return archive; + if (offset_option) + rmtlseek (archive, offset_option, SEEK_SET); + if (!multi_volume_option) { if (!use_compress_program_option) @@ -780,6 +783,20 @@ _open_archive (enum access_mode wanted_access) enum compress_type type; archive = STDIN_FILENO; + + if (offset_option) + { + /* seekable_archive is not set yet, so we need to read the data */ + char *buf = xmalloc (offset_option); + if (!buf) + paxfatal (0, _("Not enough memory")); + + int ret = read(archive, buf, offset_option); + free (buf); + if (ret != offset_option) + paxfatal (0, _("Short read on archive")); + } + type = check_compressed_archive (&shortfile); if (type != ct_tar && type != ct_none) paxfatal (0, _("Archive is compressed. Use %s option"), @@ -1096,6 +1113,8 @@ seek_archive (off_t size) if (offset < 0) return offset; + offset -= offset_option; + if (offset % record_size) paxfatal (0, _("rmtlseek not stopped at a record boundary")); diff --git a/src/common.h b/src/common.h index 07ac5fc7..5b5f3184 100644 --- a/src/common.h +++ b/src/common.h @@ -277,6 +277,9 @@ extern int acls_option; /* If positive, save the user and root xattrs. */ extern int xattrs_option; +/* If non zero, set file offset to seek to */ +extern int offset_option; + /* When set, strip the given number of file name components from the file name before extracting */ extern size_t strip_name_components; diff --git a/src/tar.c b/src/tar.c index 3d965dfd..55ff851f 100644 --- a/src/tar.c +++ b/src/tar.c @@ -90,6 +90,7 @@ int xattrs_option; size_t strip_name_components; bool show_omitted_dirs_option; bool sparse_option; +int offset_option; intmax_t tar_sparse_major; intmax_t tar_sparse_minor; enum hole_detection_method hole_detection; @@ -408,6 +409,7 @@ enum QUOTING_STYLE_OPTION, RECORD_SIZE_OPTION, RECURSIVE_UNLINK_OPTION, + OFFSET_OPTION, REMOVE_FILES_OPTION, RESTRICT_OPTION, RMT_COMMAND_OPTION, @@ -571,6 +573,8 @@ static struct argp_option options[] = { N_("handle new GNU-format incremental backup"), GRID_MODIFIER }, {"level", LEVEL_OPTION, N_("NUMBER"), 0, N_("dump level for created listed-incremental archive"), GRID_MODIFIER }, + {"offset", OFFSET_OPTION, N_("NUMBER"), 0, + N_("file offset where the archive is located"), GRID_MODIFIER }, {"ignore-failed-read", IGNORE_FAILED_READ_OPTION, 0, 0, N_("do not exit with nonzero on unreadable files"), GRID_MODIFIER }, {"occurrence", OCCURRENCE_OPTION, N_("NUMBER"), OPTION_ARG_OPTIONAL, @@ -1776,6 +1780,13 @@ parse_opt (int key, char *arg, struct argp_state *state) sparse_option = true; break; + case OFFSET_OPTION: + { + char *end; + offset_option = stoint (arg, &end, NULL, 0, INTMAX_MAX); + } + break; + case SKIP_OLD_FILES_OPTION: set_old_files_option (SKIP_OLD_FILES, args->loc); break; -- 2.46.0