Similar to commit e3dfe4b8db26 ("erofs-utils: mkfs: support tgz streams
for tarerofs"), let's add xz/lzma/lzip support by using liblzma.Signed-off-by: Gao Xiang <[email protected]> --- include/erofs/tar.h | 13 ++++++++++ lib/tar.c | 58 ++++++++++++++++++++++++++++++++++++++++++++- man/mkfs.erofs.1 | 12 ++++++---- mkfs/main.c | 42 ++++++++++++++++++++------------ 4 files changed, 105 insertions(+), 20 deletions(-) diff --git a/include/erofs/tar.h b/include/erofs/tar.h index e45b895..b5c966b 100644 --- a/include/erofs/tar.h +++ b/include/erofs/tar.h @@ -26,11 +26,24 @@ struct erofs_pax_header { #define EROFS_IOS_DECODER_NONE 0 #define EROFS_IOS_DECODER_GZIP 1 +#define EROFS_IOS_DECODER_LIBLZMA 2 + +#ifdef HAVE_LIBLZMA +#include <lzma.h> +struct erofs_iostream_liblzma { + u8 inbuf[32768]; + lzma_stream strm; + int fd; +}; +#endif struct erofs_iostream { union { int fd; /* original fd */ void *handler; +#ifdef HAVE_LIBLZMA + struct erofs_iostream_liblzma *lzma; +#endif }; u64 sz; char *buffer; diff --git a/lib/tar.c b/lib/tar.c index 7c14c06..fcccd1f 100644 --- a/lib/tar.c +++ b/lib/tar.c @@ -70,6 +70,13 @@ void erofs_iostream_close(struct erofs_iostream *ios) if (ios->decoder == EROFS_IOS_DECODER_GZIP) { #if defined(HAVE_ZLIB) gzclose(ios->handler); +#endif + return; + } else if (ios->decoder == EROFS_IOS_DECODER_LIBLZMA) { +#if defined(HAVE_LIBLZMA) + lzma_end(&ios->lzma->strm); + close(ios->lzma->fd); + free(ios->lzma); #endif return; } @@ -80,6 +87,7 @@ int erofs_iostream_open(struct erofs_iostream *ios, int fd, int decoder) { s64 fsz; + ios->feof = false; ios->tail = ios->head = 0; ios->decoder = decoder; ios->dumpfd = -1; @@ -92,6 +100,24 @@ int erofs_iostream_open(struct erofs_iostream *ios, int fd, int decoder) ios->bufsize = 32768; #else return -EOPNOTSUPP; +#endif + } else if (decoder == EROFS_IOS_DECODER_LIBLZMA) { +#ifdef HAVE_LIBLZMA + lzma_ret ret; + + ios->lzma = malloc(sizeof(*ios->lzma)); + if (!ios->lzma) + return -ENOMEM; + ios->lzma->fd = fd; + ios->lzma->strm = (lzma_stream)LZMA_STREAM_INIT; + ret = lzma_auto_decoder(&ios->lzma->strm, + UINT64_MAX, LZMA_CONCATENATED); + if (ret != LZMA_OK) + return -EFAULT; + ios->sz = fsz = 0; + ios->bufsize = 32768; +#else + return -EOPNOTSUPP; #endif } else { ios->fd = fd; @@ -100,7 +126,6 @@ int erofs_iostream_open(struct erofs_iostream *ios, int fd, int decoder) ios->feof = !fsz; ios->sz = 0; } else { - ios->feof = false; ios->sz = fsz; if (lseek(fd, 0, SEEK_SET)) return -EIO; @@ -161,6 +186,37 @@ int erofs_iostream_read(struct erofs_iostream *ios, void **buf, u64 bytes) ios->tail += ret; #else return -EOPNOTSUPP; +#endif + } else if (ios->decoder == EROFS_IOS_DECODER_LIBLZMA) { +#ifdef HAVE_LIBLZMA + struct erofs_iostream_liblzma *lzma = ios->lzma; + lzma_action action = LZMA_RUN; + lzma_ret ret2; + + if (!lzma->strm.avail_in) { + lzma->strm.next_in = lzma->inbuf; + ret = read(lzma->fd, lzma->inbuf, + sizeof(lzma->inbuf)); + if (ret < 0) + return -errno; + lzma->strm.avail_in = ret; + if (ret < sizeof(lzma->inbuf)) + action = LZMA_FINISH; + } + lzma->strm.next_out = (u8 *)ios->buffer + rabytes; + lzma->strm.avail_out = ios->bufsize - rabytes; + + ret2 = lzma_code(&lzma->strm, action); + if (ret2 != LZMA_OK) { + if (ret2 == LZMA_STREAM_END) + ios->feof = true; + else + return -EIO; + } + ios->tail += ios->bufsize - rabytes - + lzma->strm.avail_out; +#else + return -EOPNOTSUPP; #endif } else { ret = erofs_read_from_fd(ios->fd, ios->buffer + rabytes, diff --git a/man/mkfs.erofs.1 b/man/mkfs.erofs.1 index 41eb5fb..3bff41d 100644 --- a/man/mkfs.erofs.1 +++ b/man/mkfs.erofs.1 @@ -162,10 +162,6 @@ When this option is used together with the final file gids are set to \fIGID\fR + \fIGID-OFFSET\fR. .TP -.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. .TP @@ -210,6 +206,14 @@ When this option is used together with the final file uids are set to \fIUID\fR + \fIUIDOFFSET\fR. .TP +.BI \-\-ungzip\fR[\fP= file \fR]\fP +Filter tarball streams through gzip. Optionally, raw streams can be dumped +together. +.TP +.BI \-\-unxz\fR[\fP= file \fR]\fP +Filter tarball streams through xz, lzma, or lzip. Optionally, raw streams can +be dumped together. +.TP .BI "\-\-xattr-prefix=" PREFIX Specify a customized extended attribute namespace prefix for space saving, e.g. "trusted.overlay.". You may give multiple diff --git a/mkfs/main.c b/mkfs/main.c index 258c1ce..8a68a72 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -69,11 +69,15 @@ static struct option long_options[] = { {"block-list-file", required_argument, NULL, 515}, #endif {"ovlfs-strip", optional_argument, NULL, 516}, + {"offset", required_argument, NULL, 517}, #ifdef HAVE_ZLIB - {"gzip", no_argument, NULL, 517}, - {"ungzip", optional_argument, NULL, 517}, + {"gzip", no_argument, NULL, 518}, + {"ungzip", optional_argument, NULL, 518}, +#endif +#ifdef HAVE_LIBLZMA + {"unlzma", optional_argument, NULL, 519}, + {"unxz", optional_argument, NULL, 519}, #endif - {"offset", required_argument, NULL, 518}, {0, 0, 0, 0}, }; @@ -153,10 +157,6 @@ static void usage(int argc, char **argv) " --force-gid=# set all file gids to # (# = GID)\n" " --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 - " --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" " --preserve-mtime keep per-file modification time strictly\n" @@ -170,6 +170,14 @@ static void usage(int argc, char **argv) #ifndef NDEBUG " --random-pclusterblks randomize pclusterblks for big pcluster (debugging only)\n" " --random-algorithms randomize per-file algorithms (debugging only)\n" +#endif +#ifdef HAVE_ZLIB + " --ungzip[=X] try to filter the tarball stream through gzip\n" + " (and optionally dump the raw stream to X together)\n" +#endif +#ifdef HAVE_LIBLZMA + " --unxz[=X] try to filter the tarball stream through xz/lzma/lzip\n" + " (and optionally dump the raw stream to X together)\n" #endif " --xattr-prefix=X X=extra xattr name prefix\n" " --mount-point=X X=prefix of target fs path (default: /)\n" @@ -194,7 +202,7 @@ static unsigned int pclustersize_packed, pclustersize_max; static struct erofs_tarfile erofstar = { .global.xattrs = LIST_HEAD_INIT(erofstar.global.xattrs) }; -static bool tar_mode, rebuild_mode, gzip_supported; +static bool tar_mode, rebuild_mode; static unsigned int rebuild_src_count; static LIST_HEAD(rebuild_src_list); @@ -413,6 +421,7 @@ static int mkfs_parse_options_cfg(int argc, char *argv[]) char *endptr; int opt, i, err; bool quiet = false; + int tarerofs_decoder = 0; while ((opt = getopt_long(argc, argv, "C:E:L:T:U:b:d:x:z:Vh", long_options, NULL)) != -1) { @@ -639,17 +648,18 @@ 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: sbi.diskoffset = strtoull(optarg, &endptr, 0); if (*endptr != '\0') { erofs_err("invalid disk offset %s", optarg); return -EINVAL; } break; + case 518: + case 519: + if (optarg) + erofstar.dumpfile = strdup(optarg); + tarerofs_decoder = EROFS_IOS_DECODER_GZIP + (opt - 518); + break; case 'V': version(); exit(0); @@ -696,7 +706,8 @@ static int mkfs_parse_options_cfg(int argc, char *argv[]) strerror(errno)); return -errno; } - err = erofs_iostream_open(&erofstar.ios, dupfd, gzip_supported); + err = erofs_iostream_open(&erofstar.ios, dupfd, + tarerofs_decoder); if (err) return err; } @@ -717,7 +728,8 @@ static int mkfs_parse_options_cfg(int argc, char *argv[]) erofs_err("failed to open file: %s", cfg.c_src_path); return -errno; } - err = erofs_iostream_open(&erofstar.ios, fd, gzip_supported); + err = erofs_iostream_open(&erofstar.ios, fd, + tarerofs_decoder); if (err) return err; -- 2.39.3
