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