diff options
author | Elliott Hughes <enh@google.com> | 2019-04-03 10:36:10 -0700 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2019-04-03 10:36:10 -0700 |
commit | c30508d0c9631227b377a1bcda09c14ff7d47bca (patch) | |
tree | f818f8af1e5c4af48d4e5085d331b1373f6d6ad5 | |
parent | 03df06d931d43332eb470038be0d1f782cb688b9 (diff) | |
parent | d0d3b0c6819a453383bca1e6c96e75c6a3ebd93b (diff) | |
download | toybox-c30508d0c9631227b377a1bcda09c14ff7d47bca.tar.gz |
Merge remote-tracking branch 'toybox/master' into HEAD am: 7f1341e5d3
am: d0d3b0c681
Change-Id: I14e7f53c6752422d95e9f76f67604524f068f712
-rw-r--r-- | generated/flags.h | 6 | ||||
-rw-r--r-- | generated/globals.h | 4 | ||||
-rw-r--r-- | generated/help.h | 2 | ||||
-rw-r--r-- | generated/newtoys.h | 2 | ||||
-rw-r--r-- | lib/lib.c | 11 | ||||
-rw-r--r-- | lib/xwrap.c | 7 | ||||
-rwxr-xr-x | tests/rm.test | 2 | ||||
-rw-r--r-- | tests/tar.test | 75 | ||||
-rw-r--r-- | toys/pending/tar.c | 120 | ||||
-rw-r--r-- | toys/posix/id.c | 2 |
10 files changed, 159 insertions, 72 deletions
diff --git a/generated/flags.h b/generated/flags.h index 9f387ef3..7019fc94 100644 --- a/generated/flags.h +++ b/generated/flags.h @@ -2742,9 +2742,9 @@ #undef FLAG_f #endif -// tar &(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mtime):(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] &(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mtime):(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] +// tar &(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mtime):(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] &(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mtime):(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] #undef OPTSTR_tar -#define OPTSTR_tar "&(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mtime):(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]" +#define OPTSTR_tar "&(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mtime):(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]" #ifdef CLEANUP_tar #undef CLEANUP_tar #undef FOR_tar @@ -2773,6 +2773,7 @@ #undef FLAG_no_same_permissions #undef FLAG_numeric_owner #undef FLAG_no_recursion +#undef FLAG_full_time #endif // taskset <1^pa <1^pa @@ -5669,6 +5670,7 @@ #define FLAG_no_same_permissions (1<<22) #define FLAG_numeric_owner (1<<23) #define FLAG_no_recursion (1<<24) +#define FLAG_full_time (1<<25) #endif #ifdef FOR_taskset diff --git a/generated/globals.h b/generated/globals.h index 188d2b67..8f40ea18 100644 --- a/generated/globals.h +++ b/generated/globals.h @@ -811,7 +811,7 @@ struct tar_data { struct double_list *incl, *excl, *seen; struct string_list *dirs; char *cwd; - int fd, ouid, ggid, hlc, warn; + int fd, ouid, ggid, hlc, warn, adev, aino; time_t mtt; // hardlinks seen so far (hlc many) @@ -822,7 +822,7 @@ struct tar_data { } *hlx; // Parsed information about a tar header. - struct { + struct tar_header { char *name, *link_target, *uname, *gname; long long size; uid_t uid; diff --git a/generated/help.h b/generated/help.h index bd0db872..f4728dcc 100644 --- a/generated/help.h +++ b/generated/help.h @@ -544,7 +544,7 @@ #define HELP_groups "usage: groups [user]\n\nPrint the groups a user is in.\n\n" -#define HELP_id "usage: id [-GZgnru] \n\nPrint user and group ID.\n-G Show only the group IDs\n-Z Show only security context\n-g Show only the effective group ID\n-n Print names instead of numeric IDs (to be used with -Ggu)\n-r Show real ID instead of effective ID\n-u Show only the effective user ID\n" +#define HELP_id "usage: id [-GZgnru] [USER...]\n\nPrint user and group ID.\n-G Show only the group IDs\n-Z Show only security context\n-g Show only the effective group ID\n-n Print names instead of numeric IDs (to be used with -Ggu)\n-r Show real ID instead of effective ID\n-u Show only the effective user ID\n" #define HELP_iconv "usage: iconv [-f FROM] [-t TO] [FILE...]\n\nConvert character encoding of files.\n\n-c Omit invalid chars\n-f Convert from (default utf8)\n-t Convert to (default utf8)\n\n" diff --git a/generated/newtoys.h b/generated/newtoys.h index e7b09a4f..e8205572 100644 --- a/generated/newtoys.h +++ b/generated/newtoys.h @@ -246,7 +246,7 @@ USE_SYSCTL(NEWTOY(sysctl, "^neNqwpaA[!ap][!aq][!aw][+aA]", TOYFLAG_SBIN)) USE_SYSLOGD(NEWTOY(syslogd,">0l#<1>8=8R:b#<0>99=1s#<0=200m#<0>71582787=20O:p:f:a:nSKLD", TOYFLAG_SBIN|TOYFLAG_STAYROOT)) USE_TAC(NEWTOY(tac, NULL, TOYFLAG_USR|TOYFLAG_BIN)) USE_TAIL(NEWTOY(tail, "?fc-n-[-cn]", TOYFLAG_USR|TOYFLAG_BIN)) -USE_TAR(NEWTOY(tar, "&(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mtime):(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)) +USE_TAR(NEWTOY(tar, "&(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mtime):(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)) USE_TASKSET(NEWTOY(taskset, "<1^pa", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT)) USE_TCPSVD(NEWTOY(tcpsvd, "^<3c#=30<1C:b#=20<0u:l:hEv", TOYFLAG_USR|TOYFLAG_BIN)) USE_TEE(NEWTOY(tee, "ia", TOYFLAG_USR|TOYFLAG_BIN)) @@ -55,11 +55,14 @@ void error_exit(char *msg, ...) // Die with an error message and strerror(errno) void perror_exit(char *msg, ...) { - va_list va; + // Die silently if our pipeline exited. + if (errno != EPIPE) { + va_list va; - va_start(va, msg); - verror_msg(msg, errno, va); - va_end(va); + va_start(va, msg); + verror_msg(msg, errno, va); + va_end(va); + } xexit(); } diff --git a/lib/xwrap.c b/lib/xwrap.c index 778cb38d..31843edf 100644 --- a/lib/xwrap.c +++ b/lib/xwrap.c @@ -141,7 +141,7 @@ char *xmprintf(char *format, ...) void xflush(void) { - if (fflush(0) || ferror(stdout)) perror_exit("write"); + if (fflush(stdout) || ferror(stdout)) perror_exit("write"); } void xprintf(char *format, ...) @@ -517,7 +517,8 @@ void xstat(char *path, struct stat *st) } // Canonicalize path, even to file with one or more missing components at end. -// if exact, require last path component to exist +// Returns allocated string for pathname or NULL if doesn't exist +// exact = 1 file must exist, 0 dir must exist, -1 show theoretical location char *xabspath(char *path, int exact) { struct string_list *todo, *done = 0; @@ -963,7 +964,7 @@ void xparsedate(char *str, time_t *t, unsigned *nano, int endian) struct tm tm; time_t now = *t; int len = 0, i = 0; - // Formats with years must come first. Posix can't agree on whether 12 digits + // Formats with seconds come first. Posix can't agree on whether 12 digits // has year before (touch -t) or year after (date), so support both. char *s = str, *p, *oldtz = 0, *formats[] = {"%Y-%m-%d %T", "%Y-%m-%dT%T", "%H:%M:%S", "%Y-%m-%d %H:%M", "%Y-%m-%d", "%H:%M", "%m%d%H%M", diff --git a/tests/rm.test b/tests/rm.test index 42727442..f0a123c3 100755 --- a/tests/rm.test +++ b/tests/rm.test @@ -52,7 +52,7 @@ chmod 777 one 2>/dev/null ; rm -rf one mkdir -p d1 touch d1/f1.txt d1/f2.txt testing "-rv dir" \ - "rm -rv d1" "rm 'd1/f1.txt'\nrm 'd1/f2.txt'\nrmdir 'd1'\n" "" "" + "rm -rv d1 | sort" "rm 'd1/f1.txt'\nrm 'd1/f2.txt'\nrmdir 'd1'\n" "" "" rm -rf d1 touch "'" diff --git a/tests/tar.test b/tests/tar.test index 4936320c..ef83ad94 100644 --- a/tests/tar.test +++ b/tests/tar.test @@ -4,15 +4,19 @@ #testing "name" "command" "result" "infile" "stdin" -# assumes umask 0002 +# For reproducibility: UTC and umask 0002 -LONG=abcdefghijklmnopqrstuvwxyz0123456789 -LONG=$LONG$LONG$LONG$LONG$LONG$LONG$LONG$LONG$LONG$LONG OLDTZ="$TZ" -TZ=utc +export TZ=utc OLDUMASK=$(umask) umask 0002 +# 3888 bytes, most of PATH_MAX +LONG=abcdefghijklmnopqrstuvwxyz0123456789 +LONG=$LONG$LONG$LONG$LONG$LONG$LONG$LONG$LONG$LONG +LONG=$LONG$LONG$LONG$LONG$LONG$LONG +LONG=$LONG$LONG + # Reproducible tarballs: override ownership and timestamp. Also amount of # trailing NUL padding varies (1024 bytes is minimum, gnu/dammit does more) # so look at first 3 512-byte frames when analyzing header content. @@ -20,25 +24,48 @@ umask 0002 TAR='tar c --owner root --group root --mtime @1234567890' SUM='head -c $((3*512)) | sha1sum | sed "s/ .*//"' [ -n "$TARHD" ] && SUM="tee >(hd >&2) | $SUM" -SPC='sed "s/[ \t][ \t]*/ /g"' +LST='tar tv | sed "s/[ \t][ \t]*/ /g"' touch file testing "create file" "$TAR file | $SUM" \ "fecaecba936e604bb115627a6ef4db7c7a3a8f81\n" "" "" +testing "pass file" "$TAR file | $LST" \ + "-rw-rw-r-- root/root 0 2009-02-13 23:31 file\n" "" "" + +# The kernel has two hardwired meaningful UIDs: 0 (root) and 65534 (nobody). +# (Technically changeable via /proc/sys/*/overflowuid but nobody ever does) +skipnot id nobody >/dev/null +testing "pass user" "tar -c --owner nobody --group root --mtime @0 file | $LST" \ + "-rw-rw-r-- nobody/root 0 1970-01-01 00:00 file\n" "" "" +skipnot grep nobody /etc/group >/dev/null +testing "pass group" "tar c --owner root --group nobody --mtime @0 file | $LST" \ + "-rw-rw-r-- root/nobody 0 1970-01-01 00:00 file\n" "" "" + +touch -t 198701231234.56 file +testing "pass mtime" \ + "tar c --owner root --group root file | tar tv --full-time | sed 's/[ \t][ \t]*/ /g'" \ + "-rw-rw-r-- root/root 0 1987-01-23 12:34:56 file\n" "" "" + mkdir dir testing "create dir" "$TAR dir | $SUM" \ "05739c423d7d4a7f12b3dbb7c94149acb2bb4f8d\n" "" "" +testing "pass dir" "$TAR dir | $LST" \ + "drwxrwxr-x root/root 0 2009-02-13 23:31 dir/\n" "" "" + # note: does _not_ include dir entry in archive, just file touch dir/file -testing "create dir and file" "$TAR dir/file | $SUM" \ +testing "create file in dir" "$TAR dir/file | $SUM" \ "2d7b96c7025987215f5a41f10eaa84311160afdb\n" "" "" # Tests recursion without worrying about content order -testing "create dir/file 2" "$TAR dir | $SUM" \ +testing "create dir and dir/file" "$TAR dir | $SUM" \ "0bcc8005a3e07eb63c9b735267aecc5b774795d7\n" "" "" +testing "pass dir/file" "$TAR dir | $LST" \ + "drwxrwxr-x root/root 0 2009-02-13 23:31 dir/\n-rw-rw-r-- root/root 0 2009-02-13 23:31 dir/file\n" "" "" + # / and .. only stripped from name, not symlink target. ln -s ../name.././.. dir/link testing "create symlink" "$TAR dir/link | $SUM" \ @@ -57,3 +84,37 @@ skipnot mkfifo dir/fifo testing "create dir/fifo" "$TAR dir/fifo | $SUM" \ "bd1365db6e8ead4c813333f9666994c1899924d9\n" "" "" +# test L and K records + +# 4+96=100 (biggest short name), 4+97=101 (shortest long name) +touch dir/${LONG:1:96} dir/${LONG:1:97} +testing "create longfilename" "$TAR dir/${LONG:1:97} dir/${LONG:1:96} | $SUM" \ + "08af4f9d8b7f4b2f6c264689efe42a4159314708\n" "" "" + +# this expects devtmpfs values + +testing "pass /dev/null" \ + "tar c --mtime @0 /dev/null 2>/dev/null | $LST" \ + "crw-rw-rw- root/root 1,3 1970-01-01 00:00 dev/null\n" "" "" + +testing "pass /dev/loop0" \ + "tar c --numeric-owner --mtime @0 /dev/loop0 2>/dev/null | $LST" \ + "brw-rw---- 0/6 7,0 1970-01-01 00:00 dev/loop0\n" "" "" + +skipnot mknod dir/char c 12 34 +testing "create char2" "$TAR /dev/null | $SUM" \ + "" "" "" + +#testing "create block" "$TAR /dev/ + +skipnot mknod dir/block b 56 78 +testing "create dir/block" "$TAR dir/block | $SUM" \ + "" "" "" + +skipnot chown nobody dir/file +testing "ownership" "$TAR dir/block | $SUM" \ + "blat" "" "" + +TZ="$OLDTZ" +umask $OLDUMASK +unset LONG TAR SUM OLDUMASK OLDTZ LST diff --git a/toys/pending/tar.c b/toys/pending/tar.c index 77c03540..bff8b540 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)*(mtime):(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)) +USE_TAR(NEWTOY(tar, "&(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mtime):(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)) config TAR bool "tar" @@ -49,7 +49,7 @@ GLOBALS( struct double_list *incl, *excl, *seen; struct string_list *dirs; char *cwd; - int fd, ouid, ggid, hlc, warn; + int fd, ouid, ggid, hlc, warn, adev, aino; time_t mtt; // hardlinks seen so far (hlc many) @@ -60,7 +60,7 @@ GLOBALS( } *hlx; // Parsed information about a tar header. - struct { + struct tar_header { char *name, *link_target, *uname, *gname; long long size; uid_t uid; @@ -121,7 +121,6 @@ static void write_longname(char *name, char type) memset(&tmp, 0, sizeof(tmp)); strcpy(tmp.name, "././@LongLink"); - ITOO(tmp.mode, 0); ITOO(tmp.uid, 0); ITOO(tmp.gid, 0); ITOO(tmp.size, sz); @@ -129,8 +128,13 @@ static void write_longname(char *name, char type) tmp.type = type; strcpy(tmp.magic, "ustar "); - // Calculate checksum. Since 0777777 is twice 512*255 it can never use more - // than 6 digits, last byte is ' ' or historical reasons. + // Historical nonsense to match other implementations. Never used. + ITOO(tmp.mode, 0644); + strcpy(tmp.uname, "root"); + strcpy(tmp.gname, "root"); + + // Calculate checksum. Since 512*255 = 0377000 in octal, this can never + // use more than 6 digits. The last byte is ' ' or historical reasons. itoo(tmp.chksum, sizeof(tmp.chksum)-1, cksum(&tmp)); tmp.chksum[7] = ' '; @@ -168,34 +172,42 @@ static void alloread(void *buf, int len) b[len] = 0; } -static void add_file(char **nam, struct stat *st) +static int add_to_tar(struct dirtree *node) { + struct stat *st = &(node->st); struct tar_hdr hdr; struct passwd *pw = pw; struct group *gr = gr; int i, fd =-1; - char *c, *p, *name = *nam, *lnk, *hname; + char *c, *p, *name, *lnk = lnk, *hname; + + if (!dirtree_notdotdot(node)) return 0; + if (TT.adev == st->st_dev && TT.aino == st->st_ino) { + error_msg("'%s' file is the archive; not dumped", node->name); + return 0; + } + + i = 1; + name = dirtree_path(node, &i); // exclusion defaults to --no-anchored and --wildcards-match-slash for (p = name; *p; p++) - if ((p == name || p[-1] == '/') && *p != '/' && filter(TT.excl, p)) return; + if ((p == name || p[-1] == '/') && *p != '/' && filter(TT.excl, p)) + goto done; - if (S_ISDIR(st->st_mode) && name[strlen(name)-1] != '/') { - lnk = xmprintf("%s/", name); - free(name); - *nam = name = lnk; - } + // The 1 extra byte from dirtree_path() + if (S_ISDIR(st->st_mode) && name[i-1] != '/') strcat(name, "/"); // remove leading / and any .. entries from saved name for (hname = name; *hname == '/'; hname++); for (c = hname;;) { if (!(c = strstr(c, ".."))) break; if (c == hname || c[-1] == '/') { - if (!c[2]) return; + if (!c[2]) goto done; if (c[2]=='/') c = hname = c+3; } else c+= 2; } - if (!*hname) return; + if (!*hname) goto done; if (TT.warn && hname != name) { fprintf(stderr, "removing leading '%.*s' from member names\n", @@ -214,6 +226,7 @@ static void add_file(char **nam, struct stat *st) ITOO(hdr.gid, st->st_gid); ITOO(hdr.size, 0); //set size later ITOO(hdr.mtime, st->st_mtime); + strcpy(hdr.magic, "ustar "); // Hard link or symlink? i=0 neither, i=1 hardlink, i=2 symlink @@ -228,7 +241,7 @@ static void add_file(char **nam, struct stat *st) lnk = TT.hlx[i].arg; i = 1; } else { - // first time we've seen it, store as normal file. + // first time we've seen it. Store as normal file, but remember it. if (!(TT.hlc&255)) TT.hlx = xrealloc(TT.hlx, TT.hlc+256); TT.hlx[TT.hlc].arg = xstrdup(hname); TT.hlx[TT.hlc].ino = st->st_ino; @@ -247,7 +260,10 @@ static void add_file(char **nam, struct stat *st) // Handle file types if (i) { hdr.type = '0'+i; - if (i==2 && !(lnk = xreadlink(name))) return perror_msg("readlink"); + if (i==2 && !(lnk = xreadlink(name))) { + perror_msg("readlink"); + goto done; + } if (strlen(lnk) > sizeof(hdr.link)) write_longname(lnk, 'K'); strncpy(hdr.link, lnk, sizeof(hdr.link)); if (i) free(lnk); @@ -260,10 +276,12 @@ static void add_file(char **nam, struct stat *st) hdr.type = (S_ISCHR(st->st_mode))?'3':'4'; ITOO(hdr.major, dev_major(st->st_rdev)); ITOO(hdr.minor, dev_minor(st->st_rdev)); - } else return error_msg("unknown file type '%o'", st->st_mode & S_IFMT); + } else { + error_msg("unknown file type '%o'", st->st_mode & S_IFMT); + goto done; + } if (strlen(hname) > sizeof(hdr.name)) write_longname(hname, 'L'); - strcpy(hdr.magic, "ustar "); if (!FLAG(numeric_owner)) { if (TT.owner || (pw = bufgetpwuid(st->st_uid))) strncpy(hdr.uname, TT.owner ? TT.owner : pw->pw_name, sizeof(hdr.uname)); @@ -278,29 +296,16 @@ static void add_file(char **nam, struct stat *st) // Write header and data to archive xwrite(TT.fd, &hdr, 512); - if (hdr.type != '0') return; //nothing to write - if ((fd = open(name, O_RDONLY)) < 0) - return perror_msg("can't open '%s'", name); - xsendfile_pad(fd, TT.fd, st->st_size); - if (st->st_size%512) writeall(TT.fd, toybuf, (512-(st->st_size%512))); - close(fd); -} - -static int add_to_tar(struct dirtree *node) -{ - struct stat st; - char *path; - - if (!dirtree_notdotdot(node)) return 0; - if (!fstat(TT.fd, &st) && st.st_dev == node->st.st_dev - && st.st_ino == node->st.st_ino) { - error_msg("'%s' file is the archive; not dumped", TT.f); - return 0; + if (hdr.type == '0') { + if ((fd = open(name, O_RDONLY)) < 0) perror_msg("can't open '%s'", name); + else { + xsendfile_pad(fd, TT.fd, st->st_size); + if (st->st_size%512) writeall(TT.fd, toybuf, (512-(st->st_size%512))); + close(fd); + } } - - path = dirtree_path(node, 0); - add_file(&path, &(node->st)); //path may be modified - free(path); +done: + free(name); return (DIRTREE_RECURSE|(FLAG(h)?DIRTREE_SYMFOLLOW:0))*!FLAG(no_recursion); } @@ -425,18 +430,18 @@ static void extract_to_disk(void) return perror_msg("can't create '%s'", name); + // Set ownership if (!FLAG(o) && !geteuid()) { - //set ownership..., --no-same-owner, --numeric-owner int u = TT.hdr.uid, g = TT.hdr.gid; if (TT.owner) TT.hdr.uid = TT.ouid; - else if (!FLAG(numeric_owner)) { + else if (!FLAG(numeric_owner) && *TT.hdr.uname) { struct passwd *pw = getpwnam(TT.hdr.uname); if (pw && (TT.owner || !FLAG(numeric_owner))) TT.hdr.uid = pw->pw_uid; } if (TT.group) TT.hdr.gid = TT.ggid; - else if (!FLAG(numeric_owner)) { + else if (!FLAG(numeric_owner) && *TT.hdr.uname) { struct group *gr = getgrnam(TT.hdr.gname); if (gr) TT.hdr.gid = gr->gr_gid; } @@ -598,16 +603,21 @@ static void unpack_tar(void) else if (FLAG(t)) { if (FLAG(v)) { struct tm *lc = localtime(TT.mtime ? &TT.mtt : &TT.hdr.mtime); - char perm[11]; + char perm[12], gname[12]; mode_to_string(TT.hdr.mode, perm); - printf("%s %s/%s ", perm, TT.hdr.uname, TT.hdr.gname); + printf("%s", perm); + sprintf(perm, "%u", TT.hdr.uid); + sprintf(gname, "%u", TT.hdr.gid); + printf(" %s/%s ", *TT.hdr.uname ? TT.hdr.uname : perm, + *TT.hdr.gname ? TT.hdr.gname : gname); if (tar.type=='3' || tar.type=='4') printf("%u,%u", maj, min); else printf("%9lld", (long long)TT.hdr.size); - printf(" %d-%02d-%02d %02d:%02d:%02d ", 1900+lc->tm_year, 1+lc->tm_mon, - lc->tm_mday, lc->tm_hour, lc->tm_min, lc->tm_sec); + sprintf(perm, ":%02d", lc->tm_sec); + printf(" %d-%02d-%02d %02d:%02d%s ", 1900+lc->tm_year, 1+lc->tm_mon, + lc->tm_mday, lc->tm_hour, lc->tm_min, FLAG(full_time) ? perm : ""); } - printf("%s", TT.hdr.name); + printf(" %s", TT.hdr.name); if (TT.hdr.link_target) printf(" -> %s", TT.hdr.link_target); xputc('\n'); skippy(TT.hdr.size); @@ -663,6 +673,16 @@ void tar_main(void) if (TT.f && strcmp(TT.f, "-")) TT.fd = xcreate(TT.f, TT.fd*(O_WRONLY|O_CREAT|O_TRUNC), 0666); + // grab archive inode + { + struct stat st; + + if (!fstat(TT.fd, &st)) { + TT.aino = st.st_ino; + TT.adev = st.st_dev; + } + } + // Get destination directory if (TT.C) xchdir(TT.C); TT.cwd = xabspath(s = xgetcwd(), 1); diff --git a/toys/posix/id.c b/toys/posix/id.c index cf30ae74..db3cc317 100644 --- a/toys/posix/id.c +++ b/toys/posix/id.c @@ -15,7 +15,7 @@ config ID bool "id" default y help - usage: id [-nGgru] + usage: id [-nGgru] [USER...] Print user and group ID. |