2.11BSD/src/sbin/dump/dumpdir.c

Compare this file to the similar file:
Show the results in this format:

#include <stdio.h>
#include <sys/param.h>
#include <sys/inode.h>
#include <sys/fs.h>
#include <sys/dir.h>
#include <sys/mtio.h>
#include <protocols/dumprestor.h>
#ifdef NONSEPARATE
#define MAXINO 1000
#else
#define MAXINO 3000
#endif
#define BITS	8
#define MAXXTR	60

#define	MWORD(m,i) (m[(unsigned)(i-1)/MLEN])
#define	MBIT(i)	(1<<((unsigned)(i-1)%MLEN))
#define	BIS(i,w)	(MWORD(w,i) |=  MBIT(i))
#define	BIC(i,w)	(MWORD(w,i) &= ~MBIT(i))
#define	BIT(i,w)	(MWORD(w,i) & MBIT(i))

int	mt;
char	tapename[] = DEFTAPE;
char	*magtape = tapename;

daddr_t	seekpt;
int	ofile;
FILE	*df;
char	dirfile[] = "/tmp/rstXXXXXX";

#define ODIRSIZ 14
struct odirect
	{
	ino_t	d_ino;
	char	d_name[ODIRSIZ];
	};

struct {
	ino_t	t_ino;
	daddr_t	t_seekpt;
} inotab[MAXINO];
int	ipos;

#define ONTAPE	1
#define XTRACTD	2
#define XINUSE	4

short	dumpmap[MSIZ];
short	clrimap[MSIZ];


int bct = NTREC+1;
char tbf[NTREC*DEV_BSIZE];

char prebuf[MAXPATHLEN];

DIR drblock;
u_int prev;

int volno, cvtflag;

main(argc, argv)
char *argv[];
{
	extern char *ctime();

	mktemp(dirfile);
	argv++;
	if (argc>=3 && *argv[0] == 'f')
		magtape = *++argv;
	df = fopen(dirfile, "w");
	if (df == NULL) {
		printf("dumpdir: %s - cannot create directory temporary\n", dirfile);
		exit(1);
	}

	if ((mt = open(magtape, 0)) < 0) {
		printf("%s: cannot open tape\n", magtape);
		exit(1);
	}
	if (readhdr(&spcl) == 0) {
		printf("Tape is not a dump tape\n");
		exit(1);
	}
	printf("Dump   date: %s", ctime(&spcl.c_date));
	printf("Dumped from: %s", ctime(&spcl.c_ddate));
	if (checkvol(&spcl, 1) == 0) {
		printf("Tape is not volume 1 of the dump\n");
		exit(1);
	}
	pass1();  /* This sets the various maps on the way by */
	freopen(dirfile, "r", df);
	strcpy(prebuf, "/");
	printem(prebuf, (ino_t) ROOTINO);
	unlink(dirfile);
	exit(0);
}

/*
 * Read the tape, bulding up a directory structure for extraction
 * by name
 */
pass1()
{
	register i;
	struct dinode *ip;
	int	putdir(), null();
	struct direct nulldir;

	while (gethead(&spcl) == 0) {
		printf("Can't find directory header!\n");
	}
	nulldir.d_ino = 0;
	nulldir.d_namlen = 1;
	strcpy(nulldir.d_name, "/");
	nulldir.d_reclen = DIRSIZ(&nulldir);

	for (;;) {
		if (checktype(&spcl, TS_BITS) == 1) {
			readbits(dumpmap);
			continue;
		}
		if (checktype(&spcl, TS_CLRI) == 1) {
			readbits(clrimap);
			continue;
		}
		if (checktype(&spcl, TS_INODE) == 0) {
finish:
			fflush(df);
			close(mt);
			return;
		}
		ip = &spcl.c_dinode;
		i = ip->di_mode & IFMT;
		if (i != IFDIR) {
			goto finish;
		}
		inotab[ipos].t_ino = spcl.c_inumber;
		inotab[ipos++].t_seekpt = seekpt;
		getfile(spcl.c_inumber, putdir, null, spcl.c_dinode.di_size);
		putent(&nulldir);
		flushent();
	}
}

