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