source: buchla-68k/orig/GEMDOS/FSCK.C@ 5f1d169

Last change on this file since 5f1d169 was 3ae31e9, checked in by Thomas Lopatic <thomas@…>, 7 years ago

Imported original source code.

  • Property mode set to 100755
File size: 14.8 KB
RevLine 
[3ae31e9]1/*
2 =============================================================================
3 fsck.c -- Atari ST file system checker
4 Written by: D.N. Lynx Crowe
5
6 See VERMSG (below) for version information.
7
8 This version checks files in the root directory on floppy drive A only.
9 =============================================================================
10*/
11
12#define PROGID "fsck"
13#define VERMSG "1.8 -- 1988-03-25"
14
15#include "stddefs.h"
16#include "stdio.h"
17#include "osbind.h"
18#include "ctype.h"
19#include "strings.h"
20#include "bpb.h"
21#include "dirent.h"
22#include "bootsec.h"
23
24#define MAXSECLN 512 /* maximum sector length */
25
26#define PERLINE 16 /* bytes per line for mdump */
27#define MAXCLINE 10 /* number of clusters per line */
28#define FNLEN 13 /* file name buffer length */
29
30#define MAXFATSZ 9 /* maximum FAT size */
31#define MAXRDSZ 14 /* maximum root directory size */
32
33#define MAXFATLN (MAXSECLN * MAXFATSZ)
34#define MAXRDLN (MAXSECLN * MAXRDSZ)
35
36#define MAXFATNM (MAXFATLN / 2)
37
38/*
39
40*/
41char fat1[MAXFATLN]; /* FAT 1 image */
42char fat2[MAXFATLN]; /* FAT 2 image */
43char rdir[MAXRDLN]; /* root directory image */
44
45short bsec[MAXSECLN / 2]; /* boot sector image */
46
47short drive; /* drive number */
48short rdsize; /* number of root directory entries */
49short cltype; /* FAT entry type - 0 = 12, 1 = 16 */
50
51long fatlen; /* length of FAT in bytes */
52
53BOOL errflag; /* error flag */
54BOOL quiet; /* quiet flag */
55BOOL verbose; /* verbose flag */
56BOOL errdump; /* dump on errors flag */
57BOOL clslist; /* list clusters */
58BOOL bscdump; /* dump boot sector */
59BOOL dirlist; /* list directory entries */
60
61short fatmap[MAXFATNM]; /* FAT check map */
62
63unsigned fat1loc; /* starting sector of FAT 1 */
64unsigned fat2loc; /* starting sector of FAT 2 */
65unsigned rdloc; /* starting sector of root directory */
66unsigned datloc; /* starting sector of data */
67unsigned eofclus; /* cluster value limit for EOF */
68unsigned badclus; /* cluster value limit for errors */
69
70struct BPB bpb; /* copy of BPB for the drive */
71
72/*
73
74*/
75
76/*
77 =============================================================================
78 pipc() -- print if printable characters
79 =============================================================================
80*/
81
82static
83pipc(chars, length)
84char chars[];
85int length;
86{
87 int i;
88
89 for (i = 0; i < length; i++)
90 if (isascii(0x00FF & chars[i]) AND (isprint(0x00FF & chars[i])))
91 printf("%c", chars[i]);
92 else
93 printf(".");
94}
95
96/*
97
98*/
99
100/*
101 =============================================================================
102 mdump() -- dump a memory area in hexadecimal
103 =============================================================================
104*/
105
106mdump(begin, end, start)
107char *begin, *end;
108long start;
109{
110 long i, ii;
111 int j, jj, k;
112 char c, chars[PERLINE];
113
114 i = 0L;
115 ii = start;
116 j = 0;
117
118 if (begin GT end)
119 return;
120
121 while (begin LE end) {
122
123 c = *begin++;
124
125 if (! (i % PERLINE)) {
126
127 if (i) {
128
129 j=0;
130 printf(" ");
131 pipc(chars, PERLINE);
132 }
133
134 printf("\n%08.8lx:", ii);
135 }
136
137 ii++;
138 i++;
139 printf(" %02.2x", (c & 0x00FF));
140 chars[j++] = c;
141 }
142
143 if (k = (i % PERLINE)) {
144
145 k = PERLINE - k;
146
147 for (jj = 0; jj < (3 * k); ++jj)
148 printf(" ");
149 }
150
151 printf(" ");
152 pipc(chars, PERLINE);
153 printf("\n");
154}
155
156/*
157
158*/
159
160/*
161 =============================================================================
162 getiwd() -- get an Intel byte reversed word
163 =============================================================================
164*/
165
166unsigned
167getiwd(wp)
168register char wp[];
169{
170 register unsigned val;
171
172 val = ((wp[1] & 0x00FF) << 8) | (wp[0] & 0x00FF);
173 return(val);
174}
175
176/*
177 =============================================================================
178 trim() -- trim trailing blanks from a string
179 =============================================================================
180*/
181
182char *
183trim(s)
184register char *s;
185{
186 register char *sp;
187
188 if (*s EQ '\0') /* handle empty string */
189 return(s);
190
191 sp = s;
192
193 while (*sp) /* find end of string */
194 ++sp;
195
196 while (' ' EQ *--sp) {
197
198 *sp = '\0';
199
200 if (sp EQ s)
201 break;
202 }
203
204 return(s);
205}
206
207/*
208
209*/
210
211/*
212 =============================================================================
213 fileid() -- get a file identifier from a directory entry
214 =============================================================================
215*/
216
217char *
218fileid(dir, buf)
219struct Dirent *dir;
220char *buf;
221{
222 memset(buf, 0, 13);
223 strncat(buf, dir->name, 8);
224 trim(buf);
225
226 if (strncmp(dir->ext, " ", 3)) {
227
228 strcat(buf, ".");
229 strncat(buf, dir->ext, 3);
230 trim(buf);
231 }
232
233 return(buf);
234}
235
236
237/*
238
239*/
240
241/*
242 =============================================================================
243 _gtcl12(fat, cl) -- return 12 bit cluster entry 'cl' from FAT pointed
244 to by 'fat'
245 =============================================================================
246*/
247
248unsigned
249_gtcl12(fat, cl)
250register char *fat;
251unsigned cl;
252{
253 register unsigned cla, clt;
254
255 cla = cl + (cl >> 1);
256 clt = ((unsigned)0xFF00 & (fat[cla+1] << 8))
257 | ((unsigned)0x00FF & fat[cla]);
258
259 if (cl & 1)
260 clt >>= 4;
261
262 clt &= (unsigned)0x0FFF;
263 return(clt);
264}
265
266/*
267 =============================================================================
268 getcl() -- get a FAT entry
269 =============================================================================
270*/
271
272unsigned
273getcl(fp, ncl, ft)
274char *fp;
275unsigned ncl;
276short ft;
277{
278 if (ft)
279 return(getiwd(fp[ncl << 1]));
280 else
281 return(_gtcl12(fp, ncl));
282}
283
284/*
285
286*/
287
288/*
289 =============================================================================
290 ckdir() -- check a directory entry
291 =============================================================================
292*/
293
294BOOL
295ckdir(fat, dir, ent)
296char *fat;
297struct Dirent *dir;
298short ent;
299{
300 unsigned dirclus;
301 unsigned curclus;
302 short cln;
303 BOOL ok;
304 char fn1[FNLEN];
305 char fn2[FNLEN];
306
307 if ((dir[ent].name[0] & 0x00FF) EQ 0x00E5)
308 return(FALSE);
309
310 if ((dir[ent].name[0] & 0x00FF) EQ 0)
311 return(TRUE);
312
313 if (verbose OR clslist OR dirlist) {
314
315 printf(" Checking entry %d: \"%s\"",
316 ent, fileid(&dir[ent], fn1));
317
318 if (dir[ent].atrib & F_VOLUME) {
319
320 printf(" -- Volume label\n");
321 return(FALSE);
322
323 } else {
324
325 printf(" -- Flags: ");
326
327 printf("%c", dir[ent].atrib & F_ARCHIV ? 'A' : '.');
328 printf("%c", dir[ent].atrib & F_SUBDIR ? 'D' : '.');
329 printf("%c", dir[ent].atrib & F_SYSTEM ? 'S' : '.');
330 printf("%c", dir[ent].atrib & F_HIDDEN ? 'H' : '.');
331 printf("%c", dir[ent].atrib & F_RDONLY ? 'R' : '.');
332
333 printf("\n");
334 }
335 }
336/*
337
338*/
339 dirclus = getiwd(dir[ent].clus);
340
341 if (fatmap[dirclus] NE -1) {
342
343 printf("ERROR: Overlapping allocations --\n");
344 printf(" %s overlaps %s at cluster %u\n\n",
345 fileid(&dir[ent], fn1),
346 fileid(&dir[fatmap[dirclus]], fn2),
347 dirclus);
348
349 errflag = TRUE;
350 return(FALSE);
351 }
352
353 if (clslist)
354 printf(" allocated clusters:\n ");
355
356 cln = 0;
357 ok = TRUE;
358
359 while (ok) {
360
361 fatmap[dirclus] = ent;
362
363 if (clslist) {
364
365 if (cln EQ MAXCLINE) {
366
367 printf("\n ");
368 cln = 0;
369 }
370
371 ++cln;
372 printf(" %5u", dirclus);
373 }
374
375 curclus = getcl(fat, dirclus, cltype);
376/*
377
378*/
379 if (curclus LT 2) {
380
381 printf("ERROR: Bad FAT entry ($%x) at %u ($%x)",
382 curclus, dirclus, dirclus);
383
384 printf(" for file \"%s\"\n", fileid(&dir[ent], fn1));
385 errflag = TRUE;
386 ok = FALSE;
387
388 } else if (curclus LT badclus) {
389
390 if (fatmap[curclus] NE -1) {
391
392 printf("ERROR: Overlapping allocations --\n");
393 printf(" \"%s\" overlaps \"%s\" at cluster %u\n\n",
394 fileid(&dir[ent], fn1),
395 fileid(&dir[fatmap[dirclus]], fn2),
396 dirclus);
397
398 errflag = TRUE;
399 return(FALSE);
400 }
401
402 dirclus = curclus;
403
404 } else if (curclus LT eofclus) {
405
406 printf("ERROR: Bad FAT entry ($%x) at %u ($%x)",
407 curclus, dirclus, dirclus);
408
409 printf(" for file \"%s\"\n", fileid(&dir[ent], fn1));
410 errflag = TRUE;
411 ok = FALSE;
412
413 } else {
414
415 if (clslist AND cln)
416 printf("\n");
417
418 ok = FALSE;
419 }
420 }
421
422 return(FALSE);
423}
424
425/*
426
427*/
428
429/*
430 =============================================================================
431 main() -- main driver function for fsck.c
432 =============================================================================
433*/
434
435main(argc, argv)
436short argc;
437char *argv[];
438{
439 char *bpp;
440 char *ap;
441 short c;
442 long rc;
443 register long i;
444 register short j;
445 register struct BootSec *bsp;
446
447 /* setup miscellaneous variables and defaults */
448
449 drive = 0; /* drive A */
450 cltype = 0; /* 12 bit FAT entries */
451 eofclus = 0x0FF8; /* EOF cluster limit */
452 badclus = 0x0FF0; /* bad cluster limit */
453
454 quiet = FALSE; /* log all activity */
455 verbose = FALSE; /* log details */
456 errdump = FALSE; /* dump on errors */
457 clslist = FALSE; /* list cluster allocations */
458 bscdump = FALSE; /* dump boot sector */
459 dirlist = FALSE; /* list directory entries */
460/*
461
462*/
463 /* parse command line */
464
465 if (argc > 1) {
466
467 ap = argv[1];
468
469 while (c = 0x00FF & *ap++) {
470
471 c = tolower(c);
472
473 switch (c) {
474
475 case 'a': /* set options b, c, d, e, v */
476
477 bscdump = TRUE; /* b option */
478 clslist = TRUE; /* c option */
479 dirlist = TRUE; /* d option */
480 errdump = TRUE; /* e option */
481 verbose = TRUE; /* v option */
482 break;
483
484 case 'b': /* dump boot sector */
485
486 bscdump = TRUE;
487 break;
488
489 case 'c': /* list clusters */
490
491 clslist = TRUE;
492 break;
493
494 case 'd': /* list directory entries */
495
496 dirlist = TRUE;
497 break;
498
499 case 'e': /* dump on errors */
500
501 errdump = TRUE;
502 break;
503/*
504
505*/
506 case 'q': /* quiet mode */
507
508 quiet = TRUE;
509 break;
510
511 case 'v': /* verbose mode */
512
513 verbose = TRUE;
514 break;
515
516 default: /* invalid option */
517
518 printf("%s: ERROR - invalid option \"%c\" [$%02.2x]\n\n",
519 PROGID, c, c);
520
521 printf("usage: %s [abcdeqv]\n", PROGID);
522 printf(" a set options b, c, d, e, v\n");
523 printf(" b dump boot sector\n");
524 printf(" c list cluster allocations\n");
525 printf(" d list directory entries\n");
526 printf(" e dump FATS and DIR on errors\n");
527 printf(" q quiet mode\n");
528 printf(" v verbose mode\n");
529 exit(1);
530 }
531 }
532 }
533/*
534
535*/
536 errflag = FALSE; /* reset the error flag */
537
538 /* identify the program */
539
540 if (NOT quiet)
541 printf("\n%s for the Atari ST -- Version %s\n\n",
542 PROGID, VERMSG);
543
544 if (verbose)
545 printf("Reading boot sector ...\n");
546
547 if (rc = Floprd(bsec, 0L, drive, 1, 0, 0, 1)) {
548
549 printf("ERROR -- Unable to read boot sector\n");
550 exit(1);
551 }
552
553 if (verbose)
554 printf("Boot sector read OK\n");
555
556 bsp = (struct BootSec *)bsec;
557
558 if (bscdump) {
559
560 printf("\nBoot sector contents --\n\n");
561
562 printf(" Branch word = $%02.2x $%02.2x\n",
563 bsp->branch[0], bsp->branch[1]);
564
565 printf(" OEM area =");
566
567 for (j = 0; j < 6; j++)
568 printf(" $%02.2x", bsp->oem[j]);
569
570 printf("\n Volume S/N =");
571
572 for (j = 0; j < 3; j++)
573 printf(" $%02.2x", bsp->vsn[j]);
574
575 printf("\n Bytes / Sector = %u\n", getiwd(bsp->bps));
576 printf(" Sectors / Cluster = %u\n", bsp->spc);
577 printf(" Reserved sectors = %u\n", getiwd(bsp->res));
578 printf(" Number of FATS = %u\n", bsp->nfats);
579 printf(" Directory entries = %u\n", getiwd(bsp->ndirs));
580 printf(" Total Sectors = %u\n", getiwd(bsp->nsects));
581 printf(" Media byte = $%02.2x\n", bsp->media);
582 printf(" Sectors / FAT = %u\n", getiwd(bsp->spf));
583 printf(" Sectors / Track = %u\n", getiwd(bsp->spt));
584 printf(" Sides = %u\n", getiwd(bsp->nsides));
585 printf(" Hidden files = %u\n", getiwd(bsp->nhid));
586 printf(" Checksum = $%04.4x\n", getiwd(bsp->cksum));
587
588 printf("\nBoot record data area --\n\n");
589 mdump(bsp->boot, &bsp->boot[479], 0L);
590 printf("\n");
591 }
592/*
593
594*/
595 /* get the BPB */
596
597 if (bpp = (char *)Getbpb(drive)) {
598
599 memcpy(&bpb, bpp, sizeof (struct BPB));
600
601 } else {
602
603 printf("ERROR: Unable to get BPB for drive");
604 exit(1);
605 }
606
607 /* determine where things live, etc. */
608
609 fat2loc = bpb.fatrec;
610 fat1loc = bpb.fatrec - bpb.fsiz;
611 rdloc = bpb.fatrec + bpb.fsiz;
612 datloc = bpb.fatrec + bpb.fsiz + bpb.rdlen;
613 rdsize = (bpb.recsiz * bpb.rdlen) / sizeof (struct Dirent);
614 fatlen = bpb.fsiz * bpb.recsiz;
615
616 /* check BPB values for consistency */
617
618 if (verbose)
619 printf("Checking BPB for consistency ...\n");
620
621 if (datloc NE bpb.datrec) {
622
623 printf("ERROR: Data locations inconsistent:\n");
624 printf(" BPB value: %u\n", bpb.datrec);
625 printf(" Calculated: %u\n", datloc);
626 exit(1);
627 }
628/*
629
630*/
631 /* read FAT 1 */
632
633 if (verbose)
634 printf("Reading FAT 1 ...\n");
635
636 if (rc = Rwabs(0, fat1, bpb.fsiz, fat1loc, drive)) {
637
638 printf("ERROR: Unable to read FAT 1 -- error code = %ld\n",
639 rc);
640
641 exit(1);
642 }
643
644 if (verbose)
645 printf("FAT 1 read OK\n");
646
647 /* read FAT 2 */
648
649 if (verbose)
650 printf("Reading FAT 2 ...\n");
651
652 if (rc = Rwabs(0, fat2, bpb.fsiz, fat2loc, drive)) {
653
654 printf("ERROR: Unable to read FAT 2 -- error code = %ld\n",
655 rc);
656
657 exit(1);
658 }
659
660 if (verbose)
661 printf("FAT 2 read OK\n");
662
663 /* read the root directory */
664
665 if (verbose)
666 printf("Reading root directory ...\n");
667
668 if (rc = Rwabs(0, rdir, bpb.rdlen, rdloc, drive)) {
669
670 printf("ERROR: Unable to read root directory -- error code = %ld\n",
671 rc);
672
673 exit(1);
674 }
675
676 if (verbose)
677 printf("Root directory read OK\n");
678/*
679
680*/
681 /* compare the FATs */
682
683 if (verbose)
684 printf("Comparing FATs ...\n");
685
686 for (i = 0; i < fatlen; i++) {
687
688 if (fat1[i] NE fat2[i]) {
689
690 printf("ERROR: FATs differ at offset %lu ($%lx)\n\n",
691 i, i);
692
693 if (errdump) {
694
695 printf("FAT 1:\n\n");
696 mdump(fat1, fat1 + (long)(fatlen - 1), 0L);
697
698 printf("\fFAT 2:\n\n");
699 mdump(fat2, fat2 + (long)(fatlen - 1), 0L);
700
701 printf("\f");
702
703 } else {
704
705 printf("WARNING -- Primary file system damaged.\n");
706 }
707
708 exit(1);
709 }
710 }
711
712 if (verbose)
713 printf("FATs are consistent\n");
714
715 /* check the root directory files */
716
717 if (verbose | clslist)
718 printf("Checking root directory ...\n");
719
720 memsetw(fatmap, -1, MAXFATNM);
721
722 for (j = 0; j < rdsize; j++)
723 if (ckdir(fat1, rdir, j))
724 break;
725/*
726
727*/
728 if (errflag)
729 if (errdump) {
730
731 printf("\fDirectory dump:\n\n");
732 mdump(rdir,
733 rdir + (long)(sizeof (struct Dirent) * rdsize) - 1L,
734 0L);
735
736 printf("\fFAT dump:\n\n");
737 mdump(fat1, fat1 + (long)(fatlen - 1), 0L);
738
739 printf("\n");
740
741 } else {
742
743 printf("\nWARNING -- Primary file system damaged.\n");
744 }
745
746 if (NOT quiet)
747 printf("\nPrimary file system check complete on drive %c.\n\n",
748 drive + 'A');
749
750 exit(errflag ? 1 : 0);
751}
Note: See TracBrowser for help on using the repository browser.