File:  [MW Coherent from dump] / coherent / b / etc / fsck / phase1.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:35 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 *	phase 1 of fsck - Check Blocks and Sizes
 */

#include "fsck.h"

char	databuf[BSIZE];		/* buffer for blocks */

int	clrflg;			/* indicates when to clear an inode */
int	dupflag;		/* indicates whether there are any dups */

int	numbad;			/* number of bad blocks in the inode   */
int	numdup;			/* number of duplicate blocks in inode */
long	numblks;		/* number of data blks for size check */
long	sparsecnt;		/* count for sparse blocks for size check */

/*  The following is a table of the number of direct blocks pointed at by the
 *  four types of blocks direct, ..., triple-indirect, to help count sparse
 *  blocks.
 */

daddr_t	blockcnt[] = {1, (daddr_t)NBN, (daddr_t)NBN*NBN, (daddr_t)NBN*NBN*NBN};

phase1()
{
	if (!qflag)
		printf("Phase 1 : Check Blocks and Sizes\n");
	dupflag = FALSE;
	inodescan();
	if (dupflag)
		phase1b();	
}

inodescan()
{
	register daddr_t bn;
	register struct dinode *dip;
	register ino_t	ino;
	int i;

	ino = 1;

	for (bn=INODEI; bn<isize; bn++) {
		if (testblock(bn)) {		/* block is bad via inode 1 */
			ino += INOPB;
			continue;
		}
		bread(bn, databuf);
		clrflg = FALSE;
		dip = (struct dinode *) databuf;
		for (i=0; i<INOPB; i++) {
			candino(dip);
			if (inuse(dip) == TRUE) {
				if (!fflag) 
					checkmode(dip, ino);
				if ( checkblks(dip, ino) != STOP ) 
					if ( qflag == FALSE )
						checksize(dip, ino);
			}
			candino(dip);
			ino++;
			dip++;
		}
		if (clrflg)
			bwrite(bn, databuf);
	}
}

/*
 *  	Determine if the given inode is in use.
 */

inuse(dip)
register struct dinode *dip;
{
#ifdef NOT_ALL_ZERO_INODE

	if ( (dip->di_mode != 0) || (dip->di_nlink != 0) )
		return(TRUE);
	else
		return(FALSE);
#endif
#ifdef ALL_ZERO_INODE

	register char *ptr;
	register struct dinode *next;

	ptr = (char *) dip;
	next = dip + 1;
	while (ptr < next)
		if (*ptr++ != 0)
			return(TRUE);

	return(FALSE);
#endif
}

/*
 *	Check the mode of the given inode
 */

checkmode(dip, ino)
register struct dinode *dip;
register ino_t	ino;
{
	register unsigned short	mode;

	mode = dip->di_mode & IFMT;

	switch (mode) {
	case IFREG:
		setflags(ino, IREG);
		return;
	case IFDIR:
		setflags(ino, IDIR);
		return;
	case IFCHR:
		setflags(ino, ICHR);
		return;
	case IFBLK:
		setflags(ino, IBLK);
		return;
	case IFPIPE:
		setflags(ino, IPIPE);
		return;
	default:
		setflags(ino, UNKNOWN);
		break;
	}

	switch ( query("Unknown File Type i-number = %u (Clear)", ino) ){
	case NO:
		return;
	case YES:
		zeroinode(dip);
		setflags(ino, UNALLOC);
		clrflg = TRUE;
		break;
	}
}

/*
 *	Zero the given inode
 */

zeroinode(dip)
struct dinode *dip;
{
	register char *ptr;
	register struct dinode *next;

	lostsize += dip->di_size;
	next = dip+1;
	ptr = (char *) dip;

	while (ptr < next)
		*ptr++ = 0;

}

/*
 *	Check the blocks associated with the given inode to determine
 *	if any are bad or duplicate
 */

checkblks(dip, ino)
struct dinode *dip;
ino_t	ino;
{
	daddr_t	addrs[NADDR];
	register daddr_t bn;
	register int i, lev, naddr;
	register int mode;

	mode = dip->di_mode & IFMT;

	if ( (mode == IFREG) || (mode == IFDIR) )
		l3tol(addrs, dip->di_addr, naddr=NADDR);
	else if ( mode == IFPIPE )
		l3tol(addrs, dip->di_addp, naddr=ND);
	else
		return(STOP);

	numbad = 			/* number of bad blocks so far */
	numdup = 			/* num dup blocks so far THIS INODE */
	numblks =			/* num used data blocks for size chk */
	sparsecnt = 0;			/* count of missed data blocks	*/

	for(i=0; i<naddr; i++)
		for (lev=0; lev<4; lev++) 
			if (i < offsets[lev]) {
				if ( (bn=addrs[i]) != 0 ) {
					if (doblocks(bn, ino, lev) == STOP)
						return(STOP);
				} else
					sparsecnt += blockcnt[lev];
				break;
			}
	return(OK);
}

