📄 tarlib.c
字号:
/* tarLib.c - UNIX tar compatible library *//* Copyright 1993-2002 Wind River Systems, Inc. *//* Copyright (c) 1993, 1994 RST Software Industries Ltd. *//*modification history--------------------01i,20sep01,jkf SPR#69031, common code for both AE & 5.x.01h,26dec99,jkf T3 KHEAP_ALLOC03g,11nov99,jkf need to fill all eight bytes with 0x20 for the checksum calc correct for MKS toolkit 6.2 generated tar file.03f,31jul99,jkf T2 merge, tidiness & spelling.03e,30jul98,lrn partial doc cleanup03b,24jun98,lrn fixed bug causing 0-size files to be extracted as dirs, improved tarHelp to list parameters03a,07jun98,lrn derived from RST usrTapeLib.c, cleaned all tape related stuff02f,15jan95,rst adding TarToc functionality02d,28mar94,rst added Tar utilities.*//*DESCRIPTIONThis library implements functions for archiving, extracting and listingof UNIX-compatible "tar" file archives.It can be used to archive and extract entire file hierarchiesto/from archive files on local or remote disks, or directly to/frommagnetic tapes.SEE ALSO: dosFsLibCURRENT LIMITATIONSThis Tar utility does not handle MS-DOS file attributes,when used in conjunction with the MS-DOS file system.The maximum subdirectory depth supported by this library is 16,while the total maximum path name that can be handled by tar is limited at 100 characters.*/#include "vxWorks.h"#include "stdlib.h"#include "ioLib.h"#include "errnoLib.h"#include "string.h"#include "stdio.h"#include "private/dosFsVerP.h"#include "dosFsLib.h"#include "dirent.h"#include "stat.h"#include "tarLib.h"/* data types *//* * VxWorks Tar Utility, part of usrTapeLib (for now). * UNIX tar(1) tape format - header definition */#define TBLOCK 512 /* TAR Tape block size, part of TAR format */#define NAMSIZ 100 /* size of file name in TAR tape header */#define MAXLEVEL 16 /* max. # of subdirectory levels, arbitrary */#define NULLDEV "/null" /* data sink */typedef union hblock { char dummy[TBLOCK]; struct header { char name[NAMSIZ]; char mode[8]; char uid[8]; char gid[8]; char size[12]; char mtime[12]; char chksum[8]; char linkflag; char linkname[NAMSIZ]; } dbuf; } MT_HBLOCK ;/* Control structure used internally for reentrancy etc. */typedef struct { int fd ; /* current tape file descriptor */ int bFactor; /* current blocking factor */ int bValid; /* number of valid blocks in buffer */ int recurseCnt; /* recusrion counter */ MT_HBLOCK * pBuf; /* working buffer */ MT_HBLOCK * pBnext; /* ptr to next block to return */ } MT_TAR_SOFT ;/* globals */char *TAPE = "/archive0.tar" ; /* default archive name *//* locals */LOCAL char bZero[ TBLOCK ] ; /* zeroed block *//********************************************************************************* tarHelp - print help information about TAR archive functions.** NOMANUAL*/void tarHelp ( void ) { int i ; const char * help_msg[] = { "Help information on TAR archival functions:\n", "\n", " Archive any directory: \n", " tarArchive( archFile, bfactor, verbose, dirName )\n", " Extract from TAR archive into current directory:\n", " tarExtract( archFile, bfactor, verbose )\n", " List contents of TAR archive\n", " tarToc( archFile, bfactor)\n", " if <dirName> is NULL, archive current directory\n", "\n", NULL }; for(i = 0; help_msg[i] != NULL ; i++ ) printf(help_msg[i]); printf(" if <archFile> is NULL,\n" "current default archive file \"%s\" will be used,\n", TAPE); printf(" change the TAPE variable to set a different name.\n\n"); }/********************************************************************************* mtChecksum - calculate checksums for tar header blocks** RETURNS: the checksum value*/LOCAL int mtChecksum ( void * pBuf, unsigned size ) { register int sum = 0 ; register unsigned char *p = pBuf ; while( size > 0 ) { sum += *p++; size -= sizeof(*p); } return(sum); }/********************************************************************************* tarRdBlks - read <nBlocks> blocks from tape** RETURNS: number of blocks actually got, or ERROR.*/LOCAL int tarRdBlks ( MT_TAR_SOFT *pCtrl, /* control structure */ MT_HBLOCK **ppBlk, /* where to return buffer address */ unsigned int nBlocks /* how many blocks to get */ ) { register int rc ; if (pCtrl->bValid <= 0) { /* buffer empty, read more blocks from tape */ rc = read(pCtrl->fd, pCtrl->pBuf->dummy, pCtrl->bFactor * TBLOCK); if ( rc == ERROR ) return ERROR ; else if( rc == 0 ) return 0 ; else if( (rc % TBLOCK) != 0 ) { printErr("tarRdBlks: tape block not multiple of %d\n", TBLOCK); return ERROR; } pCtrl->bValid = rc / TBLOCK ; pCtrl->pBnext = pCtrl->pBuf ; } rc = min((ULONG)pCtrl->bValid, nBlocks) ; *ppBlk = pCtrl->pBnext ; pCtrl->bValid -= rc ; pCtrl->pBnext += rc ; return( rc ) ; }/********************************************************************************* mtAccess - check existence of path for a new file or directory <name>** RETURNS: OK or ERROR*/LOCAL STATUS mtAccess ( const char *name ) { char tmpName [ NAMSIZ ] ; struct stat st ; int i ; static char slash = '/' ; register char *pSlash ; strncpy( tmpName, name, NAMSIZ ) ; pSlash = tmpName ; for(i=0; i<MAXLEVEL; i++) { if ( (pSlash = strchr(pSlash, slash)) == NULL ) return OK; *pSlash = '\0' ; if ( stat( tmpName, &st ) == OK ) { if( S_ISDIR(st.st_mode ) == 0) { printErr("Path %s is not a directory\n", tmpName); return ERROR; } } else { mkdir( tmpName ); } *pSlash = slash ; /* restore slash position */ pSlash++; } printErr("Path too long %s\n", name ); return ERROR; }/********************************************************************************* tarExtractFile - extract one file or directory from tar tape** Called from tarExtract for every file/dir found on tape.** RETURNS: OK or ERROR*/LOCAL STATUS tarExtractFile ( MT_TAR_SOFT *pCtrl, /* control structure */ MT_HBLOCK *pBlk, /* header block */ BOOL verbose /* verbose */ ) { register int rc, fd ; int sum = -1 ; /* checksum */ int size = 0 ; /* file size in bytes */ int nblks = 0; /* file size in TBLOCKs */ int mode ; char * fn ; /* file/dir name */ /* Check the checksum of this header */ rc = sscanf( pBlk->dbuf.chksum, "%o", &sum ) ; /* extract checksum */ bfill( pBlk->dbuf.chksum, 8, ' '); /* fill blanks */ if( mtChecksum( pBlk->dummy, TBLOCK ) != sum ) { printErr("bad checksum %d != %d\n", mtChecksum( pBlk->dummy, TBLOCK), sum ); return ERROR; } /* Parse all fields of header that we need, and store them safely */ sscanf( pBlk->dbuf.mode, "%o", &mode ); sscanf( pBlk->dbuf.size, "%12o", &size ); fn = pBlk->dbuf.name ; /* Handle directory */ if( (size == 0) && ( fn[ strlen(fn) - 1 ] == '/' ) ) { if( strcmp(fn, "./") == 0) return OK; if ( fn[ strlen(fn) - 1 ] == '/' ) /* cut the slash */ fn[ strlen(fn) - 1 ] = '\0' ; /* Must make sure that parent exists for this new directory */ if ( mtAccess(fn) == ERROR ) { return ERROR; } fd = open (fn, O_RDWR | O_CREAT, FSTAT_DIR | (mode & 0777) ); if (( fd == ERROR ) && (errnoGet() == S_dosFsLib_FILE_EXISTS)) { printErr("Warning: directory %s already exists\n", fn ); return OK; } else if (fd == ERROR) { printErr("failed to create directory %s, %s, continuing\n", fn, strerror(errnoGet())); return OK; } if(verbose) printErr("created directory %s.\n", fn ); return (close (fd)); } /* non-empty file has a trailing slash, we better treat it as file and */ if ( fn[ strlen(fn) - 1 ] == '/' ) /* cut a trailing slash */ fn[ strlen(fn) - 1 ] = '\0' ; /* Filter out links etc */ if ((pBlk->dbuf.linkflag != '\0') && (pBlk->dbuf.linkflag != '0') && (pBlk->dbuf.linkflag != ' ')) { printErr("we do not support links, %s skipped\n", fn ); return OK; } /* Handle Regular File - calculate number of blocks */ if( size > 0 ) nblks = ( size / TBLOCK ) + ((size % TBLOCK)? 1 : 0 ) ; /* Must make sure that directory exists for this new file */ if ( mtAccess(fn) == ERROR ) { return ERROR; } /* Create file */ fd = open( fn, O_RDWR | O_CREAT, mode & 0777 ) ; if( fd == ERROR ) { printErr("failed to create file %s, %s, skipping!\n", fn, strerror(errnoGet())); fd = open( NULLDEV, O_RDWR, 0) ; } if(verbose) printErr("extracting file %s, size %d bytes, %d blocks\n", fn, size, nblks ); /* Loop until entire file extracted */ while (size > 0) { MT_HBLOCK *pBuf; register int wc ; rc = tarRdBlks( pCtrl, &pBuf, nblks) ; if ( rc < 0 ) { printErr("error reading tape\n"); close(fd); return ERROR; } wc = write( fd, pBuf->dummy, min( rc*TBLOCK, size ) ) ; if( wc == ERROR ) { printErr("error writing file\n"); break; } size -= rc*TBLOCK ; nblks -= rc ; } /* Close the newly created file */ return( close(fd) ) ; }/********************************************************************************* tarExtract - extract all files from a tar formatted tape** This is a UNIX-tar compatible utility that extracts entire* file hierarchies from tar-formatted archive.* The files are extracted with their original names and modes.* In some cases a file cannot be created on disk, for example if* the name is too long for regular DOS file name conventions,* in such cases entire files are skipped, and this program will* continue with the next file. Directories are created in order* to be able to create all files on tape.** The <tape> argument may be any tape device name or file name* that contains a tar formatted archive. If <tape> is equal "-",* standard input is used. If <tape> is NULL (or unspecified from Shell)* the default archive file name stored in global variable <TAPE> is used.** The <bfactor> dictates the blocking factor the tape was written with.* If 0, or unspecified from the shell, a default of 20 is used.** The <verbose> argument is a boolean, if set to 1, will cause informative* messages to be printed to standard error whenever an action is taken,* otherwise, only errors are reported.** All informative and error message are printed to standard error.** There is no way to selectively extract tar archives with this* utility. It extracts entire archives.*/STATUS tarExtract ( char * pTape, /* tape device name */ int bfactor, /* requested blocking factor */ BOOL verbose /* if TRUE print progress info */ ) { register int rc ; /* return codes */ MT_TAR_SOFT ctrl ; /* control structure */ STATUS retval = OK; /* Set defaults */ if( pTape == NULL ) pTape = TAPE ; if( bfactor == 0 ) bfactor = 20 ; if( verbose ) printErr("Extracting from %s\n", pTape ); bzero( (char *)&ctrl, sizeof(ctrl) ); bzero( bZero, sizeof(bZero) ); /* not harmful for reentrancy */ /* Open tape device and initialize control structure */ if( strcmp(pTape, "-") == 0) ctrl.fd = STD_IN; else ctrl.fd = open( pTape, O_RDONLY, 0) ; if ( ctrl.fd < 0 ) { printErr("Failed to open tape: %s\n", strerror(errnoGet()) ); return ERROR; } ctrl.bFactor = bfactor ; ctrl.pBuf = KHEAP_ALLOC( bfactor * TBLOCK ) ; if ( ctrl.pBuf == NULL ) { printErr("Not enough memory, exiting.\n" ); if ( ctrl.fd != STD_IN ) close( ctrl.fd ); return ERROR ; } /* all exits from now via goto in order to free the buffer */ /* Read the first block and adjust blocking factor */ rc = read( ctrl.fd, ctrl.pBuf->dummy, ctrl.bFactor*TBLOCK ) ; if ( rc == ERROR ) { printErr("read error at the beginning of tape, exiting.\n" ); retval = ERROR ; goto finish; } else if( rc == 0 ) { printErr("empty tape file, exiting.\n" ); goto finish; } else if( (rc % TBLOCK) != 0 ) { printErr("tape block not multiple of %d, exiting.\n", TBLOCK); retval = ERROR ; goto finish; } ctrl.bValid = rc / TBLOCK ; ctrl.pBnext = ctrl.pBuf ; if ( ctrl.bFactor != ctrl.bValid ) { if( verbose ) printErr("adjusting blocking factor to %d\n", ctrl.bValid ); ctrl.bFactor = ctrl.bValid ; } /* End of overture, start processing files until end of tape */ FOREVER { MT_HBLOCK * pBlk ; if ( tarRdBlks( &ctrl, &pBlk, 1) != 1 ) { retval = ERROR ; goto finish; } if ( bcmp( pBlk->dummy, bZero, TBLOCK) == 0 ) { if(verbose) printErr("end of tape encountered, read until eof...\n"); while( tarRdBlks( &ctrl, &pBlk, 1) > 0) ; if(verbose) printErr("done.\n"); retval = OK ; goto finish; } if ( tarExtractFile( &ctrl, pBlk, verbose) == ERROR ) { retval = ERROR; goto finish; } } /* end of FOREVER */ finish: if ( ctrl.fd != STD_IN ) close( ctrl.fd ); KHEAP_FREE((char *)ctrl.pBuf ); return( retval ); }/********************************************************************************* tarWrtBlks - write <nBlocks> blocks to tape** Receives any number of blocks, and handles the blocking factor* mechanism using the pCtrl->pBuf internal buffer and associated* counters.** RETURNS: OK or ERROR;*/LOCAL STATUS tarWrtBlks ( MT_TAR_SOFT *pCtrl, /* control structure */ char *pBuf, /* data to write */ unsigned int nBlocks /* how many blocks to get */ ) { register int rc ; while( nBlocks > 0 ) { if ((pCtrl->bValid <= 0) && (nBlocks >= (unsigned int)pCtrl->bFactor)) { /* internal buffer empty, write directly */ rc = write( pCtrl->fd, pBuf, pCtrl->bFactor*TBLOCK ) ; if ( rc == ERROR ) return ERROR ; /* adjust count and pointer */ pBuf += TBLOCK * pCtrl->bFactor ; nBlocks -= pCtrl->bFactor ; } else { register int cnt ; /* internal buffer partially full, fill it up */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -