📄 tarlib.c
字号:
cnt = pCtrl->bFactor - pCtrl->bValid ; cnt = min( (ULONG)cnt, nBlocks ); bcopy( pBuf, (char *) (pCtrl->pBuf + pCtrl->bValid), cnt*TBLOCK ); pBuf += cnt*TBLOCK; nBlocks -= cnt ; pCtrl->bValid += cnt ; } if( pCtrl->bValid == pCtrl->bFactor ) { /* one full blocked buffer, write to tape */ rc = write( pCtrl->fd, (char *) pCtrl->pBuf, pCtrl->bFactor*TBLOCK ) ; if ( rc == ERROR ) return ERROR ; /* adjust count and pointer */ pCtrl->bValid = 0 ; } } /* while */ return OK; }/********************************************************************************* tarCreateHdr - build a tar header block ** NOTE:* SunOS tar(5) man page is not accurate, this function* was built using empiric methods with that tar(1) command.* RETURNS: file size in bytes*/LOCAL int tarCreateHdr ( MT_TAR_SOFT *pCtrl, /* control structure */ const char *name, /* file/dir name */ struct stat *pStat, /* file stats */ MT_HBLOCK * pBlk /* block buffer for header */ ) { int chksum; strncpy( pBlk->dbuf.name, name, NAMSIZ ); if( S_ISDIR(pStat->st_mode) ) { pStat->st_mode |= 0200 ; pStat->st_size = 0 ; } sprintf( pBlk->dbuf.mode, "%6o ", pStat->st_mode ); sprintf( pBlk->dbuf.uid, "%6o ", pStat->st_uid ); sprintf( pBlk->dbuf.gid, "%6o ", pStat->st_gid ); sprintf( pBlk->dbuf.size, "%11lo ", pStat->st_size ); sprintf( pBlk->dbuf.mtime, "%11lo ", pStat->st_mtime ); pBlk->dbuf.linkflag = '0'; bfill( pBlk->dbuf.chksum, 8, ' '); /* fill blanks */ chksum = mtChecksum( pBlk->dummy, TBLOCK ) ; sprintf( pBlk->dbuf.chksum, "%6o", chksum); return( pStat->st_size ); }/********************************************************************************* tarArchDo - archive a file/dir onto tape (recursive)** Handle one file or one directory, in case of directory,* write the dir entry and recurse.** RETURNS: OK or ERROR.*/LOCAL STATUS tarArchDo ( MT_TAR_SOFT *pCtrl, /* control structure */ BOOL verbose, /* verbosity flag */ char * name /* file/dir name */ ) { MT_HBLOCK hblock; /* header block */ struct stat st; /* file/dir stat */ register int rc; bzero ( (char *) &hblock, sizeof( MT_HBLOCK ) ); if( strlen( name ) >= (NAMSIZ-1)) { printErr("tar: name too long %s, skip.\n", name ); return ERROR; } rc = stat( name, &st ); if ( rc == ERROR) { perror("tar: stat error "); return ERROR ; } if ( pCtrl->recurseCnt++ > MAXLEVEL ) { printErr("tar: nesting too deep, skipping %s\n", name); goto abort ; } if( S_ISDIR(st.st_mode) ) { char fn [ NAMSIZ ]; /* subdir name */ register DIR * pDir; struct dirent * pDirEnt ; /* handle directory */ strncpy( fn, name, NAMSIZ-2 ); strcat( fn, "/" ); /* write directory header block to tape */ tarCreateHdr( pCtrl, fn, &st, &hblock ) ; if( verbose ) printErr("tar: writing directory %s\n", name ); if (tarWrtBlks( pCtrl, (char *) &hblock, 1 ) == ERROR ) { perror("tar: error writing header to tape "); goto abort; } /* recurse on every directory member */ pDir = opendir( name ) ; if( pDir == NULL ) { perror((sprintf(fn,"tar: error opening directory %s ", name),fn)); goto abort; } for( pDirEnt = readdir(pDir); pDirEnt != NULL ; pDirEnt = readdir(pDir)) { /* Skip the "." and ".." entries */ if ( strcmp( pDirEnt->d_name, ".") == 0) continue ; if ( strcmp( pDirEnt->d_name, "..") == 0) continue ; /* build the new name by concatenating */ strncpy( fn, name, NAMSIZ-2 ); strcat( fn, "/" ); strcat( fn, pDirEnt->d_name ); /* recurse ! nesting level of MAXLEVEL maximum */ (void )tarArchDo( pCtrl, verbose, fn ) ; } closedir( pDir ); } else if( S_ISREG(st.st_mode) ) { int fileFd = -1 ; register int fileSize ; register int rc ; register char * pFileBuf ; unsigned bufSize = pCtrl->bFactor*TBLOCK; unsigned nBlocks = 0 ; /* handle plain file */ /* write file header to tape */ fileSize = tarCreateHdr( pCtrl, name, &st, &hblock ) ; /* write the file itself to tape */ pFileBuf = KHEAP_ALLOC( bufSize ); if( pFileBuf == NULL ) { printErr("tar: not enough memory\n" ); goto abort; } fileFd = open( name, O_RDONLY, 0); if( fileFd == ERROR ) { perror((sprintf(pFileBuf,"tar: file open error %s, ", name), pFileBuf)); KHEAP_FREE(((char *) pFileBuf) ); goto abort; } /* Handle Regular File - calculate number of blocks */ if( fileSize > 0 ) nBlocks = ( fileSize / TBLOCK ) + ((fileSize % TBLOCK)? 1 : 0 ) ; if( verbose ) printErr("tar: writing file %s, size %d bytes, %d blocks\n", name, fileSize, nBlocks ); if (tarWrtBlks( pCtrl, (char *) &hblock, 1 ) == ERROR ) { perror("tar: error writing header to tape "); KHEAP_FREE(((char *) pFileBuf) ); goto abort; } while( nBlocks > 0 ) { /* try to optimize into direct tape writing here */ rc = read( fileFd, pFileBuf, bufSize - (pCtrl->bValid*TBLOCK) ) ; if( rc == ERROR ) { perror((sprintf(pFileBuf,"tar: file read error %s, ", name), pFileBuf)); rc = 1; } else if( rc == 0 ) { printErr("tar: file changed size!\n"); rc = 1; } else { /* recalculate read count in blocks */ rc = ( rc / TBLOCK ) + ((rc % TBLOCK)? 1 : 0 ) ; } /* Now write the file blocks to tape */ tarWrtBlks( pCtrl, pFileBuf, rc ); nBlocks -= rc ; }/*while*/ close( fileFd ); KHEAP_FREE(((char *) pFileBuf)); } /* end of regular file handling */ else { printErr("tar: not a regular file nor a directory %s, skipped\n", name ); goto abort; } pCtrl->recurseCnt --; return OK;abort: pCtrl->recurseCnt --; return ERROR; }/********************************************************************************* tarArchive - archive named file/dir onto tape in tar format** This function creates a UNIX compatible tar formatted archives* which contain entire file hierarchies from disk file systems.* Files and directories are archived with mode and time information* as returned by stat().** The <tape> argument can be any tape drive device name or a name of any* file that will be created if necessary, and will contain the archive.* If <tape> is set to "-", standard output will be used.* If <tape> is NULL (unspecified from Shell), the default archive file* name stored in global variable <TAPE> will be used.** Each write() of the archive file will be exactly <bfactor>*512 bytes* long, hence on tapes in variable mode, this will be the physical* block size on the tape. With Fixed Mode tapes this is only a performance* matter. If <bfactor> is 0, or unspecified from Shell, it will be set* to the default value of 20.** 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.** The <name> argument is the path of the hierarchy to be archived.* if NULL (or unspecified from the Shell), the current directory path "."* will be used. This is the path as seen from the target, not from * the Tornado host.** All informative and error message are printed to standard error.** NOTE* Refrain from specifying absolute path names in <path>, such archives* tend to be either difficult to extract or can cause unexpected* damage to existing files if such exist under the same absolute name.** There is no way of specifying a number of hierarchies to dump.*/STATUS tarArchive ( char * pTape, /* tape device name */ int bfactor, /* requested blocking factor */ BOOL verbose, /* if TRUE print progress info */ char * pName /* file/dir name to archive */ ) { MT_TAR_SOFT ctrl; /* control structure */ STATUS retval = OK; /* Set defaults */ if( pTape == NULL ) pTape = TAPE ; if( bfactor == 0 ) bfactor = 20 ; if( pName == NULL ) pName = "." ; if( verbose ) printErr("Archiving to %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_OUT; else ctrl.fd = open( pTape, O_CREAT | O_WRONLY, 0644) ; if ( ctrl.fd < 0 ) { printErr("Failed to open tape: %s\n", strerror(errnoGet()) ); return ERROR; } ctrl.bValid = 0 ; ctrl.bFactor = bfactor ; ctrl.pBuf = KHEAP_ALLOC( bfactor * TBLOCK ) ; if ( ctrl.pBuf == NULL ) { printErr("Not enough memory, exiting.\n" ); if ( ctrl.fd != STD_OUT) close( ctrl.fd ); return ERROR ; } /* all exits from now via goto in order to free the buffer */ retval = tarArchDo( &ctrl, verbose, pName ) ; /* at end of tape, write at least two zero blocks */ if( verbose ) printErr("tar: writing end of tape.\n"); tarWrtBlks( &ctrl, bZero, 1 ); tarWrtBlks( &ctrl, bZero, 1 ); /* and fill the last blocked block until written to tape */ while( ctrl.bValid > 0 ) tarWrtBlks( &ctrl, bZero, 1 ); if( ctrl.fd != STD_OUT ) close( ctrl.fd ); KHEAP_FREE(((char *) ctrl.pBuf)); return( retval ); }/********************************************************************************* tarTocFile - display one file or directory from tar tape** Called from tarToc for every file/dir found on tape.** RETURNS: OK or ERROR*/LOCAL STATUS tarTocFile ( MT_TAR_SOFT *pCtrl, /* control structure */ MT_HBLOCK *pBlk /* header block */ ) { register int rc ; 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 ] == '/' ) ) { printErr("directory %s.\n", fn ); } /* 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 ) ; printErr("file %s, size %d bytes, %d blocks\n", fn, size, nblks ); /* Loop until entire file skipped */ while (size > 0) { MT_HBLOCK *pBuf; rc = tarRdBlks( pCtrl, &pBuf, nblks) ; if ( rc < 0 ) { printErr("error reading tape\n"); return ERROR; } size -= rc*TBLOCK ; nblks -= rc ; } return( OK ); }/********************************************************************************* tarToc - display all contents of a tar formatted tape** This is a UNIX-tar compatible utility that displays entire* file hierarchies from tar-formatted media, e.g. 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 Shell, default of 20 is used.** Archive contents are displayed on standard output, while* all informative and eror message are printed to standard error.**/STATUS tarToc ( char * tape, /* tape device name */ int bfactor /* requested blocking factor */ ) { register int rc ; /* return codes */ MT_TAR_SOFT ctrl ; /* control structure */ STATUS retval = OK; /* Set defaults */ if( tape == NULL ) tape = TAPE ; if( bfactor == 0 ) bfactor = 20 ; printErr("Contents from %s\n", tape ); bzero( (char *)&ctrl, sizeof(ctrl) ); bzero( bZero, sizeof(bZero) ); /* not harmful for reentrancy */ /* Open tape device and initialize control structure */ if( strcmp(tape, "-") == 0) ctrl.fd = STD_IN; else ctrl.fd = open( tape, 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 ) { 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 ) { printErr("end of tape encountered, read until eof...\n"); while( tarRdBlks( &ctrl, &pBlk, 1) > 0) ; printErr("done.\n"); retval = OK ; goto finish; } if ( tarTocFile( &ctrl, pBlk) == ERROR ) { retval = ERROR; goto finish; } } /* end of FOREVER */ finish: if ( ctrl.fd != STD_IN ) close( ctrl.fd ); KHEAP_FREE((char *) ctrl.pBuf ); return( retval ); }/* End of File */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -