[Toybox] [PATCH] cpio: Implement -u (copy unconditionally)

Yi-yo Chiang yochiang at google.com
Thu Feb 25 08:20:57 PST 2021


Thanks for checking, Rob and Elliott!
It intriguing that in my personal, non-work mailbox, my own mail from this
address got filtered to spam too, and Rob's mail in the thread got silently
dropped... despite me pressing the "report not spam" button multiple times
already 🤔

Perhaps gmail doesn't like big block of c-code?

On Thu, Feb 25, 2021 at 10:21 AM enh via Toybox <toybox at lists.landley.net>
wrote:

> No hurry, I was just checking that something like that hadn't happened 😀
>
> On Wed, Feb 24, 2021, 17:04 Rob Landley <rob at landley.net> wrote:
>
>> Ah, sorry. His email (and the follow up) wound up in gmail's spam filter
>> again.
>>
>> I'll try to take a look tonight.
>>
>> Rob
>>
>> On 2/24/21 12:17 PM, enh via Toybox wrote:
>> > ping?
>> >
>> > On Sun, Feb 14, 2021 at 5:13 AM Yi-Yo Chiang via Toybox
>> > <toybox at lists.landley.net <mailto:toybox at lists.landley.net>> wrote:
>> >
>> >     If -u is specified, then replace any existing files or directories.
>> >
>> >     If -u is not specified and the path to be inflated already exist,
>> then
>> >     report EEXIST error. This behaves slightly different from GNU cpio,
>> as
>> >     GNU cpio checks the timestamp and replaces when the timestamp of the
>> >     existing file is older than the one from the archive. This still
>> >     conforms to SUSv2 as it doesn't define how to behave when -u is not
>> >     specified.
>> >
>> >     There is an exception, if we are creating an existing directory,
>> then
>> >     don't report any error or try to rmdir() the directory as we can
>> >     "create" the directory by chmod() / chown() the existing one.
>> >
>> >     ---
>> >      tests/cpio.test   | 16 ++++++++++++++++
>> >      toys/posix/cpio.c | 46
>> ++++++++++++++++++++++++++++++++++++----------
>> >      2 files changed, 52 insertions(+), 10 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 31c777c9..795f890c 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 Copy unconditionally
>> >          -v Verbose
>> >          --no-preserve-owner (don't set ownership during extract)
>> >      */
>> >     @@ -113,7 +114,8 @@ void cpio_main(void)
>> >        if (FLAG(i) || FLAG(t)) for (;;) {
>> >          char *name, *tofree, *data;
>> >          unsigned size, mode, uid, gid, timestamp;
>> >     -    int test = FLAG(t), err = 0;
>> >     +    int test = FLAG(t), err = 0, exist = 0;
>> >     +    struct stat st;
>> >
>> >          // Read header and name.
>> >          if (!(size =readall(afd, toybuf, 110))) break;
>> >     @@ -137,25 +139,50 @@ void cpio_main(void)
>> >          // (This output is unaffected by --quiet.)
>> >          if (FLAG(t) || FLAG(v)) puts(name);
>> >
>> >     -    if (!test && FLAG(d) && strrchr(name, '/') && mkpath(name)) {
>> >     +    if (!test) exist = !lstat(name, &st);
>> >     +
>> >     +    // Create leading directories if |name| doesn't exist.
>> >     +    if (!test && !exist && FLAG(d) && strrchr(name, '/') &&
>> mkpath(name)) {
>> >            perror_msg("mkpath '%s'", name);
>> >            test++;
>> >          }
>> >
>> >     +    // Don't report error or try to rmdir(name) if we want to
>> mkdir(name)
>> >     later.
>> >     +    if (!test && exist && !(S_ISDIR(st.st_mode) && S_ISDIR(mode)))
>> {
>> >     +      if (!FLAG(u)) {
>> >     +        errno = EEXIST;
>> >     +        perror_msg_raw(name);
>> >     +        test++;
>> >     +      } else if (S_ISDIR(st.st_mode) ? rmdir(name) : unlink(name))
>> {
>> >     +        perror_msg("remove '%s'", name);
>> >     +        test++;
>> >     +      } else {
>> >     +        exist = 0;
>> >     +      }
>> >     +    }
>> >     +
>> >          // Consume entire record even if it couldn't create file, so
>> we're
>> >          // properly aligned with next file.
>> >
>> >          if (S_ISDIR(mode)) {
>> >     -      if (!test) err = mkdir(name, mode);
>> >     +      if (!test) {
>> >     +        // If |name| already exist as a directory, then just do a
>> chmod()
>> >     to fix
>> >     +        // up the directory permissions.
>> >     +        if (!exist) err = mkdir(name, mode);
>> >     +        else if (S_ISDIR(st.st_mode)) err = chmod(name, mode);
>> >     +        else err = errno = EEXIST;
>> >     +      }
>> >          } else if (S_ISLNK(mode)) {
>> >            data = strpad(afd, size, 0);
>> >     -      if (!test) err = symlink(data, name);
>> >     +      if (!test) {
>> >     +        err = symlink(data, name);
>> >     +        // Can't get a filehandle to a symlink, so do special chown
>> >     +        if (!err && !geteuid() && !FLAG(no_preserve_owner))
>> >     +          err = lchown(name, uid, gid);
>> >     +      }
>> >            free(data);
>> >     -      // Can't get a filehandle to a symlink, so do special chown
>> >     -      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_EXCL|O_WRONLY|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
>> >     @@ -197,7 +224,6 @@ void cpio_main(void)
>> >                && !FLAG(no_preserve_owner))
>> >            {
>> >              int fd = open(name, O_RDONLY|O_NOFOLLOW);
>> >     -        struct stat st;
>> >
>> >              if (fd != -1 && !fstat(fd, &st) && (st.st_mode&S_IFMT) ==
>> >     (mode&S_IFMT))
>> >                err = fchown(fd, uid, gid);
>> >     --
>> >     2.30.0.478.g8a0d178c01-goog
>> >
>> >     _______________________________________________
>> >     Toybox mailing list
>> >     Toybox at lists.landley.net <mailto:Toybox at lists.landley.net>
>> >     http://lists.landley.net/listinfo.cgi/toybox-landley.net
>> >
>> >
>> > _______________________________________________
>> > Toybox mailing list
>> > Toybox at lists.landley.net
>> > http://lists.landley.net/listinfo.cgi/toybox-landley.net
>> >
>> _______________________________________________
>> Toybox mailing list
>> Toybox at lists.landley.net
>> http://lists.landley.net/listinfo.cgi/toybox-landley.net
>>
> _______________________________________________
> Toybox mailing list
> Toybox at lists.landley.net
> http://lists.landley.net/listinfo.cgi/toybox-landley.net
>


-- 

Yi-yo Chiang
Software Engineer
yochiang at google.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.landley.net/pipermail/toybox-landley.net/attachments/20210226/d9f55a23/attachment.html>


More information about the Toybox mailing list