home *** CD-ROM | disk | FTP | other *** search
- From: wht@n4hgf.Mt-Park.GA.US (Warren Tucker)
- Newsgroups: alt.sources
- Subject: cktar - compare tar tape against file system
- Message-ID: <236@n4hgf.Mt-Park.GA.US>
- Date: 9 Nov 90 09:49:50 GMT
-
- Submitted-by: wht@n4hgf
- Archive-name: cktar/part01
-
- This program reads a tar input file and compares each
- file on the volume with a matching file on disk.
-
- If a file on the tar file has the same length as a file on the
- disk, the files are compared byte for byte and the byte position
- of the first nonmatching byte is printed.
-
- If a file on the tar file has a different length from a file on
- the disk, this fact is noted.
-
- If the -U switch is present, UIDs must match. If the -G switch is
- present, gids must match. If the -M switch is present, times of last
- modification must match.
-
- With -t or -v switch, no output is produced for matching files.
- With -t, a title is printed for each file regardless of match.
- With -v, this output is expanded to show all attributes of the file
- on the tar file as well as the match status.
-
- If you wish to have cktar read from stdin and do not wish to use
- any of the available switches, use the '--' switch.
-
- The -A switch acts like the tar A key, causing a leading '/' in
- a tar input filename to be elided.
-
- Exceptions are reported by codes appearing after filenames:
- A - stat access denied
- N - non-existent file
- U - uid difference
- G - gid difference
- T - time of last modification difference
- S - size difference
- C - comparison failed at position shown by decimal value after C
- The 'S' and 'C' codes will never appear together, 'A' and 'N' will
- never appear together or with any other codes, but any other mixture
- of codes is possible. Only the C code has a decimal file position
- appended.
-
- #!/bin/sh
- # This is cktar, a shell archive (shar 3.46)
- # made 11/09/1990 09:44 UTC by wht@n4hgf
- # Source directory /u1/src/src
- #
- # existing files will NOT be overwritten unless -c is specified
- #
- # This shar contains:
- # length mode name
- # ------ ---------- ------------------------------------------
- # 14450 -rw-r--r-- cktar.c
- #
- # ============= cktar.c ==============
- if test -f 'cktar.c' -a X"$1" != X"-c"; then
- echo 'x - skipping cktar.c (File already exists)'
- else
- echo 'x - extracting cktar.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'cktar.c' &&
- X/* CHK=0xC1F1 */
- X/*+-------------------------------------------------------------------------
- X cktar.c - read a tar tape and compare against file system
- X wht@n4hgf.Mt-Park.GA.US
- X--------------------------------------------------------------------------*/
- X/*+:EDITS:*/
- X/*:11-08-1990-16:34-wht-creation */
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X#ifdef BSD
- X#include <sys/errno.h>
- X#include <sys/time.h>
- X#define memcmp(s1,s2,c) bcmp(s2,s1,c)
- X#else
- X#include <errno.h>
- X#include <time.h>
- X#include <memory.h>
- X#endif
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X
- X#if defined(min)
- X#undef min
- X#endif
- X#define min(a,b) ((a < b) ? a : b)
- X
- Xextern int errno;
- X
- X#define TBLOCK 512
- X#define NBLOCK 20
- X#define NAMSIZ 100
- Xtypedef union tar_block
- X{
- X char d[TBLOCK]; /* data */
- X struct header /* header */
- X {
- X char name[NAMSIZ];
- X char mode[8];
- X char uid[8];
- X char gid[8];
- X char size[12];
- X char mtime[12];
- X char chksum[8];
- X char linkflag;
- X char linkname[NAMSIZ];
- X char extno[4];
- X char extotal[4];
- X char efsize[12];
- X } h;
- X} TARBLOCK;
- X
- Xchar *tar_fname = "(stdin)";
- XFILE *fptar;
- Xint Tsw = 0;
- Xint Vsw = 0;
- Xint Asw = 0;
- Xint Usw = 0;
- Xint Gsw = 0;
- Xint Msw = 0;
- Xchar _tarbuf[TBLOCK * NBLOCK];
- Xlong now;
- X
- Xchar *usage_text[] =
- X{
- X"usage: cktar [-t] [-v] [-A] [-U] [-G] [-M] [-f tar_input_file] [--]",
- X"This program reads a tar input file and compares each",
- X"file on the volume with a matching file on disk.",
- X"",
- X"If a file on the tar file has the same length as a file on the",
- X"disk, the files are compared byte for byte and the byte position",
- X"of the first nonmatching byte is printed.",
- X"",
- X"If a file on the tar file has a different length from a file on",
- X"the disk, this fact is noted.",
- X"",
- X"If the -U switch is present, UIDs must match. If the -G switch is",
- X"present, gids must match. If the -M switch is present, times of last",
- X"modification must match.",
- X"",
- X"With -t or -v switch, no output is produced for matching files.",
- X"With -t, a title is printed for each file regardless of match.",
- X"With -v, this output is expanded to show all attributes of the file",
- X"on the tar file as well as the match status.",
- X"",
- X"If you wish to have cktar read from stdin and do not wish to use",
- X"any of the available switches, use the '--' switch.",
- X"",
- X"The -A switch acts like the tar A key, causing a leading '/' in",
- X"a tar input filename to be elided.",
- X"",
- X"Exceptions are reported by codes appearing after filenames:",
- X" A - stat access denied",
- X" N - non-existent file",
- X" U - uid difference",
- X" G - gid difference",
- X" T - time of last modification difference",
- X" S - size difference",
- X" C - comparison failed at position shown by decimal value after C",
- X"The 'S' and 'C' codes will never appear together, 'A' and 'N' will",
- X"never appear together or with any other codes, but any other mixture",
- X"of codes is possible. Only the C code has a decimal file position",
- X"appended.",
- X"",
- X(char *)0
- X};
- X
- X/*+-------------------------------------------------------------------------
- X usage()
- X--------------------------------------------------------------------------*/
- Xvoid
- Xusage()
- X{
- Xchar **t = usage_text;
- X
- X while(*t)
- X {
- X fputs(*t,stderr);
- X fputs("\n",stderr);
- X t++;
- X }
- X exit(1);
- X} /* end of usage */
- X
- X/*+-----------------------------------------------------------------------
- X mode_map(mode) - build drwxrwxrwx string
- X------------------------------------------------------------------------*/
- Xchar *
- Xmode_map(mode,mode_str)
- Xunsigned short mode;
- X{
- Xregister unsigned ftype = mode & S_IFMT;
- Xstatic char result[12];
- Xregister char *rtn = result;
- X
- X /* drwxrwxrwx */
- X /* 0123456789 */
- X strcpy(rtn,"----------");
- X
- X switch(ftype)
- X {
- X case S_IFIFO: *rtn = 'p'; break; /* FIFO (named pipe) */
- X case S_IFDIR: *rtn = 'd'; break; /* directory */
- X case S_IFCHR: *rtn = 'c'; break; /* character special */
- X case S_IFBLK: *rtn = 'b'; break; /* block special */
- X case 0:
- X case S_IFREG: *rtn = '-'; break; /* regular */
- X
- X#if defined(BSD)
- X case S_IFLNK: *rtn = 'l'; break; /* symbolic link */
- X case S_IFSOCK: *rtn = 's'; break; /* socket */
- X#endif
- X#if defined (M_XENIX) || defined(M_UNIX)
- X case S_IFNAM: /* name space entry */
- X if(mode & S_INSEM) /* semaphore */
- X {
- X *rtn = 's';
- X break;
- X }
- X if(mode & S_INSHD) /* shared memory */
- X {
- X *rtn = 'm';
- X break;
- X }
- X#endif
- X
- X default: *rtn = '?'; break; /* ??? */
- X }
- X
- X if(mode & 000400) *(rtn + 1) = 'r';
- X if(mode & 000200) *(rtn + 2) = 'w';
- X if(mode & 000100) *(rtn + 3) = 'x';
- X if(mode & 004000) *(rtn + 3) = 's';
- X if(mode & 000040) *(rtn + 4) = 'r';
- X if(mode & 000020) *(rtn + 5) = 'w';
- X if(mode & 000010) *(rtn + 6) = 'x';
- X if(mode & 002000) *(rtn + 6) = 's';
- X if(mode & 000004) *(rtn + 7) = 'r';
- X if(mode & 000002) *(rtn + 8) = 'w';
- X if(mode & 000001) *(rtn + 9) = 'x';
- X if(mode & 001000) *(rtn + 9) = 't';
- X
- X return(rtn);
- X
- X} /* end of mode_map */
- X
- X/*+-----------------------------------------------------------------------
- X char *epoch_secs_to_str(epoch_secs)
- X------------------------------------------------------------------------*/
- Xchar *
- Xepoch_secs_to_str(epoch_secs)
- Xlong epoch_secs;
- X{
- Xstatic char buf[64];
- Xstruct tm *tod;
- Xchar *month_name_list = "JanFebMarAprMayJunJulAugSepOctNovDec";
- X
- X tod = localtime(&epoch_secs);
- X
- X if((now - epoch_secs) > (86400L * 365/2)) /* if older than 6 months */
- X {
- X sprintf(buf,"%02d %-3.3s %04d ",
- X tod->tm_mday,month_name_list + (tod->tm_mon * 3),
- X tod->tm_year + 1900);
- X }
- X else
- X {
- X sprintf(buf,"%02d %-3.3s %02d:%02d",
- X tod->tm_mday,month_name_list + (tod->tm_mon * 3),
- X tod->tm_hour,tod->tm_min);
- X }
- X
- X return(buf);
- X} /* end of epoch_secs_to_str */
- X
- X/*+-------------------------------------------------------------------------
- X report_tarblock(t)
- X--------------------------------------------------------------------------*/
- Xvoid
- Xreport_tarblock(t)
- Xregister TARBLOCK *t;
- X{
- Xlong tmode;
- Xlong tsize;
- Xlong tuid;
- Xlong tgid;
- Xlong tmtime;
- X
- X if(Vsw)
- X {
- X sscanf(t->h.size,"%lo",&tsize);
- X sscanf(t->h.mode,"%lo",&tmode);
- X sscanf(t->h.uid,"%lo",&tuid);
- X sscanf(t->h.gid,"%lo",&tgid);
- X sscanf(t->h.mtime,"%lo",&tmtime);
- X
- X printf("%s ",mode_map((unsigned short)tmode));
- X printf("%4d/%04d ",(unsigned short)tuid,
- X (unsigned short)tgid);
- X printf("%8ld ",tsize);
- X printf("%s ",epoch_secs_to_str(tmtime));
- X }
- X printf("%s ",t->h.name + Asw);
- X
- X} /* end of report_tarblock */
- X
- X/*+-------------------------------------------------------------------------
- X cktar(fpt,t)
- X--------------------------------------------------------------------------*/
- Xvoid
- Xcktar(fpt,t)
- XFILE *fpt;
- Xregister TARBLOCK *t;
- X{
- Xchar tb[TBLOCK]; /* tar file data block */
- Xlong tmode; /* tar file mode (as in st_mode) */
- Xlong tsize; /* tar file version of file size */
- Xlong tuid; /* tar file version of uid */
- Xlong tgid; /* tar file version of gid */
- Xlong tmtime; /* tar file version of last mod time */
- Xchar db[TBLOCK]; /* disk file data block */
- XFILE *fpd = (FILE *)0;
- Xchar *dname; /* ptr to file name with -A (Asw) considerations */
- Xstruct stat dstat; /* disk file stat() result */
- Xint report = 0; /* true if report_tarblock() needed */
- Xint do_compare = 1; /* true if we should continue to compare tape to disk */
- Xint len; /* really a scratch int, often length of read() */
- Xlong blks; /* tape blocks for this file, decremented as we go */
- Xlong fpos = 0; /* file position */
- Xint thiscount; /* TBLOCK or residue (partial block size) */
- Xchar *tbp; /* hack pointer to tape buf for final mismatch calc */
- Xchar *dbp; /* hack pointer to disk buf for final mismatch calc */
- Xchar exceptions[32]; /* accumulator for comparison failures */
- X
- X exceptions[0] = 0;
- X
- X /*
- X * if the tar "file" is a link and -t, say so
- X */
- X if(t->h.linkflag)
- X {
- X if(Tsw)
- X {
- X report_tarblock(t);
- X fputs("link->",stdout);
- X fputs(t->h.linkname,stdout);
- X }
- X return;
- X }
- X
- X#ifdef BSD
- X sscanf(t->h.mode,"%lo",&tmode);
- X if((t->h.mode & S_IFMT) && ((t->h.mode & S_IFMT) != S_IFREG)
- X {
- X if(Tsw)
- X {
- X report_tarblock(t);
- X fputs("not regular file\n",stdout);
- X }
- X return;
- X }
- X#endif
- X
- X /*
- X * get the dope on the tar file for gross level comparison
- X */
- X sscanf(t->h.size,"%lo",&tsize);
- X sscanf(t->h.uid,"%lo",&tuid);
- X sscanf(t->h.gid,"%lo",&tgid);
- X sscanf(t->h.mtime,"%lo",&tmtime);
- X
- X /*
- X * figger out how many data blocks for this file
- X */
- X blks = tsize / TBLOCK;
- X if(tsize - (blks * TBLOCK))
- X blks++;
- X
- X /*
- X * get file name with consideration for a possible -A switch
- X * then, stat() the file; if we cannot stat the file, mark
- X * it in the exceptions string and then do little else
- X * other than space over the tape file
- X */
- X dname = t->h.name + Asw;
- X if(stat(dname,&dstat))
- X {
- X if(errno = EACCES)
- X strcat(exceptions,"A"); /* stat access denied */
- X else
- X strcat(exceptions,"N"); /* non-existent file */
- X report = 1;
- X do_compare = 0;
- X }
- X
- X /*
- X * perform uid, gid and mtime comparisons; even if any
- X * or all of them fail, we'll still do a file data comparison
- X * provided the tape and data files have the same length
- X */
- X if(do_compare && Usw && (dstat.st_uid != (unsigned short)tsize))
- X {
- X strcat(exceptions,"U"); /* uid difference */
- X report = 1;
- X }
- X if(do_compare && Gsw && (dstat.st_gid != (unsigned short)tsize))
- X {
- X strcat(exceptions,"G"); /* gid difference */
- X report = 1;
- X }
- X if(do_compare && Msw && (dstat.st_mtime != tmtime))
- X {
- X strcat(exceptions,"T"); /* time of last modification different */
- X report = 1;
- X }
- X
- X /*
- X * if tape and disk files don't have the same length,
- X * omit data comparison
- X */
- X if(do_compare && (dstat.st_size != tsize))
- X {
- X strcat(exceptions,"S"); /* size difference */
- X report = 1;
- X do_compare = 0;
- X }
- X
- X /*
- X * if we can't open the disk file, data comparison unlikely
- X */
- X if(do_compare && (access(dname,4) || !(fpd = fopen(dname,"r"))))
- X {
- X strcat(exceptions,"R"); /* read access denied */
- X report = 1;
- X do_compare = 0;
- X }
- X
- X /*
- X * tape advance and possible data comparison loop
- X */
- X while(blks)
- X {
- X if((len = fread(tb,1,sizeof(tb),fpt)) != sizeof(tb))
- X {
- X if(len < 0)
- X perror(tar_fname);
- X else
- X fprintf(stderr,"%s: short read expecting data (%d bytes)\n",
- X tar_fname,len);
- X exit(1);
- X }
- X if(do_compare)
- X {
- X thiscount = min(TBLOCK,(int)(tsize - fpos));
- X if((len = fread(db,1,thiscount,fpd)) != thiscount)
- X {
- X if(len < 0)
- X perror(dname);
- X else
- X {
- X fprintf(stderr,
- X "%s: short read expecting %d bytes, got %d\n",
- X dname,thiscount,len);
- X }
- X exit(1);
- X }
- X /*
- X * compare full tape block with full disk block or
- X * valid portion of tape block with the last 1-511 bytes
- X * of a disk file
- X *
- X * first do the (supposedly) fastest compare available
- X * and if the compare fails, plod through slowly
- X * to calculate the proper file position where the
- X * compare failed
- X */
- X if(memcmp(tb,db,thiscount))
- X {
- X len = 0;
- X tbp = tb;
- X dbp = db;
- Xprintf(">>thiscount=%d\n",thiscount);
- Xprintf("*tb=%02x *db=%02x\n",*tbp,*dbp);
- X while(len < thiscount)
- X {
- X if(*tbp != *dbp)
- X break;
- X len++,tbp++,dbp++;
- X }
- X sprintf(tb,"C %ld",fpos + len); /* use tape buf for scratch */
- X strcat(exceptions,tb); /* byte compare failure position */
- X report = 1;
- X do_compare = 0;
- X }
- X } /* end of do_compare==TRUE tape<->disk comparison */
- X fpos += TBLOCK;
- X blks--; /* leaving this at bottom in case we ever want current
- X * block number in the loop
- X */
- X } /* end of while(blks) loop */
- X
- X if(fpd)
- X fclose(fpd);
- X
- X if(Tsw || report)
- X {
- X report_tarblock(t);
- X if(report)
- X fputs(exceptions,stdout);
- X fputs("\n",stdout);
- X }
- X
- X} /* end of cktar */
- X
- X/*+-------------------------------------------------------------------------
- X getopt(argc,argv,opts) - Thank you, Henry!
- X--------------------------------------------------------------------------*/
- X#ifdef BSD
- X#define strchr index /* for BSD */
- Xextern int strcmp();
- Xextern char *strchr();
- X
- X#define NULL (char *)0
- X#define EOF (-1)
- X#define ERR(s,c) if(opterr)\
- X{ \
- X extern int strlen(),write(); \
- X char errbuf[2]; \
- X errbuf[0] = c; errbuf[1] = '\n'; \
- X (void) write(2,argv[0],(unsigned)strlen(argv[0])); \
- X (void) write(2,s,(unsigned)strlen(s)); \
- X (void) write(2,errbuf,2); \
- X}
- Xint opterr = 1;
- Xint optind = 1;
- Xint optopt;
- Xchar *optarg;
- Xint
- Xgetopt(argc,argv,opts)
- Xint argc;
- Xchar **argv,*opts;
- X{
- X static int sp = 1;
- X register int c;
- X register char *cp;
- X
- X if(sp == 1)
- X {
- X if(optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
- X return(EOF);
- X else if(!strcmp(argv[optind],"--"))
- X {
- X optind++;
- X return(EOF);
- X }
- X }
- X optopt = c = argv[optind][sp];
- X if(c == ':' || (cp=strchr(opts,c)) == NULL)
- X {
- X ERR(": unknown option, -",c);
- X if(argv[optind][++sp] == '\0')
- X {
- X optind++;
- X sp = 1;
- X }
- X return('?');
- X }
- X if(*++cp == ':')
- X {
- X if(argv[optind][sp+1] != '\0')
- X optarg = &argv[optind++][sp+1];
- X else if(++optind >= argc)
- X {
- X ERR(": argument missing for -",c);
- X sp = 1;
- X return('?');
- X }
- X else
- X optarg = argv[optind++];
- X sp = 1;
- X }
- X else
- X {
- X if(argv[optind][++sp] == '\0')
- X {
- X sp = 1;
- X optind++;
- X }
- X optarg = NULL;
- X }
- X return(c);
- X} /* end of getopt */
- X#endif /* BSD */
- X
- X/*+-------------------------------------------------------------------------
- X main(argc,argv)
- X--------------------------------------------------------------------------*/
- Xmain(argc,argv)
- Xint argc;
- Xchar **argv;
- X{
- Xint iargv;
- Xint itmp;
- Xint errflg = 0;
- Xint rdlen;
- XTARBLOCK tblk;
- Xextern char *optarg;
- Xextern int optind;
- X
- X if(argc == 1)
- X usage();
- X
- X time(&now);
- X
- X fptar = stdin;
- X setvbuf(fptar,_tarbuf,_IOFBF,sizeof(_tarbuf));
- X
- X while((itmp = getopt(argc,argv,"tvAUGMf:")) != -1)
- X {
- X switch(itmp)
- X {
- X case 't':
- X Tsw = 1;
- X break;
- X case 'v':
- X Vsw = 1;
- X break;
- X case 'A':
- X Asw = 1;
- X break;
- X case 'U':
- X Usw = 1;
- X break;
- X case 'G':
- X Gsw = 1;
- X break;
- X case 'M':
- X Msw = 1;
- X break;
- X case 'f':
- X tar_fname = optarg;
- X if(fptar = fopen(tar_fname,"r"))
- X setvbuf(fptar,_tarbuf,_IOFBF,sizeof(_tarbuf));
- X break;
- X case '?':
- X errflg++;
- X }
- X }
- X
- X if(!fptar)
- X {
- X perror((tar_fname && *tar_fname) ? tar_fname : "(null)");
- X exit(1);
- X }
- X
- X if(errflg)
- X usage();
- X
- X while((rdlen = fread((char *)&tblk,1,sizeof(tblk),fptar)) == sizeof(tblk))
- X {
- X if(!tblk.h.name[0])
- X {
- X rdlen = 0;
- X break;
- X }
- X cktar(fptar,&tblk);
- X }
- X
- X if(rdlen)
- X {
- X if(rdlen < 0)
- X perror(tar_fname);
- X else
- X {
- X fprintf(stderr,"%s: short read expecting header (%d bytes)\n",
- X tar_fname,rdlen);
- X }
- X }
- X
- X exit(0);
- X
- X} /* end of main */
- X
- X/* vi: set tabstop=4 shiftwidth=4: */
- X/* end of cktar.c */
- SHAR_EOF
- chmod 0644 cktar.c ||
- echo 'restore of cktar.c failed'
- Wc_c="`wc -c < 'cktar.c'`"
- test 14451 -eq "$Wc_c" ||
- echo 'cktar.c: original size 14451, current size' "$Wc_c"
- fi
- exit 0
-
- ----------------------------------------------------------------------------
- Warren Tucker emory!n4hgf!wht or wht@n4hgf.Mt-Park.GA.US
- "I was 35 years old before I knew a pie was meant to be eaten." - Moe Howard
-