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