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


Reply via email to