aboutsummaryrefslogtreecommitdiff
path: root/toys/pending/tar.c
diff options
context:
space:
mode:
Diffstat (limited to 'toys/pending/tar.c')
-rw-r--r--toys/pending/tar.c46
1 files changed, 28 insertions, 18 deletions
diff --git a/toys/pending/tar.c b/toys/pending/tar.c
index b32a5098..8a09102e 100644
--- a/toys/pending/tar.c
+++ b/toys/pending/tar.c
@@ -453,7 +453,7 @@ static void extract_to_disk(void)
}
// || !FLAG(no_same_permissions))
- if (FLAG(p) && !S_ISLNK(ala)) chmod(TT.hdr.name, ala);
+ if (!S_ISLNK(ala)) chmod(TT.hdr.name, FLAG(p) ? ala : ala&0777);
// Apply mtime.
if (!FLAG(m)) {
@@ -493,14 +493,11 @@ static void unpack_tar(struct tar_hdr *first)
i = readall(TT.fd, &tar, 512);
}
- if (i && i != 512) error_exit("read error");
+ if (i && i!=512) error_exit("short header");
// Two consecutive empty headers ends tar even if there's more data
if (!i || !*tar.name) {
- if (!i || and++) {
- dirflush(0);
- return;
- }
+ if (!i || and++) return;
TT.hdr.size = 0;
continue;
}
@@ -721,35 +718,48 @@ void tar_main(void)
}
if (FLAG(j)||FLAG(z)) {
- int pipefd[2] = {hdr ? -1 : TT.fd, -1}, i;
+ int pipefd[2] = {hdr ? -1 : TT.fd, -1}, i, pid;
xpopen_both((char *[]){FLAG(z)?"gunzip":"bunzip2", "-cf", "-", NULL},
pipefd);
- close(TT.fd);
- TT.fd = pipefd[1];
- // If we autodetected type but then couldn't lseek to put the data back
- if (hdr) {
- // dirty trick: move pipefd[0] to 0 so child closes spare copy
+ if (!hdr) {
+ // If we could seek, child gzip inherited fd and we read its output
+ close(TT.fd);
+ TT.fd = pipefd[1];
+
+ } else {
+
+ // If we autodetected type but then couldn't lseek to put the data back
+ // we have to loop reading data from TT.fd and pass it to gzip ourselves
+ // (starting with the block of data we read to autodetect).
+
+ // dirty trick: move gzip input pipe to stdin so child closes spare copy
dup2(pipefd[0], 0);
if (pipefd[0]) close(pipefd[0]);
- // Fork a copy of ourselves to handle extraction (reads from zip proc)
- pipefd[0] = TT.fd;
+ // Fork a copy of ourselves to handle extraction (reads from zip output
+ // pipe, writes to stdout).
+ pipefd[0] = pipefd[1];
pipefd[1] = 1;
- xpopen_both(0, pipefd);
- close(TT.fd);
+ pid = xpopen_both(0, pipefd);
+ close(pipefd[1]);
// loop writing collated data to zip proc
xwrite(0, hdr, len);
for (;;) {
- if ((i = read(0, toybuf, sizeof(toybuf)))<1) return;
+ if ((i = read(TT.fd, toybuf, sizeof(toybuf)))<1) {
+ close(0);
+ xwaitpid(pid);
+ return;
+ }
xwrite(0, toybuf, i);
}
- } else hdr = 0;
+ }
}
unpack_tar(hdr);
+ dirflush(0);
if (TT.seen != TT.incl) {
if (!TT.seen) TT.seen = TT.incl;
while (TT.incl != TT.seen) {