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