1 /* 2 * Copyright (c) 1980, 1986 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 static char sccsid[] = "@(#)inode.c 5.11 (Berkeley) 02/01/90"; 20 #endif /* not lint */ 21 22 #include <sys/param.h> 23 #include <ufs/dinode.h> 24 #include <ufs/fs.h> 25 #include <ufs/dir.h> 26 #include <pwd.h> 27 #include "fsck.h" 28 29 struct bufarea *pbp = 0; 30 31 ckinode(dp, idesc) 32 struct dinode *dp; 33 register struct inodesc *idesc; 34 { 35 register daddr_t *ap; 36 long ret, n, ndb, offset; 37 struct dinode dino; 38 39 idesc->id_fix = DONTKNOW; 40 idesc->id_entryno = 0; 41 idesc->id_filesize = dp->di_size; 42 if ((dp->di_mode & IFMT) == IFBLK || (dp->di_mode & IFMT) == IFCHR) 43 return (KEEPON); 44 dino = *dp; 45 ndb = howmany(dino.di_size, sblock.fs_bsize); 46 for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) { 47 if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0) 48 idesc->id_numfrags = 49 numfrags(&sblock, fragroundup(&sblock, offset)); 50 else 51 idesc->id_numfrags = sblock.fs_frag; 52 if (*ap == 0) 53 continue; 54 idesc->id_blkno = *ap; 55 if (idesc->id_type == ADDR) 56 ret = (*idesc->id_func)(idesc); 57 else 58 ret = dirscan(idesc); 59 if (ret & STOP) 60 return (ret); 61 } 62 idesc->id_numfrags = sblock.fs_frag; 63 for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) { 64 if (*ap) { 65 idesc->id_blkno = *ap; 66 ret = iblock(idesc, n, 67 dino.di_size - sblock.fs_bsize * NDADDR); 68 if (ret & STOP) 69 return (ret); 70 } 71 } 72 return (KEEPON); 73 } 74 75 iblock(idesc, ilevel, isize) 76 struct inodesc *idesc; 77 register long ilevel; 78 long isize; 79 { 80 register daddr_t *ap; 81 register daddr_t *aplim; 82 int i, n, (*func)(), nif, sizepb; 83 register struct bufarea *bp; 84 char buf[BUFSIZ]; 85 extern int dirscan(), pass1check(); 86 87 if (idesc->id_type == ADDR) { 88 func = idesc->id_func; 89 if (((n = (*func)(idesc)) & KEEPON) == 0) 90 return (n); 91 } else 92 func = dirscan; 93 if (chkrange(idesc->id_blkno, idesc->id_numfrags)) 94 return (SKIP); 95 bp = getdatablk(idesc->id_blkno, sblock.fs_bsize); 96 ilevel--; 97 for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++) 98 sizepb *= NINDIR(&sblock); 99 nif = isize / sizepb + 1; 100 if (nif > NINDIR(&sblock)) 101 nif = NINDIR(&sblock); 102 if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) { 103 aplim = &bp->b_un.b_indir[NINDIR(&sblock)]; 104 for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) { 105 if (*ap == 0) 106 continue; 107 (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%d", 108 idesc->id_number); 109 if (dofix(idesc, buf)) { 110 *ap = 0; 111 dirty(bp); 112 } 113 } 114 flush(fswritefd, bp); 115 } 116 aplim = &bp->b_un.b_indir[nif]; 117 for (ap = bp->b_un.b_indir, i = 1; ap < aplim; ap++, i++) { 118 if (*ap) { 119 idesc->id_blkno = *ap; 120 if (ilevel > 0) 121 n = iblock(idesc, ilevel, isize - i * sizepb); 122 else 123 n = (*func)(idesc); 124 if (n & STOP) { 125 bp->b_flags &= ~B_INUSE; 126 return (n); 127 } 128 } 129 } 130 bp->b_flags &= ~B_INUSE; 131 return (KEEPON); 132 } 133 134 /* 135 * Check that a block in a legal block number. 136 * Return 0 if in range, 1 if out of range. 137 */ 138 chkrange(blk, cnt) 139 daddr_t blk; 140 int cnt; 141 { 142 register int c; 143 144 if ((unsigned)(blk + cnt) > maxfsblock) 145 return (1); 146 c = dtog(&sblock, blk); 147 if (blk < cgdmin(&sblock, c)) { 148 if ((blk + cnt) > cgsblock(&sblock, c)) { 149 if (debug) { 150 printf("blk %d < cgdmin %d;", 151 blk, cgdmin(&sblock, c)); 152 printf(" blk + cnt %d > cgsbase %d\n", 153 blk + cnt, cgsblock(&sblock, c)); 154 } 155 return (1); 156 } 157 } else { 158 if ((blk + cnt) > cgbase(&sblock, c+1)) { 159 if (debug) { 160 printf("blk %d >= cgdmin %d;", 161 blk, cgdmin(&sblock, c)); 162 printf(" blk + cnt %d > sblock.fs_fpg %d\n", 163 blk+cnt, sblock.fs_fpg); 164 } 165 return (1); 166 } 167 } 168 return (0); 169 } 170 171 struct dinode * 172 ginode(inumber) 173 ino_t inumber; 174 { 175 daddr_t iblk; 176 static ino_t startinum = 0; 177 178 if (inumber < ROOTINO || inumber > maxino) 179 errexit("bad inode number %d to ginode\n", inumber); 180 if (startinum == 0 || 181 inumber < startinum || inumber >= startinum + INOPB(&sblock)) { 182 iblk = itod(&sblock, inumber); 183 if (pbp != 0) 184 pbp->b_flags &= ~B_INUSE; 185 pbp = getdatablk(iblk, sblock.fs_bsize); 186 startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); 187 } 188 return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]); 189 } 190 191 inodirty() 192 { 193 194 dirty(pbp); 195 } 196 197 clri(idesc, type, flag) 198 register struct inodesc *idesc; 199 char *type; 200 int flag; 201 { 202 register struct dinode *dp; 203 204 dp = ginode(idesc->id_number); 205 if (flag == 1) { 206 pwarn("%s %s", type, 207 (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"); 208 pinode(idesc->id_number); 209 } 210 if (preen || reply("CLEAR") == 1) { 211 if (preen) 212 printf(" (CLEARED)\n"); 213 n_files--; 214 (void)ckinode(dp, idesc); 215 clearinode(dp); 216 statemap[idesc->id_number] = USTATE; 217 inodirty(); 218 } 219 } 220 221 findname(idesc) 222 struct inodesc *idesc; 223 { 224 register struct direct *dirp = idesc->id_dirp; 225 226 if (dirp->d_ino != idesc->id_parent) 227 return (KEEPON); 228 bcopy(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1); 229 return (STOP|FOUND); 230 } 231 232 findino(idesc) 233 struct inodesc *idesc; 234 { 235 register struct direct *dirp = idesc->id_dirp; 236 237 if (dirp->d_ino == 0) 238 return (KEEPON); 239 if (strcmp(dirp->d_name, idesc->id_name) == 0 && 240 dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) { 241 idesc->id_parent = dirp->d_ino; 242 return (STOP|FOUND); 243 } 244 return (KEEPON); 245 } 246 247 pinode(ino) 248 ino_t ino; 249 { 250 register struct dinode *dp; 251 register char *p; 252 struct passwd *pw; 253 char *ctime(); 254 255 printf(" I=%u ", ino); 256 if (ino < ROOTINO || ino > maxino) 257 return; 258 dp = ginode(ino); 259 printf(" OWNER="); 260 if ((pw = getpwuid((int)dp->di_uid)) != 0) 261 printf("%s ", pw->pw_name); 262 else 263 printf("%d ", dp->di_uid); 264 printf("MODE=%o\n", dp->di_mode); 265 if (preen) 266 printf("%s: ", devname); 267 printf("SIZE=%ld ", dp->di_size); 268 p = ctime(&dp->di_mtime); 269 printf("MTIME=%12.12s %4.4s ", p + 4, p + 20); 270 } 271 272 blkerror(ino, type, blk) 273 ino_t ino; 274 char *type; 275 daddr_t blk; 276 { 277 278 pfatal("%ld %s I=%u", blk, type, ino); 279 printf("\n"); 280 switch (statemap[ino]) { 281 282 case FSTATE: 283 statemap[ino] = FCLEAR; 284 return; 285 286 case DSTATE: 287 statemap[ino] = DCLEAR; 288 return; 289 290 case FCLEAR: 291 case DCLEAR: 292 return; 293 294 default: 295 errexit("BAD STATE %d TO BLKERR", statemap[ino]); 296 /* NOTREACHED */ 297 } 298 } 299 300 /* 301 * allocate an unused inode 302 */ 303 ino_t 304 allocino(request, type) 305 ino_t request; 306 int type; 307 { 308 register ino_t ino; 309 register struct dinode *dp; 310 311 if (request == 0) 312 request = ROOTINO; 313 else if (statemap[request] != USTATE) 314 return (0); 315 for (ino = request; ino < maxino; ino++) 316 if (statemap[ino] == USTATE) 317 break; 318 if (ino == maxino) 319 return (0); 320 switch (type & IFMT) { 321 case IFDIR: 322 statemap[ino] = DSTATE; 323 break; 324 case IFREG: 325 case IFLNK: 326 statemap[ino] = FSTATE; 327 break; 328 default: 329 return (0); 330 } 331 dp = ginode(ino); 332 dp->di_db[0] = allocblk((long)1); 333 if (dp->di_db[0] == 0) { 334 statemap[ino] = USTATE; 335 return (0); 336 } 337 dp->di_mode = type; 338 time(&dp->di_atime); 339 dp->di_mtime = dp->di_ctime = dp->di_atime; 340 dp->di_size = sblock.fs_fsize; 341 dp->di_blocks = btodb(sblock.fs_fsize); 342 n_files++; 343 inodirty(); 344 return (ino); 345 } 346 347 /* 348 * deallocate an inode 349 */ 350 freeino(ino) 351 ino_t ino; 352 { 353 struct inodesc idesc; 354 extern int pass4check(); 355 struct dinode *dp; 356 357 bzero((char *)&idesc, sizeof(struct inodesc)); 358 idesc.id_type = ADDR; 359 idesc.id_func = pass4check; 360 idesc.id_number = ino; 361 dp = ginode(ino); 362 (void)ckinode(dp, &idesc); 363 clearinode(dp); 364 inodirty(); 365 statemap[ino] = USTATE; 366 n_files--; 367 } 368