diff mbox series

[RFC,v2,5/7] lib/cpio: Add a parse-only option that doesn't extract any files

Message ID f610468635ef9933d03b130aa81cc07f8bfc6d00.1659003817.git.noodles@fb.com (mailing list archive)
State New, archived
Headers show
Series [RFC,v2,1/7] initramfs: Move cpio handling routines into lib/ | expand

Commit Message

Jonathan McDowell July 28, 2022, 2:09 p.m. UTC
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@fb.com>
---
 include/linux/cpio.h |  2 ++
 lib/cpio.c           | 35 ++++++++++++++++++++++++++++-------
 2 files changed, 30 insertions(+), 7 deletions(-)
diff mbox series

Patch

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);