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

  1. Path: sparky!uunet!cs.utexas.edu!sun-barr!ames!agate!ucbvax!mhs.attmail.com!simons/G=Colin/I=CB/S=Sewell/O=H.A.Simons.Ltd/OU=CORP
  2. From: simons/G=Colin/I=CB/S=Sewell/O=H.A.Simons.Ltd/OU=CORP@mhs.attmail.com
  3. Newsgroups: comp.os.vms
  4. Subject: Re: tar for vms
  5. Message-ID: <9212120130.AA07805@ucbvax.Berkeley.EDU>
  6. Date: 11 Dec 92 22:09:19 GMT
  7. Sender: daemon@ucbvax.BERKELEY.EDU
  8. Distribution: world
  9. Organization: The Internet
  10. Lines: 1985
  11.  
  12. #pragma nostandard
  13. #module VMSTAR "V2.0"
  14. #pragma builtins
  15.  
  16. /*
  17. **      VMSTAR.C - a Un*x-like tar reader/writer for VMS
  18. **                 based on TAR2VMS and VMS2TAR
  19. **
  20. ** Usage:
  21. **      tar x|t|c[vwbd][f tarfile] [file [file...]]
  22. **      x - extract from tarfile
  23. **      t - type contents of tarfile
  24. **      c - create tarfile, archive VMS files
  25. **      v - verbose
  26. **      w - wait for confirmation before extracting/archiving
  27. **      b - binary mode extract, create (rfm=fixed, rat=none, mrs=512) files
  28. **      z - automatic mode, try to guess if files are text or binary, extract
  29. **          text files as (rfm=stream-LF, rat=cr) binary files as
  30. **          (rfm=fixed, rat=none, mrs=512)
  31. **      d - keep trailing dots in file names
  32. **      o - restore original owner
  33. **      f - specify tarfile name, default is $TAPE
  34. **      file - space-separated list of file names, can include VMS-style
  35. **             string wildcards on extract, can be any VMS file name
  36. **             specification (except DECnet) on create archive.
  37. **
  38. ** Original author of the VMS2TAR and TAR2VMS programs:
  39. ** Copyright 1986, Sid Penstone,
  40. **  Department of Electrical Engineering,
  41. **  Queen's University,
  42. **  Kingston, Ontario, Canada K7L3N6
  43. ** (613)-545-2925
  44. ** BITNET:   PENSTONE@QUCDNEE1
  45. **
  46. ** Also deeply modified by:
  47. ** Colin Sewell
  48. ** H. A. Simons Ltd.
  49. ** Vancouver, BC
  50. **
  51. ** Deeply modified by:
  52. ** Alain Fauconnet
  53. ** System Manager
  54. ** SIM - Public Health Research Laboratories
  55. ** 91 Boulevard de l'Hopital
  56. ** 75634 PARIS CEDEX 13 - FRANCE
  57. ** Bitnet: FAUCONNE@FRSIM51
  58. **
  59. ** PROBLEMS SHOULD BE REPORTED TO ME. PLEASE DON'T BOTHER SID PENSTONE
  60. ** WITH MY OWN BUGS !
  61. **
  62. ** Version 2.0 21-NOV-1992
  63. ** Based on TAR2VMS V2.2 21-OCT-1986 and VMS2TAR V1.8 23-DEC-1986
  64. **
  65. ** Sid Penstone did not include any copyright information in his program so
  66. ** this only applies if Sid Penstone agrees: you may use VMSTAR, distribute it,
  67. ** modify it freely provided you don't use it for commercial
  68. ** or military purposes. Please include the two above author names in the
  69. ** source file of any modified version of VMSTAR.
  70. **
  71. ** Modification history:
  72. **
  73. ** 2.0   - complete rewrite
  74. ** 1.6-0 - added 'z' option for automatic determination of file type on
  75. **         extraction
  76. **       - reworked copyfile() to close files and exit on fatal error -
  77. **         error status not returned, they weren't checked anyway
  78. **       - some code cleanup (much, much more to do...)
  79. ** 1.5-3 - removed duplicate error message
  80. ** 1.5-2 - removed duplicate #include iodef
  81. **       - added write status checking in copyfile and cleaned up error
  82. **         handling (avoids duplicate messages)
  83. ** 1.5-1 - fix by Mark Parisi <MPARISI@RIPPLE.JPL.NASA.GOV>
  84. **         fixed bug in out_file: if the length of a text file was an
  85. **         exact multiple of DSIZE, flushout was called an additional
  86. **         time.
  87. **       - added some code for empty files handling.
  88. ** 1.5  - when archiving a non-text file with rfm=stream_lf, rat=cr
  89. **        attributes, VMSTAR truncated the file. Modified out_file
  90. **        to more cleanly handle various RMS file formats: only
  91. **        variable and stream_cr record formats need two passes to compute
  92. **        the actual file size and need to be read record by record.
  93. **        All other formats should by read buffer by buffer and written
  94. **        as-is in the tar archive, thus out_file now fopens the file
  95. **        in binary mode and freads buffers.
  96. **        In the case of a stream_cr file, if a single record cannot fit in
  97. **        our buffers (probably because the file is non-text and has
  98. **        incorrect RMS attributes) out_file now error exits.
  99. ** 1.4  - fixed a bug in scan_title that caused VMSTAR to fail on
  100. **        extraction of absolute tarfiles (thanks to Tom Allebrandi
  101. **        for this one)
  102. **      - added some code in scan_title to correctly handle dots in
  103. **        directory names found in tarfile (replaced by "_")
  104. ** 1.3  - changed tar2vms to use standard IO calls (fopen, fread) to
  105. **        read input tarfile in binary mode i.e. no translation of
  106. **        RMS record attributes done by C RTL. This fixes problem reading
  107. **        tarfiles created with rfm=fix, rat=cr
  108. **      - more room for file size in output formats
  109. ** 1.2  - fixed bug in out_file not closing input VMS file, limited
  110. **        maximum number of files archived to FILLM quota
  111. **      - added mapping to underscores of some more characters found
  112. **        in Un*x file names illegal in VMS file names
  113. ** 1.1  - reworked handling of current VMS default
  114. **      - will now create *relative* tarfiles (i.e. files known
  115. **        as "./..." in tar archive directory) except when
  116. **        device name is specified or wilcard search gives filenames
  117. **        located above current default (tar cvf foo.tar [-...]*.* will
  118. **        lead to this kind of situation)
  119. **      - attempt to handle more than 8 levels of directories upon
  120. **        extract : .../d7/d8/d9 will be mapped to [...D7.D8$D9]
  121. **      - greatly simplified make_new() because mkdir() creates
  122. **        intermediate levels of directories if missing
  123. ** 1.0  Original version from Sid Penstone's code
  124. **      - merged VMS2TAR & TAR2VMS into a single source file
  125. **      - code reworked, messages cleaned up
  126. **      - added support for 'f tarfile' option, changed default to $TAPE
  127. **      - added support for VMS style wildcard file names on extract
  128. **      - added support for 'b' (binary file extract) option
  129. **      - suppressed usage of intermediate scratch file for create operation
  130. **      - file list on create should now be space separated (removed difficult
  131. **        support of comma-separated list with context "a la BACKUP")
  132. **      - global code simplification attempt, may have broken some
  133. **        odd case handling
  134. **      - added some error handling in tarfile write operations
  135. **      - probably millions of bugs introduced... sorry.
  136. */
  137.  
  138.  
  139. /****************************************************************************/
  140. /*  declarations                                                            */
  141. /****************************************************************************/
  142.  
  143. #include stdlib
  144. #include stdio
  145. #include time
  146. #include ssdef
  147. #include iodef
  148. #include dvidef
  149. #include dcdef
  150. #include descrip
  151. #include ctype
  152. #include strdef
  153. #include rms
  154. #include stsdef
  155. #include file
  156. #include stat
  157. #include types
  158. #include string
  159. #include errno
  160. #include hlpdef
  161.  
  162. #define ISFILE      0           /* is a file                            */
  163. #define ISDIRE      1           /* is a directory                       */
  164. #define BLKSIZE     20          /* Block size                           */
  165. #define DSIZE       512         /* Data block size                      */
  166. #define EOS         '\0'        /* End of string character              */
  167.  
  168. #define NAMSIZE     100
  169. #define MODESIZE    8
  170. #define UIDSIZE     8
  171. #define GIDSIZE     8
  172. #define COUNTSIZE   12
  173. #define TIMESIZE    12
  174. #define CHKSUMSIZE  8
  175.  
  176. struct tarhdr                   /* A tar header                         */
  177.     {
  178.     char title[NAMSIZE];        /* name of entry                        */
  179.     char mode[MODESIZE];        /* file mode                            */
  180.     char uid[UIDSIZE];          /* this is the user id                  */
  181.     char gid[GIDSIZE];          /* this is the group id                 */
  182.     char count[COUNTSIZE];      /* was 11 in error                      */
  183.     char time[TIMESIZE];        /* UNIX format date                     */
  184.     char chksum[CHKSUMSIZE];    /* header checksum                      */
  185.     char linkcount;             /* hope this is right                   */
  186.     char linkname[NAMSIZE];     /* Space for the name of the link       */
  187.     char dummy[255];            /* and the rest                         */
  188.     };
  189.  
  190.  
  191. /****************************************************************************/
  192. /*  Function flags, options                                                 */
  193. /****************************************************************************/
  194.  
  195. static int extract  = 0;        /* x option, extract                        */
  196. static int list     = 0;        /* t option, list tape contents             */
  197. static int create   = 0;        /* c option, create                         */
  198. static int verbose  = 0;        /* v option, report actions                 */
  199. static int wait     = 0;        /* w option, prompt                         */
  200. static int dot      = 0;        /* d option, suppress dots                  */
  201. static int binmode  = 0;        /* b option, binary mode                    */
  202. static int automode = 0;        /* z option, automatic mode                 */
  203. static int foption  = 0;        /* f option, specify tarfile                */
  204. static int debug    = 0;        /* D option, debug                          */
  205. static int owner    = 0;
  206. static int help     = 0;
  207.  
  208. static int devclass = 0;        /* Tar file device class                    */
  209.  
  210. /****************************************************************************/
  211. /*  Miscellaneous globals, etc.                                             */
  212. /****************************************************************************/
  213.  
  214. static char tarfile[NAM$C_MAXRSS] = "$TAPE";/* Tarfile name                 */
  215. static char curdir[NAM$C_MAXRSS];           /* Current directory            */
  216. static FILE *tarfp;                         /* tar file pointer             */
  217.  
  218.  
  219. /****************************************************************************/
  220. /*  Global file characteristics                                             */
  221. /****************************************************************************/
  222.  
  223. /* Chars found in Un*x file names, illegal in VMS */
  224.  
  225. static const char   badchars[] = { ",+~`@#%^*?|\&[]{}" };       
  226.  
  227. /* only get the most recent version */
  228.  
  229. static const char   default_name[] = { "*.*;" };
  230.  
  231.  
  232. /****************************************************************************/
  233. /*  Forward definitions/prototypes                                          */
  234. /****************************************************************************/
  235. char    *vmserr( int );                     /* return ptr to vms error text */
  236. char    *tar_format_mode( int, char * );    /* format file mode             */
  237. char    *tar_format_time( int );            /* format time                  */
  238.  
  239.  
  240.  
  241. /****************************************************************************/
  242. /*                                                                          */
  243. /*  main program -- parses options, dispatches to tar2vms and vms2tar       */
  244. /*                                                                          */
  245. /****************************************************************************/
  246. static int vmstar( int argc, char *argv[] ) MAIN_PROGRAM
  247.  
  248. {
  249.  
  250.     register char   *cp;
  251.     register char   c;
  252.  
  253.  
  254.     /************************************************************************/
  255.     /*  decode the options and parameters:                                  */
  256.     /************************************************************************/
  257.  
  258.     if (argc == 1) tar_usage();
  259.  
  260.  
  261.     cp = argv[1];
  262.  
  263.     while (c = *cp++)
  264.         {
  265.         switch(c)
  266.             {
  267.             case 't':
  268.                 list = 1;
  269.                 break;
  270.  
  271.             case 'x':
  272.                 extract = 1;
  273.                 break;
  274.  
  275.             case 'c':
  276.                 create = 1;
  277.                 break;
  278.  
  279.             case 'v':
  280.                 verbose = 1;
  281.                 break;
  282.  
  283.             case 'w':
  284.                 wait = 1;
  285.                 break;
  286.  
  287.             case 'd':
  288.                 dot = 1;
  289.                 break;
  290.  
  291.             case 'b':
  292.                 binmode = 1;
  293.                 break;
  294.  
  295.             case 'z':
  296.                 automode = 1;
  297.                 break;
  298.  
  299.             case 'D':
  300.                 debug = 1;
  301.                 break;
  302.  
  303.             case 'o':
  304.                 owner = 1;
  305.                 break;
  306.  
  307.             case 'h':
  308.                 help = 1;
  309.                 break;
  310.  
  311.             case 'f':
  312.                 if (*cp != '\0' || argc < 3)
  313.                     tar_usage();
  314.                 else
  315.                     foption = 1;
  316.                     strcpy( tarfile, argv[2] );
  317.                 break;
  318.  
  319.             case '-':
  320.                 break;
  321.  
  322.             default:
  323.                 fprintf( stderr, "tar: option '%c' not recognized.\n",c );
  324.                 tar_usage();
  325.             }
  326.         }
  327.  
  328.  
  329.  
  330.     if (help)
  331.         {
  332.         int     status;
  333.         int     lib$put_output();
  334.         int     lib$get_input();
  335.         $DESCRIPTOR( vmstardsc,     "VMSTAR" );
  336.         $DESCRIPTOR( helplibdsc,    "SOE$UTIL:VMSTAR" );
  337.         status = lbr$output_help( &lib$put_output, 0, &vmstardsc, &helplibdsc,
  338.                                     &HLP$M_PROMPT, &lib$get_input );
  339.         return status;
  340.         }
  341.  
  342.  
  343.  
  344.     /************************************************************************/
  345.     /*  check options are coherent                                          */
  346.     /************************************************************************/
  347.  
  348.     if (extract + list + create == 0)
  349.         {
  350.         fprintf( stderr, "tar: no action specified.\n" );
  351.         exit(1);
  352.         }
  353.  
  354.     if (extract + create == 2)
  355.         {
  356.         fprintf( stderr, "tar: incompatible options 'x' and 'c' specified.\n" );
  357.         exit(1);
  358.         }
  359.  
  360.     if (binmode + automode == 2)
  361.         fprintf( stderr, "tar: incompatible options 'b' and 'z' specified.\n" );
  362.  
  363.  
  364.     /************************************************************************/
  365.     /*  get current directory                                               */
  366.     /************************************************************************/
  367.  
  368.     strcpy( curdir, getenv("PATH") );
  369.  
  370.     cp = strchr( curdir, ':' );         /* extract directory                */
  371.     strcpy( curdir, cp+1 );
  372.     tar_clean_dir( curdir );
  373.  
  374.     if (debug)
  375.         printf( "curdir = %s\n", curdir );
  376.  
  377.     if (create == 0)
  378.         tar2vms( argc, argv );
  379.     else
  380.         vms2tar( argc, argv );
  381.  
  382.     return SS$_NORMAL;
  383.  
  384. }
  385.  
  386.  
  387.  
  388. /****************************************************************************/
  389. /*  tar2vms -- handles extract and list options                             */
  390. /****************************************************************************/
  391. static tar2vms( int argc, char **argv )
  392.  
  393. {
  394.  
  395.     int                     status;
  396.     int                     ftype;
  397.     char                    *ptr;
  398.     char                    pathname[NAMSIZE+1];
  399.     char                    linkname[NAMSIZE+1];
  400.     char                    filespec[NAM$C_MAXRSS+1];
  401.     char                    dirnam[NAM$C_MAXRSS];
  402.     char                    filnam[NAM$C_MAXRSS];
  403.     struct stat             sblock;
  404.     struct tarhdr           header;
  405.     struct dsc$descriptor   pattern     = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
  406.     struct dsc$descriptor   candidate   = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
  407.  
  408.  
  409.  
  410.     /************************************************************************/
  411.     /* open the file for reading                                            */
  412.     /************************************************************************/
  413.  
  414.     if ((tarfp = fopen( tarfile, "rb" )) == NULL)
  415.         {
  416.         fprintf( stderr, "tar: error opening tarfile.\n" );
  417.         perror( "tar" );
  418.         exit( 1 );
  419.         }
  420.  
  421.     fgetname( tarfp, tarfile );
  422.     lowercase( tarfile );
  423.  
  424.     candidate.dsc$w_length  = strlen( tarfile );
  425.     candidate.dsc$a_pointer = tarfile;
  426.  
  427.     status = lib$getdvi( &DVI$_DEVCLASS, 0, &candidate, &devclass );
  428.     if (!(status & 1))
  429.         {
  430.         fprintf( stderr, "tar: error getting device information for %s\n", tarfile );
  431.         fprintf( stderr, "tar: %s\n", vmserr( status ) );
  432.         exit( SS$_NORMAL );
  433.         }
  434.  
  435.  
  436.     /************************************************************************/
  437.     /* Now keep reading headers from this file, and decode the names, etc.  */
  438.     /************************************************************************/
  439.  
  440.  
  441.     while ((status = fread( &header, 1, DSIZE, tarfp )) == DSIZE)    /* 0 on end of file */
  442.         {
  443.  
  444.         /********************************************************************/
  445.         /*  exit on empty header                                            */
  446.         /********************************************************************/
  447.  
  448.         if (!strlen(header.title)) exit( SS$_NORMAL );
  449.  
  450.  
  451.  
  452.         /********************************************************************/
  453.         /*  decode the header info                                          */
  454.         /********************************************************************/
  455.  
  456.         tar_decode_hdr( &header, pathname, linkname, &sblock );
  457.  
  458.  
  459.  
  460.         /********************************************************************/
  461.         /*  Now if file names were specified on the command line, check     */
  462.         /*  if they match the current one                                   */
  463.         /********************************************************************/
  464.  
  465.         if ((foption == 0 && argc > 2) || argc > 3)
  466.             {
  467.  
  468.             register int    argi = foption ? 3 : 2;
  469.  
  470.             candidate.dsc$w_length = strlen( pathname );
  471.             candidate.dsc$a_pointer = pathname;
  472.  
  473.             while (argi < argc)
  474.                 {
  475.                 pattern.dsc$w_length = strlen( argv[argi] );
  476.                 pattern.dsc$a_pointer = argv[argi];
  477.  
  478.                 ++argi;
  479.  
  480.                 if ((status = STR$MATCH_WILD( &candidate, &pattern )) == STR$_MATCH)
  481.                     break;
  482.                 }
  483.  
  484.             if (status != STR$_MATCH)
  485.                 {
  486.                 if (!sblock.st_nlink) tar_skip( sblock.st_size );
  487.                 continue;
  488.                 }
  489.  
  490.             }
  491.  
  492.  
  493.         /********************************************************************/
  494.         /*  listing only                                                    */
  495.         /********************************************************************/
  496.  
  497.         if (list)
  498.             {
  499.             tar_display_hdr( pathname, linkname, &sblock );
  500.             if (!sblock.st_nlink) tar_skip( sblock.st_size );
  501.             continue;
  502.             }
  503.  
  504.  
  505.         /********************************************************************/
  506.         /*  prompt to process file                                          */
  507.         /********************************************************************/
  508.  
  509.         if (wait)
  510.             {
  511.             char    temp[4] = EOS;
  512.  
  513.             while (*temp != 'y' && *temp != 'n')
  514.                 {
  515.                 printf( "x %s: ", pathname );
  516.                 scanf( "%s", temp );
  517.                 *temp = _tolower( *temp );
  518.                 }
  519.  
  520.             if (*temp != 'y')
  521.                 {
  522.                 tar_skip( sblock.st_size );
  523.                 continue;
  524.                 }
  525.             }
  526.  
  527.  
  528.         ftype = tar_cvt_unixname_to_vmsname( pathname, dirnam, filnam );
  529.  
  530.         tar_clean_dir( dirnam );
  531.  
  532.         if (tar_create_dir( dirnam ))
  533.             {
  534.             fprintf( stderr, "tar: error creating %s\n", dirnam );
  535.             perror( "tar" );
  536.             if (!sblock.st_nlink) tar_skip( sblock.st_size );
  537.             continue;
  538.             }
  539.  
  540.  
  541.         if (ftype == ISFILE)
  542.             {
  543.             strcpy( filespec, dirnam );
  544.             strcat( filespec, filnam );
  545.             tar_extract_file( filespec, linkname, &sblock );
  546.             }
  547.  
  548.         }
  549.  
  550.  
  551.     if (!status)            /* End of tar file  */
  552.         {
  553.         fprintf( stderr, "tar: EOF hit on tarfile.\n" );
  554.         exit( SS$_NORMAL );
  555.         }
  556.  
  557.  
  558.     if (status < 0)         /* An error  */
  559.         {
  560.         fprintf( stderr, "tar: error reading tarfile.\n" );
  561.         perror( "tar" );
  562.         exit( SS$_NORMAL );
  563.         }
  564.  
  565. }
  566.  
  567.  
  568.  
  569.  
  570. /****************************************************************************/
  571. /*  This function simply copies the file to the output, no conversion       */
  572. /****************************************************************************/
  573. static tar_extract_file
  574.     (   char        outfile[],  /* name of output file                      */
  575.         char        linkname[],
  576.         struct stat *sblock )
  577.  
  578. {
  579.  
  580.     char    buffer[DSIZE];      /* buffer for a tarfile record              */
  581.     int     nbytes      = sblock->st_size;
  582.     int     inbytes     = 0;
  583.     int     outbytes    = 0;
  584.     int     outfd;
  585.     int     binfile     = binmode;
  586.  
  587.  
  588.     /************************************************************************/
  589.     /*  Read the first block of the tarred file                             */
  590.     /************************************************************************/
  591.  
  592.     if (sblock->st_nlink == 0 && nbytes)
  593.         {
  594.  
  595.         if ((inbytes = fread( buffer, 1, DSIZE, tarfp )) < 0)
  596.             {
  597.             fprintf( stderr, "tar: error reading tar file.\n" );
  598.             perror( "tar" );
  599.             tar_skip( nbytes );
  600.             return;
  601.             }
  602.  
  603.  
  604.         /********************************************************************/
  605.         /*  If automatic mode is set, then try to figure out what kind      */
  606.         /*  of file this is.                                                */
  607.         /********************************************************************/
  608.  
  609.         if (automode && inbytes)
  610.             {
  611.  
  612.             int     i;
  613.             int     ctlchars        = 0;
  614.             int     eightbitchars   = 0;
  615.             int     nchars          = nbytes < inbytes ? nbytes : inbytes;
  616.             char    c;
  617.  
  618.             /****************************************************************/
  619.             /*  Scan the buffer, counting chars with msb set and control    */
  620.             /*  chars not CR, LF or FF                                      */
  621.             /****************************************************************/
  622.  
  623.             for (i = 0; i < nchars; ++i)
  624.                 {
  625.  
  626.                 c = buffer[i];
  627.  
  628.                 if (c < ' ' && c != 0x0a && c != 0x0c && c != 0x0d && c != 0x09)
  629.                     ctlchars++;
  630.  
  631.                 if (c > 127)
  632.                     eightbitchars++;
  633.  
  634.                 }
  635.  
  636.             /****************************************************************/
  637.             /* Apply some heuristics to determine file is text or binary    */
  638.             /****************************************************************/
  639.  
  640.             ctlchars = ctlchars * 100 / nchars;
  641.  
  642.             eightbitchars = eightbitchars * 100 / nchars;
  643.  
  644.             if  (ctlchars > 10 || eightbitchars > 30 ||
  645.                 (ctlchars > 5 && eightbitchars > 20))
  646.                 binfile = 1;
  647.             
  648.             }
  649.         }
  650.  
  651.  
  652.  
  653.  
  654.     /************************************************************************/
  655.     /*  Open the output file                                                */
  656.     /************************************************************************/
  657.  
  658.     if (binfile)
  659.         outfd = creat( outfile, sblock->st_mode, "rfm=fix", "mrs=512", "alq=5" );
  660.     else
  661.         outfd = creat( outfile, sblock->st_mode, "rfm=stmlf", "rat=cr" );
  662.  
  663.  
  664.     if (outfd < 0)
  665.         {
  666.         fprintf( stderr, "tar: error creating %s \n", outfile );
  667.         perror( "tar" );
  668.         if (!sblock->st_nlink) tar_skip( nbytes - inbytes );
  669.         return;
  670.         }
  671.  
  672.  
  673.     getname( outfd, outfile );
  674.     lowercase( outfile );
  675.  
  676.     if (sblock->st_nlink)
  677.         {
  678.         sprintf( buffer, "*** This file is a link to %s\n", linkname );
  679.         outbytes = write( outfd, buffer, strlen( buffer ) );
  680.         }
  681.     else
  682.         {
  683.         while (nbytes > 0 && inbytes >= 0 && outbytes >= 0)
  684.             {
  685.             outbytes = write( outfd, buffer, inbytes <= nbytes ? inbytes : nbytes );
  686.             if (outbytes > 0)
  687.                 {
  688.                 nbytes -= inbytes;
  689.                 if (nbytes > 0) inbytes = fread( buffer, 1, DSIZE, tarfp );
  690.                 }
  691.             }
  692.         }
  693.  
  694.  
  695.     if (!inbytes && inbytes)
  696.         {
  697.         fprintf( stderr, "tar: unexpected EOF on tar file.\n" );
  698.         perror("tar");
  699.         close( outfd );
  700.         return;
  701.         }
  702.  
  703.     if (inbytes < 0)
  704.         {
  705.         fprintf( stderr, "tar: error reading tar file.\n" );
  706.         perror("tar");
  707.         close( outfd );
  708.         return;
  709.         }
  710.  
  711.     if (outbytes < 0)
  712.         {
  713.         fprintf( stderr, "tar: error writing file %s\n", outfile );
  714.         perror( "tar" );
  715.         close( outfd );
  716.         tar_skip( nbytes );
  717.         return;
  718.         }
  719.  
  720.  
  721.     close( outfd );
  722.  
  723.     if (owner)
  724.         chown( outfile, sblock->st_uid, sblock->st_gid );
  725.  
  726.     if (verbose)
  727.         {
  728.         printf( "x %c%s%s%s, %d byte%s\n",
  729.                     binfile ? '*' : ' ',
  730.                     outfile,
  731.                     sblock->st_nlink ? " -> " : "",
  732.                     sblock->st_nlink ? linkname : "",
  733.                     sblock->st_size,
  734.                     sblock->st_size != 1 ? "s" : "" );
  735.         }
  736.  
  737.     return;
  738.  
  739. }
  740.  
  741.  
  742.  
  743. /****************************************************************************/
  744. /*  tar_cvt_unixname_to_vmsname                                             */
  745. /*                                                                          */
  746. /*      decode a Un*x file name into the directory and name                 */
  747. /*                                                                          */
  748. /*  Return a value to indicate if this is a directory name, or another file */
  749. /*  We return the extracted directory string in "dire", and the             */
  750. /*  filename (if it exists) in "fname". The full title is in "line"         */
  751. /*  at input.                                                               */
  752. /****************************************************************************/
  753. static int tar_cvt_unixname_to_vmsname
  754.     (   char    pathname[],
  755.         char    dirnam[],
  756.         char    filnam[] )
  757.  
  758. {
  759.  
  760.     char            temp[NAM$C_MAXRSS+1];
  761.     register char   *cp;
  762.     register char   *cp1;
  763.  
  764.  
  765.     *dirnam = *filnam = EOS;
  766.  
  767.     /************************************************************************/
  768.     /*  The format will be UNIX at input, so we have to scan for the        */
  769.     /*  UNIX directory separator '/'                                        */
  770.     /*  If the name ends with '/' then it is actually a directory name.     */
  771.     /*  If the directory consists only of '.', then don't add a             */
  772.     /*  subdirectory. The output directory will be a complete file spec,    */
  773.     /*  based on the default directory.                                     */
  774.     /************************************************************************/
  775.  
  776.     if (!strncmp( pathname, "./", 2))
  777.         strcpy( pathname, pathname + 2 );   /* ignore "./"                  */
  778.  
  779.     strcpy( temp, pathname );               /* work on a copy               */
  780.  
  781.     tar_clean_filespec( temp );             /* Remove illegal vms characters*/
  782.  
  783.  
  784.     if (cp = strrchr( temp, '/' ))
  785.         {
  786.         if (cp != &temp[strlen(temp) - 1])  /* no trailing "/"              */
  787.             strcpy( filnam, cp + 1 );
  788.  
  789.         *cp = EOS;
  790.  
  791.         while (cp = strchr( temp, '.' )) *cp = '_';
  792.         while (cp = strchr( temp, '/' )) *cp = '.';
  793.  
  794.         if (*temp == '.')                   /* absolute path                */
  795.             {
  796.             strcpy( dirnam, "[" );
  797.             strcat( dirnam, temp );
  798.             }
  799.         else                                /* relative path                */
  800.             {
  801.             strcpy( dirnam, curdir );
  802.             dirnam[ strlen(dirnam) - 1 ] = '.';
  803.             strcat( dirnam, temp );
  804.             }
  805.  
  806.         strcat( dirnam, "]" );
  807.  
  808.         }
  809.     else
  810.         {
  811.         strcpy( filnam, temp );             /* no "/", a file               */
  812.         strcpy( dirnam, curdir );
  813.         }
  814.     
  815.  
  816.  
  817.     /************************************************************************/
  818.     /*  fix up filename; replaces all '.' after first '.' with '_'          */
  819.     /************************************************************************/
  820.  
  821.     if (cp = strchr( filnam, '.' ))
  822.         while (cp1 = strchr( cp+1, '.' )) *cp1 = '_';
  823.  
  824.  
  825.     if (*filnam == EOS)
  826.         return ISDIRE;
  827.     else
  828.         return ISFILE;
  829.  
  830. }
  831.  
  832.  
  833.  
  834.  
  835. /****************************************************************************/
  836. /*  tar_create_dir -- create a new directory                                */
  837. /****************************************************************************/
  838. static int tar_create_dir( char want[] )
  839.  
  840. {
  841.  
  842.     int         status;
  843.     int         created     = 1;
  844.     char        *dotp;
  845.  
  846.  
  847.     status = mkdir( want, 0 );      /* mkdir in VAX C creates all missing levels */
  848.  
  849.     if (status)
  850.         {
  851.  
  852.         if (errno == EEXIST)        /* exists                               */
  853.             return 0;
  854.  
  855.         if (errno != EINVAL)
  856.             return -1;              /* unknown error, simply return         */
  857.  
  858.                                     /* maybe too many levels of directories */
  859.                                     /* change "[...FOO.BAR]" to "[...FOO$BAR]" */
  860.  
  861.         for (dotp = &want[strlen(want) - 1]; dotp > want && status != 0; )
  862.             if (*--dotp == '.')
  863.                 {
  864.                 *dotp = '$';
  865.                 status = mkdir( want, 0 );
  866.                 if (status && (errno == EEXIST))
  867.                     {
  868.                     status = created = 0;
  869.                     break;
  870.                     }
  871.                 }
  872.         }
  873.  
  874.     if (status)
  875.         return -1;
  876.  
  877.     if (verbose && created)
  878.         printf( "x %s%\n", want );
  879.  
  880.     return 0;
  881.  
  882. }
  883.  
  884.  
  885.  
  886.  
  887. /****************************************************************************/
  888. /*  This is supposed to skip over data to get to the desired position       */
  889. /*  Position is the number of bytes to skip.                                */
  890. /****************************************************************************/
  891. static int tar_skip( int bytes )
  892.  
  893. {
  894.  
  895.     register int    i;
  896.  
  897.     if (bytes <= 0) return 0;
  898.  
  899.     if (devclass != DC$_TAPE)
  900.         {
  901.  
  902.         int skipsize = (DSIZE * (bytes / DSIZE)) + ((bytes % DSIZE) ? DSIZE : 0);
  903.  
  904.         if ((i = fseek( tarfp, skipsize, 1 )) == EOF)
  905.             {
  906.             fprintf( stderr, "tar: EOF hit on tar file while skipping.\n" );
  907.             return -1;
  908.             }
  909.  
  910.         }
  911.     else
  912.         {
  913.  
  914.         int skipsize = (bytes / DSIZE) + ((bytes % DSIZE) ? 1 : 0);
  915.         char buffer[DSIZE];
  916.         int j;
  917.  
  918.         for (j = 0; j < skipsize; j++)
  919.             {
  920.             if (( i = fread( buffer, 1, DSIZE, tarfp )) == 0)
  921.                 {
  922.                 fprintf( stderr, "tar: EOF hit on tar file while skipping.\n" );
  923.                 return -1;
  924.                 }
  925.             }
  926.  
  927.         }
  928.  
  929.     return 0;
  930.  
  931. }
  932.  
  933.  
  934.  
  935. /****************************************************************************/
  936. /*  Display the header                                                      */
  937. /****************************************************************************/
  938. static int tar_display_hdr
  939.     (   char        *pathname,
  940.         char        *linkname,
  941.         struct stat *sblock )
  942.  
  943.  
  944. {
  945.     int     link = (sblock->st_nlink == 1 || sblock->st_nlink == 2);
  946.  
  947.     if (verbose)
  948.         {
  949.  
  950.         char    uidstr[9];
  951.         char    gidstr[9];
  952.         int     status;
  953.         short   namlen;
  954.         $DESCRIPTOR( uiddsc, uidstr );
  955.  
  956.         switch (sblock->st_uid)
  957.             {
  958.             case 0:
  959.                 strcpy( uidstr, "root" );
  960.                 break;
  961.             case 1:
  962.                 strcpy( uidstr, "system" );
  963.                 break;
  964.             default:
  965.                 if ((status = sys$idtoasc( sblock->st_uid, &namlen, &uiddsc, 0, 0, 0 )) & 1)
  966.                     {
  967.                     uidstr[namlen] = EOS;
  968.                     lowercase( uidstr );
  969.                     }
  970.                 else
  971.                     sprintf( uidstr, "%-8d", sblock->st_uid );
  972.             }
  973.  
  974.  
  975.         switch (sblock->st_gid)
  976.             {
  977.             case 0:
  978.                 strcpy( gidstr, "root" );
  979.                 break;
  980.             case 1:
  981.                 strcpy( gidstr, "system" );
  982.                 break;
  983.             default:
  984.                 sprintf( gidstr, "%-8d", sblock->st_gid );
  985.                 break;
  986.             }
  987.  
  988.         printf( "%s   1 %-8s %-8s %8d  %s %s%s%s\n",
  989.                     tar_format_mode( sblock->st_mode, pathname ),
  990.                     uidstr,
  991.                     gidstr,
  992.                     sblock->st_size,
  993.                     tar_format_time( sblock->st_mtime ),
  994.                     pathname,
  995.                     link ? " -> " : "",
  996.                     link ? linkname : "" );
  997.         }
  998.     else
  999.         printf( "%s%s%s\n", pathname, link ? " -> " : "", link ? linkname : "" );
  1000.  
  1001. }
  1002.  
  1003.  
  1004.  
  1005.  
  1006. /****************************************************************************/
  1007. /*  Decode the fields of the header                                         */
  1008. /****************************************************************************/
  1009. static int tar_decode_hdr
  1010.     (   struct tarhdr   *header,
  1011.         char            *pathname,
  1012.         char            *linkname,
  1013.         struct stat     *sblock )
  1014.  
  1015. {
  1016.  
  1017.     register int    i;
  1018.     int             chksum;
  1019.     int             value;
  1020.     char            *ptr;
  1021.     int             filetype;
  1022.  
  1023.  
  1024.  
  1025.     if (debug)
  1026.         {
  1027.         printf( "title = %.*s\n", NAMSIZE,      header->title );
  1028.         printf( " mode = %.*s\n", MODESIZE,     header->mode );
  1029.         printf( "  uid = %.*s\n", UIDSIZE,      header->uid );
  1030.         printf( "  gid = %.*s\n", GIDSIZE,      header->gid );
  1031.         printf( "count = %.*s\n", COUNTSIZE,    header->count );
  1032.         printf( " time = %.*s\n", TIMESIZE,     header->time );
  1033.         printf( "cksum = %.*s\n", CHKSUMSIZE,   header->chksum );
  1034.         printf( " lcnt = %d\n",                 header->linkcount );
  1035.         printf( " lnam = %.*s\n", NAMSIZE,      header->linkname );
  1036.         printf( " junk = %s\n",                 header->dummy );
  1037.         }
  1038.  
  1039.  
  1040.     sblock->st_nlink = 0;
  1041.     sscanf( header->title,  "%100s",pathname );
  1042.     sscanf( header->mode,   "%8o",  &sblock->st_mode );
  1043.     sscanf( header->uid,    "%8o",  &sblock->st_uid );
  1044.     sscanf( header->gid,    "%8o",  &sblock->st_gid );
  1045.     sscanf( header->count,  "%12o", &sblock->st_size );
  1046.     sscanf( header->time,   "%12o", &sblock->st_mtime );
  1047.     sscanf( header->chksum, "%8o",  &chksum );
  1048.     *linkname = EOS;
  1049.  
  1050.  
  1051.     /************************************************************************/
  1052.     /*  Verify checksum                                                     */
  1053.     /************************************************************************/
  1054.  
  1055.     for (value = 0, ptr = header; ptr < &header->chksum; ptr++)
  1056.         value += *ptr;                  /* make the checksum */
  1057.  
  1058.     for (ptr = &header->linkcount; ptr < &header->dummy[255]; ptr++)
  1059.         value += *ptr;
  1060.  
  1061.     value += (8 * ' ');                 /* checksum considered as all spaces */
  1062.  
  1063.     if (chksum != value)
  1064.         {                               /* abort if incorrect */
  1065.         fprintf( stderr, "tar: directory checksum error for %s\n", pathname );
  1066. /*      exit(1);*/
  1067.         }
  1068.  
  1069.  
  1070.     /************************************************************************/
  1071.     /*  We may have the link written as binary or as character:             */
  1072.     /************************************************************************/
  1073.  
  1074.     sblock->st_nlink = isdigit( header->linkcount ) ? (header->linkcount - '0') : header->linkcount;
  1075.  
  1076.     if (sblock->st_nlink)
  1077.         sscanf( header->linkname, "%100s", linkname );
  1078.  
  1079.     return 0;
  1080.  
  1081. }
  1082.  
  1083.  
  1084.  
  1085. /****************************************************************************/
  1086. /*  tar_format_time                                                         */
  1087. /*                                                                          */
  1088. /*      format file time into readable string                               */
  1089. /*                                                                          */
  1090. /****************************************************************************/
  1091. static char *tar_format_time
  1092.     (   int     idate )
  1093.  
  1094. {
  1095.  
  1096.     time_t          now = time( NULL );
  1097.     struct tm       *tim;
  1098.     int             curyear;
  1099.     int             filyear;
  1100.     static char     strtim[26];
  1101.  
  1102.     strcpy( strtim, ctime( &idate ) );
  1103.     strcpy( strtim, &strtim[4] );
  1104.     strtim[12] = EOS;
  1105.  
  1106.  
  1107.     tim  = localtime( &now );
  1108.     curyear = tim->tm_year;
  1109.  
  1110.     tim     = localtime( &idate );
  1111.     filyear = tim->tm_year;
  1112.  
  1113.     if (curyear != filyear)
  1114.         {
  1115.         strtim[7] = ' ';
  1116.         sprintf( &strtim[8], "%4d", filyear + 1900 );
  1117.         }
  1118.  
  1119.     return strtim;
  1120.  
  1121. }
  1122.  
  1123.  
  1124.  
  1125.  
  1126. /****************************************************************************/
  1127. /*  tar_format_mode                                                         */
  1128. /*                                                                          */
  1129. /*      format file mode into readable string                               */
  1130. /*                                                                          */
  1131. /****************************************************************************/
  1132. static char *tar_format_mode
  1133.     (   int     mode,
  1134.         char    pathname[] )
  1135.  
  1136. {
  1137.     static char     modestr[10];
  1138.     register int    filetype;
  1139.     register int    i;
  1140.  
  1141.  
  1142.     strcpy( modestr, "----------" );
  1143.  
  1144.     filetype = (mode & S_IFMT);
  1145.  
  1146.     if (pathname[ strlen(pathname) - 1 ] != '/')
  1147.         {
  1148.         switch (filetype & S_IFMPB)
  1149.             {
  1150.             case 0:
  1151.                 break;
  1152.             case S_IFCHR:
  1153.                 modestr[0] = 'l';
  1154.                 break;
  1155.             default:
  1156.                 modestr[0] = 'x';
  1157.                 break;
  1158.             }
  1159.         }
  1160.     else
  1161.         {
  1162.         switch (filetype)
  1163.             {
  1164.             case 0:
  1165.             case S_IFDIR:
  1166.                 modestr[0] = 'd';
  1167.                 break;
  1168.             case S_IFCHR:
  1169.             case S_IFBLK:
  1170.                 modestr[0] = 'b';
  1171.                 break;
  1172.             default:
  1173.                 modestr[0] = 'x';
  1174.                 break;
  1175.             }
  1176.         }
  1177.  
  1178.     for (i = 1; i < 8; i += 3)
  1179.         {
  1180.         if (mode & (S_IREAD  >> (i-1))) modestr[i]      = 'r';
  1181.         if (mode & (S_IWRITE >> (i-1))) modestr[i+1]    = 'w';
  1182.         if (mode & (S_IEXEC  >> (i-1))) modestr[i+2]    = 'x';
  1183.         }
  1184.  
  1185.     if (mode & S_ISUID)
  1186.         modestr[3] = (modestr[3] == 'x') ? 's' : 'S';
  1187.  
  1188.     if (mode & S_ISGID)
  1189.         modestr[6] = (modestr[6] == 'x') ? 's' : 'S';
  1190.  
  1191.     if (mode & S_ISVTX)
  1192.         modestr[9] = (modestr[9] == 'x') ? 't' : 'T';
  1193.  
  1194.  
  1195.     return modestr;
  1196.  
  1197. }
  1198.  
  1199.  
  1200.  
  1201.  
  1202.  
  1203. /****************************************************************************/
  1204. /*  tar_clean_filespec -- removes illegal characters from directory and     */
  1205. /*  file names. Replaces hyphens and commas with underscores.               */
  1206. /****************************************************************************/
  1207. static tar_clean_filespec( char string[] )
  1208.  
  1209. {
  1210.     register char   *c;
  1211.  
  1212.     for ( c = string; *c; c++ )
  1213.         if (strchr( badchars, *c))
  1214.             *c = '_';               /* Replace illegal characters by underscores    */
  1215.  
  1216. }
  1217.  
  1218.  
  1219.  
  1220. /****************************************************************************/
  1221. /*                                                                          */
  1222. /*  vms2tar -- handles create function                                      */
  1223. /*                                                                          */
  1224. /****************************************************************************/
  1225. static vms2tar( int argc, char **argv )
  1226.  
  1227. {
  1228.     int                     status;
  1229.     struct dsc$descriptor   fsdsc   = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
  1230.     char                    rs[NAM$C_MAXRSS+1];
  1231.     struct dsc$descriptor   rsdsc   = { sizeof(rs) - 1, DSC$K_DTYPE_T, DSC$K_CLASS_S, rs };
  1232.     struct dsc$descriptor   dsdsc   = { strlen(default_name), DSC$K_DTYPE_T, DSC$K_CLASS_S, default_name };
  1233.     struct FAB              *fab    = NULL;
  1234.     struct NAM              *nam    = NULL;
  1235.     int                     argi;
  1236.     int                     tarfd;      /* File descriptor of output tarfile*/
  1237.     int                     ftype;
  1238.     int                     absolute = 0;
  1239.     char                    pathname[NAMSIZE];
  1240.     char                    dirnam[NAMSIZE];
  1241.     char                    filnam[NAMSIZE];
  1242.     char                    filtyp[NAMSIZE];
  1243.     struct tarhdr           header;     /* A tar header                     */
  1244.     struct stat             sblock;     /* structure returned from stat()   */
  1245.     struct dsc$descriptor   tarfdsc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, tarfile };
  1246.  
  1247.  
  1248.     if (argc < 3 || (foption && argc < 4)) tar_usage();
  1249.  
  1250.     rs[sizeof(rs)-1]    = EOS;
  1251.  
  1252.  
  1253.  
  1254.  
  1255.     /************************************************************************/
  1256.     /*  Open the output file                                                */
  1257.     /************************************************************************/
  1258.  
  1259.     tarfd = creat( tarfile, 0600, "rfm=fix", "mrs=512" );
  1260.  
  1261.     if (tarfd < 0)
  1262.         {
  1263.         fprintf( stderr, "tar: error opening output tarfile %s\n", tarfile );
  1264.         perror( "tar" );
  1265.         exit( SS$_NORMAL );
  1266.         }
  1267.  
  1268.     getname( tarfd, tarfile );
  1269.     lowercase( tarfile );
  1270.  
  1271.     tarfdsc.dsc$w_length  = strlen( tarfile );
  1272.  
  1273.     status = lib$getdvi( &DVI$_DEVCLASS, 0, &tarfdsc, &devclass );
  1274.     if (!(status & 1))
  1275.         {
  1276.         fprintf( stderr, "tar: error getting device information for %s\n", tarfile );
  1277.         fprintf( stderr, "tar: %s\n", vmserr( status ) );
  1278.         exit( SS$_NORMAL );
  1279.         }
  1280.  
  1281.  
  1282.  
  1283.     /************************************************************************/
  1284.     /*  For all files on the command line ...                               */
  1285.     /************************************************************************/
  1286.  
  1287.     for (argi = foption ? 3 : 2; argi < argc; ++argi)
  1288.         {
  1289.  
  1290.         fsdsc.dsc$w_length  = strlen( argv[argi] );
  1291.         fsdsc.dsc$a_pointer = argv[argi];
  1292.  
  1293.         /********************************************************************/
  1294.         /*  start the search                                                */
  1295.         /********************************************************************/
  1296.  
  1297.         status = lib$find_file( &fsdsc, &rsdsc, &fab, &dsdsc );
  1298.  
  1299.         nam = fab->fab$l_nam;
  1300.  
  1301.  
  1302.         /********************************************************************/
  1303.         /*  check for network file access                                   */
  1304.         /********************************************************************/
  1305.  
  1306.         if (nam->nam$b_node)
  1307.             {
  1308.             fprintf( stderr, "tar: network file access is not supported.\n" );
  1309.             lib$find_file_end( &fab );
  1310.             continue;
  1311.             }
  1312.  
  1313.  
  1314.         /********************************************************************/
  1315.         /*  store absolute UNIX pathnames if explicit device or directory   */
  1316.         /********************************************************************/
  1317.  
  1318.         if (nam->nam$v_exp_dev)
  1319.             absolute = 1;
  1320.         else
  1321.             if (nam->nam$v_exp_dir)
  1322.                 if  (!strstr( argv[argi], "[-" ) &&
  1323.                      !strstr( argv[argi], "[." ) &&
  1324.                      !strstr( argv[argi], "<-" ) &&
  1325.                      !strstr( argv[argi], "<." ))
  1326.                     absolute = 1;
  1327.  
  1328.  
  1329.         do
  1330.             {
  1331.  
  1332.             tar_trim( rs );
  1333.  
  1334.             lowercase( rs );
  1335.  
  1336.             if (!(status & 1))
  1337.                 {
  1338.                 switch (status)
  1339.                     {
  1340.                     case RMS$_DNF:
  1341.                         fprintf( stderr, "tar: directory not found %s\n", rs );
  1342.                         break;
  1343.                     case RMS$_FNF:
  1344.                         fprintf( stderr, "tar: file not found %s\n", rs );
  1345.                         break;
  1346.                     case RMS$_PRV:
  1347.                         fprintf( stderr, "tar: no privilege to access %s\n", rs );
  1348.                         break;
  1349.                     default:
  1350.                         fprintf( stderr, "tar: error searching for %s\n", rs );
  1351.                         fprintf( stderr, "tar: %s.\n", vmserr( status ) );
  1352.                         break;
  1353.                     }
  1354.                 continue;
  1355.                 }
  1356.  
  1357.  
  1358.             /****************************************************************/
  1359.             /*  split filespec into directory, name, and type+version       */
  1360.             /****************************************************************/
  1361.  
  1362.  
  1363.             strncpy( dirnam, nam->nam$l_dir,  nam->nam$b_dir );
  1364.             dirnam[nam->nam$b_dir] = EOS;
  1365.  
  1366.             strncpy( filnam, nam->nam$l_name, nam->nam$b_name );
  1367.             filnam[nam->nam$b_name] = EOS;
  1368.  
  1369.             strncpy( filtyp, nam->nam$l_type, nam->nam$b_type + nam->nam$b_ver );
  1370.             filtyp[nam->nam$b_type + nam->nam$b_ver] = EOS;
  1371.  
  1372.  
  1373.             /****************************************************************/
  1374.             /*  convert vms filespec to UNIX                                */
  1375.             /****************************************************************/
  1376.  
  1377.             ftype = tar_cvt_vmsname_to_unixname( dirnam, filnam, filtyp, absolute );
  1378.  
  1379.             strcpy( pathname, dirnam );
  1380.             strcat( pathname, filnam );
  1381.             strcat( pathname, filtyp );
  1382.  
  1383.             if (tar_get_fattr( rs, &sblock )) continue;
  1384.  
  1385.             /****************************************************************/
  1386.             /* prompt to process file                                       */
  1387.             /****************************************************************/
  1388.  
  1389.             if (wait)
  1390.                 {
  1391.                 char    temp[4] = EOS;
  1392.                 while (*temp != 'y' && *temp != 'n')
  1393.                     {
  1394.                     printf( "a %s: ", rs );
  1395.                     scanf( "%s", temp );
  1396.                     *temp = _tolower( *temp );
  1397.                     }
  1398.                 if (*temp != 'y') continue;
  1399.                 }
  1400.  
  1401.  
  1402.             switch (ftype)
  1403.                 {
  1404.  
  1405.                 case ISDIRE:
  1406.                     sblock.st_size  =  0;
  1407.                     tar_fill_hdr( pathname, &sblock, &header );
  1408.                     tar_write_hdr( tarfd, &header );
  1409.                     break;
  1410.  
  1411.                 case ISFILE:
  1412.  
  1413.                     if (tar_insert_file( rs, pathname, &sblock, tarfd ) < 0)
  1414.                         continue;
  1415.                     break;
  1416.  
  1417.                 }
  1418.  
  1419.             if (verbose)
  1420.                 {
  1421.                 int blocks = (sblock.st_size / DSIZE) + ((sblock.st_size % DSIZE) ? 1 : 0);
  1422.                 printf( "a %s %d block%s\n", pathname, blocks, (blocks != 1 ? "s" : "") );
  1423.                 }
  1424.  
  1425.             }
  1426.         while ( rsdsc.dsc$w_length = sizeof(rs) - 1,
  1427.                 (status = lib$find_file( &fsdsc, &rsdsc, &fab, &dsdsc )) != RMS$_NMF );
  1428.  
  1429.         }
  1430.  
  1431.  
  1432.     tar_write_trailer( tarfd );
  1433.     close( tarfd );
  1434.  
  1435. }
  1436.  
  1437.  
  1438.  
  1439. /****************************************************************************/
  1440. /*  tar_insert_file - insert file into tar file.                            */
  1441. /*                                                                          */
  1442. /*  Move data from input file to tar file.                                  */
  1443. /*  Always pad the output to a full DSIZE                                   */
  1444. /****************************************************************************/
  1445. static int tar_insert_file
  1446.     (   char        filename[],
  1447.         char        pathname[],
  1448.         struct stat *sblock,
  1449.         int         tarfd )
  1450.  
  1451. {
  1452.  
  1453.     int             nbytes  = sblock->st_size;
  1454.     char            buffer[DSIZE];
  1455.     int             inbytes;
  1456.     FILE            *infd;
  1457.     struct tarhdr   header;
  1458.     int             tarhdrpos;
  1459.  
  1460.  
  1461.     tarhdrpos = lseek( tarfd, 0, SEEK_CUR );
  1462.  
  1463.  
  1464.  
  1465.     if (sblock->st_fab_rfm == FAB$C_FIX ||
  1466.         sblock->st_fab_rfm == FAB$C_STM ||
  1467.         sblock->st_fab_rfm == FAB$C_STMLF)
  1468.         {
  1469.  
  1470.         if ((infd = fopen( filename, "rb" )) == NULL)
  1471.             {
  1472.             fprintf( stderr, "tar: error opening input file %s\n", filename );
  1473.             perror( "tar" );
  1474.             return -1;
  1475.             }
  1476.  
  1477.         tar_fill_hdr( pathname, sblock, &header );  /* We have all of the information   */
  1478.         tar_write_hdr( tarfd, &header );            /* So write to the output           */
  1479.  
  1480.         while (nbytes > 0)
  1481.             {
  1482.  
  1483.             inbytes = fread( buffer, 1, nbytes > DSIZE ? DSIZE : nbytes, infd );
  1484.  
  1485.             if (!inbytes)
  1486.                 {
  1487.                 fprintf( stderr, "tar: error reading input file %s\n", filename );
  1488.                 perror( "tar" );
  1489.                 fclose( infd );
  1490.  
  1491.                 if (devclass != DC$_TAPE)
  1492.                     {
  1493.                     lseek( tarfd, tarhdrpos, SEEK_SET );
  1494.                     return -1;
  1495.                     }
  1496.                 else
  1497.                     exit( SS$_NORMAL );
  1498.  
  1499.                 }
  1500.             nbytes -= inbytes;
  1501.             tar_flush( tarfd, buffer );
  1502.             }
  1503.  
  1504.         fclose( infd );
  1505.  
  1506.         }
  1507.     else
  1508.         {
  1509.  
  1510.         char    *bufp   = buffer;
  1511.         char    *linep;
  1512.         char    dbuffer[DSIZE];
  1513.  
  1514.         if ((infd = fopen( filename, "r" )) == NULL)
  1515.             {
  1516.             fprintf( stderr, "tar: error opening input file %s\n", filename );
  1517.             perror( "tar" );
  1518.             return -1;
  1519.             }
  1520.  
  1521.         sblock->st_size = 0;
  1522.  
  1523.         if (devclass == DC$_TAPE)
  1524.             {
  1525.             if ((sblock->st_size = tar_find_filesize( infd, filename )) < 0)
  1526.                 {
  1527.                 fclose( infd );
  1528.                 return -1;
  1529.                 }
  1530.             }
  1531.  
  1532.         tar_fill_hdr( pathname, sblock, &header );  /* Compute the header   */
  1533.         tar_write_hdr( tarfd, &header );            /* Write it             */
  1534.  
  1535.         nbytes = 0;
  1536.  
  1537.         while (fgets( dbuffer, DSIZE, infd ) !=  NULL)
  1538.             {
  1539.  
  1540.             nbytes += strlen( dbuffer );
  1541.  
  1542.             linep = dbuffer;
  1543.  
  1544.             while (*linep != EOS)   /* read source file line by line*/
  1545.                 {
  1546.                 if (bufp >= &buffer[DSIZE])
  1547.                     {
  1548.                     bufp = buffer;
  1549.                     tar_flush( tarfd, buffer ); /* if buffer full, flush it */
  1550.                     }                   /* copy in fixed size output buffer */
  1551.                 *bufp++ = *linep++;
  1552.                 }
  1553.             }
  1554.  
  1555.         tar_flush( tarfd, buffer );
  1556.  
  1557.         fclose( infd );
  1558.  
  1559.         if (devclass != DC$_TAPE)
  1560.             if (nbytes)
  1561.                 {
  1562.                 sblock->st_size = nbytes;
  1563.                 tar_rewrite_hdr( tarfd, tarhdrpos, nbytes );
  1564.                 }
  1565.             else
  1566.                 lseek( tarfd, tarhdrpos, SEEK_SET );
  1567.  
  1568.         }
  1569.  
  1570.     return 0;
  1571.  
  1572. }
  1573.  
  1574.  
  1575. /****************************************************************************/
  1576. /*  tar_find_filesize - calc bytes inf file by reading entire file          */
  1577. /****************************************************************************/
  1578. static tar_find_filesize
  1579.     (   FILE    *infd,
  1580.         char    filename[] )
  1581.  
  1582. {
  1583.  
  1584.     register int    bytes   = 0;
  1585.     char            buffer[DSIZE];
  1586.  
  1587.  
  1588.     while (fgets( buffer, DSIZE, infd ) !=  NULL)
  1589.         bytes += strlen( buffer );
  1590.  
  1591.     if (!feof(infd))
  1592.         {
  1593.         fprintf( stderr, "tar: error reading input file %s\n", filename );
  1594.         fprintf( stderr, "tar: record too large or incorrect RMS attributes\n" );
  1595.         return -1;
  1596.         }
  1597.  
  1598.     rewind( infd );                         /* Back to the beginning        */
  1599.  
  1600.     return bytes;
  1601.  
  1602. }
  1603.  
  1604.  
  1605.  
  1606. /****************************************************************************/
  1607. /*  tar_flush - write a fixed size block in output tarfile                  */
  1608. /****************************************************************************/
  1609. static tar_flush
  1610.     (   int     tarfd,
  1611.         char    buffer[] )
  1612.  
  1613. {
  1614.  
  1615.     if (write( tarfd, buffer, DSIZE) != DSIZE)
  1616.         {
  1617.         fprintf( stderr, "tar: error writing tarfile.\n" );
  1618.         perror( "tar" );
  1619.         exit( SS$_NORMAL );
  1620.         }
  1621.  
  1622. }
  1623.  
  1624.  
  1625.  
  1626. /****************************************************************************/
  1627. /*  tar_write_hdr - copy the header to the output file                      */
  1628. /****************************************************************************/
  1629. static int tar_write_hdr
  1630.     (   int             tarfd,
  1631.         struct tarhdr   *header )
  1632.  
  1633. {
  1634.  
  1635.     register int    n;
  1636.  
  1637.     if ((n = write( tarfd, header, DSIZE )) != DSIZE)
  1638.         {
  1639.         fprintf( stderr, "tar: error writing header in tarfile.\n" );
  1640.         perror( "tar" );
  1641.         exit( SS$_NORMAL );
  1642.         }
  1643.  
  1644.     return n;
  1645.  
  1646. }
  1647.  
  1648.  
  1649.  
  1650. /****************************************************************************/
  1651. /*  tar_rewrite_hdr - rewrite header with proper count and checksum         */
  1652. /****************************************************************************/
  1653. static int tar_rewrite_hdr
  1654.     (   int     tarfd,
  1655.         int     hdrpos,
  1656.         int     bytecount )
  1657.  
  1658. {
  1659.  
  1660.     register int    status;
  1661.     int             chksum;
  1662.     char            *ptr;
  1663.     int             curpos;
  1664.     struct tarhdr   header;
  1665.     char            tmp[15];
  1666.  
  1667.  
  1668.     /************************************************************************/
  1669.     /*  save current position in file                                       */
  1670.     /************************************************************************/
  1671.  
  1672.     curpos = lseek( tarfd, 0, SEEK_CUR );
  1673.  
  1674.  
  1675.     /************************************************************************/
  1676.     /*  position to header                                                  */
  1677.     /************************************************************************/
  1678.  
  1679.     status = lseek( tarfd, hdrpos, SEEK_SET );
  1680.  
  1681.  
  1682.     /************************************************************************/
  1683.     /*  read the old header                                                 */
  1684.     /************************************************************************/
  1685.  
  1686.     status = read( tarfd, &header, DSIZE );
  1687.  
  1688.  
  1689.     /************************************************************************/
  1690.     /*  store new count and checksum                                        */
  1691.     /************************************************************************/
  1692.  
  1693.     sprintf( tmp, "%11o ", bytecount );
  1694.     strncpy( header.count, tmp, 12 );
  1695.  
  1696.     strncpy( header.chksum, "        ", 8);
  1697.  
  1698.     for (chksum = 0, ptr = &header; ptr < &header.linkcount; ptr++)
  1699.         chksum += *ptr;                         /* make the checksum */
  1700.  
  1701.     sprintf( header.chksum, "%6o", chksum );
  1702.  
  1703.  
  1704.     /************************************************************************/
  1705.     /*  rewrite the header                                                  */
  1706.     /************************************************************************/
  1707.  
  1708.     status = lseek( tarfd, hdrpos, SEEK_SET );
  1709.     status = write( tarfd, &header, DSIZE );
  1710.  
  1711.     /************************************************************************/
  1712.     /*  back to our original position                                       */
  1713.     /************************************************************************/
  1714.  
  1715.     status = lseek( tarfd, curpos, SEEK_SET );
  1716.  
  1717. }
  1718.  
  1719.  
  1720.  
  1721. /****************************************************************************/
  1722. /*  tar_get_fattr - get the file attributes via stat()                      */
  1723. /****************************************************************************/
  1724. static int tar_get_fattr
  1725.     (   char        filespec[],
  1726.         struct stat *sblock )
  1727.  
  1728. {
  1729.  
  1730.     if (stat( filespec, sblock ))
  1731.         {
  1732.         fprintf( stderr, "tar: can't get file status on %s\n", filespec );
  1733.         perror( "tar" );
  1734.         return -1;
  1735.         }
  1736.     else
  1737.         return 0;
  1738.  
  1739. }
  1740.  
  1741.  
  1742.  
  1743.  
  1744. /****************************************************************************/
  1745. /*  tar_write_trailer - write the two blank blocks on the output file       */
  1746. /*  pad the output to a full blocksize if needed.                           */
  1747. /****************************************************************************/
  1748. static tar_write_trailer( int tarfd )
  1749.  
  1750. {
  1751.     register int    i;
  1752.     struct tarhdr   header;
  1753.     register int    tarfilepos;
  1754.  
  1755.     memset( &header, 0, DSIZE );
  1756.  
  1757.     tar_write_hdr( tarfd, &header );
  1758.     tar_write_hdr( tarfd, &header );
  1759.  
  1760.     tarfilepos = (lseek( tarfd, 0, SEEK_CUR ) / DSIZE) % BLKSIZE;
  1761.  
  1762.     for ( i = tarfilepos; i < BLKSIZE; i++ )
  1763.         tar_write_hdr( tarfd, &header );
  1764.  
  1765.     return 1;
  1766.  
  1767. }
  1768.  
  1769.  
  1770. /****************************************************************************/
  1771. /*  tar_cvt_vmsname_to_unixname                                             */
  1772. /*                                                                          */
  1773. /*  Convert a VMS filename to UNIX format. Return a value to indicate       */
  1774. /*  if this is a directory name, or another file.                           */
  1775. /****************************************************************************/
  1776. static int tar_cvt_vmsname_to_unixname
  1777.     (   char    dirnam[],
  1778.         char    filnam[],
  1779.         char    filtyp[],
  1780.         int     absolute )
  1781.  
  1782. {
  1783.     register char   *cp;
  1784.  
  1785.  
  1786.     /************************************************************************/
  1787.     /*  fix up directory name, getting rid of rooted directories and mfd    */
  1788.     /************************************************************************/
  1789.  
  1790.     tar_clean_dir( dirnam );
  1791.  
  1792.  
  1793.     /************************************************************************/
  1794.     /*  lowercase the lot of em                                             */
  1795.     /************************************************************************/
  1796.  
  1797.     lowercase( dirnam );
  1798.     lowercase( filnam );
  1799.     lowercase( filtyp );
  1800.  
  1801.  
  1802.     if (!absolute)
  1803.         {
  1804.  
  1805.         char            tmp1[NAM$C_MAXRSS];
  1806.         char            tmp2[NAM$C_MAXRSS];
  1807.         register char   *cp1    = tmp1;
  1808.         register char   *cp2    = tmp2;
  1809.         register char   *dotp1;
  1810.         register char   *dotp2;
  1811.  
  1812.         strcpy( tmp1, dirnam );
  1813.         tmp1[strlen(tmp1) - 1] = '.';
  1814.  
  1815.         strcpy( tmp2, curdir );
  1816.         tmp2[strlen(tmp2) - 1] = '.';
  1817.  
  1818.         while ( (dotp1 = strchr( cp1, '.' )) && (dotp2 = strchr( cp2, '.' )) )
  1819.             {
  1820.             *dotp1 = *dotp2 = EOS;
  1821.             if (strcmp( cp1, cp2 )) break;
  1822.             cp1 = ++dotp1;
  1823.             cp2 = ++dotp2;
  1824.             }
  1825.  
  1826.         if (dotp1) *dotp1 = '.';
  1827.         strcpy( dirnam, cp1 );
  1828.         }
  1829.  
  1830.  
  1831.     if (*dirnam == '[') *dirnam = '/';
  1832.  
  1833.     while (cp = dirnam, cp = strchr(cp, '.'))
  1834.         *cp = '/';
  1835.  
  1836.     while (cp = dirnam, cp = strchr(cp, ']'))
  1837.         *cp = '/';
  1838.  
  1839.     if (!strcmp( filtyp, ".dir;1" ))
  1840.         {
  1841.         strcat( dirnam, filnam );
  1842.         strcat( dirnam, "/" );
  1843.         *filnam = *filtyp = EOS;
  1844.         return ISDIRE;
  1845.         }
  1846.  
  1847.     if (cp = strchr( filtyp, ';' )) *cp = EOS;  /* strip version number     */
  1848.  
  1849.     if (!strcmp( filtyp, "." ) && !dot)         /* strip trailing dot maybe */
  1850.         *filtyp = EOS;
  1851.  
  1852.     return ISFILE;
  1853.  
  1854. }
  1855.  
  1856.  
  1857.  
  1858.  
  1859. /****************************************************************************/
  1860. /*  tar_fill_hdr - fill the fields of the header                            */
  1861. /*                                                                          */
  1862. /*  enter with the file name, if the file name is empty,                    */
  1863. /*  then this is a trailer, and we should fill it with zeroes.              */
  1864. /****************************************************************************/
  1865. static int tar_fill_hdr
  1866.     (   char            path[],
  1867.         struct stat     *sblock,
  1868.         struct tarhdr   *header )
  1869.  
  1870. {
  1871.  
  1872.     int         chksum;
  1873.     char        *ptr;
  1874.     char        tmp[15];
  1875.  
  1876.  
  1877.     /************************************************************************/
  1878.     /*  Fill the header with zeroes                                         */
  1879.     /************************************************************************/
  1880.  
  1881.     memset( header, 0, DSIZE );
  1882.  
  1883.     if (strlen( path ))                 /* only fill if there is a file     */
  1884.         {
  1885.         sprintf( header->title,         "%s",    path );
  1886.         sprintf( header->mode,  "%6o ",  sblock->st_mode );
  1887.         sprintf( header->uid,           "%6o ",  sblock->st_uid );
  1888.         sprintf( header->gid,           "%6o ",  sblock->st_gid );
  1889.         sprintf( tmp,                   "%11o ", sblock->st_size );
  1890.         strncpy( header->count, tmp, 12 );
  1891.         sprintf( tmp,                   "%11o ", sblock->st_mtime );
  1892.         strncpy( header->time, tmp, 12 );
  1893.         strncpy( header->chksum, "        ", 8);
  1894.  
  1895.         for (chksum = 0, ptr = header; ptr < &header->linkcount; ptr++)
  1896.             chksum += *ptr;                             /* make the checksum */
  1897.  
  1898.         sprintf( header->chksum, "%6o", chksum );
  1899.         }
  1900.  
  1901.     return 0;
  1902.  
  1903. }
  1904.  
  1905.  
  1906.  
  1907. /****************************************************************************/
  1908. /*  lowercase - function to change a string to lower case                   */
  1909. /****************************************************************************/
  1910. static int lowercase( char string[] )
  1911.  
  1912. {
  1913.     int i;
  1914.  
  1915.     for (i=0; string[i] = _tolower( string[i] ); i++ );
  1916.  
  1917.     return --i;             /* return string length */
  1918.  
  1919. }
  1920.  
  1921.  
  1922.  
  1923.  
  1924. /****************************************************************************/
  1925. /*  tar_trim - trim string of trailing spaces/tabs                          */
  1926. /****************************************************************************/
  1927. static tar_trim( char *string )
  1928.  
  1929. {
  1930.     int     i;
  1931.  
  1932.     for ( i = strlen(string) - 1; string[i] == ' ' || string[i] == '\t'; i-- );
  1933.  
  1934.     string[i+1] = EOS;
  1935.  
  1936. }
  1937.  
  1938.  
  1939.  
  1940. /****************************************************************************/
  1941. /*  tar_clean_dir - routine to get rid of rooted directory problems         */
  1942. /*  and any others that turn up                                             */
  1943. /****************************************************************************/
  1944. static int tar_clean_dir( char string[] )
  1945.  
  1946. {
  1947.     register char   *cp;
  1948.  
  1949.  
  1950.  
  1951.     if (cp = strstr( string, "][" ))
  1952.         strcpy( cp, cp+2 );             /* Just collapse around the string  */
  1953.  
  1954.     if (cp = strstr( string, "[000000." ))
  1955.         strcpy( cp + 1, cp + 8 );       /* remove "000000."                 */
  1956.  
  1957.     if (cp = strchr( string, '<' ))
  1958.         *cp = '[';
  1959.  
  1960.     if (cp = strchr( string, '>' ))
  1961.         *cp = ']';
  1962.  
  1963. }
  1964.  
  1965.  
  1966.  
  1967. /****************************************************************************/
  1968. /*  Syntax error exit                                                       */
  1969. /****************************************************************************/
  1970. static tar_usage()
  1971. {
  1972.     printf( "usage: tar x|c|t[vwbdz][f tarfile] [file [file...]]\n" );
  1973.     exit( 1 );
  1974. }
  1975.  
  1976.  
  1977.  
  1978. /************************************************************************/
  1979. /*  return pointer to C-string vms error message                        */
  1980. /************************************************************************/
  1981. static char *vmserr
  1982.     ( int   status )
  1983.  
  1984. {
  1985.     static char     errmsg[133];
  1986.     $DESCRIPTOR( errmsgdsc, errmsg );
  1987.     long            i;
  1988.  
  1989.     sys$getmsg( status, &errmsgdsc.dsc$w_length, &errmsgdsc, 15, 0 );
  1990.     errmsg[errmsgdsc.dsc$w_length] = EOS;
  1991.     for (i = 0; errmsg[i]; i++)
  1992.         errmsg[i] = _tolower(errmsg[i]);
  1993.  
  1994.     return errmsg;
  1995. }
  1996.  
  1997.