aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2021-04-17 05:54:36 -0500
committerRob Landley <rob@landley.net>2021-04-17 05:54:36 -0500
commit95a15d238120167959bd7aee3e71ac5be3a72804 (patch)
treecbf37c21f822542971b1c916e1f36be25a1a3116
parentdafb9211c77788d7ea124aca18205e924d1ac48a (diff)
downloadtoybox-95a15d238120167959bd7aee3e71ac5be3a72804.tar.gz
Teach cpio to skip runs of NUL bytes between records.
-rwxr-xr-xtests/cpio.test2
-rw-r--r--toys/posix/cpio.c23
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;
}