home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / MSDOS / WATTCP / PISA_TAR.TAR / tar / create.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-05  |  12.3 KB  |  519 lines

  1. /*
  2.  * Create a tar archive.
  3.  *
  4.  * Written 25 Aug 1985 by John Gilmore, ihnp4!hoptoad!gnu.
  5.  *
  6.  * @(#)create.c 1.19 9/9/86 Public Domain - gnu
  7.  */
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <fcntl.h>
  11. #include <stdio.h>
  12.  
  13. #if defined(BSD42)/* || defined(MSDOS)  */
  14. #ifdef    OS
  15. #include <ndir.h>
  16. #else
  17. /* #include <sys/dir.h> */
  18. #include <direct.h>
  19. #endif
  20. #else
  21. /*
  22.  * FIXME: On other systems there is no standard place for the header file
  23.  * for the portable directory access routines.  Change the #include line
  24.  * below to bring it in from wherever it is.
  25.  */
  26. #include "msd_dir.h"
  27. /* #include "ndir.h" */
  28. #endif
  29.  
  30. #ifdef USG
  31. #include <sys/sysmacros.h>    /* major() and minor() defined here */
  32. #endif
  33.  
  34. /*
  35.  * V7 doesn't have a #define for this.
  36.  */
  37. #ifndef O_RDONLY
  38. #define    O_RDONLY    0
  39. #endif
  40.  
  41. #include <tar.h>
  42.  
  43. /*
  44.  * If there are no symbolic links, there is no lstat().  Use stat().
  45.  */
  46. #ifndef S_IFLNK
  47. #define lstat stat
  48. #endif
  49.  
  50. extern char    *malloc();
  51. extern char    *strcpy();
  52. extern char    *strncpy();
  53. extern int    errno;
  54.  
  55. union record *start_header();
  56. void finish_header();
  57. char *name_next();
  58. void to_oct();
  59.  
  60.  
  61. void
  62. create_archive()
  63. {
  64.     register char    *p;
  65.  
  66.     open_archive(0);        /* Open for writing */
  67.  
  68.     while (p = name_next()) {
  69.         dump_file(p);
  70.     }
  71.  
  72.     write_eot();
  73.     close_archive();
  74.     name_close();
  75. }        
  76.  
  77. /*
  78.  * Dump a single file.  If it's a directory, recurse.
  79.  * Result is 1 for success, 0 for failure.
  80.  */
  81. int
  82. dump_file(p)
  83.     char    *p;            /* File name to dump */
  84. {
  85.     struct stat    statbuf[1];
  86.     union record    *header;
  87.     char type;
  88.  
  89. #ifdef    XBUF
  90.     if(f_xbuf && !strcmp(p, ar_file))
  91.         return(0);
  92. #endif
  93.     /*
  94.      * Use stat if following (rather than dumping) 4.2BSD's
  95.      * symbolic links.  Otherwise, use lstat (which, on non-4.2
  96.      * systems, is #define'd to stat anyway.
  97.      */
  98.     if (0 != f_follow_links? stat(p, statbuf): lstat(p, statbuf))
  99.     {
  100. badperror:
  101.         perror(p);
  102. badfile:
  103.         errors++;
  104.         return 0;
  105.     }
  106.  
  107.     switch (statbuf->st_mode & S_IFMT) {
  108.  
  109.     case S_IFREG:            /* Regular file */
  110.     {
  111.         int    f;        /* File descriptor */
  112.         int    bufsize, count;
  113.         register long    sizeleft;
  114.         register union record     *start;
  115.  
  116.         /*
  117.          * Handle a regular file with multiple links.
  118.          *
  119.          * We maintain a list of all such files that we've written so
  120.          * far.  Any time we see another, we check the list and
  121.          * avoid dumping the data again if we've done it once already.
  122.          */
  123. #ifdef    DUMPTIME
  124.         if(dumptime && statbuf->st_mtime < dumptime)
  125.             break;
  126. #endif
  127.         if (statbuf->st_nlink > 1) {
  128.             register struct link    *lp;
  129.  
  130.             /* First quick and dirty.  Hashing, etc later FIXME */
  131.             for (lp = linklist; lp; lp = lp->next) {
  132.                 if (lp->ino == statbuf->st_ino &&
  133.                     lp->dev == statbuf->st_dev) {
  134.                     /* We found a link. */
  135.                     statbuf->st_size = 0;
  136.                     header = start_header(p, statbuf);
  137.                     if (header == NULL) goto badfile;
  138.                     strcpy(header->header.linkname,
  139.                         lp->name);
  140.                     header->header.linkflag = LF_LINK;
  141.                     finish_header(header);
  142.                     if (f_verbose)
  143.                         annorec(stdout, (char *)NULL);
  144.                         printf("%s link to %s\n",
  145.                             p, lp->name);
  146.             /* Maybe remove from list after all links found? */
  147.         /* If so, have to compare names in case he dumps twice. */
  148.             /* Later: I don't understand the above.  If she
  149.              * dumps the file twice, it would be BAD to dump
  150.              * it the second time as a link...  gnu 25Jul86
  151.              */
  152.                     /* FIXME */
  153.                     goto donefile;
  154.                 }
  155.             }
  156.  
  157.             /* Not found.  Add it to the list. */
  158.             lp = (struct link *) malloc( (unsigned)
  159.                 (strlen(p) + sizeof(struct link) - NAMSIZ));
  160.             lp->ino = statbuf->st_ino;
  161.             lp->dev = statbuf->st_dev;
  162.             strcpy(lp->name, p);
  163.             lp->next = linklist;
  164.             linklist = lp;
  165.         }
  166.  
  167.         sizeleft = statbuf->st_size;
  168.         /* Don't bother opening empty, world readable files. */
  169.         if (sizeleft > 0 || 0444 != (0444 & statbuf->st_mode)) {
  170. #ifdef    MSDOS
  171.             f = open(p, O_RDONLY|O_BINARY);
  172. #else
  173.             f = open(p, O_RDONLY);
  174. #endif
  175.             if (f < 0) goto badperror;
  176.         } else {
  177.             f = -1;
  178.         }
  179.         header = start_header(p, statbuf);
  180.         if (header == NULL) goto badfile;
  181.         finish_header(header);
  182.         while (sizeleft > 0) {
  183.             start = findrec();
  184.             bufsize = endofrecs()->charptr - start->charptr;
  185.             if (sizeleft < bufsize)
  186.                 bufsize = sizeleft;
  187.             count = read(f, start->charptr, bufsize);
  188.             if (count < 0) {
  189.                 annorec(stderr, tar);
  190.                 fprintf(stderr,
  191.                   "read error at byte %ld, reading %d bytes, in file ",
  192.                     statbuf->st_size - sizeleft,
  193.                     bufsize);
  194.                 perror(p);    /* FIXME */
  195.                 goto padit;
  196.             }
  197.             sizeleft -= count;
  198.             userec(start+(count-1)/RECORDSIZE);
  199.             if (count == bufsize) continue;
  200.             annorec(stderr, tar);
  201.             fprintf(stderr,
  202.     "%s: file shrunk by %d bytes, padding with zeros.\n",
  203.                 p, sizeleft);
  204.             goto padit;        /* Short read */
  205.         }
  206.         if (f >= 0)
  207.             (void)close(f);
  208.  
  209.         /* Clear last block garbage to zeros, FIXME */
  210.  
  211.         if (f_verbose) {
  212.             annorec(stdout, (char *)NULL);
  213.             printf("%s\n", p);
  214.         }
  215.     donefile:
  216.         break;
  217.  
  218.         /*
  219.          * File shrunk or gave error, pad out tape to match
  220.          * the size we specified in the header.
  221.          */
  222.     padit:
  223.         abort();
  224.     }
  225.  
  226. #ifdef S_IFLNK
  227.     case S_IFLNK:            /* Symbolic link */
  228.     {
  229.         int size;
  230.  
  231.         statbuf->st_size = 0;        /* Force 0 size on symlink */
  232.         header = start_header(p, statbuf);
  233.         if (header == NULL) goto badfile;
  234.         size = readlink(p, header->header.linkname, NAMSIZ);
  235.         if (size < 0) goto badperror;
  236.         if (size == NAMSIZ) {
  237.             annorec(stderr, tar);
  238.             fprintf(stderr,
  239.                 "%s: symbolic link too long\n", p);
  240.             break;
  241.         }
  242.         header->header.linkname[size] = '\0';
  243.         header->header.linkflag = LF_SYMLINK;
  244.         finish_header(header);        /* Nothing more to do to it */
  245.         if (f_verbose) {
  246.             annorec(stdout, (char *)NULL);
  247.             printf("%s\n", p);
  248.         }
  249.     }
  250.         break;
  251. #endif
  252.  
  253.     case S_IFDIR:            /* Directory */
  254.     {
  255.         register DIR *dirp;
  256.         register struct direct *d;
  257.         char namebuf[NAMSIZ+2];
  258.         register int len;
  259.  
  260.         /* Build new prototype name */
  261.         strncpy(namebuf, p, sizeof (namebuf));
  262.         len = strlen(namebuf);
  263.         while (len >= 1 && '/' == namebuf[len-1]) 
  264.             len--;            /* Delete trailing slashes */
  265.         namebuf[len++] = '/';        /* Now add exactly one back */
  266.  
  267.         /*
  268.          * Output directory header record with permissions
  269.          * FIXME, do this AFTER files, to avoid R/O dir problems?
  270.          * If Unix Std format, don't put / on end of dir name
  271.          * If old archive format, don't write record at all.
  272.          */
  273.         if (!f_oldarch) {
  274.             statbuf->st_size = 0;    /* Force 0 size on dir */
  275.             /*
  276.              * If people could really read standard archives,
  277.              * this should be:        (FIXME)
  278.             header = start_header(f_standard? p: namebuf, statbuf);
  279.              * but since they'd interpret LF_DIR records as
  280.              * regular files, we'd better put the / on the name.
  281.              */
  282.             header = start_header(namebuf, statbuf);
  283.             if (header == NULL)
  284.                 goto badfile;    /* eg name too long */
  285.             if (f_standard) {
  286.                 header->header.linkflag = LF_DIR;
  287.             }
  288.             finish_header(header);    /* Done with directory header */
  289.         }
  290.         if (f_verbose) {
  291.             annorec(stdout, (char *)NULL);
  292.             printf("%s\n", p);
  293.         }
  294.  
  295.         /* Hack to remove "./" from the front of all the file names */
  296.         if (len == 2 && namebuf[0] == '.') {
  297.             len = 0;
  298.         }
  299.  
  300.         /* Now output all the files in the directory */
  301.         errno = 0;
  302.         dirp = opendir(p);
  303.         if (!dirp) {
  304.             if (errno) {
  305.                 perror (p);
  306.             } else {
  307.                 annorec(stderr, tar);
  308.                 fprintf(stderr, "%s: error opening directory",
  309.                     p);
  310.             }
  311.             break;
  312.         }
  313.         
  314.         /* Should speed this up by cd-ing into the dir, FIXME */
  315.         while (NULL != (d=readdir(dirp))) {
  316.             /* Skip . and .. */
  317.             if (d->d_name[0] == '.') {
  318.                 if (d->d_name[1] == '\0') continue;
  319.                 if (d->d_name[1] == '.') {
  320.                     if (d->d_name[2] == '\0') continue;
  321.                 }
  322.             }
  323.             if (d->d_namlen + len >= NAMSIZ) {
  324.                 annorec(stderr, tar);
  325.                 fprintf(stderr, "%s%s: name too long\n", 
  326.                     namebuf, d->d_name);
  327.                 continue;
  328.             }
  329.             strcpy(namebuf+len, d->d_name);
  330.             dump_file(namebuf);
  331.         }
  332.  
  333.         closedir(dirp);
  334.     }
  335.         break;
  336.  
  337. #ifdef S_IFCHR
  338.     case S_IFCHR:            /* Character special file */
  339.         type = LF_CHR;
  340.         goto easy;
  341. #endif
  342.  
  343. #ifdef S_IFBLK
  344.     case S_IFBLK:            /* Block     special file */
  345.         type = LF_BLK;
  346.         goto easy;
  347. #endif
  348.  
  349. #ifdef S_IFIFO
  350.     case S_IFIFO:            /* Fifo      special file */
  351.         type = LF_FIFO;
  352. #endif
  353.  
  354.     easy:
  355.         if (!f_standard) goto unknown;
  356.  
  357.         statbuf->st_size = 0;        /* Force 0 size */
  358.         header = start_header(p, statbuf);
  359.         if (header == NULL) goto badfile;    /* eg name too long */
  360.  
  361.         header->header.linkflag = type;
  362.         if (type != LF_FIFO) {
  363.             to_oct((long) major(statbuf->st_rdev), 8,
  364.                 header->header.devmajor);
  365.             to_oct((long) minor(statbuf->st_rdev), 8,
  366.                 header->header.devminor);
  367.         }
  368.  
  369.         finish_header(header);
  370.         if (f_verbose) {
  371.             annorec(stdout, (char *)NULL);
  372.             printf("%s\n", p);
  373.         }
  374.         break;
  375.  
  376.     default:
  377.     unknown:
  378.         annorec(stderr, tar);
  379.         fprintf(stderr,
  380.             "%s: Unknown file type; file ignored.\n", p);
  381.         break;
  382.     }
  383.  
  384.     return 1;            /* Success */
  385. }
  386.  
  387.  
  388. /*
  389.  * Make a header block for the file  name  whose stat info is  st .
  390.  * Return header pointer for success, NULL if the name is too long.
  391.  */
  392. union record *
  393. start_header(name, st)
  394.     char    *name;
  395.     register struct stat *st;
  396. {
  397.     register union record *header;
  398.  
  399.     header = (union record *) findrec();
  400.     bzero(header->charptr, sizeof(*header)); /* XXX speed up */
  401.     strcpy(header->header.name, name);
  402.     if (header->header.name[NAMSIZ-1]) {
  403.         annorec(stderr, tar);
  404.         fprintf(stderr, "%s: name too long\n", name);
  405.         return NULL;
  406.     }
  407.     to_oct((long) (st->st_mode & ~S_IFMT),
  408.                     8,  header->header.mode);
  409.     to_oct((long) st->st_uid,    8,  header->header.uid);
  410.     to_oct((long) st->st_gid,    8,  header->header.gid);
  411.     to_oct((long) st->st_size,    1+12, header->header.size);
  412.     to_oct((long) st->st_mtime,    1+12, header->header.mtime);
  413.     /* header->header.linkflag is left as null */
  414.  
  415. #ifndef NONAMES
  416.     /* Fill in new Unix Standard fields if desired. */
  417.     if (f_standard) {
  418.         header->header.linkflag = LF_NORMAL;    /* New default */
  419.         strcpy(header->header.magic, TMAGIC);    /* Mark as Unix Std */
  420.         finduname(header->header.uname, st->st_uid);
  421.         findgname(header->header.gname, st->st_gid);
  422.     }
  423. #endif
  424.     return header;
  425. }
  426.  
  427. /* 
  428.  * Finish off a filled-in header block and write it out.
  429.  */
  430. void
  431. finish_header(header)
  432.     register union record *header;
  433. {
  434.     register int    i, sum;
  435.     register char    *p;
  436.  
  437.     bcopy(CHKBLANKS, header->header.chksum, sizeof(header->header.chksum));
  438.  
  439.     sum = 0;
  440.     p = header->charptr;
  441.     for (i = sizeof(*header); --i >= 0; ) {
  442.         /*
  443.          * We can't use unsigned char here because of old compilers,
  444.          * e.g. V7.
  445.          */
  446.         sum += 0xFF & *p++;
  447.     }
  448.  
  449.     /*
  450.      * Fill in the checksum field.  It's formatted differently
  451.      * from the other fields:  it has [6] digits, a null, then a
  452.      * space -- rather than digits, a space, then a null.
  453.      * We use to_oct then write the null in over to_oct's space.
  454.      * The final space is already there, from checksumming, and
  455.      * to_oct doesn't modify it.
  456.      *
  457.      * This is a fast way to do:
  458.      * (void) sprintf(header->header.chksum, "%6o", sum);
  459.      */
  460.     to_oct((long) sum,    8,  header->header.chksum);
  461.     header->header.chksum[6] = '\0';    /* Zap the space */
  462.  
  463.     userec(header);
  464.     return;
  465. }
  466.  
  467.  
  468. /*
  469.  * Quick and dirty octal conversion.
  470.  * Converts long "value" into a "digs"-digit field at "where",
  471.  * including a trailing space and room for a null.  "digs"==3 means
  472.  * 1 digit, a space, and room for a null.
  473.  *
  474.  * We assume the trailing null is already there and don't fill it in.
  475.  * This fact is used by start_header and finish_header, so don't change it!
  476.  *
  477.  * This should be equivalent to:
  478.  *    (void) sprintf(where, "%*lo ", digs-2, value);
  479.  * except that sprintf fills in the trailing null and we don't.
  480.  */
  481. void
  482. to_oct(value, digs, where)
  483.     register long    value;
  484.     register int    digs;
  485.     register char    *where;
  486. {
  487.     
  488.     --digs;                /* Trailing null slot is left alone */
  489.     where[--digs] = ' ';        /* Put in the space, though */
  490.  
  491.     /* Produce the digits -- at least one */
  492.     do {
  493.         where[--digs] = '0' + (value & 7);    /* one octal digit */
  494.         value >>= 3;
  495.     } while (digs > 0 && value != 0);
  496.  
  497.     /* Leading spaces, if necessary */
  498.     while (digs > 0)
  499.         where[--digs] = ' ';
  500.  
  501. }
  502.  
  503.  
  504. /*
  505.  * Write the EOT block(s).
  506.  */
  507. write_eot()
  508. {
  509.     union record *p;
  510.  
  511.     p = findrec();
  512.     bzero(p->charptr, RECORDSIZE);
  513.     userec(p);
  514.     /* FIXME, only one EOT block should be needed. */
  515.     p = findrec();
  516.     bzero(p->charptr, RECORDSIZE);
  517.     userec(p);
  518. }
  519.