xref: /original-bsd/sbin/fsck/inode.c (revision 7e21a27b)
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.7 (Berkeley) 04/27/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
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
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
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 *
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 *
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
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
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
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 	bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0],
307 	    (size_t)inp->i_numblks);
308 	if (inplast == listmax) {
309 		listmax += 100;
310 		inpsort = (struct inoinfo **)realloc((char *)inpsort,
311 		    (unsigned)listmax * sizeof(struct inoinfo *));
312 		if (inpsort == NULL)
313 			errx(EEXIT, "cannot increase directory list");
314 	}
315 	inpsort[inplast++] = inp;
316 }
317 
318 /*
319  * Look up an inode cache structure.
320  */
321 struct inoinfo *
322 getinoinfo(inumber)
323 	ino_t inumber;
324 {
325 	register struct inoinfo *inp;
326 
327 	for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
328 		if (inp->i_number != inumber)
329 			continue;
330 		return (inp);
331 	}
332 	errx(EEXIT, "cannot find inode %d", inumber);
333 	return ((struct inoinfo *)0);
334 }
335 
336 /*
337  * Clean up all the inode cache structure.
338  */
339 void
340 inocleanup()
341 {
342 	register struct inoinfo **inpp;
343 
344 	if (inphead == NULL)
345 		return;
346 	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
347 		free((char *)(*inpp));
348 	free((char *)inphead);
349 	free((char *)inpsort);
350 	inphead = inpsort = NULL;
351 }
352 
353 void
354 inodirty()
355 {
356 
357 	dirty(pbp);
358 }
359 
360 void
361 clri(idesc, type, flag)
362 	register struct inodesc *idesc;
363 	char *type;
364 	int flag;
365 {
366 	register struct dinode *dp;
367 
368 	dp = ginode(idesc->id_number);
369 	if (flag == 1) {
370 		pwarn("%s %s", type,
371 		    (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
372 		pinode(idesc->id_number);
373 	}
374 	if (preen || reply("CLEAR") == 1) {
375 		if (preen)
376 			printf(" (CLEARED)\n");
377 		n_files--;
378 		(void)ckinode(dp, idesc);
379 		clearinode(dp);
380 		statemap[idesc->id_number] = USTATE;
381 		inodirty();
382 	}
383 }
384 
385 int
386 findname(idesc)
387 	struct inodesc *idesc;
388 {
389 	register struct direct *dirp = idesc->id_dirp;
390 
391 	if (dirp->d_ino != idesc->id_parent)
392 		return (KEEPON);
393 	bcopy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1);
394 	return (STOP|FOUND);
395 }
396 
397 int
398 findino(idesc)
399 	struct inodesc *idesc;
400 {
401 	register struct direct *dirp = idesc->id_dirp;
402 
403 	if (dirp->d_ino == 0)
404 		return (KEEPON);
405 	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
406 	    dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
407 		idesc->id_parent = dirp->d_ino;
408 		return (STOP|FOUND);
409 	}
410 	return (KEEPON);
411 }
412 
413 void
414 pinode(ino)
415 	ino_t ino;
416 {
417 	register struct dinode *dp;
418 	register char *p;
419 	struct passwd *pw;
420 	char *ctime();
421 
422 	printf(" I=%lu ", ino);
423 	if (ino < ROOTINO || ino > maxino)
424 		return;
425 	dp = ginode(ino);
426 	printf(" OWNER=");
427 	if ((pw = getpwuid((int)dp->di_uid)) != 0)
428 		printf("%s ", pw->pw_name);
429 	else
430 		printf("%u ", (unsigned)dp->di_uid);
431 	printf("MODE=%o\n", dp->di_mode);
432 	if (preen)
433 		printf("%s: ", cdevname);
434 	printf("SIZE=%qu ", dp->di_size);
435 	p = ctime(&dp->di_mtime);
436 	printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
437 }
438 
439 void
440 blkerror(ino, type, blk)
441 	ino_t ino;
442 	char *type;
443 	ufs_daddr_t blk;
444 {
445 
446 	pfatal("%ld %s I=%lu", blk, type, ino);
447 	printf("\n");
448 	switch (statemap[ino]) {
449 
450 	case FSTATE:
451 		statemap[ino] = FCLEAR;
452 		return;
453 
454 	case DSTATE:
455 		statemap[ino] = DCLEAR;
456 		return;
457 
458 	case FCLEAR:
459 	case DCLEAR:
460 		return;
461 
462 	default:
463 		errx(EEXIT, "BAD STATE %d TO BLKERR", statemap[ino]);
464 		/* NOTREACHED */
465 	}
466 }
467 
468 /*
469  * allocate an unused inode
470  */
471 ino_t
472 allocino(request, type)
473 	ino_t request;
474 	int type;
475 {
476 	register ino_t ino;
477 	register struct dinode *dp;
478 
479 	if (request == 0)
480 		request = ROOTINO;
481 	else if (statemap[request] != USTATE)
482 		return (0);
483 	for (ino = request; ino < maxino; ino++)
484 		if (statemap[ino] == USTATE)
485 			break;
486 	if (ino == maxino)
487 		return (0);
488 	switch (type & IFMT) {
489 	case IFDIR:
490 		statemap[ino] = DSTATE;
491 		break;
492 	case IFREG:
493 	case IFLNK:
494 		statemap[ino] = FSTATE;
495 		break;
496 	default:
497 		return (0);
498 	}
499 	dp = ginode(ino);
500 	dp->di_db[0] = allocblk((long)1);
501 	if (dp->di_db[0] == 0) {
502 		statemap[ino] = USTATE;
503 		return (0);
504 	}
505 	dp->di_mode = type;
506 	(void)time(&dp->di_atime);
507 	dp->di_mtime = dp->di_ctime = dp->di_atime;
508 	dp->di_size = sblock.fs_fsize;
509 	dp->di_blocks = btodb(sblock.fs_fsize);
510 	n_files++;
511 	inodirty();
512 	if (newinofmt)
513 		typemap[ino] = IFTODT(type);
514 	return (ino);
515 }
516 
517 /*
518  * deallocate an inode
519  */
520 void
521 freeino(ino)
522 	ino_t ino;
523 {
524 	struct inodesc idesc;
525 	struct dinode *dp;
526 
527 	bzero((char *)&idesc, sizeof(struct inodesc));
528 	idesc.id_type = ADDR;
529 	idesc.id_func = pass4check;
530 	idesc.id_number = ino;
531 	dp = ginode(ino);
532 	(void)ckinode(dp, &idesc);
533 	clearinode(dp);
534 	inodirty();
535 	statemap[ino] = USTATE;
536 	n_files--;
537 }
538