tarLib.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:28k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* tarLib.c - UNIX tar compatible library */
  2. /* Copyright 1993-2002 Wind River Systems, Inc. */
  3. /* Copyright (c) 1993, 1994 RST Software Industries Ltd. */
  4. /*
  5. modification history
  6. --------------------
  7. 01i,20sep01,jkf  SPR#69031, common code for both AE & 5.x.
  8. 01h,26dec99,jkf  T3 KHEAP_ALLOC
  9. 03g,11nov99,jkf  need to fill all eight bytes with 0x20 for the checksum 
  10.                  calc correct for MKS toolkit 6.2 generated tar file.
  11. 03f,31jul99,jkf  T2 merge, tidiness & spelling.
  12. 03e,30jul98,lrn  partial doc cleanup
  13. 03b,24jun98,lrn  fixed bug causing 0-size files to be extracted as dirs,
  14.  improved tarHelp to list parameters
  15. 03a,07jun98,lrn  derived from RST usrTapeLib.c, cleaned all tape related stuff
  16. 02f,15jan95,rst  adding TarToc functionality
  17. 02d,28mar94,rst  added Tar utilities.
  18. */
  19. /*
  20. DESCRIPTION
  21. This library implements functions for archiving, extracting and listing
  22. of UNIX-compatible "tar" file archives.
  23. It can be used to archive and extract entire file hierarchies
  24. to/from archive files on local or remote disks, or directly to/from
  25. magnetic tapes.
  26. SEE ALSO: dosFsLib
  27. CURRENT LIMITATIONS
  28. This Tar utility does not handle MS-DOS file attributes,
  29. when used in conjunction with the MS-DOS file system.
  30. The maximum subdirectory depth supported by this library is 16,
  31. while the total maximum path name that can be handled by 
  32. tar is limited at 100 characters.
  33. */
  34. #include "vxWorks.h"
  35. #include "stdlib.h"
  36. #include "ioLib.h"
  37. #include "errnoLib.h"
  38. #include "string.h"
  39. #include "stdio.h"
  40. #include "private/dosFsVerP.h"
  41. #include "dosFsLib.h"
  42. #include "dirent.h"
  43. #include "stat.h"
  44. #include "tarLib.h"
  45. /* data types */
  46. /*
  47.  * VxWorks Tar Utility, part of usrTapeLib (for now).
  48.  * UNIX tar(1) tape format - header definition
  49.  */
  50. #define TBLOCK 512 /* TAR Tape block size, part of TAR format */
  51. #define NAMSIZ 100 /* size of file name in TAR tape header */
  52. #define MAXLEVEL 16 /* max. # of subdirectory levels, arbitrary */
  53. #define NULLDEV "/null" /* data sink */
  54. typedef union hblock
  55.     {
  56.     char dummy[TBLOCK];
  57.     struct header
  58. {
  59. char name[NAMSIZ];
  60. char mode[8];
  61. char uid[8];
  62. char gid[8];
  63. char size[12];
  64. char mtime[12];
  65. char chksum[8];
  66. char linkflag;
  67. char linkname[NAMSIZ];
  68.      }
  69.     dbuf;
  70.     } MT_HBLOCK ;
  71. /* Control structure used internally for reentrancy etc. */
  72. typedef struct
  73.     {
  74.     int  fd ; /* current tape file descriptor */
  75.     int bFactor; /* current blocking factor */
  76.     int bValid; /* number of valid blocks in buffer */
  77.     int recurseCnt; /* recusrion counter */
  78.     MT_HBLOCK * pBuf; /* working buffer */
  79.     MT_HBLOCK * pBnext; /* ptr to next block to return */
  80.     } MT_TAR_SOFT ;
  81. /* globals */
  82. char *TAPE = "/archive0.tar" ; /* default archive name */
  83. /* locals */
  84. LOCAL char bZero[ TBLOCK ] ; /* zeroed block */
  85. /*******************************************************************************
  86. *
  87. * tarHelp - print help information about TAR archive functions.
  88. *
  89. * NOMANUAL
  90. */
  91. void tarHelp
  92.     (
  93.     void
  94.     )
  95.     {
  96.     int i ;
  97.     const char * help_msg[] = {
  98.     "Help information on TAR archival functions:n",
  99.     "n",
  100.     " Archive any directory: n",
  101.     "    tarArchive( archFile, bfactor, verbose, dirName )n",
  102.     " Extract from TAR archive into current directory:n",
  103.     "    tarExtract( archFile, bfactor, verbose )n",
  104.     " List contents of TAR archiven",
  105.     "    tarToc( archFile, bfactor)n",
  106.     "      if <dirName> is NULL, archive current directoryn",
  107.     "n", NULL 
  108.     };
  109.     for(i = 0; help_msg[i] != NULL ; i++ )
  110. printf(help_msg[i]);
  111.     printf(" if <archFile> is NULL,n"
  112. "current default archive file "%s" will be used,n", TAPE);
  113.     printf(" change the TAPE variable to set a different name.nn");
  114.     }
  115. /*******************************************************************************
  116. *
  117. * mtChecksum - calculate checksums for tar header blocks
  118. *
  119. * RETURNS: the checksum value
  120. */
  121. LOCAL int mtChecksum
  122.     (
  123.     void * pBuf,
  124.     unsigned size
  125.     )
  126.     {
  127.     register int sum = 0 ;
  128.     register unsigned char *p = pBuf ;
  129.     while( size > 0 )
  130. {
  131. sum += *p++;
  132. size -= sizeof(*p);
  133. }
  134.     return(sum);
  135.     }
  136. /*******************************************************************************
  137. *
  138. * tarRdBlks - read <nBlocks> blocks from tape
  139. *
  140. * RETURNS: number of blocks actually got, or ERROR.
  141. */
  142. LOCAL int tarRdBlks
  143.     (
  144.     MT_TAR_SOFT *pCtrl, /* control structure */
  145.     MT_HBLOCK **ppBlk, /* where to return buffer address */
  146.     unsigned int nBlocks /* how many blocks to get */
  147.     )
  148.     {
  149.     register int rc ;
  150.     if (pCtrl->bValid <= 0)
  151. {
  152. /* buffer empty, read more blocks from tape */
  153. rc = read(pCtrl->fd, pCtrl->pBuf->dummy, pCtrl->bFactor * TBLOCK);
  154. if ( rc == ERROR )
  155.     return ERROR ;
  156. else if( rc == 0 )
  157.     return 0 ;
  158. else if( (rc % TBLOCK) != 0 )
  159.     {
  160.     printErr("tarRdBlks: tape block not multiple of %dn", TBLOCK);
  161.     return ERROR;
  162.     }
  163. pCtrl->bValid = rc / TBLOCK ;
  164. pCtrl->pBnext = pCtrl->pBuf ;
  165. }
  166.     rc = min((ULONG)pCtrl->bValid, nBlocks) ;
  167.     *ppBlk = pCtrl->pBnext ;
  168.     pCtrl->bValid -= rc ;
  169.     pCtrl->pBnext += rc ;
  170.     return( rc ) ;
  171.     }
  172. /*******************************************************************************
  173. *
  174. * mtAccess - check existence of path for a new file or directory <name>
  175. *
  176. * RETURNS: OK or ERROR
  177. */
  178. LOCAL STATUS mtAccess
  179.     (
  180.     const char *name
  181.     )
  182.     {
  183.     char tmpName [ NAMSIZ ] ;
  184.     struct stat st ;
  185.     int i ;
  186.     static char slash = '/' ;
  187.     register char *pSlash ;
  188.     strncpy( tmpName, name, NAMSIZ ) ;
  189.     pSlash = tmpName ;
  190.     for(i=0; i<MAXLEVEL; i++)
  191. {
  192. if ( (pSlash = strchr(pSlash, slash)) == NULL )
  193.     return OK;
  194. *pSlash = '' ;
  195. if ( stat( tmpName, &st ) == OK )
  196.     {
  197.     if( S_ISDIR(st.st_mode ) == 0)
  198. {
  199. printErr("Path %s is not a directoryn", tmpName);
  200. return ERROR;
  201. }
  202.     }
  203. else
  204.     {
  205.     mkdir( tmpName );
  206.     }
  207. *pSlash = slash ; /* restore slash position */
  208. pSlash++;
  209. }
  210.     printErr("Path too long %sn", name );
  211.     return ERROR;
  212.     }
  213. /*******************************************************************************
  214. *
  215. * tarExtractFile - extract one file or directory from tar tape
  216. *
  217. * Called from tarExtract for every file/dir found on tape.
  218. *
  219. * RETURNS: OK or ERROR
  220. */
  221. LOCAL STATUS tarExtractFile
  222.     (
  223.     MT_TAR_SOFT *pCtrl, /* control structure */
  224.     MT_HBLOCK *pBlk, /* header block */
  225.     BOOL verbose /* verbose */
  226.     )
  227.     {
  228.     register int rc, fd ;
  229.     int sum = -1 ; /* checksum */
  230.     int size = 0 ; /* file size in bytes */
  231.     int nblks = 0; /* file size in TBLOCKs */
  232.     int mode ;
  233.     char * fn ; /* file/dir name */
  234.     /* Check the checksum of this header */
  235.     rc = sscanf( pBlk->dbuf.chksum, "%o", &sum ) ; /* extract checksum */
  236.     bfill( pBlk->dbuf.chksum, 8, ' '); /* fill blanks */
  237.     if( mtChecksum( pBlk->dummy, TBLOCK ) != sum )
  238. {
  239. printErr("bad checksum %d != %dn", mtChecksum(
  240. pBlk->dummy, TBLOCK), sum );
  241. return ERROR;
  242. }
  243.     /* Parse all fields of header that we need, and store them safely */
  244.     sscanf( pBlk->dbuf.mode, "%o", &mode );
  245.     sscanf( pBlk->dbuf.size, "%12o", &size );
  246.     fn = pBlk->dbuf.name ;
  247.     /* Handle directory */
  248.     if( (size == 0) && ( fn[ strlen(fn) - 1 ] == '/' ) )
  249. {
  250. if( strcmp(fn, "./") == 0)
  251.     return OK;
  252. if ( fn[ strlen(fn) - 1 ] == '/' ) /* cut the slash */
  253.     fn[ strlen(fn) - 1 ] = '' ;
  254. /* Must make sure that parent exists for this new directory */
  255. if ( mtAccess(fn) == ERROR )
  256.     {
  257.     return ERROR;
  258.     }
  259. fd = open (fn, O_RDWR | O_CREAT, FSTAT_DIR | (mode & 0777) );
  260. if (( fd == ERROR ) && (errnoGet() == S_dosFsLib_FILE_EXISTS))
  261.     {
  262.     printErr("Warning: directory %s already existsn", fn );
  263.     return OK;
  264.     }
  265. else if (fd == ERROR)
  266.     {
  267.     printErr("failed to create directory %s, %s, continuingn",
  268.      fn, strerror(errnoGet()));
  269.     return OK;
  270.     }
  271. if(verbose)
  272.     printErr("created directory %s.n", fn );
  273. return (close (fd));
  274. }
  275.     /* non-empty file has a trailing slash, we better treat it as file and */
  276.     if ( fn[ strlen(fn) - 1 ] == '/' ) /* cut a trailing slash */
  277. fn[ strlen(fn) - 1 ] = '' ;
  278.     /* Filter out links etc */
  279.     if ((pBlk->dbuf.linkflag != '') &&
  280.      (pBlk->dbuf.linkflag != '0') &&
  281. (pBlk->dbuf.linkflag != ' '))
  282. {
  283. printErr("we do not support links, %s skippedn", fn );
  284. return OK;
  285. }
  286.     /* Handle Regular File - calculate number of blocks */
  287.     if( size > 0 )
  288. nblks = ( size / TBLOCK ) +  ((size % TBLOCK)? 1 : 0 ) ;
  289.     /* Must make sure that directory exists for this new file */
  290.     if ( mtAccess(fn) == ERROR )
  291. {
  292. return ERROR;
  293. }
  294.     /* Create file */
  295.     fd = open( fn, O_RDWR | O_CREAT, mode & 0777 ) ;
  296.     if( fd == ERROR )
  297. {
  298. printErr("failed to create file %s, %s, skipping!n",
  299. fn, strerror(errnoGet()));
  300. fd = open( NULLDEV, O_RDWR, 0) ;
  301. }
  302.     if(verbose)
  303. printErr("extracting file %s, size %d bytes, %d blocksn",
  304. fn, size, nblks );
  305.     /* Loop until entire file extracted */
  306.     while (size > 0)
  307. {
  308. MT_HBLOCK *pBuf;
  309. register int wc ;
  310. rc = tarRdBlks( pCtrl, &pBuf, nblks) ;
  311. if ( rc < 0 )
  312.     {
  313.     printErr("error reading tapen");
  314.     close(fd);
  315.     return ERROR;
  316.     }
  317. wc = write( fd, pBuf->dummy, min( rc*TBLOCK, size ) ) ;
  318. if( wc == ERROR )
  319.     {
  320.     printErr("error writing filen");
  321.     break;
  322.     }
  323. size -= rc*TBLOCK ;
  324. nblks -= rc ;
  325. }
  326.     /* Close the newly created file */
  327.     return( close(fd) ) ;
  328.     }
  329. /*******************************************************************************
  330. *
  331. * tarExtract - extract all files from a tar formatted tape
  332. *
  333. * This is a UNIX-tar compatible utility that extracts entire
  334. * file hierarchies from tar-formatted archive.
  335. * The files are extracted with their original names and modes.
  336. * In some cases a file cannot be created on disk, for example if
  337. * the name is too long for regular DOS file name conventions,
  338. * in such cases entire files are skipped, and this program will
  339. * continue with the next file. Directories are created in order
  340. * to be able to create all files on tape.
  341. *
  342. * The <tape> argument may be any tape device name or file name
  343. * that contains a tar formatted archive. If <tape> is equal "-",
  344. * standard input is used. If <tape> is NULL (or unspecified from Shell)
  345. * the default archive file name stored in global variable <TAPE> is used.
  346. *
  347. * The <bfactor> dictates the blocking factor the tape was written with.
  348. * If 0, or unspecified from the shell, a default of 20 is used.
  349. *
  350. * The <verbose> argument is a boolean, if set to 1, will cause informative
  351. * messages to be printed to standard error whenever an action is taken,
  352. * otherwise, only errors are reported.
  353. *
  354. * All informative and error message are printed to standard error.
  355. *
  356. * There is no way to selectively extract tar archives with this
  357. * utility. It extracts entire archives.
  358. */
  359. STATUS tarExtract
  360.     (
  361.     char * pTape, /* tape device name */
  362.     int bfactor, /* requested blocking factor */
  363.     BOOL verbose /* if TRUE print progress info */
  364.     )
  365.     {
  366.     register  int rc ; /* return codes */
  367.     MT_TAR_SOFT ctrl ; /* control structure */
  368.     STATUS retval = OK;
  369.     /* Set defaults */
  370.     if( pTape == NULL )
  371. pTape = TAPE ;
  372.     if( bfactor == 0 )
  373. bfactor = 20 ;
  374.     if( verbose )
  375. printErr("Extracting from %sn", pTape );
  376.     bzero( (char *)&ctrl, sizeof(ctrl) );
  377.     bzero( bZero, sizeof(bZero) ); /* not harmful for reentrancy */
  378.     /* Open tape device and initialize control structure */
  379.     if( strcmp(pTape, "-") == 0)
  380. ctrl.fd = STD_IN;
  381.     else
  382. ctrl.fd = open( pTape, O_RDONLY, 0) ;
  383.     if ( ctrl.fd < 0 )
  384. {
  385. printErr("Failed to open tape: %sn", strerror(errnoGet()) );
  386. return ERROR;
  387. }
  388.     
  389.     ctrl.bFactor = bfactor ;
  390.     ctrl.pBuf = KHEAP_ALLOC( bfactor * TBLOCK ) ;
  391.     if ( ctrl.pBuf == NULL )
  392. {
  393. printErr("Not enough memory, exiting.n" );
  394. if ( ctrl.fd != STD_IN )
  395.     close( ctrl.fd );
  396. return ERROR ;
  397. }
  398.     /* all exits from now via goto in order to free the buffer */
  399.     /* Read the first block and adjust blocking factor */
  400.     rc = read( ctrl.fd, ctrl.pBuf->dummy, ctrl.bFactor*TBLOCK ) ;
  401.     if ( rc == ERROR )
  402. {
  403. printErr("read error at the beginning of tape, exiting.n" );
  404. retval = ERROR ;
  405. goto finish;
  406. }
  407.     else if( rc == 0 )
  408. {
  409. printErr("empty tape file, exiting.n" );
  410. goto finish;
  411. }
  412.     else if( (rc % TBLOCK) != 0 )
  413. {
  414. printErr("tape block not multiple of %d, exiting.n", TBLOCK);
  415. retval = ERROR ;
  416. goto finish;
  417. }
  418.     ctrl.bValid = rc / TBLOCK ;
  419.     ctrl.pBnext = ctrl.pBuf ;
  420.     if ( ctrl.bFactor != ctrl.bValid )
  421. {
  422. if( verbose )
  423.     printErr("adjusting blocking factor to %dn", ctrl.bValid );
  424. ctrl.bFactor = ctrl.bValid ;
  425. }
  426.     /* End of overture, start processing files until end of tape */
  427.     FOREVER
  428. {
  429. MT_HBLOCK * pBlk ;
  430. if ( tarRdBlks( &ctrl, &pBlk, 1) != 1 )
  431.     {
  432.     retval = ERROR ;
  433.     goto finish;
  434.     }
  435. if ( bcmp( pBlk->dummy, bZero, TBLOCK) == 0 )
  436.     {
  437.     if(verbose)
  438. printErr("end of tape encountered, read until eof...n");
  439.     while( tarRdBlks( &ctrl, &pBlk, 1) > 0) ;
  440.     if(verbose)
  441. printErr("done.n");
  442.     retval = OK ;
  443.     goto finish;
  444.     }
  445. if ( tarExtractFile( &ctrl, pBlk, verbose) == ERROR )
  446.     {
  447.     retval = ERROR;
  448.     goto finish;
  449.     }
  450. } /* end of FOREVER */
  451.     
  452. finish:
  453. if ( ctrl.fd != STD_IN )
  454.     close( ctrl.fd );
  455. KHEAP_FREE((char *)ctrl.pBuf );
  456. return( retval );
  457.     }
  458. /*******************************************************************************
  459. *
  460. * tarWrtBlks - write <nBlocks> blocks to tape
  461. *
  462. * Receives any number of blocks, and handles the blocking factor
  463. * mechanism using the pCtrl->pBuf internal buffer and associated
  464. * counters.
  465. *
  466. * RETURNS: OK or ERROR;
  467. */
  468. LOCAL STATUS tarWrtBlks
  469.     (
  470.     MT_TAR_SOFT *pCtrl, /* control structure */
  471.     char *pBuf, /* data to write */
  472.     unsigned int nBlocks /* how many blocks to get */
  473.     )
  474.     {
  475.     register int rc ;
  476.     while( nBlocks > 0 )
  477. {
  478. if ((pCtrl->bValid <= 0) && (nBlocks >= (unsigned int)pCtrl->bFactor))
  479.     {
  480.     /* internal buffer empty, write directly */
  481.     rc = write( pCtrl->fd, pBuf, pCtrl->bFactor*TBLOCK ) ;
  482.     if ( rc == ERROR )
  483. return ERROR ;
  484.     /* adjust count and pointer */
  485.     pBuf += TBLOCK * pCtrl->bFactor ;
  486.     nBlocks -= pCtrl->bFactor ;
  487.     }
  488. else 
  489.     {
  490.     register int cnt ;
  491.     /* internal buffer partially full, fill it up */
  492.     cnt = pCtrl->bFactor - pCtrl->bValid ;
  493.     cnt = min( (ULONG)cnt, nBlocks );
  494.     bcopy( pBuf, (char *) (pCtrl->pBuf + pCtrl->bValid), cnt*TBLOCK );
  495.     pBuf += cnt*TBLOCK;
  496.     nBlocks -= cnt ;
  497.     pCtrl->bValid += cnt ;
  498.     }
  499. if( pCtrl->bValid == pCtrl->bFactor  )
  500.     {
  501.     /* one full blocked buffer, write to tape */
  502.     rc = write( pCtrl->fd, (char *) pCtrl->pBuf,
  503. pCtrl->bFactor*TBLOCK ) ;
  504.     if ( rc == ERROR )
  505. return ERROR ;
  506.     /* adjust count and pointer */
  507.     pCtrl->bValid = 0 ;
  508.     }
  509. } /* while */
  510.     return OK;
  511.     }
  512. /*******************************************************************************
  513. *
  514. * tarCreateHdr - build a tar header block 
  515. *
  516. * NOTE:
  517. * SunOS tar(5) man page is not accurate, this function
  518. * was built using empiric methods with that tar(1) command.
  519. * RETURNS: file size in bytes
  520. */
  521. LOCAL int tarCreateHdr
  522.     (
  523.     MT_TAR_SOFT *pCtrl, /* control structure */
  524.     const char  *name, /* file/dir name */
  525.     struct stat *pStat, /* file stats */
  526.     MT_HBLOCK * pBlk /* block buffer for header */
  527.     )
  528.     {
  529.     int chksum;
  530.     strncpy( pBlk->dbuf.name, name, NAMSIZ );
  531.     if( S_ISDIR(pStat->st_mode) )
  532. {
  533. pStat->st_mode |= 0200 ;
  534. pStat->st_size = 0 ;
  535. }
  536.     sprintf( pBlk->dbuf.mode, "%6o ", pStat->st_mode );
  537.     sprintf( pBlk->dbuf.uid, "%6o ", pStat->st_uid );
  538.     sprintf( pBlk->dbuf.gid, "%6o ", pStat->st_gid );
  539.     sprintf( pBlk->dbuf.size, "%11lo ", pStat->st_size );
  540.     sprintf( pBlk->dbuf.mtime, "%11lo ", pStat->st_mtime );
  541.     pBlk->dbuf.linkflag = '0';
  542.     bfill( pBlk->dbuf.chksum, 8, ' '); /* fill blanks */
  543.     chksum = mtChecksum( pBlk->dummy, TBLOCK ) ;
  544.     sprintf( pBlk->dbuf.chksum, "%6o", chksum);
  545.     return( pStat->st_size );
  546.     }
  547. /*******************************************************************************
  548. *
  549. * tarArchDo - archive a file/dir onto tape (recursive)
  550. *
  551. * Handle one file or one directory, in case of directory,
  552. * write the dir entry and recurse.
  553. *
  554. * RETURNS: OK or ERROR.
  555. */
  556. LOCAL STATUS tarArchDo
  557.     (
  558.     MT_TAR_SOFT *pCtrl, /* control structure */
  559.     BOOL verbose, /* verbosity flag */
  560.     char * name /* file/dir name */
  561.     )
  562.     {
  563.     MT_HBLOCK hblock; /* header block */
  564.     struct stat st; /* file/dir stat */
  565.     register int rc;
  566.     bzero ( (char *) &hblock, sizeof( MT_HBLOCK ) );
  567.     if( strlen( name ) >= (NAMSIZ-1))
  568. {
  569. printErr("tar: name too long %s, skip.n", name );
  570. return ERROR;
  571. }
  572.     rc = stat( name, &st );
  573.     if ( rc == ERROR)
  574. {
  575. perror("tar: stat error ");
  576. return ERROR ;
  577. }
  578.     if ( pCtrl->recurseCnt++ > MAXLEVEL )
  579. {
  580. printErr("tar: nesting too deep, skipping %sn", name);
  581. goto abort ;
  582. }
  583.     if( S_ISDIR(st.st_mode) )
  584. {
  585. char fn [ NAMSIZ ]; /* subdir name */
  586. register DIR * pDir;
  587. struct dirent * pDirEnt ;
  588. /* handle directory */
  589. strncpy( fn, name, NAMSIZ-2 );
  590. strcat( fn, "/" );
  591. /* write directory header block to tape */
  592. tarCreateHdr( pCtrl, fn, &st, &hblock ) ;
  593. if( verbose )
  594.     printErr("tar: writing directory %sn", name );
  595. if (tarWrtBlks( pCtrl, (char *) &hblock, 1 ) == ERROR )
  596.     {
  597.     perror("tar: error writing header to tape ");
  598.     goto abort;
  599.     }
  600. /* recurse on every directory member */
  601. pDir = opendir( name ) ;
  602. if( pDir == NULL )
  603.     {
  604.     perror((sprintf(fn,"tar: error opening directory %s ", name),fn));
  605.     goto abort;
  606.     }
  607. for( pDirEnt = readdir(pDir); pDirEnt != NULL ;
  608. pDirEnt = readdir(pDir))
  609.     {
  610.     /* Skip the "." and ".." entries */
  611.     if ( strcmp( pDirEnt->d_name, ".") == 0)
  612. continue ;
  613.     if ( strcmp( pDirEnt->d_name, "..") == 0)
  614. continue ;
  615.     /* build the new name by concatenating */
  616.     strncpy( fn, name, NAMSIZ-2 );
  617.     strcat( fn, "/" );
  618.     strcat( fn, pDirEnt->d_name );
  619.     /* recurse ! nesting level of MAXLEVEL maximum */
  620.     (void )tarArchDo( pCtrl, verbose, fn ) ;
  621.     }
  622. closedir( pDir );
  623. }
  624.     else if( S_ISREG(st.st_mode) )
  625. {
  626. int fileFd = -1 ;
  627. register int fileSize ;
  628. register int rc ;
  629. register char * pFileBuf ;
  630. unsigned bufSize = pCtrl->bFactor*TBLOCK;
  631. unsigned nBlocks = 0 ;
  632. /* handle plain file */
  633. /* write file header to tape */
  634. fileSize = tarCreateHdr( pCtrl, name, &st, &hblock ) ;
  635. /* write the file itself to tape */
  636. pFileBuf = KHEAP_ALLOC( bufSize );
  637. if( pFileBuf == NULL )
  638.     {
  639.     printErr("tar: not enough memoryn" );
  640.     goto abort;
  641.     }
  642. fileFd = open( name, O_RDONLY, 0);
  643. if( fileFd == ERROR )
  644.     {
  645.     perror((sprintf(pFileBuf,"tar: file open error %s, ", name),
  646. pFileBuf));
  647.     KHEAP_FREE(((char *) pFileBuf) ); 
  648.     goto abort;
  649.     }
  650. /* Handle Regular File - calculate number of blocks */
  651. if( fileSize > 0 )
  652.     nBlocks = ( fileSize / TBLOCK ) +  ((fileSize % TBLOCK)? 1 : 0 ) ;
  653. if( verbose )
  654.     printErr("tar: writing file %s, size %d bytes, %d blocksn",
  655. name, fileSize, nBlocks );
  656. if (tarWrtBlks( pCtrl, (char *) &hblock, 1 ) == ERROR )
  657.     {
  658.     perror("tar: error writing header to tape ");
  659.     KHEAP_FREE(((char *) pFileBuf) ); 
  660.     goto abort;
  661.     }
  662. while( nBlocks > 0 )
  663.     {
  664.     /* try to optimize into direct tape writing here */
  665.     rc = read( fileFd, pFileBuf,
  666. bufSize - (pCtrl->bValid*TBLOCK) ) ;
  667.     if( rc == ERROR )
  668. {
  669. perror((sprintf(pFileBuf,"tar: file read error %s, ", name),
  670. pFileBuf));
  671. rc = 1;
  672. }
  673.     else if( rc == 0 )
  674. {
  675. printErr("tar: file changed size!n");
  676. rc = 1; 
  677. }
  678.     else
  679. {
  680. /* recalculate read count in blocks */
  681. rc = ( rc / TBLOCK ) +  ((rc % TBLOCK)? 1 : 0 ) ;
  682. }
  683.     /* Now write the file blocks to tape */
  684.     tarWrtBlks( pCtrl, pFileBuf, rc );
  685.     nBlocks -= rc ;
  686.     }/*while*/
  687. close( fileFd );
  688. KHEAP_FREE(((char *) pFileBuf));
  689. } /* end of regular file handling */
  690.     else
  691. {
  692. printErr("tar: not a regular file nor a directory %s, skippedn",
  693. name );
  694. goto abort;
  695. }
  696.     pCtrl->recurseCnt --;
  697.     return OK;
  698. abort:
  699.     pCtrl->recurseCnt --;
  700.     return ERROR;
  701.     }
  702. /*******************************************************************************
  703. *
  704. * tarArchive - archive named file/dir onto tape in tar format
  705. *
  706. * This function creates a UNIX compatible tar formatted archives
  707. * which contain entire file hierarchies from disk file systems.
  708. * Files and directories are archived with mode and time information
  709. * as returned by stat().
  710. *
  711. * The <tape> argument can be any tape drive device name or a name of any
  712. * file that will be created if necessary, and will contain the archive.
  713. * If <tape> is set to "-", standard output will be used.
  714. * If <tape> is NULL (unspecified from Shell), the default archive file
  715. * name stored in global variable <TAPE> will be used.
  716. *
  717. * Each write() of the archive file will be exactly <bfactor>*512 bytes
  718. * long, hence on tapes in variable mode, this will be the physical
  719. * block size on the tape. With Fixed Mode tapes this is only a performance
  720. * matter. If <bfactor> is 0, or unspecified from Shell, it will be set
  721. * to the default value of 20.
  722. *
  723. * The <verbose> argument is a boolean, if set to 1, will cause informative
  724. * messages to be printed to standard error whenever an action is taken,
  725. * otherwise, only errors are reported.
  726. *
  727. * The <name> argument is the path of the hierarchy to be archived.
  728. * if NULL (or unspecified from the Shell), the current directory path "."
  729. * will be used.  This is the path as seen from the target, not from 
  730. * the Tornado host.
  731. *
  732. * All informative and error message are printed to standard error.
  733. *
  734. * NOTE
  735. * Refrain from specifying absolute path names in <path>, such archives
  736. * tend to be either difficult to extract or can cause unexpected
  737. * damage to existing files if such exist under the same absolute name.
  738. *
  739. * There is no way of specifying a number of hierarchies to dump.
  740. */
  741. STATUS tarArchive
  742.     (
  743.     char * pTape, /* tape device name */
  744.     int bfactor, /* requested blocking factor */
  745.     BOOL verbose, /* if TRUE print progress info */
  746.     char * pName /* file/dir name to archive */
  747.     )
  748.     {
  749.     MT_TAR_SOFT ctrl; /* control structure */
  750.     STATUS retval = OK;
  751.     /* Set defaults */
  752.     if( pTape == NULL )
  753. pTape = TAPE ;
  754.     if( bfactor == 0 )
  755. bfactor = 20 ;
  756.     if( pName == NULL )
  757. pName = "." ;
  758.     if( verbose )
  759. printErr("Archiving to %sn", pTape );
  760.     bzero( (char *)&ctrl, sizeof(ctrl) );
  761.     bzero( bZero, sizeof(bZero) ); /* not harmful for reentrancy */
  762.     /* Open tape device and initialize control structure */
  763.     if( strcmp(pTape, "-") == 0)
  764. ctrl.fd = STD_OUT;
  765.     else
  766. ctrl.fd = open( pTape, O_CREAT | O_WRONLY, 0644) ;
  767.     if ( ctrl.fd < 0 )
  768. {
  769. printErr("Failed to open tape: %sn", strerror(errnoGet()) );
  770. return ERROR;
  771. }
  772.     
  773.     ctrl.bValid = 0 ;
  774.     ctrl.bFactor = bfactor ;
  775.     ctrl.pBuf = KHEAP_ALLOC( bfactor * TBLOCK ) ;
  776.     if ( ctrl.pBuf == NULL )
  777. {
  778. printErr("Not enough memory, exiting.n" );
  779. if ( ctrl.fd != STD_OUT)
  780.     close( ctrl.fd );
  781. return ERROR ;
  782. }
  783.     /* all exits from now via goto in order to free the buffer */
  784.     retval = tarArchDo( &ctrl, verbose, pName ) ;
  785.     /* at end of tape, write at least two zero blocks */
  786.     if( verbose )
  787. printErr("tar: writing end of tape.n");
  788.     tarWrtBlks( &ctrl, bZero, 1 );
  789.     tarWrtBlks( &ctrl, bZero, 1 );
  790.     /* and fill the last blocked block until written to tape */
  791.     while( ctrl.bValid > 0 )
  792. tarWrtBlks( &ctrl, bZero, 1 );
  793.     
  794.     if( ctrl.fd != STD_OUT )
  795. close( ctrl.fd );
  796.     KHEAP_FREE(((char *) ctrl.pBuf));
  797.     return( retval );
  798.     }
  799. /*******************************************************************************
  800. *
  801. * tarTocFile - display one file or directory from tar tape
  802. *
  803. * Called from tarToc for every file/dir found on tape.
  804. *
  805. * RETURNS: OK or ERROR
  806. */
  807. LOCAL STATUS tarTocFile
  808.     (
  809.     MT_TAR_SOFT *pCtrl, /* control structure */
  810.     MT_HBLOCK *pBlk /* header block */
  811.     )
  812.     {
  813.     register int rc ;
  814.     int sum = -1 ; /* checksum */
  815.     int size = 0 ; /* file size in bytes */
  816.     int nblks = 0; /* file size in TBLOCKs */
  817.     int mode ;
  818.     char * fn ; /* file/dir name */
  819.     /* Check the checksum of this header */
  820.     rc = sscanf( pBlk->dbuf.chksum, "%o", &sum ) ; /* extract checksum */
  821.     bfill( pBlk->dbuf.chksum, 8, ' '); /* fill blanks */
  822.     if( mtChecksum( pBlk->dummy, TBLOCK ) != sum )
  823. {
  824. printErr("bad checksum %d != %dn",
  825. mtChecksum( pBlk->dummy, TBLOCK), sum );
  826. return ERROR;
  827. }
  828.     /* Parse all fields of header that we need, and store them safely */
  829.     sscanf( pBlk->dbuf.mode, "%o", &mode );
  830.     sscanf( pBlk->dbuf.size, "%12o", &size );
  831.     fn = pBlk->dbuf.name ;
  832.     /* Handle directory */
  833.     if( (size == 0) || ( fn[ strlen(fn) - 1 ] == '/' ) )
  834. {
  835. printErr("directory %s.n", fn );
  836. }
  837.     /* Filter out links etc */
  838.     if ((pBlk->dbuf.linkflag != '') &&
  839.      (pBlk->dbuf.linkflag != '0') &&
  840. (pBlk->dbuf.linkflag != ' '))
  841. {
  842. printErr("we do not support links, %s skippedn", fn );
  843. return OK;
  844. }
  845.     /* Handle Regular File - calculate number of blocks */
  846.     if( size > 0 )
  847. nblks = ( size / TBLOCK ) +  ((size % TBLOCK)? 1 : 0 ) ;
  848.     printErr("file %s, size %d bytes, %d blocksn",
  849. fn, size, nblks );
  850.     /* Loop until entire file skipped */
  851.     while (size > 0)
  852. {
  853. MT_HBLOCK *pBuf;
  854. rc = tarRdBlks( pCtrl, &pBuf, nblks) ;
  855. if ( rc < 0 )
  856.     {
  857.     printErr("error reading tapen");
  858.     return ERROR;
  859.     }
  860. size -= rc*TBLOCK ;
  861. nblks -= rc ;
  862. }
  863.     return( OK );
  864.     }
  865. /*******************************************************************************
  866. *
  867. * tarToc - display all contents of a tar formatted tape
  868. *
  869. * This is a UNIX-tar compatible utility that displays entire
  870. * file hierarchies from tar-formatted media, e.g. tape.
  871. *
  872. * The <tape> argument may be any tape device name or file name
  873. * that contains a tar formatted archive. If <tape> is equal "-",
  874. * standard input is used. If <tape> is NULL (or unspecified from Shell)
  875. * the default archive file name stored in global variable <TAPE> is used.
  876. *
  877. * The <bfactor> dictates the blocking factor the tape was written with.
  878. * If 0, or unspecified from Shell, default of 20 is used.
  879. *
  880. * Archive contents are displayed on standard output, while
  881. * all informative and eror message are printed to standard error.
  882. *
  883. */
  884. STATUS tarToc
  885.     (
  886.     char * tape, /* tape device name */
  887.     int bfactor  /* requested blocking factor */
  888.     )
  889.     {
  890.     register  int rc ; /* return codes */
  891.     MT_TAR_SOFT ctrl ; /* control structure */
  892.     STATUS retval = OK;
  893.     /* Set defaults */
  894.     if( tape == NULL )
  895. tape = TAPE ;
  896.     if( bfactor == 0 )
  897. bfactor = 20 ;
  898.     printErr("Contents from %sn", tape );
  899.     bzero( (char *)&ctrl, sizeof(ctrl) );
  900.     bzero( bZero, sizeof(bZero) ); /* not harmful for reentrancy */
  901.     /* Open tape device and initialize control structure */
  902.     if( strcmp(tape, "-") == 0)
  903. ctrl.fd = STD_IN;
  904.     else
  905. ctrl.fd = open( tape, O_RDONLY, 0) ;
  906.     if ( ctrl.fd < 0 )
  907. {
  908. printErr("Failed to open tape: %sn", strerror(errnoGet()) );
  909. return ERROR;
  910. }
  911.     
  912.     ctrl.bFactor = bfactor ;
  913.     ctrl.pBuf = KHEAP_ALLOC( bfactor * TBLOCK ) ;
  914.     if ( ctrl.pBuf == NULL )
  915. {
  916. printErr("Not enough memory, exiting.n" );
  917. if ( ctrl.fd != STD_IN )
  918.     close( ctrl.fd );
  919. return ERROR ;
  920. }
  921.     /* all exits from now via goto in order to free the buffer */
  922.     /* Read the first block and adjust blocking factor */
  923.     rc = read( ctrl.fd, ctrl.pBuf->dummy, ctrl.bFactor*TBLOCK ) ;
  924.     if ( rc == ERROR )
  925. {
  926. printErr("read error at the beginning of tape, exiting.n" );
  927. retval = ERROR ;
  928. goto finish;
  929. }
  930.     else if( rc == 0 )
  931. {
  932. printErr("empty tape file, exiting.n" );
  933. goto finish;
  934. }
  935.     else if( (rc % TBLOCK) != 0 )
  936. {
  937. printErr("tape block not multiple of %d, exiting.n", TBLOCK);
  938. retval = ERROR ;
  939. goto finish;
  940. }
  941.     ctrl.bValid = rc / TBLOCK ;
  942.     ctrl.pBnext = ctrl.pBuf ;
  943.     if ( ctrl.bFactor != ctrl.bValid )
  944. {
  945. printErr("adjusting blocking factor to %dn", ctrl.bValid );
  946. ctrl.bFactor = ctrl.bValid ;
  947. }
  948.     /* End of overture, start processing files until end of tape */
  949.     FOREVER
  950. {
  951. MT_HBLOCK * pBlk ;
  952. if ( tarRdBlks( &ctrl, &pBlk, 1) != 1 )
  953.     {
  954.     retval = ERROR ;
  955.     goto finish;
  956.     }
  957. if ( bcmp( pBlk->dummy, bZero, TBLOCK) == 0 )
  958.     {
  959.     printErr("end of tape encountered, read until eof...n");
  960.     while( tarRdBlks( &ctrl, &pBlk, 1) > 0) ;
  961.     printErr("done.n");
  962.     retval = OK ;
  963.     goto finish;
  964.     }
  965. if ( tarTocFile( &ctrl, pBlk) == ERROR )
  966.     {
  967.     retval = ERROR;
  968.     goto finish;
  969.     }
  970. } /* end of FOREVER */
  971.     
  972. finish:
  973. if ( ctrl.fd != STD_IN )
  974.     close( ctrl.fd );
  975. KHEAP_FREE((char *) ctrl.pBuf );
  976. return( retval );
  977.     }
  978. /* End of File */