checkpoint of hacking for mail.cs.berkeley.edu
[unix-history] / usr / src / sbin / fsck / inode.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 1980, 1986 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8#ifndef lint
9static char sccsid[] = "@(#)inode.c 5.19 (Berkeley) %G%";
10#endif /* not lint */
11
12#include <sys/param.h>
13#include <ufs/ufs/dinode.h>
14#include <ufs/ufs/dir.h>
15#include <ufs/ffs/fs.h>
16#include <pwd.h>
17#include <stdlib.h>
18#include <string.h>
19#include "fsck.h"
20
21static ino_t startinum;
22
23ckinode(dp, idesc)
24 struct dinode *dp;
25 register struct inodesc *idesc;
26{
27 register daddr_t *ap;
28 long ret, n, ndb, offset;
29 struct dinode dino;
30
31 if (idesc->id_fix != IGNORE)
32 idesc->id_fix = DONTKNOW;
33 idesc->id_entryno = 0;
34 idesc->id_filesize = dp->di_size;
35 if ((dp->di_mode & IFMT) == IFBLK || (dp->di_mode & IFMT) == IFCHR)
36 return (KEEPON);
37 dino = *dp;
38 ndb = howmany(dino.di_size, sblock.fs_bsize);
39 for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
40 if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
41 idesc->id_numfrags =
42 numfrags(&sblock, fragroundup(&sblock, offset));
43 else
44 idesc->id_numfrags = sblock.fs_frag;
45 if (*ap == 0)
46 continue;
47 idesc->id_blkno = *ap;
48 if (idesc->id_type == ADDR)
49 ret = (*idesc->id_func)(idesc);
50 else
51 ret = dirscan(idesc);
52 if (ret & STOP)
53 return (ret);
54 }
55 idesc->id_numfrags = sblock.fs_frag;
56 for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
57 if (*ap) {
58 idesc->id_blkno = *ap;
59 ret = iblock(idesc, n,
60 dino.di_size - sblock.fs_bsize * NDADDR);
61 if (ret & STOP)
62 return (ret);
63 }
64 }
65 return (KEEPON);
66}
67
68iblock(idesc, ilevel, isize)
69 struct inodesc *idesc;
70 register long ilevel;
71 u_long isize;
72{
73 register daddr_t *ap;
74 register daddr_t *aplim;
75 int i, n, (*func)(), nif, sizepb;
76 register struct bufarea *bp;
77 char buf[BUFSIZ];
78 extern int dirscan(), pass1check();
79
80 if (idesc->id_type == ADDR) {
81 func = idesc->id_func;
82 if (((n = (*func)(idesc)) & KEEPON) == 0)
83 return (n);
84 } else
85 func = dirscan;
86 if (chkrange(idesc->id_blkno, idesc->id_numfrags))
87 return (SKIP);
88 bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
89 ilevel--;
90 for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
91 sizepb *= NINDIR(&sblock);
92 nif = isize / sizepb + 1;
93 if (nif > NINDIR(&sblock))
94 nif = NINDIR(&sblock);
95 if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
96 aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
97 for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
98 if (*ap == 0)
99 continue;
100 (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu",
101 idesc->id_number);
102 if (dofix(idesc, buf)) {
103 *ap = 0;
104 dirty(bp);
105 }
106 }
107 flush(fswritefd, bp);
108 }
109 aplim = &bp->b_un.b_indir[nif];
110 for (ap = bp->b_un.b_indir, i = 1; ap < aplim; ap++, i++) {
111 if (*ap) {
112 idesc->id_blkno = *ap;
113 if (ilevel > 0)
114 n = iblock(idesc, ilevel, isize - i * sizepb);
115 else
116 n = (*func)(idesc);
117 if (n & STOP) {
118 bp->b_flags &= ~B_INUSE;
119 return (n);
120 }
121 }
122 }
123 bp->b_flags &= ~B_INUSE;
124 return (KEEPON);
125}
126
127/*
128 * Check that a block in a legal block number.
129 * Return 0 if in range, 1 if out of range.
130 */
131chkrange(blk, cnt)
132 daddr_t blk;
133 int cnt;
134{
135 register int c;
136
137 if ((unsigned)(blk + cnt) > maxfsblock)
138 return (1);
139 c = dtog(&sblock, blk);
140 if (blk < cgdmin(&sblock, c)) {
141 if ((blk + cnt) > cgsblock(&sblock, c)) {
142 if (debug) {
143 printf("blk %ld < cgdmin %ld;",
144 blk, cgdmin(&sblock, c));
145 printf(" blk + cnt %ld > cgsbase %ld\n",
146 blk + cnt, cgsblock(&sblock, c));
147 }
148 return (1);
149 }
150 } else {
151 if ((blk + cnt) > cgbase(&sblock, c+1)) {
152 if (debug) {
153 printf("blk %ld >= cgdmin %ld;",
154 blk, cgdmin(&sblock, c));
155 printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
156 blk+cnt, sblock.fs_fpg);
157 }
158 return (1);
159 }
160 }
161 return (0);
162}
163
164/*
165 * General purpose interface for reading inodes.
166 */
167struct dinode *
168ginode(inumber)
169 ino_t inumber;
170{
171 daddr_t iblk;
172
173 if (inumber < ROOTINO || inumber > maxino)
174 errexit("bad inode number %d to ginode\n", inumber);
175 if (startinum == 0 ||
176 inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
177 iblk = itod(&sblock, inumber);
178 if (pbp != 0)
179 pbp->b_flags &= ~B_INUSE;
180 pbp = getdatablk(iblk, sblock.fs_bsize);
181 startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
182 }
183 return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
184}
185
186/*
187 * Special purpose version of ginode used to optimize first pass
188 * over all the inodes in numerical order.
189 */
190ino_t nextino, lastinum;
191long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
192struct dinode *inodebuf;
193
194struct dinode *
195getnextinode(inumber)
196 ino_t inumber;
197{
198 long size;
199 daddr_t dblk;
200 static struct dinode *dp;
201
202 if (inumber != nextino++ || inumber > maxino)
203 errexit("bad inode number %d to nextinode\n", inumber);
204 if (inumber >= lastinum) {
205 readcnt++;
206 dblk = fsbtodb(&sblock, itod(&sblock, lastinum));
207 if (readcnt % readpercg == 0) {
208 size = partialsize;
209 lastinum += partialcnt;
210 } else {
211 size = inobufsize;
212 lastinum += fullcnt;
213 }
214 (void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */
215 dp = inodebuf;
216 }
217 return (dp++);
218}
219
220resetinodebuf()
221{
222
223 startinum = 0;
224 nextino = 0;
225 lastinum = 0;
226 readcnt = 0;
227 inobufsize = blkroundup(&sblock, INOBUFSIZE);
228 fullcnt = inobufsize / sizeof(struct dinode);
229 readpercg = sblock.fs_ipg / fullcnt;
230 partialcnt = sblock.fs_ipg % fullcnt;
231 partialsize = partialcnt * sizeof(struct dinode);
232 if (partialcnt != 0) {
233 readpercg++;
234 } else {
235 partialcnt = fullcnt;
236 partialsize = inobufsize;
237 }
238 if (inodebuf == NULL &&
239 (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL)
240 errexit("Cannot allocate space for inode buffer\n");
241 while (nextino < ROOTINO)
242 (void)getnextinode(nextino);
243}
244
245freeinodebuf()
246{
247
248 if (inodebuf != NULL)
249 free((char *)inodebuf);
250 inodebuf = NULL;
251}
252
253/*
254 * Routines to maintain information about directory inodes.
255 * This is built during the first pass and used during the
256 * second and third passes.
257 *
258 * Enter inodes into the cache.
259 */
260cacheino(dp, inumber)
261 register struct dinode *dp;
262 ino_t inumber;
263{
264 register struct inoinfo *inp;
265 struct inoinfo **inpp;
266 unsigned int blks;
267
268 blks = howmany(dp->di_size, sblock.fs_bsize);
269 if (blks > NDADDR)
270 blks = NDADDR + NIADDR;
271 inp = (struct inoinfo *)
272 malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr_t));
273 if (inp == NULL)
274 return;
275 inpp = &inphead[inumber % numdirs];
276 inp->i_nexthash = *inpp;
277 *inpp = inp;
278 inp->i_parent = (ino_t)0;
279 inp->i_dotdot = (ino_t)0;
280 inp->i_number = inumber;
281 inp->i_isize = dp->di_size;
282 inp->i_numblks = blks * sizeof(daddr_t);
283 bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0],
284 (size_t)inp->i_numblks);
285 if (inplast == listmax) {
286 listmax += 100;
287 inpsort = (struct inoinfo **)realloc((char *)inpsort,
288 (unsigned)listmax * sizeof(struct inoinfo *));
289 if (inpsort == NULL)
290 errexit("cannot increase directory list");
291 }
292 inpsort[inplast++] = inp;
293}
294
295/*
296 * Look up an inode cache structure.
297 */
298struct inoinfo *
299getinoinfo(inumber)
300 ino_t inumber;
301{
302 register struct inoinfo *inp;
303
304 for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
305 if (inp->i_number != inumber)
306 continue;
307 return (inp);
308 }
309 errexit("cannot find inode %d\n", inumber);
310 return ((struct inoinfo *)0);
311}
312
313/*
314 * Clean up all the inode cache structure.
315 */
316inocleanup()
317{
318 register struct inoinfo **inpp;
319
320 if (inphead == NULL)
321 return;
322 for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
323 free((char *)(*inpp));
324 free((char *)inphead);
325 free((char *)inpsort);
326 inphead = inpsort = NULL;
327}
328
329inodirty()
330{
331
332 dirty(pbp);
333}
334
335clri(idesc, type, flag)
336 register struct inodesc *idesc;
337 char *type;
338 int flag;
339{
340 register struct dinode *dp;
341
342 dp = ginode(idesc->id_number);
343 if (flag == 1) {
344 pwarn("%s %s", type,
345 (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
346 pinode(idesc->id_number);
347 }
348 if (preen || reply("CLEAR") == 1) {
349 if (preen)
350 printf(" (CLEARED)\n");
351 n_files--;
352 (void)ckinode(dp, idesc);
353 clearinode(dp);
354 statemap[idesc->id_number] = USTATE;
355 inodirty();
356 }
357}
358
359findname(idesc)
360 struct inodesc *idesc;
361{
362 register struct direct *dirp = idesc->id_dirp;
363
364 if (dirp->d_ino != idesc->id_parent)
365 return (KEEPON);
366 bcopy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1);
367 return (STOP|FOUND);
368}
369
370findino(idesc)
371 struct inodesc *idesc;
372{
373 register struct direct *dirp = idesc->id_dirp;
374
375 if (dirp->d_ino == 0)
376 return (KEEPON);
377 if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
378 dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
379 idesc->id_parent = dirp->d_ino;
380 return (STOP|FOUND);
381 }
382 return (KEEPON);
383}
384
385pinode(ino)
386 ino_t ino;
387{
388 register struct dinode *dp;
389 register char *p;
390 struct passwd *pw;
391 char *ctime();
392
393 printf(" I=%lu ", ino);
394 if (ino < ROOTINO || ino > maxino)
395 return;
396 dp = ginode(ino);
397 printf(" OWNER=");
398 if ((pw = getpwuid((int)dp->di_uid)) != 0)
399 printf("%s ", pw->pw_name);
400 else
401 printf("%u ", (unsigned)dp->di_uid);
402 printf("MODE=%o\n", dp->di_mode);
403 if (preen)
404 printf("%s: ", devname);
405 printf("SIZE=%lu ", dp->di_size);
406 p = ctime(&dp->di_mtime);
407 printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
408}
409
410blkerror(ino, type, blk)
411 ino_t ino;
412 char *type;
413 daddr_t blk;
414{
415
416 pfatal("%ld %s I=%lu", blk, type, ino);
417 printf("\n");
418 switch (statemap[ino]) {
419
420 case FSTATE:
421 statemap[ino] = FCLEAR;
422 return;
423
424 case DSTATE:
425 statemap[ino] = DCLEAR;
426 return;
427
428 case FCLEAR:
429 case DCLEAR:
430 return;
431
432 default:
433 errexit("BAD STATE %d TO BLKERR", statemap[ino]);
434 /* NOTREACHED */
435 }
436}
437
438/*
439 * allocate an unused inode
440 */
441ino_t
442allocino(request, type)
443 ino_t request;
444 int type;
445{
446 register ino_t ino;
447 register struct dinode *dp;
448
449 if (request == 0)
450 request = ROOTINO;
451 else if (statemap[request] != USTATE)
452 return (0);
453 for (ino = request; ino < maxino; ino++)
454 if (statemap[ino] == USTATE)
455 break;
456 if (ino == maxino)
457 return (0);
458 switch (type & IFMT) {
459 case IFDIR:
460 statemap[ino] = DSTATE;
461 break;
462 case IFREG:
463 case IFLNK:
464 statemap[ino] = FSTATE;
465 break;
466 default:
467 return (0);
468 }
469 dp = ginode(ino);
470 dp->di_db[0] = allocblk((long)1);
471 if (dp->di_db[0] == 0) {
472 statemap[ino] = USTATE;
473 return (0);
474 }
475 dp->di_mode = type;
476 (void)time(&dp->di_atime);
477 dp->di_mtime = dp->di_ctime = dp->di_atime;
478 dp->di_size = sblock.fs_fsize;
479 dp->di_blocks = btodb(sblock.fs_fsize);
480 n_files++;
481 inodirty();
482 return (ino);
483}
484
485/*
486 * deallocate an inode
487 */
488freeino(ino)
489 ino_t ino;
490{
491 struct inodesc idesc;
492 extern int pass4check();
493 struct dinode *dp;
494
495 bzero((char *)&idesc, sizeof(struct inodesc));
496 idesc.id_type = ADDR;
497 idesc.id_func = pass4check;
498 idesc.id_number = ino;
499 dp = ginode(ino);
500 (void)ckinode(dp, &idesc);
501 clearinode(dp);
502 inodirty();
503 statemap[ino] = USTATE;
504 n_files--;
505}