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