1 | /* dos{dir|read|write} - {list|read|write} MS-DOS disks Author: M. Huisjes */
|
---|
2 |
|
---|
3 | /* Dosdir - list MS-DOS directories. doswrite - write stdin to DOS-file
|
---|
4 | * dosread - read DOS-file to stdout
|
---|
5 | *
|
---|
6 | * Author: Michiel Huisjes.
|
---|
7 | *
|
---|
8 | * Usage: dos... [-lra] drive [file/dir]
|
---|
9 | * l: Give long listing.
|
---|
10 | * r: List recursively.
|
---|
11 | * a: Set ASCII bit.
|
---|
12 | */
|
---|
13 |
|
---|
14 | #include <assert.h>
|
---|
15 | #include <ctype.h>
|
---|
16 | #include <errno.h>
|
---|
17 | #include <limits.h>
|
---|
18 | #include <sys/types.h>
|
---|
19 | #include <sys/stat.h>
|
---|
20 | #include <fcntl.h>
|
---|
21 | #include <stdlib.h>
|
---|
22 | #include <stdio.h>
|
---|
23 | #include <string.h>
|
---|
24 | #include <time.h>
|
---|
25 | #include <sys/times.h>
|
---|
26 | #include <unistd.h>
|
---|
27 |
|
---|
28 |
|
---|
29 | #define MAX_CLUSTER_SIZE 4096
|
---|
30 | #define MAX_ROOT_ENTRIES 512
|
---|
31 | #define FAT_START 512L /* After bootsector */
|
---|
32 | #define ROOTADDR (FAT_START + 2L * fat_size)
|
---|
33 | #define clus_add(cl_no) ((long) (((long) cl_no - 2L) \
|
---|
34 | * (long) cluster_size \
|
---|
35 | + data_start \
|
---|
36 | ))
|
---|
37 | struct dir_entry {
|
---|
38 | unsigned char d_name[8];
|
---|
39 | unsigned char d_ext[3];
|
---|
40 | unsigned char d_attribute;
|
---|
41 | unsigned char d_reserved[10];
|
---|
42 | unsigned short d_time;
|
---|
43 | unsigned short d_date;
|
---|
44 | unsigned short d_cluster;
|
---|
45 | unsigned long d_size;
|
---|
46 | };
|
---|
47 |
|
---|
48 | typedef struct dir_entry DIRECTORY;
|
---|
49 |
|
---|
50 | #define NOT_USED 0x00
|
---|
51 | #define ERASED 0xE5
|
---|
52 | #define DIR 0x2E
|
---|
53 | #define DIR_SIZE (sizeof (struct dir_entry))
|
---|
54 | #define SUB_DIR 0x10
|
---|
55 | #define NIL_DIR ((DIRECTORY *) 0)
|
---|
56 |
|
---|
57 | #define LAST_CLUSTER12 0xFFF
|
---|
58 | #define LAST_CLUSTER 0xFFFF
|
---|
59 | #define FREE 0x000
|
---|
60 | #define BAD 0xFF0
|
---|
61 | #define BAD16 0xFFF0
|
---|
62 |
|
---|
63 | typedef int BOOL;
|
---|
64 |
|
---|
65 | #define TRUE 1
|
---|
66 | #define FALSE 0
|
---|
67 | #define NIL_PTR ((char *) 0)
|
---|
68 |
|
---|
69 | #define DOS_TIME 315532800L /* 1970 - 1980 */
|
---|
70 |
|
---|
71 | #define READ 0
|
---|
72 | #define WRITE 1
|
---|
73 |
|
---|
74 | #define FIND 3
|
---|
75 | #define LABEL 4
|
---|
76 | #define ENTRY 5
|
---|
77 | #define find_entry(d, e, p) directory(d, e, FIND, p)
|
---|
78 | #define list_dir(d, e, f) (void) directory(d, e, f, NIL_PTR)
|
---|
79 | #define label() directory(root, root_entries, LABEL, NIL_PTR)
|
---|
80 | #define new_entry(d, e) directory(d, e, ENTRY, NIL_PTR)
|
---|
81 |
|
---|
82 | #define is_dir(d) ((d)->d_attribute & SUB_DIR)
|
---|
83 |
|
---|
84 | #define STD_OUT 1
|
---|
85 |
|
---|
86 | char *cmnd;
|
---|
87 |
|
---|
88 | static int disk; /* File descriptor for disk I/O */
|
---|
89 |
|
---|
90 | static DIRECTORY root[MAX_ROOT_ENTRIES];
|
---|
91 | static DIRECTORY save_entry;
|
---|
92 | static char drive[] = "/dev/dosX";
|
---|
93 | #define DRIVE_NR (sizeof (drive) - 2)
|
---|
94 | static char null[MAX_CLUSTER_SIZE], *device = drive, path[128];
|
---|
95 | static long data_start;
|
---|
96 | static long mark; /* offset of directory entry to be written */
|
---|
97 | static unsigned short total_clusters, cluster_size, root_entries, sub_entries;
|
---|
98 | static unsigned long fat_size;
|
---|
99 |
|
---|
100 | static BOOL Rflag, Lflag, Aflag, dos_read, dos_write, dos_dir, fat_16 = 0;
|
---|
101 | static BOOL big_endian;
|
---|
102 |
|
---|
103 | /* maximum size of a cooked 12bit FAT. Also Size of 16bit FAT cache
|
---|
104 | * if not enough memory for whole FAT
|
---|
105 | */
|
---|
106 | #define COOKED_SIZE 8192
|
---|
107 | /* raw FAT. Only used for 12bit FAT to make conversion easier
|
---|
108 | */
|
---|
109 | static unsigned char *raw_fat;
|
---|
110 | /* Cooked FAT. May be only part of the FAT for 16 bit FATs
|
---|
111 | */
|
---|
112 | static unsigned short *cooked_fat;
|
---|
113 | /* lowest and highest entry in fat cache
|
---|
114 | */
|
---|
115 | static unsigned short fat_low = USHRT_MAX,
|
---|
116 | fat_high = 0;
|
---|
117 | static BOOL fat_dirty = FALSE;
|
---|
118 | static unsigned int cache_size;
|
---|
119 |
|
---|
120 |
|
---|
121 | /* Prototypes. */
|
---|
122 | _PROTOTYPE(void usage, (char *prog_name) );
|
---|
123 | _PROTOTYPE(unsigned c2u2, (unsigned char *ucarray) );
|
---|
124 | _PROTOTYPE(unsigned long c4u4, (unsigned char *ucarray) );
|
---|
125 | _PROTOTYPE(void determine, (void));
|
---|
126 | _PROTOTYPE(int main, (int argc, char *argv []));
|
---|
127 | _PROTOTYPE(DIRECTORY *directory, (DIRECTORY *dir, int entries, BOOL function, char *pathname) );
|
---|
128 | _PROTOTYPE(void extract, (DIRECTORY *entry) );
|
---|
129 | _PROTOTYPE(void make_file, (DIRECTORY *dir_ptr, int entries, char *name) );
|
---|
130 | _PROTOTYPE(void fill_date, (DIRECTORY *entry) );
|
---|
131 | _PROTOTYPE(char *make_name, (DIRECTORY *dir_ptr, int dir_fl) );
|
---|
132 | _PROTOTYPE(int fill, (char *buffer, size_t size) );
|
---|
133 | _PROTOTYPE(void xmodes, (int mode) );
|
---|
134 | _PROTOTYPE(void show, (DIRECTORY *dir_ptr, char *name) );
|
---|
135 | _PROTOTYPE(void free_blocks, (void));
|
---|
136 | _PROTOTYPE(DIRECTORY *read_cluster, (unsigned int cluster) );
|
---|
137 | _PROTOTYPE(unsigned short free_cluster, (BOOL leave_fl) );
|
---|
138 | _PROTOTYPE(void link_fat, (unsigned int cl_1, unsigned int cl_2) );
|
---|
139 | _PROTOTYPE(unsigned short next_cluster, (unsigned int cl_no) );
|
---|
140 | _PROTOTYPE(char *slash, (char *str) );
|
---|
141 | _PROTOTYPE(void add_path, (char *file, BOOL slash_fl) );
|
---|
142 | _PROTOTYPE(void disk_io, (BOOL op, unsigned long seek, void *address, unsigned bytes) );
|
---|
143 | _PROTOTYPE(void flush_fat, (void));
|
---|
144 | _PROTOTYPE(void read_fat, (unsigned int cl_no));
|
---|
145 | _PROTOTYPE(BOOL free_range, (unsigned short *first, unsigned short *last));
|
---|
146 | _PROTOTYPE(long lmin, (long a, long b));
|
---|
147 |
|
---|
148 |
|
---|
149 | void usage(prog_name)
|
---|
150 | register char *prog_name;
|
---|
151 | {
|
---|
152 | fprintf (stderr, "Usage: %s [%s\n", prog_name,
|
---|
153 | (dos_dir ? "-lr] drive [dir]" : "-a] drive file"));
|
---|
154 | exit(1);
|
---|
155 | }
|
---|
156 |
|
---|
157 | unsigned c2u2(ucarray)
|
---|
158 | unsigned char *ucarray;
|
---|
159 | {
|
---|
160 | return ucarray[0] + (ucarray[1] << 8); /* parens vital */
|
---|
161 | }
|
---|
162 |
|
---|
163 | unsigned long c4u4(ucarray)
|
---|
164 | unsigned char *ucarray;
|
---|
165 | {
|
---|
166 | return ucarray[0] + ((unsigned long) ucarray[1] << 8) +
|
---|
167 | ((unsigned long) ucarray[2] << 16) +
|
---|
168 | ((unsigned long) ucarray[3] << 24);
|
---|
169 | }
|
---|
170 |
|
---|
171 | void determine()
|
---|
172 | {
|
---|
173 | struct dosboot {
|
---|
174 | unsigned char cjump[2]; /* unsigneds avoid bugs */
|
---|
175 | unsigned char nop;
|
---|
176 | unsigned char name[8];
|
---|
177 | unsigned char cbytepers[2]; /* don't use shorts, etc */
|
---|
178 | unsigned char secpclus; /* to avoid struct member */
|
---|
179 | unsigned char creservsec[2]; /* alignment and byte */
|
---|
180 | unsigned char fats; /* order bugs */
|
---|
181 | unsigned char cdirents[2];
|
---|
182 | unsigned char ctotsec[2];
|
---|
183 | unsigned char media;
|
---|
184 | unsigned char csecpfat[2];
|
---|
185 | unsigned char csecptrack[2];
|
---|
186 | unsigned char cheads[2];
|
---|
187 | unsigned char chiddensec[2];
|
---|
188 | unsigned char dos4hidd2[2];
|
---|
189 | unsigned char dos4totsec[4];
|
---|
190 | /* Char fill[476]; */
|
---|
191 | } boot;
|
---|
192 | unsigned short boot_magic; /* last of boot block */
|
---|
193 | unsigned bytepers, reservsec, dirents;
|
---|
194 | unsigned secpfat, secptrack, heads, hiddensec;
|
---|
195 | unsigned long totsec;
|
---|
196 | unsigned char fat_info, fat_check;
|
---|
197 | unsigned short endiantest = 1;
|
---|
198 | int errcount = 0;
|
---|
199 |
|
---|
200 | big_endian = !(*(unsigned char *)&endiantest);
|
---|
201 |
|
---|
202 | /* Read Bios-Parameterblock */
|
---|
203 | disk_io(READ, 0L, &boot, sizeof boot);
|
---|
204 | disk_io(READ, 0x1FEL, &boot_magic, sizeof boot_magic);
|
---|
205 |
|
---|
206 | /* Convert some arrays */
|
---|
207 | bytepers = c2u2(boot.cbytepers);
|
---|
208 | reservsec = c2u2(boot.creservsec);
|
---|
209 | dirents = c2u2(boot.cdirents);
|
---|
210 | totsec = c2u2(boot.ctotsec);
|
---|
211 | if (totsec == 0) totsec = c4u4(boot.dos4totsec);
|
---|
212 | secpfat = c2u2(boot.csecpfat);
|
---|
213 | secptrack = c2u2(boot.csecptrack);
|
---|
214 | heads = c2u2(boot.cheads);
|
---|
215 |
|
---|
216 | /* The `hidden sectors' are the sectors before the partition.
|
---|
217 | * The calculation here is probably wrong (I think the dos4hidd2
|
---|
218 | * bytes are the msbs), but that doesn't matter, since the
|
---|
219 | * value isn't used anyway
|
---|
220 | */
|
---|
221 | hiddensec = c2u2(boot.chiddensec);
|
---|
222 | if (hiddensec == 0) hiddensec = c2u2 (boot.dos4hidd2);
|
---|
223 |
|
---|
224 | /* Safety checking */
|
---|
225 | if (boot_magic != 0xAA55) {
|
---|
226 | fprintf (stderr, "%s: magic != 0xAA55\n", cmnd);
|
---|
227 | ++errcount;
|
---|
228 | }
|
---|
229 |
|
---|
230 | /* Check sectors per track instead of inadequate media byte */
|
---|
231 | if (secptrack < 15 && /* assume > 15 hard disk & wini OK */
|
---|
232 | #ifdef SECT10 /* BIOS modified for 10 sec/track */
|
---|
233 | secptrack != 10 &&
|
---|
234 | #endif
|
---|
235 | #ifdef SECT8 /* BIOS modified for 8 sec/track */
|
---|
236 | secptrack != 8 &&
|
---|
237 | #endif
|
---|
238 | secptrack != 9) {
|
---|
239 | fprintf (stderr, "%s: %d sectors per track not supported\n", cmnd, secptrack);
|
---|
240 | ++errcount;
|
---|
241 | }
|
---|
242 | if (bytepers == 0) {
|
---|
243 | fprintf (stderr, "%s: bytes per sector == 0\n", cmnd);
|
---|
244 | ++errcount;
|
---|
245 | }
|
---|
246 | if (boot.secpclus == 0) {
|
---|
247 | fprintf (stderr, "%s: sectors per cluster == 0\n", cmnd);
|
---|
248 | ++errcount;
|
---|
249 | }
|
---|
250 | if (boot.fats != 2 && dos_write) {
|
---|
251 | fprintf (stderr, "%s: fats != 2\n", cmnd);
|
---|
252 | ++errcount;
|
---|
253 | }
|
---|
254 | if (reservsec != 1) {
|
---|
255 | fprintf (stderr, "%s: reserved != 1\n", cmnd);
|
---|
256 | ++errcount;
|
---|
257 | }
|
---|
258 | if (errcount != 0) {
|
---|
259 | fprintf (stderr, "%s: Can't handle disk\n", cmnd);
|
---|
260 | exit(2);
|
---|
261 | }
|
---|
262 |
|
---|
263 | /* Calculate everything. */
|
---|
264 | if (boot.secpclus == 0) boot.secpclus = 1;
|
---|
265 | total_clusters =
|
---|
266 | (totsec - boot.fats * secpfat - reservsec -
|
---|
267 | dirents * 32L / bytepers ) / boot.secpclus + 2;
|
---|
268 | /* first 2 entries in FAT aren't used */
|
---|
269 | cluster_size = bytepers * boot.secpclus;
|
---|
270 | fat_size = (unsigned long) secpfat * (unsigned long) bytepers;
|
---|
271 | data_start = (long) bytepers + (long) boot.fats * fat_size
|
---|
272 | + (long) dirents *32L;
|
---|
273 | root_entries = dirents;
|
---|
274 | sub_entries = boot.secpclus * bytepers / 32;
|
---|
275 | if (total_clusters > 4096) fat_16 = 1;
|
---|
276 |
|
---|
277 | /* Further safety checking */
|
---|
278 | if (cluster_size > MAX_CLUSTER_SIZE) {
|
---|
279 | fprintf (stderr, "%s: cluster size too big\n", cmnd);
|
---|
280 | ++errcount;
|
---|
281 | }
|
---|
282 |
|
---|
283 | disk_io(READ, FAT_START, &fat_info, 1);
|
---|
284 | disk_io(READ, FAT_START + fat_size, &fat_check, 1);
|
---|
285 | if (fat_check != fat_info) {
|
---|
286 | fprintf (stderr, "%s: Disk type in FAT copy differs from disk type in FAT original.\n", cmnd);
|
---|
287 | ++errcount;
|
---|
288 | }
|
---|
289 | if (errcount != 0) {
|
---|
290 | fprintf (stderr, "%s: Can't handle disk\n", cmnd);
|
---|
291 | exit(2);
|
---|
292 | }
|
---|
293 | }
|
---|
294 |
|
---|
295 | int main(argc, argv)
|
---|
296 | int argc;
|
---|
297 | register char *argv[];
|
---|
298 | {
|
---|
299 | register char *arg_ptr = slash(argv[0]);
|
---|
300 | DIRECTORY *entry;
|
---|
301 | short idx = 1;
|
---|
302 | char dev_nr = '0';
|
---|
303 |
|
---|
304 | cmnd = arg_ptr; /* needed for error messages */
|
---|
305 | if (!strcmp(arg_ptr, "dosdir"))
|
---|
306 | dos_dir = TRUE;
|
---|
307 | else if (!strcmp(arg_ptr, "dosread"))
|
---|
308 | dos_read = TRUE;
|
---|
309 | else if (!strcmp(arg_ptr, "doswrite"))
|
---|
310 | dos_write = TRUE;
|
---|
311 | else {
|
---|
312 | fprintf (stderr, "%s: Program should be named dosread, doswrite or dosdir.\n", cmnd);
|
---|
313 | exit(1);
|
---|
314 | }
|
---|
315 |
|
---|
316 | if (argc == 1) usage(argv[0]);
|
---|
317 |
|
---|
318 | if (argv[1][0] == '-') {
|
---|
319 | for (arg_ptr = &argv[1][1]; *arg_ptr; arg_ptr++) {
|
---|
320 | if (*arg_ptr == 'l' && dos_dir) {
|
---|
321 | Lflag = TRUE;
|
---|
322 | } else if (*arg_ptr == 'r' && dos_dir) {
|
---|
323 | Rflag = TRUE;
|
---|
324 | } else if (*arg_ptr == 'a' && !dos_dir) {
|
---|
325 | assert ('\n' == 10);
|
---|
326 | assert ('\r' == 13);
|
---|
327 | Aflag = TRUE;
|
---|
328 | } else {
|
---|
329 | usage(argv[0]);
|
---|
330 | }
|
---|
331 | }
|
---|
332 | idx++;
|
---|
333 | }
|
---|
334 | if (idx == argc) usage(argv[0]);
|
---|
335 |
|
---|
336 | if (strlen(argv[idx]) > 1) {
|
---|
337 | device = argv[idx++];
|
---|
338 |
|
---|
339 | /* If the device does not contain a / we assume that it
|
---|
340 | * is the name of a device in /dev. Instead of prepending
|
---|
341 | * /dev/ we try to chdir there.
|
---|
342 | */
|
---|
343 | if (strchr(device, '/') == NULL && chdir("/dev") < 0) {
|
---|
344 | perror("/dev");
|
---|
345 | exit(1);
|
---|
346 | }
|
---|
347 | } else {
|
---|
348 | if ((dev_nr = toupper (*argv[idx++])) < 'A' || dev_nr > 'Z')
|
---|
349 | usage(argv[0]);
|
---|
350 |
|
---|
351 | device[DRIVE_NR] = dev_nr;
|
---|
352 | }
|
---|
353 |
|
---|
354 | if ((disk = open(device, dos_write ? O_RDWR : O_RDONLY)) < 0) {
|
---|
355 | fprintf (stderr, "%s: cannot open %s: %s\n",
|
---|
356 | cmnd, device, strerror (errno));
|
---|
357 | exit(1);
|
---|
358 | }
|
---|
359 | determine();
|
---|
360 | disk_io(READ, ROOTADDR, root, DIR_SIZE * root_entries);
|
---|
361 |
|
---|
362 | if (dos_dir && Lflag) {
|
---|
363 | entry = label();
|
---|
364 | printf ("Volume in drive %c ", dev_nr);
|
---|
365 | if (entry == NIL_DIR)
|
---|
366 | printf("has no label.\n\n");
|
---|
367 | else
|
---|
368 | printf ("is %.11s\n\n", entry->d_name);
|
---|
369 | }
|
---|
370 | if (argv[idx] == NIL_PTR) {
|
---|
371 | if (!dos_dir) usage(argv[0]);
|
---|
372 | if (Lflag) printf ("Root directory:\n");
|
---|
373 | list_dir(root, root_entries, FALSE);
|
---|
374 | if (Lflag) free_blocks();
|
---|
375 | fflush (stdout);
|
---|
376 | exit(0);
|
---|
377 | }
|
---|
378 | for (arg_ptr = argv[idx]; *arg_ptr; arg_ptr++)
|
---|
379 | if (*arg_ptr == '\\') *arg_ptr = '/';
|
---|
380 | else *arg_ptr = toupper (*arg_ptr);
|
---|
381 | if (*--arg_ptr == '/') *arg_ptr = '\0'; /* skip trailing '/' */
|
---|
382 |
|
---|
383 | add_path(argv[idx], FALSE);
|
---|
384 | add_path("/", FALSE);
|
---|
385 |
|
---|
386 | if (dos_dir && Lflag) printf ( "Directory %s:\n", path);
|
---|
387 |
|
---|
388 | entry = find_entry(root, root_entries, argv[idx]);
|
---|
389 |
|
---|
390 | if (dos_dir) {
|
---|
391 | list_dir(entry, sub_entries, FALSE);
|
---|
392 | if (Lflag) free_blocks();
|
---|
393 | } else if (dos_read)
|
---|
394 | extract(entry);
|
---|
395 | else {
|
---|
396 | if (entry != NIL_DIR) {
|
---|
397 | fflush (stdout);
|
---|
398 | if (is_dir(entry))
|
---|
399 | fprintf (stderr, "%s: %s is a directory.\n", cmnd, path);
|
---|
400 | else
|
---|
401 | fprintf (stderr, "%s: %s already exists.\n", cmnd, argv[idx]);
|
---|
402 | exit(1);
|
---|
403 | }
|
---|
404 | add_path(NIL_PTR, TRUE);
|
---|
405 |
|
---|
406 | if (*path) make_file(find_entry(root, root_entries, path),
|
---|
407 | sub_entries, slash(argv[idx]));
|
---|
408 | else
|
---|
409 | make_file(root, root_entries, argv[idx]);
|
---|
410 | }
|
---|
411 |
|
---|
412 | (void) close(disk);
|
---|
413 | fflush (stdout);
|
---|
414 | exit(0);
|
---|
415 | return(0);
|
---|
416 | }
|
---|
417 |
|
---|
418 |
|
---|
419 | /* General directory search routine.
|
---|
420 | *
|
---|
421 | * dir:
|
---|
422 | * Points to one or more directory entries
|
---|
423 | * entries:
|
---|
424 | * number of entries
|
---|
425 | * if entries == root_entries, dir points to the entire
|
---|
426 | * root directory. Otherwise it points to a single directory
|
---|
427 | * entry describing the directory to be searched.
|
---|
428 | *
|
---|
429 | * function:
|
---|
430 | * FIND ... find pathname relative to directory dir.
|
---|
431 | * LABEL ... find first label entry in dir.
|
---|
432 | * ENTRY ... create a new empty entry.
|
---|
433 | * FALSE ... list directory
|
---|
434 | *
|
---|
435 | * pathname:
|
---|
436 | * name of the file to be found or directory to be listed.
|
---|
437 | * must be in upper case, pathname components must be
|
---|
438 | * separated by slashes, but can be longer than than
|
---|
439 | * 8+3 characters (The rest is ignored).
|
---|
440 | */
|
---|
441 | DIRECTORY *directory(dir, entries, function, pathname)
|
---|
442 | DIRECTORY *dir;
|
---|
443 | int entries;
|
---|
444 | int function;
|
---|
445 | register char *pathname;
|
---|
446 | {
|
---|
447 | register DIRECTORY *dir_ptr = dir;
|
---|
448 | DIRECTORY *mem = NIL_DIR;
|
---|
449 | unsigned short cl_no = dir->d_cluster;
|
---|
450 | unsigned short type, last = 0;
|
---|
451 | char file_name[14];
|
---|
452 | char *name;
|
---|
453 | int i = 0;
|
---|
454 |
|
---|
455 | if (function == FIND) {
|
---|
456 | while (*pathname != '/' && *pathname != '.' && *pathname &&
|
---|
457 | i < 8) {
|
---|
458 | file_name[i++] = *pathname++;
|
---|
459 | }
|
---|
460 | if (*pathname == '.') {
|
---|
461 | int j = 0;
|
---|
462 | file_name[i++] = *pathname++;
|
---|
463 | while (*pathname != '/' && *pathname != '.' && *pathname &&
|
---|
464 | j++ < 3) {
|
---|
465 | file_name[i++] = *pathname++;
|
---|
466 | }
|
---|
467 | }
|
---|
468 | while (*pathname != '/' && *pathname) pathname++;
|
---|
469 | file_name[i] = '\0';
|
---|
470 | }
|
---|
471 | do {
|
---|
472 | if (entries != root_entries) {
|
---|
473 | mem = dir_ptr = read_cluster(cl_no);
|
---|
474 | last = cl_no;
|
---|
475 | cl_no = next_cluster(cl_no);
|
---|
476 | }
|
---|
477 | for (i = 0; i < entries; i++, dir_ptr++) {
|
---|
478 | type = dir_ptr->d_name[0] & 0x0FF;
|
---|
479 | if (function == ENTRY) {
|
---|
480 | if (type == NOT_USED || type == ERASED) {
|
---|
481 | if (!mem)
|
---|
482 | mark = ROOTADDR + (long) i *(long) DIR_SIZE;
|
---|
483 | else
|
---|
484 | mark = clus_add(last) + (long) i *(long) DIR_SIZE;
|
---|
485 | return dir_ptr;
|
---|
486 | }
|
---|
487 | continue;
|
---|
488 | }
|
---|
489 | if (type == NOT_USED) break;
|
---|
490 | if (dir_ptr->d_attribute & 0x08) {
|
---|
491 | if (function == LABEL) return dir_ptr;
|
---|
492 | continue;
|
---|
493 | }
|
---|
494 | if (type == DIR || type == ERASED || function == LABEL)
|
---|
495 | continue;
|
---|
496 | type = is_dir(dir_ptr);
|
---|
497 | name = make_name(dir_ptr,
|
---|
498 | (function == FIND) ? FALSE : type);
|
---|
499 | if (function == FIND) {
|
---|
500 | if (strcmp(file_name, name) != 0) continue;
|
---|
501 | if (!type) {
|
---|
502 | if (dos_dir || *pathname) {
|
---|
503 | fflush (stdout);
|
---|
504 | fprintf (stderr, "%s: Not a directory: %s\n", cmnd, file_name);
|
---|
505 | exit(1);
|
---|
506 | }
|
---|
507 | } else if (*pathname == '\0' && dos_read) {
|
---|
508 | fflush (stdout);
|
---|
509 | fprintf (stderr, "%s: %s is a directory.\n", cmnd, path);
|
---|
510 | exit(1);
|
---|
511 | }
|
---|
512 | if (*pathname) {
|
---|
513 | dir_ptr = find_entry(dir_ptr,
|
---|
514 | sub_entries, pathname + 1);
|
---|
515 | }
|
---|
516 | if (mem) {
|
---|
517 | if (dir_ptr) {
|
---|
518 | memcpy((char *)&save_entry, (char *)dir_ptr, DIR_SIZE);
|
---|
519 | dir_ptr = &save_entry;
|
---|
520 | }
|
---|
521 | free( (void *) mem);
|
---|
522 | }
|
---|
523 | return dir_ptr;
|
---|
524 | } else {
|
---|
525 | if (function == FALSE) {
|
---|
526 | show(dir_ptr, name);
|
---|
527 | } else if (type) { /* Recursive */
|
---|
528 | printf ( "Directory %s%s:\n", path, name);
|
---|
529 | add_path(name, FALSE);
|
---|
530 | list_dir(dir_ptr, sub_entries, FALSE);
|
---|
531 | add_path(NIL_PTR, FALSE);
|
---|
532 | }
|
---|
533 | }
|
---|
534 | }
|
---|
535 | if (mem) free( (void *) mem);
|
---|
536 | } while (cl_no != LAST_CLUSTER && mem);
|
---|
537 |
|
---|
538 | switch (function) {
|
---|
539 | case FIND:
|
---|
540 | if (dos_write && *pathname == '\0') return NIL_DIR;
|
---|
541 | fflush (stdout);
|
---|
542 | fprintf (stderr, "%s: Cannot find `%s'.\n", cmnd, file_name);
|
---|
543 | exit(1);
|
---|
544 | case LABEL:
|
---|
545 | return NIL_DIR;
|
---|
546 | case ENTRY:
|
---|
547 | if (!mem) {
|
---|
548 | fflush (stdout);
|
---|
549 | fprintf (stderr, "%s: No entries left in root directory.\n", cmnd);
|
---|
550 | exit(1);
|
---|
551 | }
|
---|
552 | cl_no = free_cluster(TRUE);
|
---|
553 | link_fat(last, cl_no);
|
---|
554 | link_fat(cl_no, LAST_CLUSTER);
|
---|
555 | disk_io(WRITE, clus_add(cl_no), null, cluster_size);
|
---|
556 |
|
---|
557 | return new_entry(dir, entries);
|
---|
558 | case FALSE:
|
---|
559 | if (Rflag) {
|
---|
560 | printf ("\n");
|
---|
561 | list_dir(dir, entries, TRUE);
|
---|
562 | }
|
---|
563 | }
|
---|
564 | return NULL;
|
---|
565 | }
|
---|
566 |
|
---|
567 | void extract(entry)
|
---|
568 | register DIRECTORY *entry;
|
---|
569 | {
|
---|
570 | register unsigned short cl_no = entry->d_cluster;
|
---|
571 | char buffer[MAX_CLUSTER_SIZE];
|
---|
572 | int rest, i;
|
---|
573 |
|
---|
574 | if (entry->d_size == 0) /* Empty file */
|
---|
575 | return;
|
---|
576 |
|
---|
577 | do {
|
---|
578 | disk_io(READ, clus_add(cl_no), buffer, cluster_size);
|
---|
579 | rest = (entry->d_size > (long) cluster_size) ? cluster_size : (short) entry->d_size;
|
---|
580 |
|
---|
581 | if (Aflag) {
|
---|
582 | for (i = 0; i < rest; i ++) {
|
---|
583 | if (buffer [i] != '\r') putchar (buffer [i]);
|
---|
584 | }
|
---|
585 | if (ferror (stdout)) {
|
---|
586 | fprintf (stderr, "%s: cannot write to stdout: %s\n",
|
---|
587 | cmnd, strerror (errno));
|
---|
588 | exit (1);
|
---|
589 | }
|
---|
590 | } else {
|
---|
591 | if (fwrite (buffer, 1, rest, stdout) != rest) {
|
---|
592 | fprintf (stderr, "%s: cannot write to stdout: %s\n",
|
---|
593 | cmnd, strerror (errno));
|
---|
594 | exit (1);
|
---|
595 | }
|
---|
596 | }
|
---|
597 | entry->d_size -= (long) rest;
|
---|
598 | cl_no = next_cluster(cl_no);
|
---|
599 | if (cl_no == BAD16) {
|
---|
600 | fflush (stdout);
|
---|
601 | fprintf (stderr, "%s: reserved cluster value %x encountered.\n",
|
---|
602 | cmnd, cl_no);
|
---|
603 | exit (1);
|
---|
604 | }
|
---|
605 | } while (entry->d_size && cl_no != LAST_CLUSTER);
|
---|
606 |
|
---|
607 | if (cl_no != LAST_CLUSTER)
|
---|
608 | fprintf (stderr, "%s: Too many clusters allocated for file.\n", cmnd);
|
---|
609 | else if (entry->d_size != 0)
|
---|
610 | fprintf (stderr, "%s: Premature EOF: %ld bytes left.\n", cmnd,
|
---|
611 | entry->d_size);
|
---|
612 | }
|
---|
613 |
|
---|
614 |
|
---|
615 | /* Minimum of two long values
|
---|
616 | */
|
---|
617 | long lmin (a, b)
|
---|
618 | long a, b;
|
---|
619 | {
|
---|
620 | if (a < b) return a;
|
---|
621 | else return b;
|
---|
622 | }
|
---|
623 |
|
---|
624 |
|
---|
625 | void make_file(dir_ptr, entries, name)
|
---|
626 | DIRECTORY *dir_ptr;
|
---|
627 | int entries;
|
---|
628 | char *name;
|
---|
629 | {
|
---|
630 | register DIRECTORY *entry = new_entry(dir_ptr, entries);
|
---|
631 | register char *ptr;
|
---|
632 | char buffer[MAX_CLUSTER_SIZE];
|
---|
633 | unsigned short cl_no = 0;
|
---|
634 | int i, r;
|
---|
635 | long size = 0L;
|
---|
636 | unsigned short first_cluster, last_cluster;
|
---|
637 | long chunk;
|
---|
638 |
|
---|
639 | memset (&entry->d_name[0], ' ', 11); /* clear entry */
|
---|
640 | for (i = 0, ptr = name; i < 8 && *ptr != '.' && *ptr; i++)
|
---|
641 | entry->d_name[i] = *ptr++;
|
---|
642 | while (*ptr != '.' && *ptr) ptr++;
|
---|
643 | if (*ptr == '.') ptr++;
|
---|
644 | for (i = 0; i < 3 && *ptr != '.' && *ptr; i++) entry->d_ext[i] = *ptr++;
|
---|
645 |
|
---|
646 | for (i = 0; i < 10; i++) entry->d_reserved[i] = '\0';
|
---|
647 | entry->d_attribute = '\0';
|
---|
648 |
|
---|
649 | entry->d_cluster = 0;
|
---|
650 |
|
---|
651 | while (free_range (&first_cluster, &last_cluster)) {
|
---|
652 | do {
|
---|
653 | unsigned short nr_clus;
|
---|
654 |
|
---|
655 | chunk = lmin ((long) (last_cluster - first_cluster + 1) *
|
---|
656 | cluster_size,
|
---|
657 | (long) MAX_CLUSTER_SIZE);
|
---|
658 | r = fill(buffer, chunk);
|
---|
659 | if (r == 0) goto done;
|
---|
660 | nr_clus = (r + cluster_size - 1) / cluster_size;
|
---|
661 | disk_io(WRITE, clus_add(first_cluster), buffer, r);
|
---|
662 |
|
---|
663 | for (i = 0; i < nr_clus; i ++) {
|
---|
664 | if (entry->d_cluster == 0)
|
---|
665 | cl_no = entry->d_cluster = first_cluster;
|
---|
666 | else {
|
---|
667 | link_fat(cl_no, first_cluster);
|
---|
668 | cl_no = first_cluster;
|
---|
669 | }
|
---|
670 | first_cluster ++;
|
---|
671 | }
|
---|
672 |
|
---|
673 | size += r;
|
---|
674 | } while (first_cluster <= last_cluster);
|
---|
675 | }
|
---|
676 | fprintf (stderr, "%s: disk full. File truncated\n", cmnd);
|
---|
677 | done:
|
---|
678 | if (entry->d_cluster != 0) link_fat(cl_no, LAST_CLUSTER);
|
---|
679 | entry->d_size = size;
|
---|
680 | fill_date(entry);
|
---|
681 | disk_io(WRITE, mark, entry, DIR_SIZE);
|
---|
682 |
|
---|
683 | if (fat_dirty) flush_fat ();
|
---|
684 |
|
---|
685 | }
|
---|
686 |
|
---|
687 |
|
---|
688 | #define SEC_MIN 60L
|
---|
689 | #define SEC_HOUR (60L * SEC_MIN)
|
---|
690 | #define SEC_DAY (24L * SEC_HOUR)
|
---|
691 | #define SEC_YEAR (365L * SEC_DAY)
|
---|
692 | #define SEC_LYEAR (366L * SEC_DAY)
|
---|
693 |
|
---|
694 | unsigned short mon_len[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
---|
695 |
|
---|
696 | void fill_date(entry)
|
---|
697 | DIRECTORY *entry;
|
---|
698 | {
|
---|
699 | register long cur_time = time((long *) 0) - DOS_TIME;
|
---|
700 | unsigned short year = 0, month = 1, day, hour, minutes, seconds;
|
---|
701 | int i;
|
---|
702 | long tmp;
|
---|
703 |
|
---|
704 | if (cur_time < 0) /* Date not set on booting ... */
|
---|
705 | cur_time = 0;
|
---|
706 | for (;;) {
|
---|
707 | tmp = (year % 4 == 0) ? SEC_LYEAR : SEC_YEAR;
|
---|
708 | if (cur_time < tmp) break;
|
---|
709 | cur_time -= tmp;
|
---|
710 | year++;
|
---|
711 | }
|
---|
712 |
|
---|
713 | day = (unsigned short) (cur_time / SEC_DAY);
|
---|
714 | cur_time -= (long) day *SEC_DAY;
|
---|
715 |
|
---|
716 | hour = (unsigned short) (cur_time / SEC_HOUR);
|
---|
717 | cur_time -= (long) hour *SEC_HOUR;
|
---|
718 |
|
---|
719 | minutes = (unsigned short) (cur_time / SEC_MIN);
|
---|
720 | cur_time -= (long) minutes *SEC_MIN;
|
---|
721 |
|
---|
722 | seconds = (unsigned short) cur_time;
|
---|
723 |
|
---|
724 | mon_len[1] = (year % 4 == 0) ? 29 : 28;
|
---|
725 | i = 0;
|
---|
726 | while (day >= mon_len[i]) {
|
---|
727 | month++;
|
---|
728 | day -= mon_len[i++];
|
---|
729 | }
|
---|
730 | day++;
|
---|
731 |
|
---|
732 | entry->d_date = (year << 9) | (month << 5) | day;
|
---|
733 | entry->d_time = (hour << 11) | (minutes << 5) | seconds;
|
---|
734 | }
|
---|
735 |
|
---|
736 | char *make_name(dir_ptr, dir_fl)
|
---|
737 | register DIRECTORY *dir_ptr;
|
---|
738 | short dir_fl;
|
---|
739 | {
|
---|
740 | static char name_buf[14];
|
---|
741 | register char *ptr = name_buf;
|
---|
742 | short i;
|
---|
743 |
|
---|
744 | for (i = 0; i < 8; i++) *ptr++ = dir_ptr->d_name[i];
|
---|
745 |
|
---|
746 | while (*--ptr == ' ');
|
---|
747 | assert (ptr >= name_buf);
|
---|
748 |
|
---|
749 | ptr++;
|
---|
750 | if (dir_ptr->d_ext[0] != ' ') {
|
---|
751 | *ptr++ = '.';
|
---|
752 | for (i = 0; i < 3; i++) *ptr++ = dir_ptr->d_ext[i];
|
---|
753 | while (*--ptr == ' ');
|
---|
754 | ptr++;
|
---|
755 | }
|
---|
756 | if (dir_fl) *ptr++ = '/';
|
---|
757 | *ptr = '\0';
|
---|
758 |
|
---|
759 | return name_buf;
|
---|
760 | }
|
---|
761 |
|
---|
762 |
|
---|
763 | int fill(buffer, size)
|
---|
764 | register char *buffer;
|
---|
765 | size_t size;
|
---|
766 | {
|
---|
767 | static BOOL nl_mark = FALSE;
|
---|
768 | char *last = &buffer[size];
|
---|
769 | char *begin = buffer;
|
---|
770 | register int c;
|
---|
771 |
|
---|
772 | while (buffer < last) {
|
---|
773 | if (nl_mark) {
|
---|
774 | *buffer ++ = '\n';
|
---|
775 | nl_mark = FALSE;
|
---|
776 | } else {
|
---|
777 | c = getchar();
|
---|
778 | if (c == EOF) break;
|
---|
779 | if (Aflag && c == '\n') {
|
---|
780 | *buffer ++ = '\r';
|
---|
781 | nl_mark = TRUE;
|
---|
782 | } else {
|
---|
783 | *buffer++ = c;
|
---|
784 | }
|
---|
785 | }
|
---|
786 | }
|
---|
787 |
|
---|
788 | return (buffer - begin);
|
---|
789 | }
|
---|
790 |
|
---|
791 | #define HOUR 0xF800 /* Upper 5 bits */
|
---|
792 | #define MIN 0x07E0 /* Middle 6 bits */
|
---|
793 | #define YEAR 0xFE00 /* Upper 7 bits */
|
---|
794 | #define MONTH 0x01E0 /* Mid 4 bits */
|
---|
795 | #define DAY 0x01F /* Lowest 5 bits */
|
---|
796 |
|
---|
797 | char *month[] = {
|
---|
798 | "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
---|
799 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
---|
800 | };
|
---|
801 |
|
---|
802 | void xmodes(mode)
|
---|
803 | int mode;
|
---|
804 | {
|
---|
805 | printf ( "\t%c%c%c%c%c", (mode & SUB_DIR) ? 'd' : '-',
|
---|
806 | (mode & 02) ? 'h' : '-', (mode & 04) ? 's' : '-',
|
---|
807 | (mode & 01) ? '-' : 'w', (mode & 0x20) ? 'a' : '-');
|
---|
808 | }
|
---|
809 |
|
---|
810 | void show(dir_ptr, name)
|
---|
811 | DIRECTORY *dir_ptr;
|
---|
812 | char *name;
|
---|
813 | {
|
---|
814 | register unsigned short e_date = dir_ptr->d_date;
|
---|
815 | register unsigned short e_time = dir_ptr->d_time;
|
---|
816 | unsigned short next;
|
---|
817 | char bname[20];
|
---|
818 | short i = 0;
|
---|
819 |
|
---|
820 | while (*name && *name != '/') bname[i++] = *name++;
|
---|
821 | bname[i] = '\0';
|
---|
822 | if (!Lflag) {
|
---|
823 | printf ( "%s\n", bname);
|
---|
824 | return;
|
---|
825 | }
|
---|
826 | xmodes( (int) dir_ptr->d_attribute);
|
---|
827 | printf ( "\t%s%s", bname, strlen(bname) < 8 ? "\t\t" : "\t");
|
---|
828 | i = 1;
|
---|
829 | if (is_dir(dir_ptr)) {
|
---|
830 | next = dir_ptr->d_cluster;
|
---|
831 | while ((next = next_cluster(next)) != LAST_CLUSTER) i++;
|
---|
832 | printf ("%8ld", (long) i * (long) cluster_size);
|
---|
833 | } else
|
---|
834 | printf ("%8ld", dir_ptr->d_size);
|
---|
835 | printf (" %02d:%02d %2d %s %d\n", ((e_time & HOUR) >> 11),
|
---|
836 | ((e_time & MIN) >> 5), (e_date & DAY),
|
---|
837 | month[((e_date & MONTH) >> 5) - 1], ((e_date & YEAR) >> 9) + 1980);
|
---|
838 | }
|
---|
839 |
|
---|
840 | void free_blocks()
|
---|
841 | {
|
---|
842 | register unsigned short cl_no;
|
---|
843 | long nr_free = 0;
|
---|
844 | long nr_bad = 0;
|
---|
845 |
|
---|
846 | for (cl_no = 2; cl_no < total_clusters; cl_no++) {
|
---|
847 | switch (next_cluster(cl_no)) {
|
---|
848 | case FREE: nr_free++; break;
|
---|
849 | case BAD16: nr_bad++; break;
|
---|
850 | }
|
---|
851 | }
|
---|
852 |
|
---|
853 | printf ("Free space: %ld bytes.\n", nr_free * (long) cluster_size);
|
---|
854 | if (nr_bad != 0)
|
---|
855 | printf ("Bad sectors: %ld bytes.\n", nr_bad * (long) cluster_size);
|
---|
856 | }
|
---|
857 |
|
---|
858 |
|
---|
859 | DIRECTORY *read_cluster(cluster)
|
---|
860 | register unsigned int cluster;
|
---|
861 | {
|
---|
862 | register DIRECTORY *sub_dir;
|
---|
863 |
|
---|
864 | if ((sub_dir = malloc(cluster_size)) == NULL) {
|
---|
865 | fprintf (stderr, "%s: Cannot set break!\n", cmnd);
|
---|
866 | exit(1);
|
---|
867 | }
|
---|
868 | disk_io(READ, clus_add(cluster), sub_dir, cluster_size);
|
---|
869 |
|
---|
870 | return sub_dir;
|
---|
871 | }
|
---|
872 |
|
---|
873 | static unsigned short cl_index = 2;
|
---|
874 |
|
---|
875 | /* find a range of consecutive free clusters. Return TRUE if found
|
---|
876 | * and return the first and last cluster in the |*first| and |*last|.
|
---|
877 | * If no free clusters are left, return FALSE.
|
---|
878 | *
|
---|
879 | * Warning: Assumes that all of the range is used before the next call
|
---|
880 | * to free_range or free_cluster.
|
---|
881 | */
|
---|
882 | BOOL free_range (first, last)
|
---|
883 | unsigned short *first, *last;
|
---|
884 | {
|
---|
885 | while (cl_index < total_clusters && next_cluster(cl_index) != FREE)
|
---|
886 | cl_index++;
|
---|
887 | if (cl_index >= total_clusters) return FALSE;
|
---|
888 | *first = cl_index;
|
---|
889 | while (cl_index < total_clusters && next_cluster(cl_index) == FREE)
|
---|
890 | cl_index++;
|
---|
891 | *last = cl_index - 1;
|
---|
892 | return TRUE;
|
---|
893 | }
|
---|
894 |
|
---|
895 |
|
---|
896 | /* find a free cluster.
|
---|
897 | * Return the number of the free cluster or a number > |total_clusters|
|
---|
898 | * if none is found.
|
---|
899 | * If |leave_fl| is TRUE, the the program will be terminated if
|
---|
900 | * no free cluster can be found
|
---|
901 | *
|
---|
902 | * Warning: Assumes that the cluster is used before the next call
|
---|
903 | * to free_range or free_cluster.
|
---|
904 | */
|
---|
905 | unsigned short free_cluster(leave_fl)
|
---|
906 | BOOL leave_fl;
|
---|
907 | {
|
---|
908 | while (cl_index < total_clusters && next_cluster(cl_index) != FREE)
|
---|
909 | cl_index++;
|
---|
910 |
|
---|
911 | if (leave_fl && cl_index >= total_clusters) {
|
---|
912 | fprintf (stderr, "%s: Diskette full. File not added.\n", cmnd);
|
---|
913 | exit(1);
|
---|
914 | }
|
---|
915 | return cl_index++;
|
---|
916 | }
|
---|
917 |
|
---|
918 |
|
---|
919 | /* read a portion of the fat containing |cl_no| into the cache
|
---|
920 | */
|
---|
921 | void read_fat (cl_no)
|
---|
922 | unsigned int cl_no;
|
---|
923 | {
|
---|
924 |
|
---|
925 | if (!cooked_fat) {
|
---|
926 | /* Read the fat for the first time. We have to allocate all the
|
---|
927 | * buffers
|
---|
928 | */
|
---|
929 | if (fat_16) {
|
---|
930 | /* FAT consists of little endian shorts. Easy to convert
|
---|
931 | */
|
---|
932 | if ((cooked_fat = malloc (fat_size)) == NULL) {
|
---|
933 | /* Oops, FAT doesn't fit into memory, just read
|
---|
934 | * a chunk
|
---|
935 | */
|
---|
936 | if ((cooked_fat = malloc (COOKED_SIZE)) == NULL) {
|
---|
937 | fprintf (stderr, "%s: not enough memory for FAT cache. Use chmem\n",
|
---|
938 | cmnd);
|
---|
939 | exit (1);
|
---|
940 | }
|
---|
941 | cache_size = COOKED_SIZE / 2;
|
---|
942 | } else {
|
---|
943 | cache_size = fat_size / 2;
|
---|
944 | }
|
---|
945 | } else {
|
---|
946 | /* 12 bit FAT. Difficult encoding, but small. Keep
|
---|
947 | * both raw FAT and cooked version in memory.
|
---|
948 | */
|
---|
949 | if ((cooked_fat = malloc (total_clusters * sizeof (short))) == NULL ||
|
---|
950 | (raw_fat = malloc (fat_size)) == NULL) {
|
---|
951 | fprintf (stderr, "%s: not enough memory for FAT cache. Use chmem\n",
|
---|
952 | cmnd);
|
---|
953 | exit (1);
|
---|
954 | }
|
---|
955 | cache_size = total_clusters;
|
---|
956 | }
|
---|
957 | }
|
---|
958 | fat_low = cl_no / cache_size * cache_size;
|
---|
959 | fat_high = fat_low + cache_size - 1;
|
---|
960 |
|
---|
961 | if (!fat_16) {
|
---|
962 | unsigned short *cp;
|
---|
963 | unsigned char *rp;
|
---|
964 | unsigned short i;
|
---|
965 |
|
---|
966 | disk_io (READ, FAT_START, raw_fat, fat_size);
|
---|
967 | for (rp = raw_fat, cp = cooked_fat, i = 0;
|
---|
968 | i < cache_size;
|
---|
969 | rp += 3, i += 2) {
|
---|
970 | *cp = *rp + ((*(rp + 1) & 0x0f) << 8);
|
---|
971 | if (*cp == BAD) *cp = BAD16;
|
---|
972 | else if (*cp == LAST_CLUSTER12) *cp = LAST_CLUSTER;
|
---|
973 | cp ++;
|
---|
974 | *cp = ((*(rp + 1) & 0xf0) >> 4) + (*(rp + 2) << 4);
|
---|
975 | if (*cp == BAD) *cp = BAD16;
|
---|
976 | else if (*cp == LAST_CLUSTER12) *cp = LAST_CLUSTER;
|
---|
977 | cp ++;
|
---|
978 | }
|
---|
979 | } else {
|
---|
980 |
|
---|
981 | assert (sizeof (short) == 2);
|
---|
982 | assert (CHAR_BIT == 8); /* just in case */
|
---|
983 |
|
---|
984 | disk_io (READ, FAT_START + fat_low * 2, (void *)cooked_fat, cache_size * 2);
|
---|
985 | if (big_endian) {
|
---|
986 | unsigned short *cp;
|
---|
987 | unsigned char *rp;
|
---|
988 | unsigned short i;
|
---|
989 |
|
---|
990 | for (i = 0, rp = (unsigned char *)cooked_fat /* sic */, cp = cooked_fat;
|
---|
991 | i < cache_size;
|
---|
992 | rp += 2, cp ++, i ++) {
|
---|
993 | *cp = c2u2 (rp);
|
---|
994 | }
|
---|
995 | }
|
---|
996 | }
|
---|
997 | }
|
---|
998 |
|
---|
999 |
|
---|
1000 | /* flush the fat cache out to disk
|
---|
1001 | */
|
---|
1002 | void flush_fat ()
|
---|
1003 | {
|
---|
1004 | if (fat_16) {
|
---|
1005 | if (big_endian) {
|
---|
1006 | unsigned short *cp;
|
---|
1007 | unsigned char *rp;
|
---|
1008 | unsigned short i;
|
---|
1009 |
|
---|
1010 | for (i = 0, rp = (unsigned char *)cooked_fat /* sic */, cp = cooked_fat;
|
---|
1011 | i < cache_size;
|
---|
1012 | rp += 2, cp ++, i ++) {
|
---|
1013 | *rp = *cp;
|
---|
1014 | *(rp + 1) = *cp >> 8;
|
---|
1015 | }
|
---|
1016 | }
|
---|
1017 | disk_io (WRITE, FAT_START + fat_low * 2, (void *)cooked_fat, cache_size * 2);
|
---|
1018 | disk_io (WRITE, FAT_START + fat_size + fat_low * 2, (void *)cooked_fat, cache_size * 2);
|
---|
1019 | } else {
|
---|
1020 | unsigned short *cp;
|
---|
1021 | unsigned char *rp;
|
---|
1022 | unsigned short i;
|
---|
1023 |
|
---|
1024 | for (rp = raw_fat, cp = cooked_fat, i = 0;
|
---|
1025 | i < cache_size;
|
---|
1026 | rp += 3, cp += 2, i += 2) {
|
---|
1027 | *rp = *cp;
|
---|
1028 | *(rp + 1) = ((*cp & 0xf00) >> 8) |
|
---|
1029 | ((*(cp + 1) & 0x00f) << 4);
|
---|
1030 | *(rp + 2) = ((*(cp + 1) & 0xff0) >> 4);
|
---|
1031 | }
|
---|
1032 | disk_io (WRITE, FAT_START, raw_fat, fat_size);
|
---|
1033 | disk_io (WRITE, FAT_START + fat_size, raw_fat, fat_size);
|
---|
1034 | }
|
---|
1035 | }
|
---|
1036 |
|
---|
1037 |
|
---|
1038 | /* make cl_2 the successor of cl_1
|
---|
1039 | */
|
---|
1040 | void link_fat(cl_1, cl_2)
|
---|
1041 | unsigned int cl_1;
|
---|
1042 | unsigned int cl_2;
|
---|
1043 | {
|
---|
1044 | if (cl_1 < fat_low || cl_1 > fat_high) {
|
---|
1045 | if (fat_dirty) flush_fat ();
|
---|
1046 | read_fat (cl_1);
|
---|
1047 | }
|
---|
1048 | cooked_fat [cl_1 - fat_low] = cl_2;
|
---|
1049 | fat_dirty = TRUE;
|
---|
1050 | }
|
---|
1051 |
|
---|
1052 |
|
---|
1053 | unsigned short next_cluster(cl_no)
|
---|
1054 | register unsigned int cl_no;
|
---|
1055 | {
|
---|
1056 | if (cl_no < fat_low || cl_no > fat_high) {
|
---|
1057 | if (fat_dirty) flush_fat ();
|
---|
1058 | read_fat (cl_no);
|
---|
1059 | }
|
---|
1060 | return cooked_fat [cl_no - fat_low];
|
---|
1061 | }
|
---|
1062 |
|
---|
1063 | char *slash(str)
|
---|
1064 | register char *str;
|
---|
1065 | {
|
---|
1066 | register char *result = str;
|
---|
1067 |
|
---|
1068 | while (*str)
|
---|
1069 | if (*str++ == '/') result = str;
|
---|
1070 |
|
---|
1071 | return result;
|
---|
1072 | }
|
---|
1073 |
|
---|
1074 | void add_path(file, slash_fl)
|
---|
1075 | char *file;
|
---|
1076 | BOOL slash_fl;
|
---|
1077 | {
|
---|
1078 | register char *ptr = path;
|
---|
1079 |
|
---|
1080 | while (*ptr) ptr++;
|
---|
1081 |
|
---|
1082 | if (file == NIL_PTR) {
|
---|
1083 | if (ptr != path) ptr--;
|
---|
1084 | if (ptr != path) do {
|
---|
1085 | ptr--;
|
---|
1086 | } while (*ptr != '/' && ptr != path);
|
---|
1087 | if (ptr != path && !slash_fl) *ptr++ = '/';
|
---|
1088 | *ptr = '\0';
|
---|
1089 | } else
|
---|
1090 | strcpy (ptr, file);
|
---|
1091 | }
|
---|
1092 |
|
---|
1093 |
|
---|
1094 | void disk_io(op, seek, address, bytes)
|
---|
1095 | register BOOL op;
|
---|
1096 | unsigned long seek;
|
---|
1097 | void *address;
|
---|
1098 | register unsigned bytes;
|
---|
1099 | {
|
---|
1100 | unsigned int r;
|
---|
1101 |
|
---|
1102 | if (lseek(disk, seek, SEEK_SET) < 0L) {
|
---|
1103 | fflush (stdout);
|
---|
1104 | fprintf (stderr, "%s: Bad lseek: %s\n", cmnd, strerror (errno));
|
---|
1105 | exit(1);
|
---|
1106 | }
|
---|
1107 | if (op == READ)
|
---|
1108 | r = read(disk, (char *) address, bytes);
|
---|
1109 | else {
|
---|
1110 | r = write(disk, (char *) address, bytes);
|
---|
1111 | }
|
---|
1112 |
|
---|
1113 | if (r != bytes) {
|
---|
1114 | fprintf (stderr, "%s: read error: %s\n", cmnd, strerror (errno));
|
---|
1115 | exit (1);
|
---|
1116 | }
|
---|
1117 | }
|
---|
1118 |
|
---|
1119 | char dosread_c_rcs_id [] =
|
---|
1120 | "$Id: dosread.c,v 1.2 2005/07/13 10:02:14 beng Exp $";
|
---|