Annotation of coherent/d/bin/dos/dos1.c, revision 1.1.1.1

1.1       root        1: /* dos1.c */
                      2: /* Globals and functions common to the "dos" and "dosshrink" commands. */
                      3: 
                      4: #include "dos0.h"
                      5: 
                      6: /* Diskette parameters. */
                      7: BPB    d8floppy  = { 512, 2, 1, 2, 112,  640, 0xFF, 1,  8, 2, 0 };
                      8: BPB    d9floppy  = { 512, 2, 1, 2, 112,  720, 0xFD, 2,  9, 2, 0 };
                      9: BPB    d15floppy = { 512, 1, 1, 2, 224, 2400, 0xF9, 7, 15, 2, 0 };
                     10: BPB    d18floppy = { 512, 1, 1, 2, 224, 2880, 0xF0, 9, 18, 2, 0 };
                     11: BPB    q9floppy  = { 512, 2, 1, 2, 112, 1440, 0xF9, 3,  9, 2, 0 };
                     12: BPB    s8floppy  = { 512, 1, 1, 2,  64,  320, 0xFE, 1,  8, 1, 0 };
                     13: BPB    s9floppy  = { 512, 1, 1, 2,  64,  360, 0xFC, 2,  9, 1, 0 };
                     14: 
                     15: /* Globals. */
                     16: char           *argv0;                 /* Command name                 */
                     17: unsigned char  bootb[BBSIZE];          /* Boot block                   */
                     18: BPB            *bpb;                   /* Disk parameters              */
                     19: short          cflag;                  /* Readonly                     */
                     20: unsigned char  *clbuf;                 /* One cluster buffer           */
                     21: unsigned short clsize;                 /* Sectors per cluster          */
                     22: unsigned short dirbase;                /* First root directory sector  */
                     23: unsigned short dirsize;                /* Root dir size in sectors     */
                     24: unsigned short fatbase;                /* First FAT sector             */
                     25: unsigned short fatbytes;               /* Bytes per FAT entry (1 means 1.5)*/
                     26: unsigned short *fatcache;              /* File allocation table cache  */
                     27: unsigned short fatccount;              /* Sectors in FAT cache         */
                     28: unsigned short fatcfirst;              /* First sector in FAT cache    */
                     29: short          fatcflag;               /* FAT must be written          */
                     30: unsigned short fatcmax;                /* Max cluster in FAT cache     */
                     31: unsigned short fatcmin;                /* Min cluster in FAT cache     */
                     32: unsigned short fatsize;                /* FAT size in sectors          */
                     33: unsigned short filebase;               /* First disk file data sector  */
                     34: short          fsfd;                   /* File system file descriptor  */
                     35: unsigned short heads;                  /* Heads                        */
                     36: unsigned short maxcluster;             /* Max cluster number           */
                     37: unsigned short mdirsize;               /* MDIRs per cluster            */
                     38: unsigned short nspt;                   /* Sectors per track            */
                     39: unsigned short sectors;                /* Sectors                      */
                     40: unsigned short ssize;                  /* Sector size                  */
                     41: char           *usagemsg;              /* Usage message                */
                     42: short          vflag;                  /* Verbose                      */
                     43: 
                     44: /*
                     45:  * Convert cluster number n to a block number.
                     46:  * Complain if the cluster number is out of range.
                     47:  */
                     48: unsigned long
                     49: cltosec(n) register unsigned short n;
                     50: {
                     51:        if (n < 2 || n > maxcluster)
                     52:                fatal("cluster number %u out of range", n);
                     53:        return ((long)(n - 2) * (long)clsize + filebase);
                     54: }
                     55: 
                     56: /*
                     57:  * Decode or encode a FAT with 1.5-byte entries.
                     58:  * The FAT is already in the FAT cache and the cache is big enough
                     59:  * for the expanded version with 2-byte entries.
                     60:  * The flag is 0 to decode after read, 1 to encode before write.
                     61:  * This lazy code uses short pointers on char boundaries.
                     62:  */
                     63: void
                     64: decodefat(flag) short flag;
                     65: {
                     66:        register unsigned short i;
                     67:        register unsigned short u, *ip;
                     68:        register unsigned char *cp;
                     69: 
                     70:        cp = fatcache;
                     71:        if (flag == 0) {
                     72:                /* Expand 1.5-byte entries to unsigned shorts. */
                     73:                for (i = maxcluster; ; i--) {
                     74:                        ip = &cp[i*3/2];
                     75:                        fatcache[i] = *ip;
                     76:                        if (i & 1)
                     77:                                fatcache[i] >>= 4;
                     78:                        else
                     79:                                fatcache[i] &= FATMASK;
                     80:                        if (fatcache[i] > (CLMAX & FATMASK))
                     81:                                fatcache[i] |= 0xF000;
                     82:                        if (i == 0)
                     83:                                break;
                     84:                }
                     85:        } else {
                     86:                /* Compress the FAT table to 1.5-byte entries. */
                     87:                for (i = 0; i <= maxcluster; i++) {
                     88:                        u = fatcache[i] & FATMASK;
                     89:                        ip = &cp[i*3/2];
                     90:                        if (i & 1) {
                     91:                                *ip &= ~(FATMASK << 4);
                     92:                                *ip |= u << 4;
                     93:                        } else {
                     94:                                *ip &= ~FATMASK;
                     95:                                *ip |= u;
                     96:                        }
                     97:                }
                     98:        }
                     99: }
                    100: 
                    101: /*
                    102:  * Read size sectors starting at block n into buf.
                    103:  * Failure is fatal.
                    104:  */
                    105: void
                    106: diskread(buf, n, size, msg) char *buf; unsigned long n; short size; char *msg;
                    107: {
                    108:        diskseek(n);
                    109:        while (size-- > 0) {
                    110:                if (read(fsfd, buf, ssize) != ssize)
                    111:                        fatal("%s read error", msg);
                    112:                buf += ssize;
                    113:        }
                    114: }
                    115: 
                    116: /*
                    117:  * Seek to the specified sector on the disk.
                    118:  */
                    119: void
                    120: diskseek(n) unsigned long n;
                    121: {
                    122:        if (lseek(fsfd, partseek + n * ssize, 0) == -1L)
                    123:                fatal("seek failed 0x%lx", n * ssize);
                    124: }
                    125: 
                    126: /*
                    127:  * Write size sectors starting at block n from buf.
                    128:  * Failure is fatal.
                    129:  */
                    130: void
                    131: diskwrite(buf, n, size, msg) char *buf; unsigned long n; short size; char *msg;
                    132: {
                    133:        if (cflag)
                    134:                return;
                    135:        diskseek(n);
                    136:        while (size--) {
                    137:                if (write(fsfd, buf, ssize) != ssize)
                    138:                        fatal("%s write error", msg);
                    139:                buf += ssize;
                    140:        }
                    141: }
                    142: 
                    143: /*
                    144:  * Cry and die.
                    145:  * Uses the nonportable "%r" format.
                    146:  */
                    147: void
                    148: fatal(x) char *x;
                    149: {
                    150:        fflush(stdout);
                    151:        fprintf(stderr, "%s: %r\n", argv0, &x);
                    152:        rm_lock();
                    153:        exit(1);
                    154: }
                    155: 
                    156: void
                    157: fatal1(x) char *x;
                    158: {
                    159:        fflush(stdout);
                    160:        fprintf(stderr, "%s: %r\n", argv0, &x);
                    161:        exit(1);
                    162: }
                    163: 
                    164: /*
                    165:  * Flush the FAT cache.
                    166:  */
                    167: void
                    168: fatcflush()
                    169: {
                    170:        register unsigned short i, n;
                    171: 
                    172:        if (fatcflag)
                    173:                for (n = fatbase + fatcfirst, i = 1;
                    174:                     i <= bpb->b_fats;
                    175:                     n += fatsize, i++)
                    176:                        diskwrite(fatcache, (long)n, fatccount, "FAT cache");
                    177:        fatcflag = 0;
                    178: }
                    179: 
                    180: /*
                    181:  * Read segment of FAT including cluster n into the FAT cache.
                    182:  */
                    183: void
                    184: fatcread(n) register unsigned short n;
                    185: {
                    186:        fatcflush();                            /* flush previous contents */
                    187:        fatcflag = 0;                           /* clear dirty flag */
                    188:        fatcfirst = (n/FATCCOUNT) * FATCSECS;   /* first FAT sector to read */
                    189:        fatccount = FATCSECS;                   /* sectors to read */
                    190:        if (fatcfirst + fatccount > fatsize)
                    191:                fatccount = fatsize - fatcfirst;        /* read less at end */
                    192:        fatcmin = fatcfirst * FATCNPSEC;        /* min cluster in cache */
                    193:        fatcmax = (fatcfirst + fatccount) * FATCNPSEC - 1;      /* max cl */
                    194: /*
                    195: printf("n=%d,fatbase=%d,fatcfirst=%d,(long)(fatbase+fatcfirst)=%d,fatccount=%d\n",
                    196: n,fatbase,fatcfirst,(long)(fatbase + fatcfirst),fatccount);
                    197: */
                    198:        diskread(fatcache, (long)(fatbase + fatcfirst),fatccount,"FAT cache");
                    199: }
                    200: 
                    201: /*
                    202:  * Get the FAT entry for cluster n.
                    203:  */
                    204: unsigned short
                    205: getcluster(n) register unsigned short n;
                    206: {
                    207:        if (n < 2 || n > maxcluster)
                    208:                fatal("getcluster: bad cluster number %u", n);
                    209:        if (n < fatcmin || n > fatcmax)
                    210:                fatcread(n);
                    211:        return fatcache[n - fatcmin];
                    212: }
                    213: 
                    214: /*
                    215:  * Convert up to n characters from src (an MS-DOS filename or extension)
                    216:  * to dst (a COHERENT filename buffer),
                    217:  * mapping to lower case and stopping at ' '.
                    218:  * Return a pointer to the NUL terminator.
                    219:  */
                    220: char *
                    221: lcname(dst, src, n) unsigned char *dst, *src; register short n;
                    222: {
                    223:        register short c;
                    224: 
                    225:        while (n--) {
                    226:                if ((c = *src++) == ' ')
                    227:                        break;
                    228:                else if (isupper(c))
                    229:                        c = tolower(c);
                    230:                *dst++ = c;
                    231:        }
                    232:        *dst = '\0';
                    233:        return dst;
                    234: }
                    235: 
                    236: /*
                    237:  * Put val in the FAT entry for cluster n.
                    238:  */
                    239: void
                    240: putcluster(n, val) unsigned short n; register short val;
                    241: {
                    242:        if (n < 2 || n > maxcluster)
                    243:                fatal("putcluster: bad cluster number %u", n);
                    244:        if (n < fatcmin || n > fatcmax)
                    245:                fatcread(n);
                    246:        fatcache[n - fatcmin] = val;
                    247:        fatcflag = 1;
                    248: }
                    249: 
                    250: /*
                    251:  * Read the file allocation table.
                    252:  * Try the rational approach:
                    253:  * read the boot block and use the boot block BPB info.
                    254:  * This being MS-DOS, the rational approach sometimes loses,
                    255:  * because the BPB information is not always there;
                    256:  * try e.g. DOS 3.2 "format a: /8".
                    257:  * Hence, the somewhat backhanded approach below.
                    258:  */
                    259: void
                    260: readfat()
                    261: {
                    262:        register unsigned short i;
                    263:        unsigned char id[3];
                    264:        char *s;
                    265: 
                    266:        if (xpart != 0)
                    267:                xpartition();
                    268: 
                    269:        /* Read the boot block and hope its BPB is rational. */
                    270:        lseek(fsfd, partseek, 0);
                    271:        if (read(fsfd, bootb, BBSIZE) != BBSIZE)
                    272:                fatal("boot block read error");
                    273:        bpb = &bootb[BPBOFF];
                    274:        if (is_media_id(bpb->b_media))
                    275:                s = "Found";
                    276:        else {
                    277:                /*
                    278:                 * The boot block BPB is missing,
                    279:                 * check for media id at start of block 1.
                    280:                 */
                    281:                lseek(fsfd, (long)BBSIZE, 0);
                    282:                if (read(fsfd, id, 3) != 3)
                    283:                        fatal("media id read error");
                    284:                i = id[0];
                    285:                if ((i!=0xFC && i!=0xFD && i!=0xFE && i!=0xFF)
                    286:                  || id[1]!=0xFF || id[2]==0xFF)
                    287:                        fatal("Probably not a DOS disk (media descriptor 0x%02x)", id[0]);
                    288:                /* Known diskette format. */
                    289:                s = "Known";
                    290:                switch (i) {
                    291:                case 0xFC:      bpb = &s9floppy;        break;
                    292:                case 0xFD:      bpb = &d9floppy;        break;
                    293:                case 0xFE:      bpb = &s8floppy;        break;
                    294:                case 0xFF:      bpb = &d8floppy;        break;
                    295:                }
                    296:        }
                    297:        setglobals();
                    298: #if    DEBUG
                    299:        printf("%s BPB: %u %u %u %u %u %u 0x%x %u %u %u %u\n",
                    300:                s,
                    301:                ssize,
                    302:                clsize,
                    303:                fatbase,
                    304:                bpb->b_fats,
                    305:                bpb->b_files,
                    306:                sectors,
                    307:                bpb->b_media,
                    308:                fatsize,
                    309:                nspt,
                    310:                heads,
                    311:                bpb->b_hidden);
                    312: #endif
                    313:        /*
                    314:         * Allocate space for a FAT cache.
                    315:         * If the FAT contains 1.5-byte entries, the cache must be big
                    316:         * enough for the entire FAT table.
                    317:         * Read start of FAT for sanity check below.
                    318:         */
                    319:        if ((fatcache = malloc(FATCSECS * ssize)) == NULL)
                    320:                fatal("FAT allocation failed");
                    321:        if (fatbytes == 1) {            /* 1.5-byte FAT entries */
                    322:                if (fatsize > FATCSECS)
                    323:                        fatal("FAT cache botch fatsize=%d", fatsize);
                    324:                fatcread(0);
                    325:                fatcmax = (fatsize * ssize * 2 / 3) - 1;
                    326:                if (fatcmax < maxcluster)
                    327:                        fatal("FAT cache botch max=%d", fatcmax);
                    328:                decodefat(0);           /* expand entries to two bytes each */
                    329:        } else if (fatbytes == 2)       /* 2-byte FAT entries */
                    330:                fatcread(0);
                    331:        else                            /* 4-byte FAT entries, presumably */
                    332:                fatal("fatbytes=%u", fatbytes);
                    333: 
                    334:        /* Sanity check. */
                    335:        if (fatcache[0] != (0xFF00 | bpb->b_media) || fatcache[1] != 0xFFFF)
                    336:                fatal("bad MS-DOS diskette format 0x%x 0x%x", fatcache[0], fatcache[1]);
                    337: }
                    338: 
                    339: /*
                    340:  * Set globals based on values in BPB.
                    341:  * This is mostly for efficiency.
                    342:  */
                    343: void
                    344: setglobals()
                    345: {
                    346:        ssize = bpb->b_ssize;
                    347:        clsize = bpb->b_clsize;
                    348:        fatbase = bpb->b_reserved;
                    349:        sectors = bpb->b_sectors;
                    350:        fatsize = bpb->b_fatsize;
                    351:        nspt = bpb->b_tracks;
                    352:        heads = bpb->b_heads;
                    353: 
                    354:        /* This program is untested for sector size != 512. */
                    355:        /* It might work, it might not; let's be prudent. */
                    356:        if (ssize != BBSIZE)
                    357:                fatal("ssize=%u BBSIZE=%u", ssize, BBSIZE);
                    358: 
                    359:        /* Compute base file sector, number of clusters, etc. */
                    360:        dirbase = fatbase + fatsize * bpb->b_fats;
                    361:        dirsize = (bpb->b_files * sizeof(MDIR) + ssize - 1) / ssize;
                    362:        filebase = dirbase + dirsize;
                    363:        mdirsize = clsize * ssize / sizeof(MDIR);
                    364: 
                    365:        if (sectors == 0) {
                    366:                fatbytes = 2;
                    367:                maxcluster=1+(unsigned short)((bpb->b_bigsectors-filebase)/clsize);
                    368:        }
                    369:        else {
                    370:                fatbytes = (sectors / clsize > (FATMASK & CLMAX)) ? 2 : 1;
                    371:                maxcluster = 1 + (sectors - filebase) / clsize;
                    372:        }
                    373: 
                    374:        dbprintf(("dirbase=%u dirsize=%u fatbytes=%u filebase=%u maxcluster=%u mdirsize=%u\n", dirbase, dirsize, fatbytes, filebase, maxcluster, mdirsize));
                    375: }
                    376: 
                    377: /*
                    378:  * Print usage message and die.
                    379:  */
                    380: void
                    381: usage(msg) char *msg;
                    382: {
                    383:        fprintf(stderr, usagemsg);
                    384:        if (msg)
                    385:                fatal(msg);
                    386:        else
                    387:                exit(1);
                    388: }
                    389: 
                    390: /*
                    391:  * Write the file allocation table.
                    392:  * If fatbytes==1, the FAT is compressed into 1.5-byte entries;
                    393:  * it is not directly usable after compression.
                    394:  */
                    395: void
                    396: writefat()
                    397: {
                    398:        if (fatbytes == 1)
                    399:                decodefat(1);
                    400:        fatcflush();
                    401: }
                    402: 
                    403: /*
                    404:  * If the desired MS-DOS filesystem is an extended MS-DOS partition,
                    405:  * find the seek into the COHERENT partition
                    406:  * which specifies the base of the actual MS-DOS filessytem.
                    407:  */
                    408: void
                    409: xpartition()
                    410: {
                    411:        register short part;
                    412:        HDISK_S hd;
                    413:        FDISK_S *p1, *p2;
                    414: 
                    415:        partseek = 0L;
                    416:        for (part = 1; part <= xpart; ++part) {
                    417:                if (lseek(fsfd, partseek, 0) == -1L)
                    418:                        fatal("extended partition lseek failed part=%d seek=%lx",
                    419:                                part, partseek);
                    420:                if (read(fsfd, &hd, sizeof hd) != sizeof hd)
                    421:                        fatal("extended partition table %d read failed", part);
                    422:                if (hd.hd_sig != HDSIG)
                    423:                        fatal("no signature found on extended partition table %d",
                    424:                                part);
                    425:                p1 = &(hd.hd_partn[0]);
                    426:                p2 = &(hd.hd_partn[1]);
                    427:                if (part == xpart) {
                    428:                        partseek += p1->p_base * BBSIZE;
                    429:                        break;
                    430:                } else if (p2->p_sys == SYS_DOS_XP)
                    431:                        partseek = p2->p_base * BBSIZE;
                    432:                else
                    433:                        fatal("extended MS-DOS partition does not contain %d drives",
                    434:                                xpart);
                    435:        }
                    436: }
                    437: 
                    438: /* end of dos1.c */
                    439: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.