1 /* $NetBSD: pass1.c,v 1.2 1997/07/10 04:52:39 mikel 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 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)pass1.c 8.1 (Berkeley) 6/5/93"; 40 #else 41 static char rcsid[] = "$NetBSD: pass1.c,v 1.2 1997/07/10 04:52:39 mikel Exp $"; 42 #endif 43 #endif /* not lint */ 44 45 #include <sys/param.h> 46 #include <sys/time.h> 47 #include <ufs/ext2fs/ext2fs_dinode.h> 48 #include <ufs/ext2fs/ext2fs_dir.h> 49 #include <ufs/ext2fs/ext2fs.h> 50 51 #include <ufs/ufs/dinode.h> /* for IFMT & friends */ 52 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> 56 57 #include "fsck.h" 58 #include "extern.h" 59 #include "fsutil.h" 60 61 static daddr_t badblk; 62 static daddr_t dupblk; 63 static void checkinode __P((ino_t, struct inodesc *)); 64 65 void 66 pass1() 67 { 68 ino_t inumber; 69 int c, i, cgd; 70 struct inodesc idesc; 71 72 /* 73 * Set file system reserved blocks in used block map. 74 */ 75 for (c = 0; c < sblock.e2fs_ncg; c++) { 76 i = c * sblock.e2fs.e2fs_bpg + sblock.e2fs.e2fs_first_dblock; 77 cgd = i + cgoverhead; 78 79 if (c == 0) 80 i = 0; 81 for (; i < cgd; i++) 82 setbmap(i); 83 } 84 85 /* 86 * Find all allocated blocks. 87 */ 88 memset(&idesc, 0, sizeof(struct inodesc)); 89 idesc.id_type = ADDR; 90 idesc.id_func = pass1check; 91 inumber = 1; 92 n_files = n_blks = 0; 93 resetinodebuf(); 94 for (c = 0; c < sblock.e2fs_ncg; c++) { 95 for (i = 0; 96 i < sblock.e2fs.e2fs_ipg && inumber <= sblock.e2fs.e2fs_icount; 97 i++, inumber++) { 98 if (inumber < EXT2_ROOTINO) /* XXX */ 99 continue; 100 checkinode(inumber, &idesc); 101 } 102 } 103 freeinodebuf(); 104 } 105 106 static void 107 checkinode(inumber, idesc) 108 ino_t inumber; 109 register struct inodesc *idesc; 110 { 111 register struct ext2fs_dinode *dp; 112 struct zlncnt *zlnp; 113 int ndb, j; 114 mode_t mode; 115 char *symbuf; 116 117 dp = getnextinode(inumber); 118 if (inumber < EXT2_FIRSTINO && inumber != EXT2_ROOTINO) 119 return; 120 121 mode = 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 = 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 = 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 dp->e2di_size + sblock.e2fs_bsize - 1 < dp->e2di_size) { 168 if (debug) 169 printf("bad size %lu:", (u_long)dp->e2di_size); 170 goto unknown; 171 } 172 if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) { 173 dp = ginode(inumber); 174 dp->e2di_size = sblock.e2fs_bsize; 175 dp->e2di_mode = IFREG|0600; 176 inodirty(); 177 } 178 ndb = howmany(dp->e2di_size, sblock.e2fs_bsize); 179 if (ndb < 0) { 180 if (debug) 181 printf("bad size %lu ndb %d:", 182 (u_long)dp->e2di_size, ndb); 183 goto unknown; 184 } 185 if (mode == IFBLK || mode == IFCHR) 186 ndb++; 187 if (mode == IFLNK) { 188 /* 189 * Fake ndb value so direct/indirect block checks below 190 * will detect any garbage after symlink string. 191 */ 192 if (dp->e2di_size < EXT2_MAXSYMLINKLEN || 193 (EXT2_MAXSYMLINKLEN == 0 && dp->e2di_blocks == 0)) { 194 ndb = howmany(dp->e2di_size, sizeof(u_int32_t)); 195 if (ndb > NDADDR) { 196 j = ndb - NDADDR; 197 for (ndb = 1; j > 1; j--) 198 ndb *= NINDIR(&sblock); 199 ndb += NDADDR; 200 } 201 } 202 } 203 for (j = ndb; j < NDADDR; j++) 204 if (dp->e2di_blocks[j] != 0) { 205 if (debug) 206 printf("bad direct addr: %d\n", dp->e2di_blocks[j]); 207 goto unknown; 208 } 209 for (j = 0, ndb -= NDADDR; ndb > 0; j++) 210 ndb /= NINDIR(&sblock); 211 for (; j < NIADDR; j++) 212 if (dp->e2di_blocks[j+NDADDR] != 0) { 213 if (debug) 214 printf("bad indirect addr: %d\n", 215 dp->e2di_blocks[j+NDADDR]); 216 goto unknown; 217 } 218 if (ftypeok(dp) == 0) 219 goto unknown; 220 n_files++; 221 lncntp[inumber] = dp->e2di_nlink; 222 if (dp->e2di_nlink <= 0) { 223 zlnp = (struct zlncnt *)malloc(sizeof *zlnp); 224 if (zlnp == NULL) { 225 pfatal("LINK COUNT TABLE OVERFLOW"); 226 if (reply("CONTINUE") == 0) 227 errexit("%s\n", ""); 228 } else { 229 zlnp->zlncnt = inumber; 230 zlnp->next = zlnhead; 231 zlnhead = zlnp; 232 } 233 } 234 if (mode == IFDIR) { 235 if (dp->e2di_size == 0) 236 statemap[inumber] = DCLEAR; 237 else 238 statemap[inumber] = DSTATE; 239 cacheino(dp, inumber); 240 } else { 241 statemap[inumber] = FSTATE; 242 } 243 badblk = dupblk = 0; 244 idesc->id_number = inumber; 245 (void)ckinode(dp, idesc); 246 idesc->id_entryno *= btodb(sblock.e2fs_bsize); 247 if (dp->e2di_nblock != idesc->id_entryno) { 248 pwarn("INCORRECT BLOCK COUNT I=%u (%d should be %d)", 249 inumber, dp->e2di_nblock, idesc->id_entryno); 250 if (preen) 251 printf(" (CORRECTED)\n"); 252 else if (reply("CORRECT") == 0) 253 return; 254 dp = ginode(inumber); 255 dp->e2di_nblock = idesc->id_entryno; 256 inodirty(); 257 } 258 return; 259 unknown: 260 pfatal("UNKNOWN FILE TYPE I=%u", inumber); 261 statemap[inumber] = FCLEAR; 262 if (reply("CLEAR") == 1) { 263 statemap[inumber] = USTATE; 264 dp = ginode(inumber); 265 clearinode(dp); 266 inodirty(); 267 } 268 } 269 270 int 271 pass1check(idesc) 272 register struct inodesc *idesc; 273 { 274 int res = KEEPON; 275 int anyout, nfrags; 276 daddr_t blkno = idesc->id_blkno; 277 register struct dups *dlp; 278 struct dups *new; 279 280 if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) { 281 blkerror(idesc->id_number, "BAD", blkno); 282 if (badblk++ >= MAXBAD) { 283 pwarn("EXCESSIVE BAD BLKS I=%u", 284 idesc->id_number); 285 if (preen) 286 printf(" (SKIPPING)\n"); 287 else if (reply("CONTINUE") == 0) 288 errexit("%s\n", ""); 289 return (STOP); 290 } 291 } 292 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { 293 if (anyout && chkrange(blkno, 1)) { 294 res = SKIP; 295 } else if (!testbmap(blkno)) { 296 n_blks++; 297 setbmap(blkno); 298 } else { 299 blkerror(idesc->id_number, "DUP", blkno); 300 if (dupblk++ >= MAXDUP) { 301 pwarn("EXCESSIVE DUP BLKS I=%u", 302 idesc->id_number); 303 if (preen) 304 printf(" (SKIPPING)\n"); 305 else if (reply("CONTINUE") == 0) 306 errexit("%s\n", ""); 307 return (STOP); 308 } 309 new = (struct dups *)malloc(sizeof(struct dups)); 310 if (new == NULL) { 311 pfatal("DUP TABLE OVERFLOW."); 312 if (reply("CONTINUE") == 0) 313 errexit("%s\n", ""); 314 return (STOP); 315 } 316 new->dup = blkno; 317 if (muldup == 0) { 318 duplist = muldup = new; 319 new->next = 0; 320 } else { 321 new->next = muldup->next; 322 muldup->next = new; 323 } 324 for (dlp = duplist; dlp != muldup; dlp = dlp->next) 325 if (dlp->dup == blkno) 326 break; 327 if (dlp == muldup && dlp->dup != blkno) 328 muldup = new; 329 } 330 /* 331 * count the number of blocks found in id_entryno 332 */ 333 idesc->id_entryno++; 334 } 335 return (res); 336 } 337