xref: /original-bsd/sbin/fsck/inode.c (revision 96e323b4)
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.7 (Berkeley) 03/05/89";
9 #endif not lint
10 
11 #include <sys/param.h>
12 #include <sys/inode.h>
13 #include <sys/fs.h>
14 #include <sys/dir.h>
15 #include <pwd.h>
16 #include "fsck.h"
17 
18 BUFAREA *pbp = 0;
19 
20 ckinode(dp, idesc)
21 	DINODE *dp;
22 	register struct inodesc *idesc;
23 {
24 	register daddr_t *ap;
25 	int ret, n, ndb, offset;
26 	DINODE dino;
27 
28 	idesc->id_fix = DONTKNOW;
29 	idesc->id_entryno = 0;
30 	idesc->id_filesize = dp->di_size;
31 	if (SPECIAL(dp))
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 ilevel;
67 	long isize;
68 {
69 	register daddr_t *ap;
70 	register daddr_t *aplim;
71 	int i, n, (*func)(), nif, sizepb;
72 	register 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 (outrange(idesc->id_blkno, idesc->id_numfrags)) /* protect thyself */
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(&dfile, 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 outrange(blk, cnt)
124 	daddr_t blk;
125 	int cnt;
126 {
127 	register int c;
128 
129 	if ((unsigned)(blk+cnt) > fmax)
130 		return (1);
131 	c = dtog(&sblock, blk);
132 	if (blk < cgdmin(&sblock, c)) {
133 		if ((blk+cnt) > cgsblock(&sblock, c)) {
134 			if (debug) {
135 				printf("blk %d < cgdmin %d;",
136 				    blk, cgdmin(&sblock, c));
137 				printf(" blk+cnt %d > cgsbase %d\n",
138 				    blk+cnt, cgsblock(&sblock, c));
139 			}
140 			return (1);
141 		}
142 	} else {
143 		if ((blk+cnt) > cgbase(&sblock, c+1)) {
144 			if (debug)  {
145 				printf("blk %d >= cgdmin %d;",
146 				    blk, cgdmin(&sblock, c));
147 				printf(" blk+cnt %d > sblock.fs_fpg %d\n",
148 				    blk+cnt, sblock.fs_fpg);
149 			}
150 			return (1);
151 		}
152 	}
153 	return (0);
154 }
155 
156 DINODE *
157 ginode(inumber)
158 	ino_t inumber;
159 {
160 	daddr_t iblk;
161 	static ino_t startinum = 0;	/* blk num of first in raw area */
162 
163 	if (inumber < ROOTINO || inumber > imax)
164 		errexit("bad inode number %d to ginode\n", inumber);
165 	if (startinum == 0 ||
166 	    inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
167 		iblk = itod(&sblock, inumber);
168 		if (pbp != 0)
169 			pbp->b_flags &= ~B_INUSE;
170 		pbp = getdatablk(iblk, sblock.fs_bsize);
171 		startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
172 	}
173 	return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
174 }
175 
176 inodirty()
177 {
178 
179 	dirty(pbp);
180 }
181 
182 clri(idesc, s, flg)
183 	register struct inodesc *idesc;
184 	char *s;
185 	int flg;
186 {
187 	register DINODE *dp;
188 
189 	dp = ginode(idesc->id_number);
190 	if (flg == 1) {
191 		pwarn("%s %s", s, DIRCT(dp) ? "DIR" : "FILE");
192 		pinode(idesc->id_number);
193 	}
194 	if (preen || reply("CLEAR") == 1) {
195 		if (preen)
196 			printf(" (CLEARED)\n");
197 		n_files--;
198 		(void)ckinode(dp, idesc);
199 		zapino(dp);
200 		statemap[idesc->id_number] = USTATE;
201 		inodirty();
202 	}
203 }
204 
205 findname(idesc)
206 	struct inodesc *idesc;
207 {
208 	register DIRECT *dirp = idesc->id_dirp;
209 
210 	if (dirp->d_ino != idesc->id_parent)
211 		return (KEEPON);
212 	bcopy(dirp->d_name, idesc->id_name, dirp->d_namlen + 1);
213 	return (STOP|FOUND);
214 }
215 
216 findino(idesc)
217 	struct inodesc *idesc;
218 {
219 	register DIRECT *dirp = idesc->id_dirp;
220 
221 	if (dirp->d_ino == 0)
222 		return (KEEPON);
223 	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
224 	    dirp->d_ino >= ROOTINO && dirp->d_ino <= imax) {
225 		idesc->id_parent = dirp->d_ino;
226 		return (STOP|FOUND);
227 	}
228 	return (KEEPON);
229 }
230 
231 pinode(ino)
232 	ino_t ino;
233 {
234 	register DINODE *dp;
235 	register char *p;
236 	struct passwd *pw;
237 	char *ctime();
238 
239 	printf(" I=%u ", ino);
240 	if (ino < ROOTINO || ino > imax)
241 		return;
242 	dp = ginode(ino);
243 	printf(" OWNER=");
244 	if ((pw = getpwuid((int)dp->di_uid)) != 0)
245 		printf("%s ", pw->pw_name);
246 	else
247 		printf("%d ", dp->di_uid);
248 	printf("MODE=%o\n", dp->di_mode);
249 	if (preen)
250 		printf("%s: ", devname);
251 	printf("SIZE=%ld ", dp->di_size);
252 	p = ctime(&dp->di_mtime);
253 	printf("MTIME=%12.12s %4.4s ", p+4, p+20);
254 }
255 
256 blkerr(ino, s, blk)
257 	ino_t ino;
258 	char *s;
259 	daddr_t blk;
260 {
261 
262 	pfatal("%ld %s I=%u", blk, s, ino);
263 	printf("\n");
264 	switch (statemap[ino]) {
265 
266 	case FSTATE:
267 		statemap[ino] = FCLEAR;
268 		return;
269 
270 	case DSTATE:
271 		statemap[ino] = DCLEAR;
272 		return;
273 
274 	case FCLEAR:
275 	case DCLEAR:
276 		return;
277 
278 	default:
279 		errexit("BAD STATE %d TO BLKERR", statemap[ino]);
280 		/* NOTREACHED */
281 	}
282 }
283 
284 /*
285  * allocate an unused inode
286  */
287 ino_t
288 allocino(request, type)
289 	ino_t request;
290 	int type;
291 {
292 	register ino_t ino;
293 	register DINODE *dp;
294 
295 	if (request == 0)
296 		request = ROOTINO;
297 	else if (statemap[request] != USTATE)
298 		return (0);
299 	for (ino = request; ino < imax; ino++)
300 		if (statemap[ino] == USTATE)
301 			break;
302 	if (ino == imax)
303 		return (0);
304 	switch (type & IFMT) {
305 	case IFDIR:
306 		statemap[ino] = DSTATE;
307 		break;
308 	case IFREG:
309 	case IFLNK:
310 		statemap[ino] = FSTATE;
311 		break;
312 	default:
313 		return (0);
314 	}
315 	dp = ginode(ino);
316 	dp->di_db[0] = allocblk(1);
317 	if (dp->di_db[0] == 0) {
318 		statemap[ino] = USTATE;
319 		return (0);
320 	}
321 	dp->di_mode = type;
322 	time(&dp->di_atime);
323 	dp->di_mtime = dp->di_ctime = dp->di_atime;
324 	dp->di_size = sblock.fs_fsize;
325 	dp->di_blocks = btodb(sblock.fs_fsize);
326 	n_files++;
327 	inodirty();
328 	return (ino);
329 }
330 
331 /*
332  * deallocate an inode
333  */
334 freeino(ino)
335 	ino_t ino;
336 {
337 	struct inodesc idesc;
338 	extern int pass4check();
339 	DINODE *dp;
340 
341 	bzero((char *)&idesc, sizeof(struct inodesc));
342 	idesc.id_type = ADDR;
343 	idesc.id_func = pass4check;
344 	idesc.id_number = ino;
345 	dp = ginode(ino);
346 	(void)ckinode(dp, &idesc);
347 	zapino(dp);
348 	inodirty();
349 	statemap[ino] = USTATE;
350 	n_files--;
351 }
352