xref: /original-bsd/sbin/fsck/inode.c (revision f737e041)
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.3 (Berkeley) 02/27/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 				isize -= sizepb;
127 			}
128 			if (n & STOP) {
129 				bp->b_flags &= ~B_INUSE;
130 				return (n);
131 			}
132 		}
133 	}
134 	bp->b_flags &= ~B_INUSE;
135 	return (KEEPON);
136 }
137 
138 /*
139  * Check that a block in a legal block number.
140  * Return 0 if in range, 1 if out of range.
141  */
142 chkrange(blk, cnt)
143 	daddr_t blk;
144 	int cnt;
145 {
146 	register int c;
147 
148 	if ((unsigned)(blk + cnt) > maxfsblock)
149 		return (1);
150 	c = dtog(&sblock, blk);
151 	if (blk < cgdmin(&sblock, c)) {
152 		if ((blk + cnt) > cgsblock(&sblock, c)) {
153 			if (debug) {
154 				printf("blk %ld < cgdmin %ld;",
155 				    blk, cgdmin(&sblock, c));
156 				printf(" blk + cnt %ld > cgsbase %ld\n",
157 				    blk + cnt, cgsblock(&sblock, c));
158 			}
159 			return (1);
160 		}
161 	} else {
162 		if ((blk + cnt) > cgbase(&sblock, c+1)) {
163 			if (debug)  {
164 				printf("blk %ld >= cgdmin %ld;",
165 				    blk, cgdmin(&sblock, c));
166 				printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
167 				    blk+cnt, sblock.fs_fpg);
168 			}
169 			return (1);
170 		}
171 	}
172 	return (0);
173 }
174 
175 /*
176  * General purpose interface for reading inodes.
177  */
178 struct dinode *
179 ginode(inumber)
180 	ino_t inumber;
181 {
182 	daddr_t iblk;
183 
184 	if (inumber < ROOTINO || inumber > maxino)
185 		errexit("bad inode number %d to ginode\n", inumber);
186 	if (startinum == 0 ||
187 	    inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
188 		iblk = ino_to_fsba(&sblock, inumber);
189 		if (pbp != 0)
190 			pbp->b_flags &= ~B_INUSE;
191 		pbp = getdatablk(iblk, sblock.fs_bsize);
192 		startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
193 	}
194 	return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
195 }
196 
197 /*
198  * Special purpose version of ginode used to optimize first pass
199  * over all the inodes in numerical order.
200  */
201 ino_t nextino, lastinum;
202 long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
203 struct dinode *inodebuf;
204 
205 struct dinode *
206 getnextinode(inumber)
207 	ino_t inumber;
208 {
209 	long size;
210 	daddr_t dblk;
211 	static struct dinode *dp;
212 
213 	if (inumber != nextino++ || inumber > maxino)
214 		errexit("bad inode number %d to nextinode\n", inumber);
215 	if (inumber >= lastinum) {
216 		readcnt++;
217 		dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));
218 		if (readcnt % readpercg == 0) {
219 			size = partialsize;
220 			lastinum += partialcnt;
221 		} else {
222 			size = inobufsize;
223 			lastinum += fullcnt;
224 		}
225 		(void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */
226 		dp = inodebuf;
227 	}
228 	return (dp++);
229 }
230 
231 resetinodebuf()
232 {
233 
234 	startinum = 0;
235 	nextino = 0;
236 	lastinum = 0;
237 	readcnt = 0;
238 	inobufsize = blkroundup(&sblock, INOBUFSIZE);
239 	fullcnt = inobufsize / sizeof(struct dinode);
240 	readpercg = sblock.fs_ipg / fullcnt;
241 	partialcnt = sblock.fs_ipg % fullcnt;
242 	partialsize = partialcnt * sizeof(struct dinode);
243 	if (partialcnt != 0) {
244 		readpercg++;
245 	} else {
246 		partialcnt = fullcnt;
247 		partialsize = inobufsize;
248 	}
249 	if (inodebuf == NULL &&
250 	    (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL)
251 		errexit("Cannot allocate space for inode buffer\n");
252 	while (nextino < ROOTINO)
253 		(void)getnextinode(nextino);
254 }
255 
256 freeinodebuf()
257 {
258 
259 	if (inodebuf != NULL)
260 		free((char *)inodebuf);
261 	inodebuf = NULL;
262 }
263 
264 /*
265  * Routines to maintain information about directory inodes.
266  * This is built during the first pass and used during the
267  * second and third passes.
268  *
269  * Enter inodes into the cache.
270  */
271 cacheino(dp, inumber)
272 	register struct dinode *dp;
273 	ino_t inumber;
274 {
275 	register struct inoinfo *inp;
276 	struct inoinfo **inpp;
277 	unsigned int blks;
278 
279 	blks = howmany(dp->di_size, sblock.fs_bsize);
280 	if (blks > NDADDR)
281 		blks = NDADDR + NIADDR;
282 	inp = (struct inoinfo *)
283 		malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr_t));
284 	if (inp == NULL)
285 		return;
286 	inpp = &inphead[inumber % numdirs];
287 	inp->i_nexthash = *inpp;
288 	*inpp = inp;
289 	inp->i_parent = (ino_t)0;
290 	inp->i_dotdot = (ino_t)0;
291 	inp->i_number = inumber;
292 	inp->i_isize = dp->di_size;
293 	inp->i_numblks = blks * sizeof(daddr_t);
294 	bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0],
295 	    (size_t)inp->i_numblks);
296 	if (inplast == listmax) {
297 		listmax += 100;
298 		inpsort = (struct inoinfo **)realloc((char *)inpsort,
299 		    (unsigned)listmax * sizeof(struct inoinfo *));
300 		if (inpsort == NULL)
301 			errexit("cannot increase directory list");
302 	}
303 	inpsort[inplast++] = inp;
304 }
305 
306 /*
307  * Look up an inode cache structure.
308  */
309 struct inoinfo *
310 getinoinfo(inumber)
311 	ino_t inumber;
312 {
313 	register struct inoinfo *inp;
314 
315 	for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
316 		if (inp->i_number != inumber)
317 			continue;
318 		return (inp);
319 	}
320 	errexit("cannot find inode %d\n", inumber);
321 	return ((struct inoinfo *)0);
322 }
323 
324 /*
325  * Clean up all the inode cache structure.
326  */
327 inocleanup()
328 {
329 	register struct inoinfo **inpp;
330 
331 	if (inphead == NULL)
332 		return;
333 	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
334 		free((char *)(*inpp));
335 	free((char *)inphead);
336 	free((char *)inpsort);
337 	inphead = inpsort = NULL;
338 }
339 
340 inodirty()
341 {
342 
343 	dirty(pbp);
344 }
345 
346 clri(idesc, type, flag)
347 	register struct inodesc *idesc;
348 	char *type;
349 	int flag;
350 {
351 	register struct dinode *dp;
352 
353 	dp = ginode(idesc->id_number);
354 	if (flag == 1) {
355 		pwarn("%s %s", type,
356 		    (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
357 		pinode(idesc->id_number);
358 	}
359 	if (preen || reply("CLEAR") == 1) {
360 		if (preen)
361 			printf(" (CLEARED)\n");
362 		n_files--;
363 		(void)ckinode(dp, idesc);
364 		clearinode(dp);
365 		statemap[idesc->id_number] = USTATE;
366 		inodirty();
367 	}
368 }
369 
370 findname(idesc)
371 	struct inodesc *idesc;
372 {
373 	register struct direct *dirp = idesc->id_dirp;
374 
375 	if (dirp->d_ino != idesc->id_parent)
376 		return (KEEPON);
377 	bcopy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1);
378 	return (STOP|FOUND);
379 }
380 
381 findino(idesc)
382 	struct inodesc *idesc;
383 {
384 	register struct direct *dirp = idesc->id_dirp;
385 
386 	if (dirp->d_ino == 0)
387 		return (KEEPON);
388 	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
389 	    dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
390 		idesc->id_parent = dirp->d_ino;
391 		return (STOP|FOUND);
392 	}
393 	return (KEEPON);
394 }
395 
396 pinode(ino)
397 	ino_t ino;
398 {
399 	register struct dinode *dp;
400 	register char *p;
401 	struct passwd *pw;
402 	char *ctime();
403 
404 	printf(" I=%lu ", ino);
405 	if (ino < ROOTINO || ino > maxino)
406 		return;
407 	dp = ginode(ino);
408 	printf(" OWNER=");
409 	if ((pw = getpwuid((int)dp->di_uid)) != 0)
410 		printf("%s ", pw->pw_name);
411 	else
412 		printf("%u ", (unsigned)dp->di_uid);
413 	printf("MODE=%o\n", dp->di_mode);
414 	if (preen)
415 		printf("%s: ", cdevname);
416 	printf("SIZE=%qu ", dp->di_size);
417 	p = ctime(&dp->di_mtime.ts_sec);
418 	printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
419 }
420 
421 blkerror(ino, type, blk)
422 	ino_t ino;
423 	char *type;
424 	daddr_t blk;
425 {
426 
427 	pfatal("%ld %s I=%lu", blk, type, ino);
428 	printf("\n");
429 	switch (statemap[ino]) {
430 
431 	case FSTATE:
432 		statemap[ino] = FCLEAR;
433 		return;
434 
435 	case DSTATE:
436 		statemap[ino] = DCLEAR;
437 		return;
438 
439 	case FCLEAR:
440 	case DCLEAR:
441 		return;
442 
443 	default:
444 		errexit("BAD STATE %d TO BLKERR", statemap[ino]);
445 		/* NOTREACHED */
446 	}
447 }
448 
449 /*
450  * allocate an unused inode
451  */
452 ino_t
453 allocino(request, type)
454 	ino_t request;
455 	int type;
456 {
457 	register ino_t ino;
458 	register struct dinode *dp;
459 
460 	if (request == 0)
461 		request = ROOTINO;
462 	else if (statemap[request] != USTATE)
463 		return (0);
464 	for (ino = request; ino < maxino; ino++)
465 		if (statemap[ino] == USTATE)
466 			break;
467 	if (ino == maxino)
468 		return (0);
469 	switch (type & IFMT) {
470 	case IFDIR:
471 		statemap[ino] = DSTATE;
472 		break;
473 	case IFREG:
474 	case IFLNK:
475 		statemap[ino] = FSTATE;
476 		break;
477 	default:
478 		return (0);
479 	}
480 	dp = ginode(ino);
481 	dp->di_db[0] = allocblk((long)1);
482 	if (dp->di_db[0] == 0) {
483 		statemap[ino] = USTATE;
484 		return (0);
485 	}
486 	dp->di_mode = type;
487 	(void)time(&dp->di_atime.ts_sec);
488 	dp->di_mtime = dp->di_ctime = dp->di_atime;
489 	dp->di_size = sblock.fs_fsize;
490 	dp->di_blocks = btodb(sblock.fs_fsize);
491 	n_files++;
492 	inodirty();
493 	if (newinofmt)
494 		typemap[ino] = IFTODT(type);
495 	return (ino);
496 }
497 
498 /*
499  * deallocate an inode
500  */
501 freeino(ino)
502 	ino_t ino;
503 {
504 	struct inodesc idesc;
505 	extern int pass4check();
506 	struct dinode *dp;
507 
508 	bzero((char *)&idesc, sizeof(struct inodesc));
509 	idesc.id_type = ADDR;
510 	idesc.id_func = pass4check;
511 	idesc.id_number = ino;
512 	dp = ginode(ino);
513 	(void)ckinode(dp, &idesc);
514 	clearinode(dp);
515 	inodirty();
516 	statemap[ino] = USTATE;
517 	n_files--;
518 }
519