#!mkcmd # $Id: tart.m,v 1.4 2001/07/23 22:23:59 ksb Exp $ # from '' from '' from '' basename "tart" "" require "std_help.m" "std_control.m" "std_version.m" require "samepath.m" %i static char rcsid[] = "$Id: tart.m,v 1.4 2001/07/23 22:23:59 ksb Exp $"; #define TART_BLOCKS 20 /* this is for old school tars */ #define TART_BLOCK_SIZE 512 /* status for tar output */ typedef struct TBnode { int icount; FILE *fpout; char aacblock[TART_BLOCKS][TART_BLOCK_SIZE]; } TAR_BUF; %% boolean 'b' { named "fNoPad" init '0' help "do not pad output files to an even multiple of 20 blocks" } boolean 'r' { named "fReverse" init "0" help "reverse the output streams -- matches to stdout" } boolean '1' { named "fOnce" init "0" help "remove a pattern from the list after it matches the first file" } file ["wb"] 'O' { named "fpCatch" "pcCatch" param "caught" init '"/dev/null"' help "a tar file of the nodes that matched the patterns" } list { param "patterns" help "filenames to divert away from the output archive" } %c /* Copy an input tar chunk to the named file, or if pcHeader (ksb) * is (char *)0 close the tar file off at even 20b */ static void CopyOut(pTB, lSkip, pcHeader) TAR_BUF *pTB; long lSkip; char *pcHeader; { if ((char *)0 == pcHeader) { if (0 == pTB->icount) { return; } if (fNoPad) { goto no_pad; } for (/* nada */; pTB->icount < TART_BLOCKS; ++pTB->icount) { memset((void *)pTB->aacblock[pTB->icount], '\000', TART_BLOCK_SIZE); } } else { memmove((void *)pTB->aacblock[pTB->icount], pcHeader, TART_BLOCK_SIZE); for (++pTB->icount; lSkip > 0; --lSkip) { if (TART_BLOCKS == pTB->icount) { if (TART_BLOCKS != fwrite((void *)pTB->aacblock[0], TART_BLOCK_SIZE, pTB->icount, pTB->fpout)) { fprintf(stderr, "%s: fwrite: %s\n", progname, strerror(errno)); exit(8); } pTB->icount = 0; } if (1 == fread((void *)pTB->aacblock[pTB->icount++], TART_BLOCK_SIZE, 1, stdin)) { continue; } fprintf(stderr, "%s: fread: stdin: %s\n", progname, strerror(errno)); exit(4); } } if (TART_BLOCKS != pTB->icount) { return; } no_pad: if (pTB->icount != fwrite((void *)pTB->aacblock[0], TART_BLOCK_SIZE, pTB->icount, pTB->fpout)) { fprintf(stderr, "%s: fwrite: %s\n", progname, strerror(errno)); exit(9); } pTB->icount = 0; } /* return 1 if the filename matches any of the patterns (ksb) */ int GlobCmp(iCount, ppcPats, pcName) int iCount; char **ppcPats, *pcName; { register int i; for (i = 0; i < iCount; ++i) { if ((char *)0 == ppcPats[i] || !SamePath(ppcPats[i], pcName)) { continue; } if (fOnce) { ppcPats[i] = (char *)0; } return 1; } return 0; } /* Function(s) to parse header of tar file for names and file sizes (sea) * Position(range) for the following fields: * header[0 - 100] is the name * header[125 - 136] is the size (in octal) * Actual file starts at next block of 512 bytes */ void list_func(int argc, char **argv) { register long lSkip; register int iCmp; auto ldiv_t ldBlocks; auto char acHeader[TART_BLOCK_SIZE]; auto long nLen; auto int cKeep; auto TAR_BUF TBOut, TBCaught; TBOut.icount = TBCaught.icount = 0; TBOut.fpout = stdout; TBCaught.fpout = fpCatch; while (1 == fread(acHeader, sizeof(acHeader), 1, stdin)) { if ('\000' == acHeader[0]) { break; } sscanf(acHeader+125, "%lo", &nLen); ldBlocks = ldiv(nLen, (long)TART_BLOCK_SIZE); lSkip = ldBlocks.quot + (ldBlocks.rem != 0); cKeep = acHeader[101]; acHeader[101] = '\000'; iCmp = fReverse ^ GlobCmp(argc, argv, acHeader); if (fVerbose) { fprintf(stderr, "%s is %ld block%s, %d\n", acHeader, lSkip, (1 != lSkip) + "s", iCmp); } acHeader[101] = cKeep; if (!fExec) { if (0 != fseek(stdin, lSkip*(long)TART_BLOCK_SIZE, SEEK_CUR)) { fprintf(stderr, "%s: fseek error\n", progname); break; } continue; } CopyOut(iCmp ? &TBCaught : &TBOut, lSkip, acHeader); } CopyOut(&TBOut, 0L, (char *)0); CopyOut(&TBCaught, 0L, (char *)0); }