From 95a15d238120167959bd7aee3e71ac5be3a72804 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sat, 17 Apr 2021 05:54:36 -0500 Subject: Teach cpio to skip runs of NUL bytes between records. --- tests/cpio.test | 2 ++ toys/posix/cpio.c | 23 +++++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/tests/cpio.test b/tests/cpio.test index 3955800f..9d9d9ba9 100755 --- a/tests/cpio.test +++ b/tests/cpio.test @@ -58,6 +58,8 @@ testing "-i keeps existing files" "echo new >a/b && cpio -i /dev/null; testing "-id keeps existing files" "echo new >a/b && cpio -id /dev/null; cat a/b" "new\n" "" "" testing "-iu replaces existing files; no error" "echo new >a/b && cpio -iu a/b && cpio -idu /dev/null; cat a.cpio; done | cpio -t -H newc" \ + "a\na/b\na\na/b\n" "" "" rm -rf a a.cpio testing "error on empty file" \ diff --git a/toys/posix/cpio.c b/toys/posix/cpio.c index d90be7f3..07c294f0 100644 --- a/toys/posix/cpio.c +++ b/toys/posix/cpio.c @@ -3,7 +3,8 @@ * Copyright 2013 Isaac Dunham * Copyright 2015 Frontier Silicon Ltd. * - * see http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/cpio.html + * see https://www.kernel.org/doc/Documentation/early-userspace/buffer-format.txt + * and http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/cpio.html * and http://pubs.opengroup.org/onlinepubs/7908799/xcu/cpio.html * * Yes, that's SUSv2, newer versions removed it, but RPM and initramfs use @@ -11,7 +12,7 @@ * expanded headers to 110 bytes (first field 6 bytes, rest are 8). * In order: magic ino mode uid gid nlink mtime filesize devmajor devminor * rdevmajor rdevminor namesize check - * This is the equiavlent of mode -H newc when using GNU CPIO. + * This is the equivalent of mode -H newc in other implementations. * * todo: export/import linux file list text format ala gen_initramfs_list.sh @@ -113,11 +114,21 @@ void cpio_main(void) if (FLAG(i) || FLAG(t)) for (;; empty = 0) { char *name, *tofree, *data; - unsigned size, mode, uid, gid, timestamp; - int test = FLAG(t), err = 0; + unsigned mode, uid, gid, timestamp; + int test = FLAG(t), err = 0, size = 0, len; - // Read header and name. - if (!(size = readall(afd, toybuf, 110))) { + // read header, skipping arbitrary leading NUL bytes (concatenated archives) + for (;;) { + if (1>(len = readall(afd, toybuf+size, 110-size))) break; + if (size || *toybuf) { + size += len; + break; + } + for (size = 0; size