printem(prefix, inum)
char *prefix;
ino_t	inum;
{
	register struct direct *dp;
	register int i;
	struct direct *rddir();

	for (i = 0; i < MAXINO; i++)
		if (inotab[i].t_ino == inum) {
			goto found;
		}
	printf("PANIC - can't find directory %u\n", inum);
	return;
found:
	fseek(df, inotab[i].t_seekpt, 0);
	drblock.dd_loc = 0;
	for (;;) {
		dp = rddir();
		if (dp == NULL || dp->d_ino == 0)
			return;
		if (search((ino_t)dp->d_ino) && strcmp(dp->d_name, ".") && 
				strcmp(dp->d_name, "..")) {
			int len;
			off_t savpos;
			u_int savloc;

			savpos = ftell(df) - DIRBLKSIZ;
			savloc = drblock.dd_loc;
			len = strlen(prefix);
			strncat(prefix, dp->d_name, sizeof(dp->d_name));
			strcat(prefix, "/");
			printem(prefix, (ino_t)dp->d_ino);
			prefix[len] = '\0';
			fseek(df, savpos, 0);
			fread(drblock.dd_buf, DIRBLKSIZ, 1, df);
			drblock.dd_loc = savloc;
		}
		else
			if (BIT(dp->d_ino, dumpmap))
				printf("%5u	%s%-.14s\n", (ino_t)dp->d_ino, 
					prefix, dp->d_name);
	}
}

dcvt(odp, ndp)
register struct odirect *odp;
register struct direct *ndp;
{

	bzero(ndp, sizeof (struct direct));
	ndp->d_ino = odp->d_ino;
	strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
	ndp->d_namlen = strlen(ndp->d_name);
	ndp->d_reclen = DIRSIZ(ndp);
}

/*
 * Do the file extraction, calling the supplied functions
 * with the blocks
 */
getfile(n, f1, f2, size)
ino_t	n;
int	(*f2)(), (*f1)();
long	size;
{
	register i;
	struct spcl addrblock;
	char buf[DEV_BSIZE];

	addrblock = spcl;
	goto start;
	for (;;) {
		if (gethead(&addrblock) == 0) {
			printf("Missing address (header) block\n");
			goto eloop;
		}
		if (checktype(&addrblock, TS_ADDR) == 0) {
			spcl = addrblock;
			return;
		}
start:
		for (i = 0; i < addrblock.c_count; i++) {
			if (addrblock.c_addr[i]) {
				readtape(buf);
				(*f1)(buf, size > DEV_BSIZE ? (long) DEV_BSIZE : size);
			}
			else {
				bzero(buf, DEV_BSIZE);
				(*f2)(buf, size > DEV_BSIZE ? (long) DEV_BSIZE : size);
			}
			if ((size -= DEV_BSIZE) <= 0) {
eloop:
				while (gethead(&spcl) == 0)
					;
				if (checktype(&spcl, TS_ADDR) == 1)
					goto eloop;
				return;
			}
		}
	}
}

/*
 * Do the tape i\/o, dealling with volume changes
 * etc..
 */
readtape(b)
char *b;
{
	register i;
	struct spcl tmpbuf;

	if (bct >= NTREC) {
		for (i = 0; i < NTREC; i++)
			((struct spcl *)&tbf[i*DEV_BSIZE])->c_magic = 0;
		bct = 0;
		if ((i = read(mt, tbf, NTREC*DEV_BSIZE)) < 0) {
			exit(1);
		}
		if (i == 0) {
			bct = NTREC + 1;
			volno++;
loop:
			bct = NTREC+1;
			close(mt);
			printf("Mount volume %d\n", volno);
			while (getchar() != '\n')
				;
			if ((mt = open(magtape, 0)) == -1) {
				printf("Cannot open tape!\n");
			}
			if (readhdr(&tmpbuf) == 0) {
				printf("Not a dump tape.Try again\n");
				goto loop;
			}
			if (checkvol(&tmpbuf, volno) == 0) {
				printf("Wrong tape. Try again\n");
				goto loop;
			}
			readtape(b);
			return;
		}
	}
	bcopy(&tbf[(bct++*DEV_BSIZE)], b, DEV_BSIZE);
}

putdir(b)
char *b;
{
	register struct direct *dp;
	struct direct cvtbuf;
	struct odirect *odp, *eodp;
	u_int	loc;
	register int i;

	if (cvtflag) {
		eodp = (struct odirect *)&b[DEV_BSIZE];
		for (odp = (struct odirect *)b; odp < eodp; odp++) {
			if (odp->d_ino) {
				dcvt(odp, &cvtbuf);
				putent(&cvtbuf);
			}
		}
	return;
	}

	for (loc = 0; loc < DEV_BSIZE; ) {
		dp = (struct direct *)(b + loc);
		i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
		if (dp->d_reclen == 0 || dp->d_reclen > i) {
			loc += i;
			continue;
		}
		loc += dp->d_reclen;
		if (dp->d_ino)
			putent(dp);
	}
}

