aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xtests/cpio.test18
-rw-r--r--toys/posix/cpio.c9
2 files changed, 23 insertions, 4 deletions
diff --git a/tests/cpio.test b/tests/cpio.test
index 6ab3665a..7e2955a1 100755
--- a/tests/cpio.test
+++ b/tests/cpio.test
@@ -42,4 +42,20 @@ touch a; chmod a-rwx a; ln -s a/cant b
toyonly testing "archives unreadable empty files" "cpio -o -H newc|cpio -it" "b\na\n" "" "b\na\n"
chmod u+rw a; rm -f a b
-
+mkdir a
+echo "old" >a/b
+echo "a/b" | cpio -o -H newc >a.cpio
+rm -rf a
+testing "-i doesn't create leading directories" "cpio -i <a.cpio 2>/dev/null; [ -e a ] || echo yes" "yes\n" "" ""
+rm -rf a
+testing "-id creates leading directories" "cpio -id <a.cpio && cat a/b" "old\n" "" ""
+rm -rf a a.cpio
+
+mkdir a
+echo "old" >a/b
+find a | cpio -o -H newc >a.cpio
+testing "-i keeps existing files" "echo new >a/b && cpio -i <a.cpio 2>/dev/null; cat a/b" "new\n" "" ""
+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" "" ""
+rm -rf a a.cpio
diff --git a/toys/posix/cpio.c b/toys/posix/cpio.c
index 04700ddb..b60e19b4 100644
--- a/toys/posix/cpio.c
+++ b/toys/posix/cpio.c
@@ -22,7 +22,7 @@ config CPIO
default y
help
usage: cpio -{o|t|i|p DEST} [-v] [--verbose] [-F FILE] [--no-preserve-owner]
- [ignored: -mdu -H newc]
+ [ignored: -m -H newc]
Copy files into and out of a "newc" format cpio archive.
@@ -32,6 +32,7 @@ config CPIO
-o Create archive (stdin=list of files, stdout=archive)
-t Test files (list only, stdin=archive, stdout=list of files)
-d Create directories if needed
+ -u unlink existing files when extracting
-v Verbose
--no-preserve-owner (don't set ownership during extract)
*/
@@ -137,6 +138,8 @@ void cpio_main(void)
// (This output is unaffected by --quiet.)
if (FLAG(t) || FLAG(v)) puts(name);
+ if (FLAG(u) && !test) if (unlink(name) && errno == EISDIR) rmdir(name);
+
if (!test && FLAG(d) && strrchr(name, '/') && mkpath(name)) {
perror_msg("mkpath '%s'", name);
test++;
@@ -146,7 +149,7 @@ void cpio_main(void)
// properly aligned with next file.
if (S_ISDIR(mode)) {
- if (!test) err = mkdir(name, mode);
+ if (!test) err = mkdir(name, mode) && !FLAG(u);
} else if (S_ISLNK(mode)) {
data = strpad(afd, size, 0);
if (!test) err = symlink(data, name);
@@ -155,7 +158,7 @@ void cpio_main(void)
if (!err && !geteuid() && !FLAG(no_preserve_owner))
err = lchown(name, uid, gid);
} else if (S_ISREG(mode)) {
- int fd = test ? 0 : open(name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW, mode);
+ int fd = test ? 0 : open(name, O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, mode);
// If write fails, we still need to read/discard data to continue with
// archive. Since doing so overwrites errno, report error now