Home | History | Annotate | Line # | Download | only in fsck_ext2fs
pass1.c revision 1.18.2.1
      1  1.18.2.1       jym /*	$NetBSD: pass1.c,v 1.18.2.1 2009/05/13 19:19:01 jym Exp $	*/
      2       1.1    bouyer 
      3       1.1    bouyer /*
      4       1.1    bouyer  * Copyright (c) 1980, 1986, 1993
      5       1.1    bouyer  *	The Regents of the University of California.  All rights reserved.
      6       1.1    bouyer  *
      7       1.1    bouyer  * Redistribution and use in source and binary forms, with or without
      8       1.1    bouyer  * modification, are permitted provided that the following conditions
      9       1.1    bouyer  * are met:
     10       1.1    bouyer  * 1. Redistributions of source code must retain the above copyright
     11       1.1    bouyer  *    notice, this list of conditions and the following disclaimer.
     12       1.1    bouyer  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1    bouyer  *    notice, this list of conditions and the following disclaimer in the
     14       1.1    bouyer  *    documentation and/or other materials provided with the distribution.
     15      1.10       agc  * 3. Neither the name of the University nor the names of its contributors
     16      1.10       agc  *    may be used to endorse or promote products derived from this software
     17      1.10       agc  *    without specific prior written permission.
     18      1.10       agc  *
     19      1.10       agc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20      1.10       agc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21      1.10       agc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22      1.10       agc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23      1.10       agc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24      1.10       agc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25      1.10       agc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26      1.10       agc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27      1.10       agc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28      1.10       agc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29      1.10       agc  * SUCH DAMAGE.
     30      1.10       agc  */
     31      1.10       agc 
     32      1.10       agc /*
     33      1.10       agc  * Copyright (c) 1997 Manuel Bouyer.
     34      1.10       agc  *
     35      1.10       agc  * Redistribution and use in source and binary forms, with or without
     36      1.10       agc  * modification, are permitted provided that the following conditions
     37      1.10       agc  * are met:
     38      1.10       agc  * 1. Redistributions of source code must retain the above copyright
     39      1.10       agc  *    notice, this list of conditions and the following disclaimer.
     40      1.10       agc  * 2. Redistributions in binary form must reproduce the above copyright
     41      1.10       agc  *    notice, this list of conditions and the following disclaimer in the
     42      1.10       agc  *    documentation and/or other materials provided with the distribution.
     43       1.1    bouyer  * 3. All advertising materials mentioning features or use of this software
     44       1.1    bouyer  *    must display the following acknowledgement:
     45      1.11    bouyer  *	This product includes software developed by Manuel Bouyer.
     46      1.11    bouyer  * 4. The name of the author may not be used to endorse or promote products
     47      1.11    bouyer  *    derived from this software without specific prior written permission.
     48       1.1    bouyer  *
     49      1.12    bouyer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     50      1.12    bouyer  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     51      1.12    bouyer  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     52      1.12    bouyer  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     53      1.12    bouyer  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     54      1.12    bouyer  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     55      1.12    bouyer  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     56      1.12    bouyer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     57      1.12    bouyer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     58      1.12    bouyer  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     59       1.1    bouyer  */
     60       1.1    bouyer 
     61       1.3     lukem #include <sys/cdefs.h>
     62       1.1    bouyer #ifndef lint
     63       1.1    bouyer #if 0
     64       1.1    bouyer static char sccsid[] = "@(#)pass1.c	8.1 (Berkeley) 6/5/93";
     65       1.1    bouyer #else
     66  1.18.2.1       jym __RCSID("$NetBSD: pass1.c,v 1.18.2.1 2009/05/13 19:19:01 jym Exp $");
     67       1.1    bouyer #endif
     68       1.1    bouyer #endif /* not lint */
     69       1.1    bouyer 
     70       1.1    bouyer #include <sys/param.h>
     71       1.1    bouyer #include <sys/time.h>
     72       1.1    bouyer #include <ufs/ext2fs/ext2fs_dinode.h>
     73       1.1    bouyer #include <ufs/ext2fs/ext2fs_dir.h>
     74       1.1    bouyer #include <ufs/ext2fs/ext2fs.h>
     75       1.1    bouyer 
     76       1.1    bouyer #include <ufs/ufs/dinode.h> /* for IFMT & friends */
     77       1.1    bouyer 
     78       1.1    bouyer #include <stdio.h>
     79       1.1    bouyer #include <stdlib.h>
     80       1.1    bouyer #include <string.h>
     81       1.5    kleink #include <time.h>
     82       1.1    bouyer 
     83       1.1    bouyer #include "fsck.h"
     84       1.1    bouyer #include "extern.h"
     85       1.1    bouyer #include "fsutil.h"
     86      1.17     lukem #include "exitvalues.h"
     87       1.1    bouyer 
     88       1.1    bouyer static daddr_t badblk;
     89       1.1    bouyer static daddr_t dupblk;
     90      1.13   xtraeme static void checkinode(ino_t, struct inodesc *);
     91       1.1    bouyer 
     92       1.1    bouyer void
     93      1.13   xtraeme pass1(void)
     94       1.1    bouyer {
     95       1.1    bouyer 	ino_t inumber;
     96       1.8    bouyer 	int c, i;
     97  1.18.2.1       jym 	size_t j;
     98       1.8    bouyer 	daddr_t dbase;
     99       1.1    bouyer 	struct inodesc idesc;
    100       1.1    bouyer 
    101       1.1    bouyer 	/*
    102       1.1    bouyer 	 * Set file system reserved blocks in used block map.
    103       1.1    bouyer 	 */
    104       1.1    bouyer 	for (c = 0; c < sblock.e2fs_ncg; c++) {
    105       1.8    bouyer 		dbase = c * sblock.e2fs.e2fs_bpg +
    106       1.8    bouyer 		    sblock.e2fs.e2fs_first_dblock;
    107       1.8    bouyer 		/* Mark the blocks used for the inode table */
    108       1.9    bouyer 		if (fs2h32(sblock.e2fs_gd[c].ext2bgd_i_tables) >= dbase) {
    109       1.8    bouyer 			for (i = 0; i < sblock.e2fs_itpg; i++)
    110       1.9    bouyer 				setbmap(
    111       1.9    bouyer 				    fs2h32(sblock.e2fs_gd[c].ext2bgd_i_tables)
    112       1.9    bouyer 				    + i);
    113       1.8    bouyer 		}
    114       1.8    bouyer 		/* Mark the blocks used for the block bitmap */
    115       1.9    bouyer 		if (fs2h32(sblock.e2fs_gd[c].ext2bgd_b_bitmap) >= dbase)
    116       1.9    bouyer 			setbmap(fs2h32(sblock.e2fs_gd[c].ext2bgd_b_bitmap));
    117       1.8    bouyer 		/* Mark the blocks used for the inode bitmap */
    118       1.9    bouyer 		if (fs2h32(sblock.e2fs_gd[c].ext2bgd_i_bitmap) >= dbase)
    119       1.9    bouyer 			setbmap(fs2h32(sblock.e2fs_gd[c].ext2bgd_i_bitmap));
    120       1.8    bouyer 
    121       1.8    bouyer 		if (sblock.e2fs.e2fs_rev == E2FS_REV0 ||
    122       1.8    bouyer 		    (sblock.e2fs.e2fs_features_rocompat &
    123       1.8    bouyer 			EXT2F_ROCOMPAT_SPARSESUPER) == 0 ||
    124       1.8    bouyer 		    cg_has_sb(c)) {
    125       1.8    bouyer 			/* Mark copuy of SB and descriptors */
    126       1.8    bouyer 			setbmap(dbase);
    127       1.8    bouyer 			for (i = 1; i <= sblock.e2fs_ngdb; i++)
    128       1.8    bouyer 				setbmap(dbase+i);
    129       1.8    bouyer 		}
    130       1.1    bouyer 
    131       1.8    bouyer 
    132       1.8    bouyer 		if (c == 0) {
    133       1.8    bouyer 			for(i = 0; i < dbase; i++)
    134       1.8    bouyer 				setbmap(i);
    135       1.8    bouyer 		}
    136       1.1    bouyer 	}
    137       1.1    bouyer 
    138       1.1    bouyer 	/*
    139       1.1    bouyer 	 * Find all allocated blocks.
    140       1.1    bouyer 	 */
    141       1.1    bouyer 	memset(&idesc, 0, sizeof(struct inodesc));
    142       1.1    bouyer 	idesc.id_type = ADDR;
    143       1.1    bouyer 	idesc.id_func = pass1check;
    144       1.1    bouyer 	inumber = 1;
    145       1.1    bouyer 	n_files = n_blks = 0;
    146       1.1    bouyer 	resetinodebuf();
    147       1.1    bouyer 	for (c = 0; c < sblock.e2fs_ncg; c++) {
    148  1.18.2.1       jym 		for (j = 0;
    149  1.18.2.1       jym 			j < sblock.e2fs.e2fs_ipg && inumber <= sblock.e2fs.e2fs_icount;
    150  1.18.2.1       jym 			j++, inumber++) {
    151       1.1    bouyer 			if (inumber < EXT2_ROOTINO) /* XXX */
    152       1.1    bouyer 				continue;
    153       1.1    bouyer 			checkinode(inumber, &idesc);
    154       1.1    bouyer 		}
    155       1.1    bouyer 	}
    156       1.1    bouyer 	freeinodebuf();
    157       1.1    bouyer }
    158       1.1    bouyer 
    159       1.1    bouyer static void
    160      1.13   xtraeme checkinode(ino_t inumber, struct inodesc *idesc)
    161       1.1    bouyer {
    162       1.3     lukem 	struct ext2fs_dinode *dp;
    163       1.1    bouyer 	struct zlncnt *zlnp;
    164       1.1    bouyer 	int ndb, j;
    165       1.1    bouyer 	mode_t mode;
    166       1.1    bouyer 
    167       1.1    bouyer 	dp = getnextinode(inumber);
    168      1.16   tsutsui 	if (inumber < EXT2_FIRSTINO &&
    169      1.16   tsutsui 	    inumber != EXT2_ROOTINO &&
    170      1.16   tsutsui 	    !(inumber == EXT2_RESIZEINO &&
    171      1.16   tsutsui 	      (sblock.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE) != 0))
    172       1.1    bouyer 		return;
    173       1.1    bouyer 
    174       1.4    bouyer 	mode = fs2h16(dp->e2di_mode) & IFMT;
    175       1.1    bouyer 	if (mode == 0 || (dp->e2di_dtime != 0 && dp->e2di_nlink == 0)) {
    176       1.1    bouyer 		if (mode == 0 && (
    177      1.14        ws 		    memcmp(dp->e2di_blocks, zino.e2di_blocks,
    178      1.14        ws 		    (NDADDR + NIADDR) * sizeof(u_int32_t)) ||
    179      1.14        ws 		    dp->e2di_mode || inosize(dp))) {
    180      1.15  christos 			pfatal("PARTIALLY ALLOCATED INODE I=%llu",
    181      1.15  christos 			    (unsigned long long)inumber);
    182       1.1    bouyer 			if (reply("CLEAR") == 1) {
    183       1.1    bouyer 				dp = ginode(inumber);
    184       1.1    bouyer 				clearinode(dp);
    185       1.1    bouyer 				inodirty();
    186       1.1    bouyer 			}
    187       1.1    bouyer 		}
    188       1.1    bouyer #ifdef notyet /* it seems that dtime == 0 is valid for a unallocated inode */
    189       1.1    bouyer 		if (dp->e2di_dtime == 0) {
    190      1.15  christos 			pwarn("DELETED INODE I=%llu HAS A NULL DTIME",
    191      1.15  christos 			    (unsigned long long)inumber);
    192       1.1    bouyer 			if (preen) {
    193       1.1    bouyer 				printf(" (CORRECTED)\n");
    194       1.1    bouyer 			}
    195       1.1    bouyer 			if (preen || reply("CORRECT")) {
    196       1.1    bouyer 				time_t t;
    197       1.1    bouyer 				time(&t);
    198       1.4    bouyer 				dp->e2di_dtime = h2fs32(t);
    199       1.1    bouyer 				dp = ginode(inumber);
    200       1.1    bouyer 				inodirty();
    201       1.1    bouyer 			}
    202       1.1    bouyer 		}
    203       1.1    bouyer #endif
    204       1.1    bouyer 		statemap[inumber] = USTATE;
    205       1.1    bouyer 		return;
    206       1.1    bouyer 	}
    207       1.1    bouyer 	lastino = inumber;
    208       1.1    bouyer 	if (dp->e2di_dtime != 0) {
    209       1.4    bouyer 		time_t t = fs2h32(dp->e2di_dtime);
    210       1.1    bouyer 		char *p = ctime(&t);
    211      1.15  christos 		pwarn("INODE I=%llu HAS DTIME=%12.12s %4.4s",
    212      1.15  christos 		    (unsigned long long)inumber, &p[4], &p[20]);
    213       1.1    bouyer 		if (preen) {
    214       1.1    bouyer 			printf(" (CORRECTED)\n");
    215       1.1    bouyer 		}
    216       1.1    bouyer 		if (preen || reply("CORRECT")) {
    217       1.1    bouyer 			dp = ginode(inumber);
    218       1.1    bouyer 			dp->e2di_dtime = 0;
    219       1.1    bouyer 			inodirty();
    220       1.1    bouyer 		}
    221       1.1    bouyer 	}
    222      1.14        ws 	if (inosize(dp) + sblock.e2fs_bsize - 1 < inosize(dp)) {
    223       1.1    bouyer 		if (debug)
    224      1.14        ws 			printf("bad size %llu:", (unsigned long long)inosize(dp));
    225       1.1    bouyer 		goto unknown;
    226       1.1    bouyer 	}
    227       1.1    bouyer 	if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
    228       1.1    bouyer 		dp = ginode(inumber);
    229       1.4    bouyer 		dp->e2di_mode = h2fs16(IFREG|0600);
    230      1.14        ws 		inossize(dp, sblock.e2fs_bsize);
    231       1.1    bouyer 		inodirty();
    232       1.1    bouyer 	}
    233      1.14        ws 	ndb = howmany(inosize(dp), sblock.e2fs_bsize);
    234       1.1    bouyer 	if (ndb < 0) {
    235       1.1    bouyer 		if (debug)
    236      1.14        ws 			printf("bad size %llu ndb %d:",
    237      1.14        ws 			    (unsigned long long)inosize(dp), ndb);
    238       1.1    bouyer 		goto unknown;
    239       1.1    bouyer 	}
    240       1.1    bouyer 	if (mode == IFBLK || mode == IFCHR)
    241       1.1    bouyer 		ndb++;
    242       1.1    bouyer 	if (mode == IFLNK) {
    243       1.1    bouyer 		/*
    244       1.1    bouyer 		 * Fake ndb value so direct/indirect block checks below
    245       1.1    bouyer 		 * will detect any garbage after symlink string.
    246       1.1    bouyer 		 */
    247      1.14        ws 		if (inosize(dp) < EXT2_MAXSYMLINKLEN ||
    248       1.1    bouyer 		    (EXT2_MAXSYMLINKLEN == 0 && dp->e2di_blocks == 0)) {
    249      1.14        ws 			ndb = howmany(inosize(dp), sizeof(u_int32_t));
    250       1.1    bouyer 			if (ndb > NDADDR) {
    251       1.1    bouyer 				j = ndb - NDADDR;
    252       1.1    bouyer 				for (ndb = 1; j > 1; j--)
    253       1.1    bouyer 					ndb *= NINDIR(&sblock);
    254       1.1    bouyer 				ndb += NDADDR;
    255       1.1    bouyer 			}
    256       1.1    bouyer 		}
    257       1.1    bouyer 	}
    258       1.6    bouyer 	/* Linux puts things in blocks for FIFO, so skip this check */
    259       1.6    bouyer 	if (mode != IFIFO) {
    260       1.6    bouyer 		for (j = ndb; j < NDADDR; j++)
    261       1.6    bouyer 			if (dp->e2di_blocks[j] != 0) {
    262       1.6    bouyer 				if (debug)
    263       1.6    bouyer 					printf("bad direct addr: %d\n",
    264       1.6    bouyer 					    fs2h32(dp->e2di_blocks[j]));
    265       1.6    bouyer 				goto unknown;
    266       1.6    bouyer 			}
    267       1.6    bouyer 		for (j = 0, ndb -= NDADDR; ndb > 0; j++)
    268       1.6    bouyer 			ndb /= NINDIR(&sblock);
    269       1.6    bouyer 		for (; j < NIADDR; j++) {
    270       1.6    bouyer 			if (dp->e2di_blocks[j+NDADDR] != 0) {
    271       1.6    bouyer 				if (debug)
    272       1.6    bouyer 					printf("bad indirect addr: %d\n",
    273       1.6    bouyer 					    fs2h32(dp->e2di_blocks[j+NDADDR]));
    274       1.6    bouyer 				goto unknown;
    275       1.6    bouyer 			}
    276       1.1    bouyer 		}
    277       1.6    bouyer 	}
    278       1.1    bouyer 	if (ftypeok(dp) == 0)
    279       1.1    bouyer 		goto unknown;
    280      1.16   tsutsui 	if (inumber >= EXT2_FIRSTINO || inumber == EXT2_ROOTINO) {
    281      1.16   tsutsui 		/* Don't count reserved inodes except root */
    282      1.16   tsutsui 		n_files++;
    283      1.16   tsutsui 	}
    284       1.4    bouyer 	lncntp[inumber] = fs2h16(dp->e2di_nlink);
    285       1.4    bouyer 	if (dp->e2di_nlink == 0) {
    286      1.18   tsutsui 		zlnp = malloc(sizeof *zlnp);
    287       1.1    bouyer 		if (zlnp == NULL) {
    288       1.1    bouyer 			pfatal("LINK COUNT TABLE OVERFLOW");
    289       1.1    bouyer 			if (reply("CONTINUE") == 0)
    290      1.17     lukem 				exit(FSCK_EXIT_CHECK_FAILED);
    291       1.1    bouyer 		} else {
    292       1.1    bouyer 			zlnp->zlncnt = inumber;
    293       1.1    bouyer 			zlnp->next = zlnhead;
    294       1.1    bouyer 			zlnhead = zlnp;
    295       1.1    bouyer 		}
    296       1.1    bouyer 	}
    297       1.1    bouyer 	if (mode == IFDIR) {
    298      1.14        ws 		if (inosize(dp) == 0)
    299       1.1    bouyer 			statemap[inumber] = DCLEAR;
    300       1.1    bouyer 		else
    301       1.1    bouyer 			statemap[inumber] = DSTATE;
    302       1.1    bouyer 		cacheino(dp, inumber);
    303       1.1    bouyer 	} else {
    304       1.1    bouyer 		statemap[inumber] = FSTATE;
    305       1.1    bouyer 	}
    306       1.8    bouyer 	typemap[inumber] = E2IFTODT(mode);
    307       1.1    bouyer 	badblk = dupblk = 0;
    308       1.1    bouyer 	idesc->id_number = inumber;
    309       1.1    bouyer 	(void)ckinode(dp, idesc);
    310       1.1    bouyer 	idesc->id_entryno *= btodb(sblock.e2fs_bsize);
    311  1.18.2.1       jym 	if (fs2h32(dp->e2di_nblock) != (uint32_t)idesc->id_entryno) {
    312      1.15  christos 		pwarn("INCORRECT BLOCK COUNT I=%llu (%d should be %d)",
    313      1.15  christos 		    (unsigned long long)inumber, fs2h32(dp->e2di_nblock),
    314      1.15  christos 		    idesc->id_entryno);
    315       1.1    bouyer 		if (preen)
    316       1.1    bouyer 			printf(" (CORRECTED)\n");
    317       1.1    bouyer 		else if (reply("CORRECT") == 0)
    318       1.1    bouyer 			return;
    319       1.1    bouyer 		dp = ginode(inumber);
    320       1.4    bouyer 		dp->e2di_nblock = h2fs32(idesc->id_entryno);
    321       1.1    bouyer 		inodirty();
    322       1.1    bouyer 	}
    323       1.1    bouyer 	return;
    324       1.1    bouyer unknown:
    325      1.15  christos 	pfatal("UNKNOWN FILE TYPE I=%llu", (unsigned long long)inumber);
    326       1.1    bouyer 	statemap[inumber] = FCLEAR;
    327       1.1    bouyer 	if (reply("CLEAR") == 1) {
    328       1.1    bouyer 		statemap[inumber] = USTATE;
    329       1.1    bouyer 		dp = ginode(inumber);
    330       1.1    bouyer 		clearinode(dp);
    331       1.1    bouyer 		inodirty();
    332       1.1    bouyer 	}
    333       1.1    bouyer }
    334       1.1    bouyer 
    335       1.1    bouyer int
    336      1.13   xtraeme pass1check(struct inodesc *idesc)
    337       1.1    bouyer {
    338       1.1    bouyer 	int res = KEEPON;
    339       1.1    bouyer 	int anyout, nfrags;
    340       1.1    bouyer 	daddr_t blkno = idesc->id_blkno;
    341       1.3     lukem 	struct dups *dlp;
    342       1.1    bouyer 	struct dups *new;
    343       1.1    bouyer 
    344       1.1    bouyer 	if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
    345       1.1    bouyer 		blkerror(idesc->id_number, "BAD", blkno);
    346       1.1    bouyer 		if (badblk++ >= MAXBAD) {
    347      1.15  christos 			pwarn("EXCESSIVE BAD BLKS I=%llu",
    348      1.15  christos 			    (unsigned long long)idesc->id_number);
    349       1.1    bouyer 			if (preen)
    350       1.1    bouyer 				printf(" (SKIPPING)\n");
    351       1.1    bouyer 			else if (reply("CONTINUE") == 0)
    352      1.17     lukem 				exit(FSCK_EXIT_CHECK_FAILED);
    353       1.1    bouyer 			return (STOP);
    354       1.1    bouyer 		}
    355       1.1    bouyer 	}
    356       1.1    bouyer 	for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
    357       1.1    bouyer 		if (anyout && chkrange(blkno, 1)) {
    358       1.1    bouyer 			res = SKIP;
    359       1.1    bouyer 		} else if (!testbmap(blkno)) {
    360       1.1    bouyer 			n_blks++;
    361       1.1    bouyer 			setbmap(blkno);
    362       1.1    bouyer 		} else {
    363       1.1    bouyer 			blkerror(idesc->id_number, "DUP", blkno);
    364       1.1    bouyer 			if (dupblk++ >= MAXDUP) {
    365      1.15  christos 				pwarn("EXCESSIVE DUP BLKS I=%llu",
    366      1.15  christos 				    (unsigned long long)idesc->id_number);
    367       1.1    bouyer 				if (preen)
    368       1.1    bouyer 					printf(" (SKIPPING)\n");
    369       1.1    bouyer 				else if (reply("CONTINUE") == 0)
    370      1.17     lukem 					exit(FSCK_EXIT_CHECK_FAILED);
    371       1.1    bouyer 				return (STOP);
    372       1.1    bouyer 			}
    373      1.18   tsutsui 			new = malloc(sizeof(struct dups));
    374       1.1    bouyer 			if (new == NULL) {
    375       1.1    bouyer 				pfatal("DUP TABLE OVERFLOW.");
    376       1.1    bouyer 				if (reply("CONTINUE") == 0)
    377      1.17     lukem 					exit(FSCK_EXIT_CHECK_FAILED);
    378       1.1    bouyer 				return (STOP);
    379       1.1    bouyer 			}
    380       1.1    bouyer 			new->dup = blkno;
    381       1.1    bouyer 			if (muldup == 0) {
    382       1.1    bouyer 				duplist = muldup = new;
    383       1.1    bouyer 				new->next = 0;
    384       1.1    bouyer 			} else {
    385       1.1    bouyer 				new->next = muldup->next;
    386       1.1    bouyer 				muldup->next = new;
    387       1.1    bouyer 			}
    388       1.1    bouyer 			for (dlp = duplist; dlp != muldup; dlp = dlp->next)
    389       1.1    bouyer 				if (dlp->dup == blkno)
    390       1.1    bouyer 					break;
    391       1.1    bouyer 			if (dlp == muldup && dlp->dup != blkno)
    392       1.1    bouyer 				muldup = new;
    393       1.1    bouyer 		}
    394       1.1    bouyer 		/*
    395       1.1    bouyer 		 * count the number of blocks found in id_entryno
    396       1.1    bouyer 		 */
    397       1.1    bouyer 		idesc->id_entryno++;
    398       1.1    bouyer 	}
    399       1.1    bouyer 	return (res);
    400       1.1    bouyer }
    401