[PATCH] erofs-utils: support dumping raw tar streams together

Gao Xiang hsiangkao at linux.alibaba.com
Thu Feb 22 20:01:45 AEDT 2024


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 <hsiangkao at linux.alibaba.com>
---
 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



More information about the Linux-erofs mailing list