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