pass1.c revision 176575
18871Srgrimes/* 21558Srgrimes * Copyright (c) 1980, 1986, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 4. Neither the name of the University nor the names of its contributors 141558Srgrimes * may be used to endorse or promote products derived from this software 151558Srgrimes * without specific prior written permission. 161558Srgrimes * 171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271558Srgrimes * SUCH DAMAGE. 281558Srgrimes */ 291558Srgrimes 30114589Sobrien#if 0 311558Srgrimes#ifndef lint 3223675Speterstatic const char sccsid[] = "@(#)pass1.c 8.6 (Berkeley) 4/28/95"; 33114589Sobrien#endif /* not lint */ 3441477Sjulian#endif 35114589Sobrien#include <sys/cdefs.h> 36114589Sobrien__FBSDID("$FreeBSD: head/sbin/fsck_ffs/pass1.c 176575 2008-02-26 03:08:22Z delphij $"); 371558Srgrimes 381558Srgrimes#include <sys/param.h> 3962668Smckusick#include <sys/stat.h> 4074556Smckusick#include <sys/sysctl.h> 4123675Speter 421558Srgrimes#include <ufs/ufs/dinode.h> 431558Srgrimes#include <ufs/ufs/dir.h> 441558Srgrimes#include <ufs/ffs/fs.h> 4523675Speter 4623675Speter#include <err.h> 47103949Smike#include <limits.h> 48101037Smux#include <stdint.h> 491558Srgrimes#include <string.h> 5023675Speter 511558Srgrimes#include "fsck.h" 521558Srgrimes 5398542Smckusickstatic ufs2_daddr_t badblk; 5498542Smckusickstatic ufs2_daddr_t dupblk; 5541474Sjulianstatic ino_t lastino; /* last inode in use */ 561558Srgrimes 5792839Simpstatic void checkinode(ino_t inumber, struct inodesc *); 587585Sbde 597585Sbdevoid 6092839Simppass1(void) 611558Srgrimes{ 6241474Sjulian struct inostat *info; 631558Srgrimes struct inodesc idesc; 6498542Smckusick ino_t inumber, inosused; 6598542Smckusick ufs2_daddr_t i, cgd; 6698542Smckusick u_int8_t *cp; 6798542Smckusick int c; 681558Srgrimes 691558Srgrimes /* 70102231Strhodes * Set file system reserved blocks in used block map. 711558Srgrimes */ 721558Srgrimes for (c = 0; c < sblock.fs_ncg; c++) { 731558Srgrimes cgd = cgdmin(&sblock, c); 741558Srgrimes if (c == 0) { 751558Srgrimes i = cgbase(&sblock, c); 761558Srgrimes } else 771558Srgrimes i = cgsblock(&sblock, c); 781558Srgrimes for (; i < cgd; i++) 791558Srgrimes setbmap(i); 801558Srgrimes } 8169800Stomsoft i = sblock.fs_csaddr; 8269800Stomsoft cgd = i + howmany(sblock.fs_cssize, sblock.fs_fsize); 8369800Stomsoft for (; i < cgd; i++) 8469800Stomsoft setbmap(i); 8569800Stomsoft 861558Srgrimes /* 871558Srgrimes * Find all allocated blocks. 881558Srgrimes */ 8923675Speter memset(&idesc, 0, sizeof(struct inodesc)); 901558Srgrimes idesc.id_func = pass1check; 911558Srgrimes n_files = n_blks = 0; 921558Srgrimes for (c = 0; c < sblock.fs_ncg; c++) { 9341474Sjulian inumber = c * sblock.fs_ipg; 9441474Sjulian setinodebuf(inumber); 9598542Smckusick getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize); 96176575Sdelphij if (sblock.fs_magic == FS_UFS2_MAGIC) { 9798542Smckusick inosused = cgrp.cg_initediblk; 98176575Sdelphij if (inosused > sblock.fs_ipg) 99176575Sdelphij inosused = sblock.fs_ipg; 100176575Sdelphij } else 10198542Smckusick inosused = sblock.fs_ipg; 10270050Siedowse if (got_siginfo) { 10370050Siedowse printf("%s: phase 1: cyl group %d of %d (%d%%)\n", 10470050Siedowse cdevname, c, sblock.fs_ncg, 10570050Siedowse c * 100 / sblock.fs_ncg); 10670050Siedowse got_siginfo = 0; 10770050Siedowse } 108126345Sscottl if (got_sigalarm) { 109126345Sscottl setproctitle("%s p1 %d%%", cdevname, 110126345Sscottl c * 100 / sblock.fs_ncg); 111126345Sscottl got_sigalarm = 0; 112126345Sscottl } 11341474Sjulian /* 11441474Sjulian * If we are using soft updates, then we can trust the 11541474Sjulian * cylinder group inode allocation maps to tell us which 11641474Sjulian * inodes are allocated. We will scan the used inode map 11741474Sjulian * to find the inodes that are really in use, and then 11841474Sjulian * read only those inodes in from disk. 11941474Sjulian */ 12041474Sjulian if (preen && usedsoftdep) { 12141474Sjulian if (!cg_chkmagic(&cgrp)) 12241474Sjulian pfatal("CG %d: BAD MAGIC NUMBER\n", c); 123103949Smike cp = &cg_inosused(&cgrp)[(inosused - 1) / CHAR_BIT]; 124103949Smike for ( ; inosused > 0; inosused -= CHAR_BIT, cp--) { 12541474Sjulian if (*cp == 0) 12641474Sjulian continue; 127103949Smike for (i = 1 << (CHAR_BIT - 1); i > 0; i >>= 1) { 12841474Sjulian if (*cp & i) 12941474Sjulian break; 13041474Sjulian inosused--; 13141474Sjulian } 13241474Sjulian break; 13341474Sjulian } 13441474Sjulian if (inosused < 0) 13541474Sjulian inosused = 0; 13641474Sjulian } 13741474Sjulian /* 13841474Sjulian * Allocate inoinfo structures for the allocated inodes. 13941474Sjulian */ 14041474Sjulian inostathead[c].il_numalloced = inosused; 14141474Sjulian if (inosused == 0) { 14241474Sjulian inostathead[c].il_stat = 0; 14341474Sjulian continue; 14441474Sjulian } 14541474Sjulian info = calloc((unsigned)inosused, sizeof(struct inostat)); 14641474Sjulian if (info == NULL) 147125036Scperciva errx(EEXIT, "cannot alloc %u bytes for inoinfo", 14841474Sjulian (unsigned)(sizeof(struct inostat) * inosused)); 14941474Sjulian inostathead[c].il_stat = info; 15041474Sjulian /* 15141474Sjulian * Scan the allocated inodes. 15241474Sjulian */ 15341474Sjulian for (i = 0; i < inosused; i++, inumber++) { 15441474Sjulian if (inumber < ROOTINO) { 15541474Sjulian (void)getnextinode(inumber); 1561558Srgrimes continue; 15741474Sjulian } 1581558Srgrimes checkinode(inumber, &idesc); 1591558Srgrimes } 16041474Sjulian lastino += 1; 16141474Sjulian if (inosused < sblock.fs_ipg || inumber == lastino) 16241474Sjulian continue; 16341474Sjulian /* 16441474Sjulian * If we were not able to determine in advance which inodes 16541474Sjulian * were in use, then reduce the size of the inoinfo structure 16641474Sjulian * to the size necessary to describe the inodes that we 16741474Sjulian * really found. 16841474Sjulian */ 16998542Smckusick if (lastino < (c * sblock.fs_ipg)) 17041474Sjulian inosused = 0; 17198542Smckusick else 17298542Smckusick inosused = lastino - (c * sblock.fs_ipg); 17341474Sjulian inostathead[c].il_numalloced = inosused; 17441474Sjulian if (inosused == 0) { 17541474Sjulian free(inostathead[c].il_stat); 17641474Sjulian inostathead[c].il_stat = 0; 17741474Sjulian continue; 17841474Sjulian } 17941474Sjulian info = calloc((unsigned)inosused, sizeof(struct inostat)); 18041474Sjulian if (info == NULL) 181125036Scperciva errx(EEXIT, "cannot alloc %u bytes for inoinfo", 18241474Sjulian (unsigned)(sizeof(struct inostat) * inosused)); 18341474Sjulian memmove(info, inostathead[c].il_stat, inosused * sizeof(*info)); 18441474Sjulian free(inostathead[c].il_stat); 18541474Sjulian inostathead[c].il_stat = info; 1861558Srgrimes } 1871558Srgrimes freeinodebuf(); 1881558Srgrimes} 1891558Srgrimes 19023675Speterstatic void 19192839Simpcheckinode(ino_t inumber, struct inodesc *idesc) 1921558Srgrimes{ 19398542Smckusick union dinode *dp; 19498542Smckusick off_t kernmaxfilesize; 19598542Smckusick ufs2_daddr_t ndb; 1961558Srgrimes mode_t mode; 197103885Smckusick int j, ret, offset; 1981558Srgrimes 1991558Srgrimes dp = getnextinode(inumber); 20098542Smckusick mode = DIP(dp, di_mode) & IFMT; 2011558Srgrimes if (mode == 0) { 20298542Smckusick if ((sblock.fs_magic == FS_UFS1_MAGIC && 20398542Smckusick (memcmp(dp->dp1.di_db, ufs1_zino.di_db, 20498542Smckusick NDADDR * sizeof(ufs1_daddr_t)) || 20598542Smckusick memcmp(dp->dp1.di_ib, ufs1_zino.di_ib, 20698542Smckusick NIADDR * sizeof(ufs1_daddr_t)) || 20798542Smckusick dp->dp1.di_mode || dp->dp1.di_size)) || 20898542Smckusick (sblock.fs_magic == FS_UFS2_MAGIC && 20998542Smckusick (memcmp(dp->dp2.di_db, ufs2_zino.di_db, 21098542Smckusick NDADDR * sizeof(ufs2_daddr_t)) || 21198542Smckusick memcmp(dp->dp2.di_ib, ufs2_zino.di_ib, 21298542Smckusick NIADDR * sizeof(ufs2_daddr_t)) || 21398542Smckusick dp->dp2.di_mode || dp->dp2.di_size))) { 21486514Siedowse pfatal("PARTIALLY ALLOCATED INODE I=%lu", 21586514Siedowse (u_long)inumber); 2161558Srgrimes if (reply("CLEAR") == 1) { 2171558Srgrimes dp = ginode(inumber); 2181558Srgrimes clearinode(dp); 2191558Srgrimes inodirty(); 2201558Srgrimes } 2211558Srgrimes } 22241474Sjulian inoinfo(inumber)->ino_state = USTATE; 2231558Srgrimes return; 2241558Srgrimes } 2251558Srgrimes lastino = inumber; 22671884Siedowse /* This should match the file size limit in ffs_mountfs(). */ 22798888Siedowse if (sblock.fs_magic == FS_UFS1_MAGIC) 22898888Siedowse kernmaxfilesize = (off_t)0x40000000 * sblock.fs_bsize - 1; 22998888Siedowse else 23098888Siedowse kernmaxfilesize = sblock.fs_maxfilesize; 23198542Smckusick if (DIP(dp, di_size) > kernmaxfilesize || 23298542Smckusick DIP(dp, di_size) > sblock.fs_maxfilesize || 23398542Smckusick (mode == IFDIR && DIP(dp, di_size) > MAXDIRSIZE)) { 2341558Srgrimes if (debug) 235101037Smux printf("bad size %ju:", (uintmax_t)DIP(dp, di_size)); 2361558Srgrimes goto unknown; 2371558Srgrimes } 2381558Srgrimes if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) { 2391558Srgrimes dp = ginode(inumber); 240134589Sscottl DIP_SET(dp, di_size, sblock.fs_fsize); 241134589Sscottl DIP_SET(dp, di_mode, IFREG|0600); 2421558Srgrimes inodirty(); 2431558Srgrimes } 24463003Smckusick if ((mode == IFBLK || mode == IFCHR || mode == IFIFO || 24598542Smckusick mode == IFSOCK) && DIP(dp, di_size) != 0) { 24663003Smckusick if (debug) 247101037Smux printf("bad special-file size %ju:", 248101037Smux (uintmax_t)DIP(dp, di_size)); 24963003Smckusick goto unknown; 25063003Smckusick } 25198542Smckusick if ((mode == IFBLK || mode == IFCHR) && 25298542Smckusick (dev_t)DIP(dp, di_rdev) == NODEV) { 25372525Stegge if (debug) 25472525Stegge printf("bad special-file rdev NODEV:"); 25572525Stegge goto unknown; 25672525Stegge } 25798542Smckusick ndb = howmany(DIP(dp, di_size), sblock.fs_bsize); 2581558Srgrimes if (ndb < 0) { 2591558Srgrimes if (debug) 260101037Smux printf("bad size %ju ndb %ju:", 261101037Smux (uintmax_t)DIP(dp, di_size), (uintmax_t)ndb); 2621558Srgrimes goto unknown; 2631558Srgrimes } 2641558Srgrimes if (mode == IFBLK || mode == IFCHR) 2651558Srgrimes ndb++; 2661558Srgrimes if (mode == IFLNK) { 2671558Srgrimes /* 2681558Srgrimes * Fake ndb value so direct/indirect block checks below 2691558Srgrimes * will detect any garbage after symlink string. 2701558Srgrimes */ 27198542Smckusick if (DIP(dp, di_size) < (off_t)sblock.fs_maxsymlinklen) { 27298542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 27398542Smckusick ndb = howmany(DIP(dp, di_size), 27498542Smckusick sizeof(ufs1_daddr_t)); 27598542Smckusick else 27698542Smckusick ndb = howmany(DIP(dp, di_size), 27798542Smckusick sizeof(ufs2_daddr_t)); 2781558Srgrimes if (ndb > NDADDR) { 2791558Srgrimes j = ndb - NDADDR; 2801558Srgrimes for (ndb = 1; j > 1; j--) 2811558Srgrimes ndb *= NINDIR(&sblock); 2821558Srgrimes ndb += NDADDR; 2831558Srgrimes } 2841558Srgrimes } 2851558Srgrimes } 28698879Siedowse for (j = ndb; ndb < NDADDR && j < NDADDR; j++) 28798542Smckusick if (DIP(dp, di_db[j]) != 0) { 2881558Srgrimes if (debug) 289101037Smux printf("bad direct addr[%d]: %ju\n", j, 290101037Smux (uintmax_t)DIP(dp, di_db[j])); 2911558Srgrimes goto unknown; 2921558Srgrimes } 2931558Srgrimes for (j = 0, ndb -= NDADDR; ndb > 0; j++) 2941558Srgrimes ndb /= NINDIR(&sblock); 2951558Srgrimes for (; j < NIADDR; j++) 29698542Smckusick if (DIP(dp, di_ib[j]) != 0) { 2971558Srgrimes if (debug) 298101037Smux printf("bad indirect addr: %ju\n", 299101037Smux (uintmax_t)DIP(dp, di_ib[j])); 3001558Srgrimes goto unknown; 3011558Srgrimes } 3021558Srgrimes if (ftypeok(dp) == 0) 3031558Srgrimes goto unknown; 3041558Srgrimes n_files++; 30598542Smckusick inoinfo(inumber)->ino_linkcnt = DIP(dp, di_nlink); 3061558Srgrimes if (mode == IFDIR) { 30798542Smckusick if (DIP(dp, di_size) == 0) 30841474Sjulian inoinfo(inumber)->ino_state = DCLEAR; 309136281Struckman else if (DIP(dp, di_nlink) <= 0) 310136281Struckman inoinfo(inumber)->ino_state = DZLINK; 3111558Srgrimes else 31241474Sjulian inoinfo(inumber)->ino_state = DSTATE; 3131558Srgrimes cacheino(dp, inumber); 31441474Sjulian countdirs++; 315136281Struckman } else if (DIP(dp, di_nlink) <= 0) 316136281Struckman inoinfo(inumber)->ino_state = FZLINK; 317136281Struckman else 31841474Sjulian inoinfo(inumber)->ino_state = FSTATE; 31941474Sjulian inoinfo(inumber)->ino_type = IFTODT(mode); 3201558Srgrimes badblk = dupblk = 0; 3211558Srgrimes idesc->id_number = inumber; 32298542Smckusick if (DIP(dp, di_flags) & SF_SNAPSHOT) 32362668Smckusick idesc->id_type = SNAP; 32462668Smckusick else 32562668Smckusick idesc->id_type = ADDR; 3261558Srgrimes (void)ckinode(dp, idesc); 327103885Smckusick if (sblock.fs_magic == FS_UFS2_MAGIC && dp->dp2.di_extsize > 0) { 328103885Smckusick idesc->id_type = ADDR; 329103885Smckusick ndb = howmany(dp->dp2.di_extsize, sblock.fs_bsize); 330103885Smckusick for (j = 0; j < NXADDR; j++) { 331103885Smckusick if (--ndb == 0 && 332103885Smckusick (offset = blkoff(&sblock, dp->dp2.di_extsize)) != 0) 333103885Smckusick idesc->id_numfrags = numfrags(&sblock, 334103885Smckusick fragroundup(&sblock, offset)); 335103885Smckusick else 336103885Smckusick idesc->id_numfrags = sblock.fs_frag; 337103885Smckusick if (dp->dp2.di_extb[j] == 0) 338103885Smckusick continue; 339103885Smckusick idesc->id_blkno = dp->dp2.di_extb[j]; 340103885Smckusick ret = (*idesc->id_func)(idesc); 341103885Smckusick if (ret & STOP) 342103885Smckusick break; 343103885Smckusick } 344103885Smckusick } 345103398Sphk if (sblock.fs_magic == FS_UFS2_MAGIC) 346103398Sphk eascan(idesc, &dp->dp2); 3471558Srgrimes idesc->id_entryno *= btodb(sblock.fs_fsize); 34898542Smckusick if (DIP(dp, di_blocks) != idesc->id_entryno) { 349101037Smux pwarn("INCORRECT BLOCK COUNT I=%lu (%ju should be %ju)", 350101037Smux (u_long)inumber, (uintmax_t)DIP(dp, di_blocks), 351101037Smux (uintmax_t)idesc->id_entryno); 3521558Srgrimes if (preen) 3531558Srgrimes printf(" (CORRECTED)\n"); 3541558Srgrimes else if (reply("CORRECT") == 0) 3551558Srgrimes return; 35674556Smckusick if (bkgrdflag == 0) { 35774556Smckusick dp = ginode(inumber); 358134589Sscottl DIP_SET(dp, di_blocks, idesc->id_entryno); 35974556Smckusick inodirty(); 36074556Smckusick } else { 36174556Smckusick cmd.value = idesc->id_number; 36298542Smckusick cmd.size = idesc->id_entryno - DIP(dp, di_blocks); 36374556Smckusick if (debug) 364101037Smux printf("adjblkcnt ino %ju amount %lld\n", 365101037Smux (uintmax_t)cmd.value, (long long)cmd.size); 36674556Smckusick if (sysctl(adjblkcnt, MIBSIZE, 0, 0, 36774556Smckusick &cmd, sizeof cmd) == -1) 36874556Smckusick rwerror("ADJUST INODE BLOCK COUNT", cmd.value); 36974556Smckusick } 3701558Srgrimes } 3711558Srgrimes return; 3721558Srgrimesunknown: 37386514Siedowse pfatal("UNKNOWN FILE TYPE I=%lu", (u_long)inumber); 37441474Sjulian inoinfo(inumber)->ino_state = FCLEAR; 3751558Srgrimes if (reply("CLEAR") == 1) { 37641474Sjulian inoinfo(inumber)->ino_state = USTATE; 3771558Srgrimes dp = ginode(inumber); 3781558Srgrimes clearinode(dp); 3791558Srgrimes inodirty(); 3801558Srgrimes } 3811558Srgrimes} 3821558Srgrimes 3837585Sbdeint 38492839Simppass1check(struct inodesc *idesc) 3851558Srgrimes{ 3861558Srgrimes int res = KEEPON; 3871558Srgrimes int anyout, nfrags; 38898542Smckusick ufs2_daddr_t blkno = idesc->id_blkno; 38992806Sobrien struct dups *dlp; 3901558Srgrimes struct dups *new; 3911558Srgrimes 39262668Smckusick if (idesc->id_type == SNAP) { 39362668Smckusick if (blkno == BLK_NOCOPY) 39462668Smckusick return (KEEPON); 39562668Smckusick if (idesc->id_number == cursnapshot) { 39662668Smckusick if (blkno == blkstofrags(&sblock, idesc->id_lbn)) 39762668Smckusick return (KEEPON); 39862668Smckusick if (blkno == BLK_SNAP) { 39962668Smckusick blkno = blkstofrags(&sblock, idesc->id_lbn); 40062668Smckusick idesc->id_entryno -= idesc->id_numfrags; 40162668Smckusick } 40262668Smckusick } else { 40362668Smckusick if (blkno == BLK_SNAP) 40462668Smckusick return (KEEPON); 40562668Smckusick } 40662668Smckusick } 4071558Srgrimes if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) { 4081558Srgrimes blkerror(idesc->id_number, "BAD", blkno); 4091558Srgrimes if (badblk++ >= MAXBAD) { 4101558Srgrimes pwarn("EXCESSIVE BAD BLKS I=%lu", 41186514Siedowse (u_long)idesc->id_number); 4121558Srgrimes if (preen) 4131558Srgrimes printf(" (SKIPPING)\n"); 41434266Sjulian else if (reply("CONTINUE") == 0) { 41534266Sjulian ckfini(0); 41623675Speter exit(EEXIT); 41734266Sjulian } 4181558Srgrimes return (STOP); 4191558Srgrimes } 4201558Srgrimes } 4211558Srgrimes for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { 4221558Srgrimes if (anyout && chkrange(blkno, 1)) { 4231558Srgrimes res = SKIP; 4241558Srgrimes } else if (!testbmap(blkno)) { 4251558Srgrimes n_blks++; 4261558Srgrimes setbmap(blkno); 4271558Srgrimes } else { 4281558Srgrimes blkerror(idesc->id_number, "DUP", blkno); 4291558Srgrimes if (dupblk++ >= MAXDUP) { 4301558Srgrimes pwarn("EXCESSIVE DUP BLKS I=%lu", 43186514Siedowse (u_long)idesc->id_number); 4321558Srgrimes if (preen) 4331558Srgrimes printf(" (SKIPPING)\n"); 43434266Sjulian else if (reply("CONTINUE") == 0) { 43534266Sjulian ckfini(0); 43623675Speter exit(EEXIT); 43734266Sjulian } 4381558Srgrimes return (STOP); 4391558Srgrimes } 4401558Srgrimes new = (struct dups *)malloc(sizeof(struct dups)); 4411558Srgrimes if (new == NULL) { 4421558Srgrimes pfatal("DUP TABLE OVERFLOW."); 44334266Sjulian if (reply("CONTINUE") == 0) { 44434266Sjulian ckfini(0); 44523675Speter exit(EEXIT); 44634266Sjulian } 4471558Srgrimes return (STOP); 4481558Srgrimes } 4491558Srgrimes new->dup = blkno; 4501558Srgrimes if (muldup == 0) { 4511558Srgrimes duplist = muldup = new; 4521558Srgrimes new->next = 0; 4531558Srgrimes } else { 4541558Srgrimes new->next = muldup->next; 4551558Srgrimes muldup->next = new; 4561558Srgrimes } 4571558Srgrimes for (dlp = duplist; dlp != muldup; dlp = dlp->next) 4581558Srgrimes if (dlp->dup == blkno) 4591558Srgrimes break; 4601558Srgrimes if (dlp == muldup && dlp->dup != blkno) 4611558Srgrimes muldup = new; 4621558Srgrimes } 4631558Srgrimes /* 4641558Srgrimes * count the number of blocks found in id_entryno 4651558Srgrimes */ 4661558Srgrimes idesc->id_entryno++; 4671558Srgrimes } 4681558Srgrimes return (res); 4691558Srgrimes} 470