From daea408ef11a8df15ae4e99f422351417657e226 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Fri, 22 Mar 2019 12:49:08 -0500 Subject: More tar cleanup, add --owner and --group, and start of new tests. --- tests/tar.test | 106 ++++------------------------------------------------- toys/pending/tar.c | 66 +++++++++++++++++++-------------- 2 files changed, 46 insertions(+), 126 deletions(-) diff --git a/tests/tar.test b/tests/tar.test index 50a94e60..31aee386 100644 --- a/tests/tar.test +++ b/tests/tar.test @@ -1,104 +1,14 @@ #!/bin/bash -# Copyright 2014 Divya Kothari -# Copyright 2014 Naha Maggu - [ -f testing.sh ] && . testing.sh #testing "name" "command" "result" "infile" "stdin" -#Creating dir -mkdir dir/dir1 -p -echo "This is testdata" > dir/dir1/file -testing "tgz - compession, extraction and data validation" "tar -czf dir.tgz dir/ && [ -e dir.tgz ] && echo 'yes'; rm -rf dir; tar -xf dir.tgz && [ -f dir/dir1/file ] && cat dir/dir1/file; rm -rf dir.tgz" "yes\nThis is testdata\n" "" "" - -#Creating dir -mkdir dir/dir1 -p -echo "This is testdata" > dir/dir1/file -testing "tar.gz - compession, extraction and data validation" "tar -czf dir.tar.gz dir/ && [ -e dir.tar.gz ] && echo 'yes'; rm -rf dir; tar -xf dir.tar.gz && [ -f dir/dir1/file ] && cat dir/dir1/file; rm -rf dir.tar.gz" "yes\nThis is testdata\n" "" "" - -#Creating dir -mkdir dir/dir1 -p -echo "This is testdata" > dir/dir1/file -testing "verbose compression" "tar -cvzf dir.tgz dir/; rm -rf dir.tgz" "dir/\ndir/dir1/\ndir/dir1/file\n" "" "" -rm -rf dir/ - -#creating test file -dd if=/dev/zero of=testFile ibs=4096 obs=4096 count=1000 2>/dev/null -testing "- compession and extraction of a file" "tar -czf testFile.tgz testFile && [ -e testFile.tgz ] && echo 'yes'; rm -rf testFile; tar -xf testFile.tgz && [ -f testFile ] && echo 'yes'; rm -rf testFile.tgz" "yes\nyes\n" "" "" - -#creating empty test file -touch testFile -testing "- compession and extraction of a empty file" "tar -czf testFile.tgz testFile && [ -e testFile.tgz ] && echo 'yes'; rm -rf testFile; tar -xf testFile.tgz && [ -f testFile ] && echo 'yes'; rm -rf testFile.tgz" "yes\nyes\n" "" "" - -#Creating dir -mkdir dir/dir1 -p -touch dir/dir1/file1 dir/dir1/file2 dir/dir1/file3 dir/dir1/file4 -testing "-t option" "tar -czf dir.tar.gz dir/; rm -rf dir; tar -tf dir.tar.gz | sort; rm -rf dir.tar.gz" "dir/\ndir/dir1/\ndir/dir1/file1\ndir/dir1/file2\ndir/dir1/file3\ndir/dir1/file4\n" "" "" -rm -rf dir/ - -#Creating nested directory -mkdir -p dir/dir1 dir/dir2 dir/dir3 dir/dir4 -echo "This is testdata" > dir/dir1/file; echo "Dont exclude me" > dir/dir3/file1 ; -echo "Exclude me" > dir/dir3/file2 ; echo "YO" > dir/dir4/file1 ; echo "Hello" >dir/dir4/file2; echo "Dont" > dir/dir2/file1 -echo -ne "dir/dir4\ndir/dir3/file2\n" > exclude_file -testing "create with files excluded : -X" "tar -czf dir.tgz dir/ -X exclude_file ; rm -rf dir ; tar -tf dir.tgz | sort; rm -rf dir.tgz " "dir/\ndir/dir1/\ndir/dir1/file\ndir/dir2/\ndir/dir2/file1\ndir/dir3/\ndir/dir3/file1\n" "" "" -rm -rf exclude_file - -#Creating nested directory -mkdir dir/dir1 -p ; mkdir dir/dir2 ; mkdir dir/dir3 ; mkdir dir/dir4 -echo "This is testdata" > dir/dir1/file -echo "Dont exclude me" > dir/dir3/file1 ; echo "Exclude me" > dir/dir3/file2 ; echo "YO" > dir/dir4/file1 ; echo "Hello" >dir/dir4/file2; echo "Dont" > dir/dir2/file1 -testing "with pattern --exclude" "tar --exclude=dir/dir3/* -czf dir.tgz dir/ ; rm -rf dir ; tar -tf dir.tgz | sort; rm -rf dir.tgz " "dir/\ndir/dir1/\ndir/dir1/file\ndir/dir2/\ndir/dir2/file1\ndir/dir3/\ndir/dir4/\ndir/dir4/file1\ndir/dir4/file2\n" "" "" - -#Creating directory to be compressed -mkdir dir/dir1 -p -echo "This is testdata" > dir/dir1/file -mkdir temp -testing "extract with -C Dir" "tar -czf dir.tgz dir/ ;rm -rf dir ;tar -xf dir.tgz -C temp/ ; [ -e temp/dir ] && echo 'yes' ; rm -rf dir dir.tgz" "yes\n" "" "" -rm -rf temp - -#Creating nested directory -mkdir dir/dir1 -p ; mkdir dir/dir2 ; mkdir dir/dir3 ; mkdir dir/dir4 ; mkdir temp_dir -echo "dir1/file" > dir/dir1/file ; echo "temp_dir/file" > temp_dir/file -echo "dir3/file1" > dir/dir3/file1 ; echo "dir3/file2" > dir/dir3/file2 ; echo "YO" > dir/dir4/file1 ; echo "Hello" >dir/dir4/file2; echo "dir2/file1" > dir/dir2/file1 -echo "temp_dir/file" > exclude_file -testing "create with extra files/directory included : -T" "tar -czf dir.tgz dir/ -T exclude_file ; rm -rf dir ; tar -tf dir.tgz | sort; rm -rf dir.tgz " "dir/\ndir/dir1/\ndir/dir1/file\ndir/dir2/\ndir/dir2/file1\ndir/dir3/\ndir/dir3/file1\ndir/dir3/file2\ndir/dir4/\ndir/dir4/file1\ndir/dir4/file2\ntemp_dir/file\n" "" "" -rm -rf exclude_file -rm -rf temp_dir - -#Creating dir -mkdir dir/dir1 -p -echo "Inside dir/dir1" > dir/dir1/file ; echo "Hello Inside dir" > dir/file -testing "extract to STDOUT : -O" " tar -czf dir.tgz dir/ ; rm -rf dir ; tar -xf dir.tgz -O ; [ -e 'Inside dir/dir1/\nHello Inside dir\n' ] && echo 'yes'; rm -rf dir.tgz " "" "" "" - -#Creating short filename -f="filename_with_100_chars_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -echo "This is testdata" > $f -testing "shortname filename" "tar -cf testFile.tar $f && [ -e testFile.tar ] && echo 'yes'; rm -f $f; tar -xf testFile.tar && [ -f $f ] && cat $f && strings testFile.tar | grep -o LongLink; rm -f testFile.tar; rm -f $f" "yes\nThis is testdata\n" "" "" - -#Creating long filename -f="filename_with_101_chars_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -echo "This is testdata" > $f -testing "longname filename" "tar -cf testFile.tar $f && [ -e testFile.tar ] && echo 'yes'; rm -f $f; tar -xf testFile.tar && [ -f $f ] && cat $f && strings testFile.tar | grep -o LongLink; rm -f testFile.tar; rm -f $f" "yes\nThis is testdata\nLongLink\n" "" "" - -#Creating long pathname -d="dirname_with_50_chars_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" -f="filename_with_50_chars_xxxxxxxxxxxxxxxxxxxxxxxxxxx" -mkdir $d -echo "This is testdata" > $d/$f -testing "longname pathname" "tar -cf testFile.tar $d/$f && [ -e testFile.tar ] && echo 'yes'; rm -rf $d; tar -xf testFile.tar && [ -f $d/$f ] && cat $d/$f && strings testFile.tar | grep -o LongLink; rm -f testFile.tar; rm -rf $d" "yes\nThis is testdata\nLongLink\n" "" "" - -# gzip -rm -rf d -mkdir d -echo "hello world" > d/f -testing "gzip compression" "tar zcf f d && file f | grep -q gzip && echo y ; rm -rf d ; tar xf f && cat d/f" "y\nhello world\n" "" "" -testing "gzip decompression" "tar xf $FILES/tar/tar.tgz && cat dir/file" "hello world\n" "" "" - -# bzip2 -rm -rf d -mkdir d -echo "hello world" > d/f -testing "bzip2 compression" "tar jcf f d && file f | grep -q bzip2 && echo y ; rm -rf d ; tar xf f && cat d/f" "y\nhello world\n" "" "" -testing "bzip2 decompression" "tar xf $FILES/tar/tar.tbz2 && cat dir/file" "hello world\n" "" "" +TARSUM='--owner root --group root | head -c $((3*512)) | sha1sum | sed "s/ .*//"' +touch -t 198001010101 file +testing "create file" "tar c file $TARSUM" \ + "d551292408833aa5e9db32c0d14d7f32e7e96882\n" "" "" +mkdir walrus +touch -t 198001010101 dir +testing "create dir" "tar c dir $TARSUM" \ + "c4e630d9c89f4f20d603a6f71ff4410ab56fe965\n" "" "" diff --git a/toys/pending/tar.c b/toys/pending/tar.c index 18a078e1..0e7a49f9 100644 --- a/toys/pending/tar.c +++ b/toys/pending/tar.c @@ -18,7 +18,7 @@ * Extract into dir same as filename, --restrict? "Tarball is splodey" * -USE_TAR(NEWTOY(tar, "&(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)j(bzip2)z(gzip)O(to-stdout)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):[!txc][!jz]", TOYFLAG_USR|TOYFLAG_BIN)) +USE_TAR(NEWTOY(tar, "&(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)j(bzip2)z(gzip)O(to-stdout)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):[!txc][!jz]", TOYFLAG_USR|TOYFLAG_BIN)) todo: support .txz todo: directory timestamps not set on extract @@ -47,14 +47,14 @@ config TAR GLOBALS( char *f, *C; struct arg_list *T, *X; - char *to_command; + char *to_command, *owner, *group; struct arg_list *exclude; // exc is an argument but inc isn't? struct double_list *incl, *excl, *seen; void *inodes; char *cwd; - int fd; + int fd, ouid, ggid; // Parsed information about a tar header. struct { @@ -204,7 +204,7 @@ static void add_file(char **nam, struct stat *st) char *c, *p, *name = *nam, *lnk, *hname; static int warn = 1; -// TODO what/why? fnmatch()? +// TODO TT.incl defaults to --anchored TT.excl defaults to --no-anchored for (p = name; *p; p++) if ((p == name || p[-1] == '/') && *p != '/' && filter(TT.excl, p)) return; @@ -224,6 +224,9 @@ static void add_file(char **nam, struct stat *st) warn = 0; } + if (TT.owner) st->st_uid = TT.ouid; + if (TT.group) st->st_gid = TT.ggid; + memset(&hdr, 0, sizeof(hdr)); strncpy(hdr.name, hname, sizeof(hdr.name)); ITOO(hdr.mode, st->st_mode &07777); @@ -234,13 +237,13 @@ static void add_file(char **nam, struct stat *st) // Hard link or symlink? i = !!S_ISLNK(st->st_mode); +// TODO: hardlink to symlink? if (i || (node = seen_inode(&TT.inodes, st, hname))) { // TODO: test preserve symlink ownership hdr.type = '1'+i; if (!(lnk = i ? xreadlink(name) : node->arg)) return perror_msg("readlink"); // TODO: does this need NUL terminator? - if (strlen(lnk) > sizeof(hdr.link)) - write_longname(lnk, 'K'); //write longname LINK + if (strlen(lnk) > sizeof(hdr.link)) write_longname(lnk, 'K'); strncpy(hdr.link, lnk, sizeof(hdr.link)); if (i) free(lnk); } else if (S_ISREG(st->st_mode)) { @@ -255,16 +258,18 @@ static void add_file(char **nam, struct stat *st) ITOO(hdr.minor, dev_minor(st->st_rdev)); } else return error_msg("unknown file type '%o'", st->st_mode & S_IFMT); - if (strlen(hname) > sizeof(hdr.name)) - write_longname(hname, 'L'); //write longname NAME + if (strlen(hname) > sizeof(hdr.name)) write_longname(hname, 'L'); strcpy(hdr.magic, "ustar "); - if ((pw = bufgetpwuid(st->st_uid))) - snprintf(hdr.uname, sizeof(hdr.uname), "%s", pw->pw_name); - else sprintf(hdr.uname, "%d", st->st_uid); - - if ((gr = bufgetgrgid(st->st_gid))) - snprintf(hdr.gname, sizeof(hdr.gname), "%s", gr->gr_name); - else sprintf(hdr.gname, "%d", st->st_gid); + if (!FLAG(numeric_owner)) { + if (!TT.owner && !(pw = bufgetpwuid(st->st_uid))) + sprintf(hdr.uname, "%d", st->st_uid); + else snprintf(hdr.uname, sizeof(hdr.uname), "%s", + TT.owner ? TT.owner : pw->pw_name); + if (!TT.group && !(gr = bufgetgrgid(st->st_gid))) + sprintf(hdr.gname, "%d", st->st_gid); + else snprintf(hdr.gname, sizeof(hdr.gname), "%s", + TT.group ? TT.group : gr->gr_name); + } itoo(hdr.chksum, sizeof(hdr.chksum)-1, cksum(&hdr)); hdr.chksum[7] = ' '; @@ -311,13 +316,10 @@ static void extract_to_command(void) int pipefd[2], status = 0; pid_t cpid; - xpipe(pipefd); if (!S_ISREG(TT.hdr.mode)) return; //only regular files are supported. - cpid = fork(); - if (cpid == -1) perror_exit("fork"); - - if (!cpid) { // Child reads from pipe + xpipe(pipefd); + if (!(cpid = xfork())) { // Child reads from pipe char buf[64], *argv[4] = {"sh", "-c", TT.to_command, NULL}; setenv("TAR_FILETYPE", "f", 1); @@ -411,18 +413,24 @@ COPY: xsendfile_len(TT.fd, dst_fd, TT.hdr.size); close(dst_fd); - if (!FLAG(o)) { + if (!FLAG(o) && !geteuid()) { //set ownership..., --no-same-owner, --numeric-owner uid_t u = TT.hdr.uid; gid_t g = TT.hdr.gid; - if (!FLAG(numeric_owner)) { - struct group *gr = getgrnam(TT.hdr.gname); + if (TT.owner) u = TT.ouid; + else if (!FLAG(numeric_owner)) { struct passwd *pw = getpwnam(TT.hdr.uname); - if (pw) u = pw->pw_uid; + if (pw && (TT.owner || !FLAG(numeric_owner))) u = pw->pw_uid; + } + + if (TT.group) g = TT.ggid; + else if (!FLAG(numeric_owner)) { + struct group *gr = getgrnam(TT.hdr.gname); if (gr) g = gr->gr_gid; } - if (!geteuid() && lchown(TT.hdr.name, u, g)) + + if (lchown(TT.hdr.name, u, g)) perror_msg("chown %d:%d '%s'", u, g, TT.hdr.name);; } @@ -499,7 +507,7 @@ static void unpack_tar(void) continue; } - // At this point, we're writing to the filesystem. + // At this point, we have something to output. Convert metadata. TT.hdr.mode = otoi(tar.mode, sizeof(tar.mode)); TT.hdr.mode |= (char []){8,8,10,2,6,4,1,8}[tar.type-'0']<<12; TT.hdr.uid = otoi(tar.uid, sizeof(tar.uid)); @@ -508,8 +516,8 @@ static void unpack_tar(void) TT.hdr.device = dev_makedev(otoi(tar.major, sizeof(tar.major)), otoi(tar.minor, sizeof(tar.minor))); - TT.hdr.uname = xstrndup(tar.uname, sizeof(tar.uname)); - TT.hdr.gname = xstrndup(tar.gname, sizeof(tar.gname)); + TT.hdr.uname = xstrndup(TT.owner ? TT.owner : tar.uname,sizeof(tar.uname)); + TT.hdr.gname = xstrndup(TT.group ? TT.group : tar.gname,sizeof(tar.gname)); if (!TT.hdr.link_target && *tar.link) TT.hdr.link_target = xstrndup(tar.link, sizeof(tar.link)); if (!TT.hdr.name) { @@ -597,6 +605,8 @@ void tar_main(void) signal(SIGPIPE, SIG_IGN); if (!geteuid()) toys.optflags |= FLAG_p; + if (TT.owner) TT.ouid = xgetuid(TT.owner); + if (TT.group) TT.ggid = xgetgid(TT.group); // Collect file list. Note: trim_list appends to TT.incl when !TT.X for (;TT.X; TT.X = TT.X->next) do_lines(xopenro(TT.X->arg), '\n', trim_list); -- cgit v1.2.3