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