From: Chengyu Zhu <hudson...@tencent.com> Introduce OCI tarindex mode and optional zinfo generation.
e.g.: mkfs.erofs --oci=i,platform=linux/amd64,layer=3 \ --gzinfo=golang.zinfo golang.erofs golang:1.22.8 Signed-off-by: Chengyu Zhu <hudson...@tencent.com> --- lib/remotes/oci.c | 57 ++++++++++++++++++++++++++++++++++++++--- mkfs/main.c | 65 ++++++++++++++++++++++++++++------------------- 2 files changed, 92 insertions(+), 30 deletions(-) diff --git a/lib/remotes/oci.c b/lib/remotes/oci.c index b25e0b2..349e080 100644 --- a/lib/remotes/oci.c +++ b/lib/remotes/oci.c @@ -27,6 +27,7 @@ #include "liberofs_base64.h" #include "liberofs_oci.h" #include "liberofs_private.h" +#include "liberofs_gzran.h" #ifdef OCIEROFS_ENABLED @@ -840,14 +841,33 @@ out: return ret; } -static int ocierofs_process_tar_stream(struct erofs_importer *importer, int fd) +static int ocierofs_process_tar_stream(struct erofs_importer *importer, int fd, + const struct ocierofs_config *config, + u64 *tar_offset_out) { struct erofs_tarfile tarfile = {}; - int ret; + int ret, decoder, zinfo_fd; + struct erofs_vfile vf; init_list_head(&tarfile.global.xattrs); - ret = erofs_iostream_open(&tarfile.ios, fd, EROFS_IOS_DECODER_GZIP); + /* + * Choose decoder based on config: + * - tarindex + zinfo → tar.gzip (GZRAN decoder) + * - tarindex only → tar (no decoder, raw) + * - neither → default gzip decoder + */ + if (config && config->tarindex_path) { + tarfile.index_mode = true; + if (config->zinfo_path) + decoder = EROFS_IOS_DECODER_GZRAN; + else + decoder = EROFS_IOS_DECODER_NONE; + } else { + decoder = EROFS_IOS_DECODER_GZIP; + } + + ret = erofs_iostream_open(&tarfile.ios, fd, decoder); if (ret) { erofs_err("failed to initialize tar stream: %s", erofs_strerror(ret)); @@ -858,6 +878,25 @@ static int ocierofs_process_tar_stream(struct erofs_importer *importer, int fd) ret = tarerofs_parse_tar(importer, &tarfile); /* Continue parsing until end of archive */ } while (!ret); + + if (decoder == EROFS_IOS_DECODER_GZRAN) { + zinfo_fd = open(config->zinfo_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (zinfo_fd < 0) { + ret = -errno; + } else { + vf = (struct erofs_vfile){ .fd = zinfo_fd }; + ret = erofs_gzran_builder_export_zinfo(tarfile.ios.gb, &vf); + close(zinfo_fd); + if (ret < 0) { + erofs_err("failed to export zinfo: %s", + erofs_strerror(ret)); + } + } + } + + if (tar_offset_out) + *tar_offset_out = tarfile.offset; + erofs_iostream_close(&tarfile.ios); if (ret < 0 && ret != -ENODATA) { @@ -1230,6 +1269,7 @@ int ocierofs_build_trees(struct erofs_importer *importer, { struct ocierofs_ctx ctx = {}; int ret, i, end, fd; + u64 tar_offset = 0; ret = ocierofs_init(&ctx, config); if (ret) { @@ -1250,6 +1290,12 @@ int ocierofs_build_trees(struct erofs_importer *importer, end = ctx.layer_count; } + if (config->tarindex_path && (end - i) != 1) { + erofs_err("tarindex mode requires exactly one layer (use blob= or layer= option)"); + ret = -EINVAL; + goto out; + } + while (i < end) { char *trimmed = erofs_trim_for_progressinfo(ctx.layers[i]->digest, sizeof("Extracting layer ...") - 1); @@ -1263,7 +1309,7 @@ int ocierofs_build_trees(struct erofs_importer *importer, ret = fd; break; } - ret = ocierofs_process_tar_stream(importer, fd); + ret = ocierofs_process_tar_stream(importer, fd, config, &tar_offset); close(fd); if (ret) { erofs_err("failed to process tar stream for layer %s: %s", @@ -1273,6 +1319,9 @@ int ocierofs_build_trees(struct erofs_importer *importer, i++; } out: + if (config->tarindex_path && importer->sbi) + importer->sbi->devs[0].blocks = BLK_ROUND_UP(importer->sbi, tar_offset); + ocierofs_ctx_cleanup(&ctx); return ret; } diff --git a/mkfs/main.c b/mkfs/main.c index 1c37576..c7359f6 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -218,6 +218,8 @@ static void usage(int argc, char **argv) " [,blob=Y] Y=blob digest to extract (omit to extract all layers)\n" " [,username=Z] Z=username for authentication (optional)\n" " [,password=W] W=password for authentication (optional)\n" + " [,i] generate tarindex file (requires layer or blob selection)\n" + #endif " --tar=X generate a full or index-only image from a tarball(-ish) source\n" " (X = f|i|headerball; f=full mode, i=index mode,\n" @@ -285,7 +287,7 @@ static struct erofs_s3 s3cfg; #ifdef OCIEROFS_ENABLED static struct ocierofs_config ocicfg; -static char *mkfs_oci_options; +static bool mkfs_oci_tarindex_mode; #endif enum { @@ -727,7 +729,7 @@ static int mkfs_parse_s3_cfg(char *cfg_str) * @options_str: comma-separated options string * * Parse OCI options string containing comma-separated key=value pairs. - * Supported options include platform, blob, layer, username, and password. + * Supported options include platform, blob, layer, username, password, i (tarindex mode), and zinfo. * * Return: 0 on success, negative errno on failure */ @@ -745,6 +747,7 @@ static int mkfs_parse_oci_options(struct ocierofs_config *oci_cfg, char *options if (q) *q = '\0'; + p = strstr(opt, "platform="); if (p) { p += strlen("platform="); @@ -790,19 +793,23 @@ static int mkfs_parse_oci_options(struct ocierofs_config *oci_cfg, char *options oci_cfg->username = strdup(p); if (!oci_cfg->username) return -ENOMEM; + } else { + p = strstr(opt, "password="); + if (p) { + p += strlen("password="); + free(oci_cfg->password); + oci_cfg->password = strdup(p); + if (!oci_cfg->password) + return -ENOMEM; + } else { + if (!strcmp(opt, "i")) + mkfs_oci_tarindex_mode = true; + else { + erofs_err("mkfs: invalid --oci value %s", opt); + return -EINVAL; + } + } } - - p = strstr(opt, "password="); - if (p) { - p += strlen("password="); - free(oci_cfg->password); - oci_cfg->password = strdup(p); - if (!oci_cfg->password) - return -ENOMEM; - } - - erofs_err("mkfs: invalid --oci value %s", opt); - return -EINVAL; } } } @@ -1378,10 +1385,13 @@ static int mkfs_parse_options_cfg(struct erofs_importer_params *params, break; #endif #ifdef OCIEROFS_ENABLED - case 534: - mkfs_oci_options = optarg; + case 534: { source_mode = EROFS_MKFS_SOURCE_OCI; + err = mkfs_parse_oci_options(&ocicfg, optarg); + if (err) + return err; break; + } #endif case 535: if (optarg) @@ -1757,6 +1767,9 @@ int main(int argc, char **argv) goto exit; } mkfs_blkszbits = src->blkszbits; + } else if (mkfs_oci_tarindex_mode) { + mkfs_blkszbits = 9; + tar_index_512b = true; } if (!incremental_mode) @@ -1883,13 +1896,11 @@ int main(int argc, char **argv) #endif #ifdef OCIEROFS_ENABLED } else if (source_mode == EROFS_MKFS_SOURCE_OCI) { - ocicfg.blob_digest = NULL; - ocicfg.layer_index = -1; - - err = mkfs_parse_oci_options(&ocicfg, mkfs_oci_options); - if (err) - goto exit; ocicfg.image_ref = cfg.c_src_path; + if (mkfs_oci_tarindex_mode) + ocicfg.tarindex_path = strdup(cfg.c_src_path); + if (!ocicfg.zinfo_path) + ocicfg.zinfo_path = mkfs_aws_zinfo_file; if (incremental_mode || dataimport_mode == EROFS_MKFS_DATA_IMPORT_RVSP || @@ -1914,10 +1925,12 @@ int main(int argc, char **argv) if (!g_sbi.extra_devices) { DBG_BUGON(1); } else { - if (cfg.c_src_path) - g_sbi.devs[0].src_path = strdup(cfg.c_src_path); - g_sbi.devs[0].blocks = - BLK_ROUND_UP(&g_sbi, erofstar.offset); + if (source_mode != EROFS_MKFS_SOURCE_OCI) { + if (cfg.c_src_path) + g_sbi.devs[0].src_path = strdup(cfg.c_src_path); + g_sbi.devs[0].blocks = + BLK_ROUND_UP(&g_sbi, erofstar.offset); + } } } -- 2.47.1