In order to allow a CPIO archive to be parsed without actually extracting anything add a parse_only flag. Signed-off-by: Jonathan McDowell <noodles@xxxxxx> --- include/linux/cpio.h | 2 ++ lib/cpio.c | 35 ++++++++++++++++++++++++++++------- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/include/linux/cpio.h b/include/linux/cpio.h index 7e9888e6a1ad..5b897d1d3143 100644 --- a/include/linux/cpio.h +++ b/include/linux/cpio.h @@ -78,6 +78,8 @@ struct cpio_context { struct cpio_link_hash *link_hash[CPIO_LINK_HASH_SIZE]; struct list_head dir_list; + + bool parse_only; }; int __cpio cpio_start(struct cpio_context *ctx); diff --git a/lib/cpio.c b/lib/cpio.c index 03967e063c76..37e2e2071c8d 100644 --- a/lib/cpio.c +++ b/lib/cpio.c @@ -15,7 +15,12 @@ static ssize_t __cpio xwrite(struct cpio_context *ctx, struct file *file, /* sys_write only can write MAX_RW_COUNT aka 2G-4K bytes at most */ while (count) { - ssize_t rv = kernel_write(file, p, count, pos); + ssize_t rv; + + if (ctx->parse_only) + rv = count; + else + rv = kernel_write(file, p, count, pos); if (rv < 0) { if (rv == -EINTR || rv == -EAGAIN) @@ -136,7 +141,8 @@ static void __cpio dir_utime(struct cpio_context *ctx) list_for_each_entry_safe(de, tmp, &ctx->dir_list, list) { list_del(&de->list); - do_utime(de->name, de->mtime); + if (!ctx->parse_only) + do_utime(de->name, de->mtime); kfree(de); } } @@ -374,6 +380,13 @@ static int __cpio do_name(struct cpio_context *ctx) free_hash(ctx); return 0; } + + if (ctx->parse_only) { + if (S_ISREG(ctx->mode)) + ctx->state = CPIO_COPYFILE; + return 0; + } + clean_path(ctx->collected, ctx->mode); if (S_ISREG(ctx->mode)) { int ml = maybe_link(ctx); @@ -454,8 +467,10 @@ static int __cpio do_copy(struct cpio_context *ctx) if (ret != ctx->body_len) return (ret < 0) ? ret : -EIO; - do_utime_path(&ctx->wfile->f_path, ctx->mtime); - fput(ctx->wfile); + if (!ctx->parse_only) { + do_utime_path(&ctx->wfile->f_path, ctx->mtime); + fput(ctx->wfile); + } if (ctx->csum_present && ctx->io_csum != ctx->hdr_csum) return -EBADMSG; @@ -480,6 +495,12 @@ static int __cpio do_symlink(struct cpio_context *ctx) struct path path; int error; + ctx->state = CPIO_SKIPIT; + ctx->next_state = CPIO_RESET; + + if (ctx->parse_only) + return 0; + ctx->collected[N_ALIGN(ctx->name_len) + ctx->body_len] = '\0'; clean_path(ctx->collected, 0); @@ -498,8 +519,7 @@ static int __cpio do_symlink(struct cpio_context *ctx) cpio_chown(ctx->collected, ctx->uid, ctx->gid, AT_SYMLINK_NOFOLLOW); do_utime(ctx->collected, ctx->mtime); - ctx->state = CPIO_SKIPIT; - ctx->next_state = CPIO_RESET; + return 0; } @@ -581,7 +601,8 @@ int __cpio cpio_start(struct cpio_context *ctx) void __cpio cpio_finish(struct cpio_context *ctx) { - dir_utime(ctx); + if (!ctx->parse_only) + dir_utime(ctx); kfree(ctx->name_buf); kfree(ctx->symlink_buf); kfree(ctx->header_buf); -- 2.30.2