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