|
|
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.