home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / tapeutils.zip / tuvrt2.c < prev    next >
C/C++ Source or Header  |  1989-02-06  |  17KB  |  501 lines

  1. /*
  2. >From: EVERHART%ARISIA.decnet@GE-CRD.ARPA
  3. Newsgroups: comp.os.vms
  4. Subject: Small upgrade to TAR reader
  5. Message-ID: <8901280458.AA21037@ucbvax.Berkeley.EDU>
  6. Date: 27 Jan 89 21:23:00 GMT
  7. Sender: daemon@ucbvax.BERKELEY.EDU
  8. Organization: The Internet
  9. Lines: 489
  10.  
  11. Folks -
  12.   I noticed that some TAR tape directory trees are too deep for VMS when
  13. trying to use Sid Penstone's TAR reader here. To fix things up, I added a
  14. small edit. Its effect is to add an s option to the reader to effectively
  15. partly flatten directory trees. This is done by replacing the / between
  16. levels of directories after the first with _. As a result, one can
  17. arrange that a directory that might have been created as, for
  18. example
  19. [x11r3.lib.clx.debug]
  20.   gets created instead as
  21. [x11r3.lib_clx.debug]
  22.   and so on. Using the s option more than once allows multiple such
  23. replacements to occur. Thus, basically no information is lost so long
  24. as the total directory length is short enough to fit in a VMS file
  25. specification. The trees remain shallow enough for VMS to handle them and
  26. you can read them in.
  27.   I send it out in thanks to Sid Penstone for the original TAR reader,
  28. which works very nicely.
  29.         Glenn Everhart
  30.         Everhart%Arisia.decnet@ge-crd.arpa
  31.  
  32. ----------- cut here ----------
  33. */
  34. /* Read a TAR format tape or file , move files into VMS directories */
  35. /* Copyright 1986, Sid Penstone,
  36. *  Department of Electrical Engineering,
  37. *  Queen's University,
  38. *  Kingston, Ontario, Canada K7L3N6
  39. * (613)-545-5925
  40. * BITNET:          PENSTONE@QUCDNEE1  (Preferred)
  41. *       or  PENSTONE@QUCDN
  42. *
  43. * Version 2.3a, Jan. 17, 1989
  44. * mods: - Added a few more chars to VMS forbidden list and allowed -
  45. *       - in filenames. Added "s" option to skip a directory spec,
  46. *       - done by changing the . for subdirs into a _. Multiple s's
  47. *       - cause multiple dirs to be so "skipped". gce.
  48. *       - Use ss to pass one dir, sss for two and so on.
  49. * Version 2.3, Jan.9,1987
  50. * mods: - corrected header size (thanks to Eric Gisin, U .of Waterloo)
  51. *       - No more of the dreaded QIO's ( "  "  " )
  52. *       - tried to sort out link flag format
  53. *       - uses a tape or a file as input
  54. *       - NOTE: default is NO conversion to vms standard text format (cr)
  55. * 2.1   - trapped commas in file names, converted to '_'
  56. * 2.2   - reported translations of names
  57. *       - continued after error in opening output file
  58. *       - exit correctly after error opening input file
  59. * 2.3   - fixed bug in make_new on top level file (thanks to Ursula Natrup,
  60. *                                       natrup@vax.hmi.dfn )
  61. *       - reject "@" in filenames
  62. */
  63.  
  64.  
  65. /* The input data is in record format, length 512, blocks of 10240 bytes;
  66.  */
  67.  
  68.  
  69. #include stdio
  70. #include time
  71. #include ssdef
  72. #include iodef
  73. #include descrip
  74. #include ctype
  75.  
  76. #define ERROR1 -1
  77. #define BUFFSIZE 512
  78. #define ISDIRE 1
  79. #define ISFILE 0
  80. #define NAMSIZE 100
  81. #define SIZE 20480              /* Block size */
  82. #define DSIZE 512               /* Data block size */
  83.  
  84. struct                  /* A Tar header */
  85.     {
  86.     char title[NAMSIZE];
  87.     char protection[8];
  88.     char field1[8];             /* this is the user id */
  89.     char field2[8];             /*  this is the group id */
  90.     char count[12];             /*  was 11 in error */
  91.     char time[12];              /* UNIX format date  */
  92.     char chksum[8];             /* Header Checksum (ignored) */
  93.     char linkcount;             /* hope this is right */
  94.     char linkname[NAMSIZE]; /* Space for the name of the link */
  95.     char dummy[255];    /* and the rest */
  96.     } header;
  97.  
  98. static char buffer[DSIZE];      /* BUFFER for a record */
  99.  
  100. /* Function flags, options:*/
  101. int extract,            /* x option (default) */
  102.     list,                       /* t option : list tape contents */
  103.     verbose,            /* v option, report actions */
  104.     wait;
  105.  
  106. /* Miscellaneous globals, etc. */
  107.  
  108. char *tarfile = "tape", /* Input file name  */
  109.     pathname[NAMSIZE],  /* File name as found on tape (UNIX) */
  110.     directory[NAMSIZE], /* Current directory */
  111.     new_directory[NAMSIZE],     /* Directory of current file */
  112.     top[NAMSIZE],               /* Top level or root */
  113.     newfile[NAMSIZE],   /* VMS format of file name */
  114.     outfile[NAMSIZE],   /* Complete output file specification */
  115.     temp[256],          /* Scratch */
  116.     creation[NAMSIZE],  /* Date as extracted from the TAR file */
  117.     *ctime(),           /* System function */
  118.     linkname[NAMSIZE];  /* Linked file name  */
  119.  
  120. int bytecount,  mode, uic1, uic2, linktype;/* Data from header */
  121. int tarfd;                      /* The input file descriptor */
  122. int dirskp;             /* directories to skip in input */
  123.  
  124. main(argc,argv)
  125. int argc;
  126. char *argv[];
  127. {
  128. int isterm,status,file_type,j,c, flag;
  129. char *make_directory(), *cp;
  130.  
  131. /* Decode the options and parameters: */
  132.  
  133.     dirskp=0;
  134.     if(argc ==1)
  135.         {
  136.         extract = 1;            /* Default for now */
  137.         verbose = 1;
  138.         wait = 0;               /* Don't wait for prompt */
  139.         }
  140.     while(--argc > 0)
  141.         {
  142.         cp = argv[1];
  143.         while(c = *cp++)
  144.             {
  145.             switch(c)
  146.             {
  147.             case 't':
  148.                 list=1;
  149.                 break;
  150.             case 'x':
  151.                 extract=1;
  152.                 break;
  153.             case 'v':
  154.                 verbose=1;
  155.                 break;
  156.             case 'w':
  157.                 wait=1;
  158.                 break;
  159.             case 's':
  160.                 dirskp++;
  161.                 break;
  162.             default:
  163.                 printf("Option '%c' not recognized.\n",c);
  164.             }
  165.        }
  166.    }
  167.  
  168.  
  169. /* Find if this is a terminal */
  170.     isterm = isatty(0);
  171.  
  172. /* Set up directory names */
  173.     strcpy(top,getenv("PATH"));
  174.  
  175. /* Start with the default as the top */
  176.     strcpy(directory,top);
  177.  
  178. /* open the file for reading */
  179.     if((tarfd = opentar()) <= 0)
  180.         {
  181.         printf("Error opening the Tar tape\n");
  182.         exit(2);
  183.         }
  184. /* Now keep reading headers from this file, and decode the names, etc. */
  185.  
  186.     while((status=hdr_read(&header))==DSIZE)    /* 0 on end of file */
  187.         {
  188.         if(strlen(header.title)!=0)     /* Valid header */
  189.             {
  190.             decode_header();
  191.             if(extract)
  192.                 {
  193.                 file_type=scan_title(pathname,new_directory,newfile);
  194.                 if( make_new(new_directory)!=0)
  195.                     printf("Error creating %s\n",new_directory);
  196.                 if(file_type == ISDIRE)
  197.                     {}
  198.                 if(file_type == ISFILE)
  199. /*  Now move the data into the output file */
  200.                     if(bytecount>0)
  201.                         {
  202.                         strcpy(outfile,new_directory);
  203.                         strcat(outfile,newfile);
  204.                         if((j=copyfile(outfile,bytecount))<0)
  205.                             printf("Error writing file %s\n",outfile);
  206.                         }
  207.                 }
  208.             else                        /* listing only */
  209.                 {
  210.                 printf("%o %6d %s %s\n",
  211.                     mode,bytecount,creation+4,pathname);
  212.                 if(linktype == 0)
  213.                     tarskip(bytecount);
  214.                 else
  215.                     printf("     *****( Linked to file: %s)\n",linkname);
  216.                 }
  217.             }
  218.         else                    /* Empty header means the end!!! */
  219.             {
  220.             status = 1;
  221.             printf("End of Tar file found.\n");
  222.             break;
  223.             }
  224.  
  225.         }       /* end while  */
  226.     if(status == 1)                     /* Empty header */
  227.         {
  228.         printf("Do you wish to move past the EOF mark ? y/n\n");
  229.         gets(temp);
  230.         if(tolower(temp[0]) == 'y')
  231.             while((status=hdr_read(&header)) >0);
  232.         else
  233.             exit(SS$_NORMAL);
  234.         }
  235.     if(status==0)                       /* End of tar file  */
  236.         {
  237.         printf("End of file encountered\n");
  238.         exit(SS$_NORMAL);
  239.         }
  240.     if(status<0)                        /* An error  */
  241.         {
  242.         printf("Error reading input.\n");
  243.         exit(2);
  244.         }
  245. }
  246.  
  247.  
  248. /* This function simply copies the file to the output, no conversion */
  249.  
  250. int copyfile(outfile,nbytes)
  251. char outfile[]; /* name of output version */
  252. int nbytes;
  253.  
  254. {
  255. int inbytes, fil;
  256. /*  Open the output file */
  257.     if((fil=creat(outfile,0)) == ERROR1)
  258.         {
  259.         printf(" Creation error in opening %s \n",outfile);
  260.         tarskip(bytecount);
  261.         return(-2);
  262.         }
  263.     if(linktype !=0)
  264.         {
  265.         sprintf(buffer,"This file is linked to %s\n",linkname);
  266.         write(fil,buffer,strlen(temp));
  267.         }
  268.     else
  269.         {
  270.         while(nbytes>0)
  271.             {
  272.             if((inbytes=read(tarfd,buffer,DSIZE)) > 0)
  273.                 {
  274.                 write(fil,buffer,(nbytes > DSIZE)? DSIZE:nbytes);
  275.                 nbytes -= inbytes;
  276.                 }
  277.             else
  278.                 {
  279.                 printf("End of input file detected\n");
  280.                 close(fil);
  281.                 return(-1);
  282.                 }
  283.             }
  284.         }
  285. /* Close the file */
  286.     close(fil);
  287.     if(verbose)
  288.         {
  289.         printf("CREATED: %s\n",outfile);
  290.         if(linktype!=0)
  291.             printf(" *** REAL DATA IS IN: %s\n",linkname);
  292.         }
  293.     return(0);
  294. }
  295.  
  296. /* Decode a file name into the directory, and the name, return
  297. * a value to indicate if this is a directory name, or another file
  298. * We return the extracted directory string in "dire", and the
  299. * filename (if it exists) in "fname". The full title is in "line"
  300. * at input.
  301. */
  302.  
  303. int scan_title(line,dire,fname)
  304. char line[],dire[],fname[];
  305. {
  306. char temp[NAMSIZE],*end1;
  307. int len,len2,i,ind;
  308. int dlvl;
  309. /* The format will be UNIX at input, so we have to scan for the
  310. * UNIX directory separator '/'
  311. * If the name ends with '/' then it is actually a directory name.
  312. * If the directory consists only of '.', then don't add a subdirectory
  313. * The output directory will be a complete file spec, based on the default
  314. * directory.
  315. */
  316.     dlvl=0;
  317.     strcpy(dire,top);                   /* Start with the top level */
  318.     if(strncmp(line,"./",2)==0)
  319.         strcpy(line,line+2);            /* ignore "./" */
  320.     strcpy(temp,line);                  /* Start in local buffer */
  321.     ind=vms_cleanup(temp);              /* Remove illegal vms characters */
  322.     if((end1=strrchr(temp,'/'))==0)     /* No directory at all  ? */
  323.         strcpy(fname,temp);             /* Only a file name */
  324.     else
  325.         {                               /* End of directory name is '/' */
  326.         *end1 = 0;                      /* Terminate directory name */
  327.         dlvl=0;
  328.         strcpy(fname,end1+1);           /* File name without directory */
  329.         for (i=0;temp[i];i++)           /* Change '/' to '.' in directory */
  330.             if(temp[i]=='/'){
  331.                 temp[i]='.';
  332. /* Change first "n" . chars to _ if s option given */
  333.               if(dlvl<dirskp)temp[i]='_';
  334.               dlvl++;
  335.                         }
  336.         dire[strlen(dire)-1] = (temp[0]=='.')?0:'.' ;
  337.                  /* "." to indicate a subdirectory (unless already there )*/
  338.         strcat(dire,temp);      /* Add on the new directory  */
  339.         strcat(dire,"]") ;              /* And close with ']' */
  340.         }
  341.     if(strlen(fname)==0)        /* Could this cause problems ? */
  342.         {
  343.         return(ISDIRE);
  344.         }
  345.     else
  346.         for(i=0,end1=fname;*end1;end1++) /* Replace multiple . */
  347.             if(*end1 == '.')
  348.                 if(i++)*end1 = '_'; /* After the first */
  349.         if((i>1||ind)&& verbose )       /* Any translations ? */
  350.             printf("****RENAMED: %s \n         TO: %s\n",line,fname);
  351.     return(ISFILE);
  352. }
  353.  
  354. /* Create a new directory, finding out any higher levels that are missing */
  355.  
  356. /* We will parse the directory name into the next higher directory, and the
  357. * desired directory as "desired.dir".
  358. * Thus: "DEV:[top.sub1.sub2]" is made into "DEV:[top.sub1]sub2.dir" . If
  359. * the directory does not exist , then create the original directory. There
  360. * may be higher levels missing, so we can recurse until we reach the top
  361. * level directory, then work our way back, creating directories at each
  362. * successive level.
  363. * Bug fix: if the input file was at top level, we will not find a '.'
  364. *       and 'name' will be garbage.
  365. */
  366.  
  367. int make_new(want)
  368. char want[];
  369. {
  370. int i,len;
  371. char a[NAMSIZE],parent[NAMSIZE],*end,name[NAMSIZE];
  372.     strcpy(parent,want);
  373.     len = strlen(parent);
  374.     parent[len-1] =0 ;          /* Get rid of the "]" */
  375.     end = strrchr(parent,'.');  /* Find the last '.' */
  376.     if(end != NULL)
  377.         {
  378.         strcpy(a,end+1);        /* Get the last parent */
  379.         strcat(a,".dir");       /* Add the extension */
  380.         *end++ = ']' ;          /* Reduce the directory parent */
  381.         *end = 0;               /* Terminate the directory */
  382.         strcpy(name,parent);
  383.         strcat(name,a);
  384.  
  385.         if(access(name,0) <0)   /* Does the directory exist ? */
  386.             {
  387.                 if(strcmp(parent,top)!=0) /* No, are we at the top? */
  388.                     if(make_new(parent))   /*  No, look again */
  389.                         return(-1);     /* recurse */
  390.                 if(mkdir(want,0755,0,0,0)) /* make it */
  391.                     return(-1);         /* Leave on error */
  392.                 else
  393.                     if(verbose)
  394.                         printf("CREATED: %s\n",want);
  395.                 return(0);
  396.             }
  397.         }
  398.     return(0);
  399. }
  400.  
  401.  /* Function to open and get data from the blocked input file */
  402. int opentar()
  403. {
  404. int fd;
  405.     fd = open(tarfile, 0, "rfm = fix","mrs = 512");
  406.     if(fd < 0)
  407.         {
  408.         printf("Can't open input file \n");
  409.         return(0);
  410.         }
  411.     return(fd);
  412. }
  413.  
  414. /* Get the next file header from the input file buffer. We will always
  415. * move to the next 512 byte boundary.
  416. */
  417. int hdr_read(buffer)
  418. char *buffer;
  419. {
  420. int stat;
  421.     stat = read(tarfd,buffer,DSIZE);    /* read the header */
  422.     return(stat);                               /* Catch them next read ? */
  423. }
  424.  
  425.  
  426. /* This is supposed to skip over data to get to the desired position */
  427. /* Position is the number of bytes to skip. We should never have to use
  428. * this during data transfers; just during listings. */
  429. int tarskip(bytes)
  430. int bytes;
  431. {
  432. int i=0;
  433.     while(bytes > 0)
  434.         {
  435.         if((i=read(tarfd,buffer,DSIZE)) == 0)
  436.             {
  437.             printf("End of file encountered while skipping.\n");
  438.             return(-1);
  439.             }
  440.         bytes -= i;
  441.         }
  442.     return(0);
  443. }
  444.  
  445. /* Decode the fields of the header */
  446.  
  447. int decode_header()
  448. {
  449. int idate, *bintim;
  450. char ll;
  451. bintim = &idate;
  452.     linktype=0; strcpy(linkname,"");
  453.     strcpy(pathname,header.title);
  454.     sscanf(header.time,"%o",bintim);
  455.     strcpy(creation,ctime(bintim));     /* Work on this! */
  456.     creation[24]=0;
  457.     sscanf(header.count,"%o",&bytecount);
  458.     sscanf(header.protection,"%o",&mode);
  459.     sscanf(header.field1,"%o",&uic1);
  460.     sscanf(header.field2,"%o",&uic2);
  461.     /* We may have the link written as binary or as character:  */
  462.     linktype = isdigit(header.linkcount)?
  463.             (header.linkcount - '0'):header.linkcount;
  464.     if(linktype != 0)
  465.         sscanf(header.linkname,"%s",linkname);
  466.     return(0);
  467. }
  468.  
  469.  
  470. /* remove illegal characters from directory and file names; replace
  471. * hyphens and commas with underscores.Returns number of translations
  472. * that were made.
  473. */
  474. vms_cleanup(string)
  475. char string[];
  476. {
  477. int i,flag=0;
  478. char c;
  479.     for(i=0;c=string[i];i++)
  480.         {
  481.         switch (c)
  482.             {
  483. /* allow hyphens; ok sinve vms 4.4 */
  484. /*            case '-':    */       /* No hyphens in file names */
  485.             case ',':           /* No commas in file names  */
  486.             case '+':           /* No plusses in file names */
  487.             case '@':           /* No '@' allowed in a name  */
  488.             case '^':           /* No '^' allowed in a name  */
  489.             case '&':           /* No '&' allowed in a name  */
  490.             case '?':           /* No '?' allowed in a name  */
  491.             case '*':           /* No '*' allowed in a name  */
  492.                 string[i]= '_';
  493.                 flag++;         /* Record if any changes were made */
  494.                 break;
  495.             default:
  496.                 break;
  497.             }
  498.         }
  499.     return(flag);
  500. }
  501.