xref: /csrg-svn/sbin/fsck/inode.c (revision 39973)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)inode.c	5.10 (Berkeley) 02/01/90";
9 #endif not lint
10 
11 #include <sys/param.h>
12 #include <ufs/dinode.h>
13 #include <ufs/fs.h>
14 #include <ufs/dir.h>
15 #include <pwd.h>
16 #include "fsck.h"
17 
18 struct bufarea *pbp = 0;
19 
20 ckinode(dp, idesc)
21 	struct dinode *dp;
22 	register struct inodesc *idesc;
23 {
24 	register daddr_t *ap;
25 	long ret, n, ndb, offset;
26 	struct dinode dino;
27 
28 	idesc->id_fix = DONTKNOW;
29 	idesc->id_entryno = 0;
30 	idesc->id_filesize = dp->di_size;
31 	if ((dp->di_mode & IFMT) == IFBLK || (dp->di_mode & IFMT) == IFCHR)
32 		return (KEEPON);
33 	dino = *dp;
34 	ndb = howmany(dino.di_size, sblock.fs_bsize);
35 	for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
36 		if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
37 			idesc->id_numfrags =
38 				numfrags(&sblock, fragroundup(&sblock, offset));
39 		else
40 			idesc->id_numfrags = sblock.fs_frag;
41 		if (*ap == 0)
42 			continue;
43 		idesc->id_blkno = *ap;
44 		if (idesc->id_type == ADDR)
45 			ret = (*idesc->id_func)(idesc);
46 		else
47 			ret = dirscan(idesc);
48 		if (ret & STOP)
49 			return (ret);
50 	}
51 	idesc->id_numfrags = sblock.fs_frag;
52 	for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
53 		if (*ap) {
54 			idesc->id_blkno = *ap;
55 			ret = iblock(idesc, n,
56 				dino.di_size - sblock.fs_bsize * NDADDR);
57 			if (ret & STOP)
58 				return (ret);
59 		}
60 	}
61 	return (KEEPON);
62 }
63 
64 iblock(idesc, ilevel, isize)
65 	struct inodesc *idesc;
66 	register long ilevel;
67 	long isize;
68 {
69 	register daddr_t *ap;
70 	register daddr_t *aplim;
71 	int i, n, (*func)(), nif, sizepb;
72 	register struct bufarea *bp;
73 	char buf[BUFSIZ];
74 	extern int dirscan(), pass1check();
75 
76 	if (idesc->id_type == ADDR) {
77 		func = idesc->id_func;
78 		if (((n = (*func)(idesc)) & KEEPON) == 0)
79 			return (n);
80 	} else
81 		func = dirscan;
82 	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
83 		return (SKIP);
84 	bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
85 	ilevel--;
86 	for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
87 		sizepb *= NINDIR(&sblock);
88 	nif = isize / sizepb + 1;
89 	if (nif > NINDIR(&sblock))
90 		nif = NINDIR(&sblock);
91 	if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
92 		aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
93 		for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
94 			if (*ap == 0)
95 				continue;
96 			(void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%d",
97 				idesc->id_number);
98 			if (dofix(idesc, buf)) {
99 				*ap = 0;
100 				dirty(bp);
101 			}
102 		}
103 		flush(fswritefd, bp);
104 	}
105 	aplim = &bp->b_un.b_indir[nif];
106 	for (ap = bp->b_un.b_indir, i = 1; ap < aplim; ap++, i++) {
107 		if (*ap) {
108 			idesc->id_blkno = *ap;
109 			if (ilevel > 0)
110 				n = iblock(idesc, ilevel, isize - i * sizepb);
111 			else
112 				n = (*func)(idesc);
113 			if (n & STOP) {
114 				bp->b_flags &= ~B_INUSE;
115 				return (n);
116 			}
117 		}
118 	}
119 	bp->b_flags &= ~B_INUSE;
120 	return (KEEPON);
121 }
122 
123 /*
124  * Check that a block in a legal block number.
125  * Return 0 if in range, 1 if out of range.
126  */
127 chkrange(blk, cnt)
128 	daddr_t blk;
129 	int cnt;
130 {
131 	register int c;
132 
133 	if ((unsigned)(blk + cnt) > maxfsblock)
134 		return (1);
135 	c = dtog(&sblock, blk);
136 	if (blk < cgdmin(&sblock, c)) {
137 		if ((blk + cnt) > cgsblock(&sblock, c)) {
138 			if (debug) {
139 				printf("blk %d < cgdmin %d;",
140 				    blk, cgdmin(&sblock, c));
141 				printf(" blk + cnt %d > cgsbase %d\n",
142 				    blk + cnt, cgsblock(&sblock, c));
143 			}
144 			return (1);
145 		}
146 	} else {
147 		if ((blk + cnt) > cgbase(&sblock, c+1)) {
148 			if (debug)  {
149 				printf("blk %d >= cgdmin %d;",
150 				    blk, cgdmin(&sblock, c));
151 				printf(" blk + cnt %d > sblock.fs_fpg %d\n",
152 				    blk+cnt, sblock.fs_fpg);
153 			}
154 			return (1);
155 		}
156 	}
157 	return (0);
158 }
159 
160 struct dinode *
161 ginode(inumber)
162 	ino_t inumber;
163 {
164 	daddr_t iblk;
165 	static ino_t startinum = 0;
166 
167 	if (inumber < ROOTINO || inumber > maxino)
168 		errexit("bad inode number %d to ginode\n", inumber);
169 	if (startinum == 0 ||
170 	    inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
171 		iblk = itod(&sblock, inumber);
172 		if (pbp != 0)
173 			pbp->b_flags &= ~B_INUSE;
174 		pbp = getdatablk(iblk, sblock.fs_bsize);
175 		startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
176 	}
177 	return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
178 }
179 
180 inodirty()
181 {
182 
183 	dirty(pbp);
184 }
185 
186 clri(idesc, type, flag)
187 	register struct inodesc *idesc;
188 	char *type;
189 	int flag;
190 {
191 	register struct dinode *dp;
192 
193 	dp = ginode(idesc->id_number);
194 	if (flag == 1) {
195 		pwarn("%s %s", type,
196 		    (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
197 		pinode(idesc->id_number);
198 	}
199 	if (preen || reply("CLEAR") == 1) {
200 		if (preen)
201 			printf(" (CLEARED)\n");
202 		n_files--;
203 		(void)ckinode(dp, idesc);
204 		clearinode(dp);
205 		statemap[idesc->id_number] = USTATE;
206 		inodirty();
207 	}
208 }
209 
210 findname(idesc)
211 	struct inodesc *idesc;
212 {
213 	register struct direct *dirp = idesc->id_dirp;
214 
215 	if (dirp->d_ino != idesc->id_parent)
216 		return (KEEPON);
217 	bcopy(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1);
218 	return (STOP|FOUND);
219 }
220 
221 findino(idesc)
222 	struct inodesc *idesc;
223 {
224 	register struct direct *dirp = idesc->id_dirp;
225 
226 	if (dirp->d_ino == 0)
227 		return (KEEPON);
228 	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
229 	    dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
230 		idesc->id_parent = dirp->d_ino;
231 		return (STOP|FOUND);
232 	}
233 	return (KEEPON);
234 }
235 
236 pinode(ino)
237 	ino_t ino;
238 {
239 	register struct dinode *dp;
240 	register char *p;
241 	struct passwd *pw;
242 	char *ctime();
243 
244 	printf(" I=%u ", ino);
245 	if (ino < ROOTINO || ino > maxino)
246 		return;
247 	dp = ginode(ino);
248 	printf(" OWNER=");
249 	if ((pw = getpwuid((int)dp->di_uid)) != 0)
250 		printf("%s ", pw->pw_name);
251 	else
252 		printf("%d ", dp->di_uid);
253 	printf("MODE=%o\n", dp->di_mode);
254 	if (preen)
255 		printf("%s: ", devname);
256 	printf("SIZE=%ld ", dp->di_size);
257 	p = ctime(&dp->di_mtime);
258 	printf("MTIME=%12.12s %4.4s ", p + 4, p + 20);
259 }
260 
261 blkerror(ino, type, blk)
262 	ino_t ino;
263 	char *type;
264 	daddr_t blk;
265 {
266 
267 	pfatal("%ld %s I=%u", blk, type, ino);
268 	printf("\n");
269 	switch (statemap[ino]) {
270 
271 	case FSTATE:
272 		statemap[ino] = FCLEAR;
273 		return;
274 
275 	case DSTATE:
276 		statemap[ino] = DCLEAR;
277 		return;
278 
279 	case FCLEAR:
280 	case DCLEAR:
281 		return;
282 
283 	default:
284 		errexit("BAD STATE %d TO BLKERR", statemap[ino]);
285 		/* NOTREACHED */
286 	}
287 }
288 
289 /*
290  * allocate an unused inode
291  */
292 ino_t
293 allocino(request, type)
294 	ino_t request;
295 	int type;
296 {
297 	register ino_t ino;
298 	register struct dinode *dp;
299 
300 	if (request == 0)
301 		request = ROOTINO;
302 	else if (statemap[request] != USTATE)
303 		return (0);
304 	for (ino = request; ino < maxino; ino++)
305 		if (statemap[ino] == USTATE)
306 			break;
307 	if (ino == maxino)
308 		return (0);
309 	switch (type & IFMT) {
310 	case IFDIR:
311 		statemap[ino] = DSTATE;
312 		break;
313 	case IFREG:
314 	case IFLNK:
315 		statemap[ino] = FSTATE;
316 		break;
317 	default:
318 		return (0);
319 	}
320 	dp = ginode(ino);
321 	dp->di_db[0] = allocblk((long)1);
322 	if (dp->di_db[0] == 0) {
323 		statemap[ino] = USTATE;
324 		return (0);
325 	}
326 	dp->di_mode = type;
327 	time(&dp->di_atime);
328 	dp->di_mtime = dp->di_ctime = dp->di_atime;
329 	dp->di_size = sblock.fs_fsize;
330 	dp->di_blocks = btodb(sblock.fs_fsize);
331 	n_files++;
332 	inodirty();
333 	return (ino);
334 }
335 
336 /*
337  * deallocate an inode
338  */
339 freeino(ino)
340 	ino_t ino;
341 {
342 	struct inodesc idesc;
343 	extern int pass4check();
344 	struct dinode *dp;
345 
346 	bzero((char *)&idesc, sizeof(struct inodesc));
347 	idesc.id_type = ADDR;
348 	idesc.id_func = pass4check;
349 	idesc.id_number = ino;
350 	dp = ginode(ino);
351 	(void)ckinode(dp, &idesc);
352 	clearinode(dp);
353 	inodirty();
354 	statemap[ino] = USTATE;
355 	n_files--;
356 }
357