Gesendet: Donnerstag, 24. Oktober 2024 um 17:25 Uhr
Von: "Matteo Croce" <technoboy85@gmail.com>
An: bug-tar@gnu.org
Cc: "Matteo Croce" <teknoraver@meta.com>
Betreff: [PATCH 1/2] add option to set the offset of the archive
From: Matteo Croce <teknoraver@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