/* tape.c - handle (tape) archive for the Tar program (see file tar.c) * Author: T.V.Shaporev * Creation date: 14 Dec 1990 * Contains both MS-DOS and UNIX specific codes * Called by many functions - see files tar.c store.c extract.c */ #include #include #include "sysup.h" #include "modern.h" #include "zippipe.h" #include "lzwhead.h" #include "compress.h" #include "define.h" #ifdef MODERN # include # include #else # ifdef M_XENIX # include # else int strlen(); char *strcpy(), *strncpy(), *mktemp(); # endif #endif #ifdef MSDOS # include # ifdef __TURBOC__ # include # else # include # endif #else int creat(), open(), read(), write(), close(); long lseek(); #endif static int n_read, mblock, nblock, rblock, wblock; static int indread, indwrite; static char rerror[] = "Tar: tape read error\n"; static int sread __ARGS__((char*, int)); static int swrite __ARGS__((char*, int)); static int sback __ARGS__((int)); #ifdef MSDOS extern int dread __ARGS__((char*, int)); extern int dwrite __ARGS__((char*, int)); extern int dback __ARGS__((int)); extern int qparse __ARGS__((char*)); extern int qbegin __ARGS__((void)); extern int qread __ARGS__((char*, int)); extern int qwrite __ARGS__((char*, int)); extern int qback __ARGS__((int)); extern int aspiparse __ARGS__((char*)); extern int aspistart __ARGS__((void)); extern int aspiread __ARGS__((char*, int)); extern int aspiwrite __ARGS__((char*, int)); extern int aspiback __ARGS__((int)); #endif static void talign __ARGS__((long)); void printbs __ARGS__((int)); static void psyserr __ARGS__((void)) { extern char *sys_errlist[]; extern sys_nerr; if (errno < sys_nerr) (void)fprintf(myout, "%s\n", sys_errlist[errno]); else (void)fprintf(myout, "error %d\n", errno); } static int sread(buf, n) /* regular file reading */ char *buf; register n; { if ((n = read(handle, buf, n)) == -1) { (void)fprintf(myout, "Tar: archive read error: "); psyserr(); } return n; } static int swrite(buf, n) /* regular file writing */ char *buf; register n; { if (write(hwrite, buf, n) != n) { (void)fprintf(myout, "Tar: archive write error: "); #ifdef MSDOS if (n != -1) (void)fprintf(myout,"disk full\n"); else #endif psyserr(); n = -1; } return n; } static int sback(n) register n; { return lseek(handle, (long)-BLKSIZE*n, 1) < 0 ? -1 : n; } #ifdef USE_COMPRESS static int zwrite __ARGS__((char*, int)); static int zwrite(buf, n) /* compressed file writing */ char *buf; register n; { cpiece(buf, n); return n; } #endif static int gread __ARGS__((char*, int)); static int gwrite __ARGS__((char*, int)); static int gread(buf, n) /* deflated file reading */ char *buf; register n; { if ((n = unzread(buf, n)) == -1) { (void)fprintf(myout, "Tar: unzip error: %s\n", ziperrlist[ziperror]); } return n; } static int gwrite(buf, n) /* deflated file reading */ char *buf; register n; { if ((n = zipwrite(buf, n)) == -1) { (void)fprintf(myout, "Tar: unzip error: %s\n", ziperrlist[ziperror]); } return n; } static int ziperr __ARGS__((void)) { (void)fprintf(stderr, "Tar: zip error: %s\n", ziperrlist[ziperror]); return ziperror == ZNOMEM ? ESMALL : ERINIT; } #ifndef USE_COMPRESS static int twofault __ARGS__((char*, int)); /*ARGSUSED2*/ static int twofault(buf, n) char *buf; register n; { #ifdef __TURBOC__ (void)buf; (void)n; #endif return -1; } #endif /*ARGSUSED*/ static int onefault(n) int n; { #ifdef __TURBOC__ (void)n; #endif return -1; } static int (*pread) __ARGS__((char*, int)) = sread; static int (*pwrite)__ARGS__((char*, int)) = swrite; static int (*pback) __ARGS__((int)) = sback; static int (*lread) __ARGS__((char*, int)) = sread; static int (*lwrite)__ARGS__((char*, int)) = swrite; static int (*lback) __ARGS__((int)) = sback; static int (*rcount)__ARGS__((char*, int)) = sread; static int cntread __ARGS__((char*, int)); static int cntread(buf, n) char *buf; register n; { if ((n = (*rcount)(buf, n)) != -1) { allblock += (BLKSIZE-1 + (unsigned)n) / BLKSIZE; } return n; } static void talign(i) long i; { if (i % BLKSIZE) { (void)fprintf(myout, "Tar: tape blocksize error\n"); if (!i_flag) done(ERREAD); } } void printbs(bs) int bs; { if (v_flag) (void)fprintf(myout, "Tar: blocksize = %d\n", bs); } static void wrerror __ARGS__((void)) { (void)fprintf(myout, "Tar: tape write error\n"); done(EWRITE); } static int indget; static int eof_already = FALSE; static int got_length; static int indput; static int getbyte __ARGS__(( void )) { if (eof_already) goto end; if (indget >= got_length) { if (pksize == 0) { if ((got_length = (*lread)(pk_inp, MAXBLOCK*BLKSIZE)) < 0) goto err; if ((sa.st_mode & S_IFMT) == S_IFCHR) talign((long)got_length); pksize = got_length; if (pksize && (pksize % BLKSIZE)==0) printbs(pksize/BLKSIZE); } else { if (got_length < pksize || got_length % BLKSIZE) goto end; if ((got_length = (*lread)(pk_inp, pksize)) < 0) goto err; } if (got_length < 1) goto end; indget = 0; } return ((unsigned char *)pk_inp)[indget++]; err: (void)fprintf(myout, rerror); done(ERREAD); end: eof_already = TRUE; return EOF; } static void pkflush __ARGS__((void)) { #ifdef MSDOS if (devtype != DEV_FILE && devtype != DEV_FLOP) #else if (!isfile) #endif while (indput < pksize) pk_out[indput++] = 0; if ((*lwrite)(pk_out, indput) < indput) wrerror(); indput = 0; } static void putbyte(c) register c; { if (indput >= pksize) { #ifndef pksize /* Buffer size must not be less then 512 bytes, so we */ /* can wait for blocksize will be detected by reading */ if (indput < BLKSIZE) goto put; if (pksize < BLKSIZE) pksize = BLKSIZE; #endif pkflush(); } put: pk_out[indput++] = c; } int initape(name) char *name; { #ifdef UNIX char tn[10]; register char *n; #endif #ifdef MSDOS register k; #endif handle = -1; pread = lread = sread; pwrite = lwrite = swrite; pback = lback = sback; if (name && name[0]=='-' && name[1]==0) { if ((a_flag && !c_flag) || d_flag) { (void)fprintf(stderr, "Tar: can\'t update stdout\n"); return ERRARG; } #ifdef myinp if (j_flag # ifndef MSDOS || w_flag # endif ) { (void)fprintf(stderr, "Tar: input must be free\n"); return ERRARG; } #endif handle = a_flag ? /* stdout */ 1 : /* stdin */ 0; myout = stderr; } else { #ifdef UNIX if (name && name[0]) { n = name; } else { n = strcpy(tn, "/dev/mt0"); tn[7] = (ndrive & 7) | '0'; } /* Do not create a file unless name specified */ handle = c_flag && n == name ? creat(n, 0666) : open(n, a_flag && !d_flag ? O_RDWR : O_RDONLY); if (handle < 0) { cantopen(n); return ERINIT; } #endif #ifdef MSDOS if (!name || !name[0]) { devtype = DEV_FLOP; inidisk(); } else if ((k=qparse(name)) != FALSE) { if (k != TRUE) return ERRARG; pread = lread = qread; pwrite = lwrite = qwrite; pback = lback = qback; devtype = DEV_QIC2; } else if ((k=aspiparse(name)) != FALSE) { if (k != TRUE) return ERRARG; pread = lread = aspiread; pwrite = lwrite = aspiwrite; pback = lback = aspiback; devtype = DEV_ASPI; } else { if (!k_flag && defdev(name)==0) k_flag = TRUE; if (k_flag) { devtype = DEV_FLOP; inidisk(); } else { handle = open(name, !a_flag || d_flag ? O_RDONLY+O_BINARY : c_flag ? O_CREAT+O_TRUNC+O_WRONLY+O_BINARY : O_RDWR+O_BINARY, S_IREAD+S_IWRITE); if (handle < 0) { cantopen(name); return ERINIT; } devtype = DEV_FILE; } } if (devtype == DEV_FLOP) { pread = lread = dread; pwrite = lwrite = dwrite; pback = lback = dback; } #endif } if (t_flag) {/* yet another redirection */ rcount = lread; pread = lread = cntread; allblock = 0L; } if (handle < 0 || fstat(handle, &sa) != 0) sa.st_mode = S_IFBLK; hwrite = handle; n_read = 0; return CORRECT; } static void swapbufs __ARGS__((void)) { register j; register char *p; p = pk_inp; pk_inp = io_buf; io_buf = p; p = pk_out; pk_out = io_2nd; io_2nd = p; j = pksize; pksize = BLKSIZE*cblock; cblock = j/BLKSIZE; } int redirect() { if (pktype == PKpLZW) { /* Redirect IO */ pread = dpiece; #ifdef USE_COMPRESS pwrite = zwrite; #else pwrite = twofault; #endif pback = onefault; swapbufs(); if (x_flag || t_flag || d_flag) { register j; indget = 0; got_length = (int)n_read; if ((j=dbegin(getbyte))!=0) { if (j < 0) { outmem(stderr); return ESMALL; } else { (void)fprintf(stderr, "Tar: archive is not in compressed format\n"); return ERINIT; } } } if (a_flag || d_flag) { #ifdef USE_COMPRESS if (cbegin(lzwbits, putbyte, 0x7fffffffL) != lzwbits) { outmem(stderr); return ESMALL; } #else (void)fprintf(stderr, "Tar: this restricted version does not support LZW compression\n"); return ERRARG; #endif } #ifdef USE_COMPRESS indput = 0; #endif } else if (pktype == PKZIP) { /* Redirect IO */ pread = gread; pwrite = gwrite; pback = onefault; swapbufs(); if (x_flag || t_flag || d_flag) { indget = 0; got_length = (int)n_read; if (unzopen(getbyte, ZIP_ANY) != 0) return ziperr(); } indput = 0; if (a_flag || d_flag) { if (zipcreat(putbyte, (gnuzip ? ZIP_GNU : ZIP_PKW), ziplevel) != 0) return ziperr(); } } rblock = mblock = cblock; nblock = 0; return CORRECT; } int runtape() { register k; #ifdef MSDOS if (devtype == DEV_QIC2) { if (qbegin()) return ERINIT; } else if (devtype == DEV_ASPI) { if (aspistart()) return ERINIT; } #endif if (!cblock && c_flag) printbs(cblock = MAXBLOCK); if ((k = redirect()) != CORRECT) return k; if (c_flag && !mblock) printbs(cblock = mblock = MAXBLOCK); wblock = 0; return CORRECT; } void duptape(n) char *n; { register i; static char template[] = "XXXXXX"; io_2nd = getbuf(BLKSIZE * (mblock ? mblock : MAXBLOCK)); if (!io_2nd) done(ESMALL); i=strlen(n); while (i>0 && #ifdef MSDOS n[i-1]!='\\' && n[i-1]!=':' && #endif n[i-1]!='/') --i; scratch = salloc((int)(i + sizeof(template))); (void)strncpy(scratch, n, i); (void)strcpy (scratch+i, template); (void)mktemp (scratch); #ifdef UNIX hwrite = creat(scratch, 0666); #endif #ifdef MSDOS hwrite = open(scratch, O_CREAT+O_TRUNC+O_RDWR+O_BINARY, S_IREAD+S_IWRITE); #endif if (hwrite < 0) { (void)fprintf(myout, "Tar: can\'t create scratch file\n"); done(EWRITE); } } void backtape() { register i; talign((long)n_read); if ((i = (int)(n_read / BLKSIZE % mblock)) == 0) i = mblock; if (!isfile) { register j; if ((*pback)(i)!=i) goto fault; if ((j=(*pread)(io_buf, BLKSIZE*rblock)) 0) pkflush(); } else #endif if (pwrite == gwrite) {/* zip compression */ if (zipclose() == -1L) wrerror(); if (indput > 0) pkflush(); } if (hwrite >= 0 && close(hwrite)!=0) { (void)fprintf(myout, "Tar: tape close error\n"); done(EWRITE); } } static int readbuf __ARGS__(( void )) { register i; for (;;) { if (mblock) { if ((i=(*pread)(io_buf, BLKSIZE*mblock)) < BLKSIZE || i%BLKSIZE!=0) { (void)fprintf(myout, rerror); if (i_flag) return -1; done(ERREAD); } n_read += i; nblock = i / BLKSIZE; } else { if ((i = (*pread)(io_buf, MAXBLOCK*BLKSIZE)) < 1) { (void)fprintf(myout, rerror); if (i_flag) return -1; done(ERREAD); } n_read += i; if (i % BLKSIZE != 0 && pktest((unsigned char*)io_buf) == CORRECT) { mblock = cblock; n_read = 0; continue; } talign((long)i); mblock = nblock = i / BLKSIZE; printbs(cblock = mblock); } break; } rblock = 0; return 0; } header *readtape() { if (rblock>=nblock && readbuf()!=0) return NULL; indread = 0; return (header *)(io_buf + BLKSIZE * rblock++); } int readbyte() { register c; if (indread == 0) ++rblock; /* get 1-st byte - take all the block */ if (rblock>nblock) { if (readbuf()!=0) return -1; rblock = 1; /* preserve 1-st block from readtape() */ } c = ((unsigned char *)(io_buf + BLKSIZE * (rblock-1)))[indread]; indread = (indread+1) & (BLKSIZE-1); return c; } void bacouple() /* return to the beginning of block after try to uncompress */ { indread = 0; --rblock; } int readarch(h, length) int h; long length; { register i; while (length > 0) { if (rblock>=nblock && readbuf()!=0) return -1; if ((i = (nblock-rblock)*BLKSIZE) > length) i = (int)length; if (write(h, io_buf + rblock * BLKSIZE, i)!=i) extwrerr(); rblock += (i + BLKSIZE-1) / BLKSIZE; length -= i; } indread = 0; return 0; } header *steptape() { if (!mblock) mblock = 1; if (wblock >= mblock) { if ((*pwrite)(io_2nd, BLKSIZE*mblock) < 0) wrerror(); wblock = 0; } indwrite = 0; return (header *)(io_2nd + BLKSIZE * wblock++); } void writebyte(c) int c; { if (indwrite == 0) ++wblock; if (wblock > mblock) { if ((*pwrite)(io_2nd, BLKSIZE*mblock) < 0) wrerror(); wblock = 1; } ((unsigned char *)(io_2nd + BLKSIZE * (wblock-1)))[indwrite] = c; indwrite = (indwrite+1) & (BLKSIZE-1); } int writearch(h, length, name) int h; long length; char *name; { register i; register j; register k; register char *p; register b; if (!mblock) mblock = 1; b = 0; while (length > 0) { if (wblock >= mblock) { if ((*pwrite)(io_2nd, BLKSIZE*mblock) < 0) wrerror(); wblock = 0; } k = BLKSIZE * (mblock-wblock); i = length < k ? (int)length : k; p = io_2nd + BLKSIZE * wblock; if ((j = read(h, p, i)) < 0) { (void)fprintf(myout, "Tar: error reading \'%s\'\n", name); done(ERREAD); } /* Calculate number of blocks affected */ k = (BLKSIZE-1 + j) / BLKSIZE; wblock += k; b += k; /* Fill the slack area */ for (p+=j, k=BLKSIZE*k-j; k>0; k--) *p++ = '\0'; if (j != i) return b; length -= i; } if (wblock >= mblock) { if ((*pwrite)(io_2nd, BLKSIZE*mblock) < 0) wrerror(); wblock = 0; } indwrite = 0; return b; }