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