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