/* restore.c - extract regular files from (tape) archive. * This is a part of the Tar program (see file tar.c) * Author: T.V.Shaporev * Creation date: 11 Mar 1993 */ #include #include #include "sysup.h" #include "modern.h" #ifdef MODERN # include #else char *strncpy(); int strlen(); #endif #ifdef MSDOS # include # include # include # ifdef __TURBOC__ # include # else # include # endif #else int access(), creat(), open(), close(), link(), unlink(); int write(), chown(), utime(); char *malloc(); long lseek(); void free(); #endif #include "lzwbits.h" #include "lzwhead.h" #include "compress.h" #include "zippipe.h" #include "crc32.h" #include "define.h" #include "lzpack.h" char ofname[MAXTNAME #ifdef MSDOS +MAXFILE #endif +1]; void extwrerr() { (void)fprintf(myout, "Tar: error extracting \'%s\'\n", ofname); done(EWRITE); } #ifdef MSDOS static void setime __ARGS__(( int, long )); static void setime(h, mt) int h; long mt; { struct date d; struct time t; struct ftime f; if (m_flag) return; unixtodos(mt, &d, &t); f.ft_tsec = t.ti_sec; f.ft_min = t.ti_min; f.ft_hour = t.ti_hour; f.ft_day = d.da_day; f.ft_month = d.da_mon; f.ft_year = d.da_year - 1980; (void)setftime(h, &f); } #define wcnt_type unsigned short #define MAXWARN 8 static renamed = FALSE; static wcnt_type wcount = 0; static nwarn = 0; static struct { wcnt_type lru; char wnm[MAXTNAME]; } wlist[MAXWARN]; static void wrename __ARGS__(( char * )); static void wrename(n) char *n; { register i; renamed = FALSE; for (i=0; i='A' && p[0]<='Z' || p[0]>='a' && p[0]<='z')) p += 2; tmpren = FALSE; while (*p) { if (*p == '/') { ++p; /* Forget dir name changes */ tmpren = FALSE; } for (offext=i=0; p[i] && p[i]!='/'; i++) { if (p[i] == '.') { if (i == 0) { if (p[1]=='.' && (p[2]=='/' || p[2]=='\0')) { /* This is '..' directory, skip */ ++i; } else if (p[1]!='/' && p[1]!='\0') { /* This is not current directory */ p[0] = CH_DOT; tmpren = TRUE; } } else { if (offext) { p[offext] = CH_DOT; tmpren = TRUE; } offext = i; } } else if (p[i]<=' ' || p[i]>'~' || strchr(invalid, p[i])) { p[i] = CH_BAD; tmpren = TRUE; } } if (!offext) offext = i; limcpy = MAXTNAME - (int)(p-fname) - offext; i -= offext; if (offext <= 8) { j = offext; } else { (void)strncpy(p+8, p+offext, i>4 ? 4 : limcpy); tmpren = TRUE; j = 8; } if (i <= 4) { j += i; } else { (void)strncpy(p+(offext>8 ? 12 : offext+4), p+i+offext, limcpy-i); tmpren = TRUE; j += 4; } p += j; } if (tmpren) renamed = TRUE; } #else # define setime(h,t) # define uname(s) #endif int makedir __ARGS__((char *, int)); int testdir __ARGS__((char *)); /*ARGSUSED*/ int makedir(p, to_print) char *p; int to_print; { #ifdef UNIX # ifdef RMKDIR if (mkdir(p, 0777) != 0 && to_print) { (void)fprintf(myout, "Tar: can\'t create directory \'%s\'\n", p); return ERROR; } # else switch (bincall("mkdir", p)) { case 0: break; case -1: (void)fprintf(myout, "Tar: fault run mkdir!\n"); default: done(0); } # endif if (!o_flag) (void)chown(p,(int)st.st_uid,(int)st.st_gid); #endif #ifdef MSDOS if (mkdir(p) != 0 && to_print) { (void)fprintf(myout, "Tar: can\'t create directory \'%s\'\n", p); return ERROR; } #endif return 0; } int testdir(p) char *p; { register j; register k = FALSE; #ifndef UNIX register char *q = p; #endif #ifdef MSDOS renamed = FALSE; #endif for (j=1; j= pksize) { if (write(o_file, pk_out, pksize) != pksize) { if (v_flag) (void)fprintf(myout, "\n"); extwrerr(); } indput = 0; } } #define savename(s) ((void)strncpy(ofname,(s),MAXTNAME),ofname[MAXTNAME]='\0') static int newfile __ARGS__(( char *, int )); static int newfile(name, mode) char *name; int mode; { #ifdef MSDOS int h, caccess; unsigned cmode; register k = 0; savename(name); caccess = o_flag ? O_CREAT+O_EXCL+O_WRONLY+O_BINARY : O_CREAT+O_TRUNC+O_WRONLY+O_BINARY; cmode = (mode & 0444 ? S_IREAD : 0) | (mode & 0222 ? S_IWRITE : 0) | (mode & 0111 ? S_IEXEC : 0); if ((h = open(name, caccess, cmode)) < 0) { if (errno == ENOENT || errno == ENOPATH) { if ((k=testdir(name)) == TRUE) h = open(name, caccess, cmode); } else if (errno == EEXIST && o_flag) { static char del[4] = "^~\'`"; register unsigned ntry = 0; register nb, len, i, j; char suffix[5]; if ((len = strlen(name)) > MAXTNAME) goto end; for (nb=len; nb>0 && name[nb-1]!='/' && name[nb-1]!=':'; nb--) { if (name[nb] == '.') len = nb; } len -= nb; do { ++ntry; /* Convert number of try into suffix */ suffix[0] = del[ntry & 3]; for (i=1, j=ntry>>2; j; j>>=5) { suffix[i++] = ((j & 037) < 10 ? '0': 'A'-10) + (j & 037); } suffix[i] = '\0'; /* Replace end of the name by suffix */ if (len < 8) { (void)strcat( strcpy(ofname+nb+(len+i<8 ? len : 8-i), suffix), name+nb+len); } else { (void)strncpy(ofname+nb+len-i, suffix, i); } renamed = TRUE; h = open(ofname, caccess, cmode); } while (h<0 && errno == EEXIST && ntry); } } end: if (h < 0) { if (k!=ERROR) (void)fprintf(myout,"Tar: can\'t create \'%s\'\n",name); } else { if (renamed && v_flag) wrename(ofname); if ((mode & 0777) == 0) (void)_chmod(name, 1, FA_HIDDEN); } return h; #else register j = 0; register h; savename(name); do { if ((h = creat(name, (int)(mode & 07777))) >= 0) { if (!o_flag) (void)chown(name, (int)st.st_uid, (int)st.st_gid); return h; } } while (++j < 2 && testdir(name) == TRUE); if (j > 1) (void)fprintf(myout, "Tar: can\'t create \'%s\'\n", name); return ERROR; #endif } static void pfile __ARGS__((char *, long, long)); static void pfile(name, bytes, blocks) char name[]; long bytes, blocks; { if (v_flag) { (void)fprintf(myout, "x %s, %ld bytes, %ld tape blocks", name, bytes, blocks); (void)fflush(myout); } } static int xany __ARGS__((void)) { (void)fprintf(stderr, " Extract anyway? "); (void)fflush(stderr); return YES_NO(); } int restore(p) register char *p; { register j; register long bytes, blocks; static char no_mem[] = "\nTar: no memory to unpack."; static char e[] = " \n"; short nx=0, allx; long l=0, xinfo; int multy = FALSE; /* Multyvolume processing flag */ extern int soctul __ARGS__((char*, long*)); #ifdef MSDOS renamed = FALSE; #endif if (hblock->m.filetype == GF_MUL) { (void)soctul(hblock->x.offset, &xinfo); multy = TRUE; } else { if ((nx = isextent(&allx, &xinfo)) > 0) multy = TRUE; } bytes = codesize > st.st_size ? codesize : st.st_size; blocks = (st.st_size + BLKSIZE-1)/BLKSIZE; if (pktype == PKfLZW && !multy && st.st_size >= codesize) { j = strlen(p); if (p[--j] != 'Z' || p[--j] != '.') goto regular; p[j] = '\0'; uname(p); if ((o_file = newfile(p, st.st_mode)) < 0) { skipfile(); return ERROR; } pfile(p, bytes, blocks); p[j] = '.'; (void)z_getmem(BITS); thisread = 0; indput = 0; thiscsum = 0; if ((j = dbegin(arcget)) == 0) { do { j = dpiece(pk_out, pksize); if (j > 0) { if (write(o_file, pk_out, j) != j) { if (v_flag) (void)fprintf(myout, "\n"); extwrerr(); } if (v_flag) percent(thisread, st.st_size); } } while (j == pksize); (void)fprintf(myout, v_flag ? e : e+sizeof(e)-2); goto xend; } else if (j > 0) { if (v_flag) (void)fprintf(myout, " is not in compressed format\n"); } else { if (!xany()) done(ESMALL); } bacouple(); z_relmem(); } regular: uname(p); if (nx > 1 || (hblock->m.filetype == GF_MUL && xinfo > 0)) { /* Multivolume processing */ if ((o_file = open(p, O_WRONLY|O_BINARY)) >= 0) { savename(p); if ((l=lseek(o_file, 0L, 2)) == -1L) { (void)fprintf(myout, " Tar: \'%s\' seek error\n", p); goto fault; } if (hblock->m.filetype == GF_MUL && l != xinfo) { if (w_flag) { (void)fprintf(stderr, " Tar: \'%s\' mismatch size. Append? ", p); (void)fflush(stderr); if (YES_NO()) goto opened; } else { (void)fprintf(myout, " Tar: warning: \'%s\' mismatch size\n", p); } l = lseek(o_file, xinfo, 0); } goto opened; } else if (errno == ENOENT) { if (w_flag) { (void)fprintf(stderr, " Tar: \'%s\' does not exist.", p); if (!xany()) goto fault; } else { (void)fprintf(myout, " Tar: warning: \'%s\' does not exist\n", p); goto fault; } } else { (void)fprintf(myout, "Tar: can\'t append \'%s\'\n", p); goto fault; } } if ((o_file = newfile(p, st.st_mode)) < 0) goto fault; opened: pfile(ofname, bytes, blocks); if (st.st_size >= codesize || multy) {/* file was not packed */ if (v_flag) { if (nx > 0) { (void)fprintf(myout," [extent #%d of %d]", nx, allx); } else if (hblock->m.filetype == GF_MUL) { (void)fprintf(myout," ["); if (l != xinfo) (void)fprintf(myout,"from %ld - ", xinfo); (void)fprintf(myout,"append @%ld]", l); } (void)fprintf(myout, "\n"); } (void)readarch(o_file, st.st_size); if (nx > 1 && nx == allx && lseek(o_file, 0L, 2) != xinfo) { /* last extent extracted, so check for total file size */ (void)fprintf(myout,"Tar: warning: \'%s\' changed size\n",ofname); } } else {/* file was packed */ if (!pk_out) pk_out = malloc(pksize); if (hblock->m.srcsum[1] != 'x') {/* Old decompression */ if (!pk_out || lzgetmem()) { (void)fprintf(myout, "%s\n", no_mem); done(ESMALL); } thisread = 0; indput = 0; thiscsum = 0; l = lzdecode(arcget, dstput, codesize); (void)fprintf(myout, v_flag ? e : e+sizeof(e)-2); if (indput > 0 && write(o_file, pk_out, indput) != indput) extwrerr(); if (l != codesize) { (void)fprintf(myout, "Tar: \'%s\' decode error\n", ofname); if (!i_flag) done(EINTER); } if (thiscsum != longcsum) { (void)fprintf(myout, "Tar: \'%s\' checksum error\n", ofname); } } else {/* Inflation */ if (!pk_out || unzalloc()) { (void)fprintf(myout, "%s\n", no_mem); done(ESMALL); } thisread = 0; indput = 0; thiscsum = 0; if (unzopen(arcget, ZIP_RAW)) { (void)fprintf(myout, "Tar: unzip error: %s\n", ziperrlist[ziperror]); done(EINTER); } do { j = unzread(pk_out, pksize); if (j > 0) { if (write(o_file, pk_out, j) != j) { if (v_flag) (void)fprintf(myout, "\n"); extwrerr(); } if (v_flag) percent(thisread, st.st_size); } } while (j == pksize); (void)fprintf(myout, v_flag ? e : e+sizeof(e)-2); if (j != -1) { if ((j = unzclose()) == 0) { if (getcrc() != longcsum) j = ziperror = BADCRC; } } if (j) { (void)fprintf(myout,"Unzip %s: %s\n", (j == -1 ? "error" : "warning"), ziperrlist[ziperror]); if (j == -1) done(EINTER); } } } xend: j = nx > 0 && nx < allx; #ifdef MSDOS if (!j) setime(o_file, st.st_mtime); #endif (void)close(o_file); return j; fault: if (o_file >= 0) (void)close(o_file); skipfile(); return ERROR; } void makelink(fname, lname) char *fname, *lname; { #ifdef MSDOS # define BUFSIZE 8192 char *buffer = NULL; int bufsize = BUFSIZE; #endif register j; #ifdef UNIX (void)unlink(fname); if ((j = link(lname, fname)) < 0) { if (testdir(fname) == TRUE) j = link(lname, fname); } if (j < 0) (void)fprintf(myout, "Tar: can\'t link \'%s\' to \'%s\'\n", fname, lname); else #endif #ifdef MSDOS if (l_flag) {/* copy file */ int inp, out; char *buffer; int bufsize; long rsize, mtime; if ((buffer = malloc(BUFSIZE)) == NULL) { if (pk_out) { buffer = pk_out; bufsize = pksize; } else { buffer = (char *)hblock; bufsize = BLKSIZE; } } if ((inp = open(lname, O_RDONLY+O_BINARY)) < 0) { cantopen(lname); goto quit; } if ((out = newfile(fname, st.st_mode)) < 0) { (void)close(inp); goto quit; } rsize = st.st_size; mtime = st.st_mtime; do { if ((j = read(inp, buffer, bufsize)) > 0) { rsize -= j; if (write(out, buffer, j) != j) { extwrerr(); j = ERROR; } } } while (j == bufsize); if (j >= 0) setime(out, mtime); (void)close(out); (void)close(inp); if (j < 0) goto quit; if (v_flag) (void)fprintf(myout, "x %s copied from %s\n", fname, lname); if (rsize != 0) (void)fprintf(myout, "Tar: warning \'%s\' real size differs from the recorded\n",fname); } else #endif if (v_flag) (void)fprintf(myout, "x %s linked to %s\n", fname, lname); #ifdef MSDOS quit: if (buffer != NULL && bufsize == BUFSIZE) free(buffer); #endif }