diff options
-rwxr-xr-x | tests/cpio.test | 2 | ||||
-rw-r--r-- | 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 <a.cpio 2>/dev/null; testing "-id keeps existing files" "echo new >a/b && cpio -id <a.cpio 2>/dev/null; cat a/b" "new\n" "" "" testing "-iu replaces existing files; no error" "echo new >a/b && cpio -iu <a.cpio && cat a/b" "old\n" "" "" testing "-idu replaces existing files; no error" "echo new >a/b && cpio -idu <a.cpio && cat a/b" "old\n" "" "" +testing "skip NUL" "for i in a b; do dd if=/dev/zero bs=512 count=1 2>/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 <ibid.ag@gmail.com> * 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<len; size++) if (toybuf[size]) break; + memmove(toybuf, toybuf+size, len-size); + size = len-size; + } + if (!size) { if (empty) error_exit("empty archive"); else break; } |