1 /* $NetBSD: pass1.c,v 1.9 2000/01/31 11:40:12 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.9 2000/01/31 11:40:12 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 #include <time.h> 58 59 #include "fsck.h" 60 #include "extern.h" 61 #include "fsutil.h" 62 63 static daddr_t badblk; 64 static daddr_t dupblk; 65 static void checkinode __P((ino_t, struct inodesc *)); 66 67 void 68 pass1() 69 { 70 ino_t inumber; 71 int c, i; 72 daddr_t dbase; 73 struct inodesc idesc; 74 75 /* 76 * Set file system reserved blocks in used block map. 77 */ 78 for (c = 0; c < sblock.e2fs_ncg; c++) { 79 dbase = c * sblock.e2fs.e2fs_bpg + 80 sblock.e2fs.e2fs_first_dblock; 81 /* Mark the blocks used for the inode table */ 82 if (fs2h32(sblock.e2fs_gd[c].ext2bgd_i_tables) >= dbase) { 83 for (i = 0; i < sblock.e2fs_itpg; i++) 84 setbmap( 85 fs2h32(sblock.e2fs_gd[c].ext2bgd_i_tables) 86 + i); 87 } 88 /* Mark the blocks used for the block bitmap */ 89 if (fs2h32(sblock.e2fs_gd[c].ext2bgd_b_bitmap) >= dbase) 90 setbmap(fs2h32(sblock.e2fs_gd[c].ext2bgd_b_bitmap)); 91 /* Mark the blocks used for the inode bitmap */ 92 if (fs2h32(sblock.e2fs_gd[c].ext2bgd_i_bitmap) >= dbase) 93 setbmap(fs2h32(sblock.e2fs_gd[c].ext2bgd_i_bitmap)); 94 95 if (sblock.e2fs.e2fs_rev == E2FS_REV0 || 96 (sblock.e2fs.e2fs_features_rocompat & 97 EXT2F_ROCOMPAT_SPARSESUPER) == 0 || 98 cg_has_sb(c)) { 99 /* Mark copuy of SB and descriptors */ 100 setbmap(dbase); 101 for (i = 1; i <= sblock.e2fs_ngdb; i++) 102 setbmap(dbase+i); 103 } 104 105 106 if (c == 0) { 107 for(i = 0; i < dbase; i++) 108 setbmap(i); 109 } 110 } 111 112 /* 113 * Find all allocated blocks. 114 */ 115 memset(&idesc, 0, sizeof(struct inodesc)); 116 idesc.id_type = ADDR; 117 idesc.id_func = pass1check; 118 inumber = 1; 119 n_files = n_blks = 0; 120 resetinodebuf(); 121 for (c = 0; c < sblock.e2fs_ncg; c++) { 122 for (i = 0; 123 i < sblock.e2fs.e2fs_ipg && inumber <= sblock.e2fs.e2fs_icount; 124 i++, inumber++) { 125 if (inumber < EXT2_ROOTINO) /* XXX */ 126 continue; 127 checkinode(inumber, &idesc); 128 } 129 } 130 freeinodebuf(); 131 } 132 133 static void 134 checkinode(inumber, idesc) 135 ino_t inumber; 136 struct inodesc *idesc; 137 { 138 struct ext2fs_dinode *dp; 139 struct zlncnt *zlnp; 140 int ndb, j; 141 mode_t mode; 142 143 dp = getnextinode(inumber); 144 if (inumber < EXT2_FIRSTINO && inumber != EXT2_ROOTINO) 145 return; 146 147 mode = fs2h16(dp->e2di_mode) & IFMT; 148 if (mode == 0 || (dp->e2di_dtime != 0 && dp->e2di_nlink == 0)) { 149 if (mode == 0 && ( 150 memcmp(dp->e2di_blocks, zino.e2di_blocks, 151 (NDADDR + NIADDR) * sizeof(u_int32_t)) || 152 dp->e2di_mode || dp->e2di_size)) { 153 pfatal("PARTIALLY ALLOCATED INODE I=%u", inumber); 154 if (reply("CLEAR") == 1) { 155 dp = ginode(inumber); 156 clearinode(dp); 157 inodirty(); 158 } 159 } 160 #ifdef notyet /* it seems that dtime == 0 is valid for a unallocated inode */ 161 if (dp->e2di_dtime == 0) { 162 pwarn("DELETED INODE I=%u HAS A NULL DTIME", inumber); 163 if (preen) { 164 printf(" (CORRECTED)\n"); 165 } 166 if (preen || reply("CORRECT")) { 167 time_t t; 168 time(&t); 169 dp->e2di_dtime = h2fs32(t); 170 dp = ginode(inumber); 171 inodirty(); 172 } 173 } 174 #endif 175 statemap[inumber] = USTATE; 176 return; 177 } 178 lastino = inumber; 179 if (dp->e2di_dtime != 0) { 180 time_t t = fs2h32(dp->e2di_dtime); 181 char *p = ctime(&t); 182 pwarn("INODE I=%u HAS DTIME=%12.12s %4.4s", inumber, &p[4], &p[20]); 183 if (preen) { 184 printf(" (CORRECTED)\n"); 185 } 186 if (preen || reply("CORRECT")) { 187 dp = ginode(inumber); 188 dp->e2di_dtime = 0; 189 inodirty(); 190 } 191 } 192 if (/* dp->di_size < 0 || */ 193 fs2h32(dp->e2di_size) + sblock.e2fs_bsize - 1 < 194 fs2h32(dp->e2di_size)) { 195 if (debug) 196 printf("bad size %lu:", (u_long)fs2h32(dp->e2di_size)); 197 goto unknown; 198 } 199 if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) { 200 dp = ginode(inumber); 201 dp->e2di_size = h2fs32(sblock.e2fs_bsize); 202 dp->e2di_mode = h2fs16(IFREG|0600); 203 inodirty(); 204 } 205 ndb = howmany(fs2h32(dp->e2di_size), sblock.e2fs_bsize); 206 if (ndb < 0) { 207 if (debug) 208 printf("bad size %lu ndb %d:", 209 (u_long)fs2h32(dp->e2di_size), ndb); 210 goto unknown; 211 } 212 if (mode == IFBLK || mode == IFCHR) 213 ndb++; 214 if (mode == IFLNK) { 215 /* 216 * Fake ndb value so direct/indirect block checks below 217 * will detect any garbage after symlink string. 218 */ 219 if (fs2h32(dp->e2di_size) < EXT2_MAXSYMLINKLEN || 220 (EXT2_MAXSYMLINKLEN == 0 && dp->e2di_blocks == 0)) { 221 ndb = howmany(fs2h32(dp->e2di_size), sizeof(u_int32_t)); 222 if (ndb > NDADDR) { 223 j = ndb - NDADDR; 224 for (ndb = 1; j > 1; j--) 225 ndb *= NINDIR(&sblock); 226 ndb += NDADDR; 227 } 228 } 229 } 230 /* Linux puts things in blocks for FIFO, so skip this check */ 231 if (mode != IFIFO) { 232 for (j = ndb; j < NDADDR; j++) 233 if (dp->e2di_blocks[j] != 0) { 234 if (debug) 235 printf("bad direct addr: %d\n", 236 fs2h32(dp->e2di_blocks[j])); 237 goto unknown; 238 } 239 for (j = 0, ndb -= NDADDR; ndb > 0; j++) 240 ndb /= NINDIR(&sblock); 241 for (; j < NIADDR; j++) { 242 if (dp->e2di_blocks[j+NDADDR] != 0) { 243 if (debug) 244 printf("bad indirect addr: %d\n", 245 fs2h32(dp->e2di_blocks[j+NDADDR])); 246 goto unknown; 247 } 248 } 249 } 250 if (ftypeok(dp) == 0) 251 goto unknown; 252 n_files++; 253 lncntp[inumber] = fs2h16(dp->e2di_nlink); 254 if (dp->e2di_nlink == 0) { 255 zlnp = (struct zlncnt *)malloc(sizeof *zlnp); 256 if (zlnp == NULL) { 257 pfatal("LINK COUNT TABLE OVERFLOW"); 258 if (reply("CONTINUE") == 0) 259 errexit("%s\n", ""); 260 } else { 261 zlnp->zlncnt = inumber; 262 zlnp->next = zlnhead; 263 zlnhead = zlnp; 264 } 265 } 266 if (mode == IFDIR) { 267 if (dp->e2di_size == 0) 268 statemap[inumber] = DCLEAR; 269 else 270 statemap[inumber] = DSTATE; 271 cacheino(dp, inumber); 272 } else { 273 statemap[inumber] = FSTATE; 274 } 275 typemap[inumber] = E2IFTODT(mode); 276 badblk = dupblk = 0; 277 idesc->id_number = inumber; 278 (void)ckinode(dp, idesc); 279 idesc->id_entryno *= btodb(sblock.e2fs_bsize); 280 if (fs2h32(dp->e2di_nblock) != idesc->id_entryno) { 281 pwarn("INCORRECT BLOCK COUNT I=%u (%d should be %d)", 282 inumber, fs2h32(dp->e2di_nblock), idesc->id_entryno); 283 if (preen) 284 printf(" (CORRECTED)\n"); 285 else if (reply("CORRECT") == 0) 286 return; 287 dp = ginode(inumber); 288 dp->e2di_nblock = h2fs32(idesc->id_entryno); 289 inodirty(); 290 } 291 return; 292 unknown: 293 pfatal("UNKNOWN FILE TYPE I=%u", inumber); 294 statemap[inumber] = FCLEAR; 295 if (reply("CLEAR") == 1) { 296 statemap[inumber] = USTATE; 297 dp = ginode(inumber); 298 clearinode(dp); 299 inodirty(); 300 } 301 } 302 303 int 304 pass1check(idesc) 305 struct inodesc *idesc; 306 { 307 int res = KEEPON; 308 int anyout, nfrags; 309 daddr_t blkno = idesc->id_blkno; 310 struct dups *dlp; 311 struct dups *new; 312 313 if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) { 314 blkerror(idesc->id_number, "BAD", blkno); 315 if (badblk++ >= MAXBAD) { 316 pwarn("EXCESSIVE BAD BLKS I=%u", 317 idesc->id_number); 318 if (preen) 319 printf(" (SKIPPING)\n"); 320 else if (reply("CONTINUE") == 0) 321 errexit("%s\n", ""); 322 return (STOP); 323 } 324 } 325 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { 326 if (anyout && chkrange(blkno, 1)) { 327 res = SKIP; 328 } else if (!testbmap(blkno)) { 329 n_blks++; 330 setbmap(blkno); 331 } else { 332 blkerror(idesc->id_number, "DUP", blkno); 333 if (dupblk++ >= MAXDUP) { 334 pwarn("EXCESSIVE DUP BLKS I=%u", 335 idesc->id_number); 336 if (preen) 337 printf(" (SKIPPING)\n"); 338 else if (reply("CONTINUE") == 0) 339 errexit("%s\n", ""); 340 return (STOP); 341 } 342 new = (struct dups *)malloc(sizeof(struct dups)); 343 if (new == NULL) { 344 pfatal("DUP TABLE OVERFLOW."); 345 if (reply("CONTINUE") == 0) 346 errexit("%s\n", ""); 347 return (STOP); 348 } 349 new->dup = blkno; 350 if (muldup == 0) { 351 duplist = muldup = new; 352 new->next = 0; 353 } else { 354 new->next = muldup->next; 355 muldup->next = new; 356 } 357 for (dlp = duplist; dlp != muldup; dlp = dlp->next) 358 if (dlp->dup == blkno) 359 break; 360 if (dlp == muldup && dlp->dup != blkno) 361 muldup = new; 362 } 363 /* 364 * count the number of blocks found in id_entryno 365 */ 366 idesc->id_entryno++; 367 } 368 return (res); 369 } 370