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