From ae3e3ae4a00b3ed4d763aea498e7e5e0eb137f1e Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sat, 1 Jun 2019 17:16:08 -0500 Subject: Teach file to recognize xz archives and old style tarballs. --- lib/lib.c | 23 +++++++++++++++++++++++ lib/lib.h | 2 ++ toys/posix/file.c | 9 ++++++--- toys/posix/tar.c | 26 ++------------------------ 4 files changed, 33 insertions(+), 27 deletions(-) diff --git a/lib/lib.c b/lib/lib.c index b5825fd2..ffb24f65 100644 --- a/lib/lib.c +++ b/lib/lib.c @@ -1416,3 +1416,26 @@ void loggit(int priority, char *format, ...) va_end(va); closelog(); } + +// Calculate tar packet checksum, with cksum field treated as 8 spaces +unsigned tar_cksum(void *data) +{ + unsigned i, cksum = 8*' '; + + for (i = 0; i<500; i += (i==147) ? 9 : 1) cksum += ((char *)data)[i]; + + return cksum; +} + +// is this a valid tar header? +int is_tar_header(void *pkt) +{ + char *p = pkt; + int i = 0; + + if (p[257] && memcmp("ustar", p+257, 5)) return 0; + if (p[148] != '0') return 0; + sscanf(p+148, "%8o", &i); + + return i && tar_cksum(pkt) == i; +} diff --git a/lib/lib.h b/lib/lib.h index 5ce29380..080c533f 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -265,6 +265,8 @@ long long millitime(void); char *format_iso_time(char *buf, size_t len, struct timespec *ts); void reset_env(struct passwd *p, int clear); void loggit(int priority, char *format, ...); +unsigned tar_cksum(void *data); +int is_tar_header(void *pkt); #define HR_SPACE 1 // Space between number and units #define HR_B 2 // Use "B" for single byte units diff --git a/toys/posix/file.c b/toys/posix/file.c index 567c68d2..6b8c6779 100644 --- a/toys/posix/file.c +++ b/toys/posix/file.c @@ -269,9 +269,10 @@ static void do_regular_file(int fd, char *name) } else if (len>33 && (magic=peek(&s,2), magic==0143561 || magic==070707)) { if (magic == 0143561) printf("byte-swapped "); xprintf("cpio archive\n"); - // tar archive (ustar/pax or gnu) - } else if (len>500 && !strncmp(s+257, "ustar", 5)) - xprintf("POSIX tar archive%s\n", strncmp(s+262," ",2)?"":" (GNU)"); + // tar archive (old, ustar/pax, or gnu) + } else if (len>500 && is_tar_header(s)) + xprintf("%s tar archive%s\n", s[257] ? "POSIX" : "old", + strncmp(s+262," ",2)?"":" (GNU)"); // zip/jar/apk archive, ODF/OOXML document, or such else if (len>5 && strstart(&s, "PK\03\04")) { int ver = toybuf[4]; @@ -281,6 +282,8 @@ static void do_regular_file(int fd, char *name) xputc('\n'); } else if (len>4 && strstart(&s, "BZh") && isdigit(*s)) xprintf("bzip2 compressed data, block size = %c00k\n", *s); + else if (len > 31 && peek_be(s, 7) == 0xfd377a585a0000) + xprintf("xz compressed data"); else if (len>10 && strstart(&s, "\x1f\x8b")) xputs("gzip compressed data"); else if (len>32 && !memcmp(s+1, "\xfa\xed\xfe", 3)) { int bit = s[0]=='\xce'?32:64; diff --git a/toys/posix/tar.c b/toys/posix/tar.c index 17d382d5..2819a355 100644 --- a/toys/posix/tar.c +++ b/toys/posix/tar.c @@ -83,28 +83,6 @@ struct tar_hdr { prefix[155], padd[12]; }; -// Calculate packet checksum, with cksum field treated as 8 spaces -unsigned tar_cksum(void *data) -{ - unsigned i, cksum = 8*' '; - - for (i = 0; i<500; i += (i==147) ? 9 : 1) cksum += ((char *)data)[i]; - - return cksum; -} - -static int is_tar(void *pkt) -{ - char *p = pkt; - int i = 0; - - if (p[257] && memcmp("ustar", p+257, 5)) return 0; - if (p[148] != '0') return 0; - sscanf(p+148, "%8o", &i); - - return i && tar_cksum(pkt) == i; -} - // convert from int to octal (or base-256) static void itoo(char *str, int len, unsigned long long val) { @@ -594,7 +572,7 @@ static void unpack_tar(char *first) tar.padd[0] = and = 0; // Is this a valid TAR header? - if (!is_tar(&tar)) error_exit("bad header"); + if (!is_tar_header(&tar)) error_exit("bad header"); TT.hdr.size = OTOI(tar.size); // If this header isn't writing something to the filesystem @@ -856,7 +834,7 @@ void tar_main(void) // autodetect compression type when not specified if (!(FLAG(j)||FLAG(z)||FLAG(J))) { len = xread(TT.fd, hdr = toybuf+sizeof(toybuf)-512, 512); - if (len!=512 || !is_tar(hdr)) { + if (len!=512 || !is_tar_header(hdr)) { // detect gzip and bzip signatures if (SWAP_BE16(*(short *)hdr)==0x1f8b) toys.optflags |= FLAG_z; else if (!memcmp(hdr, "BZh", 3)) toys.optflags |= FLAG_j; -- cgit v1.2.3