home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 mARCH / PCWK3A99.iso / Archiwiz / Tar320 / SOURCES.ZIP / TAR.C < prev    next >
Text File  |  1996-07-03  |  30KB  |  874 lines

  1. /* tar.c - Tape ARchive utility program (main function)
  2.  * Author: T.V.Shaporev
  3.  * Creation date: 14 Dec 1990
  4.  *
  5.  * The program works in a same fashion under UNIX (most clones) and MS-DOS.
  6.  * The main idear was to develop a tool for file transferring via diskette
  7.  * between different operating systems - such as all UNIX clones, MS-DOS,
  8.  * RSX, VAX/VMS - and all others which support tar format on a diskette.
  9.  *
  10.  * First step on this way (made in 1989) lies in adapting common UNIX tar
  11.  * program to MS-DOS.
  12.  *
  13.  * On the second step
  14.  *  - some bugs were fixed (especially in DOS-applied codes) and some
  15.  *    optimization were done;
  16.  *  - nonstandard (under DOS) diskette formats were added (i.e.
  17.  *    DEC Rainbow and 80 tracks & 9 sectors format)
  18.  *  - the possibility for compress encoding were included
  19.  *    (this compressor has the best ratio among all others which
  20.  *    I know, but don't ask me about its speed). Compressed-file
  21.  *    format is compatible with the common versions of tar, so You
  22.  *    can extract the compressed image from the archive by the
  23.  *    common program, but I doubt You could uncompress them at last.
  24.  *
  25.  * On the fird step the program was totally (newly) overwritten to bypass
  26.  * any copyright exclamations. In fact, it must be considered new program
  27.  * but I prefer to continue version enumeration (I hope, nobody cares).
  28.  *
  29.  * I think, this program must be called Tar (with capital first letter)
  30.  * to distinguish it from regular UNIX tar.
  31.  *
  32.  * The program's behaviour is analogous to usual tar, and I hope, its
  33.  * internal help will be enough to understand the differences.
  34.  *
  35.  * The program doesn't perform any text file conversion - it passes
  36.  * strict binary image of each file. If You has a problems with reading
  37.  * DOS text files under UNIX (or UNIX files under DOS) please use my
  38.  * dostext program.
  39.  *
  40.  * The program must be compiled by Turbo C 2.0 compiler (in a compact
  41.  * model) under MS-DOS. Please don't replace dynamic arrays back to
  42.  * static and automatic - MS-DOS compilers dislike them.
  43.  *
  44.  *            tim    tim@ecsc.mipt.su    14 Dec 1990
  45.  */
  46. /* Version 3.01
  47.  * Handling of the 'l' option corrected
  48.  */
  49. /* Version 3.02                                       31 Dec 1990
  50.  *  - great deal of minor corrections
  51.  *  - u<pdate> option expanded to extracting
  52.  *  - j<ournal> option added (comment storying files)
  53.  *  - wildcards * and ? are now processed in archive; this may be
  54.  *    suppressed by s<trict> option
  55.  *  - d<elete> option added to replace previous occurencies of files
  56.  *    in archive on storying, or deleting files from archive when
  57.  *    whithout a<dd> parameter - this is for file archives only!
  58.  */
  59. /* Version 3.03                                       22 Feb 1991
  60.  *  - an error corrected in mismatch() (file extract.c)
  61.  *  - decreased stack requirements for tree processing
  62.  *    (see store() in store.c and putfiles() in tar.c)
  63.  *  - added codes to prevent archive file self-storying
  64.  *    (not quite reliable for MS-DOS)
  65.  *  - bincall() invocations changed by calls to rmdir() and mkdir()
  66.  *    this is done automatically for 386/ix and may be switched by
  67.  *    RMKDIR macro
  68.  */
  69. /* Version 3.04                                       29 Jul 1991
  70.  *  - a direct intialization of static global variables inserted into
  71.  *    lzencode() and lzdecode() - see file lzpack.c
  72.  */
  73. /* Version 3.04b                                      03 Oct 1991
  74.  *  - a minor correction of bincall()
  75.  *  - added default block number = sectors on track (MS-DOS)
  76.  */
  77. /* Version 3.05                                       11 Nov 1991
  78.  *  - block factor for diskette writing is set to 1 for most BIOS
  79.  *    compatibility
  80.  *  - scantape() is slightly optimized
  81.  */
  82. /* Version 3.06                                       17 Dec 1991
  83.  *  - n<onest> option applied to all actions (see inarg() in extract.c)
  84.  *  - command-line-extension-file option (responce file) added
  85.  *    for vak (vak@kiae.su) request (see append() in tar.c)
  86.  *  - p<ermission> option added to save directories permissions (UNIX)
  87.  */
  88. /* Version 3.06b                                      22 Dec 1991
  89.  *   - UNIX to DOS renaming algorithm (dot elimination) slightly
  90.  *     changed (see extract.c)
  91.  *   - most of output redirected to stdout (vs stderr)
  92.  */
  93. /* Version 3.07                                       28 Dec 1992
  94.  *   - all unary apostrofs in string constants preserved by backslashes
  95.  *   - reading file list from stdin allowed (see append() in tar.c)
  96.  *   - input redirected to /dev/tty under UNIX
  97.  *   - support for traditional UNIX compression algorithm
  98.  *   - few changes in converting UNIX names for DOS
  99.  */
  100. /* Version 3.07b                                      20 Jan 1993
  101.  *   - gethead() does not return FALSE while errors,
  102.  *     scantape() looks for tape reading errors
  103.  */
  104. /* Version 3.08                                       22 Feb 1993
  105.  *   - method-dependent comression indicator masks (see percent.c)
  106.  *   - 'z' option applied to catalog printing (see catalog())
  107.  *   - compatibility corrections in directory structure checking
  108.  *   - st.st_size == codesize - means file unpacked! (see extract.c)
  109.  */
  110. /* Version 3.09                                       14 Mar 1993
  111.  *   - a bug fixed wich prevents archiving unpacked files at all
  112.  *     (ha-ha!) - see store.c
  113.  *   - changed header description to support new features
  114.  *     see define.h
  115.  *   - support for P1003 and GNU file types - 't' option only! -
  116.  *     see extract.c
  117.  *   - small changes in #ifdef-s to distinguish SCO UNIXes from
  118.  *     XENIXes - see store.c
  119.  *   - regular file processing extracted into separate source
  120.  *     files (see savefile.c & restore.c)
  121.  *   - support for devices and FIFOs added
  122.  *   - 'l' option added for DOS (copy linked files)
  123.  *   - support for System V extents - see extract.c and restore.c
  124.  *     to read archives only, extents may not be unpacked on the
  125.  *     fly - alas, that's all for now
  126.  *   - an error corrected in roll.c
  127.  */
  128. /* Version 3.10                                       28 Jun 1993
  129.  *   - a bug fixed in old compression code (see lzpack.c)
  130.  *   - added possibility to run through compress (',' comma option)
  131.  *     see tar.c, tape.c and compress.c
  132.  *   - comments will not be printed unless 'j' is given (extract.c)
  133.  *   - separated compress-related codes
  134.  */
  135. /* Version 3.11                                       14 Jul 1993
  136.  *   - support for QIC-02 streamers (first version!)
  137.  *     devices supported: fastape, everex
  138.  */
  139. /* Version 3.12                                       29 Sen 1993
  140.  *   - slack area in archive is filled by nulls to improve compression
  141.  *   - added support for Wangtek (QIC-02) device
  142.  *   - a bug fixed in memory release ('pk_out' variable - see _done())
  143.  *   - program support for QIC-02 drive number and tape format
  144.  *     selection
  145.  *   - experimental (!) support for appending QIC-02 tapes
  146.  *     (see qback() in qicface.c)
  147.  *   - LZW support splitted into compressor and extractor and
  148.  *     the letter included in official release (see unlzw.c etc.)
  149.  *   - get default file name from TAPE environment variable
  150.  *   - 'o' flag for DOS means prevent file overwriting
  151.  */
  152. /* Version 3.12b                                      10 Nov 1993
  153.  *   - an error corrected in QIC device selection (see qicface.c)
  154.  *   - eliminated idle rewindings around QIC tape initialisation
  155.  */
  156. /* Version 3.13                                       26 Dec 1993
  157.  *   - online inflatter (unzip) and corresponding '.' (dot) option
  158.  */
  159. /* Version 3.14                                       19 Feb 1994
  160.  *   - online deflatter (zip); compilation model changed to large
  161.  */
  162. /* Version 3.15 - general bugfix                      03 Apr 1994
  163.  *   - strerror() missed in some UNIXes, so psyserr() function added
  164.  *     into tape.c
  165.  *   - extended local header signature inserted in deflated output and
  166.  *     unzclose() changed to uderstand both formats
  167.  *     (see zipdefs.h, zippipe.c and diszip.c)
  168.  *   - pkflush() output is aligned to pksize boundary if output is not
  169.  *     regular file or DOS floppy to avoid block device alignment error
  170.  *     (see tape.c)
  171.  *   - "total blocks" number is reported accordingly to real archive
  172.  *     size (see tape.c, extract.c, tar.c)
  173.  */
  174. /* Version 3.15b - bugfix                             15 Jun 1994
  175.  *   - uname() (see restore.c) bug fixed;
  176.  *   - bi_reverse() cleaned (__emit__ed code cause BC 3.1 error)
  177.  *     moved to trees.c and renamed;
  178.  *   - getlg() changed to look for NEEDBITS buffer;
  179.  *   - diszip.c cleaned a bit.
  180.  */
  181. /* Version 3.16                                       ?? Jul 1994
  182.  *   - got rid of __emit__() - completely;
  183.  *   - got rid of "#pragma pack()" - see define.h;
  184.  *   - error corrected in ct_free() (see trees.c);
  185.  *   - default (-e) compression changed to deflation,
  186.  *     keep support for old-style decompression;
  187.  *   - exclude file(s) specification ('#' option) - up to 16 patterns
  188.  *     (see fmatch.c, store.c, extract.c);
  189.  *   - autodetection of compressed or (g)zipped archives
  190.  *     (pktest() from extract.c etc.)
  191.  */
  192. /* Version 3.17                                       04 Nov 1994
  193.  *   - changed foloppy calibrating logic (see disk.c), added diskspec()
  194.  *     function (see pclevel.asm) and support for 2.88M floppies (?);
  195.  *   - corrected missing IBEGIN updating into diszip.c;
  196.  *   - added 'drop online' op. into streamer() and qend();
  197.  *   - restored handling of ':' option in savefile();
  198.  *   - restored "idle rewindings" while starting tape since
  199.  *     they arrear to improve reliability;
  200.  *   - use conditional XOFF flag in ct_iobyte() (see streamer.c);
  201.  *   - added explicit call to tzset() in tar.c;
  202.  *   - implemented 'add' and 'skip' device parameters;
  203.  *   - unzipping stored file (see diszip.c),
  204.  *     gmtime() changed to localtime() in zippipe.c;
  205.  *   - GNU-like command line syntax, environment configuration;
  206.  *   - cascade EOI changed to specific in cthandle.asm.
  207.  */
  208. /* Version 3.18                                       24 Dec 1994
  209.      - ASPI support (first version!);
  210.      - bug fixed in blocksize reading (see readblk() in readopt.c);
  211.      - bug fixed in pattern comparing (see mismatch() in fmatch.c)
  212.  */
  213. /* Version 3.20g                                       03 Jul 1996
  214.      - fix for 'file changed size'
  215.      - attempt to handle EOF inside zip
  216.  */
  217. #include "sysup.h"
  218. #include "modern.h"
  219. #include "zippipe.h"
  220. #include "lzwbits.h"
  221. #include "lzwhead.h"
  222. #include "compress.h"
  223.  
  224. static char note[] = "\n\
  225.    Tape ARchive utility        v3.20g        (C) 1990-94 Tim V.Shaporev\n";
  226.  
  227. #ifdef UNIX
  228. static char help[] = "\n\
  229.    Usage: tar -<options> [tapefile] [blocksize] [disksize] file ...\n\n\
  230.    Options are:                       s - no wildcards for archive\n\
  231.      c - put files to new archive     i - ignore read errors\n\
  232.      a,r - add files to archive       m - forget files origin date/time\n\
  233.      y - move files to archive        o - forget files owner\n\
  234.      x - extract files from archive   l - type missed links\n\
  235.      t - show archive catalog         p - save directories & permissions\n\
  236.      d - delete files in archive      n - no proceed with dir nesting\n\
  237.      u - update files                 / - omit left \'/\' in file names\n\
  238.      v - verbose                      0...7 - number of tape device\n\
  239.      w - acknowledge operations       j - comment storying files\n\
  240.      e - compress encode files        f - next arg is an archive file\n\
  241.      z - old-fashion compression      b - next arg is a blocking factor\n\
  242.      , - run through compressor       @ - next arg is a responce file\n\
  243.      . - run through (g)zip           # - exclude file(s) specification\n\
  244. ";
  245. #endif
  246.  
  247. #ifdef MSDOS
  248. static char help[] = "\n\
  249.    Usage: tar -<options> [tapefile] [blocksize] [disksize] file ...\n\n\
  250.    Options are:\n\
  251.      c - put files to new archive     s - no wildcards for archive\n\
  252.      a,r - add files to archive       m - forget files date/time\n\
  253.      y - move files to archive        n - no proceed with dir nesting\n\
  254.      x - extract files from archive   l - copy linked files\n\
  255.      t - show archive catalog         o - prevent files overwriting\n\
  256.      d - delete files in archive      \\ - omit left \'\\\' in file names\n\
  257.      u - update files                 : - omit DOS drive name\n\
  258.      v - verbose                      0...3 - number of storage device\n\
  259.      w - acknowledge operations       j - comment storying files\n\
  260.      i - ignore read errors           f - next arg is an archive file\n\
  261.      e - compress encode files        b - next arg is a blocking factor\n\
  262.      z - old-fashion compression      k - next arg is K diskette size\n\
  263.      , - run through compressor       @ - next arg is a responce file\n\
  264.      . - run through (g)zip           # - exclude file(s) specification\n\
  265. \n\
  266.    Most of options may be combined. Wildcards * and ? are o\'k\n\
  267. ";
  268. static char devlist[] = "\n\
  269.    The following \"file names\" will be treated as diskette format/size:\n\
  270. \tfd048ss8  - 160K\tfd048ds8  - 320K\tfd135ds9  - 720K\n\
  271. \tfd048ss9  - 180K\tfd048ds9  - 360K\tfd135ds18 - 1.4M\n\
  272. \tfd096ds9  - 720K\tfd096ds15 - 1.2M\trainbow\n\
  273. \n\
  274.    Streamer \"file name\" syntax (full form) is:\n\
  275. \t<device>:base:=<base address>h,dma:=<DRQ>[,irq:=<IRQ>][,norewind]\n\
  276.    Streamer device clones supported are:\n\
  277. \tarchive,\teverex,\t\twangtek\n\
  278. \n\
  279.    The following \"file names\" are aliases for ASPI driven SCSI streamer:\n\
  280. \taspitape,\taspimgr$,\taspi\n\
  281.    Full form is:\n\
  282. \taspi[:target:=<n>[,lun:=<n>][,adapter:=<n>][,density:=<x>]]\n\
  283. ";
  284. #endif
  285.  
  286. #include <signal.h>
  287. #include <stdio.h>
  288. #ifdef MSDOS
  289. #    include <string.h>
  290. #    include <stdlib.h>
  291. #    include <time.h>
  292. #    include <dos.h>
  293. #    include <dir.h>
  294. #    include <io.h>
  295. #else
  296.     char *strcpy(), *strcat(), *strncpy();
  297.         char *getenv(), *malloc(), *realloc();
  298.     int  open(), read(), close(), link(), unlink(), isatty();
  299.     int  strlen(), strncmp(), atoi();
  300.         void exit(), free();
  301.     long lseek();
  302. #endif
  303.  
  304. #define __ALLOCEXT__
  305. #include "define.h"
  306.  
  307. #include "lzpack.h"
  308. #include "roll.h"
  309.  
  310. #ifdef UNIX
  311. #    ifdef MAXNAMSIZ
  312. #        define MAXPATH MAXNAMSIZ+1
  313. #    else
  314. #        define MAXPATH 512+1
  315. #    endif
  316. #endif
  317.  
  318. #ifdef UNIX
  319. #    ifndef RMKDIR
  320. int bincall(name, args)
  321. char *name, *args;
  322. {
  323.    extern int fork(), execl(), wait();
  324.    int i; register k;
  325.    char b[24];
  326.  
  327.    if (fork() == 0) {
  328.       (void)execl(strcat(strcpy(b, "/bin/"),     name), name, args, 0);
  329.       (void)execl(strcat(strcpy(b, "/usr/bin/"), name), name, args, 0);
  330.       k = -1;
  331.    } else {
  332.       (void)wait(&i); k = i>>8;
  333.    }
  334.    return k;
  335. }
  336. #    endif
  337. #endif
  338.  
  339. #ifdef MSDOS
  340. void takename(dst, src)
  341. register char *dst, *src;
  342. {
  343.    do {
  344.       *(dst++) = *src >= 'A' && *src <= 'Z' ? *src + ('z'-'Z') :
  345.                  *src == '\\' ? '/' : *src;
  346.    } while (*(src++));
  347. }
  348. #endif
  349.  
  350. short headsum(h)
  351. header *h;
  352. {
  353.    register short i, j;
  354.  
  355.    for (i=0, j=0; i<BLKSIZE; i++) {
  356.       j += i >= MAXTNAME+3*8+2*12 && i < MAXTNAME+3*8+2*12+8 ?
  357.            ' ' : *((unsigned char *)h + i);
  358.    }
  359. #if ~0 != 0177777
  360.    return j & 0177777;
  361. #else
  362.    return j;
  363. #endif
  364. }
  365.  
  366. node *finditem(fname, prev, head)
  367. char *fname; node **prev, *head;
  368. {
  369.    register node *this;
  370.    register i;
  371.  
  372.    *prev = this = head; i = 1;
  373.    while (this && i>0) {
  374.       if ((i = strcmp(fname, this->name)) > 0) {
  375.          *prev = this; this = this->next;
  376.       }
  377.    }
  378.    return i ? NONE : this;
  379. }
  380.  
  381. node *additem(fname, prev, head)
  382. char *fname; node *prev, **head;
  383. {
  384.    register node *this;
  385.    register i;
  386.  
  387.    i = sizeof(node) - (MINTNAME-1) + strlen(fname);
  388.    if ((this = (node *)malloc(i)) == NULL) return NONE;
  389.    (void)strcpy(this->name, fname);
  390.    this->prev = prev;
  391.    if (prev != NONE) {
  392.       if ((this->next = prev->next) != NONE) this->next->prev = this;
  393.       prev->next = this;
  394.    } else {/* initialise the list */
  395.       this->next = NONE;
  396.       (*head) = this;
  397.    }
  398.    return this;
  399. }
  400.  
  401. void delitem(this, head)
  402. node *this, **head;
  403. {
  404.    if (this == *head) {/* head of the list */
  405.       if (this->next != NONE) {
  406.          this->next->prev = this->prev != this ? this->prev : this->next;
  407.       }
  408.       this = this->next;
  409.       free(*head);
  410.       *head = this;
  411.    } else {
  412.       if (this->next != NONE) this->next->prev = this->prev;
  413.       this->prev->next = this->next;
  414.       free(this);
  415.    }
  416. }
  417.  
  418. static void _done __ARGS__(( void ))
  419. {
  420.    register node *p, *q;
  421. #ifdef MSDOS
  422.    extern void qend __ARGS__((void)), aspiend __ARGS__((void));
  423.  
  424.    if      (devtype == DEV_QIC2) qend();
  425.    else if (devtype == DEV_ASPI) aspiend();
  426.    if (archname) free(archname);
  427. #endif
  428.    if (responce)  free(responce);
  429.    if (argvector) free((char*)argvector);
  430.    if (tarcmd)    free(tarcmd);
  431.    p = timehead; while (p) { q = p->next; free(p); p = q; }
  432. #ifdef UNIX
  433.    p = linkhead; while (p) { q = p->next; free(p); p = q; }
  434. #endif
  435.    if (hwrite >= 0 && hwrite != handle) {
  436.       (void)close(hwrite); (void)unlink(scratch);
  437.    }
  438.    if (io_2nd && io_2nd!=io_buf) free(io_2nd);
  439.    if (io_buf) free(io_buf);
  440.    if (pk_out && pk_out!=pk_inp) free(pk_out);
  441.    if (pk_inp) free(pk_inp);
  442.    zipfree();
  443.    unzfree();
  444. #ifdef USE_COMPRESS
  445.    z_reltab();
  446. #endif
  447.    z_relmem();
  448.    delroll();
  449. }
  450.  
  451. void done(n)
  452. int n;
  453. {
  454.    _done(); exit(n);
  455. }
  456.  
  457. void outmem(f)
  458. FILE *f;
  459. {
  460.    (void)fprintf(f, "Tar: not enough memory\n");
  461.    done(ESMALL);
  462. }
  463.  
  464. char *salloc(n)
  465. int n;
  466. {
  467.    register char *p;
  468.  
  469.    if ((p = malloc(n)) == NULL) outmem(stderr);
  470.    return p;
  471. }
  472.  
  473. int yes_no(d)
  474. char d;
  475. {
  476.    register int c;
  477. #ifdef MSDOS
  478.    extern int getkey __ARGS__((void));
  479.  
  480.    do {
  481.       c = getkey();
  482.    } while (c!='y' && c!='Y' && c!='n' && c!='N' && c!='q' && c!='Q' &&
  483.             c!='\r' && c!='\n' && c!=27 && c!=3);
  484.    if (c == 3) {
  485.       cbreak = TRUE;
  486.    } else if (c >= ' ') {
  487.       (void)fprintf(stderr, "%c", c);
  488.    } else if (d) {
  489.       (void)fprintf(stderr, "%c", d);
  490.    }
  491.    (void)fprintf(stderr, "\n");
  492. #else
  493.    if ((c = getc(myinp)) == '\n') {
  494.       c = d;
  495.    } else {
  496.       while (getc(myinp) != '\n') ;
  497.    }
  498. #endif
  499.    if (c == 'q' || c == 'Q') done(EXIT);
  500.    return c == 'y' || c == 'Y';
  501. }
  502.  
  503. void prmode(c, m)
  504. char c; int m;
  505. {
  506.    (void)fprintf(myout, "%c%c%c%c%c%c%c%c%c%c", c,
  507.       (m & S_IREAD ? 'r' : '-'), (m & S_IWRITE? 'w' : '-'),
  508.       (m & S_ISUID ? 's' : m & S_IEXEC ? 'x' : '-'),
  509.       (m & 00040   ? 'r' : '-'), (m & 00020   ? 'w' : '-'),
  510.       (m & S_ISGID ? 's' : m & 00010   ? 'x' : '-'),
  511.       (m & 00004   ? 'r' : '-'), (m & 00002   ? 'w' : '-'),
  512.       (m & S_ISVTX ? 't' : m & 00001   ? 'x' : '-'));
  513. }
  514.  
  515. int okwork(c, p, s, n)
  516. char c, p, *n;
  517. struct stat *s;
  518. {
  519.    register m;
  520.  
  521.    (void)fprintf(stderr, "%c ", c);
  522.    if (v_flag) {
  523.       if (p == ' ' && (m = s->st_mode & S_IFMT) != 0) {
  524.          switch (m) {
  525.             case S_IFREG: break;
  526.             case S_IFDIR: p = 'd'; break;
  527.             case S_IFIFO: p = 'p'; break;
  528.             case S_IFCHR: p = 'c'; break;
  529.             case S_IFBLK: p = 'b'; break;
  530. #ifdef S_IFLNK
  531.             case S_IFLNK: p = 'l'; break;
  532. #endif
  533.             default:      p = '?';
  534.          }
  535.       }
  536.       prmode(p, (int)(s->st_mode));
  537.       (void)fprintf(stderr," %3d/%1d %7ld ",s->st_uid,s->st_gid,s->st_size);
  538.    }
  539.    (void)fprintf(stderr, "%s : ", n);
  540.    return YES_NO();
  541. }
  542.  
  543. void onintr() { (void)signal(SIGINT,  SIG_IGN); cbreak = TRUE; }
  544. #ifdef UNIX
  545. void onquit() { (void)signal(SIGQUIT, SIG_IGN); cbreak = TRUE; }
  546. void onhup()  { (void)signal(SIGHUP,  SIG_IGN); cbreak = TRUE; }
  547. #endif
  548.  
  549. static void set_sig __ARGS__(( void ))
  550. {
  551.    if (signal(SIGINT, SIG_IGN) != SIG_IGN) (void)signal(SIGINT, onintr);
  552. #ifdef UNIX
  553.    if (signal(SIGHUP, SIG_IGN) != SIG_IGN) (void)signal(SIGHUP, onhup );
  554.    if (signal(SIGQUIT,SIG_IGN) != SIG_IGN) (void)signal(SIGQUIT,onquit);
  555. #endif
  556. }
  557.  
  558. static void delfile __ARGS__(( void ))
  559. {
  560.    if (v_flag)
  561.       (void)fprintf(myout, "d %s, %ld bytes, %ld tape blocks\n",
  562.          hblock->m.name, st.st_size, (st.st_size + (BLKSIZE-1))/BLKSIZE);
  563.    if (usize()) skipfile();
  564. }
  565.  
  566. static void putfiles __ARGS__(( int, char ** ));
  567.  
  568. static void putfiles(argc, argv)
  569. int argc; char *argv[];
  570. {
  571.    register i;
  572.    char fnmbuf[MAXPATH];
  573.  
  574.    for (i=0; i<argc; i++) {
  575.       if (strlen(argv[i]) > MAXTNAME) {
  576.          (void)fprintf(myout, "Tar: \'%s\' name too long\n", argv[i]);
  577.          continue;
  578.       }
  579.       takename(fnmbuf, argv[i]);
  580.       store(fnmbuf);
  581.    }
  582. }
  583.  
  584. static void stdhelp __ARGS__((void))
  585. {
  586.    (void)fprintf(stdout, note);
  587.    (void)fprintf(stdout, help);
  588.    (void)fflush (stdout);
  589. #ifdef MSDOS
  590.    if (ioctl(fileno(stdout),0) & 0x80) {/* not a disk file */
  591.       (void)fprintf(stderr,"\nDo you want to see device list? ");
  592.       (void)fflush (stderr);
  593.       if (!YES_NO()) return;
  594.    }
  595.    (void)fprintf(stdout, devlist);
  596. #endif
  597. }
  598.  
  599. int pkalloc()
  600. {
  601.    register k;
  602.  
  603.    if (pktype == PKpLZW || pktype == PKZIP) {/* Pipe compression */
  604.       pksize = BLKSIZE;
  605.       k = (d_flag || x_flag || t_flag) && (pk_inp=malloc(pksize))==NULL ||
  606.           (d_flag || a_flag)           && (pk_out=malloc(pksize))==NULL;
  607.    } else {/* Individual file(s) compression */
  608.       pksize = PKSIZE;
  609.       k = (d_flag || x_flag || (t_flag && pktype == PKfLZW)) &&
  610.                                 (pk_out=malloc(pksize))==NULL ||
  611.           (d_flag || a_flag) && (pk_inp=malloc(pksize))==NULL;
  612.    }
  613.    return k;
  614. }
  615.  
  616. int main(argc, argv)
  617. int argc; char *argv[];
  618. {
  619.    register i, k;
  620.    register char *p;
  621.    int cenv; char **earg;
  622.  
  623.    if (argc < 2) {
  624.       stdhelp(); return ERRARG;
  625.    }
  626. #ifdef MSDOS
  627.    setdrive = FALSE;
  628.    filemask = FA_SYSTEM+FA_HIDDEN+FA_RDONLY+FA_DIREC+FA_ARCH;
  629. #endif
  630.    pktype = PKNONE;
  631.    pklock = FALSE;
  632.    cblock = 0;
  633.    tapename = NULL;
  634.    myout = stdout;
  635.    xcnt = 0;
  636.    lzwbits = BITS; ziplevel = 6;
  637.  
  638.    /* Skip the program name */ --argc; ++argv;
  639.    appname = NULL;
  640.    if ((cenv = envbuild(0, &earg)) > 0) {
  641.       i = readopt(&cenv, &earg, OPTFLAG);
  642.       if (i < cenv) {
  643.          revector(argc, &argv, cenv-i);
  644.          /* append new arguments */
  645.          while(i<cenv) argv[argc++] = earg[i++];
  646.       }
  647.       if (appname) argc = argfile(argc, &argv, appname, &responce);
  648.    }
  649.    i = readopt(&argc, &argv, 0);
  650.    pktype &= OPTMASK;
  651. #ifdef MSDOS
  652.    if (nonest) filemask = FA_SYSTEM+FA_HIDDEN+FA_RDONLY+FA_ARCH;
  653. #endif
  654.    if (
  655. #ifdef MSDOS
  656.        !k_flag &&
  657. #endif
  658.                   !tapename) tapename = getenv("TAPE");
  659.    if (!a_flag && !x_flag && !t_flag && !d_flag) {
  660.       (void)fprintf(stderr, "Tar: nothing to do\n"); return ERRARG;
  661.    }
  662.    if (a_flag || d_flag) {
  663.       if (i >= argc) {
  664.          (void)fprintf(stderr, "Tar: no files specified\n");
  665.          return ERRARG;
  666.       }
  667. #ifndef USE_COMPRESS
  668.       if (pktype == PKfLZW || pktype == PKpLZW) {
  669.          (void)fprintf(stderr,
  670.          "Tar: this restricted version does not support LZW compression\n");
  671.          return ERRARG;
  672.       }
  673. #endif
  674.    }
  675.    if ((k = initape(tapename)) != CORRECT) done(k);
  676.    if ((io_buf=getbuf(cblock ? cblock*BLKSIZE : MAXBLOCK*BLKSIZE)) == NULL)
  677.       done(ESMALL);
  678.    io_2nd = io_buf;
  679.    if (pktype != PKNONE) {
  680.       if (pkalloc()) {/* Memory lack */
  681.          if (!w_flag) {
  682.             outmem(stderr);
  683.          } else {
  684.             (void)fprintf(stderr,
  685.                "No memory for [de]compression. Continue? ");
  686.             k = YES_NO();
  687.             (void)fprintf(stderr, "\n");
  688.             if (!k) done(ESMALL);
  689.             if (pk_inp) { free(pk_inp); pk_inp = NULL; }
  690.             pktype = PKNONE;
  691.          }
  692.       }
  693.    }
  694.    cbreak = FALSE;
  695.  
  696.    if ((k = runtape()) != CORRECT) done(k);
  697. #ifdef UNIX
  698.    myinp = stdin;
  699.    if (!isatty(/* stdin */ 0) && (myinp = fopen("/dev/tty", "r")) == NULL) {
  700.       (void)fprintf(myout,
  701.          "Tar: warning: can\'t open terminal device, may be problems\n");
  702.       myinp = stdin;
  703.    }
  704. #endif
  705.  
  706. #ifdef MSDOS
  707.    if (a_flag && isfile) {
  708.       p = tapename;
  709.       if ((p[0]>='A' && p[0]<='Z' || p[0]>='a' && p[0]<='z') && p[1]==':') {
  710.          k = p[0] < 'a' ? p[0] - ('A'-1) : p[0] - ('a'-1); p += 2;
  711.       } else {
  712.          k = 0;
  713.       }
  714.       if (p[0] == '/' || p[0] == '\\') {
  715.          takename((archname = salloc(strlen(p) + 1)), p);
  716.       } else {
  717.          archname = salloc(strlen(p) + MAXPATH);
  718.          *(int *)archname = '/';
  719.          getcurdir(k, archname+1); takename(archname, archname);
  720.          k = strlen(archname);
  721.          archname[k++] = '/';
  722.          takename(archname+k, p);
  723.       }
  724.    }
  725.    /* Turbo C 2.0 stat() does not call tzset(), so
  726.       invoke it explicitly (for non-file archives) */
  727.    tzset();
  728. #endif
  729.    argc -= i; argv += i;
  730.  
  731.    if (d_flag) {
  732.       register header *h; register long l; register m;
  733.  
  734.       if (d_flag && !isfile) {
  735.          (void)fprintf(stderr,
  736.                        "Tar: delete option is for file archives only\n");
  737.          return ERRARG;
  738.       }
  739.       duptape(tapename);
  740.  
  741.       m = FALSE;
  742.       do {
  743.          if ((k = gethead()) == ERROR) done(ERREAD);
  744.          if (!k) continue;
  745.  
  746.          if        (a_flag) {
  747.             struct stat s;
  748.  
  749.              if (inargs(argc, argv, hblock->m.name)) {
  750.                 if (u_flag) uplist();
  751.                 if (stat(hblock->m.name, &s)!=0) {
  752.                    if (v_flag) {
  753.                       (void)fprintf(myout, "Tar: can\'t access \'%s\'\n",
  754.                                             hblock->m.name);
  755.                    }
  756.                 } else if (!u_flag || s.st_mtime > st.st_mtime) {
  757.                    delfile(); continue;
  758.                 }
  759.              }
  760.          } else {/* pure delete */
  761.             if (inargs(argc, argv, hblock->m.name) ||
  762.                ((hblock->m.filetype==TF_LNK || hblock->m.filetype==TF_SYM) &&
  763.                 inargs(argc, argv, hblock->m.linkname))) {
  764.                m = TRUE; delfile(); continue;
  765.             }
  766.          }
  767.  
  768.          /* move file to output archive */
  769.          for (h=steptape(), i=0; i<BLKSIZE/sizeof(int); i++) {
  770.             ((int *)h)[i] = ((int *)hblock)[i];
  771.          }
  772.          if (usize()) {
  773.             l = (st.st_size + (BLKSIZE-1)) / BLKSIZE;
  774.             while (l-- > 0) {
  775.                if ((hblock = readtape()) == NULL) done(ERREAD);
  776.                for (h=steptape(), i=0; i<BLKSIZE/sizeof(int); i++) {
  777.                   ((int *)h)[i] = ((int *)hblock)[i];
  778.                }
  779.             }
  780.          }
  781.       } while (k);
  782.  
  783.       if (a_flag) {
  784.          l = lseek(hwrite, 0L, 1);
  785.          putfiles(argc, argv);
  786.          m = lseek(hwrite, 0L, 1) > l;
  787.       }
  788.  
  789.       if (m) {/* archive was modified */
  790.          endtape();
  791.          if (unlink(tapename)) {
  792.             (void)fprintf(myout, "Tar: can\'t delete \'%s\'\n", tapename);
  793.             done(EWRITE);
  794.          }
  795. #ifdef UNIX
  796.          if (link(scratch, tapename)) {
  797.             (void)fprintf(myout,
  798.                "Tar: can\'t link \'%s\' - data stay in \'%s\'\n",
  799.                tapename, scratch);
  800.             done(EWRITE);
  801.          }
  802.          if (unlink(scratch)) {
  803.             (void)fprintf(myout, "Tar: can\'t delete scratch file\n");
  804.          }
  805. #endif
  806.  
  807. #ifdef MSDOS
  808.          if (rename(scratch, tapename)) {
  809.             (void)fprintf(myout, "Tar: can\'t rename \'%s\' to \'%s\'\n",
  810.                                   scratch, tapename);
  811.             done(EWRITE);
  812.          }
  813. #endif
  814.  
  815. #ifdef UNIX
  816.          if (a_flag && l_flag) {
  817.             register node *this;
  818.  
  819.             for (this=linkhead; this; this=this->next) {
  820.                (void)fprintf(myout, "Tar: missed %d link(s) to \'%s\'\n",
  821.                              this->info.data.count, this->name);
  822.             }
  823.          }
  824. #endif
  825.       } else {
  826.          if (v_flag) (void)fprintf(myout, "Tar: archive unchanged\n");
  827.          (void)close(hwrite);
  828.          if (unlink(scratch)) {
  829.             (void)fprintf(myout, "Tar: can\'t delete scratch file\n");
  830.             done(EWRITE);
  831.          }
  832.       }
  833.    } else if (a_flag) {
  834. #ifdef MSDOS
  835.       if (w_flag && c_flag && devtype == DEV_FLOP) {
  836.          fprintf(stderr,
  837.                  "\007Data on drive %c: would be destroyed. Continue ? ",
  838.                  ndrive + 'A');
  839.          if (!YES_NO()) done(ERRARG);
  840.       }
  841. #endif
  842.       if (a_flag && !c_flag) {
  843.          scantape(argc, argv, acctime); backtape();
  844.       }
  845.       set_sig();
  846.       putfiles(argc, argv);
  847.       endtape();
  848. #ifdef UNIX
  849.       if (l_flag) {
  850.          register node *this;
  851.  
  852.          for (this=linkhead; this; this=this->next) {
  853.             (void)fprintf(myout, "Tar: missed %d link(s) to \'%s\'\n",
  854.                           this->info.data.count, this->name);
  855.          }
  856.       }
  857. #endif
  858.    } else if (x_flag) {
  859. #ifdef UNIX
  860.       (void)umask(0);
  861. #endif
  862.       scantape(argc, argv, extract);
  863.    } else {/* if (t_flag) */
  864.       allbytes = 0; allfiles = 0;
  865.       scantape(argc, argv, catalog);
  866.       if (v_flag) {
  867.          (void)fprintf(myout,
  868.             "\tTotal %u file(s) for %lu bytes in %lu tape blocks\n",
  869.             allfiles, allbytes, allblock);
  870.       }
  871.    }
  872.    _done(); return 0;
  873. }
  874.