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