xref: /original-bsd/sbin/fsck/inode.c (revision b55621b9)
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
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 	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 *
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
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
353 inodirty()
354 {
355 
356 	dirty(pbp);
357 }
358 
359 void
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
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
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
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
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
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
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