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

enh enh at google.com
Wed Feb 24 18:21:27 PST 2021


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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.landley.net/pipermail/toybox-landley.net/attachments/20210224/aac8dd17/attachment-0001.html>


More information about the Toybox mailing list