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