Annotation of coherent/d/bin/dos/dos1.c, revision 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.