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

  1. /******************************************************************************
  2.  
  3.     RTAR - remotely execute a TAR command
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it, but you may not sell it.
  7.  
  8.     This program is distributed in the hope that it will be useful,
  9.     but without any warranty; without even the implied warranty of
  10.     merchantability or fitness for a particular purpose.
  11.  
  12.         Giovanni Mercaldo 
  13.         Faculty of Engineering
  14.         University of Pisa 
  15.         
  16. ******************************************************************************/
  17.  
  18. /*
  19.  * A public domain tar(1) program.
  20.  * 
  21.  * Written by John Gilmore, ihnp4!hoptoad!gnu, starting 25 Aug 85.
  22.  *
  23.  * @(#)tar.c 1.21 10/29/86 Public Domain - gnu
  24.  * 
  25.  * and modified by G.Mercaldo 9-Apr-92
  26.  *
  27.  * Main routine for tar.
  28.  */
  29.  
  30. #include <stdio.h>
  31. #include <string.h>
  32. #include <time.h>        /* for randomize */
  33. #include <stdlib.h>
  34. #include <conio.h>        /* for getpass */
  35. #include <sys/types.h>        /* Needed for typedefs in tar.h */
  36.  
  37. /* extern char     *malloc(); */
  38. extern char    *strncpy();
  39. extern char    *optarg;    /* Pointer to argument */
  40. extern int    optind;        /* Global argv index from getopt */
  41.  
  42. /*
  43.  * The following causes "tar.h" to produce definitions of all the
  44.  * global variables, rather than just "extern" declarations of them.
  45.  */
  46. #define TAR_EXTERN /**/
  47. #define SEP_CHAR ':'
  48.  
  49. #include <tar.h>
  50.  
  51. /*
  52.  * We should use a conversion routine that does reasonable error
  53.  * checking -- atoi doesn't.  For now, punt.  FIXME.
  54.  */
  55. #define intconv    atoi
  56. extern int    getoldopt();
  57. extern void    read_and();
  58. extern void    list_archive();
  59. extern void    extract_archive();
  60. extern void    create_archive();
  61.  
  62. static FILE    *namef;        /* File to read names from */
  63. static char    **n_argv;    /* Argv used by name routines */
  64. static int    n_argc;    /* Argc used by name routines */
  65.             /* They also use "optind" from getopt(). */
  66. int cmd_remote=0;
  67.  
  68. void    describe();
  69.  
  70. help()
  71. {
  72.  puts("Usage in remote mode:");
  73.  puts("RTAR options [host/[ username/ [password]]]/ remote command or file ");
  74.  puts("For options type tar -h");
  75.  exit( 3 );
  76. }
  77.  
  78. /* Control if ar_file is for remote connection */
  79. void check_ar_file()
  80. {
  81.   char *p,*p1,*usefile;
  82.   
  83.   usefile="";
  84.  
  85.   p=ar_file;
  86.  
  87.   hostname=p;
  88.   p1=p;
  89.  
  90.     while(*p1 && *p1!=SEP_CHAR) p1++; 
  91.     if ( *p1 ) {
  92.         *(p1++)='\0';
  93.         f_remote++;
  94.         name=p1;
  95.         while(*p1 && *p1!=SEP_CHAR) p1++;      
  96.         if (*p1) {
  97.             *(p1++)='\0';
  98.             if(!(strcmp(name,""))) name=NULL;
  99.             pass=p1;
  100.             while(*p1 && *p1!=SEP_CHAR) p1++;          
  101.             if (*p1) {
  102.                 *(p1++)='\0';
  103.                 if(!(strcmp(pass,""))) pass=NULL;
  104.                 usefile=p1;
  105.             }
  106.         }
  107.     }
  108.  
  109.     if ( f_remote ) {
  110.         if (cmd_remote) strcpy(cmd,usefile);
  111.         else {
  112.             if (f_create) strcpy(cmd,"cat - > "); 
  113.             else strcpy(cmd,"cat "); 
  114.             if (f_use_zcat) {
  115.             if (f_create)  strcpy(cmd,"compress - > "); 
  116.                 else strcpy(cmd,"zcat "); 
  117.             }
  118.  
  119.             strcat (cmd,usefile);
  120.             if (f_create && f_use_zcat) strcat (cmd,".Z");
  121.         }
  122.     }
  123.  
  124.     if(!(strcmp(usefile,""))) usefile=NULL;
  125.  
  126.     if (f_remote && !cmd_remote && !usefile) {
  127.         help();
  128.         exit(EX_ARGSBAD);
  129.     }
  130. }
  131.  
  132. main(argc, argv)
  133.     int    argc;
  134.     char    **argv;
  135. {
  136.     hostname = name = pass = NULL;
  137.  
  138.     tar = "tar";        /* Set program name */
  139.  
  140.     options(argc, argv);
  141.  
  142.     check_ar_file();
  143.  
  144.     if (f_remote) {    
  145.         dbuginit();
  146.         sock_init();
  147.     }
  148.  
  149.     name_init(argc, argv);
  150.  
  151.     if (f_create) {
  152.         /* if (f_remote) goto errflags; */
  153.         if (f_extract || f_list) goto dupflags;
  154.         create_archive();
  155.     } else if (f_extract) {
  156.         if (f_list) goto dupflags;
  157.         read_and(extract_archive);
  158.     } else if (f_list) {
  159.         read_and(list_archive);
  160.     } else {
  161. dupflags:
  162.         fprintf (stderr,
  163. "tar: you must specify exactly one of the c, t, or x options\n");
  164.         describe();
  165.         exit(EX_ARGSBAD);
  166. /* errflags:
  167.         fprintf (stderr,
  168. "tar: you can't specify the c option! \n");
  169.         describe();
  170.         exit(EX_ARGSBAD); */
  171.     }
  172.     exit(0);
  173. }
  174.  
  175.  
  176. /*
  177.  * Parse the options for tar.
  178.  */
  179. int
  180. options(argc, argv)
  181.     int    argc;
  182.     char    **argv;
  183. {
  184.     register int    c;        /* Option letter */
  185.  
  186.     /* Set default option values */
  187.     blocking = DEFBLOCKING;        /* From Makefile */
  188. #ifdef    DEF_AR_FILE
  189.     ar_file = DEF_AR_FILE;        /* From Makefile */
  190. #else
  191.     ar_file = "/dev/null";
  192. #endif
  193.  
  194.     /* Parse options */
  195.     while ((c = getoldopt(argc, argv, "a:b:BcdDf:hikmoprstT:vxXzZ")
  196.         ) != EOF) {
  197.         switch (c) {
  198.  
  199. #ifdef    DUMPTIME
  200.         case 'a':
  201.             time(&dumptime);
  202.             dumptime -= (long)intconv(optarg) * 60L * 60L * 24L;
  203.             break;
  204. #endif
  205.  
  206.         case 'b':
  207.             blocking = intconv(optarg);
  208.             break;
  209.  
  210.         case 'B':
  211.             f_reblock++;        /* For reading 4.2BSD pipes */
  212.             break;
  213.  
  214.         case 'c':
  215.             f_create++;
  216.             break;
  217.  
  218.         case 'd':
  219.             f_debug++;        /* Debugging code */
  220.             break;            /* Yes, even with dbx */
  221.  
  222.         case 'D':
  223.             f_sayblock++;        /* Print block #s for debug */
  224.             break;            /* of bad tar archives */
  225.  
  226.         case 'f':
  227.             ar_file = optarg;
  228.             break;
  229.  
  230.         case 'h':
  231.             f_follow_links++;    /* follow symbolic links */
  232.             break;
  233.  
  234.         case 'i':
  235.             f_ignorez++;        /* Ignore zero records (eofs) */
  236.             /*
  237.              * This can't be the default, because Unix tar
  238.              * writes two records of zeros, then pads out the
  239.              * block with garbage.
  240.              */
  241.             break;
  242.  
  243.         case 'k':            /* Don't overwrite files */
  244.             f_keep++;
  245.             break;
  246.  
  247.  
  248.         case 'm':
  249.             f_modified++;
  250.             break;
  251.  
  252.         case 'o':            /* Generate old archive */
  253.             f_oldarch++;
  254.             break;
  255.  
  256.         case 'p':
  257.             f_use_protection++;
  258.             (void)umask(0);        /* Turn off kernel "help" */
  259.             break;
  260.  
  261.         case 'r':
  262.             cmd_remote++;
  263.             break;
  264.  
  265.         case 's':
  266.             f_sorted_names++;    /* Names to extr are sorted */
  267.             break;
  268.  
  269.         case 't':
  270.             f_list++;
  271.             break;
  272.  
  273.         case 'T':
  274.             name_file = optarg;
  275.             f_namefile++;
  276.             break;
  277.  
  278.         case 'v':
  279.             f_verbose++;
  280.             break;
  281.  
  282.         case 'x':
  283.             f_extract++;
  284.             break;
  285.  
  286. #ifdef    XBUF
  287.         case 'X':
  288.             f_xbuf++;
  289.             break;
  290. #endif
  291.  
  292.         case 'z':        /* Easy to type */
  293.         case 'Z':        /* Like the filename extension .Z */
  294.             f_use_zcat++;
  295.             f_compress++;
  296.             break;
  297.  
  298.         case '?':
  299.             help();
  300.             describe();
  301.             exit(EX_ARGSBAD);
  302.  
  303.         }
  304.     }
  305.  
  306.     blocksize = blocking * RECORDSIZE;
  307. }
  308.  
  309.  
  310. /* FIXME, describe tar options here */
  311. void
  312. describe()
  313. {
  314.  
  315.     fputs("tar: valid options:\n\
  316. -b N    blocking factor N (block size = Nx512 bytes)\n\
  317. -B    reblock as we read (for reading 4.2BSD pipes)\n\
  318. -c    create an archive\n\
  319. -D    dump record number within archive with each message\n\
  320. -f F    read/write archive from file or device F\n\
  321.     optionally, can specify remoptehost:user:password:filename\n\
  322. -h    don't dump symbolic links; dump the files they point to\n\
  323. -i    ignore blocks of zeros in the archive, which normally mean EOF\n\
  324. -k    keep existing files, don't overwrite them from the archive\n\
  325. -l    indicates the begin of the file list to operate on\n\
  326. -m    don't extract file modified time\n", stderr);
  327.     fputs("\
  328. -o    write an old V7 format archive, rather than ANSI [draft 6] format\n\
  329. -p    do extract all protection information\n\
  330. -r    filename is a remote command (see -f)\n\
  331. -s    list of names to extract is sorted to match the archive\n\
  332. -t    list a table of contents of an archive\n\
  333. -T F    get names to extract or create from file F\n\
  334. -v    verbosely list what files we process\n\
  335. -x    extract files from an archive\n\
  336. -z or Z    run the archive through compress(1)\n", stderr);
  337. }
  338.  
  339. /*
  340.  * Set up to gather file names for tar.
  341.  *
  342.  * They can either come from stdin or from argv.
  343.  */
  344. name_init(argc, argv)
  345.     int    argc;
  346.     char    **argv;
  347. {
  348.     int app;
  349.  
  350.     if (f_namefile) {
  351.         if (optind < argc) {
  352.             fprintf(stderr, "tar: too many args with -T option\n");
  353.             exit(EX_ARGSBAD);
  354.         }
  355.         if (!strcmp(name_file, "-")) {
  356.             namef = stdin;
  357.         } else {
  358.             namef = fopen(name_file, "r");
  359.             if (namef == NULL) {
  360.                 fprintf(stderr, "tar: ");
  361.                 perror(name_file);
  362.                 exit(EX_BADFILE);
  363.             }
  364.         }
  365.     } else {
  366.         /* Get file names from argv, after options. */
  367.         n_argc = argc;
  368.         n_argv = argv;
  369.         }
  370. }
  371.  
  372. /*
  373.  * Get the next name from argv or the name file.
  374.  *
  375.  * Result is in static storage and can't be relied upon across two calls.
  376.  */
  377. char *
  378. name_next()
  379. {
  380.     static char    buffer[NAMSIZ+2];    /* Holding pattern */
  381.     register char    *p;
  382.     register char    *q;
  383.  
  384.         if (namef == NULL) {
  385.             /* Names come from argv, after options */
  386.             if (optind < n_argc){
  387.                 return n_argv[optind++];
  388.             }
  389.             return (char *)NULL;
  390.         }
  391.         else p = fgets(buffer, NAMSIZ+1 /*nl*/, namef);
  392.         if (p == NULL) return p;    /* End of file */
  393.         q = p+strlen(p)-1;        /* Find the newline */
  394.         *q-- = '\0';            /* Zap the newline */
  395.         while (*q == '/')  *q-- = '\0';    /* Zap trailing slashes too */
  396.         return p;
  397. }
  398.  
  399.  
  400. /*
  401.  * Close the name file, if any.
  402.  */
  403. name_close()
  404. {
  405.  
  406.     if (namef != NULL && namef != stdin) fclose(namef);
  407. }
  408.  
  409.  
  410. /*
  411.  * Gather names in a list for scanning.
  412.  * Could hash them later if we really care.
  413.  *
  414.  * If the names are already sorted to match the archive, we just
  415.  * read them one by one.  name_gather reads the first one, and it
  416.  * is called by name_match as appropriate to read the next ones.
  417.  * At EOF, the last name read is just left in the buffer.
  418.  * This option lets users of small machines extract an arbitrary
  419.  * number of files by doing "tar t" and editing down the list of files.
  420.  */
  421. name_gather()
  422. {
  423.     register char *p;
  424.     static struct name namebuf[1];    /* One-name buffer */
  425.  
  426.     if (f_sorted_names) {
  427.         p = name_next();
  428.         if (p) {
  429.             namebuf->length = strlen(p);
  430.             if (namebuf->length >= sizeof namebuf->name) {
  431.                 fprintf(stderr, "Argument name too long: %s\n",
  432.                     p);
  433.                 namebuf->length = (sizeof namebuf->name) - 1;
  434.             }
  435.             strncpy(namebuf->name, p, namebuf->length);
  436.             namebuf->next = (struct name *)NULL;
  437.             namebuf->found = 0;
  438.             namelist = namebuf;
  439.             namelast = namelist;
  440.         }
  441.         return;
  442.     }
  443.  
  444.     /* Non sorted names -- read them all in */
  445.     while (NULL != (p = name_next())) {
  446.         addname(p);
  447.     }
  448. }
  449.  
  450. /*
  451.  * A name from the namelist has been found.
  452.  * If it's just a list, 
  453.  
  454. /*
  455.  * Add a name to the namelist.
  456.  */
  457. addname(name)
  458.     char    *name;            /* pointer to name */
  459. {
  460.     register int    i;        /* Length of string */
  461.     register struct name    *p;    /* Current struct pointer */
  462.  
  463.     i = strlen(name);
  464.     /*NOSTRICT*/
  465.     p = (struct name *)
  466.         malloc((unsigned)(i + sizeof(struct name) - NAMSIZ));
  467.     p->next = (struct name *)NULL;
  468.     p->length = i;
  469.     p->found = 0;
  470.     strncpy(p->name, name, i);
  471.     p->name[i] = '\0';    /* Null term */
  472.     if (namelast) namelast->next = p;
  473.     namelast = p;
  474.     if (!namelist) namelist = p;
  475. }
  476.  
  477.  
  478. /*
  479.  * Match a name from an archive, p, with a name from the namelist.
  480.  *
  481.  * FIXME: Allow regular expressions in the name list.
  482.  */
  483. name_match(p)
  484.     register char *p;
  485. {
  486.     register struct name    *nlp;
  487.     register int        len;
  488.  
  489. again:
  490.     if (0 == (nlp = namelist))    /* Empty namelist is easy */
  491.         return 1;
  492.     len = strlen(p);
  493.     for (; nlp != 0; nlp = nlp->next) {
  494.         if ( nlp->name[0] == p[0]    /* First chars match */
  495.          && nlp->length <= len        /* Archive len >= specified */
  496.          && (p[nlp->length] == '\0' || p[nlp->length] == '/')
  497.                         /* Full match on file/dirname */
  498.          && strncmp(p, nlp->name, nlp->length) == 0) /* Name compare */
  499.         {
  500.             nlp->found = 1;        /* Remember it matched */
  501.             return 1;        /* We got a match */
  502.         }
  503.     }
  504.     /*
  505.      * Filename from archive not found in namelist.
  506.      * If we have the whole namelist here, just return 0.
  507.      * Otherwise, read the next name in and compare it.
  508.      * If this was the last name, namelist->found will remain on.
  509.      * If not, we loop to compare the newly read name.
  510.      */
  511.     if (f_sorted_names && namelist->found) {
  512.         name_gather();        /* Read one more */
  513.         if (!namelist->found) goto again;
  514.     }
  515.     return 0;
  516. }
  517.  
  518.  
  519. /*
  520.  * Print the names of things in the namelist that were not matched.
  521.  */
  522. names_notfound()
  523. {
  524.     register struct name    *nlp;
  525.     register char        *p;
  526.  
  527.     for (nlp = namelist; nlp != 0; nlp = nlp->next) {
  528.         if (!nlp->found) {
  529.             fprintf(stderr, "tar: %s not found in archive\n",
  530.                 nlp->name);
  531.         }
  532.         /*
  533.          * We could free() the list, but the process is about
  534.          * to die anyway, so save some CPU time.  Amigas and
  535.          * other similarly broken software will need to waste
  536.          * the time, though.
  537.          */
  538. #ifndef unix
  539.         if (!f_sorted_names)
  540.             free(nlp);
  541. #endif
  542.     }
  543.     namelist = (struct name *)NULL;
  544.     namelast = (struct name *)NULL;
  545.  
  546.     if (f_sorted_names) {
  547.         while (0 != (p = name_next()))
  548.             fprintf(stderr, "tar: %s not found in archive\n", p);
  549.     }
  550. }
  551.