home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume23 / afio / part01 / afio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-16  |  33.4 KB  |  1,456 lines

  1. /*
  2.  * afio.c
  3.  *
  4.  * Manipulate archives and files.
  5.  *
  6.  * Copyright (c) 1985 Lachman Associates, Inc..
  7.  *
  8.  * This software was written by Mark Brukhartz at Lachman Associates,
  9.  * Inc.. It may be distributed within the following restrictions:
  10.  *    (1) It may not be sold at a profit.
  11.  *    (2) This credit and notice must remain intact.
  12.  * This software may be distributed with other software by a commercial
  13.  * vendor, provided that it is included at no additional charge.
  14.  *
  15.  * Please report bugs to "uunet!sawmill!prslnk!buhrt"
  16.  *
  17.  * Options:
  18.  *  o Define INDEX to use index() in place of strchr() (v7, BSD).
  19.  *  o Define MEMCPY when an efficient memcpy() exists (SysV).
  20.  *  o Define MKDIR when a mkdir() system call is present (4.2BSD, SysVr3).
  21.  *  o Define NOVOID if your compiler doesn't like void casts.
  22.  *  o Define SYSTIME to use <sys/time.h> rather than <time.h> (4.2BSD).
  23.  *  o Define VOIDFIX to allow pointers to functions returning void (non-PCC).
  24.  *  o Define CTC3B2 to support AT&T 3B2 streaming cartridge tape.
  25.  *  o Define HAVEFCNTL if you have <fcntl.h>
  26.  *  o Define USESHMEM if you have shared memory (AT&T 3b1)
  27.  *  o Define MYTEMPNAM if you don't have tempnam()
  28.  *  o Define UNIXPC if you are on a 3b1, 7300, etc.
  29.  *  o Define HAVEMEMCMP if you have memcmp otherwise assumes bcmp
  30.  *  o Define DEFFMTCMD to being how to format the media you use the most.
  31.  *  o Define LONGZFILE if you want .Z to be tagged on the end of a 14 char
  32.  *
  33.  * BUGS:
  34.  *    Still needs '286 floppy support.
  35.  *
  36.  * Added by Jeff Buhrt:
  37.  *    Floppy Verify/format/restart output in the middle of a set,
  38.  *    compress files on output, extended error messages and logging
  39.  *
  40.  * NOTE: If you are compressing and the temp directory you pick is
  41.  *    on a NSF file system, watch out for "stale handle" caused
  42.  *    by opening the compress output file then unlinking before
  43.  *    returning an open file descriptor.
  44.  */
  45.  
  46. static char *ident = "$Header: /u/buhrt/src/afio/RCS/afio.c,v 2.3 1991/09/25 20:08:33 buhrt Exp $";
  47.  
  48. #include <stdio.h>
  49. #include <errno.h>
  50. #include <sys/signal.h>
  51. #include <sys/types.h>
  52. #include <sys/ioctl.h>
  53. #include <sys/stat.h>
  54. #include <pwd.h>
  55. #include <grp.h>
  56. #include "patchlevel.h"
  57.  
  58. #ifndef    major
  59. #    include <sys/sysmacros.h>
  60. #endif    /* major */
  61.  
  62. #ifdef    SYSTIME
  63. #    include <sys/time.h>
  64. #else    /* SYSTIME */
  65. #    include <time.h>
  66. #endif    /* SYSTIME */
  67.  
  68. #ifdef    CTC3B2
  69. #    include <sys/vtoc.h>
  70. #    include <sys/ct.h>
  71. #endif    /* CTC3B2 */
  72.  
  73. #ifdef MYTEMPNAM
  74. #include <sys/file.h>
  75. #endif
  76.  
  77. #ifdef USESHMEM
  78. #include <sys/ipc.h>
  79. #include <sys/shm.h>
  80.  
  81. #define    NUMSHKEYS    20
  82. #define    SHMEMSIZE    262144    /* 2^18 (dev3b1) */
  83. #endif
  84.  
  85. /* done writing to the archive */
  86. #define    FALSE    0
  87. #define    TRUE    1
  88. #define    NOTDONE    0
  89. #define    DONE    1
  90. #define    NODIE    0
  91. #define    DIE    1
  92.  
  93. /*
  94.  * Address link information base.
  95.  */
  96. #define    linkhash(ino)    \
  97.     (linkbase + (ino) % nel(linkbase))
  98.  
  99. /*
  100.  * Mininum value.
  101.  */
  102. #define    min(one, two)    \
  103.     (one < two ? one : two)
  104.  
  105. /*
  106.  * Number of array elements.
  107.  */
  108. #define    nel(a)        \
  109.     (sizeof(a) / sizeof(*(a)))
  110.  
  111. /*
  112.  * Remove a file or directory.
  113.  */
  114. #define    afremove(name, asb) \
  115.     (((asb)->sb_mode & S_IFMT) == S_IFDIR ? rmdir(name) : unlink(name))
  116.  
  117. /*
  118.  * Swap bytes.
  119.  */
  120. #define    swab(n)        \
  121.     ((((ushort)(n) >> 8) & 0xff) | (((ushort)(n) << 8) & 0xff00))
  122.  
  123. /*
  124.  * Cast and reduce to unsigned short.
  125.  */
  126. #define    ush(n)        \
  127.     (((ushort) (n)) & 0177777)
  128.  
  129. /*
  130.  * Definitions.
  131.  */
  132. #define    reg    register    /* Convenience */
  133. #define    uint    unsigned int    /* Not always in types.h */
  134. #define    ushort    unsigned short    /* Not always in types.h */
  135. #define    BLOCK    5120        /* Default archive block size */
  136. #define    FSBUF    (8*1024)    /* Filesystem buffer size */
  137. #define    H_COUNT    10        /* Number of items in ASCII header */
  138. #define    H_PRINT    "%06o%06o%06o%06o%06o%06o%06o%011lo%06o%011lo"
  139. #define    H_SCAN    "%6ho%6ho%6ho%6ho%6ho%6ho%6ho%11lo%6o%11lo"
  140. #define    H_STRLEN 70        /* ASCII header string length */
  141. #define    M_ASCII "070707"    /* ASCII magic number */
  142. #define    M_BINARY 070707        /* Binary magic number */
  143. #define    M_STRLEN 6        /* ASCII magic number length */
  144. #define    NULLDEV    -1        /* Null device code */
  145. #define    NULLINO    0        /* Null inode number */
  146. #define    PATHELEM 256        /* Pathname element count limit */
  147. #define    PATHSIZE 1024        /* Pathname length limit */
  148. #define    S_IFSHF    12        /* File type shift (shb in stat.h) */
  149. #define    S_IPERM    07777        /* File permission bits (shb in stat.h) */
  150. #define    S_IPEXE    07000        /* Special execution bits (shb in stat.h) */
  151. #define    S_IPOPN    0777        /* Open access bits (shb in stat.h) */
  152. #define    STDIN    0        /* Standard input file descriptor */
  153. #define    STDOUT    1        /* Standard output file descriptor */
  154. #define    TTY    "/dev/tty"    /* For volume-change queries */
  155.  
  156. /*
  157.  * Some versions of the portable "C" compiler (PCC) can't handle
  158.  * pointers to functions returning void.
  159.  */
  160. #ifdef    VOIDFIX
  161. #    define    VOIDFN    void    /* Expect "void (*fnptr)()" to work */
  162. #else    /* VOIDFIX */
  163. #    define    VOIDFN    int    /* Avoid PCC "void (*fnptr)()" bug */
  164. #endif    /* VOIDFIX */
  165.  
  166. /*
  167.  * Trailer pathnames. All must be of the same length.
  168.  */
  169. #define    TRAILER    "TRAILER!!!"    /* Archive trailer (cpio compatible) */
  170. #define    TRAILZ    11        /* Trailer pathname length (including null) */
  171.  
  172. /*
  173.  * Open modes; there is no <fcntl.h> with v7 UNIX.
  174.  */
  175. #ifdef HAVEFCNTL
  176. #include <fcntl.h>
  177. #else
  178. #define    O_RDONLY 0        /* Read-only */
  179. #define    O_WRONLY 1        /* Write-only */
  180. #define    O_RDWR    2        /* Read/write */
  181. #endif
  182. /*
  183.  * V7 and BSD UNIX use old-fashioned names for a couple of
  184.  * string functions.
  185.  */
  186. #ifdef    INDEX
  187. #    define    strchr    index    /* Forward character search */
  188. #    define    strrchr    rindex    /* Reverse character search */
  189. #endif    /* INDEX */
  190.  
  191. /*
  192.  * Some compilers can't handle void casts.
  193.  */
  194. #ifdef    NOVOID
  195. #    define    VOID        /* Omit void casts */
  196. #else    /* NOVOID */
  197. #    define    VOID    (void)    /* Quiet lint about ignored return values */
  198. #endif    /* NOVOID */
  199.  
  200. /*
  201.  * Adb is more palatable when static functions and variables are
  202.  * declared as globals. Lint gives more useful information when
  203.  * statics are truly static.
  204.  */
  205. #ifdef    lint
  206. #    define    STATIC    static    /* Declare static variables for lint */
  207. #else    /* lint */
  208. #    define    STATIC        /* Make static variables global for adb */
  209. #endif    /* lint */
  210.  
  211. /*
  212.  * Simple types.
  213.  */
  214. typedef struct group    Group;    /* Structure for getgrgid(3) */
  215. typedef struct passwd    Passwd;    /* Structure for getpwuid(3) */
  216. typedef struct tm    Time;    /* Structure for localtime(3) */
  217.  
  218. #ifdef    S_IFLNK
  219.     /*
  220.      * File status with symbolic links. Kludged to hold symbolic
  221.      * link pathname within structure.
  222.      */
  223.     typedef struct {
  224.         struct stat    sb_stat;
  225.         char        sb_link[PATHSIZE];
  226.     } Stat;
  227. #    define    STAT(name, asb)        stat(name, &(asb)->sb_stat)
  228. #    define    FSTAT(fd, asb)        fstat(fd, &(asb)->sb_stat)
  229. #    define    LSTAT(name, asb)    lstat(name, &(asb)->sb_stat)
  230. #    define    sb_dev        sb_stat.st_dev
  231. #    define    sb_ino        sb_stat.st_ino
  232. #    define    sb_mode        sb_stat.st_mode
  233. #    define    sb_nlink    sb_stat.st_nlink
  234. #    define    sb_uid        sb_stat.st_uid
  235. #    define    sb_gid        sb_stat.st_gid
  236. #    define    sb_rdev        sb_stat.st_rdev
  237. #    define    sb_size        sb_stat.st_size
  238. #    define    sb_atime    sb_stat.st_atime
  239. #    define    sb_mtime    sb_stat.st_mtime
  240. #    define    sb_ctime    sb_stat.st_ctime
  241. #    define    sb_blksize    sb_stat.st_blksize
  242. #    define    sb_blocks    sb_stat.st_blocks
  243. #else    /* S_IFLNK */
  244.     /*
  245.      * File status without symbolic links.
  246.      */
  247.     typedef    struct stat    Stat;
  248. #    define    STAT(name, asb)        stat(name, asb)
  249. #    define    FSTAT(fd, asb)        fstat(fd, asb)
  250. #    define    LSTAT(name, asb)    stat(name, asb)
  251. #    define    sb_dev        st_dev
  252. #    define    sb_ino        st_ino
  253. #    define    sb_mode        st_mode
  254. #    define    sb_nlink    st_nlink
  255. #    define    sb_uid        st_uid
  256. #    define    sb_gid        st_gid
  257. #    define    sb_rdev        st_rdev
  258. #    define    sb_size        st_size
  259. #    define    sb_atime    st_atime
  260. #    define    sb_mtime    st_mtime
  261. #    define    sb_ctime    st_ctime
  262. #endif    /* S_IFLNK */
  263.  
  264. /*
  265.  * Binary archive header (obsolete).
  266.  */
  267. typedef struct {
  268.     short    b_dev;            /* Device code */
  269.     ushort    b_ino;            /* Inode number */
  270.     ushort    b_mode;            /* Type and permissions */
  271.     ushort    b_uid;            /* Owner */
  272.     ushort    b_gid;            /* Group */
  273.     short    b_nlink;        /* Number of links */
  274.     short    b_rdev;            /* Real device */
  275.     ushort    b_mtime[2];        /* Modification time (hi/lo) */
  276.     ushort    b_name;            /* Length of pathname (with null) */
  277.     ushort    b_size[2];        /* Length of data */
  278. } Binary;
  279.  
  280. /*
  281.  * Child process structure.
  282.  */
  283. typedef struct child {
  284.     struct child    *c_forw;    /* Forward link */
  285.     int        c_pid;        /* Process ID */
  286.     int        c_flags;    /* Flags (CF_) */
  287.     int        c_status;    /* Exit status */
  288. } Child;
  289.  
  290. /*
  291.  * Child process flags (c_flags).
  292.  */
  293. #define    CF_EXIT    (1<<0)            /* Exited */
  294.  
  295. /*
  296.  * Hard link sources. One or more are chained from each link
  297.  * structure.
  298.  */
  299. typedef struct name {
  300.     struct name    *p_forw;    /* Forward chain (terminated) */
  301.     struct name    *p_back;    /* Backward chain (circular) */
  302.     char        *p_name;    /* Pathname to link from */
  303. } Path;
  304.  
  305. /*
  306.  * File linking information. One entry exists for each unique
  307.  * file with with outstanding hard links.
  308.  */
  309. typedef struct link {
  310.     struct link    *l_forw;    /* Forward chain (terminated) */
  311.     struct link    *l_back;    /* Backward chain (terminated) */
  312.     dev_t        l_dev;        /* Device */
  313.     ino_t        l_ino;        /* Inode */
  314.     ushort        l_nlink;    /* Unresolved link count */
  315.     off_t        l_size;        /* Length */
  316.     Path        *l_path;    /* Pathname(s) to link from */
  317. } Link;
  318.  
  319. /*
  320.  * Pathnames to (or to not) be processed.
  321.  */
  322. typedef struct pattern {
  323.     struct pattern    *p_forw;    /* Forward chain */
  324.     char        *p_str;        /* String */
  325.     int        p_len;        /* Length of string */
  326.     int        p_not;        /* Reverse logic */
  327. } Pattern;
  328.  
  329. /*
  330.  * External functions.
  331.  */
  332. void    _exit();
  333. void    exit();
  334. void    free();
  335. char    *getenv();
  336. ushort    getgid();
  337. Group    *getgrgid();
  338. Passwd    *getpwuid();
  339. ushort    getuid();
  340. Time    *localtime();
  341. off_t    lseek();
  342. char    *malloc();
  343. uint    sleep();
  344. char    *strcat();
  345. char    *strchr();
  346. char    *strcpy();
  347. char    *strncpy();
  348. char    *strrchr();
  349. time_t    time();
  350.  
  351.  
  352. /*
  353.  * Internal functions.
  354.  */
  355. VOIDFN    copyin();
  356. VOIDFN    copyout();
  357. void    compressfile();
  358. int    dirchg();
  359. int    dirmake();
  360. int    dirneed();
  361. void    fatal();
  362. void    goodbye();
  363. VOIDFN    in();
  364. void    inalloc();
  365. int    inascii();
  366. int    inavail();
  367. int    inbinary();
  368. int    indata();
  369. int    inentry();
  370. int    infill();
  371. int    inhead();
  372. int    inread();
  373. int    inskip();
  374. int    inswab();
  375. int    lineget();
  376. void    linkalso();
  377. Link    *linkfrom();
  378. void    linkleft();
  379. Link    *linkto();
  380. char    *memcpy();
  381. char    *memget();
  382. char    *memstr();
  383. int    mkdir();
  384. void    nameadd();
  385. int    namecmp();
  386. int    nameopt();
  387. void    next();
  388. void    nextask();
  389. void    nextclos();
  390. int    nextopen();
  391. int    openin();
  392. int    openotty();
  393. int    openqtty();
  394. int    options();
  395. off_t    optsize();
  396. VOIDFN    out();
  397. void    outalloc();
  398. uint    outavail();
  399. int    outdata();
  400. void    outeof();
  401. void    outflush();
  402. void    outhead();
  403. void    outpad();
  404. void    outwait();
  405. void    outwrite();
  406. VOIDFN    pass();
  407. void    passdata();
  408. int    passitem();
  409. int    pipechld();
  410. int    pipeopen();
  411. void    pipewait();
  412. void    prsize();
  413. int    rmdir();
  414. VOIDFN    (*signal())();
  415. int    fswrite();
  416. #ifdef USESHMEM
  417. char    *shmemalloc();
  418. void    shmemfree();
  419. #endif
  420. char    *syserr();
  421. #ifdef MYTEMPNAM
  422. char    *tempnam();
  423. else
  424. extern    char *tempnam();
  425. #endif
  426. VOIDFN    toc();
  427. void    tocentry();
  428. void    tocmode();
  429. void    usage();
  430. void    verify();
  431. int    warn();
  432. int    warnarch();
  433. int    writedisk();
  434. int    xfork();
  435. void    xpause();
  436. int    xwait();
  437.  
  438. extern    int    atoi();
  439. extern    int    chdir();
  440. extern    int    chmod();
  441. extern    int    chown();
  442. extern    int    dup();
  443. extern    int    fork();
  444. extern    int    isatty();
  445. extern    int    link();
  446. extern    int    memcmp();
  447. extern    int    mknod();
  448. extern    int    pipe();
  449. extern    int    read();
  450. extern    int    stat();
  451. extern    int    strcmp();
  452. extern    int    strlen();
  453. extern    int    strncmp();
  454. extern    int    umask();
  455. extern    int    unlink();
  456. extern    int    utime();
  457. extern    int    wait();
  458. extern    int    write();
  459.  
  460. /*
  461.  * External variables.
  462.  */
  463. extern int    errno;        /* System error code */
  464. extern char    *sys_errlist[];    /* System error messages */
  465. extern int    sys_nerr;    /* Number of sys_errlist entries */
  466.  
  467. /*
  468.  * Static variables.
  469.  */
  470. STATIC short    Fflag;        /*
  471.                  * floppy flag (write when buf full)
  472.                  * set -sdisk_size as well
  473.                  */
  474. STATIC short    Zflag;        /* compress the files that we can */
  475. STATIC short    verifyflag;    /* Verify (floppy) flag */
  476. STATIC short    verifycnt;
  477. #ifdef    CTC3B2
  478. STATIC short    Cflag;        /* Enable 3B2 CTC streaming (kludge) */
  479. #endif    /* CTC3B2 */
  480. STATIC short    dflag;        /* Don't create missing directories */
  481. STATIC short    fflag;        /* Fork before writing to archive */
  482. STATIC short    gflag;        /* Change to input file directories */
  483. STATIC short    hflag;        /* Follow symbolic links */
  484. STATIC short    jflag;        /* Don't generate sparse filesystem blocks */
  485. STATIC short    kflag;        /* Skip initial junk to find a header */
  486. STATIC short    lflag;        /* Link rather than copying (when possible) */
  487. STATIC short    mflag;        /* Ignore archived timestamps */
  488. STATIC short    nflag;        /* Keep newer existing files */
  489. STATIC short    uflag;        /* Report files with unseen links */
  490. STATIC short    vflag;        /* Verbose */
  491. STATIC short    xflag;        /* Retain file ownership */
  492. STATIC short    zflag;        /* Print final statistics */
  493. STATIC short    hidequit;    /* show the quit option? */
  494. STATIC short    abspaths;    /* allow absolute path names? */
  495. STATIC uint    arbsize = BLOCK;/* Archive block size */
  496. STATIC short    areof;        /* End of input volume reached */
  497. STATIC int    arfd = -1;    /* Archive file descriptor */
  498. STATIC off_t    arleft;        /* Space remaining within current volume */
  499. STATIC char    *arname;    /* Expanded archive name */
  500. STATIC uint    arpad;        /* Final archive block padding boundary */
  501. STATIC char    arspec[PATHSIZE];/* Specified archive name */
  502. STATIC off_t    aruntil;    /* Volume size limit */
  503. STATIC uint    arvolume = 1;    /* Volume number */
  504. STATIC uint    buflen;        /* Archive buffer length */
  505. STATIC char    *buffer;    /* Archive buffer */
  506. STATIC char    *bufidx;    /* Archive buffer index */
  507. STATIC char    *bufend;    /* End of data within archive buffer */
  508. STATIC Child    *children;    /* Child processes */
  509. STATIC char    *formatcmd = DEFFMTCMD; /* how to format */
  510. STATIC ushort    gid;        /* Group ID */
  511. STATIC Link    *linkbase[256];    /* Unresolved link information */
  512. STATIC FILE    *logfile = NULL;/* log same errors as stderr would */
  513. STATIC ushort    mask;        /* File creation mask */
  514. STATIC char    *myname;    /* Arg0 */
  515. extern char    *optarg;    /* Option argument */
  516. extern int    optind;        /* Command line index */
  517. STATIC int    outpid;        /* Process ID of outstanding outflush() */
  518. STATIC Pattern    *pattern;    /* Pathname matching patterns */
  519. STATIC char    pwd[PATHSIZE];    /* Working directory (with "-g") */
  520. STATIC int    pipepid;    /* Pipeline process ID */
  521. STATIC time_t    timenow;    /* Current time */
  522. STATIC time_t    timewait;    /* Time spent awaiting new media */
  523. STATIC off_t    total;        /* Total number of bytes transferred */
  524. STATIC int    ttyf;        /* For interactive queries (yuk) */
  525. STATIC ushort    uid;        /* User ID */
  526. int    uncompressrun    = 0;    /* is uncompress running? its pid if so */
  527. char    uncompto[PATHSIZE];    /* name we uncompressed to */
  528.  
  529. main(ac, av)
  530. int        ac;
  531. reg char    **av;
  532. {
  533.     reg int        c;
  534.     reg uint    group = 1;
  535.     VOIDFN    (*fn)() = NULL;
  536.     time_t    timedone;
  537.     auto char    remote[PATHSIZE];
  538.  
  539.     if (myname = strrchr(*av, '/'))
  540.         ++myname;
  541.     else
  542.         myname = *av;
  543.     mask = umask(0);
  544.     uid = getuid();
  545.     gid = getgid();
  546.     if (uid == 0)
  547.         ++xflag;
  548.     VOID signal(SIGPIPE, SIG_IGN);
  549.     while (c = options(ac, av, "ioptIOVCb:c:de:fghjklmns:uvxXy:Y:zFKZL:R:qA")) {
  550.         switch (c) {
  551.         case 'i':
  552.             if (fn)
  553.                 usage();
  554.             fn = in;
  555.             break;
  556.         case 'o':
  557.             if (fn)
  558.                 usage();
  559.             fn = out;
  560.             break;
  561.         case 'p':
  562.             if (fn)
  563.                 usage();
  564.             fn = pass;
  565.             break;
  566.         case 't':
  567.             if (fn)
  568.                 usage();
  569.             fn = toc;
  570.             break;
  571.         case 'I':
  572.             if (fn)
  573.                 usage();
  574.             fn = copyin;
  575.             break;
  576.         case 'O':
  577.             if (fn)
  578.                 usage();
  579.             fn = copyout;
  580.             break;
  581.         case 'V':
  582.             VOID printf("%s: Version %s dated %s\n",
  583.                     myname, VERSION, DATE);
  584.             exit(0);
  585. #ifdef    CTC3B2
  586.         case 'C':
  587.             ++Cflag;
  588.             arbsize = 31 * 512;
  589.             group = 10;
  590.             aruntil = 1469 * 31 * 512;
  591.             break;
  592. #endif    /* CTC3B2 */
  593.         case 'b':
  594.             if ((arbsize = (uint) optsize(optarg)) == 0)
  595.                 fatal(optarg, "Bad block size");
  596.             break;
  597.         case 'c':
  598.             if ((group = (uint) optsize(optarg)) == 0)
  599.                 fatal(optarg, "Bad buffer count");
  600.             break;
  601.         case 'd':
  602.             ++dflag;
  603.             break;
  604.         case 'e':
  605.             arpad = (uint) optsize(optarg);
  606.             break;
  607.         case 'f':
  608.             ++fflag;
  609.             break;
  610.         case 'g':
  611.             ++gflag;
  612.             break;
  613.         case 'h':
  614.             ++hflag;
  615.             break;
  616.         case 'j':
  617.             ++jflag;
  618.             break;
  619.         case 'k':
  620.             ++kflag;
  621.             break;
  622.         case 'l':
  623.             ++lflag;
  624.             break;
  625.         case 'm':
  626.             ++mflag;
  627.             break;
  628.         case 'n':
  629.             ++nflag;
  630.             break;
  631.         case 's':
  632.             aruntil = optsize(optarg);
  633.             if (aruntil == 0)
  634.                 usage();
  635.             break;
  636.         case 'F':
  637.             ++Fflag;
  638.             break;
  639.         case 'Z':
  640.             ++Zflag;
  641.             break;
  642.         case 'K':
  643.             ++verifyflag;
  644.             break;
  645.         case 'u':
  646.             ++uflag;
  647.             break;
  648.         case 'v':
  649.             ++vflag;
  650.             break;
  651.         case 'x':
  652.             ++xflag;
  653.             break;
  654.         case 'X':
  655.             xflag = 0;
  656.             break;
  657.         case 'y':
  658.             nameadd(optarg, 0);
  659.             break;
  660.         case 'Y':
  661.             nameadd(optarg, 1);
  662.             break;
  663.         case 'z':
  664.             ++zflag;
  665.             break;
  666.         case 'L':
  667.             if ((logfile = fopen(optarg, "a")) == (FILE *)0)
  668.             {    fprintf(stderr,
  669.                     "Can't open %s to append, get help\n",
  670.                     optarg);
  671.                 exit(1);
  672.             }
  673.             break;
  674.         case 'R':
  675.             formatcmd = optarg;
  676.             break;
  677.         case 'q':
  678.             hidequit = TRUE;
  679.             break;
  680.         case 'A':
  681.             abspaths = TRUE;
  682.             break;
  683.         default:
  684.             usage();
  685.         }
  686.     }
  687.     if (fn == NULL || av[optind] == NULL)
  688.         usage();
  689.     ttyf = openqtty();
  690.     if (Fflag)
  691.     {    if ((buflen = aruntil) == 0)
  692.             usage();
  693.     }
  694.     else
  695.         buflen = arbsize * group;
  696.     if (aruntil && (aruntil < arbsize))
  697.     {    fprintf(stderr, "Media size %d is less than buffer size %d\n",
  698.                 aruntil, arbsize);
  699.         usage();
  700.     }
  701.     if (arpad == 0)
  702.         arpad = arbsize;
  703.     if (fn != pass) {
  704.         reg char    *colon;
  705.         reg char    *equal;
  706.         reg int        isoutput = (fn == out || fn == copyout);
  707.  
  708.         arname = strcpy(arspec, av[optind++]);
  709.         if (colon = strchr(arspec, ':')) {
  710.             *colon++ = '\0';
  711.             if (equal = strchr(arspec, '='))
  712.                 *equal++ = '\0';
  713.             VOID sprintf(arname = remote,
  714.                 "!rsh %s %s -%c -b %u -c %u %s",
  715.                 arspec, equal ? equal : myname,
  716.                 isoutput ? 'O' : 'I', arbsize,
  717.                 group, colon);
  718.             if (equal)
  719.                 *--equal = '=';
  720.             *--colon = ':';
  721.         }
  722.         if (gflag && *arname != '/' && *arname != '!')
  723.             fatal(arspec, "Relative pathname");
  724.         VOID signal(SIGINT, goodbye);
  725. #ifdef USESHMEM
  726.         /* alloc the space as shared if we will be forking a lot */
  727.         if ((*arspec != '!') && (Fflag || fflag)
  728. #if ((defined (USESHMEM)) && (defined (UNIXPC)))
  729.             /*
  730.              * UNIXPC and shared memory read/write bug
  731.              * -only a write() is handled correctly below
  732.              * in writedisk()
  733.              */
  734.             && ((fn == out) || (fn == copyout)))
  735. #else
  736.             )
  737. #endif
  738.         {
  739.             if ((buffer = bufidx = bufend = shmemalloc(buflen+BLOCK, arname)) == NULL)
  740.                 fatal(arspec, "Cannot allocate I/O buffer (shmem)");
  741.         }
  742.         else
  743. #endif
  744.         /*
  745.          * +BLOCK is added to make sure we don't overrun buffer on a
  746.          * read (internal read(1) length is thus met)
  747.          */
  748.         if ((buffer = bufidx = bufend = malloc(buflen+BLOCK)) == NULL)
  749.             fatal(arspec, "Cannot allocate I/O buffer");
  750.  
  751.         /*
  752.          * open a floppy at the last moment (if output), otherwise now
  753.          * note we set arleft prematurely so we don't have to open the
  754.          * disk now
  755.          */
  756.         if (!Fflag || !isoutput)
  757.         {    if (nextopen(isoutput ? O_WRONLY : O_RDONLY) < 0)
  758.                 goodbye(1);
  759.         }
  760.         else
  761.             arleft = aruntil;
  762.     }
  763.     timenow = time((time_t *) NULL);
  764.     (*fn)(av + optind);
  765.     timedone = time((time_t *) NULL);
  766.     if (uflag)
  767.         linkleft();
  768.     if (zflag) {
  769.         reg FILE    *stream;
  770.  
  771.         stream = fn == toc || arfd == STDOUT ? stderr : stdout;
  772.         VOID fprintf(stream, "%s: ", myname);
  773.         prsize(stream, total);
  774.         VOID fprintf(stream, " bytes %s in %lu seconds. The backup was successfull!\n",
  775.           fn == pass
  776.             ? "transferred"
  777.             : fn == out || fn == copyout
  778.               ? "written"
  779.               : "read",
  780.           timedone - timenow - timewait);
  781.     }
  782.     if (logfile != (FILE *)0)
  783.     {    VOID fprintf(logfile, "%s: Successfully backed up ", myname);
  784.         prsize(logfile, total);
  785.         VOID fprintf(logfile,
  786.     " bytes %s in %lu seconds (+waited %d seconds for disk swapping (%u disks)) finished at %s",
  787.             fn == pass
  788.             ? "transferred"
  789.             : fn == out || fn == copyout
  790.             ? "written"
  791.             : "read",
  792.             timedone - timenow - timewait,
  793.             timewait,
  794.             arvolume,
  795.             ctime(&timedone));
  796.     }
  797.     nextclos();
  798.     goodbye(0);
  799.     /* NOTREACHED */
  800. }
  801.  
  802. /*
  803.  * copyin()
  804.  *
  805.  * Copy directly from the archive to the standard output.
  806.  */
  807. STATIC VOIDFN
  808. copyin(av)
  809. reg char    **av;
  810. {
  811.     reg int        got;
  812.     reg uint    have;
  813.  
  814.     if (*av)
  815.         fatal(*av, "Extraneous argument");
  816.     while (!areof) {
  817.         VOID infill();
  818.         while (have = bufend - bufidx)
  819.             if ((got = write(STDOUT, bufidx, have)) < 0)
  820.                 fatal("<stdout>", syserr());
  821.             else if (got > 0)
  822.                 bufidx += got;
  823.             else
  824.                 return;
  825.     }
  826. }
  827.  
  828. /*
  829.  * copyout()
  830.  *
  831.  * Copy directly from the standard input to the archive.
  832.  */
  833. STATIC VOIDFN
  834. copyout(av)
  835. reg char    **av;
  836. {
  837.     reg int        got;
  838.     reg uint    want;
  839.  
  840.     if (*av)
  841.         fatal(*av, "Extraneous argument");
  842.     for (;;) {
  843.         while ((want = bufend - bufidx) == 0)
  844.             outflush(NOTDONE);
  845.         if ((got = read(STDIN, bufidx, want)) < 0)
  846.             fatal("<stdin>", syserr());
  847.         else if (got == 0)
  848.             break;
  849.         else
  850.             bufidx += got;
  851.     }
  852.     outflush(DONE);
  853.     if (fflag)
  854.         outwait();
  855. }
  856.  
  857. /*
  858.  * dirchg()
  859.  *
  860.  * Change to the directory containing a given file.
  861.  */
  862. STATIC int
  863. dirchg(name, local)
  864. reg char    *name;
  865. reg char    *local;
  866. {
  867.     reg char    *last;
  868.     reg int        len;
  869.     auto char    dir[PATHSIZE];
  870.  
  871.     if (*name != '/')
  872.         return (warn(name, "Relative pathname"));
  873.     for (last = name + strlen(name); last[-1] != '/'; --last)
  874.         ;
  875.     len = last - name;
  876.     strncpy(dir, name, len)[len] = '\0';
  877.     VOID strcpy(local, *last ? last : ".");
  878.     if (strcmp(dir, pwd) == 0)
  879.         return (0);
  880.     if (chdir(dir) < 0)
  881.         return (warn(name, syserr()));
  882.     VOID strcpy(pwd, dir);
  883.     return (0);
  884. }
  885.  
  886. /*
  887.  * dirmake()
  888.  *
  889.  * Make a directory. Returns zero if successful, -1 otherwise.
  890.  */
  891. STATIC int
  892. dirmake(name, asb)
  893. reg char    *name;
  894. reg Stat    *asb;
  895. {
  896.     if (mkdir(name, asb->sb_mode & S_IPOPN) < 0)
  897.         return (-1);
  898.     if (asb->sb_mode & S_IPEXE)
  899.         VOID chmod(name, asb->sb_mode & S_IPERM);
  900.     if (xflag)
  901.         VOID chown(name,
  902.             uid == 0 ? ush(asb->sb_uid) : uid,
  903.             ush(asb->sb_gid));
  904.     return (0);
  905. }
  906.  
  907. /*
  908.  * dirneed()
  909.  *
  910.  * Recursively create missing directories (with the same permissions
  911.  * as their first existing parent). Temporarily modifies the 'name'
  912.  * argument string. Returns zero if successful, -1 otherwise.
  913.  */
  914. STATIC int
  915. dirneed(name)
  916. char        *name;
  917. {
  918.     reg char    *cp;
  919.     reg char    *last;
  920.     reg int        ok;
  921.     static Stat    sb;
  922.  
  923.     last = NULL;
  924.     for (cp = name; *cp; )
  925.         if (*cp++ == '/')
  926.             last = cp;
  927.     if (last == NULL)
  928.         return (STAT(".", &sb));
  929.     *--last = '\0';
  930.     ok = STAT(*name ? name : "/", &sb) == 0
  931.         ? ((sb.sb_mode & S_IFMT) == S_IFDIR)
  932.         : (!dflag && dirneed(name) == 0 && dirmake(name, &sb) == 0);
  933.     *last = '/';
  934.     return (ok ? 0 : -1);
  935. }
  936.  
  937. /*
  938.  * fatal()
  939.  *
  940.  * Print fatal message and exit.
  941.  */
  942. STATIC void
  943. fatal(what, why)
  944. char        *what;
  945. char        *why;
  946. {
  947.     VOID warn(what, why);
  948.     goodbye(1);
  949. }
  950.  
  951. /*
  952.  * in()
  953.  *
  954.  * Read an archive.
  955.  */
  956. STATIC VOIDFN
  957. in(av)
  958. reg char    **av;
  959. {
  960.     auto Stat    sb;
  961.     auto char    name[PATHSIZE];
  962.     int    sel;
  963.  
  964.     if (*av)
  965.         fatal(*av, "Extraneous argument");
  966.     name[0] = '\0';
  967.     while (inhead(name, &sb) == 0) {
  968.         if (((sel = namecmp(name)) < 0) || inentry(name, &sb) < 0)
  969.             if (inskip(sb.sb_size) < 0)
  970.                 VOID warn(name, "Skipped file data is corrupt");
  971.         if (vflag && (sel == 0))
  972.         {    if (*uncompto)
  973.                 VOID fprintf(stderr, "%s uncompressed to: %s\n",
  974.                          name, uncompto);
  975.             else
  976.                 VOID fprintf(stderr, "%s\n", name);
  977.         }
  978.     }
  979. }
  980.  
  981. /*
  982.  * inalloc()
  983.  *
  984.  * Allocate input buffer space (which was previously indexed
  985.  * by inavail()).
  986.  */
  987. STATIC void
  988. inalloc(len)
  989. reg uint    len;
  990. {
  991.     bufidx += len;
  992.     total += len;
  993. }
  994.  
  995. /*
  996.  * inascii()
  997.  *
  998.  * Read an ASCII header. Returns zero if successful;
  999.  * -1 otherwise. Assumes that the entire magic number
  1000.  * has been read.
  1001.  */
  1002. STATIC int
  1003. inascii(magic, name, asb)
  1004. reg char    *magic;
  1005. reg char    *name;
  1006. reg Stat    *asb;
  1007. {
  1008.     auto uint    namelen;
  1009.     auto char    header[H_STRLEN + 1];
  1010.  
  1011.     if (strncmp(magic, M_ASCII, M_STRLEN) != 0)
  1012.         return (-1);
  1013.     if (inread(header, H_STRLEN) < 0)
  1014.         return (warnarch("Corrupt ASCII header", (off_t) H_STRLEN));
  1015.     header[H_STRLEN] = '\0';
  1016.     if (sscanf(header, H_SCAN, &asb->sb_dev,
  1017.         &asb->sb_ino, &asb->sb_mode, &asb->sb_uid,
  1018.         &asb->sb_gid, &asb->sb_nlink, &asb->sb_rdev,
  1019.         &asb->sb_mtime, &namelen, &asb->sb_size) != H_COUNT)
  1020.         return (warnarch("Bad ASCII header", (off_t) H_STRLEN));
  1021.     if (namelen == 0 || namelen >= PATHSIZE)
  1022.         return (warnarch("Bad ASCII pathname length", (off_t) H_STRLEN));
  1023.     if (inread(name, namelen) < 0)
  1024.         return (warnarch("Corrupt ASCII pathname", (off_t) namelen));
  1025.     if (name[namelen - 1] != '\0')
  1026.         return (warnarch("Bad ASCII pathname", (off_t) namelen));
  1027.     return (0);
  1028. }
  1029.  
  1030. /*
  1031.  * inavail()
  1032.  *
  1033.  * Index availible input data within the buffer. Stores a pointer
  1034.  * to the data and its length in given locations. Returns zero with
  1035.  * valid data, -1 if unreadable portions were replaced with nulls.
  1036.  */
  1037. STATIC int
  1038. inavail(bufp, lenp)
  1039. reg char    **bufp;
  1040. uint        *lenp;
  1041. {
  1042.     reg uint    have;
  1043.     reg int        corrupt = 0;
  1044.  
  1045.     while ((have = bufend - bufidx) == 0)
  1046.         corrupt |= infill();
  1047.     *bufp = bufidx;
  1048.     *lenp = have;
  1049.     return (corrupt);
  1050. }
  1051.  
  1052. /*
  1053.  * inbinary()
  1054.  *
  1055.  * Read a binary header. Returns the number of trailing alignment
  1056.  * bytes to skip; -1 if unsuccessful.
  1057.  */
  1058. STATIC int
  1059. inbinary(magic, name, asb)
  1060. reg char    *magic;
  1061. reg char    *name;
  1062. reg Stat    *asb;
  1063. {
  1064.     reg uint    namefull;
  1065.     auto Binary    binary;
  1066.  
  1067.     if ((int)*((ushort *) magic) != M_BINARY)
  1068.         return (-1);
  1069.     memcpy((char *) &binary,
  1070.         magic + sizeof(ushort),
  1071.         M_STRLEN - sizeof(ushort));
  1072.     if (inread((char *) &binary + M_STRLEN - sizeof(ushort),
  1073.         sizeof(binary) - (M_STRLEN - sizeof(ushort))) < 0)
  1074.         return (warnarch("Corrupt binary header",
  1075.             (off_t) sizeof(binary) - (M_STRLEN - sizeof(ushort))));
  1076.     asb->sb_dev = binary.b_dev;
  1077.     asb->sb_ino = binary.b_ino;
  1078.     asb->sb_mode = binary.b_mode;
  1079.     asb->sb_uid = binary.b_uid;
  1080.     asb->sb_gid = binary.b_gid;
  1081.     asb->sb_nlink = binary.b_nlink;
  1082.     asb->sb_rdev = binary.b_rdev;
  1083.     asb->sb_mtime = binary.b_mtime[0] << 16 | binary.b_mtime[1];
  1084.     asb->sb_size = binary.b_size[0] << 16 | binary.b_size[1];
  1085.     if (binary.b_name == 0 || binary.b_name >= PATHSIZE)
  1086.         return (warnarch("Bad binary pathname length",
  1087.             (off_t) sizeof(binary) - (M_STRLEN - sizeof(ushort))));
  1088.     if (inread(name, namefull = binary.b_name + binary.b_name % 2) < 0)
  1089.         return (warnarch("Corrupt binary pathname", (off_t) namefull));
  1090.     if (name[binary.b_name - 1] != '\0')
  1091.         return (warnarch("Bad binary pathname", (off_t) namefull));
  1092.     return (asb->sb_size % 2);
  1093. }
  1094.  
  1095. /*
  1096.  * indata()
  1097.  *
  1098.  * Install data from an archive. Returns given file descriptor.
  1099.  */
  1100. STATIC int
  1101. indata(fd, size, name)
  1102. int        fd;
  1103. reg off_t    size;
  1104. char        *name;
  1105. {
  1106.     reg uint    chunk;
  1107.     reg char    *oops;
  1108.     reg int        sparse;
  1109.     reg int        corrupt;
  1110.     auto char    *buf;
  1111.     auto uint    avail;
  1112.  
  1113.     corrupt = sparse = 0;
  1114.     oops = NULL;
  1115.     while (size) {
  1116.         corrupt |= inavail(&buf, &avail);
  1117.         size -= (chunk = size < avail ? (uint) size : avail);
  1118.         if (oops == NULL && (sparse = fswrite(fd, buf, chunk)) < 0)
  1119.             oops = syserr();
  1120.         inalloc(chunk);
  1121.     }
  1122.     if (corrupt)
  1123.         VOID warn(name, "Corrupt archive data");
  1124.     if (oops)
  1125.         VOID warn(name, oops);
  1126.     else if (sparse > 0
  1127.       && (lseek(fd, (off_t) -1, 1) < 0
  1128.         || write(fd, "", 1) != 1))
  1129.         VOID warn(name, syserr());
  1130.     return (fd);
  1131. }
  1132.  
  1133. /*
  1134.  * inentry()
  1135.  *
  1136.  * Install a single archive entry. Returns zero if successful, -1 otherwise.
  1137.  */
  1138. STATIC int
  1139. inentry(name, asb)
  1140. char        *name;
  1141. reg Stat    *asb;
  1142. {
  1143.     reg Link    *linkp;
  1144.     reg int        ifd;
  1145.     reg int        ofd;
  1146.     auto time_t    tstamp[2];
  1147.  
  1148.     if ((ofd = openotty(name, asb, linkp = linkfrom(asb), 0, Zflag)) > 0)
  1149.     {    if (asb->sb_size || linkp == NULL || linkp->l_size == 0)
  1150.             VOID close(indata(ofd, asb->sb_size, name));
  1151.         else if ((ifd = open(linkp->l_path->p_name, O_RDONLY)) < 0)
  1152.             VOID warn(linkp->l_path->p_name, syserr());
  1153.         else {
  1154.             passdata(linkp->l_path->p_name, ifd, name, ofd);
  1155.             VOID close(ifd);
  1156.             VOID close(ofd);
  1157.         }
  1158.         /* safety */
  1159.         if (uncompressrun)
  1160.         {    VOID xwait(uncompressrun, "inentry xwait()", TRUE);
  1161.             uncompressrun = 0;
  1162.         }
  1163.     }
  1164.     else if (ofd < 0)
  1165.         return (-1);
  1166.     else if (inskip(asb->sb_size) < 0)
  1167.         VOID warn(name, "Redundant file data is corrupt");
  1168.     tstamp[0] = tstamp[1] = mflag ? timenow : asb->sb_mtime;
  1169.     VOID utime(name, tstamp);
  1170.     return (0);
  1171. }
  1172.  
  1173. /*
  1174.  * infill()
  1175.  *
  1176.  * Fill the archive buffer. Remembers mid-buffer read failures and
  1177.  * reports them the next time through. Replaces unreadable data with
  1178.  * null characters. Returns zero with valid data, -1 otherwise.
  1179.  */
  1180. STATIC int
  1181. infill()
  1182. {
  1183.     reg int        got;
  1184.     static    int    failed;
  1185.  
  1186.     bufend = bufidx = buffer;
  1187.     if (!failed) {
  1188.         if (areof)
  1189.             if (total == 0)
  1190.                 fatal(arspec, "No input");
  1191.             else
  1192.                 next(O_RDONLY, "Input EOF");
  1193.         if (aruntil && arleft < arbsize)
  1194.             next(O_RDONLY, "Input limit reached");
  1195.         while (!failed
  1196.             && !areof
  1197.             && (aruntil == 0 || arleft >= arbsize)
  1198.             && buffer + buflen - bufend >= arbsize) {
  1199.             if ((got = read(arfd, bufend, arbsize)) > 0) {
  1200.                 bufend += got;
  1201.                 arleft -= got;
  1202.             } else if (got < 0)
  1203.                 failed = warnarch(syserr(),
  1204.                     (off_t) 0 - (bufend - bufidx));
  1205.             else
  1206.                 ++areof;
  1207.         }
  1208.     }
  1209.     if (failed && bufend == buffer) {
  1210.         failed = 0;
  1211.         for (got = 0; got < arbsize; ++got)
  1212.             *bufend++ = '\0';
  1213.         return (-1);
  1214.     }
  1215.     return (0);
  1216. }
  1217.  
  1218. /*
  1219.  * inhead()
  1220.  *
  1221.  * Read a header. Quietly translates old-fashioned binary cpio headers
  1222.  * (and arranges to skip the possible alignment byte). Returns zero if
  1223.  * successful, -1 upon archive trailer.
  1224.  */
  1225. STATIC int
  1226. inhead(name, asb)
  1227. reg char    *name;
  1228. reg Stat    *asb;
  1229. {
  1230.     reg off_t    skipped;
  1231.     auto char    magic[M_STRLEN];
  1232.     static int    align;
  1233.  
  1234.     if (align > 0)
  1235.         VOID inskip((off_t) align);
  1236.     align = 0;
  1237.     for (;;) {
  1238.         VOID inread(magic, M_STRLEN);
  1239.         skipped = 0;
  1240.         while ((align = inascii(magic, name, asb)) < 0
  1241.             && (align = inbinary(magic, name, asb)) < 0
  1242.             && (align = inswab(magic, name, asb)) < 0) {
  1243.             if (++skipped == 1) {
  1244.                 if (!kflag && total - sizeof(magic) == 0)
  1245.                     fatal(arspec, "Unrecognizable archive");
  1246.                 VOID warnarch("Bad magic number",
  1247.                     (off_t) sizeof(magic));
  1248.                 if (name[0])
  1249.                     VOID warn(name, "May be corrupt");
  1250.             }
  1251.             memcpy(magic, magic + 1, sizeof(magic) - 1);
  1252.             VOID inread(magic + sizeof(magic) - 1, 1);
  1253.         }
  1254.         if (skipped) {
  1255.             VOID warnarch("Apparently resynchronized",
  1256.                 (off_t) sizeof(magic));
  1257.             VOID warn(name, "Continuing");
  1258.         }
  1259.         if (strcmp(name, TRAILER) == 0)
  1260.             return (-1);
  1261.         if (nameopt(name) >= 0)
  1262.             break;
  1263.         VOID inskip(asb->sb_size + align);
  1264.     }
  1265. #ifdef    S_IFLNK
  1266.     if ((asb->sb_mode & S_IFMT) == S_IFLNK) {
  1267.         if (inread(asb->sb_link, (uint) asb->sb_size) < 0) {
  1268.             VOID warn(name, "Corrupt symbolic link");
  1269.             return (inhead(name, asb));
  1270.         }
  1271.         asb->sb_link[asb->sb_size] = '\0';
  1272.         asb->sb_size = 0;
  1273.     }
  1274. #endif    /* S_IFLNK */
  1275.     if ((name[0] == '/') && !abspaths)
  1276.         if (name[1])
  1277.             while (name[0] = name[1])
  1278.                 ++name;
  1279.         else
  1280.             name[0] = '.';
  1281.     asb->sb_atime = asb->sb_ctime = asb->sb_mtime;
  1282.     return (0);
  1283. }
  1284.  
  1285. /*
  1286.  * inread()
  1287.  *
  1288.  * Read a given number of characters from the input archive. Returns
  1289.  * zero with valid data, -1 if unreadable portions were replaced by
  1290.  * null characters.
  1291.  */
  1292. STATIC int
  1293. inread(dst, len)
  1294. reg char    *dst;
  1295. uint        len;
  1296. {
  1297.     reg uint    have;
  1298.     reg uint    want;
  1299.     reg int        corrupt = 0;
  1300.     char        *endx = dst + len;
  1301.  
  1302.     while (want = endx - dst) {
  1303.         while ((have = bufend - bufidx) == 0)
  1304.             corrupt |= infill();
  1305.         if (have > want)
  1306.             have = want;
  1307.         memcpy(dst, bufidx, have);
  1308.         bufidx += have;
  1309.         dst += have;
  1310.         total += have;
  1311.     }
  1312.     return (corrupt);
  1313. }
  1314.  
  1315. /*
  1316.  * inskip()
  1317.  *
  1318.  * Skip input archive data. Returns zero under normal circumstances,
  1319.  * -1 if unreadable data is encountered.
  1320.  */
  1321. STATIC int
  1322. inskip(len)
  1323. reg off_t    len;
  1324. {
  1325.     reg uint    chunk;
  1326.     reg int        corrupt = 0;
  1327.  
  1328.     while (len) {
  1329.         while ((chunk = bufend - bufidx) == 0)
  1330.             corrupt |= infill();
  1331.         if (chunk > len)
  1332.             chunk = len;
  1333.         bufidx += chunk;
  1334.         len -= chunk;
  1335.         total += chunk;
  1336.     }
  1337.     return (corrupt);
  1338. }
  1339.  
  1340. /*
  1341.  * inswab()
  1342.  *
  1343.  * Read a reversed byte order binary header. Returns the number
  1344.  * of trailing alignment bytes to skip; -1 if unsuccessful.
  1345.  */
  1346. STATIC int
  1347. inswab(magic, name, asb)
  1348. reg char    *magic;
  1349. reg char    *name;
  1350. reg Stat    *asb;
  1351. {
  1352.     reg ushort    namesize;
  1353.     reg uint    namefull;
  1354.     auto Binary    binary;
  1355.  
  1356.     if ((int)*((ushort *) magic) != swab(M_BINARY))
  1357.         return (-1);
  1358.     memcpy((char *) &binary,
  1359.         magic + sizeof(ushort),
  1360.         M_STRLEN - sizeof(ushort));
  1361.     if (inread((char *) &binary + M_STRLEN - sizeof(ushort),
  1362.         sizeof(binary) - (M_STRLEN - sizeof(ushort))) < 0)
  1363.         return (warnarch("Corrupt swapped header",
  1364.             (off_t) sizeof(binary) - (M_STRLEN - sizeof(ushort))));
  1365.     asb->sb_dev = (dev_t) swab(binary.b_dev);
  1366.     asb->sb_ino = (ino_t) swab(binary.b_ino);
  1367.     asb->sb_mode = swab(binary.b_mode);
  1368.     asb->sb_uid = swab(binary.b_uid);
  1369.     asb->sb_gid = swab(binary.b_gid);
  1370.     asb->sb_nlink = swab(binary.b_nlink);
  1371.     asb->sb_rdev = (dev_t) swab(binary.b_rdev);
  1372.     asb->sb_mtime = swab(binary.b_mtime[0]) << 16 | swab(binary.b_mtime[1]);
  1373.     asb->sb_size = swab(binary.b_size[0]) << 16 | swab(binary.b_size[1]);
  1374.     if ((namesize = swab(binary.b_name)) == 0 || namesize >= PATHSIZE)
  1375.         return (warnarch("Bad swapped pathname length",
  1376.             (off_t) sizeof(binary) - (M_STRLEN - sizeof(ushort))));
  1377.     if (inread(name, namefull = namesize + namesize % 2) < 0)
  1378.         return (warnarch("Corrupt swapped pathname", (off_t) namefull));
  1379.     if (name[namesize - 1] != '\0')
  1380.         return (warnarch("Bad swapped pathname", (off_t) namefull));
  1381.     return (asb->sb_size % 2);
  1382. }
  1383.  
  1384. /*
  1385.  * lineget()
  1386.  *
  1387.  * Get a line from a given stream. Returns 0 if successful, -1 at EOF.
  1388.  */
  1389. STATIC int
  1390. lineget(stream, buf)
  1391. reg FILE    *stream;
  1392. reg char    *buf;
  1393. {
  1394.     reg int        c;
  1395.  
  1396.     for (;;) {
  1397.         if ((c = getc(stream)) == EOF)
  1398.             return (-1);
  1399.         if (c == '\n')
  1400.             break;
  1401.         *buf++ = c;
  1402.     }
  1403.     *buf = '\0';
  1404.     return (0);
  1405. }
  1406.  
  1407. /*
  1408.  * linkalso()
  1409.  *
  1410.  * Add a destination pathname to an existing chain. Assumes that
  1411.  * at least one element is present.
  1412.  */
  1413. STATIC void
  1414. linkalso(linkp, name)
  1415. reg Link    *linkp;
  1416. char        *name;
  1417. {
  1418.     reg Path    *path;
  1419.  
  1420.     if (((path = (Path *) memget(sizeof(Path))) == NULL)
  1421.         || ((path->p_name = memstr(name)) == NULL))
  1422.         return;
  1423.     path->p_forw = NULL;
  1424.     path->p_back = linkp->l_path->p_back;
  1425.     path->p_back->p_forw = path;
  1426.     linkp->l_path->p_back = path;
  1427. }
  1428.  
  1429. /*
  1430.  * linkfrom()
  1431.  *
  1432.  * Find a file to link from. Returns a pointer to a link
  1433.  * structure, or NULL if unsuccessful.
  1434.  */
  1435. STATIC Link *
  1436. linkfrom(asb)
  1437. reg Stat    *asb;
  1438. {
  1439.     reg Link    *linkp;
  1440.     reg Link    *linknext;
  1441.     reg Path    *path;
  1442.     reg Path    *pathnext;
  1443.     reg Link    **abase;
  1444.  
  1445.     for (linkp = *(abase = linkhash(asb->sb_ino)); linkp; linkp = linknext)
  1446.         if (linkp->l_nlink == 0) {
  1447.             for (path = linkp->l_path; path; path = pathnext) {
  1448.                 pathnext = path->p_forw;
  1449.                 free(path->p_name);
  1450.             }
  1451.             free((char *) linkp->l_path);
  1452.             if (linknext = linkp->l_forw)
  1453.                 linknext->l_back = linkp->l_back;
  1454.             if (linkp->l_back)
  1455.                 linkp->l_back->l_forw = linkp->l_forw;
  1456.