/* extarct.c - extract files from (tape) archive. * This is a part of the Tar program (see file tar.c) * Author: T.V.Shaporev * Creation date: 14 Dec 1990 */ #include #include "sysup.h" #include "nodedef.h" #include "modern.h" #ifdef MODERN # include #else char *strncpy(); int strlen(); #endif #ifndef MSDOS int mknod(), chown(), utime(); long time(); #endif #include "zippipe.h" #include "zipdefs.h" #include "lzwbits.h" #include "lzwhead.h" #include "compress.h" #include "define.h" #include "lzpack.h" static int soctus __ARGS__(( register char *, register short* )); int soctul __ARGS__(( register char *, register long * )); int shexul __ARGS__(( register char *, register long * )); #define octal(c) (((c)&0370)=='0') static char unknown[] = "Tar: \'%s\' unknown file type \'%c\'\n"; #define _unknown (unknown+9) static int soctus(s, u) register short *u; register char *s; { register i; while (*s == ' ') ++s; for (*u=0, i=0; octal(*s) && i<7; i++, s++) *u = (*u<<3)|(*s&7); return *s!=' ' && *s!='\0'; } int soctul(s, u) register long *u; register char *s; { register i; while (*s == ' ') ++s; for (*u=0, i=0; octal(*s) && i<11; i++, s++) *u = (*u<<3)|(*s&7); return *s!=' ' && *s!='\0'; } int shexul(s, u) register long *u; register char *s; { register i, k; while (*s == ' ') ++s; for (*u=0, i=0; i<8; i++, s++) { k = *s; if (k >= '0' && k <= '9') k -= '0'; else if (k >= 'A' && k <= 'F') k -= 'A'-10; else if (k >= 'a' && k <= 'f') k -= 'a'-10; else break; *u = (*u << 4) | k; } return *s!=' ' && *s!='\0'; } int pktest(p) unsigned char *p; { register unsigned k; if (pklock || i_flag || pktype != PKNONE) return ERROR; pklock = TRUE; k = ((unsigned)(p[1]) << 8) | p[0]; if (k == (unsigned)((LZW_1ST_MAGIC << 8) | LZW_0TH_MAGIC)) { pktype = PKpLZW; } else if (k == GZIP_MAGIC || k == PKW_01_MAGIC && (((unsigned)(p[3]) << 8) | p[2]) == PKW_23_MAGIC) { pktype = PKZIP; } else { return ERROR; } if (pkalloc()) { (void)fprintf(stderr, "No memory for decompression\n"); done(ESMALL); } if (redirect()) done(EINTER); return CORRECT; } int gethead() { short n; static short errcount = 0; register char *err_text = "Tar: bad directory structure\n"; for (;;) { if ((hblock = readtape()) == NULL) return ERROR; if ((hblock->m.name[0]) == '\0') { return errcount ? (++errcount, ERROR) : FALSE; } if (soctus(hblock->m.chksum, &n) == CORRECT) { if (n == headsum(hblock)) break; err_text = "Tar: directory checksum error\n"; } if (pktest((unsigned char*)(hblock->m.name))) goto bad; } if (soctus(hblock->m.mode, (short*)&(st.st_mode)) || soctus(hblock->m.uid, (short*)&(st.st_uid)) || soctus(hblock->m.gid, (short*)&(st.st_gid)) || soctul(hblock->m.size, (long *)&(st.st_size)) || soctul(hblock->m.mtime, (long *)&(st.st_mtime))) goto bad; if (hblock->m.filetype == TF_CHR || hblock->m.filetype == TF_BLK) { if (soctus(hblock->x.devmajor, &dmajor) || soctus(hblock->x.devminor, &dminor)) goto bad; } if (errcount != 0) { (void)fprintf(myout, "Tar: %d blocks skipped to find header\n", errcount); errcount = 0; } if (hblock->m.filetype != TF_OLD && hblock->m.filetype != TF_REG) { longcsum = codesize = 0L; } else if (hblock->m.srcsum[1]!='x' || hblock->m.srcsum[0]!='0') { (void)soctul(hblock->m.srclen, &codesize); /* no sence for */ (void)soctul(hblock->m.srcsum, &longcsum); /* non-packed file */ } else { (void)shexul(hblock->m.srclen + 2, &codesize); (void)shexul(hblock->m.srcsum + 2, &longcsum); } return TRUE; bad: if (errcount++ == 0) (void)fprintf(myout, err_text); if (!i_flag) done(ERREAD); return ERROR; } static int tstfield __ARGS__(( char *, int )); static int tstfield(s,n) /* is the field a valid octal number? */ char *s; int n; { register j; for (j=0; j= n) return FALSE; if (s[j] == ' ') ++j; while (j=n; } #define TstField(x) tstfield(x, sizeof(x)) short isextent(allx, allb) short *allx; long *allb; { short n; if ((hblock->m.filetype != TF_OLD && hblock->m.filetype != TF_REG) || !TstField(hblock->s.extent) || !TstField(hblock->s.allext) || !TstField(hblock->s.total)) return ERROR; (void)soctus(hblock->s.extent, &n); (void)soctus(hblock->s.allext, allx); (void)soctul(hblock->s.total, allb); return n < 1 || n > *allx || *allb <= st.st_size ? ERROR : n; } int ismagic() { register i; register char *p, *q; static char magic_list[][8] = { TMAGIC, GMAGIC }; if (hblock->m.filetype != TF_OLD) { for (i=0; ix.magic; while (*q && *q == *p) { ++q; p++; } if (*q == '\0' && (*p == '\0' || *p == ' ')) return magic_list[i][0]; } } return 0; } char prefix() { switch (hblock->m.filetype) { case TF_CTG: /* ??? contiguous file */ case TF_OLD: case TF_REG: case TF_LNK: return ' '; case TF_SYM: return 'l'; case TF_CHR: return 'c'; case TF_BLK: return 'b'; case TF_DIR: return 'd'; case TF_QUE: return 'p'; case GF_DMP: return 'D'; case GF_MUL: return ','; case GF_VOL: return 'v'; } return '?'; } int usize() /* is it valid to use file size in header */ { switch (hblock->m.filetype) { case TF_OLD: case TF_REG: case TF_CTG: case GF_DMP: case GF_MUL: case GF_SPR: /* what's it? I wonder */ return TRUE; } return FALSE; } void skipfile() { register long blocks; for (blocks=(st.st_size+BLKSIZE-1)/BLKSIZE; blocks>0; blocks--) { if (readtape() == NULL) { (void)fprintf(myout, "Tar: tape read error\n"); if (i_flag) done(ERREAD); return; } } } static inlist __ARGS__((int, char**, char*)); static int inlist(argc, argv, n) int argc; register char *argv[], *n; { register i; register j; register k; register char *p; for (i=0; im.name)) && (xcnt < 1 || !inlist(xcnt, xarg, hblock->m.name))) { (*handler)(); } else { if (usize()) skipfile(); } } if (pktype == PKZIP) { while ((k=unzread((char*)hblock, BLKSIZE)) == BLKSIZE); if (k != ERROR) { if (k) (void)fprintf(myout, "Tar: final block misaligned\n"); k = unzclose(); } if (k) { p = k == -1 ? "error" : v_flag ? "warning" : NULL; if (p) (void)fprintf(myout, "Tar: unzip %s: %s\n", p, ziperrlist[ziperror]); } } } extern long thisread; extern int arcget __ARGS__(( void )); void catalog() { register long thislen; register reverse = FALSE, skipped = FALSE; register char *p; static no_mem = FALSE; short nx = 1, allx; long xinfo; extern char ofname[]; register c; p = hblock->m.name; c = hblock->m.filetype; if (v_flag) prmode(prefix(), (int)(st.st_mode)); if ((c == TF_OLD || c == TF_REG) && (nx=isextent(&allx, &xinfo)) < 1) { if (st.st_size <= codesize) { reverse = TRUE; } else if (pktype == PKfLZW) { register i, j; i = strlen(hblock->m.name); if (hblock->m.name[--i] == 'Z' && hblock->m.name[--i] == '.') { p = strncpy(ofname, hblock->m.name, MAXTNAME); (void)z_getmem(BITS); codesize = 0; thisread = 0; if ((j = dbegin(arcget)) == 0) { do { if ((j = dpiece(pk_out, pksize)) > 0) codesize += j; } while (j == pksize); skipped = TRUE; } else if (j > 0) { bacouple(); /* file is not in compressed format */ } else if (!no_mem) { (void)fprintf(myout, "Tar: not enough memory to uncompress\n"); no_mem = TRUE; } } } thislen = codesize > st.st_size ? codesize : st.st_size; } else { thislen = st.st_size; } if (v_flag) { (void)fprintf(myout, " %3d/%1d ", st.st_uid, st.st_gid); if (c == TF_CHR || c == TF_BLK) { (void)fprintf(myout, pkfile ? "%10d,%-5d " : "%3d,%-3d ", dmajor, dminor); } else { (void)fprintf(myout, "%7ld ", reverse ? thislen : st.st_size); if (pkfile) { if ((c == TF_OLD || c == TF_REG) && st.st_size <= codesize) { (void)fprintf(myout, reverse && hblock->m.srcsum[1] != 'x' ? "{%7ld} " : "(%7ld) ", reverse ? st.st_size : codesize); } else { (void)fprintf(myout, " "); } } } } (void)fprintf(myout, "%-.*s", MAXTNAME, p); switch (c) { case TF_LNK: case TF_SYM: if (v_flag) (void)fprintf(myout, "\n"); (void)fprintf(myout, " %s to %s\n", c == TF_SYM ? "symlink" : "linked", hblock->m.linkname); break; case TF_OLD: case TF_REG: if (nx >= 1) { if (v_flag) (void)fprintf(myout, "\n"); (void)fprintf(myout, " [extent #%d of %d]", nx, allx); if (v_flag) (void)fprintf(myout, " %ld bytes total", xinfo); } case TF_CHR: case TF_BLK: case TF_DIR: case TF_QUE: case TF_CTG: case GF_DMP: case GF_VOL: (void)fprintf(myout, "\n"); break; case GF_MUL: if (v_flag) (void)fprintf(myout, "\n"); (void)soctul(hblock->x.offset, &xinfo); (void)fprintf(myout, "[from %ld to %ld]", xinfo, xinfo+st.st_size-1); (void)fprintf(myout, "\n"); break; default: if (v_flag) (void)fprintf(myout, "\n"); (void)fprintf(myout, _unknown, c); } if (nx < 1 && v_flag && j_flag && /*dummy*/!skipped && hblock->m.comment[0] && !ismagic()) { (void)fprintf(myout, "> %s\n", hblock->m.comment); } if (usize()) { if (!skipped) skipfile(); allbytes += thislen; } ++allfiles; } static char *cutname __ARGS__((register char *p)); static char *cutname(p) register char *p; { register j; if (nonest) { j = strlen(p); while (j>0 && p[j-1] != '/' #ifdef MSDOS && p[j-1] != ':' #endif ) --j; p += j; } else { #ifdef MSDOS if (deldrv && p[1] == ':' && (p[0]>='A' && p[0]<='Z' || p[0]>='a' && p[0]<='z')) p += 2; #endif if (dslash && *p == '/') ++p; } return p; } void extract() { register j, k; register char *p; extern int makedir __ARGS__((char *, int)); extern int testdir __ARGS__((char *)); p = cutname(hblock->m.name); if (u_flag) { struct stat s; if (stat(p, &s)==0 && s.st_mtime >= st.st_mtime) { if (usize()) skipfile(); return; } } if (w_flag && !okwork('x', prefix(), &st, p)) { if (usize()) skipfile(); return; } if ((j=strlen(p)-1) >= 0 && p[j] == '/') {/* directory with permissions */ if (testdir(p) != TRUE) return; p[j] = '\0'; } else if (hblock->m.filetype == TF_DIR || hblock->m.filetype == GF_DMP) { k = FALSE; if (makedir(p, FALSE) != 0) { if (testdir(p) != TRUE || makedir(p, TRUE) != 0) k = TRUE; } if (usize()) skipfile(); if (k) return; } else if (hblock->m.filetype == TF_LNK) { makelink(p, cutname(hblock->m.linkname)); return; } else if (hblock->m.filetype == TF_OLD || hblock->m.filetype == TF_REG) { if (restore(p) != 0) return; #ifdef UNIX } else if (hblock->m.filetype == TF_CHR || hblock->m.filetype == TF_BLK || hblock->m.filetype == TF_QUE) { st.st_mode &= 07777; if (hblock->m.filetype != TF_QUE) { st.st_mode |= hblock->m.filetype == TF_BLK ? S_IFBLK : S_IFCHR; st.st_rdev = makedev(dmajor, dminor); } else { st.st_mode |= S_IFIFO; st.st_rdev = 0; } j = 0; k = FALSE; do { if (mknod(p, st.st_mode, st.st_rdev) == 0) break; } while (++j < 2 && (k = testdir(p)) == TRUE); if (j > 1) (void)fprintf(myout, "Tar: can\'t create \'%s\'\n", p); if (j > 1 || k == ERROR) return; if (v_flag) (void)fprintf(myout, "x %s\n", p); #endif } else { (void)fprintf(myout, unknown, p, hblock->m.filetype); return; } #ifdef UNIX if (!o_flag) (void)chown(p, (int)st.st_uid, (int)st.st_gid); if (!m_flag) { long t[2]; t[0] = time(t); t[1] = st.st_mtime; (void)utime(p, t); } #endif } void uplist() { register node *this; node *prev; if ((this = finditem(hblock->m.name, &prev, timehead)) == NONE) { if ((this = additem(hblock->m.name, prev, &timehead)) == NONE) { outmem(myout); } this->info.time = st.st_mtime; } else { if (this->info.time < st.st_mtime) this->info.time = st.st_mtime; } } void acctime() { if (u_flag) uplist(); if (usize()) skipfile(); }