Since commit e3dfe4b8db26 ("erofs-utils: mkfs: support tgz streams for
tarerofs"), tgz streams can be converted to EROFS directly.

However, many use cases also require raw tar streams.  Let's add
support for dumping raw streams with `--ungzip=FILE` option.

Signed-off-by: Gao Xiang <[email protected]>
---
 include/erofs/tar.h |  4 ++--
 lib/tar.c           |  7 ++++++-
 man/mkfs.erofs.1    |  5 +++--
 mkfs/main.c         | 20 ++++++++++++++++++--
 4 files changed, 29 insertions(+), 7 deletions(-)

diff --git a/include/erofs/tar.h b/include/erofs/tar.h
index a76f740..be03d1b 100644
--- a/include/erofs/tar.h
+++ b/include/erofs/tar.h
@@ -35,14 +35,14 @@ struct erofs_iostream {
        u64 sz;
        char *buffer;
        unsigned int head, tail, bufsize;
-       int decoder;
+       int decoder, dumpfd;
        bool feof;
 };
 
 struct erofs_tarfile {
        struct erofs_pax_header global;
        struct erofs_iostream ios;
-       char *mapfile;
+       char *mapfile, *dumpfile;
 
        int fd;
        u64 offset;
diff --git a/lib/tar.c b/lib/tar.c
index ead74ba..1d764b2 100644
--- a/lib/tar.c
+++ b/lib/tar.c
@@ -82,6 +82,7 @@ int erofs_iostream_open(struct erofs_iostream *ios, int fd, 
int decoder)
 
        ios->tail = ios->head = 0;
        ios->decoder = decoder;
+       ios->dumpfd = -1;
        if (decoder == EROFS_IOS_DECODER_GZIP) {
 #if defined(HAVE_ZLIB)
                ios->handler = gzdopen(fd, "r");
@@ -170,6 +171,10 @@ int erofs_iostream_read(struct erofs_iostream *ios, void 
**buf, u64 bytes)
                        if (ret < ios->bufsize - rabytes)
                                ios->feof = true;
                }
+               if (unlikely(ios->dumpfd >= 0))
+                       if (write(ios->dumpfd, ios->buffer + rabytes, ret) < 
ret)
+                               erofs_err("failed to dump %d bytes of the raw 
stream: %s",
+                                         ret, erofs_strerror(-errno));
        }
        *buf = ios->buffer;
        ret = min_t(int, ios->tail, bytes);
@@ -210,7 +215,7 @@ int erofs_iostream_lskip(struct erofs_iostream *ios, u64 sz)
        if (ios->feof)
                return sz;
 
-       if (ios->sz) {
+       if (ios->sz && likely(ios->dumpfd < 0)) {
                s64 cur = lseek(ios->fd, sz, SEEK_CUR);
 
                if (cur > ios->sz)
diff --git a/man/mkfs.erofs.1 b/man/mkfs.erofs.1
index 45be11a..f32dc26 100644
--- a/man/mkfs.erofs.1
+++ b/man/mkfs.erofs.1
@@ -162,8 +162,9 @@ When this option is used together with
 the final file gids are
 set to \fIGID\fR + \fIGID-OFFSET\fR.
 .TP
-.B \-\-gzip
-Filter tarball streams through gzip.
+.BI \-\-ungzip\fR[\fP= file \fR]\fP
+Filter tarball streams through gzip. Optionally, raw streams can be dumped
+together.
 .TP
 \fB\-V\fR, \fB\-\-version\fR
 Print the version number and exit.
diff --git a/mkfs/main.c b/mkfs/main.c
index 7aea64a..75b80ab 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -71,6 +71,7 @@ static struct option long_options[] = {
        {"ovlfs-strip", optional_argument, NULL, 516},
 #ifdef HAVE_ZLIB
        {"gzip", no_argument, NULL, 517},
+       {"ungzip", optional_argument, NULL, 517},
 #endif
        {"offset", required_argument, NULL, 518},
        {0, 0, 0, 0},
@@ -153,7 +154,8 @@ static void usage(int argc, char **argv)
                " --uid-offset=#        add offset # to all file uids (# = id 
offset)\n"
                " --gid-offset=#        add offset # to all file gids (# = id 
offset)\n"
 #ifdef HAVE_ZLIB
-               " --gzip                try to filter the tarball stream 
through gzip\n"
+               " --ungzip[=X]          try to filter the tarball stream 
through gzip\n"
+               "                       (and optionally dump the raw stream to 
X together)\n"
 #endif
                " --ignore-mtime        use build time instead of strict 
per-file modification time\n"
                " --max-extent-bytes=#  set maximum decompressed extent size # 
in bytes\n"
@@ -633,6 +635,8 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                                cfg.c_ovlfs_strip = false;
                        break;
                case 517:
+                       if (optarg)
+                               erofstar.dumpfile = strdup(optarg);
                        gzip_supported = true;
                        break;
                case 518:
@@ -712,6 +716,15 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                        err = erofs_iostream_open(&erofstar.ios, fd, 
gzip_supported);
                        if (err)
                                return err;
+
+                       fd = open(erofstar.dumpfile,
+                                 O_WRONLY | O_CREAT | O_TRUNC, 0644);
+                       if (fd < 0) {
+                               erofs_err("failed to open dumpfile: %s",
+                                         erofstar.dumpfile);
+                               return -errno;
+                       }
+                       erofstar.ios.dumpfd = fd;
                } else {
                        err = lstat(cfg.c_src_path, &st);
                        if (err)
@@ -1315,8 +1328,11 @@ exit:
        erofs_rebuild_cleanup();
        erofs_diskbuf_exit();
        erofs_exit_configure();
-       if (tar_mode)
+       if (tar_mode) {
                erofs_iostream_close(&erofstar.ios);
+               if (erofstar.ios.dumpfd >= 0)
+                       close(erofstar.ios.dumpfd);
+       }
 
        if (err) {
                erofs_err("\tCould not format the device : %s\n",
-- 
2.39.3

Reply via email to