putent(dp)
register struct direct *dp;
{

	dp->d_reclen = DIRSIZ(dp);
	if (drblock.dd_loc + dp->d_reclen > DIRBLKSIZ) {
		((struct direct *)(drblock.dd_buf + prev))->d_reclen = 
			DIRBLKSIZ - prev;
		fwrite(drblock.dd_buf, DIRBLKSIZ, 1, df);
		drblock.dd_loc = 0;
	}
	bcopy(dp, drblock.dd_buf + drblock.dd_loc, dp->d_reclen);
	prev = drblock.dd_loc;
	drblock.dd_loc += dp->d_reclen;
}

flushent()
{

	((struct direct *)(drblock.dd_buf + prev))->d_reclen =DIRBLKSIZ - prev;
	fwrite(drblock.dd_buf, DIRBLKSIZ, 1, df);
	prev = drblock.dd_loc = 0;
	seekpt = ftell(df);
}

struct direct *
rddir()
{
register struct direct *dp;

	for (;;) {
		if (drblock.dd_loc == 0) {
			drblock.dd_size = fread(drblock.dd_buf, 1,DIRBLKSIZ,df);
			if (drblock.dd_size <= 0) {
				printf("error reading directory\n");
				return(NULL);
			}
		}
		if (drblock.dd_loc >= drblock.dd_size) {
			drblock.dd_loc = 0;
			continue;
		}
		dp = (struct direct *)(drblock.dd_buf + drblock.dd_loc);
		if (dp->d_reclen == 0 ||
			dp->d_reclen > DIRBLKSIZ + 1 - drblock.dd_loc) {
				printf("corrupted directory: bad reclen %d\n",
					dp->d_reclen);
				return(NULL);
		}
		drblock.dd_loc += dp->d_reclen;
		if (dp->d_ino == 0 && strcmp(dp->d_name, "/"))
			continue;
	return(dp);
	}
}

/*
 * search the directory inode ino
 * looking for entry cp
 */
search(inum)
ino_t	inum;
{
	register low, high, probe;

	low = 0;
	high = ipos-1;

	while (low != high) {
		probe = (high - low + 1)/2 + low;
/*
printf("low = %d, high = %d, probe = %d, ino = %d, inum = %d\n", low, high, probe, inum, inotab[probe].t_ino);
*/
		if (inum >= inotab[probe].t_ino)
			low = probe;
		else
			high = probe - 1;
	}
	return(inum == inotab[low].t_ino);
}

/*
 * read the tape into buf, then return whether or
 * or not it is a header block.
 */
gethead(buf)
struct spcl *buf;
{
	readtape((char *)buf);
	return(ishead(buf));
}

ishead(buf)
register struct spcl *buf;
{
register int ret = 0;

	if (buf->c_magic == OFS_MAGIC) {
		if (cvtflag == 0)
			printf("Convert old direct format to new\n");
		ret = cvtflag = 1;
	}
	else if (buf->c_magic == NFS_MAGIC) {
		if (cvtflag)
			printf("Was converting old direct format, not now\n");
		cvtflag = 0;
		ret = 1;
	}
	if (ret == 0)
		return(ret);
	return(checksum((int *) buf));
}

/*
 * return whether or not the buffer contains a header block
 */
checktype(b, t)
struct	spcl *b;
int	t;
{
	return(b->c_type == t);
}


checksum(b)
int *b;
{
	register i, j;

	j = DEV_BSIZE/sizeof(int);
	i = 0;
	do
		i += *b++;
	while (--j);
	if (i != CHECKSUM) {
		printf("Checksum error %o\n", i);
		return(0);
	}
	return(1);
}

checkvol(b, t)
struct spcl *b;
int t;
{
	if (b->c_volume == t)
		return(1);
	return(0);
}

readhdr(b)
struct	spcl *b;
{
	if (gethead(b) == 0)
		return(0);
	if (checktype(b, TS_TAPE) == 0)
		return(0);
	return(1);
}

/*
 * read a bit mask from the tape into m.
 */
readbits(m)
short	*m;
{
	register i;

	i = spcl.c_count;

	while (i--) {
		readtape((char *) m);
		m += (DEV_BSIZE/(MLEN/BITS));
	}
	while (gethead(&spcl) == 0)
		;
}

null() { ; }