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