xref: /freebsd/sbin/fsck_ffs/inode.c (revision afe61c15161c324a7af299a9b8457aba5afc92db)
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.4 (Berkeley) 4/18/94";
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))
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 	inp->i_parent = (ino_t)0;
315 	inp->i_dotdot = (ino_t)0;
316 	inp->i_number = inumber;
317 	inp->i_isize = dp->di_size;
318 	inp->i_numblks = blks * sizeof(daddr_t);
319 	bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0],
320 	    (size_t)inp->i_numblks);
321 	if (inplast == listmax) {
322 		listmax += 100;
323 		inpsort = (struct inoinfo **)realloc((char *)inpsort,
324 		    (unsigned)listmax * sizeof(struct inoinfo *));
325 		if (inpsort == NULL)
326 			errexit("cannot increase directory list");
327 	}
328 	inpsort[inplast++] = inp;
329 }
330 
331 /*
332  * Look up an inode cache structure.
333  */
334 struct inoinfo *
335 getinoinfo(inumber)
336 	ino_t inumber;
337 {
338 	register struct inoinfo *inp;
339 
340 	for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
341 		if (inp->i_number != inumber)
342 			continue;
343 		return (inp);
344 	}
345 	errexit("cannot find inode %d\n", inumber);
346 	return ((struct inoinfo *)0);
347 }
348 
349 /*
350  * Clean up all the inode cache structure.
351  */
352 inocleanup()
353 {
354 	register struct inoinfo **inpp;
355 
356 	if (inphead == NULL)
357 		return;
358 	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
359 		free((char *)(*inpp));
360 	free((char *)inphead);
361 	free((char *)inpsort);
362 	inphead = inpsort = NULL;
363 }
364 
365 inodirty()
366 {
367 
368 	dirty(pbp);
369 }
370 
371 clri(idesc, type, flag)
372 	register struct inodesc *idesc;
373 	char *type;
374 	int flag;
375 {
376 	register struct dinode *dp;
377 
378 	dp = ginode(idesc->id_number);
379 	if (flag == 1) {
380 		pwarn("%s %s", type,
381 		    (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
382 		pinode(idesc->id_number);
383 	}
384 	if (preen || reply("CLEAR") == 1) {
385 		if (preen)
386 			printf(" (CLEARED)\n");
387 		n_files--;
388 		(void)ckinode(dp, idesc);
389 		clearinode(dp);
390 		statemap[idesc->id_number] = USTATE;
391 		inodirty();
392 	}
393 }
394 
395 findname(idesc)
396 	struct inodesc *idesc;
397 {
398 	register struct direct *dirp = idesc->id_dirp;
399 
400 	if (dirp->d_ino != idesc->id_parent)
401 		return (KEEPON);
402 	bcopy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1);
403 	return (STOP|FOUND);
404 }
405 
406 findino(idesc)
407 	struct inodesc *idesc;
408 {
409 	register struct direct *dirp = idesc->id_dirp;
410 
411 	if (dirp->d_ino == 0)
412 		return (KEEPON);
413 	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
414 	    dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
415 		idesc->id_parent = dirp->d_ino;
416 		return (STOP|FOUND);
417 	}
418 	return (KEEPON);
419 }
420 
421 pinode(ino)
422 	ino_t ino;
423 {
424 	register struct dinode *dp;
425 	register char *p;
426 	struct passwd *pw;
427 	char *ctime();
428 
429 	printf(" I=%lu ", ino);
430 	if (ino < ROOTINO || ino > maxino)
431 		return;
432 	dp = ginode(ino);
433 	printf(" OWNER=");
434 	if ((pw = getpwuid((int)dp->di_uid)) != 0)
435 		printf("%s ", pw->pw_name);
436 	else
437 		printf("%u ", (unsigned)dp->di_uid);
438 	printf("MODE=%o\n", dp->di_mode);
439 	if (preen)
440 		printf("%s: ", cdevname);
441 	printf("SIZE=%qu ", dp->di_size);
442 	p = ctime(&dp->di_mtime.ts_sec);
443 	printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
444 }
445 
446 blkerror(ino, type, blk)
447 	ino_t ino;
448 	char *type;
449 	daddr_t blk;
450 {
451 
452 	pfatal("%ld %s I=%lu", blk, type, ino);
453 	printf("\n");
454 	switch (statemap[ino]) {
455 
456 	case FSTATE:
457 		statemap[ino] = FCLEAR;
458 		return;
459 
460 	case DSTATE:
461 		statemap[ino] = DCLEAR;
462 		return;
463 
464 	case FCLEAR:
465 	case DCLEAR:
466 		return;
467 
468 	default:
469 		errexit("BAD STATE %d TO BLKERR", statemap[ino]);
470 		/* NOTREACHED */
471 	}
472 }
473 
474 /*
475  * allocate an unused inode
476  */
477 ino_t
478 allocino(request, type)
479 	ino_t request;
480 	int type;
481 {
482 	register ino_t ino;
483 	register struct dinode *dp;
484 
485 	if (request == 0)
486 		request = ROOTINO;
487 	else if (statemap[request] != USTATE)
488 		return (0);
489 	for (ino = request; ino < maxino; ino++)
490 		if (statemap[ino] == USTATE)
491 			break;
492 	if (ino == maxino)
493 		return (0);
494 	switch (type & IFMT) {
495 	case IFDIR:
496 		statemap[ino] = DSTATE;
497 		break;
498 	case IFREG:
499 	case IFLNK:
500 		statemap[ino] = FSTATE;
501 		break;
502 	default:
503 		return (0);
504 	}
505 	dp = ginode(ino);
506 	dp->di_db[0] = allocblk((long)1);
507 	if (dp->di_db[0] == 0) {
508 		statemap[ino] = USTATE;
509 		return (0);
510 	}
511 	dp->di_mode = type;
512 	(void)time(&dp->di_atime.ts_sec);
513 	dp->di_mtime = dp->di_ctime = dp->di_atime;
514 	dp->di_size = sblock.fs_fsize;
515 	dp->di_blocks = btodb(sblock.fs_fsize);
516 	n_files++;
517 	inodirty();
518 	if (newinofmt)
519 		typemap[ino] = IFTODT(type);
520 	return (ino);
521 }
522 
523 /*
524  * deallocate an inode
525  */
526 freeino(ino)
527 	ino_t ino;
528 {
529 	struct inodesc idesc;
530 	extern int pass4check();
531 	struct dinode *dp;
532 
533 	bzero((char *)&idesc, sizeof(struct inodesc));
534 	idesc.id_type = ADDR;
535 	idesc.id_func = pass4check;
536 	idesc.id_number = ino;
537 	dp = ginode(ino);
538 	(void)ckinode(dp, &idesc);
539 	clearinode(dp);
540 	inodirty();
541 	statemap[ino] = USTATE;
542 	n_files--;
543 }
544