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