386BSD 0.1 development
authorWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Sat, 27 Jun 1992 02:42:17 +0000 (18:42 -0800)
committerWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Sat, 27 Jun 1992 02:42:17 +0000 (18:42 -0800)
Work on file usr/src/usr.bin/cpio/cpio.c

Co-Authored-By: Lynne Greer Jolitz <ljolitz@cardio.ucsf.edu>
Synthesized-from: 386BSD-0.1

usr/src/usr.bin/cpio/cpio.c [new file with mode: 0644]

diff --git a/usr/src/usr.bin/cpio/cpio.c b/usr/src/usr.bin/cpio/cpio.c
new file mode 100644 (file)
index 0000000..5c7d865
--- /dev/null
@@ -0,0 +1,1502 @@
+/*     Copyright (c) 1988 AT&T */
+/*       All Rights Reserved   */
+
+/*     THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T     */
+/*     The copyright notice above does not evidence any        */
+/*     actual or intended publication of such source code.     */
+
+#ident "@(#)cpio:cpio.c        1.30.1.11"
+/*     /sccs/src/cmd/s.cpio.c
+       cpio.c  1.30.1.11       1/11/86 13:46:48
+       Reworked cpio which uses getopt(3) to interpret flag arguments and
+       changes reels to the save file name.
+       Performance and size improvements.
+*/
+
+/*     cpio    COMPILE:        cc -O cpio.c -s -i -o cpio -lgen -lerr
+       cpio -- copy file collections
+
+*/
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <memory.h>
+#include <pwd.h>
+#include <string.h>
+#include <signal.h>
+#include <varargs.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <paths.h>
+
+struct utimbuf {
+       time_t  actime;
+       time_t  modtime;
+};
+#ifndef S_IFIFO
+#define        S_IFIFO 010000
+#endif
+
+#define EQ(x,y)        (strcmp(x,y)==0)
+
+                               /* MKSHORT:  for VAX, Interdata, ...    */
+                               /* Take a 4-byte long, lv, and turn it  */
+                               /* into an array of two 2-byte shorts, v*/
+#define MKSHORT(v,lv) {U.l=1L;if(U.c[0]) U.l=lv,v[0]=U.s[1],v[1]=U.s[0]; else U.l=lv,v[0]=U.s[0],v[1]=U.s[1];}
+
+#define MAGIC  070707          /* cpio magic number */
+#define BSMAGIC        0143561         /* byte-swapped cpio magic number */
+#define IN     'i'             /* copy in */
+#define OUT    'o'             /* copy out */
+#define PASS   'p'             /* direct copy */
+#define HDRSIZE        (Hdr.h_name - (char *)&Hdr)     /* header size minus filename field */
+#define LINKS  500             /* no. of links allocated per bunch */
+#define CHARS  76              /* ASCII header size minus filename field */
+#define BUFSIZE 512            /* In u370, can't use BUFSIZ or BSIZE */
+#define CPIOBSZ 4096           /* file read/write */
+#define MK_USHORT(a)   (a & 00000177777)       /* Make unsigned shorts for portable  */
+                                               /* header.  Hardware may only know    */
+                                               /* integer operations and sign extend */
+                                               /* the large unsigned short resulting */
+                                               /* in 8 rather than 6 octal char in   */
+                                               /* the header.                        */
+
+static struct  stat    Statb, Xstatb;
+
+       /* Cpio header format */
+static struct header {
+       short   h_magic;
+       short   h_dev;
+       ushort  h_ino;
+       ushort  h_mode,
+               h_uid,
+               h_gid;
+       short   h_nlink;
+       short   h_rdev;
+       short   h_mtime[2],
+               h_namesize,
+               h_filesize[2];
+       char    h_name[256];
+} Hdr;
+
+char   Symlbuf[MAXPATHLEN + 1];        /* target of symbolic link */
+static unsigned        Bufsize = BUFSIZE;              /* default record size */
+static char    Buf[CPIOBSZ], *Cbuf;
+static char    *Cp;
+
+
+static
+short  Option,
+       Dir,
+       Uncond,
+       PassLink,
+       Rename,
+       Toc,
+       Verbose,
+       Mod_time,
+       Acc_time,
+       Cflag,
+       fflag,
+       Swap,
+       byteswap,
+       halfswap;
+
+static
+int    Ifile,
+       Ofile,
+       Input = 0,
+       Output = 1;
+                       /* sBlocks: short Blocks.  Cumulative character   */
+                       /* count for short reads in bread().  Encountered */
+                       /* with communication lines and pipes as in:      */
+                       /* split -100 cpio_archive; cat xa* | cpio -icd   */
+static
+long   sBlocks,
+       Blocks,
+       Longfile,
+       Longtime;
+
+static
+char   Fullname[256],
+       Name[256];
+static
+int    Pathend;
+static
+char   *swfile;
+static
+char   *eommsg = "Change to part %d and press RETURN key. [q] ";
+
+static
+FILE   *Rtty,
+       *Wtty;
+static
+char   ttyname[] = _PATH_TTY;
+
+static
+char   **Pattern = 0;
+static
+char   Chdr[500];
+static
+short  Dev;
+ushort Uid,
+       A_directory,
+       A_special,
+       A_symlink,
+       Filetype = S_IFMT;
+
+extern errno;
+extern void exit();
+char   *malloc();
+FILE   *popen();
+
+static char *smemcpy();
+
+static
+union {
+       long l;
+       short s[2];
+       char c[4];
+} U;
+
+/* for VAX, Interdata, ... */
+static
+long mklong(v)
+short v[];
+{
+       U.l = 1;
+       if(U.c[0])
+               U.s[0] = v[1], U.s[1] = v[0];
+       else
+               U.s[0] = v[0], U.s[1] = v[1];
+       return U.l;
+}
+
+static usage(), chkswfile(), getname(), bintochar(), chkhdr(), gethdr();
+static ckname(), openout(), breread(), bread(), bwrite(), eomchgreel();
+static postml(), pentry(), nmatch(), gmatch(), umatch(), set_time();
+static chgreel(), missdir(), pwd(), fperr(), fperrno();
+
+main(argc, argv)
+int argc;
+char **argv;
+{
+       register ct;
+       long    filesz;
+       int     symlsz;
+       register char *fullp;
+       register i;
+       int ans;
+       register char *symlinkp;
+       short select;                   /* set when files are selected */
+       extern char     *optarg;
+       extern int      optind;
+
+       signal(SIGSYS, SIG_IGN);
+       if(argc <= 1 || *argv[1] != '-')
+               usage();
+       Uid = getuid();
+
+       while( (ans = getopt( argc, argv, "aBC:ifopcdlmrSsbtuvM:6eI:O:")) != EOF ) {
+
+               switch( ans ) {
+               case 'a':               /* reset access time */
+                       Acc_time++;
+                       break;
+               case 'B':               /* change record size to 5120 bytes */
+                       Bufsize = 5120;
+                       break;
+               case 'C':               /* reset buffer size to arbitrary valu
+                                       */
+                       Bufsize = atoi( optarg );
+                       if( Bufsize == 0 ) {
+                               fperr("Illegal argument to -%c, '%s'",
+                                       ans, optarg );
+                               exit(2);
+                       }
+                       break;
+               case 'i':
+                       Option = IN;
+                       break;
+               case 'f':       /* copy files not matched by patterns */
+                       fflag++;
+                       break;
+               case 'o':
+                       Option = OUT;
+                       break;
+               case 'p':
+                       Option = PASS;
+                       break;
+               case 'c':               /* ASCII header */
+                       Cflag++;
+                       break;
+               case 'd':               /* create directories when needed */
+                       Dir++;
+                       break;
+               case 'l':               /* link files, when necessary */
+                       PassLink++;
+                       break;
+               case 'm':               /* retain mod time */
+                       Mod_time++;
+                       break;
+               case 'r':               /* rename files interactively */
+                       Rename++;
+                       Rtty = fopen(ttyname, "r");
+                       Wtty = fopen(ttyname, "w");
+                       if(Rtty==NULL || Wtty==NULL) {
+                               fperrno("Cannot rename (%s missing)",
+                                       ttyname );
+                               exit(2);
+                       }
+                       break;
+               case 'S':               /* swap halfwords */
+                       halfswap++;
+                       Swap++;
+                       break;
+               case 's':               /* swap bytes */
+                       byteswap++;
+                       Swap++;
+                       break;
+               case 'b':               /* swap both bytes and halfwords */
+                       halfswap++;
+                       byteswap++;
+                       Swap++;
+                       break;
+               case 't':               /* table of contents */
+                       Toc++;
+                       break;
+               case 'u':               /* copy unconditionally */
+                       Uncond++;
+                       break;
+               case 'v':               /* verbose - print out file names */
+                       Verbose++;
+                       break;
+               case 'M':               /* alternate message for end-of-media */
+                       eommsg = optarg;
+                       break;
+               case '6':               /* for old, sixth-edition files */
+                       Filetype = 060000;
+                       break;
+               case 'I':
+                       chkswfile( swfile, ans, Option );
+                       if( (i = open( optarg, O_RDONLY ) ) < 0) {
+                               fperrno("Cannot open <%s> for input", optarg);
+                               exit(2);
+                       }
+                       if( dup2(i, Input ) < 0 ) {
+                               fperrno("Cannot dup to standard input");
+                               exit(2);
+                       }
+                       swfile = optarg;
+                       break;
+               case 'O':
+                       chkswfile( swfile, ans, Option );
+                       if( (i = open( optarg, O_WRONLY | O_CREAT | O_TRUNC,
+                           0666 ) ) < 0) {
+                               fperrno("Cannot open <%s> for output", optarg);
+                               exit(2);
+                       }
+                       if( dup2(i, Output ) < 0 ) {
+                               fperrno("Cannot dup to standard output");
+                               exit(2);
+                       }
+                       swfile = optarg;
+                       break;
+               default:
+                       usage();
+               }
+       }
+       if(!Option) {
+               (void) fprintf(stderr,
+                   "Options must include one of -o, -i, or -p\n");
+               exit(2);
+       }
+
+       if(Option == PASS) {
+               if(Rename) {
+                       (void) fprintf(stderr,
+                           "Pass and Rename cannot be used together\n");
+                       exit(2);
+               }
+               if( Bufsize != BUFSIZE ) {
+                       fprintf( stderr, "`B' or `C' option is irrelevant with the '-p' option\n");
+                       Bufsize = BUFSIZE;
+               }
+
+       }else  {
+               Cp = Cbuf = (char *)malloc(Bufsize);
+               if(Cp == NULL) {
+                       perror("cpio");
+                       exit(2);
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       switch(Option) {
+       case OUT:
+               if(argc != 0)
+                       usage();
+               /* get filename, copy header and file out */
+               while(getname()) {
+                       if( mklong(Hdr.h_filesize) == 0L) {
+                               if( Cflag )
+                                       bwrite(Chdr,CHARS+Hdr.h_namesize);
+                               else
+                                       bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
+                               if(Verbose)
+                                       (void) fprintf(stderr, "%s\n",
+                                           Hdr.h_name);
+                               continue;
+                       } else if( A_symlink ) {
+                               symlsz = (int) mklong(Hdr.h_filesize);
+                               if (readlink(Hdr.h_name, Symlbuf, symlsz) < 0) {
+                                       fperrno("Cannot read symbolic link <%s>",
+                                           Hdr.h_name);
+                                       continue;
+                               }
+                               Symlbuf[symlsz] = '\0';
+                               bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
+                               bwrite(Symlbuf, symlsz);
+                               if(Verbose)
+                                       (void) fprintf(stderr, "%s\n",
+                                           Hdr.h_name);
+                               continue;
+                       }
+                       if((Ifile = open(Hdr.h_name, 0)) < 0) {
+                               fperrno("Cannot open <%s>", Hdr.h_name);
+                               continue;
+                       }
+                       if ( Cflag )
+                               bwrite(Chdr,CHARS+Hdr.h_namesize);
+                       else
+                               bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
+                       for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= CPIOBSZ){
+                               ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
+                               if(read(Ifile, Buf, ct) < 0) {
+                                       fperrno("Cannot read %s", Hdr.h_name);
+                                       continue;
+                               }
+                               bwrite(Buf,ct);
+                       }
+                       close(Ifile);
+                       if(Acc_time) {
+                               struct utimbuf utb;
+
+                               utb.actime = Statb.st_atime;
+                               utb.modtime = Statb.st_mtime;
+                               (void)utime(Hdr.h_name, &utb);
+                       }
+                       if(Verbose)
+                               (void) fprintf(stderr, "%s\n", Hdr.h_name);
+               }
+
+       /* copy trailer, after all files have been copied */
+               strcpy(Hdr.h_name, "TRAILER!!!");
+               Hdr.h_magic = MAGIC;
+               MKSHORT(Hdr.h_filesize, 0L);
+               Hdr.h_namesize = strlen("TRAILER!!!") + 1;
+               if ( Cflag )  {
+                       bintochar(0L);
+                       bwrite(Chdr, CHARS+Hdr.h_namesize);
+               }
+               else
+                       bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
+               bwrite(Cbuf, Bufsize);
+               break;
+
+       case IN:
+               if(argc > 0 ) { /* save patterns, if any */
+                       Pattern = argv;
+               }
+               pwd();
+               chkhdr();
+               while(gethdr()) {
+                       if (A_symlink) {
+                               symlsz = (int) mklong(Hdr.h_filesize);
+                               bread(Symlbuf, symlsz);
+                               Symlbuf[symlsz] = '\0';
+                               if( ckname(Hdr.h_name)  &&  !Toc)
+                                       (void)openout(Hdr.h_name, Symlbuf);
+                       } else {
+                               if( (select = ckname(Hdr.h_name))  &&  !Toc )
+                                       Ofile = openout(Hdr.h_name, (char *)0);
+                               else
+                                       Ofile = 0;
+                               for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= CPIOBSZ){
+                                       ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
+                                       bread(Buf, ct);
+                                       if(Ofile) {
+                                               if(Swap)
+                                                      swap(Buf,ct,byteswap,halfswap);
+                                               if(write(Ofile, Buf, ct) < 0) {
+                                                fperrno("Cannot write %s", Hdr.h_name);
+                                                continue;
+                                               }
+                                       }
+                               }
+                               if( Ofile ) {
+                                       (void) close(Ofile);
+                                       if(chmod(Hdr.h_name, Hdr.h_mode) < 0)
+                                               fperrno("Cannot change mode of <%s>",
+                                                   Hdr.h_name);
+                                       set_time(Hdr.h_name, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
+                               }
+                       }
+                       if(select) {
+                               if(Verbose)
+                                       if(Toc)
+                                               pentry(Hdr.h_name);
+                                       else
+                                               puts(Hdr.h_name);
+                               else if(Toc)
+                                       puts(Hdr.h_name);
+                       }
+               }
+               break;
+
+       case PASS:              /* move files around */
+               if(argc != 1)
+                       usage();
+               if(access(argv[0], 2) == -1) {
+                       (void) fperrno("Cannot write in <%s>", argv[0]);
+                       exit(2);
+               }
+               strcpy(Fullname, argv[0]);      /* destination directory */
+               if(stat(Fullname, &Xstatb) < 0) {
+                       fperrno("Cannot stat <%s>", Fullname);
+                       exit(2);
+               }
+               if((Xstatb.st_mode&S_IFMT) != S_IFDIR) {
+                       (void) fprintf(stderr, "<%s> is not a directory",
+                           Fullname);
+                       exit(2);
+               }
+               Dev = Xstatb.st_dev;
+               if( Fullname[ strlen(Fullname) - 1 ] != '/' )
+                       strcat(Fullname, "/");
+               fullp = Fullname + strlen(Fullname);
+
+               while(getname()) {
+                       if (A_directory && !Dir)
+                               fperr("Use `-d' option to copy <%s>",
+                                       Hdr.h_name);
+                       if(!ckname(Hdr.h_name))
+                               continue;
+                       i = 0;
+                       while(Hdr.h_name[i] == '/')
+                               i++;
+                       strcpy(fullp, &(Hdr.h_name[i]));
+
+                       if( PassLink  &&  !A_directory  &&  Dev == Statb.st_dev ) {
+                               if(link(Hdr.h_name, Fullname) < 0) {
+                                       switch(errno) {
+                                               case ENOENT:
+                                                       if(missdir(Fullname) != 0) {
+                                                               fperrno("Cannot create directory for <%s>",
+                                                                       Fullname);
+                                                               continue;
+                                                       }
+                                                       break;
+                                               case EEXIST:
+                                                       if(unlink(Fullname) < 0) {
+                                                               fperrno("Cannot unlink <%s>",
+                                                                       Fullname);
+                                                               continue;
+                                                       }
+                                                       break;
+                                               default:
+                                                       fperrno("Cannot link <%s> to <%s>",
+                                                               Hdr.h_name, Fullname);
+                                                       continue;
+                                               }
+                                       if(link(Hdr.h_name, Fullname) < 0) {
+                                               fperrno("Cannot link <%s> to <%s>",
+                                                       Hdr.h_name, Fullname);
+                                               continue;
+                                       }
+                               }
+
+                               goto ckverbose;
+                       }
+                       if( A_symlink ) {
+                          symlsz = (int) mklong(Hdr.h_filesize);
+                          if (readlink(Hdr.h_name, Symlbuf, symlsz) < 0) {
+                               fperrno("Cannot read symbolic link <%s>",
+                                   Hdr.h_name);
+                               continue;
+                          }
+                          Symlbuf[symlsz] = '\0';
+                          if(!openout(Fullname, Symlbuf))
+                               continue;
+                          Blocks += ((symlsz + (BUFSIZE - 1)) / BUFSIZE);
+                          if(Verbose)
+                               puts(Fullname);
+                          continue;
+                       }
+                       if(!(Ofile = openout(Fullname, (char *)0)))
+                               continue;
+                       if((Ifile = open(Hdr.h_name, 0)) < 0) {
+                               fperrno("Cannot open <%s>", Hdr.h_name);
+                               close(Ofile);
+                               continue;
+                       }
+                       filesz = Statb.st_size;
+                       for(; filesz > 0; filesz -= CPIOBSZ) {
+                               ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
+                               if(read(Ifile, Buf, ct) < 0) {
+                                       fperrno("Cannot read %s", Hdr.h_name);
+                                       break;
+                               }
+                               if(write(Ofile, Buf, ct) < 0) {
+                                fperrno("Cannot write %s", Hdr.h_name);
+                                break;
+                               }
+                               /* Removed u370 ifdef which caused cpio */
+                               /* to report blocks in terms of 4096 bytes. */
+
+                               Blocks += ((ct + (BUFSIZE - 1)) / BUFSIZE);
+                       }
+                       close(Ifile);
+                       if(Acc_time) {
+                               struct utimbuf utb;
+
+                               utb.actime = Statb.st_atime;
+                               utb.modtime = Statb.st_mtime;
+                               (void)utime(Hdr.h_name, &utb);
+                       }
+                       if(Ofile) {
+                               close(Ofile);
+                               if(chmod(Fullname, Hdr.h_mode) < 0)
+                                       fperrno("Cannot change mode of <%s>",
+                                           Fullname);
+                               set_time(Fullname, Statb.st_atime, mklong(Hdr.h_mtime));
+ckverbose:
+                               if(Verbose)
+                                       puts(Fullname);
+                       }
+               }
+       }
+#ifdef dontbother
+       /* print number of blocks actually copied */
+       Blocks += ((sBlocks + (BUFSIZE - 1)) / BUFSIZE);
+       (void) fprintf(stderr, "%ld blocks\n", Blocks * (Bufsize>>9));
+#endif
+       exit(0);
+}
+
+static
+usage()
+{
+       (void) fprintf(stderr,
+           "Usage: %s\n     %s\n     %s\n     %s\n       %s\n",
+           "cpio -o[acvB] <name-list >collection",
+           "cpio -o[acvB] -Ocollection <name-list",
+           "cpio -i[cdmrstuvfB6] [ pattern ... ] <collection",
+           "cpio -i[cdmrstuvfB6] -Icollection [ pattern ... ]",
+           "cpio -p[adlmruv] directory <name-list");
+}
+
+static
+chkswfile( sp, c, option )
+char   *sp;
+char   c;
+short  option;
+{
+       if( !option ) {
+               fperr( "-%c must be specified before -%c option",
+                       c == 'I' ? 'i' : 'o', c );
+               exit(2);
+       }
+       if( (c == 'I'  &&  option != IN)  ||  (c == 'O'  &&  option != OUT) ) {
+               fperr( "-%c option not permitted with -%c option", c,
+                       option );
+               exit(2);
+       }
+       if( !sp )
+               return;
+       fperr("No more than one -I or -O flag permitted");
+       exit(2);
+}
+
+static
+getname()              /* get file name, get info for header */
+{
+       register char *namep = Name;
+       register ushort ftype;
+       struct stat Lstatb;
+       long tlong;
+
+       for(;;) {
+               if (fgets(namep, sizeof Name, stdin) == NULL)
+                       return 0;
+               /* zap newline */
+               for (;*namep; namep++)
+                       if(*namep == '\n')
+                               *namep = 0;
+               namep = Name;
+               
+               while(*namep == '.' && namep[1] == '/') {
+                       namep++;
+                       while(*namep == '/') namep++;
+               }
+               strcpy(Hdr.h_name, namep);
+               if(lstat(namep, &Statb) < 0) {
+                       fperrno("Cannot stat <%s>", Hdr.h_name);
+                       continue;
+               }
+               ftype = Statb.st_mode & Filetype;
+               A_directory = (ftype == S_IFDIR);
+               A_special = (ftype == S_IFBLK)
+                       || (ftype == S_IFCHR)
+                       || (ftype == S_IFIFO);
+               A_symlink = (ftype == S_IFLNK);
+               Hdr.h_magic = MAGIC;
+               Hdr.h_namesize = strlen(Hdr.h_name) + 1;
+               Hdr.h_uid = Statb.st_uid;
+               Hdr.h_gid = Statb.st_gid;
+               Hdr.h_dev = Statb.st_dev;
+               Hdr.h_ino = Statb.st_ino;
+               Hdr.h_mode = Statb.st_mode;
+               MKSHORT(Hdr.h_mtime, Statb.st_mtime);
+               Hdr.h_nlink = Statb.st_nlink;
+               tlong = ((Hdr.h_mode&S_IFMT) == S_IFREG ||
+                       (Hdr.h_mode&S_IFMT) == S_IFLNK)? Statb.st_size: 0L;
+               MKSHORT(Hdr.h_filesize, tlong);
+               Hdr.h_rdev = Statb.st_rdev;
+               if( Cflag )
+                       bintochar(tlong);
+               return 1;
+       }
+}
+
+static
+bintochar(t)           /* ASCII header write */
+long t;
+{
+       sprintf(Chdr,"%.6o%.6ho%.6ho%.6ho%.6ho%.6ho%.6ho%.6ho%.11lo%.6ho%.11lo%s",
+               MAGIC, MK_USHORT(Statb.st_dev), MK_USHORT(Statb.st_ino), Statb.st_mode, Statb.st_uid,
+               Statb.st_gid, Statb.st_nlink, MK_USHORT(Statb.st_rdev),
+               Statb.st_mtime, (short)strlen(Hdr.h_name)+1, t, Hdr.h_name);
+}
+
+static
+chartobin()            /* ASCII header read */
+{
+       sscanf(Chdr, "%6ho%6ho%6ho%6ho%6ho%6ho%6ho%6ho%11lo%6ho%11lo",
+               &Hdr.h_magic, &Hdr.h_dev, &Hdr.h_ino, &Hdr.h_mode, &Hdr.h_uid,
+               &Hdr.h_gid, &Hdr.h_nlink, &Hdr.h_rdev, &Longtime,
+               &Hdr.h_namesize, &Longfile);
+       MKSHORT(Hdr.h_filesize, Longfile);
+       MKSHORT(Hdr.h_mtime, Longtime);
+}
+
+
+/*     Check the header for the magic number.  Switch modes automatically to
+       match the type of header found.
+*/
+static
+chkhdr()
+{
+       bread(Chdr, CHARS);
+       chartobin();
+       if( Hdr.h_magic == MAGIC )
+               Cflag = 1;
+       else {
+               breread(&Hdr.h_magic, sizeof Hdr.h_magic);
+               if( Hdr.h_magic == MAGIC || Hdr.h_magic == (short)BSMAGIC )
+                       Cflag = 0;
+               else {
+                       fperr("This is not a cpio file.  Bad magic number.");
+                       exit(2);
+               }
+       }
+       breread(Chdr, 0);
+}
+
+
+static
+gethdr()               /* get file headers */
+{
+       register ushort ftype;
+
+       if (Cflag)  {
+               bread(Chdr, CHARS);
+               chartobin();
+       }
+       else
+               bread(&Hdr, HDRSIZE);
+
+       if(Hdr.h_magic == (short)BSMAGIC)
+               swap((char *)&Hdr, HDRSIZE, 1, 0);
+       else if( Hdr.h_magic != MAGIC ) {
+               fperr("Out of phase--get help");
+               exit(2);
+       }
+       bread(Hdr.h_name, Hdr.h_namesize);
+       if(EQ(Hdr.h_name, "TRAILER!!!"))
+               return 0;
+       ftype = Hdr.h_mode & Filetype;
+       A_directory = (ftype == S_IFDIR);
+       A_special = (ftype == S_IFBLK)
+               ||  (ftype == S_IFCHR)
+               ||  (ftype == S_IFIFO);
+       A_symlink = (ftype == S_IFLNK);
+       return 1;
+}
+
+static
+ckname(namep)  /* check filenames with patterns given on cmd line */
+register char *namep;
+{
+       char    buf[sizeof Hdr.h_name];
+
+       if(fflag ^ !nmatch(namep, Pattern)) {
+               return 0;
+       }
+       if(Rename && !A_directory) {    /* rename interactively */
+               fprintf(Wtty, "Rename <%s>\n", namep);
+               fflush(Wtty);
+               fgets(buf, sizeof buf, Rtty);
+               if(feof(Rtty))
+                       exit(2);
+               buf[strlen(buf) - 1] = '\0';
+               if(EQ(buf, "")) {
+                       strcpy(namep,buf);
+                       printf("Skipped\n");
+                       return 0;
+               }
+               else if(EQ(buf, "."))
+                       printf("Same name\n");
+               else
+                       strcpy(namep,buf);
+       }
+       return  1;
+}
+
+static
+openout(namep, symlname)       /* open files for writing, set all necessary info */
+register char *namep;
+char *symlname;
+{
+       register f;
+       register char *np;
+       int ans;
+
+       if(!strncmp(namep, "./", 2))
+               namep += 2;
+       np = namep;
+       if(A_directory) {
+               if( !Dir  ||  Rename  ||  EQ(namep, ".")  ||  EQ(namep, "..") )
+                       /* do not consider . or .. files */
+                       return 0;
+               if(stat(namep, &Xstatb) == -1) {
+
+/* try creating (only twice) */
+                       ans = 0;
+                       do {
+                               if(mkdir(namep, Hdr.h_mode) != 0) {
+                                       ans += 1;
+                               }else {
+                                       ans = 0;
+                                       break;
+                               }
+                       }while(ans < 2 && missdir(namep) == 0);
+                       if(ans == 1) {
+                               fperrno("Cannot create directory for <%s>",
+                                       namep);
+                               return(0);
+                       }else if(ans == 2) {
+                               fperrno("Cannot create directory <%s>", namep);
+                               return(0);
+                       }
+               }
+
+ret:
+               if(chmod(namep, Hdr.h_mode) < 0)
+                       fperrno("Cannot change mode of <%s>", namep);
+               if(Uid == 0)
+                       if(chown(namep, Hdr.h_uid, Hdr.h_gid) < 0)
+                               fperrno("Cannot change ownership of <%s>",
+                                   namep);
+               set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
+               return 0;
+       }
+       if(Hdr.h_nlink > 1)
+               if(!postml(namep, np))
+                       return 0;
+       if(lstat(namep, &Xstatb) == 0) {
+               if(Uncond && !((!(Xstatb.st_mode & S_IWRITE) || A_special) && (Uid != 0))) {
+                       if(unlink(namep) < 0) {
+                               fperrno("cannot unlink current <%s>", namep);
+                       }
+               }
+               if(!Uncond && (mklong(Hdr.h_mtime) <= Xstatb.st_mtime)) {
+               /* There's a newer or same aged version of file on destination */
+                       fperr("current <%s> newer or same age", np);
+                       return 0;
+               }
+       }
+       if( Option == PASS
+               && Hdr.h_ino == Xstatb.st_ino
+               && Hdr.h_dev == Xstatb.st_dev) {
+               fperr("Attempt to pass file to self!");
+               exit(2);
+       }
+       if(A_symlink) {
+/* try symlinking (only twice) */
+               ans = 0;
+               do {
+                       if(symlink(
+symlname, namep) < 0) {
+                               ans += 1;
+                       }else {
+                               ans = 0;
+                               break;
+                       }
+               }while(ans < 2 && missdir(np) == 0);
+               if(ans == 1) {
+                       fperrno("Cannot create directory for <%s>", namep);
+                       return(0);
+               }else if(ans == 2) {
+                       fperrno("Cannot symlink <%s> and <%s>", namep, symlname);
+                       return(0);
+               }
+
+               return 0;
+       }
+       if(A_special) {
+               if((Hdr.h_mode & Filetype) == S_IFIFO)
+                       Hdr.h_rdev = 0;
+
+/* try creating (only twice) */
+               ans = 0;
+               do {
+                       if(mknod(namep, Hdr.h_mode, Hdr.h_rdev) < 0) {
+                               ans += 1;
+                       }else {
+                               ans = 0;
+                               break;
+                       }
+               }while(ans < 2 && missdir(np) == 0);
+               if(ans == 1) {
+                       fperrno("Cannot create directory for <%s>", namep);
+                       return(0);
+               }else if(ans == 2) {
+                       fperrno("Cannot mknod <%s>", namep);
+                       return(0);
+               }
+
+               goto ret;
+       }
+
+/* try creating (only twice) */
+       ans = 0;
+       do {
+               if((f = creat(namep, Hdr.h_mode)) < 0) {
+                       ans += 1;
+               }else {
+                       ans = 0;
+                       break;
+               }
+       }while(ans < 2 && missdir(np) == 0);
+       if(ans == 1) {
+               fperrno("Cannot create directory for <%s>", namep);
+               return(0);
+       }else if(ans == 2) {
+               fperrno("Cannot create <%s>", namep);
+               return(0);
+       }
+
+       if(Uid == 0)
+               if(chown(namep, Hdr.h_uid, Hdr.h_gid) < 0)
+                       fperrno("Cannot change ownership of <%s>", namep);
+       return f;
+}
+
+
+/*     Shared by bread() and breread()
+*/
+static int     nleft = 0;      /* unread chars left in Cbuf */
+static char    *ip;            /* pointer to next char to be read from Cbuf */
+
+/*     Reread the current buffer Cbuf.
+       A character count, c, of 0 simply resets the pointer so next bread gets
+       the same data again.
+*/
+static
+breread(b, c)
+char   *b;
+int    c;
+{
+       ip = Cbuf;
+       if( nleft )
+               nleft = Bufsize;
+       if( !c )
+               return;
+       bread(b, c);
+}
+
+static
+bread(b, c)
+register char  *b;
+register int   c;
+{
+       register int    rv;
+       register char   *p = ip;
+
+       if( !Cflag ) {
+               /* round c up to an even number */
+               c = (c+1)/2;
+               c *= 2;
+       }
+       while( c )  {
+               if( nleft == 0 ) {
+                       while( (rv = read(Input, Cbuf, Bufsize)) == 0 ) {
+                               Input = chgreel(0, Input, rv);
+                       }
+                       if( rv == Bufsize ) {
+                               nleft = Bufsize;
+                               p = Cbuf;
+                               ++Blocks;
+                       }
+                       else if( rv == -1 ) {
+                               fperrno("Read error on archive");
+                               exit(2);
+                       }
+                       else if( rv < Bufsize ) {       /* short read */
+                               smemcpy( &Cbuf[ Bufsize - rv ], Cbuf, rv );
+                               nleft = rv;
+                               p = &Cbuf[ Bufsize - rv ];
+                               sBlocks += rv;
+                       }
+               }
+               if( nleft <= c ) {
+                       memcpy( b, p, nleft );
+                       c -= nleft;
+                       b += nleft;
+                       p += nleft;
+                       nleft = 0;
+               }
+               else {
+                       memcpy( b, p, c );
+                       nleft -= c;
+                       b += c;
+                       p += c;
+                       c = 0;
+               }
+       }
+       ip = p;
+}
+
+
+static
+bwrite(rp, c)
+register char *rp;
+register c;
+{
+       register char   *cp = Cp;
+       static unsigned Ccnt = 0;
+       register unsigned Cleft;
+       register int    rv;
+
+       if( !Cflag ) {
+               /* round c up to an even number */
+               c = (c+1)/2;
+               c *= 2;
+       }
+       while( c )  {
+               if( (Cleft = Bufsize - Ccnt) <= c ) {
+                       memcpy( cp, rp, Cleft );
+                       rv = write(Output, Cbuf, Bufsize);
+                       if( rv == 0  ||  ( rv == -1  &&  errno == ENXIO ) ) {
+                               rv = eomchgreel();
+                       }
+                       if( rv == Bufsize ) {
+                               Ccnt = 0;
+                               cp = Cbuf;
+                       }
+                       else if( rv == -1 ) {
+                               fperrno("Write error on archive");
+                               exit(2);
+                       }
+                       else if( rv < Bufsize ) {
+                               Output = chgreel(1, Output, 0);
+                               smemcpy( Cbuf, &Cbuf[ Bufsize - rv ], rv );
+                               Ccnt = Bufsize - rv;
+                               cp = &Cbuf[ rv ];
+                       }
+                       ++Blocks;
+                       rp += Cleft;
+                       c -= Cleft;
+               }
+               else {
+                       memcpy( cp, rp, c );
+                       Ccnt += c;
+                       cp += c;
+                       rp += c;
+                       c = 0;
+               }
+       }
+       Cp = cp;
+}
+
+
+static int     reelcount = 1;  /* used below and in chgreel() */
+
+/*     Change reel due to reaching end-of-media.
+       Keep trying to get a successful write before considering the
+       change-of-reel as successful.
+*/
+static
+int
+eomchgreel()
+{
+       int     rv;
+
+       while( 1 ) {
+               Output = chgreel(1, Output, 0);
+               rv = write(Output, Cbuf, Bufsize);
+               if( rv == Bufsize )
+                       return  rv;
+               if( rv == -1 )
+                       fperrno( "Unable to write this medium" );
+               else
+                       fperr( "Unable to write this medium: Premature EOF" );
+               (void) fprintf(stderr, "Try again.\n");
+               reelcount--;
+       }
+       /*NOTREACHED*/
+}
+
+
+static
+postml(namep, np)              /* linking funtion:  Postml() is called after */
+register char *namep, *np;     /* namep is created.  Postml() checks to see  */
+{                              /* if namep should be linked to np.  If so,   */
+                               /* postml() removes the independent instance  */
+       register i;             /* of namep and links namep to np.            */
+       static struct ml {
+               short   m_dev;
+               ushort  m_ino;
+               char    m_name[2];
+       } **ml = 0;
+       register struct ml      *mlp;
+       static unsigned mlsize = 0;
+       static unsigned mlinks = 0;
+       char            *lnamep;
+       int             ans;
+
+       if( !ml ) {
+               mlsize = LINKS;
+               ml = (struct ml **) malloc(mlsize * sizeof(struct ml));
+       }
+       else if( mlinks == mlsize ) {
+               mlsize += LINKS;
+               ml = (struct ml **) realloc((char *) ml,
+                   mlsize * sizeof(struct ml));
+       }
+       if (ml == NULL) {
+               fperr("Out of memory for links");
+               exit(2);
+       }
+       for(i = 0; i < mlinks; ++i) {
+               mlp = ml[i];
+               if(mlp->m_ino==Hdr.h_ino  &&  mlp->m_dev==Hdr.h_dev) {
+                       if(Verbose)
+                         printf("%s linked to %s\n", ml[i]->m_name,
+                               np);
+                       unlink(namep);
+                       if(Option == IN && *(mlp->m_name) != '/') {
+                               Fullname[Pathend] = '\0';
+                               strcat(Fullname, mlp->m_name);
+                               lnamep = Fullname;
+                       }
+                       lnamep = mlp->m_name;
+
+/* try linking (only twice) */
+                       ans = 0;
+                       do {
+                               if(link(lnamep, namep) < 0) {
+                                       ans += 1;
+                               }else {
+                                       ans = 0;
+                                       break;
+                               }
+                       }while(ans < 2 && missdir(np) == 0);
+                       if(ans == 1) {
+                               fperrno("Cannot create directory for <%s>", np);
+                               return(0);
+                       }else if(ans == 2) {
+                               fperrno("Cannot link <%s> & <%s>", lnamep, np);
+                               return(0);
+                       }
+
+                       set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
+                       return 0;
+               }
+       }
+       if( !(ml[mlinks] = (struct ml *)malloc(strlen(np) + 2 + sizeof(struct ml)))) {
+               static int first=1;
+
+               if(first)
+                       fperr("Out of memory for links");
+               first = 0;
+               return 1;
+       }
+       ml[mlinks]->m_dev = Hdr.h_dev;
+       ml[mlinks]->m_ino = Hdr.h_ino;
+       strcpy(ml[mlinks]->m_name, np);
+       ++mlinks;
+       return 1;
+}
+
+static
+pentry(namep)          /* print verbose table of contents */
+register char *namep;
+{
+       static short lastid = -1;
+       static struct passwd *pw;
+       static char tbuf[32];
+       char *ctime();
+
+       printf("%-7o", MK_USHORT(Hdr.h_mode));
+       if(lastid == Hdr.h_uid)
+               printf("%-6s", pw->pw_name);
+       else {
+               setpwent();
+               if(pw = getpwuid((int)Hdr.h_uid)) {
+                       printf("%-6s", pw->pw_name);
+                       lastid = Hdr.h_uid;
+               } else {
+                       printf("%-6d", Hdr.h_uid);
+                       lastid = -1;
+               }
+       }
+       printf("%7ld ", mklong(Hdr.h_filesize));
+       U.l = mklong(Hdr.h_mtime);
+       strcpy(tbuf, ctime((long *)&U.l));
+       tbuf[24] = '\0';
+       printf(" %s  %s", &tbuf[4], namep);
+       if (A_symlink)
+               printf(" -> %s", Symlbuf);
+       putchar('\n');
+}
+
+               /* pattern matching functions */
+static
+nmatch(s, pat)
+char *s, **pat;
+{
+       if( !pat )
+               return 1;
+       while(*pat) {
+               if((**pat == '!' && !gmatch(s, *pat+1))
+               || gmatch(s, *pat))
+                       return 1;
+               ++pat;
+       }
+       return 0;
+}
+
+
+static
+gmatch(s, p)
+register char *s, *p;
+{
+       register int c;
+       register cc, ok, lc, scc;
+
+       scc = *s;
+       lc = 077777;
+       switch (c = *p) {
+
+       case '[':
+               ok = 0;
+               while (cc = *++p) {
+                       switch (cc) {
+
+                       case ']':
+                               if (ok)
+                                       return(gmatch(++s, ++p));
+                               else
+                                       return(0);
+
+                       case '-':
+                               ok |= ((lc <= scc) && (scc <= (cc=p[1])));
+                       }
+                       if (scc==(lc=cc)) ok++;
+               }
+               return(0);
+
+       case '?':
+       caseq:
+               if(scc) return(gmatch(++s, ++p));
+               return(0);
+       case '*':
+               return(umatch(s, ++p));
+       case 0:
+               return(!scc);
+       }
+       if (c==scc) goto caseq;
+       return(0);
+}
+
+
+
+static
+umatch(s, p)
+register char *s, *p;
+{
+       if(*p==0) return(1);
+       while(*s)
+               if (gmatch(s++,p)) return(1);
+       return(0);
+}
+
+swap(buf, bytecount, bytes, halfwords) /* swap halfwords, bytes or both */
+char *buf;
+int bytecount;
+int bytes, halfwords;
+{
+       register int count;
+       int n, i;
+
+       if(bytes) {
+               register union swpbytes {
+                       short   shortw;
+                       char    charv[2];
+               } *pbuf;
+               register char c;
+
+               count = bytecount;
+               pbuf = (union swpbytes *)buf;
+               if (count % sizeof(union swpbytes))
+                       pbuf->charv[count] = 0;
+               count = (count + (sizeof(union swpbytes) - 1)) / sizeof(union swpbytes);
+               while (count--) {
+                       c = pbuf->charv[0];
+                       pbuf->charv[0] = pbuf->charv[1];
+                       pbuf->charv[1] = c;
+                       ++pbuf;
+               }
+       }
+       if (halfwords) {
+               register union swphalf {
+                       long    longw;
+                       short   shortv[2];
+                       char    charv[4];
+               } *pbuf;
+               register short cc;
+
+               count = bytecount;
+               pbuf = (union swphalf *)buf;
+               if (n = count % sizeof(union swphalf))
+                       if(bytes && n % 2)
+                               for(i = count + 1; i <= count + (sizeof(union swphalf) - n); i++)
+                                       pbuf->charv[i] = 0;
+                       else
+                               for (i = count; i < count + (sizeof(union swphalf) - n); i++)
+                                       pbuf->charv[i] = 0;
+               count = (count + (sizeof(union swphalf) - 1)) / sizeof(union swphalf);
+               while (count--) {
+                       cc = pbuf->shortv[0];
+                       pbuf->shortv[0] = pbuf->shortv[1];
+                       pbuf->shortv[1] = cc;
+                       ++pbuf;
+               }
+       }
+}
+
+
+static
+set_time(namep, atime, mtime)  /* set access and modification times */
+register char *namep;
+time_t atime, mtime;
+{
+       static struct utimbuf timevec;
+
+       if(!Mod_time)
+               return;
+       timevec.actime = atime;
+       timevec.modtime = mtime;
+       (void)utime(namep, &timevec);
+}
+
+
+
+static
+chgreel(x, fl, rv)
+       int x, fl, rv;
+{
+       register f;
+       char str[BUFSIZ];
+       struct stat statb;
+
+       fstat(fl, &statb);
+       if((statb.st_mode&S_IFMT) != S_IFCHR) {
+               fperrno("Can't %s: ", x? "write output": "read input");
+               exit(2);
+       }
+       if( rv == 0  ||
+               ( rv == -1  &&  ( errno == ENOSPC  ||  errno == ENXIO ) ) )
+               fperr( "\007Reached end of medium on %s",
+                       x? "output":"input" );
+       else {
+               fperrno( "\007Encountered an error on %s",
+                       x? "output":"input" );
+               exit(2);
+       }
+       if( Rtty == NULL ) {
+               Rtty = fopen(ttyname, "r");
+               if( Rtty == NULL ) {
+                       fperrno("Cannot prompt (can't open %s)", ttyname);
+                       exit(2);
+               }
+       }
+       close(fl);
+       reelcount++;
+again:
+       if( swfile ) {
+           askagain:
+               fperr( eommsg, reelcount );
+               fgets(str, sizeof str, Rtty);
+               switch( *str ) {
+               case '\n':
+                       strcpy( str, swfile );
+                       break;
+               case 'q':
+                       exit(2);
+               default:
+                       goto askagain;
+               }
+       }
+       else {
+               fperr("If you want to go on, type device/file name when ready.");
+               fgets(str, sizeof str, Rtty);
+               str[strlen(str) - 1] = '\0';
+               if(!*str)
+                       exit(2);
+       }
+       if((f = open(str, x? 1: 0)) < 0) {
+               fperrno("Can't open <%s>", str);
+               goto again;
+       }
+       return f;
+}
+
+
+
+static
+missdir(namep)
+register char *namep;
+{
+       register char *np;
+       register ct = 2;
+
+       for(np = namep; *np; ++np)
+               if(*np == '/') {
+                       if(np == namep) continue;       /* skip over 'root slash' */
+                       *np = '\0';
+                       if(stat(namep, &Xstatb) == -1) {
+                               if(Dir) {
+                                       if((ct = mkdir(namep, 0777)) != 0) {
+                                               *np = '/';
+                                               return(ct);
+                                       }
+                               }else {
+                                       fperr("missing 'd' option");
+                                       return(-1);
+                               }
+                       }
+                       *np = '/';
+               }
+       if (ct == 2) ct = 0;            /* the file already exists */
+       return ct;
+}
+
+
+
+static
+pwd()          /* get working directory */
+{
+       if (getwd(Fullname) == 0) {
+               (void)fprintf(stderr, "cpio: %s\n",
+                   Fullname);
+               exit(2);
+       }
+       Pathend = strlen(Fullname);
+       Fullname[Pathend++] = '/';
+       Fullname[Pathend] = '\0';
+}
+
+
+/*
+       print message on the stderr
+*/
+static
+fperr( va_alist )
+va_dcl
+{
+       va_list args;
+       char    *fmt;
+
+       va_start( args );
+       fprintf( stderr, "cpio: ");
+       fmt = va_arg( args, char * );
+       vfprintf( stderr, fmt, args );
+       putc( '\n', stderr);
+       fflush( stderr );
+}
+
+/*
+       print message on the stderr followed by error number and meaning.
+*/
+static
+fperrno( va_alist )
+va_dcl
+{
+       va_list args;
+       char    *fmt;
+
+       va_start( args );
+       fprintf( stderr, "cpio: ");
+       fmt = va_arg( args, char * );
+       vfprintf( stderr, fmt, args );
+       fprintf( stderr, ": " );
+       fflush( stderr );
+       perror("");
+}
+
+
+/*     Safe memory copy.
+       Fast if the to and from strings do not overlap,
+       slower but safe if they do.
+*/
+
+static char *
+smemcpy( to, from, count )
+register char          *to, *from;
+register unsigned      count;
+{
+       char    *savedto;
+
+       if( &to[ count ] <= from  ||  &from[ count ] <= to )
+               return  memcpy( to, from, count );
+
+       if( to == from )
+               return  to;
+
+       savedto = to;
+       if( to < from )
+               while( count-- )
+                       *(to++) = *(from++);
+       else {
+               to += count;
+               from += count;
+               while( count-- )
+                       *(--to) = *(--from);
+       }
+
+       return  savedto;
+}