home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / utils / unix / pdtar / part0~ca < prev    next >
Encoding:
Text File  |  1988-09-11  |  37.1 KB  |  1,641 lines

  1. Subject:  v12i070:  Public-domain TAR, Part03/03
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rs@uunet.UU.NET
  5.  
  6. Submitted-by: John Gilmore <hoptoad!gnu@UUNET.UU.NET>
  7. Posting-number: Volume 12, Issue 70
  8. Archive-name: pdtar/part03
  9.  
  10. : To unbundle, sh this file
  11. echo list.c
  12. cat >list.c <<'@@@ Fin de list.c'
  13. /*
  14.  * List a tar archive.
  15.  *
  16.  * Also includes support routines for reading a tar archive.
  17.  *
  18.  * Pubic Domain version written 26 Aug 1985 by John Gilmore (ihnp4!hoptoad!gnu).
  19.  *
  20.  * @(#)list.c 1.31 11/5/87 Public Domain - gnu
  21.  */
  22. #include <stdio.h>
  23. #include <ctype.h>
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #ifndef    MSDOS
  27. #include <sys/file.h>
  28. #endif    /* MSDOS */
  29.  
  30. #ifdef USG
  31. #include <sys/sysmacros.h>    /* major() and minor() defined here */
  32. #endif
  33.  
  34. char *ctime();                /* From libc.a */
  35.  
  36. #define    isodigit(c)    ( ((c) >= '0') && ((c) <= '7') )
  37.  
  38. #include "tar.h"
  39. #include "port.h"
  40.  
  41. long from_oct();            /* Decode octal number */
  42. void demode();                /* Print file mode */
  43.  
  44. union record *head;            /* Points to current archive header */
  45. struct stat hstat;            /* Stat struct corresponding */
  46. int head_standard;            /* Tape header is in ANSI format */
  47.  
  48. void print_header();
  49. void skip_file();
  50.  
  51.  
  52. /*
  53.  * Main loop for reading an archive.
  54.  */
  55. void
  56. read_and(do_something)
  57.     void (*do_something)();
  58. {
  59.     int status = 3;            /* Initial status at start of archive */
  60.     int prev_status;
  61.  
  62.     name_gather();            /* Gather all the names */
  63.     open_archive(1);        /* Open for reading */
  64.  
  65.     for(;;) {
  66.         prev_status = status;
  67.         status = read_header();
  68.         switch (status) {
  69.  
  70.         case 1:            /* Valid header */
  71.             /* We should decode next field (mode) first... */
  72.             /* Ensure incoming names are null terminated. */
  73.             head->header.name[NAMSIZ-1] = '\0';
  74.             
  75.             if (!name_match(head->header.name)) {
  76.                 /* Skip past it in the archive */
  77.                 userec(head);
  78.                 /* Skip to the next header on the archive */
  79.                 skip_file((long)hstat.st_size);
  80.                 continue;
  81.             }
  82.  
  83.             (*do_something)();
  84.             continue;
  85.  
  86.             /*
  87.              * If the previous header was good, tell them
  88.              * that we are skipping bad ones.
  89.              */
  90.         case 0:            /* Invalid header */
  91.             userec(head);
  92.             switch (prev_status) {
  93.             case 3:        /* Error on first record */
  94.                 annorec(stderr, tar);
  95.                 fprintf(stderr,
  96.                 "Hmm, this doesn't look like a tar archive.\n");
  97.                 /* FALL THRU */
  98.             case 2:        /* Error after record of zeroes */
  99.             case 1:        /* Error after header rec */
  100.                 annorec(stderr, tar);
  101.                 fprintf(stderr,
  102.                     "Skipping to next file header...\n");
  103.             case 0:        /* Error after error */
  104.                 break;
  105.             }
  106.             continue;
  107.  
  108.         case 2:            /* Record of zeroes */
  109.             userec(head);
  110.             status = prev_status;    /* If error after 0's */
  111.             if (f_ignorez)    
  112.                 continue;
  113.             /* FALL THRU */
  114.         case EOF:        /* End of archive */
  115.             break;
  116.         }
  117.         break;
  118.     };
  119.  
  120.     close_archive();
  121.     names_notfound();        /* Print names not found */
  122. }        
  123.  
  124.  
  125. /*
  126.  * Print a header record, based on tar options.
  127.  */
  128. void
  129. list_archive()
  130. {
  131.  
  132.     /* Save the record */
  133.     saverec(&head);
  134.  
  135.     /* Print the header record */
  136.     if (f_verbose) {
  137.         if (f_verbose > 1)
  138.             decode_header(head, &hstat, &head_standard, 0);
  139.         print_header(stdout);
  140.     }
  141.  
  142.     /* Skip past it in the archive */
  143.     saverec((union record **) 0);    /* Unsave it */
  144.     userec(head);
  145.  
  146.     /* Skip to the next header on the archive */
  147.     skip_file((long)hstat.st_size);
  148. }
  149.  
  150.  
  151. /*
  152.  * Read a record that's supposed to be a header record.
  153.  * Return its address in "head", and if it is good, the file's
  154.  * size in hstat.st_size.
  155.  *
  156.  * Return 1 for success, 0 if the checksum is bad, EOF on eof,
  157.  * 2 for a record full of zeros (EOF marker).
  158.  *
  159.  * You must always userec(head) to skip past the header which this
  160.  * routine reads.
  161.  */
  162. int
  163. read_header()
  164. {
  165.     register int    i;
  166.     register long    sum, recsum;
  167.     register char    *p;
  168.     register union record *header;
  169.  
  170.     header = findrec();
  171.     head = header;        /* This is our current header */
  172.     if (NULL == header) return EOF;
  173.  
  174.     recsum = from_oct(8,  header->header.chksum);
  175.  
  176.     sum = 0;
  177.     p = header->charptr;
  178.     for (i = sizeof(*header); --i >= 0;) {
  179.         /*
  180.          * We can't use unsigned char here because of old compilers,
  181.          * e.g. V7.
  182.          */
  183.         sum += 0xFF & *p++;
  184.     }
  185.  
  186.     /* Adjust checksum to count the "chksum" field as blanks. */
  187.     for (i = sizeof(header->header.chksum); --i >= 0;)
  188.         sum -= 0xFF & header->header.chksum[i];
  189.     sum += ' '* sizeof header->header.chksum;    
  190.  
  191.     if (sum == recsum) {
  192.         /*
  193.          * Good record.  Decode file size and return.
  194.          */
  195.         if (header->header.linkflag == LF_LINK)
  196.             hstat.st_size = 0;    /* Links 0 size on tape */
  197.         else
  198.             hstat.st_size = from_oct(1+12, header->header.size);
  199.         return 1;
  200.     }
  201.  
  202.     if (sum == 8*' ') {
  203.         /*
  204.          * This is a zeroed record...whole record is 0's except
  205.          * for the 8 blanks we faked for the checksum field.
  206.          */
  207.         return 2;
  208.     }
  209.  
  210.     return 0;
  211. }
  212.  
  213.  
  214. /* 
  215.  * Decode things from a file header record into a "struct stat".
  216.  * Also set "*stdp" to !=0 or ==0 depending whether header record is "Unix
  217.  * Standard" tar format or regular old tar format.
  218.  *
  219.  * read_header() has already decoded the checksum and length, so we don't.
  220.  *
  221.  * If wantug != 0, we want the uid/group info decoded from Unix Standard
  222.  * tapes (for extraction).  If == 0, we are just printing anyway, so save time.
  223.  *
  224.  * decode_header should NOT be called twice for the same record, since the
  225.  * two calls might use different "wantug" values and thus might end up with
  226.  * different uid/gid for the two calls.  If anybody wants the uid/gid they
  227.  * should decode it first, and other callers should decode it without uid/gid
  228.  * before calling a routine, e.g. print_header, that assumes decoded data.
  229.  */
  230. decode_header(header, st, stdp, wantug)
  231.     register union record    *header;
  232.     register struct stat    *st;
  233.     int    *stdp;
  234.     int    wantug;
  235. {
  236.  
  237.     st->st_mode = from_oct(8,  header->header.mode);
  238.     st->st_mtime = from_oct(1+12, header->header.mtime);
  239.     
  240.     if (0==strcmp(header->header.magic, TMAGIC)) {
  241.         /* Unix Standard tar archive */
  242.         *stdp = 1;
  243.         if (wantug) {
  244. #ifdef NONAMES
  245.             st->st_uid = from_oct(8,  header->header.uid);
  246.             st->st_gid = from_oct(8,  header->header.gid);
  247. #else
  248.             st->st_uid = finduid(header->header.uname);
  249.             st->st_gid = findgid(header->header.gname);
  250. #endif
  251.         }
  252.         switch  (header->header.linkflag) 
  253.         case LF_BLK: case LF_CHR:
  254.             st->st_rdev = makedev(from_oct(8, header->header.devmajor),
  255.                        from_oct(8, header->header.devminor));
  256.     } else {
  257.         /* Old fashioned tar archive */
  258.         *stdp = 0;
  259.         st->st_uid = from_oct(8,  header->header.uid);
  260.         st->st_gid = from_oct(8,  header->header.gid);
  261.         st->st_rdev = 0;
  262.     }
  263. }
  264.  
  265.  
  266. /*
  267.  * Quick and dirty octal conversion.
  268.  *
  269.  * Result is -1 if the field is invalid (all blank, or nonoctal).
  270.  */
  271. long
  272. from_oct(digs, where)
  273.     register int    digs;
  274.     register char    *where;
  275. {
  276.     register long    value;
  277.  
  278.     while (isspace(*where)) {        /* Skip spaces */
  279.         where++;
  280.         if (--digs <= 0)
  281.             return -1;        /* All blank field */
  282.     }
  283.     value = 0;
  284.     while (digs > 0 && isodigit(*where)) {    /* Scan til nonoctal */
  285.         value = (value << 3) | (*where++ - '0');
  286.         --digs;
  287.     }
  288.  
  289.     if (digs > 0 && *where && !isspace(*where))
  290.         return -1;            /* Ended on non-space/nul */
  291.  
  292.     return value;
  293. }
  294.  
  295.  
  296. /*
  297.  * Actually print it.
  298.  *
  299.  * Plain and fancy file header block logging.
  300.  * Non-verbose just prints the name, e.g. for "tar t" or "tar x".
  301.  * This should just contain file names, so it can be fed back into tar
  302.  * with xargs or the "-T" option.  The verbose option can give a bunch
  303.  * of info, one line per file.  I doubt anybody tries to parse its
  304.  * format, or if they do, they shouldn't.  Unix tar is pretty random here
  305.  * anyway.
  306.  *
  307.  * Note that print_header uses the globals <head>, <hstat>, and
  308.  * <head_standard>, which must be set up in advance.  This is not very clean
  309.  * and should be cleaned up.  FIXME.
  310.  */
  311. #define    UGSWIDTH    11        /* min width of User, group, size */
  312. #define    DATEWIDTH    19        /* Last mod date */
  313. static int    ugswidth = UGSWIDTH;    /* Max width encountered so far */
  314.  
  315. void
  316. print_header(outfile)
  317.     FILE *outfile;
  318. {
  319.     char modes[11];
  320.     char *timestamp;
  321.     char uform[11], gform[11];    /* These hold formatted ints */
  322.     char *user, *group;
  323.     char size[24];        /* Holds a formatted long or maj, min */
  324.     long longie;        /* To make ctime() call portable */
  325.     int    pad;
  326.  
  327.     annofile(outfile, (char *)NULL);
  328.  
  329.     if (f_verbose <= 1) {
  330.         /* Just the fax, mam. */
  331.         fprintf(outfile, "%s\n", head->header.name);
  332.         return;
  333.     } else {
  334.         /* File type and modes */
  335.         modes[0] = '?';
  336.         switch (head->header.linkflag) {
  337.         case LF_NORMAL:
  338.         case LF_OLDNORMAL:
  339.         case LF_LINK:
  340.                 modes[0] = '-'; 
  341.                 if ('/' == head->header.name[strlen(head->header.name)-1])
  342.                     modes[0] = 'd';
  343.                 break;
  344.         case LF_DIR:    modes[0] = 'd'; break;
  345.         case LF_SYMLINK:modes[0] = 'l'; break;
  346.         case LF_BLK:    modes[0] = 'b'; break;
  347.         case LF_CHR:    modes[0] = 'c'; break;
  348.         case LF_FIFO:    modes[0] = 'p'; break;    
  349.         case LF_CONTIG:    modes[0] = 'C'; break;
  350.         }
  351.  
  352.         demode((unsigned)hstat.st_mode, modes+1);
  353.  
  354.         /* Timestamp */
  355.         longie = hstat.st_mtime;
  356.         timestamp = ctime(&longie);
  357.         timestamp[16] = '\0';
  358.         timestamp[24] = '\0';
  359.  
  360.         /* User and group names */
  361.         if (*head->header.uname && head_standard) {
  362.             user  = head->header.uname;
  363.         } else {
  364.             user = uform;
  365.             (void)sprintf(uform, "%d", (int)hstat.st_uid);
  366.         }
  367.         if (*head->header.gname && head_standard) {
  368.             group = head->header.gname;
  369.         } else {
  370.             group = gform;
  371.             (void)sprintf(gform, "%d", (int)hstat.st_gid);
  372.         }
  373.  
  374.         /* Format the file size or major/minor device numbers */
  375.         switch (head->header.linkflag) {
  376.         case LF_CHR:
  377.         case LF_BLK:
  378.             (void)sprintf(size, "%d,%d",
  379.                     major(hstat.st_rdev),
  380.                     minor(hstat.st_rdev));
  381.             break;
  382.  
  383.         default:
  384.             (void)sprintf(size, "%ld", (long)hstat.st_size);
  385.         }
  386.  
  387.         /* Figure out padding and print the whole line. */
  388.         pad = strlen(user) + strlen(group) + strlen(size) + 1;
  389.         if (pad > ugswidth) ugswidth = pad;
  390.  
  391.         fprintf(outfile, "%s %s/%s %*s%s %s %s %.*s",
  392.             modes,
  393.             user,
  394.             group,
  395.             ugswidth - pad,
  396.             "",
  397.             size,
  398.             timestamp+4, timestamp+20,
  399.             sizeof(head->header.name),
  400.             head->header.name);
  401.  
  402.         switch (head->header.linkflag) {
  403.         case LF_SYMLINK:
  404.             fprintf(outfile, " -> %s\n", head->header.linkname);
  405.             break;
  406.  
  407.         case LF_LINK:
  408.             fprintf(outfile, " link to %s\n", head->header.linkname);
  409.             break;
  410.  
  411.         default:
  412.             fprintf(outfile, " unknown file type '%c'\n",
  413.                 head->header.linkflag);
  414.             break;
  415.  
  416.         case LF_OLDNORMAL:
  417.         case LF_NORMAL:
  418.         case LF_CHR:
  419.         case LF_BLK:
  420.         case LF_DIR:
  421.         case LF_FIFO:
  422.         case LF_CONTIG:
  423.             putc('\n', outfile);
  424.             break;
  425.         }
  426.     }
  427. }
  428.  
  429. /*
  430.  * Print a similar line when we make a directory automatically.
  431.  */
  432. void
  433. pr_mkdir(pathname, length, mode, outfile)
  434.     char *pathname;
  435.     int length;
  436.     int mode;
  437.     FILE *outfile;
  438. {
  439.     char modes[11];
  440.  
  441.     if (f_verbose > 1) {
  442.         /* File type and modes */
  443.         modes[0] = 'd';
  444.         demode((unsigned)mode, modes+1);
  445.  
  446.         annofile(outfile, (char *)NULL);
  447.         fprintf(outfile, "%s %*s %.*s\n",
  448.             modes,
  449.             ugswidth+DATEWIDTH,
  450.             "Creating directory:",
  451.             length,
  452.             pathname);
  453.     }
  454. }
  455.  
  456.  
  457. /*
  458.  * Skip over <size> bytes of data in records in the archive.
  459.  */
  460. void
  461. skip_file(size)
  462.     register long size;
  463. {
  464.     union record *x;
  465.  
  466.     while (size > 0) {
  467.         x = findrec();
  468.         if (x == NULL) {    /* Check it... */
  469.             annorec(stderr, tar);
  470.             fprintf(stderr, "Unexpected EOF on archive file\n");
  471.             exit(EX_BADARCH);
  472.         }
  473.         userec(x);
  474.         size -= RECORDSIZE;
  475.     }
  476. }
  477.  
  478.  
  479. /*
  480.  * Decode the mode string from a stat entry into a 9-char string and a null.
  481.  */
  482. void
  483. demode(mode, string)
  484.     register unsigned mode;
  485.     register char *string;
  486. {
  487.     register unsigned mask;
  488.     register char *rwx = "rwxrwxrwx";
  489.  
  490.     for (mask = 0400; mask != 0; mask >>= 1) {
  491.         if (mode & mask)
  492.             *string++ = *rwx++;
  493.         else {
  494.             *string++ = '-';
  495.             rwx++;
  496.         }
  497.     }
  498.  
  499.     if (mode & S_ISUID)
  500.         if (string[-7] == 'x')
  501.             string[-7] = 's';
  502.         else
  503.             string[-7] = 'S';
  504.     if (mode & S_ISGID)
  505.         if (string[-4] == 'x')
  506.             string[-4] = 's';
  507.         else
  508.             string[-4] = 'S';
  509.     if (mode & S_ISVTX)
  510.         if (string[-1] == 'x')
  511.             string[-1] = 't';
  512.         else
  513.             string[-1] = 'T';
  514.     *string = '\0';
  515. }
  516. @@@ Fin de list.c
  517. echo names.c
  518. cat >names.c <<'@@@ Fin de names.c'
  519. /*
  520.  * Look up user and/or group names.
  521.  *
  522.  * This file should be modified for non-unix systems to do something
  523.  * reasonable.
  524.  *
  525.  * @(#)names.c 1.3 10/30/87 Public Domain - gnu
  526.  */ 
  527. #include <sys/types.h>
  528. #include "tar.h"
  529.  
  530. extern    char    *strncpy();
  531.  
  532. #ifndef NONAMES
  533. /* Whole module goes away if NONAMES defined.  Otherwise... */
  534. #include <pwd.h>
  535. #include <grp.h>
  536.  
  537. static int    saveuid = -993;
  538. static char    saveuname[TUNMLEN];
  539. static int    my_uid = -993;
  540.  
  541. static int    savegid = -993;
  542. static char    savegname[TGNMLEN];
  543. static int    my_gid = -993;
  544.  
  545. #define myuid    ( my_uid < 0? (my_uid = getuid()): my_uid )
  546. #define    mygid    ( my_gid < 0? (my_gid = getgid()): my_gid )
  547.  
  548. /*
  549.  * Look up a user or group name from a uid/gid, maintaining a cache.
  550.  * FIXME, for now it's a one-entry cache.
  551.  * FIXME2, the "-993" is to reduce the chance of a hit on the first lookup.
  552.  *
  553.  * This is ifdef'd because on Suns, it drags in about 38K of "yellow
  554.  * pages" code, roughly doubling the program size.  Thanks guys.
  555.  */
  556. void
  557. finduname(uname, uid)
  558.     char    uname[TUNMLEN];
  559.     int    uid;
  560. {
  561.     struct passwd    *pw;
  562.     extern struct passwd *getpwuid ();
  563.  
  564.     if (uid != saveuid) {
  565.         saveuid = uid;
  566.         saveuname[0] = '\0';
  567.         pw = getpwuid(uid); 
  568.         if (pw) 
  569.             strncpy(saveuname, pw->pw_name, TUNMLEN);
  570.     }
  571.     strncpy(uname, saveuname, TUNMLEN);
  572. }
  573.  
  574. int
  575. finduid(uname)
  576.     char    uname[TUNMLEN];
  577. {
  578.     struct passwd    *pw;
  579.     extern struct passwd *getpwnam();
  580.  
  581.     if (uname[0] != saveuname[0]    /* Quick test w/o proc call */
  582.         || 0!=strncmp(uname, saveuname, TUNMLEN)) {
  583.         strncpy(saveuname, uname, TUNMLEN);
  584.         pw = getpwnam(uname); 
  585.         if (pw) {
  586.             saveuid = pw->pw_uid;
  587.         } else {
  588.             saveuid = myuid;
  589.         }
  590.     }
  591.     return saveuid;
  592. }
  593.  
  594.  
  595. void
  596. findgname(gname, gid)
  597.     char    gname[TGNMLEN];
  598.     int    gid;
  599. {
  600.     struct group    *gr;
  601.     extern struct group *getgrgid ();
  602.  
  603.     if (gid != savegid) {
  604.         savegid = gid;
  605.         savegname[0] = '\0';
  606.         (void)setgrent();
  607.         gr = getgrgid(gid); 
  608.         if (gr) 
  609.             strncpy(savegname, gr->gr_name, TGNMLEN);
  610.     }
  611.     (void) strncpy(gname, savegname, TGNMLEN);
  612. }
  613.  
  614.  
  615. int
  616. findgid(gname)
  617.     char    gname[TUNMLEN];
  618. {
  619.     struct group    *gr;
  620.     extern struct group *getgrnam();
  621.  
  622.     if (gname[0] != savegname[0]    /* Quick test w/o proc call */
  623.         || 0!=strncmp(gname, savegname, TUNMLEN)) {
  624.         strncpy(savegname, gname, TUNMLEN);
  625.         gr = getgrnam(gname); 
  626.         if (gr) {
  627.             savegid = gr->gr_gid;
  628.         } else {
  629.             savegid = mygid;
  630.         }
  631.     }
  632.     return savegid;
  633. }
  634. #endif
  635. @@@ Fin de names.c
  636. echo diffarch.c
  637. cat >diffarch.c <<'@@@ Fin de diffarch.c'
  638. /*
  639.  * Diff files from a tar archive.
  640.  *
  641.  * Written 30 April 1987 by John Gilmore, ihnp4!hoptoad!gnu.
  642.  *
  643.  * @(#) diffarch.c 1.10 87/11/11 Public Domain - gnu
  644.  */
  645.  
  646. #include <stdio.h>
  647. #include <errno.h>
  648. #include <sys/types.h>
  649. #include <sys/stat.h>
  650.  
  651. #ifdef BSD42
  652. #include <sys/file.h>
  653. #endif
  654.  
  655. #ifdef USG
  656. #include <fcntl.h>
  657. #endif
  658.  
  659. /* Some systems don't have these #define's -- we fake it here. */
  660. #ifndef O_RDONLY
  661. #define    O_RDONLY    0
  662. #endif
  663. #ifndef    O_NDELAY
  664. #define    O_NDELAY    0
  665. #endif
  666.  
  667. extern int errno;            /* From libc.a */
  668. extern char *valloc();            /* From libc.a */
  669.  
  670. #include "tar.h"
  671. #include "port.h"
  672.  
  673. extern union record *head;        /* Points to current tape header */
  674. extern struct stat hstat;        /* Stat struct corresponding */
  675. extern int head_standard;        /* Tape header is in ANSI format */
  676.  
  677. extern void print_header();
  678. extern void skip_file();
  679.  
  680. char *filedata;                /* Pointer to area for reading
  681.                        file contents into */
  682.  
  683. /*
  684.  * Initialize for a diff operation
  685.  */
  686. diff_init()
  687. {
  688.  
  689.     /*NOSTRICT*/
  690.     filedata = (char *) valloc((unsigned)blocksize);
  691.     if (!filedata) {
  692.         fprintf(stderr,
  693.         "tar: could not allocate memory for diff buffer of %d bytes\n",
  694.             blocking);
  695.         exit(EX_ARGSBAD);
  696.     }
  697. }
  698.  
  699. /*
  700.  * Diff a file against the archive.
  701.  */
  702. void
  703. diff_archive()
  704. {
  705.     register char *data;
  706.     int fd, check, namelen, written;
  707.     int err, firsttime;
  708.     long size;
  709.     struct stat filestat;
  710.     char linkbuf[NAMSIZ+3];
  711.  
  712.     errno = EPIPE;            /* FIXME, remove perrors */
  713.  
  714.     saverec(&head);            /* Make sure it sticks around */
  715.     userec(head);            /* And go past it in the archive */
  716.     decode_header(head, &hstat, &head_standard, 1);    /* Snarf fields */
  717.  
  718.     /* Print the record from 'head' and 'hstat' */
  719.     if (f_verbose)
  720.         print_header(stdout);
  721.  
  722.     switch (head->header.linkflag) {
  723.  
  724.     default:
  725.         annofile(stderr, tar);
  726.         fprintf(stderr,
  727.            "Unknown file type '%c' for %s, diffed as normal file\n",
  728.             head->header.linkflag, head->header.name);
  729.         /* FALL THRU */
  730.  
  731.     case LF_OLDNORMAL:
  732.     case LF_NORMAL:
  733.     case LF_CONTIG:
  734.         /*
  735.          * Appears to be a file.
  736.          * See if it's really a directory.
  737.          */
  738.         namelen = strlen(head->header.name)-1;
  739.         if (head->header.name[namelen] == '/')
  740.             goto really_dir;
  741.  
  742.         fd = open(head->header.name, O_NDELAY|O_RDONLY);
  743.  
  744.         if (fd < 0) {
  745.             if (errno == ENOENT) {
  746.                 /* Expected error -- to stdout */
  747.                 annofile(stdout, (char *)NULL);
  748.                 fprintf(stdout, "%s: does not exist\n",
  749.                     head->header.name);
  750.             } else {
  751.                 annofile(stderr, (char *)NULL);
  752.                 perror(head->header.name);
  753.             }
  754.             skip_file((long)hstat.st_size);
  755.             goto quit;
  756.         }
  757.  
  758.         err = fstat(fd, &filestat);
  759.         if (err < 0) {
  760.             annofile(stdout, (char *)NULL);
  761.             fprintf(stdout, "Cannot fstat file ");
  762.             perror(head->header.name);
  763.             skip_file((long)hstat.st_size);
  764.             goto qclose;
  765.         }
  766.  
  767.         if ((filestat.st_mode & S_IFMT) != S_IFREG) {
  768.             annofile(stdout, (char *)NULL);
  769.             fprintf(stdout, "%s: not a regular file\n",
  770.                 head->header.name);
  771.             skip_file((long)hstat.st_size);
  772.             goto qclose;
  773.         }
  774.  
  775.         filestat.st_mode &= ~S_IFMT;
  776.         if (filestat.st_mode != hstat.st_mode)
  777.             sigh("mode");
  778.         if (filestat.st_uid  != hstat.st_uid)
  779.             sigh("uid");
  780.         if (filestat.st_gid  != hstat.st_gid)
  781.             sigh("gid");
  782.         if (filestat.st_size != hstat.st_size) {
  783.             sigh("size");
  784.             skip_file((long)hstat.st_size);
  785.             goto qclose;
  786.         }
  787.         if (filestat.st_mtime != hstat.st_mtime)
  788.             sigh("mod time");
  789.  
  790.         firsttime = 0;
  791.  
  792.         for (size = hstat.st_size;
  793.              size > 0;
  794.              size -= written) {
  795.             /*
  796.              * Locate data, determine max length
  797.              * writeable, write it, record that
  798.              * we have used the data, then check
  799.              * if the write worked.
  800.              */
  801.             data = findrec()->charptr;
  802.             if (data == NULL) {    /* Check it... */
  803.                 annorec(stderr, tar);
  804.                 fprintf(stderr, "Unexpected EOF on archive file\n");
  805.                 break;
  806.             }
  807.             written = endofrecs()->charptr - data;
  808.             if (written > size) written = size;
  809.             errno = 0;
  810.             check = read (fd, filedata, written);
  811.             /*
  812.              * The following is in violation of strict
  813.              * typing, since the arg to userec
  814.              * should be a struct rec *.  FIXME.
  815.              */
  816.             userec(data + written - 1);
  817.             if (check == written) {
  818.                 /* The read worked, now compare the data */
  819.                 if (bcmp(data, filedata, check) == 0)
  820.                     continue;    /* It compares */
  821.                 if (firsttime++) {
  822.                     annofile(stdout, (char *)NULL);
  823.                     fprintf(stdout, "%s: data differs\n",
  824.                         head->header.name);
  825.                 }
  826.             }
  827.  
  828.             /*
  829.              * Error in reading from file.
  830.              * Print it, skip to next file in archive.
  831.              */
  832.             annofile(stderr, tar);
  833.             fprintf(stderr,
  834.     "Tried to read %d bytes from file, could only read %d:\n",
  835.                 written, check);
  836.             perror(head->header.name);
  837.             skip_file((long)(size - written));
  838.             break;    /* Still do the close, mod time, chmod, etc */
  839.         }
  840.  
  841.     qclose:
  842.         check = close(fd);
  843.         if (check < 0) {
  844.             annofile(stderr, tar);
  845.             fprintf(stderr, "Error while closing ");
  846.             perror(head->header.name);
  847.         }
  848.         
  849.     quit:
  850.         break;
  851.  
  852.     case LF_LINK:
  853.         check = 1;    /* FIXME deal with this */
  854.         /* check = link (head->header.linkname,
  855.                   head->header.name); */
  856.         /* FIXME, don't worry uid, gid, etc... */
  857.         if (check == 0)
  858.             break;
  859.         annofile(stderr, tar);
  860.         fprintf(stderr, "Could not link %s to ",
  861.             head->header.name);
  862.         perror(head->header.linkname);
  863.         break;
  864.  
  865. #ifdef S_IFLNK
  866.     case LF_SYMLINK:
  867.         check = readlink(head->header.name, linkbuf,
  868.                  (sizeof linkbuf)-1);
  869.         
  870.         if (check < 0) {
  871.             if (errno == ENOENT) {
  872.                 annofile(stdout, (char *)NULL);
  873.                 fprintf(stdout,
  874.                     "%s: no such file or directory\n",
  875.                     head->header.name);
  876.             } else {
  877.                 annofile(stderr, tar);
  878.                 fprintf(stderr, "Could not read link");
  879.                 perror(head->header.name);
  880.             }
  881.             break;
  882.         }
  883.  
  884.         linkbuf[check] = '\0';    /* Null-terminate it */
  885.         if (strncmp(head->header.linkname, linkbuf, check) != 0) {
  886.             annofile(stdout, (char *)NULL);
  887.             fprintf(stdout, "%s: symlink differs\n",
  888.                 head->header.linkname);
  889.         }
  890.         break;
  891. #endif
  892.  
  893.     case LF_CHR:
  894.         hstat.st_mode |= S_IFCHR;
  895.         goto make_node;
  896.  
  897. #ifdef S_IFBLK
  898.     /* If local system doesn't support block devices, use default case */
  899.     case LF_BLK:
  900.         hstat.st_mode |= S_IFBLK;
  901.         goto make_node;
  902. #endif
  903.  
  904. #ifdef S_IFIFO
  905.     /* If local system doesn't support FIFOs, use default case */
  906.     case LF_FIFO:
  907.         hstat.st_mode |= S_IFIFO;
  908.         hstat.st_rdev = 0;        /* FIXME, do we need this? */
  909.         goto make_node;
  910. #endif
  911.  
  912.     make_node:
  913.         /* FIXME, deal with umask */
  914.         
  915.         check = 1; /* FIXME, implement this */
  916.         /* check = mknod(head->header.name, (int) hstat.st_mode,
  917.             (int) hstat.st_rdev); */
  918.         if (check != 0) {
  919.             annofile(stderr, tar);
  920.             fprintf(stderr, "Could not make ");
  921.             perror(head->header.name);
  922.             break;
  923.         };
  924.         break;
  925.  
  926.     case LF_DIR:
  927.         /* Check for trailing / */
  928.         namelen = strlen(head->header.name)-1;
  929.     really_dir:
  930.         while (namelen && head->header.name[namelen] == '/')
  931.             head->header.name[namelen--] = '\0';    /* Zap / */
  932.         
  933.         check = 1; /* FIXME, implement this */
  934.         /* check = mkdir(head->header.name, 0300 | (int)hstat.st_mode); */
  935.         if (check != 0) {
  936.             annofile(stderr, tar);
  937.             fprintf(stderr, "Could not make directory ");
  938.             perror(head->header.name);
  939.             break;
  940.         }
  941.         
  942.         break;
  943.  
  944.     }
  945.  
  946.     /* We don't need to save it any longer. */
  947.     saverec((union record **) 0);    /* Unsave it */
  948. }
  949.  
  950. /*
  951.  * Sigh about something that differs.
  952.  */
  953. sigh(what)
  954.     char *what;
  955. {
  956.  
  957.     annofile(stdout, (char *)NULL);
  958.     fprintf(stdout, "%s: %s differs\n",
  959.         head->header.name, what);
  960. }
  961. @@@ Fin de diffarch.c
  962. echo port.c
  963. cat >port.c <<'@@@ Fin de port.c'
  964. /*
  965.  * @(#)port.c 1.15    87/11/05    Public Domain, by John Gilmore, 1986
  966.  *
  967.  * These are routines not available in all environments.
  968.  *
  969.  * I know this introduces an extra level of subroutine calls and is
  970.  * slightly slower.  Frankly, my dear, I don't give a damn.  Let the
  971.  * Missed-Em Vee losers suffer a little.  This software is proud to
  972.  * have been written on a BSD system.
  973.  */
  974. #include <stdio.h>
  975. #include <sys/types.h>
  976. #include <sys/stat.h>
  977. #include <signal.h>
  978. #include <errno.h>
  979.  
  980. #ifdef    MSDOS
  981. #include <fcntl.h>
  982. #else
  983. #include <sys/file.h>
  984. #endif
  985.  
  986. #include "tar.h"
  987.  
  988. extern char **environ;
  989.  
  990. #ifndef NULL
  991. #define NULL 0
  992. #endif
  993.  
  994. /*
  995.  * Some people (e.g. V7) don't have a #define for these.
  996.  */
  997. #ifndef    O_BINARY
  998. #define    O_BINARY    0
  999. #endif
  1000. #ifndef    O_RDONLY
  1001. #define    O_RDONLY    0
  1002. #endif
  1003.  
  1004.  
  1005. #include "port.h"
  1006.  
  1007.  
  1008. /*
  1009.  * Some computers are not so crass as to align themselves into the BSD
  1010.  * or USG camps.  If a system supplies all of the routines we fake here,
  1011.  * add it to the list in the #ifndefs below and it'll all be skipped.
  1012.  * Make sure to add a matching #endif at the end of the file!
  1013.  *
  1014.  * We are avoiding #if defined() here for the sake of Minix, which comes
  1015.  * with the severely broken Amsterdam Compiler Kit.  Thanks, Andy!
  1016.  */
  1017. #ifndef mc300
  1018. #ifndef mc500
  1019. #ifndef mc700
  1020.  
  1021.  
  1022. #ifndef BSD42
  1023. /*
  1024.  * lstat() is a stat() which does not follow symbolic links.
  1025.  * If there are no symbolic links, just use stat().
  1026.  */
  1027. int
  1028. lstat (path, buf)
  1029.     char *path;
  1030.     struct stat *buf;
  1031. {
  1032.     extern int stat ();
  1033.     return (stat (path, buf));
  1034. }
  1035.  
  1036. /*
  1037.  * valloc() does a malloc() on a page boundary.  On some systems,
  1038.  * this can make large block I/O more efficient.
  1039.  */
  1040. char *
  1041. valloc (size)
  1042.     unsigned size;
  1043. {
  1044.     extern char *malloc ();
  1045.     return (malloc (size));
  1046. }
  1047.  
  1048. /*
  1049.  *                NMKDIR.C
  1050.  *
  1051.  * Written by Robert Rother, Mariah Corporation, August 1985. 
  1052.  *
  1053.  * I wrote this out of shear disgust with myself because I couldn't
  1054.  * figure out how to do this in /bin/sh.
  1055.  *
  1056.  * If you want it, it's yours.  All I ask in return is that if you
  1057.  * figure out how to do this in a Bourne Shell script you send me
  1058.  * a copy.
  1059.  *                    sdcsvax!rmr or rmr@uscd
  1060. *
  1061. * Severely hacked over by John Gilmore to make a 4.2BSD compatible
  1062. * subroutine.    11Mar86; hoptoad!gnu
  1063. *
  1064. * Modified by rmtodd@uokmax 6-28-87 -- when making an already existing dir,
  1065. * subroutine didn't return EEXIST.  It does now.
  1066. */
  1067.  
  1068. /*
  1069.  * Make a directory.  Compatible with the mkdir() system call on 4.2BSD.
  1070.  */
  1071. #ifndef    MSDOS
  1072. int
  1073. mkdir(dpath, dmode)
  1074.     char *dpath;
  1075.     int dmode;
  1076. {
  1077.     int cpid, status;
  1078.     struct stat statbuf;
  1079.     extern int errno;
  1080.  
  1081.     if (stat(dpath,&statbuf) == 0) {
  1082.         errno = EEXIST;        /* Stat worked, so it already exists */
  1083.         return -1;
  1084.     }
  1085.  
  1086.     /* If stat fails for a reason other than non-existence, return error */
  1087.     if (errno != ENOENT) return -1; 
  1088.  
  1089.     switch (cpid = fork()) {
  1090.  
  1091.     case -1:            /* Error in fork() */
  1092.         return(-1);        /* Errno is set already */
  1093.  
  1094.     case 0:                /* Child process */
  1095.         /*
  1096.          * Cheap hack to set mode of new directory.  Since this
  1097.          * child process is going away anyway, we zap its umask.
  1098.          * FIXME, this won't suffice to set SUID, SGID, etc. on this
  1099.          * directory.  Does anybody care?
  1100.          */
  1101.         status = umask(0);    /* Get current umask */
  1102.         status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
  1103.         execl("/bin/mkdir", "mkdir", dpath, (char *)0);
  1104.         _exit(-1);        /* Can't exec /bin/mkdir */
  1105.     
  1106.     default:            /* Parent process */
  1107.         while (cpid != wait(&status)) ;    /* Wait for kid to finish */
  1108.     }
  1109.  
  1110.     if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
  1111.         errno = EIO;        /* We don't know why, but */
  1112.         return -1;        /* /bin/mkdir failed */
  1113.     }
  1114.  
  1115.     return 0;
  1116. }
  1117. #endif    /* MSDOS */
  1118. #endif
  1119.  
  1120. /* This next bit is called "doing OR on Minix cpp", e.g. without defined(). */
  1121. #undef WANTSTRING
  1122. #ifdef USG
  1123. #define WANTSTRING
  1124. #endif
  1125. #ifdef MSDOS
  1126. #define WANTSTRING
  1127. #endif
  1128.  
  1129. #ifdef WANTSTRING
  1130. /*
  1131.  * Translate V7 style into Sys V style.
  1132.  */
  1133. #include <string.h>
  1134. #include <memory.h>
  1135.  
  1136. char *
  1137. index (s, c)
  1138.     char *s;
  1139.     int c;
  1140. {
  1141.     return (strchr (s, c));
  1142. }
  1143.  
  1144. void
  1145. bcopy (s1, s2, n)
  1146.     char *s1, *s2;
  1147.     int n;
  1148. {
  1149.     (void) memcpy (s2, s1, n);
  1150. }
  1151.  
  1152. void
  1153. bzero (s1, n)
  1154.     char *s1;
  1155.     int n;
  1156. {
  1157.     (void) memset(s1, 0, n);
  1158. }
  1159.  
  1160. int
  1161. bcmp(s1, s2, n)
  1162.     char    *s1, *s2;
  1163.     int    n;
  1164. {
  1165.     return memcmp(s1, s2, n);
  1166. }
  1167. #endif
  1168.  
  1169. #ifdef MINIX
  1170. /* Minix has bcopy but not bzero, and no memset.  Thanks, Andy. */
  1171. void
  1172. bzero (s1, n)
  1173.     register char *s1;
  1174.     register int n;
  1175. {
  1176.     while (n--) *s1++ = '\0';
  1177. }
  1178.  
  1179. /* It also has no bcmp() */
  1180. int
  1181. bcmp (s1, s2, n) 
  1182.     register char *s1,*s2;
  1183.     register int n;
  1184. {
  1185.     for ( ; n-- ; ++s1, ++s2) {
  1186.         if (*s1 != *s2) return *s1 - *s2;
  1187.     }
  1188.     return 0;
  1189. }
  1190.  
  1191. /*
  1192.  * Groan, Minix doesn't have execlp either!
  1193.  *
  1194.  * execlp(file,arg0,arg1...argn,(char *)NULL)
  1195.  * exec a program, automatically searching for the program through
  1196.  * all the directories on the PATH.
  1197.  *
  1198.  * This version is naive about variable argument lists, it assumes
  1199.  * a straightforward C calling sequence.  If your system has odd stacks
  1200.  * *and* doesn't have execlp, YOU get to fix it.
  1201.  */
  1202. int
  1203. execlp(filename, arg0)
  1204.     char *filename, *arg0;
  1205. {
  1206.     extern char *malloc(), *getenv(), *index();
  1207.     extern int errno;
  1208.     register char *p, *path;    
  1209.     char **argstart = &arg0;
  1210.     register char *fnbuffer;
  1211.     struct stat statbuf;
  1212.  
  1213.     if ((p = getenv("PATH")) == NULL) {
  1214.         /* couldn't find path variable -- try to exec given filename */
  1215.         return execve(filename, argstart, environ);
  1216.     }
  1217.  
  1218.     /*
  1219.      * make a place to build the filename.  We malloc larger than we
  1220.      * need, but we know it will fit in this.
  1221.      */
  1222.     fnbuffer = malloc( strlen(p) + 1 + strlen(filename) );
  1223.     if (fnbuffer == NULL) {
  1224.         errno = ENOMEM;
  1225.         return -1;
  1226.     }
  1227.  
  1228.     /*
  1229.      * try each component of the path to see if the file's there
  1230.      * and executable.
  1231.      */
  1232.     for (path = p ; path ; path = p) {
  1233.         /* construct full path name to try */
  1234.         if ((p = index(path,':')) == NULL) {
  1235.             strcpy(fnbuffer, path);
  1236.         } else {
  1237.             strncpy(fnbuffer, path, p-path);
  1238.             fnbuffer[p-path] = '\0';
  1239.             p++;        /* Skip : for next time */
  1240.         }
  1241.         if (strlen(fnbuffer) != 0)
  1242.             strcat(fnbuffer,"/");
  1243.         strcat(fnbuffer,filename);
  1244.  
  1245.         /* check to see if file is there and is a normal file */
  1246.         if (stat(fnbuffer, &statbuf) < 0) {
  1247.             if (errno == ENOENT)
  1248.                 continue; /* file not there,keep on looking */
  1249.             else
  1250.                 goto fail; /* failed for some reason, return */
  1251.         }
  1252.         if ( (statbuf.st_mode & S_IFMT) != S_IFREG) continue;
  1253.  
  1254.         if (execve(fnbuffer, argstart, environ) < 0
  1255.             && errno != ENOENT
  1256.             && errno != ENOEXEC) {
  1257.             /* failed, for some other reason besides "file
  1258.              * not found" or "not a.out format"
  1259.              */
  1260.             goto fail;
  1261.         }
  1262.  
  1263.         /*
  1264.          * If we got error ENOEXEC, the file is executable but is
  1265.          * not an object file.  Try to execute it as a shell script,
  1266.          * returning error if we can't execute /bin/sh.
  1267.          *
  1268.          * FIXME, this code is broken in several ways.  Shell
  1269.          * scripts should not in general be executed by the user's
  1270.          * SHELL variable program.  On more mature systems, the
  1271.          * script can specify with #!/bin/whatever.  Also, this
  1272.          * code clobbers argstart[-1] if the exec of the shell
  1273.          * fails.
  1274.          */
  1275.         if (errno == ENOEXEC) {
  1276.             char *shell;
  1277.  
  1278.             /* Try to execute command "sh arg0 arg1 ..." */
  1279.             if ((shell = getenv("SHELL")) == NULL)
  1280.                 shell = "/bin/sh";
  1281.             argstart[-1] = shell;
  1282.             argstart[0] = fnbuffer;
  1283.             execve(shell, &argstart[-1], environ);
  1284.             goto fail;    /* Exec didn't work */
  1285.         }
  1286.  
  1287.         /* 
  1288.          * If we succeeded, the execve() doesn't return, so we
  1289.          * can only be here is if the file hasn't been found yet.
  1290.          * Try the next place on the path.
  1291.          */
  1292.     }
  1293.  
  1294.     /* all attempts failed to locate the file.  Give up. */
  1295.     errno = ENOENT;
  1296.  
  1297. fail:
  1298.     free(fnbuffer);
  1299.     return -1;
  1300. }
  1301. #endif /* MINIX */
  1302.  
  1303.  
  1304. #ifdef EMUL_OPEN3
  1305. #include "open3.h"
  1306. /*
  1307.  * open3 -- routine to emulate the 3-argument open system
  1308.  * call that is present in most modern Unix systems.
  1309.  * This version attempts to support all the flag bits except for O_NDELAY
  1310.  * and O_APPEND, which are silently ignored.  The emulation is not as efficient
  1311.  * as the real thing (at worst, 4 system calls instead of one), but there's
  1312.  * not much I can do about that.
  1313.  *
  1314.  * Written 6/10/87 by rmtodd@uokmax
  1315.  *
  1316.  * open3(path, flag, mode)
  1317.  * Attempts to open the file specified by
  1318.  * the given pathname.  The following flag bits (#defined in tar.h)
  1319.  * specify options to the routine:
  1320.  *    O_RDONLY    file open for read only
  1321.  *    O_WRONLY    file open for write only
  1322.  *    O_RDWR        file open for both read & write
  1323.  * (Needless to say, you should only specify one of the above).
  1324.  *     O_CREAT        file is created with specified mode if it needs to be.
  1325.  *    O_TRUNC        if file exists, it is truncated to 0 bytes
  1326.  *    O_EXCL        used with O_CREAT--routine returns error if file exists
  1327.  * Function returns file descriptor if successful, -1 and errno if not.
  1328.  */
  1329.  
  1330. /*
  1331.  * array to give arguments to access for various modes
  1332.  * FIXME, this table depends on the specific integer values of O_XXX,
  1333.  * and also contains integers (args to 'access') that should be #define's.
  1334.  */
  1335. static int modes[] =
  1336.     {
  1337.         04, /* O_RDONLY */
  1338.         02, /* O_WRONLY */
  1339.         06, /* O_RDWR */
  1340.         06, /* invalid but we'd better cope -- O_WRONLY+O_RDWR */
  1341.     };
  1342.  
  1343. /* Shut off the automatic emulation of open(), we'll need it. */
  1344. #undef open
  1345.  
  1346. int
  1347. open3(path, flags, mode)
  1348. char *path;
  1349. int flags, mode;
  1350. {
  1351.     extern int errno;
  1352.     int exists = 1;
  1353.     int call_creat = 0;
  1354.     int fd;
  1355.     /*
  1356.      * We actually do the work by calling the open() or creat() system
  1357.      * call, depending on the flags.  Call_creat is true if we will use 
  1358.      * creat(), false if we will use open().
  1359.      */
  1360.  
  1361.     /*
  1362.      * See if the file exists and is accessible in the requested mode. 
  1363.      *
  1364.      * Strictly speaking we shouldn't be using access, since access checks
  1365.      * against real uid, and the open call should check against euid.
  1366.      * Most cases real uid == euid, so it won't matter.   FIXME.
  1367.      * FIXME, the construction "flags & 3" and the modes table depends
  1368.      * on the specific integer values of the O_XXX #define's.  Foo!
  1369.      */
  1370.     if (access(path,modes[flags & 3]) < 0) {
  1371.         if (errno == ENOENT) {
  1372.             /* the file does not exist */
  1373.             exists = 0;
  1374.         } else {
  1375.             /* probably permission violation */
  1376.             if (flags & O_EXCL) {
  1377.                 /* Oops, the file exists, we didn't want it. */
  1378.                 /* No matter what the error, claim EEXIST. */
  1379.                 errno = EEXIST;
  1380.             }
  1381.             return -1;
  1382.         }
  1383.     }
  1384.  
  1385.     /* if we have the O_CREAT bit set, check for O_EXCL */
  1386.     if (flags & O_CREAT) {
  1387.         if ((flags & O_EXCL) && exists) {
  1388.             /* Oops, the file exists and we didn't want it to. */
  1389.             errno = EEXIST;
  1390.             return -1;
  1391.         }
  1392.         /*
  1393.          * If the file doesn't exist, be sure to call creat() so that
  1394.          * it will be created with the proper mode.
  1395.          */
  1396.         if (!exists) call_creat = 1;
  1397.     } else {
  1398.         /* If O_CREAT isn't set and the file doesn't exist, error. */
  1399.         if (!exists) {
  1400.             errno = ENOENT;
  1401.             return -1;
  1402.         }
  1403.     }
  1404.  
  1405.     /*
  1406.      * If the O_TRUNC flag is set and the file exists, we want to call
  1407.      * creat() anyway, since creat() guarantees that the file will be
  1408.      * truncated and open()-for-writing doesn't.
  1409.      * (If the file doesn't exist, we're calling creat() anyway and the
  1410.      * file will be created with zero length.)
  1411.      */
  1412.     if ((flags & O_TRUNC) && exists) call_creat = 1;
  1413.     /* actually do the call */
  1414.     if (call_creat) {
  1415.         /*
  1416.          * call creat.  May have to close and reopen the file if we
  1417.          * want O_RDONLY or O_RDWR access -- creat() only gives
  1418.          * O_WRONLY.
  1419.          */
  1420.         fd = creat(path,mode);
  1421.         if (fd < 0 || (flags & O_WRONLY)) return fd;
  1422.         if (close(fd) < 0) return -1;
  1423.         /* Fall out to reopen the file we've created */
  1424.     }
  1425.  
  1426.     /*
  1427.      * calling old open, we strip most of the new flags just in case.
  1428.      */
  1429.     return open(path, flags & (O_RDONLY|O_WRONLY|O_RDWR|O_BINARY));
  1430. }
  1431. #endif
  1432.  
  1433. #endif /* MASSCOMP mc700 */
  1434. #endif /* MASSCOMP mc500 */
  1435. #endif /* MASSCOMP mc300 */
  1436.  
  1437.  
  1438.  
  1439. #ifdef    MSDOS
  1440. /* Fake mknod by complaining */
  1441. int
  1442. mknod(path, mode, dev)
  1443.     char        *path;
  1444.     unsigned short    mode;
  1445.     dev_t        dev;
  1446. {
  1447.     extern int    errno;
  1448.     int        fd;
  1449.     
  1450.     errno = ENXIO;        /* No such device or address */
  1451.     return -1;        /* Just give an error */
  1452. }
  1453.  
  1454. /* Fake links by copying */
  1455. int
  1456. link(path1, path2)
  1457.     char        *path1;
  1458.     char        *path2;
  1459. {
  1460.     char    buf[256];
  1461.     int    ifd, ofd;
  1462.     int    nrbytes;
  1463.     int    nwbytes;
  1464.  
  1465.     fprintf(stderr, "%s: %s: cannot link to %s, copying instead\n",
  1466.         tar, path1, path2);
  1467.     if ((ifd = open(path1, O_RDONLY|O_BINARY)) < 0)
  1468.         return -1;
  1469.     if ((ofd = creat(path2, 0666)) < 0)
  1470.         return -1;
  1471.     setmode(ofd, O_BINARY);
  1472.     while ((nrbytes = read(ifd, buf, sizeof(buf))) > 0) {
  1473.         if ((nwbytes = write(ofd, buf, nrbytes)) != nrbytes) {
  1474.             nrbytes = -1;
  1475.             break;
  1476.         }
  1477.     }
  1478.     /* Note use of "|" rather than "||" below: we want to close
  1479.      * the files even if an error occurs.
  1480.      */
  1481.     if ((nrbytes < 0) | (0 != close(ifd)) | (0 != close(ofd))) {
  1482.         unlink(path2);
  1483.         return -1;
  1484.     }
  1485.     return 0;
  1486. }
  1487.  
  1488. /* everyone owns everything on MS-DOS (or is it no one owns anything?) */
  1489. int
  1490. chown(path, uid, gid)
  1491.     char    *path;
  1492.     int    uid;
  1493.     int    gid;
  1494. {
  1495.     return 0;
  1496. }
  1497.  
  1498. int
  1499. geteuid()
  1500. {
  1501.     return 0;
  1502. }
  1503. #endif    /* MSDOS */
  1504. @@@ Fin de port.c
  1505. echo wildmat.c
  1506. cat >wildmat.c <<'@@@ Fin de wildmat.c'
  1507. /*
  1508.  * @(#)wildmat.c 1.3 87/11/06    Public Domain.
  1509.  *
  1510. From: rs@mirror.TMC.COM (Rich Salz)
  1511. Newsgroups: net.sources
  1512. Subject: Small shell-style pattern matcher
  1513. Message-ID: <596@mirror.TMC.COM>
  1514. Date: 27 Nov 86 00:06:40 GMT
  1515.  
  1516. There have been several regular-expression subroutines and one or two
  1517. filename-globbing routines in mod.sources.  They handle lots of
  1518. complicated patterns.  This small piece of code handles the *?[]\
  1519. wildcard characters the way the standard Unix(tm) shells do, with the
  1520. addition that "[^.....]" is an inverse character class -- it matches
  1521. any character not in the range ".....".  Read the comments for more
  1522. info.
  1523.  
  1524. For my application, I had first ripped off a copy of the "glob" routine
  1525. from within the find(1) source, but that code is bad news:  it recurses
  1526. on every character in the pattern.  I'm putting this replacement in the
  1527. public domain.  It's small, tight, and iterative.  Compile with -DTEST
  1528. to get a test driver.  After you're convinced it works, install in
  1529. whatever way is appropriate for you.
  1530.  
  1531. I would like to hear of bugs, but am not interested in additions; if I
  1532. were, I'd use the code I mentioned above.
  1533. */
  1534. /*
  1535. **  Do shell-style pattern matching for ?, \, [], and * characters.
  1536. **  Might not be robust in face of malformed patterns; e.g., "foo[a-"
  1537. **  could cause a segmentation violation.
  1538. **
  1539. **  Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
  1540. */
  1541.  
  1542. /*
  1543.  * Modified 6Nov87 by John Gilmore (hoptoad!gnu) to return a "match"
  1544.  * if the pattern is immediately followed by a "/", as well as \0.
  1545.  * This matches what "tar" does for matching whole subdirectories.
  1546.  *
  1547.  * The "*" code could be sped up by only recursing one level instead
  1548.  * of two for each trial pattern, perhaps, and not recursing at all
  1549.  * if a literal match of the next 2 chars would fail.
  1550.  */
  1551. #define TRUE        1
  1552. #define FALSE        0
  1553.  
  1554.  
  1555. static int
  1556. Star(s, p)
  1557.     register char    *s;
  1558.     register char    *p;
  1559. {
  1560.     while (wildmat(s, p) == FALSE)
  1561.     if (*++s == '\0')
  1562.         return(FALSE);
  1563.     return(TRUE);
  1564. }
  1565.  
  1566.  
  1567. int
  1568. wildmat(s, p)
  1569.     register char    *s;
  1570.     register char    *p;
  1571. {
  1572.     register int      last;
  1573.     register int      matched;
  1574.     register int      reverse;
  1575.  
  1576.     for ( ; *p; s++, p++)
  1577.     switch (*p) {
  1578.         case '\\':
  1579.         /* Literal match with following character; fall through. */
  1580.         p++;
  1581.         default:
  1582.         if (*s != *p)
  1583.             return(FALSE);
  1584.         continue;
  1585.         case '?':
  1586.         /* Match anything. */
  1587.         if (*s == '\0')
  1588.             return(FALSE);
  1589.         continue;
  1590.         case '*':
  1591.         /* Trailing star matches everything. */
  1592.         return(*++p ? Star(s, p) : TRUE);
  1593.         case '[':
  1594.         /* [^....] means inverse character class. */
  1595.         if (reverse = p[1] == '^')
  1596.             p++;
  1597.         for (last = 0400, matched = FALSE; *++p && *p != ']'; last = *p)
  1598.             /* This next line requires a good C compiler. */
  1599.             if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
  1600.             matched = TRUE;
  1601.         if (matched == reverse)
  1602.             return(FALSE);
  1603.         continue;
  1604.     }
  1605.  
  1606.     /* For "tar" use, matches that end at a slash also work. --hoptoad!gnu */
  1607.     return(*s == '\0' || *s == '/');
  1608. }
  1609.  
  1610.  
  1611. #ifdef    TEST
  1612. #include <stdio.h>
  1613.  
  1614. extern char    *gets();
  1615.  
  1616.  
  1617. main()
  1618. {
  1619.     char     pattern[80];
  1620.     char     text[80];
  1621.  
  1622.     while (TRUE) {
  1623.     printf("Enter pattern:  ");
  1624.     if (gets(pattern) == NULL)
  1625.         break;
  1626.     while (TRUE) {
  1627.         printf("Enter text:  ");
  1628.         if (gets(text) == NULL)
  1629.         exit(0);
  1630.         if (text[0] == '\0')
  1631.         /* Blank line; go back and get a new pattern. */
  1632.         break;
  1633.         printf("      %d\n", wildmat(text, pattern));
  1634.     }
  1635.     }
  1636.     exit(0);
  1637. }
  1638. #endif    /* TEST */
  1639. @@@ Fin de wildmat.c
  1640. exit 0
  1641.