xref: /csrg-svn/sbin/fsck/inode.c (revision 39980)
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.12 (Berkeley) 02/01/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  * Inode cache data structures.
32  */
33 struct inoinfo {
34 	struct	inoinfo *i_next;	/* next entry in hash chain */
35 	ino_t	i_number;		/* inode number of this entry */
36 	size_t	i_size;			/* size of inode */
37 	u_int	i_numblks;		/* size of block array */
38 	daddr_t	i_blks[1];		/* actually longer */
39 } **inphead;
40 long hashsize;
41 
42 ckinode(dp, idesc)
43 	struct dinode *dp;
44 	register struct inodesc *idesc;
45 {
46 	register daddr_t *ap;
47 	long ret, n, ndb, offset;
48 	struct dinode dino;
49 
50 	idesc->id_fix = DONTKNOW;
51 	idesc->id_entryno = 0;
52 	idesc->id_filesize = dp->di_size;
53 	if ((dp->di_mode & IFMT) == IFBLK || (dp->di_mode & IFMT) == IFCHR)
54 		return (KEEPON);
55 	dino = *dp;
56 	ndb = howmany(dino.di_size, sblock.fs_bsize);
57 	for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
58 		if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
59 			idesc->id_numfrags =
60 				numfrags(&sblock, fragroundup(&sblock, offset));
61 		else
62 			idesc->id_numfrags = sblock.fs_frag;
63 		if (*ap == 0)
64 			continue;
65 		idesc->id_blkno = *ap;
66 		if (idesc->id_type == ADDR)
67 			ret = (*idesc->id_func)(idesc);
68 		else
69 			ret = dirscan(idesc);
70 		if (ret & STOP)
71 			return (ret);
72 	}
73 	idesc->id_numfrags = sblock.fs_frag;
74 	for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
75 		if (*ap) {
76 			idesc->id_blkno = *ap;
77 			ret = iblock(idesc, n,
78 				dino.di_size - sblock.fs_bsize * NDADDR);
79 			if (ret & STOP)
80 				return (ret);
81 		}
82 	}
83 	return (KEEPON);
84 }
85 
86 iblock(idesc, ilevel, isize)
87 	struct inodesc *idesc;
88 	register long ilevel;
89 	long isize;
90 {
91 	register daddr_t *ap;
92 	register daddr_t *aplim;
93 	int i, n, (*func)(), nif, sizepb;
94 	register struct bufarea *bp;
95 	char buf[BUFSIZ];
96 	extern int dirscan(), pass1check();
97 
98 	if (idesc->id_type == ADDR) {
99 		func = idesc->id_func;
100 		if (((n = (*func)(idesc)) & KEEPON) == 0)
101 			return (n);
102 	} else
103 		func = dirscan;
104 	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
105 		return (SKIP);
106 	bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
107 	ilevel--;
108 	for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
109 		sizepb *= NINDIR(&sblock);
110 	nif = isize / sizepb + 1;
111 	if (nif > NINDIR(&sblock))
112 		nif = NINDIR(&sblock);
113 	if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
114 		aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
115 		for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
116 			if (*ap == 0)
117 				continue;
118 			(void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%d",
119 				idesc->id_number);
120 			if (dofix(idesc, buf)) {
121 				*ap = 0;
122 				dirty(bp);
123 			}
124 		}
125 		flush(fswritefd, bp);
126 	}
127 	aplim = &bp->b_un.b_indir[nif];
128 	for (ap = bp->b_un.b_indir, i = 1; ap < aplim; ap++, i++) {
129 		if (*ap) {
130 			idesc->id_blkno = *ap;
131 			if (ilevel > 0)
132 				n = iblock(idesc, ilevel, isize - i * sizepb);
133 			else
134 				n = (*func)(idesc);
135 			if (n & STOP) {
136 				bp->b_flags &= ~B_INUSE;
137 				return (n);
138 			}
139 		}
140 	}
141 	bp->b_flags &= ~B_INUSE;
142 	return (KEEPON);
143 }
144 
145 /*
146  * Check that a block in a legal block number.
147  * Return 0 if in range, 1 if out of range.
148  */
149 chkrange(blk, cnt)
150 	daddr_t blk;
151 	int cnt;
152 {
153 	register int c;
154 
155 	if ((unsigned)(blk + cnt) > maxfsblock)
156 		return (1);
157 	c = dtog(&sblock, blk);
158 	if (blk < cgdmin(&sblock, c)) {
159 		if ((blk + cnt) > cgsblock(&sblock, c)) {
160 			if (debug) {
161 				printf("blk %d < cgdmin %d;",
162 				    blk, cgdmin(&sblock, c));
163 				printf(" blk + cnt %d > cgsbase %d\n",
164 				    blk + cnt, cgsblock(&sblock, c));
165 			}
166 			return (1);
167 		}
168 	} else {
169 		if ((blk + cnt) > cgbase(&sblock, c+1)) {
170 			if (debug)  {
171 				printf("blk %d >= cgdmin %d;",
172 				    blk, cgdmin(&sblock, c));
173 				printf(" blk + cnt %d > sblock.fs_fpg %d\n",
174 				    blk+cnt, sblock.fs_fpg);
175 			}
176 			return (1);
177 		}
178 	}
179 	return (0);
180 }
181 
182 struct dinode *
183 ginode(inumber)
184 	ino_t inumber;
185 {
186 	daddr_t iblk;
187 	static ino_t startinum = 0;
188 
189 	if (inumber < ROOTINO || inumber > maxino)
190 		errexit("bad inode number %d to ginode\n", inumber);
191 	if (startinum == 0 ||
192 	    inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
193 		iblk = itod(&sblock, inumber);
194 		if (pbp != 0)
195 			pbp->b_flags &= ~B_INUSE;
196 		pbp = getdatablk(iblk, sblock.fs_bsize);
197 		startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
198 	}
199 	return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
200 }
201 
202 cacheino(dp, inumber)
203 	register struct dinode *dp;
204 	ino_t inumber;
205 {
206 	register struct inoinfo *inp;
207 	struct inoinfo **inpp;
208 	unsigned int blks;
209 
210 	if (inphead == NULL) {
211 		hashsize = sblock.fs_cstotal.cs_ndir;
212 		inphead = (struct inoinfo **)malloc(hashsize * sizeof(daddr_t));
213 		if (inphead == NULL)
214 			return;
215 		bzero((char *)inphead, hashsize * sizeof(daddr_t));
216 	}
217 	blks = howmany(dp->di_size, sblock.fs_bsize);
218 	if (blks > NDADDR)
219 		blks = NDADDR + NIADDR;
220 	inp = (struct inoinfo *)
221 		malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr_t));
222 	if (inp == NULL)
223 		return;
224 	inpp = &inphead[inumber % hashsize];
225 	inp->i_next = *inpp;
226 	*inpp = inp;
227 	inp->i_number = inumber;
228 	inp->i_size = dp->di_size;
229 	inp->i_numblks = blks * sizeof(daddr_t);
230 	bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0], inp->i_numblks);
231 }
232 
233 struct dinode *
234 getcacheino(inumber)
235 	ino_t inumber;
236 {
237 	register struct inoinfo *inp;
238 	static struct dinode dino;
239 	register struct dinode *dp = &dino;
240 
241 	for (inp = inphead[inumber % hashsize]; inp; inp = inp->i_next) {
242 		if (inp->i_number != inumber)
243 			continue;
244 		dp->di_size = inp->i_size;
245 		bcopy((char *)&inp->i_blks[0], (char *)&dp->di_db[0],
246 			inp->i_numblks);
247 		return (dp);
248 	}
249 	return (ginode(inumber));
250 }
251 
252 inocleanup()
253 {
254 	register struct inoinfo *inp, **inpp;
255 	struct inoinfo *inpnext;
256 
257 	if (inphead == NULL)
258 		return;
259 	for (inpp = &inphead[hashsize - 1]; inpp >= inphead; inpp--) {
260 		for (inp = *inpp; inp; inp = inpnext) {
261 			inpnext = inp->i_next;
262 			free(inp);
263 		}
264 	}
265 	free(inphead);
266 	inphead = NULL;
267 }
268 
269 inodirty()
270 {
271 
272 	dirty(pbp);
273 }
274 
275 clri(idesc, type, flag)
276 	register struct inodesc *idesc;
277 	char *type;
278 	int flag;
279 {
280 	register struct dinode *dp;
281 
282 	dp = ginode(idesc->id_number);
283 	if (flag == 1) {
284 		pwarn("%s %s", type,
285 		    (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
286 		pinode(idesc->id_number);
287 	}
288 	if (preen || reply("CLEAR") == 1) {
289 		if (preen)
290 			printf(" (CLEARED)\n");
291 		n_files--;
292 		(void)ckinode(dp, idesc);
293 		clearinode(dp);
294 		statemap[idesc->id_number] = USTATE;
295 		inodirty();
296 	}
297 }
298 
299 findname(idesc)
300 	struct inodesc *idesc;
301 {
302 	register struct direct *dirp = idesc->id_dirp;
303 
304 	if (dirp->d_ino != idesc->id_parent)
305 		return (KEEPON);
306 	bcopy(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1);
307 	return (STOP|FOUND);
308 }
309 
310 findino(idesc)
311 	struct inodesc *idesc;
312 {
313 	register struct direct *dirp = idesc->id_dirp;
314 
315 	if (dirp->d_ino == 0)
316 		return (KEEPON);
317 	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
318 	    dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
319 		idesc->id_parent = dirp->d_ino;
320 		return (STOP|FOUND);
321 	}
322 	return (KEEPON);
323 }
324 
325 pinode(ino)
326 	ino_t ino;
327 {
328 	register struct dinode *dp;
329 	register char *p;
330 	struct passwd *pw;
331 	char *ctime();
332 
333 	printf(" I=%u ", ino);
334 	if (ino < ROOTINO || ino > maxino)
335 		return;
336 	dp = ginode(ino);
337 	printf(" OWNER=");
338 	if ((pw = getpwuid((int)dp->di_uid)) != 0)
339 		printf("%s ", pw->pw_name);
340 	else
341 		printf("%d ", dp->di_uid);
342 	printf("MODE=%o\n", dp->di_mode);
343 	if (preen)
344 		printf("%s: ", devname);
345 	printf("SIZE=%ld ", dp->di_size);
346 	p = ctime(&dp->di_mtime);
347 	printf("MTIME=%12.12s %4.4s ", p + 4, p + 20);
348 }
349 
350 blkerror(ino, type, blk)
351 	ino_t ino;
352 	char *type;
353 	daddr_t blk;
354 {
355 
356 	pfatal("%ld %s I=%u", blk, type, ino);
357 	printf("\n");
358 	switch (statemap[ino]) {
359 
360 	case FSTATE:
361 		statemap[ino] = FCLEAR;
362 		return;
363 
364 	case DSTATE:
365 		statemap[ino] = DCLEAR;
366 		return;
367 
368 	case FCLEAR:
369 	case DCLEAR:
370 		return;
371 
372 	default:
373 		errexit("BAD STATE %d TO BLKERR", statemap[ino]);
374 		/* NOTREACHED */
375 	}
376 }
377 
378 /*
379  * allocate an unused inode
380  */
381 ino_t
382 allocino(request, type)
383 	ino_t request;
384 	int type;
385 {
386 	register ino_t ino;
387 	register struct dinode *dp;
388 
389 	if (request == 0)
390 		request = ROOTINO;
391 	else if (statemap[request] != USTATE)
392 		return (0);
393 	for (ino = request; ino < maxino; ino++)
394 		if (statemap[ino] == USTATE)
395 			break;
396 	if (ino == maxino)
397 		return (0);
398 	switch (type & IFMT) {
399 	case IFDIR:
400 		statemap[ino] = DSTATE;
401 		break;
402 	case IFREG:
403 	case IFLNK:
404 		statemap[ino] = FSTATE;
405 		break;
406 	default:
407 		return (0);
408 	}
409 	dp = ginode(ino);
410 	dp->di_db[0] = allocblk((long)1);
411 	if (dp->di_db[0] == 0) {
412 		statemap[ino] = USTATE;
413 		return (0);
414 	}
415 	dp->di_mode = type;
416 	time(&dp->di_atime);
417 	dp->di_mtime = dp->di_ctime = dp->di_atime;
418 	dp->di_size = sblock.fs_fsize;
419 	dp->di_blocks = btodb(sblock.fs_fsize);
420 	n_files++;
421 	inodirty();
422 	return (ino);
423 }
424 
425 /*
426  * deallocate an inode
427  */
428 freeino(ino)
429 	ino_t ino;
430 {
431 	struct inodesc idesc;
432 	extern int pass4check();
433 	struct dinode *dp;
434 
435 	bzero((char *)&idesc, sizeof(struct inodesc));
436 	idesc.id_type = ADDR;
437 	idesc.id_func = pass4check;
438 	idesc.id_number = ino;
439 	dp = ginode(ino);
440 	(void)ckinode(dp, &idesc);
441 	clearinode(dp);
442 	inodirty();
443 	statemap[ino] = USTATE;
444 	n_files--;
445 }
446