From: Chengyu Zhu <[email protected]> Replace numeric layer_index with layer_digest string for more precise and reliable OCI layer identification. This change affects both mkfs.erofs and mount.erofs tools.
Signed-off-by: Chengyu Zhu <[email protected]> --- lib/liberofs_oci.h | 6 ++-- lib/remotes/oci.c | 72 ++++++++++++++++++++++++++++++++-------------- mkfs/main.c | 21 +++++++------- mount/main.c | 33 +++++++++++---------- 4 files changed, 82 insertions(+), 50 deletions(-) diff --git a/lib/liberofs_oci.h b/lib/liberofs_oci.h index aa41141..ef8d0ea 100644 --- a/lib/liberofs_oci.h +++ b/lib/liberofs_oci.h @@ -21,7 +21,7 @@ struct erofs_importer; * @platform: target platform in "os/arch" format (e.g., "linux/amd64") * @username: username for authentication (optional) * @password: password for authentication (optional) - * @layer_index: specific layer to extract (-1 for all layers) + * @layer_digest: specific layer digest to extract (NULL for all layers) * * Configuration structure for OCI image parameters including registry * location, image identification, platform specification, and authentication @@ -32,7 +32,7 @@ struct ocierofs_config { char *platform; char *username; char *password; - int layer_index; + char *layer_digest; }; struct ocierofs_layer_info { @@ -51,7 +51,7 @@ struct ocierofs_ctx { char *tag; char *manifest_digest; struct ocierofs_layer_info **layers; - int layer_index; + char *layer_digest; int layer_count; }; diff --git a/lib/remotes/oci.c b/lib/remotes/oci.c index 26aec27..f6181cc 100644 --- a/lib/remotes/oci.c +++ b/lib/remotes/oci.c @@ -898,6 +898,21 @@ static int ocierofs_prepare_auth(struct ocierofs_ctx *ctx, return 0; } +static int ocierofs_find_layer_by_digest(struct ocierofs_ctx *ctx, const char *digest) +{ + int i; + + if (!digest || !ctx->layers) + return -1; + + for (i = 0; i < ctx->layer_count; i++) { + if (ctx->layers[i] && ctx->layers[i]->digest && + !strcmp(ctx->layers[i]->digest, digest)) + return i; + } + return -1; +} + static int ocierofs_prepare_layers(struct ocierofs_ctx *ctx, const struct ocierofs_config *config) { @@ -925,16 +940,18 @@ static int ocierofs_prepare_layers(struct ocierofs_ctx *ctx, goto out_manifest; } - if (ctx->layer_index >= ctx->layer_count) { - erofs_err("layer index %d exceeds available layers (%d)", - ctx->layer_index, ctx->layer_count); - ret = -EINVAL; - goto out_layers; + if (ctx->layer_digest) { + if (ocierofs_find_layer_by_digest(ctx, ctx->layer_digest) < 0) { + erofs_err("layer digest %s not found in image layers", + ctx->layer_digest); + ret = -ENOENT; + goto out_layers; + } } return 0; out_layers: - free(ctx->layers); + ocierofs_free_layers_info(ctx->layers, ctx->layer_count); ctx->layers = NULL; out_manifest: free(ctx->manifest_digest); @@ -1054,10 +1071,10 @@ static int ocierofs_init(struct ocierofs_ctx *ctx, const struct ocierofs_config if (ocierofs_curl_setup_common_options(ctx->curl)) return -EIO; - if (config->layer_index >= 0) - ctx->layer_index = config->layer_index; + if (config->layer_digest) + ctx->layer_digest = strdup(config->layer_digest); else - ctx->layer_index = -1; + ctx->layer_digest = NULL; ctx->registry = strdup("registry-1.docker.io"); ctx->tag = strdup("latest"); if (config->platform) @@ -1190,6 +1207,7 @@ static void ocierofs_ctx_cleanup(struct ocierofs_ctx *ctx) free(ctx->tag); free(ctx->platform); free(ctx->manifest_digest); + free(ctx->layer_digest); } int ocierofs_build_trees(struct erofs_importer *importer, @@ -1204,8 +1222,13 @@ int ocierofs_build_trees(struct erofs_importer *importer, return ret; } - if (ctx.layer_index >= 0) { - i = ctx.layer_index; + if (ctx.layer_digest) { + i = ocierofs_find_layer_by_digest(&ctx, ctx.layer_digest); + if (i < 0) { + erofs_err("layer digest %s not found", ctx.layer_digest); + ret = -ENOENT; + goto out; + } end = i + 1; } else { i = 0; @@ -1215,25 +1238,26 @@ int ocierofs_build_trees(struct erofs_importer *importer, while (i < end) { char *trimmed = erofs_trim_for_progressinfo(ctx.layers[i]->digest, sizeof("Extracting layer ...") - 1); - erofs_update_progressinfo("Extracting layer %d: %s ...", i, - trimmed); + erofs_update_progressinfo("Extracting layer %s ...", trimmed); free(trimmed); fd = ocierofs_extract_layer(&ctx, ctx.layers[i]->digest, ctx.auth_header); if (fd < 0) { - erofs_err("failed to extract layer %d: %s", i, - erofs_strerror(fd)); + erofs_err("failed to extract layer %s: %s", + ctx.layers[i]->digest, erofs_strerror(fd)); + ret = fd; break; } ret = ocierofs_process_tar_stream(importer, fd); close(fd); if (ret) { - erofs_err("failed to process tar stream for layer %d: %s", i, - erofs_strerror(ret)); + erofs_err("failed to process tar stream for layer %s: %s", + ctx.layers[i]->digest, erofs_strerror(ret)); break; } i++; } +out: ocierofs_ctx_cleanup(&ctx); return ret; } @@ -1246,12 +1270,18 @@ static int ocierofs_download_blob_range(struct ocierofs_ctx *ctx, off_t offset, const char *api_registry; char rangehdr[64]; long http_code = 0; - int ret; - int index = ctx->layer_index; - u64 blob_size = ctx->layers[index]->size; + int ret, index; + const char *digest; + u64 blob_size; size_t available; size_t copy_size; + index = ocierofs_find_layer_by_digest(ctx, ctx->layer_digest); + if (index < 0) + return -ENOENT; + digest = ctx->layer_digest; + blob_size = ctx->layers[index]->size; + if (offset < 0) return -EINVAL; @@ -1265,7 +1295,7 @@ static int ocierofs_download_blob_range(struct ocierofs_ctx *ctx, off_t offset, api_registry = ocierofs_get_api_registry(ctx->registry); if (asprintf(&req.url, "https://%s/v2/%s/blobs/%s", - api_registry, ctx->repository, ctx->layers[index]->digest) == -1) + api_registry, ctx->repository, digest) == -1) return -ENOMEM; if (length) diff --git a/mkfs/main.c b/mkfs/main.c index a8208d4..a34e58b 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -213,7 +213,7 @@ static void usage(int argc, char **argv) #endif #ifdef OCIEROFS_ENABLED " --oci[=platform=X] X=platform (default: linux/amd64)\n" - " [,layer=Y] Y=layer index to extract (0-based; omit to extract all layers)\n" + " [,layer=Y] Y=layer 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" #endif @@ -728,16 +728,15 @@ static int mkfs_parse_oci_options(struct ocierofs_config *oci_cfg, char *options p = strstr(opt, "layer="); if (p) { p += strlen("layer="); - { - char *endptr; - unsigned long v = strtoul(p, &endptr, 10); + free(oci_cfg->layer_digest); - if (endptr == p || *endptr != '\0') { - erofs_err("invalid layer index %s", - p); - return -EINVAL; - } - oci_cfg->layer_index = (int)v; + if (strncmp(p, "sha256:", 7) != 0) { + if (asprintf(&oci_cfg->layer_digest, "sha256:%s", p) < 0) + return -ENOMEM; + } else { + oci_cfg->layer_digest = strdup(p); + if (!oci_cfg->layer_digest) + return -ENOMEM; } } else { p = strstr(opt, "username="); @@ -1838,7 +1837,7 @@ int main(int argc, char **argv) #endif #ifdef OCIEROFS_ENABLED } else if (source_mode == EROFS_MKFS_SOURCE_OCI) { - ocicfg.layer_index = -1; + ocicfg.layer_digest = NULL; err = mkfs_parse_oci_options(&ocicfg, mkfs_oci_options); if (err) diff --git a/mount/main.c b/mount/main.c index f368746..7094344 100644 --- a/mount/main.c +++ b/mount/main.c @@ -85,13 +85,15 @@ static int erofsmount_parse_oci_option(const char *option) p = strstr(option, "oci.layer="); if (p != NULL) { p += strlen("oci.layer="); - { - char *endptr; - unsigned long v = strtoul(p, &endptr, 10); + free(oci_cfg->layer_digest); - if (endptr == p || *endptr != '\0') - return -EINVAL; - oci_cfg->layer_index = (int)v; + if (strncmp(p, "sha256:", 7) != 0) { + if (asprintf(&oci_cfg->layer_digest, "sha256:%s", p) < 0) + return -ENOMEM; + } else { + oci_cfg->layer_digest = strdup(p); + if (!oci_cfg->layer_digest) + return -ENOMEM; } } else { p = strstr(option, "oci.platform="); @@ -125,7 +127,7 @@ static int erofsmount_parse_oci_option(const char *option) } if (oci_cfg->platform || oci_cfg->username || oci_cfg->password || - oci_cfg->layer_index) + oci_cfg->layer_digest) nbdsrc.type = EROFSNBD_SOURCE_OCI; return 0; } @@ -413,10 +415,10 @@ static int erofsmount_write_recovery_oci(FILE *f, struct erofs_nbd_source *sourc if (IS_ERR(b64cred)) return PTR_ERR(b64cred); } - ret = fprintf(f, "OCI_LAYER %s %s %d %s\n", + ret = fprintf(f, "OCI_LAYER %s %s %s %s\n", source->ocicfg.image_ref ?: "", source->ocicfg.platform ?: "", - source->ocicfg.layer_index, + source->ocicfg.layer_digest ?: "", b64cred ?: ""); free(b64cred); return ret < 0 ? -ENOMEM : 0; @@ -485,8 +487,6 @@ static int erofsmount_parse_recovery_ocilayer(struct ocierofs_config *oci_cfg, int token_count = 0; char *p = source; int err; - char *endptr; - unsigned long v; while (token_count < 4 && (p = strchr(p, ' ')) != NULL) { *p++ = '\0'; @@ -503,10 +503,13 @@ static int erofsmount_parse_recovery_ocilayer(struct ocierofs_config *oci_cfg, oci_cfg->image_ref = source; oci_cfg->platform = tokens[0]; - v = strtoul(tokens[1], &endptr, 10); - if (endptr == tokens[1] || *endptr != '\0') - return -EINVAL; - oci_cfg->layer_index = (int)v; + if (tokens[1] && strlen(tokens[1]) > 0) { + oci_cfg->layer_digest = strdup(tokens[1]); + if (!oci_cfg->layer_digest) + return -ENOMEM; + } else { + oci_cfg->layer_digest = NULL; + } if (token_count > 2) { err = ocierofs_decode_userpass(tokens[2], &oci_cfg->username, -- 2.51.0
