|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.