1 /*
2 * Copyright (c) 1980, 1986, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)inode.c 8.8 (Berkeley) 04/28/95";
10 #endif /* not lint */
11
12 #include <sys/param.h>
13 #include <sys/time.h>
14
15 #include <ufs/ufs/dinode.h>
16 #include <ufs/ufs/dir.h>
17 #include <ufs/ffs/fs.h>
18
19 #include <err.h>
20 #include <pwd.h>
21 #include <string.h>
22
23 #include "fsck.h"
24
25 static ino_t startinum;
26
27 static int iblock __P((struct inodesc *, long ilevel, quad_t isize));
28
29 int
ckinode(dp,idesc)30 ckinode(dp, idesc)
31 struct dinode *dp;
32 register struct inodesc *idesc;
33 {
34 ufs_daddr_t *ap;
35 long ret, n, ndb, offset;
36 struct dinode dino;
37 quad_t remsize, sizepb;
38 mode_t mode;
39
40 if (idesc->id_fix != IGNORE)
41 idesc->id_fix = DONTKNOW;
42 idesc->id_entryno = 0;
43 idesc->id_filesize = dp->di_size;
44 mode = dp->di_mode & IFMT;
45 if (mode == IFBLK || mode == IFCHR || (mode == IFLNK &&
46 dp->di_size < sblock.fs_maxsymlinklen))
47 return (KEEPON);
48 dino = *dp;
49 ndb = howmany(dino.di_size, sblock.fs_bsize);
50 for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
51 if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
52 idesc->id_numfrags =
53 numfrags(&sblock, fragroundup(&sblock, offset));
54 else
55 idesc->id_numfrags = sblock.fs_frag;
56 if (*ap == 0)
57 continue;
58 idesc->id_blkno = *ap;
59 if (idesc->id_type == ADDR)
60 ret = (*idesc->id_func)(idesc);
61 else
62 ret = dirscan(idesc);
63 if (ret & STOP)
64 return (ret);
65 }
66 idesc->id_numfrags = sblock.fs_frag;
67 remsize = dino.di_size - sblock.fs_bsize * NDADDR;
68 sizepb = sblock.fs_bsize;
69 for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
70 if (*ap) {
71 idesc->id_blkno = *ap;
72 ret = iblock(idesc, n, remsize);
73 if (ret & STOP)
74 return (ret);
75 }
76 sizepb *= NINDIR(&sblock);
77 remsize -= sizepb;
78 }
79 return (KEEPON);
80 }
81
82 static int
iblock(idesc,ilevel,isize)83 iblock(idesc, ilevel, isize)
84 struct inodesc *idesc;
85 long ilevel;
86 quad_t isize;
87 {
88 ufs_daddr_t *ap;
89 ufs_daddr_t *aplim;
90 struct bufarea *bp;
91 int i, n, (*func)(), nif;
92 quad_t sizepb;
93 char buf[BUFSIZ];
94
95 if (idesc->id_type == ADDR) {
96 func = idesc->id_func;
97 if (((n = (*func)(idesc)) & KEEPON) == 0)
98 return (n);
99 } else
100 func = dirscan;
101 if (chkrange(idesc->id_blkno, idesc->id_numfrags))
102 return (SKIP);
103 bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
104 ilevel--;
105 for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
106 sizepb *= NINDIR(&sblock);
107 nif = howmany(isize , sizepb);
108 if (nif > NINDIR(&sblock))
109 nif = NINDIR(&sblock);
110 if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
111 aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
112 for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
113 if (*ap == 0)
114 continue;
115 (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu",
116 idesc->id_number);
117 if (dofix(idesc, buf)) {
118 *ap = 0;
119 dirty(bp);
120 }
121 }
122 flush(fswritefd, bp);
123 }
124 aplim = &bp->b_un.b_indir[nif];
125 for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
126 if (*ap) {
127 idesc->id_blkno = *ap;
128 if (ilevel == 0)
129 n = (*func)(idesc);
130 else
131 n = iblock(idesc, ilevel, isize);
132 if (n & STOP) {
133 bp->b_flags &= ~B_INUSE;
134 return (n);
135 }
136 }
137 isize -= sizepb;
138 }
139 bp->b_flags &= ~B_INUSE;
140 return (KEEPON);
141 }
142
143 /*
144 * Check that a block in a legal block number.
145 * Return 0 if in range, 1 if out of range.
146 */
147 int
chkrange(blk,cnt)148 chkrange(blk, cnt)
149 ufs_daddr_t blk;
150 int cnt;
151 {
152 register int c;
153
154 if ((unsigned)(blk + cnt) > maxfsblock)
155 return (1);
156 c = dtog(&sblock, blk);
157 if (blk < cgdmin(&sblock, c)) {
158 if ((blk + cnt) > cgsblock(&sblock, c)) {
159 if (debug) {
160 printf("blk %ld < cgdmin %ld;",
161 blk, cgdmin(&sblock, c));
162 printf(" blk + cnt %ld > cgsbase %ld\n",
163 blk + cnt, cgsblock(&sblock, c));
164 }
165 return (1);
166 }
167 } else {
168 if ((blk + cnt) > cgbase(&sblock, c+1)) {
169 if (debug) {
170 printf("blk %ld >= cgdmin %ld;",
171 blk, cgdmin(&sblock, c));
172 printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
173 blk+cnt, sblock.fs_fpg);
174 }
175 return (1);
176 }
177 }
178 return (0);
179 }
180
181 /*
182 * General purpose interface for reading inodes.
183 */
184 struct dinode *
ginode(inumber)185 ginode(inumber)
186 ino_t inumber;
187 {
188 ufs_daddr_t iblk;
189
190 if (inumber < ROOTINO || inumber > maxino)
191 errx(EEXIT, "bad inode number %d to ginode", inumber);
192 if (startinum == 0 ||
193 inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
194 iblk = ino_to_fsba(&sblock, inumber);
195 if (pbp != 0)
196 pbp->b_flags &= ~B_INUSE;
197 pbp = getdatablk(iblk, sblock.fs_bsize);
198 startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
199 }
200 return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
201 }
202
203 /*
204 * Special purpose version of ginode used to optimize first pass
205 * over all the inodes in numerical order.
206 */
207 ino_t nextino, lastinum;
208 long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
209 struct dinode *inodebuf;
210
211 struct dinode *
getnextinode(inumber)212 getnextinode(inumber)
213 ino_t inumber;
214 {
215 long size;
216 ufs_daddr_t dblk;
217 static struct dinode *dp;
218
219 if (inumber != nextino++ || inumber > maxino)
220 errx(EEXIT, "bad inode number %d to nextinode", inumber);
221 if (inumber >= lastinum) {
222 readcnt++;
223 dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));
224 if (readcnt % readpercg == 0) {
225 size = partialsize;
226 lastinum += partialcnt;
227 } else {
228 size = inobufsize;
229 lastinum += fullcnt;
230 }
231 (void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */
232 dp = inodebuf;
233 }
234 return (dp++);
235 }
236
237 void
resetinodebuf()238 resetinodebuf()
239 {
240
241 startinum = 0;
242 nextino = 0;
243 lastinum = 0;
244 readcnt = 0;
245 inobufsize = blkroundup(&sblock, INOBUFSIZE);
246 fullcnt = inobufsize / sizeof(struct dinode);
247 readpercg = sblock.fs_ipg / fullcnt;
248 partialcnt = sblock.fs_ipg % fullcnt;
249 partialsize = partialcnt * sizeof(struct dinode);
250 if (partialcnt != 0) {
251 readpercg++;
252 } else {
253 partialcnt = fullcnt;
254 partialsize = inobufsize;
255 }
256 if (inodebuf == NULL &&
257 (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL)
258 errx(EEXIT, "Cannot allocate space for inode buffer");
259 while (nextino < ROOTINO)
260 (void)getnextinode(nextino);
261 }
262
263 void
freeinodebuf()264 freeinodebuf()
265 {
266
267 if (inodebuf != NULL)
268 free((char *)inodebuf);
269 inodebuf = NULL;
270 }
271
272 /*
273 * Routines to maintain information about directory inodes.
274 * This is built during the first pass and used during the
275 * second and third passes.
276 *
277 * Enter inodes into the cache.
278 */
279 void
cacheino(dp,inumber)280 cacheino(dp, inumber)
281 register struct dinode *dp;
282 ino_t inumber;
283 {
284 register struct inoinfo *inp;
285 struct inoinfo **inpp;
286 unsigned int blks;
287
288 blks = howmany(dp->di_size, sblock.fs_bsize);
289 if (blks > NDADDR)
290 blks = NDADDR + NIADDR;
291 inp = (struct inoinfo *)
292 malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs_daddr_t));
293 if (inp == NULL)
294 return;
295 inpp = &inphead[inumber % numdirs];
296 inp->i_nexthash = *inpp;
297 *inpp = inp;
298 if (inumber == ROOTINO)
299 inp->i_parent = ROOTINO;
300 else
301 inp->i_parent = (ino_t)0;
302 inp->i_dotdot = (ino_t)0;
303 inp->i_number = inumber;
304 inp->i_isize = dp->di_size;
305 inp->i_numblks = blks * sizeof(ufs_daddr_t);
306 memmove(&inp->i_blks[0], &dp->di_db[0], (size_t)inp->i_numblks);
307 if (inplast == listmax) {
308 listmax += 100;
309 inpsort = (struct inoinfo **)realloc((char *)inpsort,
310 (unsigned)listmax * sizeof(struct inoinfo *));
311 if (inpsort == NULL)
312 errx(EEXIT, "cannot increase directory list");
313 }
314 inpsort[inplast++] = inp;
315 }
316
317 /*
318 * Look up an inode cache structure.
319 */
320 struct inoinfo *
getinoinfo(inumber)321 getinoinfo(inumber)
322 ino_t inumber;
323 {
324 register struct inoinfo *inp;
325
326 for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
327 if (inp->i_number != inumber)
328 continue;
329 return (inp);
330 }
331 errx(EEXIT, "cannot find inode %d", inumber);
332 return ((struct inoinfo *)0);
333 }
334
335 /*
336 * Clean up all the inode cache structure.
337 */
338 void
inocleanup()339 inocleanup()
340 {
341 register struct inoinfo **inpp;
342
343 if (inphead == NULL)
344 return;
345 for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
346 free((char *)(*inpp));
347 free((char *)inphead);
348 free((char *)inpsort);
349 inphead = inpsort = NULL;
350 }
351
352 void
inodirty()353 inodirty()
354 {
355
356 dirty(pbp);
357 }
358
359 void
clri(idesc,type,flag)360 clri(idesc, type, flag)
361 register struct inodesc *idesc;
362 char *type;
363 int flag;
364 {
365 register struct dinode *dp;
366
367 dp = ginode(idesc->id_number);
368 if (flag == 1) {
369 pwarn("%s %s", type,
370 (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
371 pinode(idesc->id_number);
372 }
373 if (preen || reply("CLEAR") == 1) {
374 if (preen)
375 printf(" (CLEARED)\n");
376 n_files--;
377 (void)ckinode(dp, idesc);
378 clearinode(dp);
379 statemap[idesc->id_number] = USTATE;
380 inodirty();
381 }
382 }
383
384 int
findname(idesc)385 findname(idesc)
386 struct inodesc *idesc;
387 {
388 register struct direct *dirp = idesc->id_dirp;
389
390 if (dirp->d_ino != idesc->id_parent)
391 return (KEEPON);
392 memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
393 return (STOP|FOUND);
394 }
395
396 int
findino(idesc)397 findino(idesc)
398 struct inodesc *idesc;
399 {
400 register struct direct *dirp = idesc->id_dirp;
401
402 if (dirp->d_ino == 0)
403 return (KEEPON);
404 if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
405 dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
406 idesc->id_parent = dirp->d_ino;
407 return (STOP|FOUND);
408 }
409 return (KEEPON);
410 }
411
412 void
pinode(ino)413 pinode(ino)
414 ino_t ino;
415 {
416 register struct dinode *dp;
417 register char *p;
418 struct passwd *pw;
419 char *ctime();
420
421 printf(" I=%lu ", ino);
422 if (ino < ROOTINO || ino > maxino)
423 return;
424 dp = ginode(ino);
425 printf(" OWNER=");
426 if ((pw = getpwuid((int)dp->di_uid)) != 0)
427 printf("%s ", pw->pw_name);
428 else
429 printf("%u ", (unsigned)dp->di_uid);
430 printf("MODE=%o\n", dp->di_mode);
431 if (preen)
432 printf("%s: ", cdevname);
433 printf("SIZE=%qu ", dp->di_size);
434 p = ctime(&dp->di_mtime);
435 printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
436 }
437
438 void
blkerror(ino,type,blk)439 blkerror(ino, type, blk)
440 ino_t ino;
441 char *type;
442 ufs_daddr_t blk;
443 {
444
445 pfatal("%ld %s I=%lu", blk, type, ino);
446 printf("\n");
447 switch (statemap[ino]) {
448
449 case FSTATE:
450 statemap[ino] = FCLEAR;
451 return;
452
453 case DSTATE:
454 statemap[ino] = DCLEAR;
455 return;
456
457 case FCLEAR:
458 case DCLEAR:
459 return;
460
461 default:
462 errx(EEXIT, "BAD STATE %d TO BLKERR", statemap[ino]);
463 /* NOTREACHED */
464 }
465 }
466
467 /*
468 * allocate an unused inode
469 */
470 ino_t
allocino(request,type)471 allocino(request, type)
472 ino_t request;
473 int type;
474 {
475 register ino_t ino;
476 register struct dinode *dp;
477
478 if (request == 0)
479 request = ROOTINO;
480 else if (statemap[request] != USTATE)
481 return (0);
482 for (ino = request; ino < maxino; ino++)
483 if (statemap[ino] == USTATE)
484 break;
485 if (ino == maxino)
486 return (0);
487 switch (type & IFMT) {
488 case IFDIR:
489 statemap[ino] = DSTATE;
490 break;
491 case IFREG:
492 case IFLNK:
493 statemap[ino] = FSTATE;
494 break;
495 default:
496 return (0);
497 }
498 dp = ginode(ino);
499 dp->di_db[0] = allocblk((long)1);
500 if (dp->di_db[0] == 0) {
501 statemap[ino] = USTATE;
502 return (0);
503 }
504 dp->di_mode = type;
505 (void)time(&dp->di_atime);
506 dp->di_mtime = dp->di_ctime = dp->di_atime;
507 dp->di_size = sblock.fs_fsize;
508 dp->di_blocks = btodb(sblock.fs_fsize);
509 n_files++;
510 inodirty();
511 if (newinofmt)
512 typemap[ino] = IFTODT(type);
513 return (ino);
514 }
515
516 /*
517 * deallocate an inode
518 */
519 void
freeino(ino)520 freeino(ino)
521 ino_t ino;
522 {
523 struct inodesc idesc;
524 struct dinode *dp;
525
526 memset(&idesc, 0, sizeof(struct inodesc));
527 idesc.id_type = ADDR;
528 idesc.id_func = pass4check;
529 idesc.id_number = ino;
530 dp = ginode(ino);
531 (void)ckinode(dp, &idesc);
532 clearinode(dp);
533 inodirty();
534 statemap[ino] = USTATE;
535 n_files--;
536 }
537