/*
 *	Checks recursively the blocks pointed at via
 *	the inode list of blocks.  'bn' is the block number,
 *	'ino' is the inode referencing it, and 'lev' is the
 *	level 0 == direct ... 3 = triple-indirect
 */

doblocks(bn, ino, lev)
register daddr_t bn;
ino_t	ino;
int	lev;
{
	char buf[BSIZE];
	register daddr_t *bnptr;
	register char *end;
	register int flag;

	if (lev-- == 0)	{		/* we have a direct block */
		numblks += sparsecnt + 1;
		sparsecnt = 0;
		return(dodirect(bn, ino));
	} else {
		end = &buf[BSIZE];
		if ( (flag=dodirect(bn, ino)) == OK ) {
			bread(bn, buf);
			bnptr = (long *) buf;
			while ( bnptr < end ) {
				bn = *bnptr++;
				candaddr(bn);
				if ( bn == 0 ) {
					sparsecnt += blockcnt[lev];
					continue;
				}
				if ( doblocks(bn, ino, lev) == STOP )
					return(STOP);
			}
			return(OK);
		} else 
			return(flag);
	}
}
			
/*
 *	Check the given block to determine if it is bad
 * 	or if it is a duplicate.  'ino' is the inode referencing it
 */

dodirect(bn, ino)
register daddr_t bn;
register ino_t ino;
{
	register int flag;
	
	if ( (flag=checkbad(bn, ino)) == OK ) 
		return( checkdup(bn, ino) );
	else
		return(flag);
}

/*
 *	Check the given block number for being bad.
 */

checkbad(bn, ino)
register daddr_t bn;
ino_t	ino;
{
	if ( (bn>=isize) && (bn<fsize) )
		return(OK);

	else if ( (bn<isize) && (bn>=INODEI) && (ino == 1) ) {
							/* bad block is in  */
		totfree++;				/* the inode blocks */
		return(OK);
	}
		
	if (!fflag)
		orflags(ino, IBAD_IDUP);

	printf("Bad block %lu, i-number = %u\n", bn, ino);

	if (numbad++ < MAXBADOK)
		return(BAD_DUP);

	switch ( query("Excessive Bad Blocks i-number = %u (Continue)", ino) ){
	case NO:
		abort();
	case YES:
		return(STOP);
	}
}


/*
 *	Check the given block number for duplicate reference.
 */

checkdup(bn, ino)
register daddr_t bn;
ino_t	ino;
{
	if ( !testblock(bn) ) {
		markblock(bn);
		totfree--;
		return(OK);
	}

	dupflag = TRUE;
	if (!fflag)
		orflags(ino, IBAD_IDUP);
	printf("Dup Block %lu, i-number = %u\n", bn, ino);

	if (totdups < DUPTBLSIZE) 
		dupblck[totdups++] = bn;
	else {
		switch ( query("DUP Table Overflow (Continue)") ) {
		case NO:
			abort();
		case YES:
			return(BAD_DUP);
		}
	}

	if (numdup++ < MAXDUPOK)
		return(BAD_DUP);

	switch ( query("Excessive Dup Blocks i-number = %u (Continue)", ino) ) {
	case NO:
		abort();
	case YES:
		return(STOP);
	}
}

/*
 *	Check For Possible File Size Error 
 */

checksize(dip, ino)
register struct dinode *dip;
ino_t	ino;
{
	register int mode;
	register fsize_t size;

	mode = dip->di_mode & IFMT;
	size = dip->di_size;
	
	if ( mode == IFREG )
		filesize(ino, size);
	else if ( mode == IFDIR )
		dirsize(dip, ino, size);
	else if ( mode == IFPIPE )
		pipesize(dip, ino, size);
}

dirsize(dip, ino, size)
struct dinode *dip;
ino_t ino;
register fsize_t size;
{
	if ( size <= 0 ) {
		switch ( query("\
Bad Directory Size, size = %D, i-number = %u (Clear i-node)", size, ino) ) {
		case NO:
			break;
		case YES:
			zeroinode(dip);
			setflags(ino, UNALLOC);
			clrflg = TRUE;
			return;
		}
	}

	if ( size < (2*DSIZE) )
		printf("Directory Size too small i-number = %u\n", ino);

	if ( size % sizeof(struct direct) != 0 )
		printf("Directory Misaligned i-number = %u\n", ino);

	if (sizerr(size))
		printf("Possible Directory Size Error i-number = %u\n", ino);
}

filesize(ino, size)
ino_t ino;
register fsize_t size;
{
	if (sizerr(size))
		printf("Possible File Size Error i-number = %u\n", ino);
}

pipesize(dip, ino, size)
struct dinode *dip;
ino_t ino;
register fsize_t size;
{
	if (sizerr(size))
		printf("Possible PIPE Size Error i-number = %u\n", ino);
	return;
}

sizerr(size)
register fsize_t size;
{
	register fsize_t calc;

	calc = (unsigned long)numblks*BSIZE;
	if ( (size > calc) || ( calc >= (size+BSIZE) ) ) 
		return(TRUE);
	else
		return(FALSE);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.