home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #30 / NN_1992_30.iso / spool / comp / os / vms / 19139 < prev    next >
Encoding:
Text File  |  1992-12-11  |  13.9 KB  |  456 lines

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