home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1999 mARCH
/
PCWK3A99.iso
/
Archiwiz
/
Tar320
/
SOURCES.ZIP
/
EXTRACT.C
< prev
next >
Wrap
Text File
|
1995-04-14
|
15KB
|
526 lines
/* 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 <stdio.h>
#include "sysup.h"
#include "nodedef.h"
#include "modern.h"
#ifdef MODERN
# include <string.h>
#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 && octal(s[j]); j++);
if (!j || j >= n) return FALSE;
if (s[j] == ' ') ++j;
while (j<n && !s[j++]);
return 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; i<dimof(magic_list); i++) {
p = magic_list[i];
q = hblock->x.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; i<argc; i++) {
if (s_flag) {
for (p=argv[i], j=0; j<MAXTNAME && p[j]==n[j] && p[j]!=0; j++);
if (j<MAXTNAME && p[j]==0 && (n[j]==0 || n[j]=='/')) return TRUE;
} else {
for (j=0; j<MAXTNAME && n[j];) {
do ++j; while (n[j]!='/' && n[j]!=0);
if ((k = mismatch(argv[i], n, j)) == ERROR) break;
if (!k) return TRUE;
}
}
}
return FALSE;
}
int inargs(argc, argv, n)
int argc; char *argv[], *n;
{
return inlist(argc, argv, n) && !inlist(xcnt, xarg, n);
}
void scantape(argc, argv, handler)
int argc; char *argv[]; void (*handler)__ARGS__((void));
{
register k;
register char *p;
#ifdef MSDOS
for (k=0; k<argc; k++) for (p=argv[k]; *p; p++) if (*p=='\\') *p='/';
for (k=0; k<xcnt; k++) for (p=xarg[k]; *p; p++) if (*p=='\\') *p='/';
#endif
while ((k=gethead()) != FALSE) {
pklock = TRUE;
if (k == ERROR) continue;
if ((argc < 1 || inlist(argc, argv, hblock->m.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();
}