|
|
1.1 root 1: static char *sccsid = "@(#)fsck.c 4.13 (Berkeley) 81/03/09";
2: #include <stdio.h>
3: #include <ctype.h>
4: #include <sys/param.h>
5: #include <sys/filsys.h>
6: #include <sys/dir.h>
7: #include <sys/fblk.h>
8: #include <sys/ino.h>
9: #include <sys/inode.h>
10: #include <sys/stat.h>
11: #include <fstab.h>
12: #include <pwd.h>
13:
14: /*typedef int (*SIG_TYP)();*/
15:
16: #define BIG 64 /* 4k file systems */
17: #define SMALL 0 /* 1k file systems */
18: #define NDIRECT(x) (BSIZE(x)/sizeof(struct direct))
19: #define SPERB(x) (BSIZE(x)/sizeof(short))
20:
21: #define NO 0
22: #define YES 1
23:
24: #define MAXDUP 10 /* limit on dup blks (per inode) */
25: #define MAXBAD 10 /* limit on bad blks (per inode) */
26:
27: #define STEPSIZE 9 /* default step for freelist spacing */
28: #define CYLSIZE 400 /* default cyl size for spacing */
29: #define MAXCYL 1000 /* maximum cylinder size */
30:
31: #define BITSPB 8 /* number bits per byte */
32: #define BITSHIFT 3 /* log2(BITSPB) */
33: #define BITMASK 07 /* BITSPB-1 */
34: #define LSTATE 2 /* bits per inode state */
35: #define STATEPB (BITSPB/LSTATE) /* inode states per byte */
36: #define USTATE 0 /* inode not allocated */
37: #define FSTATE 01 /* inode is file */
38: #define DSTATE 02 /* inode is directory */
39: #define CLEAR 03 /* inode is to be cleared */
40: #define SMASK 03 /* mask for inode state */
41:
42: typedef struct dinode DINODE;
43: typedef struct direct DIRECT;
44:
45: #define ALLOC ((dp->di_mode & IFMT) != 0)
46: #define DIR ((dp->di_mode & IFMT) == IFDIR)
47: #define REG ((dp->di_mode & IFMT) == IFREG)
48: #define BLK ((dp->di_mode & IFMT) == IFBLK)
49: #define CHR ((dp->di_mode & IFMT) == IFCHR)
50: #define MPC ((dp->di_mode & IFMT) == IFMPC)
51: #define MPB ((dp->di_mode & IFMT) == IFMPB)
52: #define LNK ((dp->di_mode & IFMT) == IFLNK)
53: #define SPECIAL (BLK || CHR /* || MPC || MPB */ )
54:
55: #define NINOBLK 11 /* num blks for raw reading */
56: #define MAXRAW 110 /* largest raw read (in blks) */
57: daddr_t startib; /* blk num of first in raw area */
58: unsigned niblk; /* num of blks in raw area */
59:
60: struct bufarea {
61: struct bufarea *b_next; /* must be first */
62: daddr_t b_bno;
63: union {
64: char b_buf[BSIZE(BIG)]; /* buffer space */
65: short b_lnks[SPERB(BIG)]; /* link counts */
66: daddr_t b_indir[NINDIR(BIG)]; /* indirect block */
67: struct filsys b_fs; /* super block */
68: struct fblk b_fb; /* free block */
69: struct dinode b_dinode[INOPB(BIG)]; /* inode block */
70: DIRECT b_dir[NDIRECT(BIG)]; /* directory */
71: } b_un;
72: char b_dirty;
73: };
74:
75: typedef struct bufarea BUFAREA;
76:
77: BUFAREA inoblk; /* inode blocks */
78: BUFAREA fileblk; /* other blks in filesys */
79: BUFAREA sblk; /* file system superblock */
80: BUFAREA *poolhead; /* ptr to first buffer in pool */
81:
82: #define initbarea(x) (x)->b_dirty = 0;(x)->b_bno = (daddr_t)-1
83: #define dirty(x) (x)->b_dirty = 1
84: #define inodirty() inoblk.b_dirty = 1
85: #define fbdirty() fileblk.b_dirty = 1
86: #define sbdirty() sblk.b_dirty = 1
87:
88: #define freeblk fileblk.b_un.b_fb
89: #define dirblk fileblk.b_un
90: #define superblk sblk.b_un.b_fs
91:
92: struct filecntl {
93: int rfdes;
94: int wfdes;
95: int mod;
96: };
97:
98: struct filecntl dfile; /* file descriptors for filesys */
99: struct filecntl sfile; /* file descriptors for scratch file */
100:
101: typedef unsigned MEMSIZE;
102:
103: MEMSIZE memsize; /* amt of memory we got */
104: #ifdef pdp11
105: #define MAXDATA ((MEMSIZE)54*1024)
106: #endif
107: #ifdef vax
108: #define MAXDATA ((MEMSIZE)400*1024)
109: #endif
110: #ifdef mc68000
111: #define MAXDATA ((MEMSIZE)500*1024)
112: #endif
113:
114: #define DUPTBLSIZE 100 /* num of dup blocks to remember */
115: daddr_t duplist[DUPTBLSIZE]; /* dup block table */
116: daddr_t *enddup; /* next entry in dup table */
117: daddr_t *muldup; /* multiple dups part of table */
118:
119: #define MAXLNCNT 500 /* num zero link cnts to remember */
120: ino_t badlncnt[MAXLNCNT]; /* table of inos with zero link cnts */
121: ino_t *badlnp; /* next entry in table */
122:
123: char sflag; /* salvage free block list */
124: char csflag; /* salvage free block list (conditional) */
125: char nflag; /* assume a no response */
126: char yflag; /* assume a yes response */
127: char tflag; /* scratch file specified */
128: char preen; /* just fix normal inconsistencies */
129: char rplyflag; /* any questions asked? */
130: char hotroot; /* checking root device */
131: char rawflg; /* read raw device */
132: char rmscr; /* remove scratch file when done */
133: char fixfree; /* corrupted free list */
134: char *membase; /* base of memory we get */
135: char *blkmap; /* ptr to primary blk allocation map */
136: char *freemap; /* ptr to secondary blk allocation map */
137: char *statemap; /* ptr to inode state table */
138: char *pathp; /* pointer to pathname position */
139: char *thisname; /* ptr to current pathname component */
140: char *srchname; /* name being searched for in dir */
141: char pathname[200];
142: char scrfile[80];
143: char *lfname = "lost+found";
144: char *checklist = FSTAB;
145: char big; /* it is a 4k file system */
146:
147: short *lncntp; /* ptr to link count table */
148:
149: int cylsize; /* num blocks per cylinder */
150: int stepsize; /* num blocks for spacing purposes */
151: int badblk; /* num of bad blks seen (per inode) */
152: int dupblk; /* num of dup blks seen (per inode) */
153: int (*pfunc)(); /* function to call to chk blk */
154:
155: ino_t inum; /* inode we are currently working on */
156: ino_t imax; /* number of inodes */
157: ino_t parentdir; /* i number of parent directory */
158: ino_t lastino; /* hiwater mark of inodes */
159: ino_t lfdir; /* lost & found directory */
160: ino_t orphan; /* orphaned inode */
161:
162: off_t filsize; /* num blks seen in file */
163: off_t maxblk; /* largest logical blk in file */
164: off_t bmapsz; /* num chars in blkmap */
165:
166: daddr_t smapblk; /* starting blk of state map */
167: daddr_t lncntblk; /* starting blk of link cnt table */
168: daddr_t fmapblk; /* starting blk of free map */
169: daddr_t n_free; /* number of free blocks */
170: daddr_t n_blks; /* number of blocks used */
171: daddr_t n_files; /* number of files seen */
172: daddr_t fmin; /* block number of the first data block */
173: daddr_t fmax; /* number of blocks in the volume */
174:
175: #define howmany(x,y) (((x)+((y)-1))/(y))
176: #define roundup(x,y) ((((x)+((y)-1))/(y))*(y))
177: #define outrange(x) (x < fmin || x >= fmax)
178: #define zapino(x) clear((char *)(x),sizeof(DINODE))
179:
180: #define setlncnt(x) dolncnt(x,0)
181: #define getlncnt() dolncnt(0,1)
182: #define declncnt() dolncnt(0,2)
183:
184: #define setbmap(x) domap(x,0)
185: #define getbmap(x) domap(x,1)
186: #define clrbmap(x) domap(x,2)
187:
188: #define setfmap(x) domap(x,0+4)
189: #define getfmap(x) domap(x,1+4)
190: #define clrfmap(x) domap(x,2+4)
191:
192: #define setstate(x) dostate(x,0)
193: #define getstate() dostate(0,1)
194:
195: #define DATA 1
196: #define ADDR 0
197: #define ALTERD 010
198: #define KEEPON 04
199: #define SKIP 02
200: #define STOP 01
201:
202: int (*signal())();
203: long lseek();
204: long time();
205: DINODE *ginode();
206: BUFAREA *getblk();
207: BUFAREA *search();
208: int dirscan();
209: int findino();
210: int catch();
211: int mkentry();
212: int chgdd();
213: int pass1();
214: int pass1b();
215: int pass2();
216: int pass3();
217: int pass4();
218: int pass5();
219:
220: char *devname;
221:
222: main(argc,argv)
223: int argc;
224: char *argv[];
225: {
226: register FILE *fp;
227: register n;
228: register char *p;
229: char filename[50];
230: char *sbrk();
231:
232: sync();
233: while(--argc > 0 && **++argv == '-') {
234: switch(*++*argv) {
235: case 'p':
236: preen++;
237: break;
238: case 't':
239: case 'T':
240: tflag++;
241: if(**++argv == '-' || --argc <= 0)
242: errexit("Bad -t option\n");
243: p = scrfile;
244: while(*p++ = **argv)
245: (*argv)++;
246: break;
247: case 's': /* salvage flag */
248: stype(++*argv);
249: sflag++;
250: break;
251: case 'S': /* conditional salvage */
252: stype(++*argv);
253: csflag++;
254: break;
255: case 'n': /* default no answer flag */
256: case 'N':
257: nflag++;
258: yflag = 0;
259: break;
260: case 'y': /* default yes answer flag */
261: case 'Y':
262: yflag++;
263: nflag = 0;
264: break;
265: default:
266: errexit("%c option?\n",**argv);
267: }
268: }
269: if(nflag && (sflag || csflag))
270: errexit("Incompatible options: -n and -%s\n",sflag?"s":"S");
271: if(sflag && csflag)
272: sflag = 0;
273: memsize = (MEMSIZE)sbrk(0);
274: memsize = MAXDATA - memsize - sizeof(int);
275: while(memsize >= 2*sizeof(BUFAREA) &&
276: (membase = sbrk(memsize)) == (char *)-1)
277: memsize -= 1024;
278: if(memsize < 2*sizeof(BUFAREA))
279: errexit("Can't get memory\n");
280: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
281: signal(SIGINT, catch);
282: if(argc) { /* arg list has file names */
283: while(argc-- > 0){
284: hotroot = 0;
285: check(*argv++);
286: }
287: }
288: else { /* use default checklist */
289: struct fstab *fsp;
290: int pid, passno, anygtr, sumstatus = 0;
291: passno = 1;
292: do {
293: anygtr = 0;
294: if (setfsent() == 0)
295: errexit("Can't open checklist file: %s\n",
296: FSTAB);
297: while ( (fsp = getfsent()) != 0){
298: if (strcmp(fsp->fs_type, FSTAB_RW) &&
299: strcmp(fsp->fs_type, FSTAB_RO))
300: continue;
301: if (preen == 0 ||
302: passno == 1 && fsp->fs_passno == passno) {
303: if (blockcheck(fsp->fs_spec) == NO &&
304: preen)
305: exit(8);
306: } else if (fsp->fs_passno > passno)
307: anygtr = 1;
308: else if (fsp->fs_passno == passno) {
309: pid = fork();
310: if (pid < 0) {
311: perror("fork");
312: exit(8);
313: }
314: if (pid == 0)
315: if (blockcheck(fsp->fs_spec)==NO)
316: exit(8);
317: else
318: exit(0);
319: }
320: }
321: if (preen) {
322: int status;
323: while (wait(&status) != -1)
324: sumstatus |= status;
325: }
326: passno++;
327: } while (anygtr);
328: if (sumstatus)
329: exit(8);
330: endfsent();
331: }
332: exit(0);
333: }
334:
335: char *rawname(), *strrchr(), *unrawname();
336:
337: blockcheck(name)
338: char *name;
339: {
340: struct stat stat_slash, stat_block, stat_char;
341: char *raw;
342: int looped = 0;
343:
344: hotroot = 0;
345: if (stat("/", &stat_slash) < 0){
346: error("Can't stat root\n");
347: return(NO);
348: }
349: retry:
350: if (stat(name, &stat_block) < 0){
351: error("Can't stat %s\n", name);
352: return(NO);
353: }
354: big = SMALL; /* 1k blocks by default */
355: if (stat_block.st_mode & S_IFBLK){
356: if(BITFS(stat_block.st_rdev))
357: big = BIG; /* a 4k file system */
358: raw = rawname(name);
359: if (stat(raw, &stat_char) < 0){
360: error("Can't stat %s\n", raw);
361: return(NO);
362: }
363: if (stat_char.st_mode & S_IFCHR){
364: if (stat_slash.st_dev == stat_block.st_rdev) {
365: hotroot++;
366: raw = unrawname(name);
367: }
368: check(raw);
369: return(YES);
370: } else if(big == BIG) {
371: check(name);
372: return(YES);
373: } else {
374: error("%s is not a character device\n", raw);
375: return(NO);
376: }
377: } else
378: if (stat_block.st_mode & S_IFCHR){
379: if (looped) {
380: error("Can't make sense out of name %s\n", name);
381: return(NO);
382: }
383: name = unrawname(name);
384: looped++;
385: goto retry;
386: }
387: error("Can't make sense out of name %s\n", name);
388: return(NO);
389: }
390:
391: char *
392: unrawname(cp)
393: char *cp;
394: {
395: char *dp = strrchr(cp, '/');
396: struct stat stb;
397: if (dp == 0)
398: return(cp);
399: if (stat(cp, &stb) < 0)
400: return(cp);
401: if ((stb.st_mode&S_IFMT) != S_IFCHR)
402: return(cp);
403: if (*(dp+1) != 'r')
404: return(cp);
405: strcpy(dp+1, dp+2);
406: return(cp);
407: }
408:
409: char *
410: rawname(cp)
411: char *cp;
412: {
413: static char rawbuf[32];
414: char *dp = strrchr(cp, '/');
415:
416: if (dp == 0)
417: return (0);
418: if(big == BIG)
419: return(cp);
420: *dp = 0;
421: strcpy(rawbuf, cp);
422: *dp = '/';
423: strcat(rawbuf, "/r");
424: strcat(rawbuf, dp+1);
425: return (rawbuf);
426: }
427:
428: check(dev)
429: char *dev;
430: {
431:
432: devname = dev;
433: check1(dev);
434: devname = 0;
435: }
436:
437: check1(dev)
438: char *dev;
439: {
440: register DINODE *dp;
441: register n;
442: register ino_t *blp;
443: ino_t savino;
444: daddr_t blk;
445: BUFAREA *bp1, *bp2;
446:
447: if(setup(dev) == NO)
448: return;
449: if (preen==0) {
450: printf("** Checking %s\n", dev);
451: printf("** Phase 1 - Check Blocks and Sizes\n");
452: }
453: pfunc = pass1;
454: for(inum = 1; inum <= imax; inum++) {
455: if((dp = ginode()) == NULL)
456: continue;
457: if(ALLOC) {
458: lastino = inum;
459: if(ftypeok(dp) == NO) {
460: pfatal("UNKNOWN FILE TYPE I=%u",inum);
461: if(reply("CLEAR") == YES) {
462: zapino(dp);
463: inodirty();
464: }
465: continue;
466: }
467: n_files++;
468: if(setlncnt(dp->di_nlink) <= 0) {
469: if(badlnp < &badlncnt[MAXLNCNT])
470: *badlnp++ = inum;
471: else {
472: pfatal("LINK COUNT TABLE OVERFLOW");
473: if(reply("CONTINUE") == NO)
474: errexit("");
475: }
476: }
477: setstate(DIR ? DSTATE : FSTATE);
478: badblk = dupblk = 0;
479: filsize = 0;
480: maxblk = 0;
481: ckinode(dp,ADDR);
482: if((n = getstate()) == DSTATE || n == FSTATE)
483: sizechk(dp);
484: }
485: else if(dp->di_mode != 0) {
486: pfatal("PARTIALLY ALLOCATED INODE I=%u",inum);
487: if(reply("CLEAR") == YES) {
488: zapino(dp);
489: inodirty();
490: }
491: }
492: }
493:
494:
495: if(enddup != &duplist[0]) {
496: if (preen)
497: pfatal("INTERNAL ERROR: dups with -p");
498: printf("** Phase 1b - Rescan For More DUPS\n");
499: pfunc = pass1b;
500: for(inum = 1; inum <= lastino; inum++) {
501: if(getstate() != USTATE && (dp = ginode()) != NULL)
502: if(ckinode(dp,ADDR) & STOP)
503: break;
504: }
505: }
506: if(rawflg) { /* shouldn't be set for 4k system */
507: if(inoblk.b_dirty)
508: bwrite(&dfile,membase,startib,(int)niblk*BSIZE(big));
509: inoblk.b_dirty = 0;
510: if(poolhead) {
511: clear(membase,niblk*BSIZE(BIG));
512: for(bp1 = poolhead;bp1->b_next;bp1 = bp1->b_next);
513: bp2 = &((BUFAREA *)membase)[(niblk*BSIZE(BIG))/sizeof(BUFAREA)];
514: while(--bp2 >= (BUFAREA *)membase) {
515: initbarea(bp2);
516: bp2->b_next = bp1->b_next;
517: bp1->b_next = bp2;
518: }
519: }
520: rawflg = 0;
521:
522: }
523:
524:
525: if (preen == 0)
526: printf("** Phase 2 - Check Pathnames\n");
527: inum = ROOTINO;
528: thisname = pathp = pathname;
529: pfunc = pass2;
530: switch(getstate()) {
531: case USTATE:
532: errexit("ROOT INODE UNALLOCATED. TERMINATING.\n");
533: case FSTATE:
534: pfatal("ROOT INODE NOT DIRECTORY");
535: if(reply("FIX") == NO || (dp = ginode()) == NULL)
536: errexit("");
537: dp->di_mode &= ~IFMT;
538: dp->di_mode |= IFDIR;
539: inodirty();
540: setstate(DSTATE);
541: case DSTATE:
542: descend();
543: break;
544: case CLEAR:
545: pfatal("DUPS/BAD IN ROOT INODE");
546: printf("\n");
547: if(reply("CONTINUE") == NO)
548: errexit("");
549: setstate(DSTATE);
550: descend();
551: }
552:
553:
554: if (preen == 0)
555: printf("** Phase 3 - Check Connectivity\n");
556: for(inum = ROOTINO; inum <= lastino; inum++) {
557: if(getstate() == DSTATE) {
558: pfunc = findino;
559: srchname = "..";
560: savino = inum;
561: do {
562: orphan = inum;
563: if((dp = ginode()) == NULL)
564: break;
565: filsize = dp->di_size;
566: parentdir = 0;
567: ckinode(dp,DATA);
568: if((inum = parentdir) == 0)
569: break;
570: } while(getstate() == DSTATE);
571: inum = orphan;
572: if(linkup() == YES) {
573: thisname = pathp = pathname;
574: *pathp++ = '?';
575: pfunc = pass2;
576: descend();
577: }
578: inum = savino;
579: }
580: }
581:
582:
583: if (preen == 0)
584: printf("** Phase 4 - Check Reference Counts\n");
585: pfunc = pass4;
586: for(inum = ROOTINO; inum <= lastino; inum++) {
587: switch(getstate()) {
588: case FSTATE:
589: if(n = getlncnt())
590: adjust((short)n);
591: else {
592: for(blp = badlncnt;blp < badlnp; blp++)
593: if(*blp == inum) {
594: clri("UNREF",YES);
595: break;
596: }
597: }
598: break;
599: case DSTATE:
600: clri("UNREF",YES);
601: break;
602: case CLEAR:
603: clri("BAD/DUP",YES);
604: }
605: }
606: if(imax - n_files != superblk.s_tinode) {
607: pwarn("FREE INODE COUNT %u SHOULD BE %u IN SUPERBLK",
608: superblk.s_tinode, imax - n_files);
609: if (preen)
610: printf(" (FIXED)\n");
611: if (preen || reply("FIX") == YES) {
612: superblk.s_tinode = imax - n_files;
613: sbdirty();
614: }
615: }
616: flush(&dfile,&fileblk);
617:
618: if (preen == 0)
619: printf("** Phase 5 - Check Free List ");
620: if(sflag || (csflag && rplyflag == 0)) {
621: if (preen == 0)
622: printf("(Ignored)\n");
623: fixfree = 1;
624: }
625: else {
626: if (preen == 0)
627: printf("\n");
628: if(freemap)
629: copy(blkmap,freemap,(MEMSIZE)bmapsz);
630: else {
631: for(blk = 0; blk < fmapblk; blk++) {
632: bp1 = getblk((BUFAREA *)NULL,blk);
633: bp2 = getblk((BUFAREA *)NULL,blk+fmapblk);
634: copy(bp1->b_un.b_buf,bp2->b_un.b_buf,BSIZE(big));
635: dirty(bp2);
636: }
637: }
638: badblk = dupblk = 0;
639: if(big == SMALL) {
640: freeblk.df_nfree = superblk.s_nfree;
641: for(n = 0; n < NICFREE; n++)
642: freeblk.df_free[n] = superblk.s_free[n];
643: }
644: freechk();
645: if(badblk) {
646: pfatal("%d BAD BLKS IN FREE LIST",badblk);
647: printf("\n");
648: }
649: if(dupblk)
650: pwarn("%d DUP BLKS IN FREE LIST\n",dupblk);
651: if(fixfree == 0) {
652: if((n_blks+n_free) != (fmax-fmin)) {
653: pwarn("%ld BLK(S) MISSING\n",
654: fmax-fmin-n_blks-n_free);
655: fixfree = 1;
656: }
657: else if(big == SMALL && n_free != superblk.s_tfree) {
658: pwarn("FREE BLK COUNT WRONG IN SUPERBLK");
659: if (preen)
660: printf(" (FIXED)\n");
661: if(preen || reply("FIX") == YES) {
662: superblk.s_tfree = n_free;
663: sbdirty();
664: }
665: }
666: }
667: if(fixfree) {
668: pwarn("BAD FREE LIST");
669: if (preen)
670: printf(" (SALVAGED)\n");
671: else if(reply("SALVAGE") == NO)
672: fixfree = 0;
673: }
674: }
675:
676: if(fixfree) {
677: if (preen == 0)
678: printf("** Phase 6 - Salvage Free List\n");
679: makefree();
680: n_free = superblk.s_tfree;
681: }
682:
683: pwarn("%ld files %ld blocks %ld free\n", n_files,n_blks,n_free);
684: if(dfile.mod) {
685: time(&superblk.s_time);
686: sbdirty();
687: }
688: ckfini();
689: sync();
690: if(dfile.mod && hotroot) {
691: printf("ROOT MODIFIED\n");
692: }
693: if(dfile.mod && preen == 0)
694: printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
695: }
696:
697: /* VARARGS1 */
698: error(s1,s2,s3,s4)
699: char *s1;
700: {
701: printf(s1,s2,s3,s4);
702: }
703:
704: /* VARARGS1 */
705: errexit(s1,s2,s3,s4)
706: char *s1;
707: {
708: error(s1,s2,s3,s4);
709: exit(8);
710: }
711:
712: /*
713: * Pfatal is called when an inconsistency occurs
714: * which should not happen during normal operations.
715: * It prints a message and then dies.
716: * When not preening, this is just a printf.
717: */
718: pfatal(s,a1,a2,a3)
719: {
720:
721: if (preen) {
722: printf("%s: ", devname);
723: printf(s, a1, a2, a3);
724: printf("\n");
725: preendie();
726: }
727: printf(s, a1, a2, a3);
728: }
729:
730: /*
731: * Fatal is called to terminate preening
732: * due to unexplainable inconsistency.
733: */
734: preendie()
735: {
736:
737: printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname);
738: exit(8);
739: }
740:
741: /*
742: * Pwarn is like printf when not preening,
743: * or a warning (preceded by filename) when preening.
744: */
745: pwarn(s,a1,a2,a3,a4,a5,a6)
746: {
747:
748: if (preen)
749: printf("%s: ", devname);
750: printf(s, a1, a2, a3, a4, a5, a6);
751: }
752:
753: ckinode(dp,flg)
754: DINODE *dp;
755: register flg;
756: {
757: register daddr_t *ap;
758: register ret;
759: int (*func)(), n;
760: daddr_t iaddrs[NADDR];
761:
762: if(SPECIAL)
763: return(KEEPON);
764: l3tol(iaddrs,dp->di_addr,NADDR);
765: func = (flg == ADDR) ? pfunc : dirscan;
766: for(ap = iaddrs; ap < &iaddrs[NADDR-3]; ap++) {
767: if(*ap && (ret = (*func)(*ap)) & STOP)
768: return(ret);
769: }
770: for(n = 1; n < 4; n++) {
771: if(*ap && (ret = iblock(*ap,n,flg)) & STOP)
772: return(ret);
773: ap++;
774: }
775: return(KEEPON);
776: }
777:
778:
779: iblock(blk,ilevel,flg)
780: daddr_t blk;
781: register ilevel;
782: {
783: register daddr_t *ap;
784: register n;
785: int (*func)();
786: BUFAREA ib;
787:
788: if(flg == ADDR) {
789: func = pfunc;
790: if(((n = (*func)(blk)) & KEEPON) == 0)
791: return(n);
792: }
793: else
794: func = dirscan;
795: if(outrange(blk)) /* protect thyself */
796: return(SKIP);
797: initbarea(&ib);
798: if(getblk(&ib,blk) == NULL)
799: return(SKIP);
800: ilevel--;
801: for(ap = ib.b_un.b_indir; ap < &ib.b_un.b_indir[NINDIR(big)]; ap++) {
802: if(*ap) {
803: if(ilevel > 0) {
804: n = iblock(*ap,ilevel,flg);
805: }
806: else
807: n = (*func)(*ap);
808: if(n & STOP)
809: return(n);
810: }
811: }
812: return(KEEPON);
813: }
814:
815:
816: pass1(blk)
817: daddr_t blk;
818: {
819: register daddr_t *dlp;
820:
821: if(outrange(blk)) {
822: blkerr("BAD",blk);
823: if(++badblk >= MAXBAD) {
824: printf("EXCESSIVE BAD BLKS I=%u",inum);
825: if(reply("CONTINUE") == NO)
826: errexit("");
827: return(STOP);
828: }
829: return(SKIP);
830: }
831: if(getbmap(blk)) {
832: blkerr("DUP",blk);
833: if(++dupblk >= MAXDUP) {
834: printf("EXCESSIVE DUP BLKS I=%u",inum);
835: if(reply("CONTINUE") == NO)
836: errexit("");
837: return(STOP);
838: }
839: if(enddup >= &duplist[DUPTBLSIZE]) {
840: printf("DUP TABLE OVERFLOW.");
841: if(reply("CONTINUE") == NO)
842: errexit("");
843: return(STOP);
844: }
845: for(dlp = duplist; dlp < muldup; dlp++) {
846: if(*dlp == blk) {
847: *enddup++ = blk;
848: break;
849: }
850: }
851: if(dlp >= muldup) {
852: *enddup++ = *muldup;
853: *muldup++ = blk;
854: }
855: }
856: else {
857: n_blks++;
858: setbmap(blk);
859: }
860: filsize++;
861: return(KEEPON);
862: }
863:
864:
865: pass1b(blk)
866: daddr_t blk;
867: {
868: register daddr_t *dlp;
869:
870: if(outrange(blk))
871: return(SKIP);
872: for(dlp = duplist; dlp < muldup; dlp++) {
873: if(*dlp == blk) {
874: blkerr("DUP",blk);
875: *dlp = *--muldup;
876: *muldup = blk;
877: return(muldup == duplist ? STOP : KEEPON);
878: }
879: }
880: return(KEEPON);
881: }
882:
883:
884: pass2(dirp)
885: register DIRECT *dirp;
886: {
887: register char *p;
888: register n;
889: DINODE *dp;
890:
891: if((inum = dirp->d_ino) == 0)
892: return(KEEPON);
893: thisname = pathp;
894: for(p = dirp->d_name; p < &dirp->d_name[DIRSIZ]; )
895: if((*pathp++ = *p++) == 0) {
896: --pathp;
897: break;
898: }
899: *pathp = 0;
900: n = NO;
901: if(inum > imax || inum < ROOTINO)
902: n = direrr("I OUT OF RANGE");
903: else {
904: again:
905: switch(getstate()) {
906: case USTATE:
907: n = direrr("UNALLOCATED");
908: break;
909: case CLEAR:
910: if((n = direrr("DUP/BAD")) == YES)
911: break;
912: if((dp = ginode()) == NULL)
913: break;
914: setstate(DIR ? DSTATE : FSTATE);
915: goto again;
916: case FSTATE:
917: declncnt();
918: break;
919: case DSTATE:
920: declncnt();
921: descend();
922: }
923: }
924: pathp = thisname;
925: if(n == NO)
926: return(KEEPON);
927: dirp->d_ino = 0;
928: return(KEEPON|ALTERD);
929: }
930:
931:
932: pass4(blk)
933: daddr_t blk;
934: {
935: register daddr_t *dlp;
936:
937: if(outrange(blk))
938: return(SKIP);
939: if(getbmap(blk)) {
940: for(dlp = duplist; dlp < enddup; dlp++)
941: if(*dlp == blk) {
942: *dlp = *--enddup;
943: return(KEEPON);
944: }
945: clrbmap(blk);
946: n_blks--;
947: }
948: return(KEEPON);
949: }
950:
951:
952: pass5(blk)
953: daddr_t blk;
954: {
955: if(outrange(blk)) {
956: fixfree = 1;
957: if (preen)
958: pfatal("BAD BLOCKS IN FREE LIST.");
959: if(++badblk >= MAXBAD) {
960: printf("EXCESSIVE BAD BLKS IN FREE LIST.");
961: if(reply("CONTINUE") == NO)
962: errexit("");
963: return(STOP);
964: }
965: return(SKIP);
966: }
967: if(getfmap(blk)) {
968: fixfree = 1;
969: if(++dupblk >= DUPTBLSIZE) {
970: printf("EXCESSIVE DUP BLKS IN FREE LIST.");
971: if(reply("CONTINUE") == NO)
972: errexit("");
973: return(STOP);
974: }
975: }
976: else {
977: n_free++;
978: setfmap(blk);
979: }
980: return(KEEPON);
981: }
982:
983:
984: blkerr(s,blk)
985: daddr_t blk;
986: char *s;
987: {
988: pfatal("%ld %s I=%u",blk,s,inum);
989: printf("\n");
990: setstate(CLEAR); /* mark for possible clearing */
991: }
992:
993:
994: descend()
995: {
996: register DINODE *dp;
997: register char *savname;
998: off_t savsize;
999:
1000: setstate(FSTATE);
1001: if((dp = ginode()) == NULL)
1002: return;
1003: savname = thisname;
1004: *pathp++ = '/';
1005: savsize = filsize;
1006: filsize = dp->di_size;
1007: ckinode(dp,DATA);
1008: thisname = savname;
1009: *--pathp = 0;
1010: filsize = savsize;
1011: }
1012:
1013:
1014: dirscan(blk)
1015: daddr_t blk;
1016: {
1017: register DIRECT *dirp;
1018: register char *p1, *p2;
1019: register n;
1020: DIRECT direntry;
1021:
1022: if(outrange(blk)) {
1023: filsize -= BSIZE(big);
1024: return(SKIP);
1025: }
1026: for(dirp = dirblk.b_dir; dirp < &dirblk.b_dir[NDIRECT(big)] &&
1027: filsize > 0; dirp++, filsize -= sizeof(DIRECT)) {
1028: if(getblk(&fileblk,blk) == NULL) {
1029: filsize -= (&dirblk.b_dir[NDIRECT(big)]-dirp)*
1030: sizeof(DIRECT);
1031: return(SKIP);
1032: }
1033: p1 = &dirp->d_name[DIRSIZ];
1034: p2 = &direntry.d_name[DIRSIZ];
1035: while(p1 > (char *)dirp)
1036: *--p2 = *--p1;
1037: if((n = (*pfunc)(&direntry)) & ALTERD) {
1038: if(getblk(&fileblk,blk) != NULL) {
1039: p1 = &dirp->d_name[DIRSIZ];
1040: p2 = &direntry.d_name[DIRSIZ];
1041: while(p1 > (char *)dirp)
1042: *--p1 = *--p2;
1043: fbdirty();
1044: }
1045: else
1046: n &= ~ALTERD;
1047: }
1048: if(n & STOP)
1049: return(n);
1050: }
1051: return(filsize > 0 ? KEEPON : STOP);
1052: }
1053:
1054:
1055: direrr(s)
1056: char *s;
1057: {
1058: register DINODE *dp;
1059:
1060: pwarn("%s ",s);
1061: pinode();
1062: printf("\n");
1063: if((dp = ginode()) != NULL && ftypeok(dp))
1064: pfatal("%s=%s",DIR?"DIR":"FILE",pathname);
1065: else
1066: pfatal("NAME=%s",pathname);
1067: return(reply("REMOVE"));
1068: }
1069:
1070:
1071: adjust(lcnt)
1072: register short lcnt;
1073: {
1074: register DINODE *dp;
1075:
1076: if((dp = ginode()) == NULL)
1077: return;
1078: if(dp->di_nlink == lcnt) {
1079: if(linkup() == NO)
1080: clri("UNREF",NO);
1081: }
1082: else {
1083: pwarn("LINK COUNT %s",
1084: (lfdir==inum)?lfname:(DIR?"DIR":"FILE"));
1085: pinode();
1086: printf(" COUNT %d SHOULD BE %d",
1087: dp->di_nlink,dp->di_nlink-lcnt);
1088: if (preen) {
1089: if (lcnt < 0) {
1090: printf("\n");
1091: preendie();
1092: }
1093: printf(" (ADJUSTED)\n");
1094: }
1095: if(preen || reply("ADJUST") == YES) {
1096: dp->di_nlink -= lcnt;
1097: inodirty();
1098: }
1099: }
1100: }
1101:
1102:
1103: clri(s,flg)
1104: char *s;
1105: {
1106: register DINODE *dp;
1107:
1108: if((dp = ginode()) == NULL)
1109: return;
1110: if(flg == YES) {
1111: pwarn("%s %s",s,DIR?"DIR":"FILE");
1112: pinode();
1113: }
1114: if(preen || reply("CLEAR") == YES) {
1115: if (preen)
1116: printf(" (CLEARED)\n");
1117: n_files--;
1118: pfunc = pass4;
1119: ckinode(dp,ADDR);
1120: zapino(dp);
1121: inodirty();
1122: }
1123: }
1124:
1125:
1126: setup(dev)
1127: char *dev;
1128: {
1129: register n;
1130: register BUFAREA *bp;
1131: register MEMSIZE msize;
1132: char *mbase;
1133: daddr_t bcnt, nscrblk;
1134: dev_t rootdev;
1135: off_t smapsz, lncntsz, totsz;
1136: struct stat statarea;
1137:
1138: if(stat("/",&statarea) < 0)
1139: errexit("Can't stat root\n");
1140: rootdev = statarea.st_dev;
1141: if(stat(dev,&statarea) < 0) {
1142: error("Can't stat %s\n",dev);
1143: return(NO);
1144: }
1145: rawflg = 0;
1146: big = SMALL; /* does this undo the work in blockcheck? */
1147: if((statarea.st_mode & S_IFMT) == S_IFBLK) {
1148: if(BITFS(statarea.st_rdev))
1149: big = BIG;
1150: }
1151: else if((statarea.st_mode & S_IFMT) == S_IFCHR)
1152: rawflg++;
1153: else {
1154: if (reply("file is not a block or character device; OK") == NO)
1155: return(NO);
1156: }
1157: if(rootdev == statarea.st_rdev)
1158: hotroot++;
1159: if((dfile.rfdes = open(dev,0)) < 0) {
1160: error("Can't open %s\n",dev);
1161: return(NO);
1162: }
1163: if (preen == 0)
1164: printf("\n%s",dev);
1165: if(nflag || (dfile.wfdes = open(dev,1)) < 0) {
1166: dfile.wfdes = -1;
1167: if (preen)
1168: pfatal("NO WRITE ACCESS");
1169: printf(" (NO WRITE)");
1170: }
1171: if (preen == 0)
1172: printf("\n");
1173: fixfree = 0;
1174: dfile.mod = 0;
1175: n_files = n_blks = n_free = 0;
1176: muldup = enddup = &duplist[0];
1177: badlnp = &badlncnt[0];
1178: lfdir = 0;
1179: rplyflag = 0;
1180: initbarea(&sblk);
1181: initbarea(&fileblk);
1182: initbarea(&inoblk);
1183: sfile.wfdes = sfile.rfdes = -1;
1184: rmscr = 0;
1185: if(getblk(&sblk,SUPERB) == NULL) {
1186: ckfini();
1187: return(NO);
1188: }
1189: imax = ((ino_t)superblk.s_isize - (SUPERB+1)) * INOPB(big);
1190: fmin = (daddr_t)superblk.s_isize; /* first data blk num */
1191: fmax = superblk.s_fsize; /* first invalid blk num */
1192: if(fmin >= fmax ||
1193: (imax/INOPB(big)) != ((ino_t)superblk.s_isize-(SUPERB+1))) {
1194: pfatal("Size check: fsize %ld isize %d",
1195: superblk.s_fsize,superblk.s_isize);
1196: printf("\n");
1197: ckfini();
1198: return(NO);
1199: }
1200: if (preen == 0)
1201: printf("File System: %.12s\n\n", superblk.s_fsmnt);
1202: bmapsz = roundup(howmany(fmax,BITSPB),sizeof(*lncntp));
1203: smapsz = roundup(howmany((long)(imax+1),STATEPB),sizeof(*lncntp));
1204: lncntsz = (long)(imax+1) * sizeof(*lncntp);
1205: if(bmapsz > smapsz+lncntsz)
1206: smapsz = bmapsz-lncntsz;
1207: totsz = bmapsz+smapsz+lncntsz;
1208: msize = memsize;
1209: mbase = membase;
1210: if(rawflg) {
1211: if(msize < (MEMSIZE)(NINOBLK*BSIZE(big)) + 2*sizeof(BUFAREA))
1212: rawflg = 0;
1213: else {
1214: msize -= (MEMSIZE)NINOBLK*BSIZE(big);
1215: mbase += (MEMSIZE)NINOBLK*BSIZE(big);
1216: niblk = NINOBLK;
1217: startib = fmax;
1218: }
1219: }
1220: clear(mbase,msize);
1221: if((off_t)msize < totsz) {
1222: bmapsz = roundup(bmapsz,BSIZE(big));
1223: smapsz = roundup(smapsz,BSIZE(big));
1224: lncntsz = roundup(lncntsz,BSIZE(big));
1225: nscrblk = (bmapsz+smapsz+lncntsz)>>BSHIFT(big);
1226: if(tflag == 0) {
1227: printf("\nNEED SCRATCH FILE (%ld BLKS)\n",nscrblk);
1228: do {
1229: printf("ENTER FILENAME: ");
1230: if((n = getline(stdin,scrfile,sizeof(scrfile))) == EOF)
1231: errexit("\n");
1232: } while(n == 0);
1233: }
1234: if(stat(scrfile,&statarea) < 0 ||
1235: (statarea.st_mode & S_IFMT) == S_IFREG)
1236: rmscr++;
1237: if((sfile.wfdes = creat(scrfile,0666)) < 0 ||
1238: (sfile.rfdes = open(scrfile,0)) < 0) {
1239: error("Can't create %s\n",scrfile);
1240: ckfini();
1241: return(NO);
1242: }
1243: bp = &((BUFAREA *)mbase)[(msize/sizeof(BUFAREA))];
1244: poolhead = NULL;
1245: while(--bp >= (BUFAREA *)mbase) {
1246: initbarea(bp);
1247: bp->b_next = poolhead;
1248: poolhead = bp;
1249: }
1250: bp = poolhead;
1251: for(bcnt = 0; bcnt < nscrblk; bcnt++) {
1252: bp->b_bno = bcnt;
1253: dirty(bp);
1254: flush(&sfile,bp);
1255: }
1256: blkmap = freemap = statemap = (char *) NULL;
1257: lncntp = (short *) NULL;
1258: smapblk = bmapsz / BSIZE(big);
1259: lncntblk = smapblk + smapsz / BSIZE(big);
1260: fmapblk = smapblk;
1261: }
1262: else {
1263: if(rawflg && (off_t)msize > totsz+BSIZE(big)) {
1264: niblk += (unsigned)((off_t)msize-totsz)>>BSHIFT(big);
1265: if(niblk > MAXRAW)
1266: niblk = MAXRAW;
1267: msize = memsize - (niblk*BSIZE(big));
1268: mbase = membase + (niblk*BSIZE(big));
1269: }
1270: poolhead = NULL;
1271: blkmap = mbase;
1272: statemap = &mbase[(MEMSIZE)bmapsz];
1273: freemap = statemap;
1274: lncntp = (short *)&statemap[(MEMSIZE)smapsz];
1275: }
1276: return(YES);
1277: }
1278:
1279:
1280: DINODE *
1281: ginode()
1282: {
1283: register DINODE *dp;
1284: register char *mbase;
1285: daddr_t iblk;
1286:
1287: if(inum > imax)
1288: return(NULL);
1289: iblk = itod(big, inum);
1290: if(rawflg) {
1291: mbase = membase;
1292: if(iblk < startib || iblk >= startib+niblk) {
1293: if(inoblk.b_dirty)
1294: bwrite(&dfile,mbase,startib,(int)niblk*BSIZE(big));
1295: inoblk.b_dirty = 0;
1296: if(bread(&dfile,mbase,iblk,(int)niblk*BSIZE(big)) == NO) {
1297: startib = fmax;
1298: return(NULL);
1299: }
1300: startib = iblk;
1301: }
1302: dp = (DINODE *)&mbase[(unsigned)((iblk-startib)<<BSHIFT(big))];
1303: }
1304: else if(getblk(&inoblk,iblk) != NULL)
1305: dp = inoblk.b_un.b_dinode;
1306: else
1307: return(NULL);
1308: return(dp + itoo(big, inum));
1309: }
1310:
1311:
1312: ftypeok(dp)
1313: DINODE *dp;
1314: {
1315: switch(dp->di_mode & IFMT) {
1316: case IFDIR:
1317: case IFREG:
1318: case IFBLK:
1319: case IFCHR:
1320: /* case IFMPC: */
1321: case IFLNK:
1322: /* case IFMPB: */
1323: return(YES);
1324: default:
1325: return(NO);
1326: }
1327: }
1328:
1329:
1330: reply(s)
1331: char *s;
1332: {
1333: char line[80];
1334:
1335: if (preen)
1336: pfatal("INTERNAL ERROR: GOT TO reply()");
1337: rplyflag = 1;
1338: printf("\n%s? ",s);
1339: if(nflag || csflag || dfile.wfdes < 0) {
1340: printf(" no\n\n");
1341: return(NO);
1342: }
1343: if(yflag) {
1344: printf(" yes\n\n");
1345: return(YES);
1346: }
1347: if(getline(stdin,line,sizeof(line)) == EOF)
1348: errexit("\n");
1349: printf("\n");
1350: if(line[0] == 'y' || line[0] == 'Y')
1351: return(YES);
1352: else
1353: return(NO);
1354: }
1355:
1356:
1357: getline(fp,loc,maxlen)
1358: FILE *fp;
1359: char *loc;
1360: {
1361: register n;
1362: register char *p, *lastloc;
1363:
1364: p = loc;
1365: lastloc = &p[maxlen-1];
1366: while((n = getc(fp)) != '\n') {
1367: if(n == EOF)
1368: return(EOF);
1369: if(!isspace(n) && p < lastloc)
1370: *p++ = n;
1371: }
1372: *p = 0;
1373: return(p - loc);
1374: }
1375:
1376:
1377: stype(p)
1378: register char *p;
1379: {
1380: if(*p == 0)
1381: return;
1382: if (*(p+1) == 0) {
1383: if (*p == '3') {
1384: cylsize = 200;
1385: stepsize = 5;
1386: return;
1387: }
1388: if (*p == '4') {
1389: cylsize = 418;
1390: stepsize = 9;
1391: return;
1392: }
1393: }
1394: cylsize = atoi(p);
1395: while(*p && *p != ':')
1396: p++;
1397: if(*p)
1398: p++;
1399: stepsize = atoi(p);
1400: if(stepsize <= 0 || stepsize > cylsize ||
1401: cylsize <= 0 || cylsize > MAXCYL) {
1402: error("Invalid -s argument, defaults assumed\n");
1403: cylsize = stepsize = 0;
1404: }
1405: }
1406:
1407:
1408: dostate(s,flg)
1409: {
1410: register char *p;
1411: register unsigned byte, shift;
1412: BUFAREA *bp;
1413:
1414: byte = (inum)/STATEPB;
1415: shift = LSTATE * ((inum)%STATEPB);
1416: if(statemap != NULL) {
1417: bp = NULL;
1418: p = &statemap[byte];
1419: }
1420: else if((bp = getblk((BUFAREA *)NULL,
1421: (daddr_t)(smapblk+(byte/BSIZE(big))))) == NULL)
1422: errexit("Fatal I/O error\n");
1423: else
1424: p = &bp->b_un.b_buf[byte%BSIZE(big)];
1425: switch(flg) {
1426: case 0:
1427: *p &= ~(SMASK<<(shift));
1428: *p |= s<<(shift);
1429: if(bp != NULL)
1430: dirty(bp);
1431: return(s);
1432: case 1:
1433: return((*p>>(shift)) & SMASK);
1434: }
1435: return(USTATE);
1436: }
1437:
1438:
1439: domap(blk,flg)
1440: daddr_t blk;
1441: {
1442: register char *p;
1443: register unsigned n;
1444: register BUFAREA *bp;
1445: off_t byte;
1446:
1447: byte = blk >> BITSHIFT;
1448: n = 1<<((unsigned)(blk & BITMASK));
1449: if(flg & 04) {
1450: p = freemap;
1451: blk = fmapblk;
1452: }
1453: else {
1454: p = blkmap;
1455: blk = 0;
1456: }
1457: if(p != NULL) {
1458: bp = NULL;
1459: p += (unsigned)byte;
1460: }
1461: else if((bp = getblk((BUFAREA *)NULL,blk+(byte>>BSHIFT(big)))) == NULL)
1462: errexit("Fatal I/O error\n");
1463: else
1464: p = &bp->b_un.b_buf[(unsigned)(byte&BMASK(big))];
1465: switch(flg&03) {
1466: case 0:
1467: *p |= n;
1468: break;
1469: case 1:
1470: n &= *p;
1471: bp = NULL;
1472: break;
1473: case 2:
1474: *p &= ~n;
1475: }
1476: if(bp != NULL)
1477: dirty(bp);
1478: return(n);
1479: }
1480:
1481:
1482: dolncnt(val,flg)
1483: short val;
1484: {
1485: register short *sp;
1486: register BUFAREA *bp;
1487:
1488: if(lncntp != NULL) {
1489: bp = NULL;
1490: sp = &lncntp[inum];
1491: }
1492: else if((bp = getblk((BUFAREA *)NULL,(daddr_t)(lncntblk+(inum/SPERB(big))))) == NULL)
1493: errexit("Fatal I/O error\n");
1494: else
1495: sp = &bp->b_un.b_lnks[inum%SPERB(big)];
1496: switch(flg) {
1497: case 0:
1498: *sp = val;
1499: break;
1500: case 1:
1501: bp = NULL;
1502: break;
1503: case 2:
1504: (*sp)--;
1505: }
1506: if(bp != NULL)
1507: dirty(bp);
1508: return(*sp);
1509: }
1510:
1511:
1512: BUFAREA *
1513: getblk(bp,blk)
1514: daddr_t blk;
1515: register BUFAREA *bp;
1516: {
1517: register struct filecntl *fcp;
1518:
1519: if(bp == NULL) {
1520: bp = search(blk);
1521: fcp = &sfile;
1522: }
1523: else
1524: fcp = &dfile;
1525: if(bp->b_bno == blk)
1526: return(bp);
1527: flush(fcp,bp);
1528: if(bread(fcp,bp->b_un.b_buf,blk,BSIZE(big)) != NO) {
1529: bp->b_bno = blk;
1530: return(bp);
1531: }
1532: bp->b_bno = (daddr_t)-1;
1533: return(NULL);
1534: }
1535:
1536:
1537: flush(fcp,bp)
1538: struct filecntl *fcp;
1539: register BUFAREA *bp;
1540: {
1541: if(bp->b_dirty) {
1542: bwrite(fcp,bp->b_un.b_buf,bp->b_bno,BSIZE(big));
1543: }
1544: bp->b_dirty = 0;
1545: }
1546:
1547:
1548: rwerr(s,blk)
1549: char *s;
1550: daddr_t blk;
1551: {
1552: if (preen == 0)
1553: printf("\n");
1554: pfatal("CAN NOT %s: BLK %ld",s,blk);
1555: if(reply("CONTINUE") == NO)
1556: errexit("Program terminated\n");
1557: }
1558:
1559:
1560: sizechk(dp)
1561: register DINODE *dp;
1562: {
1563: /*
1564: if (maxblk != howmany(dp->di_size, BSIZE))
1565: printf("POSSIBLE FILE SIZE ERROR I=%u (%ld,%ld)\n\n",
1566: inum, maxblk, howmany(dp->di_size,BSIZE));
1567: */
1568: if(DIR && (dp->di_size % sizeof(DIRECT)) != 0) {
1569: pwarn("DIRECTORY MISALIGNED I=%u\n",inum);
1570: if (preen == 0)
1571: printf("\n");
1572: }
1573: }
1574:
1575:
1576: ckfini()
1577: {
1578: flush(&dfile,&fileblk);
1579: flush(&dfile,&sblk);
1580: flush(&dfile,&inoblk);
1581: close(dfile.rfdes);
1582: close(dfile.wfdes);
1583: close(sfile.rfdes);
1584: close(sfile.wfdes);
1585: if(rmscr) {
1586: unlink(scrfile);
1587: }
1588: }
1589:
1590:
1591: pinode()
1592: {
1593: register DINODE *dp;
1594: register char *p;
1595: struct passwd *passwd;
1596: char *ctime();
1597:
1598: printf(" I=%u ",inum);
1599: if((dp = ginode()) == NULL)
1600: return;
1601: printf(" OWNER=");
1602: if((passwd = getpwuid((int)dp->di_uid)) != 0) {
1603: printf("%s ", passwd->pw_name);
1604: }
1605: else {
1606: printf("%d ",dp->di_uid);
1607: }
1608: printf("MODE=%o\n",dp->di_mode);
1609: if (preen)
1610: printf("%s: ", devname);
1611: printf("SIZE=%ld ",dp->di_size);
1612: p = ctime(&dp->di_mtime);
1613: printf("MTIME=%12.12s %4.4s ",p+4,p+20);
1614: }
1615:
1616:
1617: copy(fp,tp,size)
1618: register char *tp, *fp;
1619: MEMSIZE size;
1620: {
1621: while(size--)
1622: *tp++ = *fp++;
1623: }
1624:
1625:
1626: freechk()
1627: {
1628: register daddr_t *ap;
1629: register int i, j;
1630:
1631: if(big == BIG) {
1632: for(i = superblk.s_isize; i < superblk.s_fsize; i++) {
1633: j = i - superblk.s_isize;
1634: if(!getfmap(i)) {
1635: superblk.s_bfree[j>>5] |= (1 << (j&31));
1636: n_free++;
1637: }
1638: else
1639: superblk.s_bfree[j>>5] &= ~(1 << (j&31));
1640: }
1641: superblk.s_valid = 1;
1642: superblk.s_tfree = n_free;
1643: sbdirty();
1644: return;
1645: }
1646: if(freeblk.df_nfree == 0)
1647: return;
1648: do {
1649: if(freeblk.df_nfree <= 0 || freeblk.df_nfree > NICFREE) {
1650: pwarn("BAD FREEBLK COUNT");
1651: printf("\n");
1652: fixfree = 1;
1653: return;
1654: }
1655: ap = &freeblk.df_free[freeblk.df_nfree];
1656: while(--ap > &freeblk.df_free[0]) {
1657: if(pass5(*ap) == STOP)
1658: return;
1659: }
1660: if(*ap == (daddr_t)0 || pass5(*ap) != KEEPON)
1661: return;
1662: } while(getblk(&fileblk,*ap) != NULL);
1663: }
1664:
1665:
1666: makefree()
1667: {
1668: register i, cyl, step;
1669: int j;
1670: char flg[MAXCYL];
1671: short addr[MAXCYL];
1672: daddr_t blk, baseblk;
1673:
1674: if(big == BIG)
1675: return;
1676: superblk.s_nfree = 0;
1677: superblk.s_flock = 0;
1678: superblk.s_fmod = 0;
1679: superblk.s_tfree = 0;
1680: superblk.s_ninode = 0;
1681: superblk.s_ilock = 0;
1682: superblk.s_ronly = 0;
1683: if(cylsize == 0 || stepsize == 0) {
1684: step = superblk.s_dinfo[0];
1685: cyl = superblk.s_dinfo[1];
1686: }
1687: else {
1688: step = stepsize;
1689: cyl = cylsize;
1690: }
1691: if(step > cyl || step <= 0 || cyl <= 0 || cyl > MAXCYL) {
1692: error("Default free list spacing assumed\n");
1693: step = STEPSIZE;
1694: cyl = CYLSIZE;
1695: }
1696: superblk.s_dinfo[0] = step;
1697: superblk.s_dinfo[1] = cyl;
1698: clear(flg,sizeof(flg));
1699: i = 0;
1700: for(j = 0; j < cyl; j++) {
1701: while(flg[i])
1702: i = (i + 1) % cyl;
1703: addr[j] = i + 1;
1704: flg[i]++;
1705: i = (i + step) % cyl;
1706: }
1707: baseblk = (daddr_t)roundup(fmax,cyl);
1708: clear((char *)&freeblk,BSIZE(big));
1709: freeblk.df_nfree++;
1710: for( ; baseblk > 0; baseblk -= cyl)
1711: for(i = 0; i < cyl; i++) {
1712: blk = baseblk - addr[i];
1713: if(!outrange(blk) && !getbmap(blk)) {
1714: superblk.s_tfree++;
1715: if(freeblk.df_nfree >= NICFREE) {
1716: fbdirty();
1717: fileblk.b_bno = blk;
1718: flush(&dfile,&fileblk);
1719: clear((char *)&freeblk,BSIZE(big));
1720: }
1721: freeblk.df_free[freeblk.df_nfree] = blk;
1722: freeblk.df_nfree++;
1723: }
1724: }
1725: superblk.s_nfree = freeblk.df_nfree;
1726: for(i = 0; i < NICFREE; i++)
1727: superblk.s_free[i] = freeblk.df_free[i];
1728: sbdirty();
1729: }
1730:
1731:
1732: clear(p,cnt)
1733: register char *p;
1734: MEMSIZE cnt;
1735: {
1736: while(cnt--)
1737: *p++ = 0;
1738: }
1739:
1740:
1741: BUFAREA *
1742: search(blk)
1743: daddr_t blk;
1744: {
1745: register BUFAREA *pbp, *bp;
1746:
1747: for(bp = (BUFAREA *) &poolhead; bp->b_next; ) {
1748: pbp = bp;
1749: bp = pbp->b_next;
1750: if(bp->b_bno == blk)
1751: break;
1752: }
1753: pbp->b_next = bp->b_next;
1754: bp->b_next = poolhead;
1755: poolhead = bp;
1756: return(bp);
1757: }
1758:
1759:
1760: findino(dirp)
1761: register DIRECT *dirp;
1762: {
1763: register char *p1, *p2;
1764:
1765: if(dirp->d_ino == 0)
1766: return(KEEPON);
1767: for(p1 = dirp->d_name,p2 = srchname;*p2++ == *p1; p1++) {
1768: if(*p1 == 0 || p1 == &dirp->d_name[DIRSIZ-1]) {
1769: if(dirp->d_ino >= ROOTINO && dirp->d_ino <= imax)
1770: parentdir = dirp->d_ino;
1771: return(STOP);
1772: }
1773: }
1774: return(KEEPON);
1775: }
1776:
1777:
1778: mkentry(dirp)
1779: register DIRECT *dirp;
1780: {
1781: register ino_t in;
1782: register char *p;
1783:
1784: if(dirp->d_ino)
1785: return(KEEPON);
1786: dirp->d_ino = orphan;
1787: in = orphan;
1788: p = &dirp->d_name[8];
1789: *--p = 0;
1790: while(p > dirp->d_name) {
1791: *--p = (in % 10) + '0';
1792: in /= 10;
1793: }
1794: *p = '#';
1795: return(ALTERD|STOP);
1796: }
1797:
1798:
1799: chgdd(dirp)
1800: register DIRECT *dirp;
1801: {
1802: if(dirp->d_name[0] == '.' && dirp->d_name[1] == '.' &&
1803: dirp->d_name[2] == 0) {
1804: dirp->d_ino = lfdir;
1805: return(ALTERD|STOP);
1806: }
1807: return(KEEPON);
1808: }
1809:
1810:
1811: linkup()
1812: {
1813: register DINODE *dp;
1814: register lostdir;
1815: register ino_t pdir;
1816:
1817: if((dp = ginode()) == NULL)
1818: return(NO);
1819: lostdir = DIR;
1820: pdir = parentdir;
1821: pwarn("UNREF %s ",lostdir ? "DIR" : "FILE");
1822: pinode();
1823: if (preen && dp->di_size == 0)
1824: return(NO);
1825: if (preen)
1826: printf(" (RECONNECTED)\n");
1827: else
1828: if (reply("RECONNECT") == NO)
1829: return(NO);
1830: orphan = inum;
1831: if(lfdir == 0) {
1832: inum = ROOTINO;
1833: if((dp = ginode()) == NULL) {
1834: inum = orphan;
1835: return(NO);
1836: }
1837: pfunc = findino;
1838: srchname = lfname;
1839: filsize = dp->di_size;
1840: parentdir = 0;
1841: ckinode(dp,DATA);
1842: inum = orphan;
1843: if((lfdir = parentdir) == 0) {
1844: pfatal("SORRY. NO lost+found DIRECTORY");
1845: printf("\n\n");
1846: return(NO);
1847: }
1848: }
1849: inum = lfdir;
1850: if((dp = ginode()) == NULL || !DIR || getstate() != FSTATE) {
1851: inum = orphan;
1852: pfatal("SORRY. NO lost+found DIRECTORY");
1853: printf("\n\n");
1854: return(NO);
1855: }
1856: if(dp->di_size & BMASK(big)) {
1857: dp->di_size = roundup(dp->di_size,BSIZE(big));
1858: inodirty();
1859: }
1860: filsize = dp->di_size;
1861: inum = orphan;
1862: pfunc = mkentry;
1863: if((ckinode(dp,DATA) & ALTERD) == 0) {
1864: pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
1865: printf("\n\n");
1866: return(NO);
1867: }
1868: declncnt();
1869: if(lostdir) {
1870: pfunc = chgdd;
1871: dp = ginode();
1872: filsize = dp->di_size;
1873: ckinode(dp,DATA);
1874: inum = lfdir;
1875: if((dp = ginode()) != NULL) {
1876: dp->di_nlink++;
1877: inodirty();
1878: setlncnt(getlncnt()+1);
1879: }
1880: inum = orphan;
1881: pwarn("DIR I=%u CONNECTED. ",orphan);
1882: printf("PARENT WAS I=%u\n",pdir);
1883: if (preen == 0)
1884: printf("\n");
1885: }
1886: return(YES);
1887: }
1888:
1889:
1890: bread(fcp,buf,blk,size)
1891: daddr_t blk;
1892: register struct filecntl *fcp;
1893: register size;
1894: char *buf;
1895: {
1896: if(lseek(fcp->rfdes,blk<<BSHIFT(big),0) < 0)
1897: rwerr("SEEK",blk);
1898: else if(read(fcp->rfdes,buf,size) == size)
1899: return(YES);
1900: rwerr("READ",blk);
1901: return(NO);
1902: }
1903:
1904:
1905: bwrite(fcp,buf,blk,size)
1906: daddr_t blk;
1907: register struct filecntl *fcp;
1908: register size;
1909: char *buf;
1910: {
1911: if(fcp->wfdes < 0)
1912: return(NO);
1913: if(lseek(fcp->wfdes,blk<<BSHIFT(big),0) < 0)
1914: rwerr("SEEK",blk);
1915: else if(write(fcp->wfdes,buf,size) == size) {
1916: fcp->mod = 1;
1917: return(YES);
1918: }
1919: rwerr("WRITE",blk);
1920: return(NO);
1921: }
1922:
1923: catch()
1924: {
1925: ckfini();
1926: exit(12);
1927: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.