00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <assert.h>
00015 #include <ctype.h>
00016 #include <errno.h>
00017 #include <limits.h>
00018 #include <sys/types.h>
00019 #include <sys/stat.h>
00020 #include <fcntl.h>
00021 #include <stdlib.h>
00022 #include <stdio.h>
00023 #include <string.h>
00024 #include <time.h>
00025 #include <sys/times.h>
00026 #include <unistd.h>
00027
00028
00029 #define MAX_CLUSTER_SIZE 4096
00030 #define MAX_ROOT_ENTRIES 512
00031 #define FAT_START 512L
00032 #define ROOTADDR (FAT_START + 2L * fat_size)
00033 #define clus_add(cl_no) ((long) (((long) cl_no - 2L) \
00034 * (long) cluster_size \
00035 + data_start \
00036 ))
00037 struct dir_entry {
00038 unsigned char d_name[8];
00039 unsigned char d_ext[3];
00040 unsigned char d_attribute;
00041 unsigned char d_reserved[10];
00042 unsigned short d_time;
00043 unsigned short d_date;
00044 unsigned short d_cluster;
00045 unsigned long d_size;
00046 };
00047
00048 typedef struct dir_entry DIRECTORY;
00049
00050 #define NOT_USED 0x00
00051 #define ERASED 0xE5
00052 #define DIR 0x2E
00053 #define DIR_SIZE (sizeof (struct dir_entry))
00054 #define SUB_DIR 0x10
00055 #define NIL_DIR ((DIRECTORY *) 0)
00056
00057 #define LAST_CLUSTER12 0xFFF
00058 #define LAST_CLUSTER 0xFFFF
00059 #define FREE 0x000
00060 #define BAD 0xFF0
00061 #define BAD16 0xFFF0
00062
00063 typedef int BOOL;
00064
00065 #define TRUE 1
00066 #define FALSE 0
00067 #define NIL_PTR ((char *) 0)
00068
00069 #define DOS_TIME 315532800L
00070
00071 #define READ 0
00072 #define WRITE 1
00073
00074 #define FIND 3
00075 #define LABEL 4
00076 #define ENTRY 5
00077 #define find_entry(d, e, p) directory(d, e, FIND, p)
00078 #define list_dir(d, e, f) (void) directory(d, e, f, NIL_PTR)
00079 #define label() directory(root, root_entries, LABEL, NIL_PTR)
00080 #define new_entry(d, e) directory(d, e, ENTRY, NIL_PTR)
00081
00082 #define is_dir(d) ((d)->d_attribute & SUB_DIR)
00083
00084 #define STD_OUT 1
00085
00086 char *cmnd;
00087
00088 static int disk;
00089
00090 static DIRECTORY root[MAX_ROOT_ENTRIES];
00091 static DIRECTORY save_entry;
00092 static char drive[] = "/dev/dosX";
00093 #define DRIVE_NR (sizeof (drive) - 2)
00094 static char null[MAX_CLUSTER_SIZE], *device = drive, path[128];
00095 static long data_start;
00096 static long mark;
00097 static unsigned short total_clusters, cluster_size, root_entries, sub_entries;
00098 static unsigned long fat_size;
00099
00100 static BOOL Rflag, Lflag, Aflag, dos_read, dos_write, dos_dir, fat_16 = 0;
00101 static BOOL big_endian;
00102
00103
00104
00105
00106 #define COOKED_SIZE 8192
00107
00108
00109 static unsigned char *raw_fat;
00110
00111
00112 static unsigned short *cooked_fat;
00113
00114
00115 static unsigned short fat_low = USHRT_MAX,
00116 fat_high = 0;
00117 static BOOL fat_dirty = FALSE;
00118 static unsigned int cache_size;
00119
00120
00121
00122 _PROTOTYPE(void usage, (char *prog_name) );
00123 _PROTOTYPE(unsigned c2u2, (unsigned char *ucarray) );
00124 _PROTOTYPE(unsigned long c4u4, (unsigned char *ucarray) );
00125 _PROTOTYPE(void determine, (void));
00126 _PROTOTYPE(int main, (int argc, char *argv []));
00127 _PROTOTYPE(DIRECTORY *directory, (DIRECTORY *dir, int entries, BOOL function, char *pathname) );
00128 _PROTOTYPE(void extract, (DIRECTORY *entry) );
00129 _PROTOTYPE(void make_file, (DIRECTORY *dir_ptr, int entries, char *name) );
00130 _PROTOTYPE(void fill_date, (DIRECTORY *entry) );
00131 _PROTOTYPE(char *make_name, (DIRECTORY *dir_ptr, int dir_fl) );
00132 _PROTOTYPE(int fill, (char *buffer, size_t size) );
00133 _PROTOTYPE(void xmodes, (int mode) );
00134 _PROTOTYPE(void show, (DIRECTORY *dir_ptr, char *name) );
00135 _PROTOTYPE(void free_blocks, (void));
00136 _PROTOTYPE(DIRECTORY *read_cluster, (unsigned int cluster) );
00137 _PROTOTYPE(unsigned short free_cluster, (BOOL leave_fl) );
00138 _PROTOTYPE(void link_fat, (unsigned int cl_1, unsigned int cl_2) );
00139 _PROTOTYPE(unsigned short next_cluster, (unsigned int cl_no) );
00140 _PROTOTYPE(char *slash, (char *str) );
00141 _PROTOTYPE(void add_path, (char *file, BOOL slash_fl) );
00142 _PROTOTYPE(void disk_io, (BOOL op, unsigned long seek, void *address, unsigned bytes) );
00143 _PROTOTYPE(void flush_fat, (void));
00144 _PROTOTYPE(void read_fat, (unsigned int cl_no));
00145 _PROTOTYPE(BOOL free_range, (unsigned short *first, unsigned short *last));
00146 _PROTOTYPE(long lmin, (long a, long b));
00147
00148
00149 void usage(prog_name)
00150 register char *prog_name;
00151 {
00152 fprintf (stderr, "Usage: %s [%s\n", prog_name,
00153 (dos_dir ? "-lr] drive [dir]" : "-a] drive file"));
00154 exit(1);
00155 }
00156
00157 unsigned c2u2(ucarray)
00158 unsigned char *ucarray;
00159 {
00160 return ucarray[0] + (ucarray[1] << 8);
00161 }
00162
00163 unsigned long c4u4(ucarray)
00164 unsigned char *ucarray;
00165 {
00166 return ucarray[0] + ((unsigned long) ucarray[1] << 8) +
00167 ((unsigned long) ucarray[2] << 16) +
00168 ((unsigned long) ucarray[3] << 24);
00169 }
00170
00171 void determine()
00172 {
00173 struct dosboot {
00174 unsigned char cjump[2];
00175 unsigned char nop;
00176 unsigned char name[8];
00177 unsigned char cbytepers[2];
00178 unsigned char secpclus;
00179 unsigned char creservsec[2];
00180 unsigned char fats;
00181 unsigned char cdirents[2];
00182 unsigned char ctotsec[2];
00183 unsigned char media;
00184 unsigned char csecpfat[2];
00185 unsigned char csecptrack[2];
00186 unsigned char cheads[2];
00187 unsigned char chiddensec[2];
00188 unsigned char dos4hidd2[2];
00189 unsigned char dos4totsec[4];
00190
00191 } boot;
00192 unsigned short boot_magic;
00193 unsigned bytepers, reservsec, dirents;
00194 unsigned secpfat, secptrack, heads, hiddensec;
00195 unsigned long totsec;
00196 unsigned char fat_info, fat_check;
00197 unsigned short endiantest = 1;
00198 int errcount = 0;
00199
00200 big_endian = !(*(unsigned char *)&endiantest);
00201
00202
00203 disk_io(READ, 0L, &boot, sizeof boot);
00204 disk_io(READ, 0x1FEL, &boot_magic, sizeof boot_magic);
00205
00206
00207 bytepers = c2u2(boot.cbytepers);
00208 reservsec = c2u2(boot.creservsec);
00209 dirents = c2u2(boot.cdirents);
00210 totsec = c2u2(boot.ctotsec);
00211 if (totsec == 0) totsec = c4u4(boot.dos4totsec);
00212 secpfat = c2u2(boot.csecpfat);
00213 secptrack = c2u2(boot.csecptrack);
00214 heads = c2u2(boot.cheads);
00215
00216
00217
00218
00219
00220
00221 hiddensec = c2u2(boot.chiddensec);
00222 if (hiddensec == 0) hiddensec = c2u2 (boot.dos4hidd2);
00223
00224
00225 if (boot_magic != 0xAA55) {
00226 fprintf (stderr, "%s: magic != 0xAA55\n", cmnd);
00227 ++errcount;
00228 }
00229
00230
00231 if (secptrack < 15 && /* assume > 15 hard disk & wini OK */
00232 #ifdef SECT10
00233 secptrack != 10 &&
00234 #endif
00235 #ifdef SECT8
00236 secptrack != 8 &&
00237 #endif
00238 secptrack != 9) {
00239 fprintf (stderr, "%s: %d sectors per track not supported\n", cmnd, secptrack);
00240 ++errcount;
00241 }
00242 if (bytepers == 0) {
00243 fprintf (stderr, "%s: bytes per sector == 0\n", cmnd);
00244 ++errcount;
00245 }
00246 if (boot.secpclus == 0) {
00247 fprintf (stderr, "%s: sectors per cluster == 0\n", cmnd);
00248 ++errcount;
00249 }
00250 if (boot.fats != 2 && dos_write) {
00251 fprintf (stderr, "%s: fats != 2\n", cmnd);
00252 ++errcount;
00253 }
00254 if (reservsec != 1) {
00255 fprintf (stderr, "%s: reserved != 1\n", cmnd);
00256 ++errcount;
00257 }
00258 if (errcount != 0) {
00259 fprintf (stderr, "%s: Can't handle disk\n", cmnd);
00260 exit(2);
00261 }
00262
00263
00264 if (boot.secpclus == 0) boot.secpclus = 1;
00265 total_clusters =
00266 (totsec - boot.fats * secpfat - reservsec -
00267 dirents * 32L / bytepers ) / boot.secpclus + 2;
00268
00269 cluster_size = bytepers * boot.secpclus;
00270 fat_size = (unsigned long) secpfat * (unsigned long) bytepers;
00271 data_start = (long) bytepers + (long) boot.fats * fat_size
00272 + (long) dirents *32L;
00273 root_entries = dirents;
00274 sub_entries = boot.secpclus * bytepers / 32;
00275 if (total_clusters > 4096) fat_16 = 1;
00276
00277
00278 if (cluster_size > MAX_CLUSTER_SIZE) {
00279 fprintf (stderr, "%s: cluster size too big\n", cmnd);
00280 ++errcount;
00281 }
00282
00283 disk_io(READ, FAT_START, &fat_info, 1);
00284 disk_io(READ, FAT_START + fat_size, &fat_check, 1);
00285 if (fat_check != fat_info) {
00286 fprintf (stderr, "%s: Disk type in FAT copy differs from disk type in FAT original.\n", cmnd);
00287 ++errcount;
00288 }
00289 if (errcount != 0) {
00290 fprintf (stderr, "%s: Can't handle disk\n", cmnd);
00291 exit(2);
00292 }
00293 }
00294
00295 int main(argc, argv)
00296 int argc;
00297 register char *argv[];
00298 {
00299 register char *arg_ptr = slash(argv[0]);
00300 DIRECTORY *entry;
00301 short idx = 1;
00302 char dev_nr = '0';
00303
00304 cmnd = arg_ptr;
00305 if (!strcmp(arg_ptr, "dosdir"))
00306 dos_dir = TRUE;
00307 else if (!strcmp(arg_ptr, "dosread"))
00308 dos_read = TRUE;
00309 else if (!strcmp(arg_ptr, "doswrite"))
00310 dos_write = TRUE;
00311 else {
00312 fprintf (stderr, "%s: Program should be named dosread, doswrite or dosdir.\n", cmnd);
00313 exit(1);
00314 }
00315
00316 if (argc == 1) usage(argv[0]);
00317
00318 if (argv[1][0] == '-') {
00319 for (arg_ptr = &argv[1][1]; *arg_ptr; arg_ptr++) {
00320 if (*arg_ptr == 'l' && dos_dir) {
00321 Lflag = TRUE;
00322 } else if (*arg_ptr == 'r' && dos_dir) {
00323 Rflag = TRUE;
00324 } else if (*arg_ptr == 'a' && !dos_dir) {
00325 assert ('\n' == 10);
00326 assert ('\r' == 13);
00327 Aflag = TRUE;
00328 } else {
00329 usage(argv[0]);
00330 }
00331 }
00332 idx++;
00333 }
00334 if (idx == argc) usage(argv[0]);
00335
00336 if (strlen(argv[idx]) > 1) {
00337 device = argv[idx++];
00338
00339
00340
00341
00342
00343 if (strchr(device, '/') == NULL && chdir("/dev") < 0) {
00344 perror("/dev");
00345 exit(1);
00346 }
00347 } else {
00348 if ((dev_nr = toupper (*argv[idx++])) < 'A' || dev_nr > 'Z')
00349 usage(argv[0]);
00350
00351 device[DRIVE_NR] = dev_nr;
00352 }
00353
00354 if ((disk = open(device, dos_write ? O_RDWR : O_RDONLY)) < 0) {
00355 fprintf (stderr, "%s: cannot open %s: %s\n",
00356 cmnd, device, strerror (errno));
00357 exit(1);
00358 }
00359 determine();
00360 disk_io(READ, ROOTADDR, root, DIR_SIZE * root_entries);
00361
00362 if (dos_dir && Lflag) {
00363 entry = label();
00364 printf ("Volume in drive %c ", dev_nr);
00365 if (entry == NIL_DIR)
00366 printf("has no label.\n\n");
00367 else
00368 printf ("is %.11s\n\n", entry->d_name);
00369 }
00370 if (argv[idx] == NIL_PTR) {
00371 if (!dos_dir) usage(argv[0]);
00372 if (Lflag) printf ("Root directory:\n");
00373 list_dir(root, root_entries, FALSE);
00374 if (Lflag) free_blocks();
00375 fflush (stdout);
00376 exit(0);
00377 }
00378 for (arg_ptr = argv[idx]; *arg_ptr; arg_ptr++)
00379 if (*arg_ptr == '\\') *arg_ptr = '/';
00380 else *arg_ptr = toupper (*arg_ptr);
00381 if (*--arg_ptr == '/') *arg_ptr = '\0';
00382
00383 add_path(argv[idx], FALSE);
00384 add_path("/", FALSE);
00385
00386 if (dos_dir && Lflag) printf ( "Directory %s:\n", path);
00387
00388 entry = find_entry(root, root_entries, argv[idx]);
00389
00390 if (dos_dir) {
00391 list_dir(entry, sub_entries, FALSE);
00392 if (Lflag) free_blocks();
00393 } else if (dos_read)
00394 extract(entry);
00395 else {
00396 if (entry != NIL_DIR) {
00397 fflush (stdout);
00398 if (is_dir(entry))
00399 fprintf (stderr, "%s: %s is a directory.\n", cmnd, path);
00400 else
00401 fprintf (stderr, "%s: %s already exists.\n", cmnd, argv[idx]);
00402 exit(1);
00403 }
00404 add_path(NIL_PTR, TRUE);
00405
00406 if (*path) make_file(find_entry(root, root_entries, path),
00407 sub_entries, slash(argv[idx]));
00408 else
00409 make_file(root, root_entries, argv[idx]);
00410 }
00411
00412 (void) close(disk);
00413 fflush (stdout);
00414 exit(0);
00415 return(0);
00416 }
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441 DIRECTORY *directory(dir, entries, function, pathname)
00442 DIRECTORY *dir;
00443 int entries;
00444 int function;
00445 register char *pathname;
00446 {
00447 register DIRECTORY *dir_ptr = dir;
00448 DIRECTORY *mem = NIL_DIR;
00449 unsigned short cl_no = dir->d_cluster;
00450 unsigned short type, last = 0;
00451 char file_name[14];
00452 char *name;
00453 int i = 0;
00454
00455 if (function == FIND) {
00456 while (*pathname != '/' && *pathname != '.' && *pathname &&
00457 i < 8) {
00458 file_name[i++] = *pathname++;
00459 }
00460 if (*pathname == '.') {
00461 int j = 0;
00462 file_name[i++] = *pathname++;
00463 while (*pathname != '/' && *pathname != '.' && *pathname &&
00464 j++ < 3) {
00465 file_name[i++] = *pathname++;
00466 }
00467 }
00468 while (*pathname != '/' && *pathname) pathname++;
00469 file_name[i] = '\0';
00470 }
00471 do {
00472 if (entries != root_entries) {
00473 mem = dir_ptr = read_cluster(cl_no);
00474 last = cl_no;
00475 cl_no = next_cluster(cl_no);
00476 }
00477 for (i = 0; i < entries; i++, dir_ptr++) {
00478 type = dir_ptr->d_name[0] & 0x0FF;
00479 if (function == ENTRY) {
00480 if (type == NOT_USED || type == ERASED) {
00481 if (!mem)
00482 mark = ROOTADDR + (long) i *(long) DIR_SIZE;
00483 else
00484 mark = clus_add(last) + (long) i *(long) DIR_SIZE;
00485 return dir_ptr;
00486 }
00487 continue;
00488 }
00489 if (type == NOT_USED) break;
00490 if (dir_ptr->d_attribute & 0x08) {
00491 if (function == LABEL) return dir_ptr;
00492 continue;
00493 }
00494 if (type == DIR || type == ERASED || function == LABEL)
00495 continue;
00496 type = is_dir(dir_ptr);
00497 name = make_name(dir_ptr,
00498 (function == FIND) ? FALSE : type);
00499 if (function == FIND) {
00500 if (strcmp(file_name, name) != 0) continue;
00501 if (!type) {
00502 if (dos_dir || *pathname) {
00503 fflush (stdout);
00504 fprintf (stderr, "%s: Not a directory: %s\n", cmnd, file_name);
00505 exit(1);
00506 }
00507 } else if (*pathname == '\0' && dos_read) {
00508 fflush (stdout);
00509 fprintf (stderr, "%s: %s is a directory.\n", cmnd, path);
00510 exit(1);
00511 }
00512 if (*pathname) {
00513 dir_ptr = find_entry(dir_ptr,
00514 sub_entries, pathname + 1);
00515 }
00516 if (mem) {
00517 if (dir_ptr) {
00518 memcpy((char *)&save_entry, (char *)dir_ptr, DIR_SIZE);
00519 dir_ptr = &save_entry;
00520 }
00521 free( (void *) mem);
00522 }
00523 return dir_ptr;
00524 } else {
00525 if (function == FALSE) {
00526 show(dir_ptr, name);
00527 } else if (type) {
00528 printf ( "Directory %s%s:\n", path, name);
00529 add_path(name, FALSE);
00530 list_dir(dir_ptr, sub_entries, FALSE);
00531 add_path(NIL_PTR, FALSE);
00532 }
00533 }
00534 }
00535 if (mem) free( (void *) mem);
00536 } while (cl_no != LAST_CLUSTER && mem);
00537
00538 switch (function) {
00539 case FIND:
00540 if (dos_write && *pathname == '\0') return NIL_DIR;
00541 fflush (stdout);
00542 fprintf (stderr, "%s: Cannot find `%s'.\n", cmnd, file_name);
00543 exit(1);
00544 case LABEL:
00545 return NIL_DIR;
00546 case ENTRY:
00547 if (!mem) {
00548 fflush (stdout);
00549 fprintf (stderr, "%s: No entries left in root directory.\n", cmnd);
00550 exit(1);
00551 }
00552 cl_no = free_cluster(TRUE);
00553 link_fat(last, cl_no);
00554 link_fat(cl_no, LAST_CLUSTER);
00555 disk_io(WRITE, clus_add(cl_no), null, cluster_size);
00556
00557 return new_entry(dir, entries);
00558 case FALSE:
00559 if (Rflag) {
00560 printf ("\n");
00561 list_dir(dir, entries, TRUE);
00562 }
00563 }
00564 return NULL;
00565 }
00566
00567 void extract(entry)
00568 register DIRECTORY *entry;
00569 {
00570 register unsigned short cl_no = entry->d_cluster;
00571 char buffer[MAX_CLUSTER_SIZE];
00572 int rest, i;
00573
00574 if (entry->d_size == 0)
00575 return;
00576
00577 do {
00578 disk_io(READ, clus_add(cl_no), buffer, cluster_size);
00579 rest = (entry->d_size > (long) cluster_size) ? cluster_size : (short) entry->d_size;
00580
00581 if (Aflag) {
00582 for (i = 0; i < rest; i ++) {
00583 if (buffer [i] != '\r') putchar (buffer [i]);
00584 }
00585 if (ferror (stdout)) {
00586 fprintf (stderr, "%s: cannot write to stdout: %s\n",
00587 cmnd, strerror (errno));
00588 exit (1);
00589 }
00590 } else {
00591 if (fwrite (buffer, 1, rest, stdout) != rest) {
00592 fprintf (stderr, "%s: cannot write to stdout: %s\n",
00593 cmnd, strerror (errno));
00594 exit (1);
00595 }
00596 }
00597 entry->d_size -= (long) rest;
00598 cl_no = next_cluster(cl_no);
00599 if (cl_no == BAD16) {
00600 fflush (stdout);
00601 fprintf (stderr, "%s: reserved cluster value %x encountered.\n",
00602 cmnd, cl_no);
00603 exit (1);
00604 }
00605 } while (entry->d_size && cl_no != LAST_CLUSTER);
00606
00607 if (cl_no != LAST_CLUSTER)
00608 fprintf (stderr, "%s: Too many clusters allocated for file.\n", cmnd);
00609 else if (entry->d_size != 0)
00610 fprintf (stderr, "%s: Premature EOF: %ld bytes left.\n", cmnd,
00611 entry->d_size);
00612 }
00613
00614
00615
00616
00617 long lmin (a, b)
00618 long a, b;
00619 {
00620 if (a < b) return a;
00621 else return b;
00622 }
00623
00624
00625 void make_file(dir_ptr, entries, name)
00626 DIRECTORY *dir_ptr;
00627 int entries;
00628 char *name;
00629 {
00630 register DIRECTORY *entry = new_entry(dir_ptr, entries);
00631 register char *ptr;
00632 char buffer[MAX_CLUSTER_SIZE];
00633 unsigned short cl_no = 0;
00634 int i, r;
00635 long size = 0L;
00636 unsigned short first_cluster, last_cluster;
00637 long chunk;
00638
00639 memset (&entry->d_name[0], ' ', 11);
00640 for (i = 0, ptr = name; i < 8 && *ptr != '.' && *ptr; i++)
00641 entry->d_name[i] = *ptr++;
00642 while (*ptr != '.' && *ptr) ptr++;
00643 if (*ptr == '.') ptr++;
00644 for (i = 0; i < 3 && *ptr != '.' && *ptr; i++) entry->d_ext[i] = *ptr++;
00645
00646 for (i = 0; i < 10; i++) entry->d_reserved[i] = '\0';
00647 entry->d_attribute = '\0';
00648
00649 entry->d_cluster = 0;
00650
00651 while (free_range (&first_cluster, &last_cluster)) {
00652 do {
00653 unsigned short nr_clus;
00654
00655 chunk = lmin ((long) (last_cluster - first_cluster + 1) *
00656 cluster_size,
00657 (long) MAX_CLUSTER_SIZE);
00658 r = fill(buffer, chunk);
00659 if (r == 0) goto done;
00660 nr_clus = (r + cluster_size - 1) / cluster_size;
00661 disk_io(WRITE, clus_add(first_cluster), buffer, r);
00662
00663 for (i = 0; i < nr_clus; i ++) {
00664 if (entry->d_cluster == 0)
00665 cl_no = entry->d_cluster = first_cluster;
00666 else {
00667 link_fat(cl_no, first_cluster);
00668 cl_no = first_cluster;
00669 }
00670 first_cluster ++;
00671 }
00672
00673 size += r;
00674 } while (first_cluster <= last_cluster);
00675 }
00676 fprintf (stderr, "%s: disk full. File truncated\n", cmnd);
00677 done:
00678 if (entry->d_cluster != 0) link_fat(cl_no, LAST_CLUSTER);
00679 entry->d_size = size;
00680 fill_date(entry);
00681 disk_io(WRITE, mark, entry, DIR_SIZE);
00682
00683 if (fat_dirty) flush_fat ();
00684
00685 }
00686
00687
00688 #define SEC_MIN 60L
00689 #define SEC_HOUR (60L * SEC_MIN)
00690 #define SEC_DAY (24L * SEC_HOUR)
00691 #define SEC_YEAR (365L * SEC_DAY)
00692 #define SEC_LYEAR (366L * SEC_DAY)
00693
00694 unsigned short mon_len[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
00695
00696 void fill_date(entry)
00697 DIRECTORY *entry;
00698 {
00699 register long cur_time = time((long *) 0) - DOS_TIME;
00700 unsigned short year = 0, month = 1, day, hour, minutes, seconds;
00701 int i;
00702 long tmp;
00703
00704 if (cur_time < 0)
00705 cur_time = 0;
00706 for (;;) {
00707 tmp = (year % 4 == 0) ? SEC_LYEAR : SEC_YEAR;
00708 if (cur_time < tmp) break;
00709 cur_time -= tmp;
00710 year++;
00711 }
00712
00713 day = (unsigned short) (cur_time / SEC_DAY);
00714 cur_time -= (long) day *SEC_DAY;
00715
00716 hour = (unsigned short) (cur_time / SEC_HOUR);
00717 cur_time -= (long) hour *SEC_HOUR;
00718
00719 minutes = (unsigned short) (cur_time / SEC_MIN);
00720 cur_time -= (long) minutes *SEC_MIN;
00721
00722 seconds = (unsigned short) cur_time;
00723
00724 mon_len[1] = (year % 4 == 0) ? 29 : 28;
00725 i = 0;
00726 while (day >= mon_len[i]) {
00727 month++;
00728 day -= mon_len[i++];
00729 }
00730 day++;
00731
00732 entry->d_date = (year << 9) | (month << 5) | day;
00733 entry->d_time = (hour << 11) | (minutes << 5) | seconds;
00734 }
00735
00736 char *make_name(dir_ptr, dir_fl)
00737 register DIRECTORY *dir_ptr;
00738 short dir_fl;
00739 {
00740 static char name_buf[14];
00741 register char *ptr = name_buf;
00742 short i;
00743
00744 for (i = 0; i < 8; i++) *ptr++ = dir_ptr->d_name[i];
00745
00746 while (*--ptr == ' ');
00747 assert (ptr >= name_buf);
00748
00749 ptr++;
00750 if (dir_ptr->d_ext[0] != ' ') {
00751 *ptr++ = '.';
00752 for (i = 0; i < 3; i++) *ptr++ = dir_ptr->d_ext[i];
00753 while (*--ptr == ' ');
00754 ptr++;
00755 }
00756 if (dir_fl) *ptr++ = '/';
00757 *ptr = '\0';
00758
00759 return name_buf;
00760 }
00761
00762
00763 int fill(buffer, size)
00764 register char *buffer;
00765 size_t size;
00766 {
00767 static BOOL nl_mark = FALSE;
00768 char *last = &buffer[size];
00769 char *begin = buffer;
00770 register int c;
00771
00772 while (buffer < last) {
00773 if (nl_mark) {
00774 *buffer ++ = '\n';
00775 nl_mark = FALSE;
00776 } else {
00777 c = getchar();
00778 if (c == EOF) break;
00779 if (Aflag && c == '\n') {
00780 *buffer ++ = '\r';
00781 nl_mark = TRUE;
00782 } else {
00783 *buffer++ = c;
00784 }
00785 }
00786 }
00787
00788 return (buffer - begin);
00789 }
00790
00791 #define HOUR 0xF800
00792 #define MIN 0x07E0
00793 #define YEAR 0xFE00
00794 #define MONTH 0x01E0
00795 #define DAY 0x01F
00796
00797 char *month[] = {
00798 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
00799 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
00800 };
00801
00802 void xmodes(mode)
00803 int mode;
00804 {
00805 printf ( "\t%c%c%c%c%c", (mode & SUB_DIR) ? 'd' : '-',
00806 (mode & 02) ? 'h' : '-', (mode & 04) ? 's' : '-',
00807 (mode & 01) ? '-' : 'w', (mode & 0x20) ? 'a' : '-');
00808 }
00809
00810 void show(dir_ptr, name)
00811 DIRECTORY *dir_ptr;
00812 char *name;
00813 {
00814 register unsigned short e_date = dir_ptr->d_date;
00815 register unsigned short e_time = dir_ptr->d_time;
00816 unsigned short next;
00817 char bname[20];
00818 short i = 0;
00819
00820 while (*name && *name != '/') bname[i++] = *name++;
00821 bname[i] = '\0';
00822 if (!Lflag) {
00823 printf ( "%s\n", bname);
00824 return;
00825 }
00826 xmodes( (int) dir_ptr->d_attribute);
00827 printf ( "\t%s%s", bname, strlen(bname) < 8 ? "\t\t" : "\t");
00828 i = 1;
00829 if (is_dir(dir_ptr)) {
00830 next = dir_ptr->d_cluster;
00831 while ((next = next_cluster(next)) != LAST_CLUSTER) i++;
00832 printf ("%8ld", (long) i * (long) cluster_size);
00833 } else
00834 printf ("%8ld", dir_ptr->d_size);
00835 printf (" %02d:%02d %2d %s %d\n", ((e_time & HOUR) >> 11),
00836 ((e_time & MIN) >> 5), (e_date & DAY),
00837 month[((e_date & MONTH) >> 5) - 1], ((e_date & YEAR) >> 9) + 1980);
00838 }
00839
00840 void free_blocks()
00841 {
00842 register unsigned short cl_no;
00843 long nr_free = 0;
00844 long nr_bad = 0;
00845
00846 for (cl_no = 2; cl_no < total_clusters; cl_no++) {
00847 switch (next_cluster(cl_no)) {
00848 case FREE: nr_free++; break;
00849 case BAD16: nr_bad++; break;
00850 }
00851 }
00852
00853 printf ("Free space: %ld bytes.\n", nr_free * (long) cluster_size);
00854 if (nr_bad != 0)
00855 printf ("Bad sectors: %ld bytes.\n", nr_bad * (long) cluster_size);
00856 }
00857
00858
00859 DIRECTORY *read_cluster(cluster)
00860 register unsigned int cluster;
00861 {
00862 register DIRECTORY *sub_dir;
00863
00864 if ((sub_dir = malloc(cluster_size)) == NULL) {
00865 fprintf (stderr, "%s: Cannot set break!\n", cmnd);
00866 exit(1);
00867 }
00868 disk_io(READ, clus_add(cluster), sub_dir, cluster_size);
00869
00870 return sub_dir;
00871 }
00872
00873 static unsigned short cl_index = 2;
00874
00875
00876
00877
00878
00879
00880
00881
00882 BOOL free_range (first, last)
00883 unsigned short *first, *last;
00884 {
00885 while (cl_index < total_clusters && next_cluster(cl_index) != FREE)
00886 cl_index++;
00887 if (cl_index >= total_clusters) return FALSE;
00888 *first = cl_index;
00889 while (cl_index < total_clusters && next_cluster(cl_index) == FREE)
00890 cl_index++;
00891 *last = cl_index - 1;
00892 return TRUE;
00893 }
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905 unsigned short free_cluster(leave_fl)
00906 BOOL leave_fl;
00907 {
00908 while (cl_index < total_clusters && next_cluster(cl_index) != FREE)
00909 cl_index++;
00910
00911 if (leave_fl && cl_index >= total_clusters) {
00912 fprintf (stderr, "%s: Diskette full. File not added.\n", cmnd);
00913 exit(1);
00914 }
00915 return cl_index++;
00916 }
00917
00918
00919
00920
00921 void read_fat (cl_no)
00922 unsigned int cl_no;
00923 {
00924
00925 if (!cooked_fat) {
00926
00927
00928
00929 if (fat_16) {
00930
00931
00932 if ((cooked_fat = malloc (fat_size)) == NULL) {
00933
00934
00935
00936 if ((cooked_fat = malloc (COOKED_SIZE)) == NULL) {
00937 fprintf (stderr, "%s: not enough memory for FAT cache. Use chmem\n",
00938 cmnd);
00939 exit (1);
00940 }
00941 cache_size = COOKED_SIZE / 2;
00942 } else {
00943 cache_size = fat_size / 2;
00944 }
00945 } else {
00946
00947
00948
00949 if ((cooked_fat = malloc (total_clusters * sizeof (short))) == NULL ||
00950 (raw_fat = malloc (fat_size)) == NULL) {
00951 fprintf (stderr, "%s: not enough memory for FAT cache. Use chmem\n",
00952 cmnd);
00953 exit (1);
00954 }
00955 cache_size = total_clusters;
00956 }
00957 }
00958 fat_low = cl_no / cache_size * cache_size;
00959 fat_high = fat_low + cache_size - 1;
00960
00961 if (!fat_16) {
00962 unsigned short *cp;
00963 unsigned char *rp;
00964 unsigned short i;
00965
00966 disk_io (READ, FAT_START, raw_fat, fat_size);
00967 for (rp = raw_fat, cp = cooked_fat, i = 0;
00968 i < cache_size;
00969 rp += 3, i += 2) {
00970 *cp = *rp + ((*(rp + 1) & 0x0f) << 8);
00971 if (*cp == BAD) *cp = BAD16;
00972 else if (*cp == LAST_CLUSTER12) *cp = LAST_CLUSTER;
00973 cp ++;
00974 *cp = ((*(rp + 1) & 0xf0) >> 4) + (*(rp + 2) << 4);
00975 if (*cp == BAD) *cp = BAD16;
00976 else if (*cp == LAST_CLUSTER12) *cp = LAST_CLUSTER;
00977 cp ++;
00978 }
00979 } else {
00980
00981 assert (sizeof (short) == 2);
00982 assert (CHAR_BIT == 8);
00983
00984 disk_io (READ, FAT_START + fat_low * 2, (void *)cooked_fat, cache_size * 2);
00985 if (big_endian) {
00986 unsigned short *cp;
00987 unsigned char *rp;
00988 unsigned short i;
00989
00990 for (i = 0, rp = (unsigned char *)cooked_fat , cp = cooked_fat;
00991 i < cache_size;
00992 rp += 2, cp ++, i ++) {
00993 *cp = c2u2 (rp);
00994 }
00995 }
00996 }
00997 }
00998
00999
01000
01001
01002 void flush_fat ()
01003 {
01004 if (fat_16) {
01005 if (big_endian) {
01006 unsigned short *cp;
01007 unsigned char *rp;
01008 unsigned short i;
01009
01010 for (i = 0, rp = (unsigned char *)cooked_fat , cp = cooked_fat;
01011 i < cache_size;
01012 rp += 2, cp ++, i ++) {
01013 *rp = *cp;
01014 *(rp + 1) = *cp >> 8;
01015 }
01016 }
01017 disk_io (WRITE, FAT_START + fat_low * 2, (void *)cooked_fat, cache_size * 2);
01018 disk_io (WRITE, FAT_START + fat_size + fat_low * 2, (void *)cooked_fat, cache_size * 2);
01019 } else {
01020 unsigned short *cp;
01021 unsigned char *rp;
01022 unsigned short i;
01023
01024 for (rp = raw_fat, cp = cooked_fat, i = 0;
01025 i < cache_size;
01026 rp += 3, cp += 2, i += 2) {
01027 *rp = *cp;
01028 *(rp + 1) = ((*cp & 0xf00) >> 8) |
01029 ((*(cp + 1) & 0x00f) << 4);
01030 *(rp + 2) = ((*(cp + 1) & 0xff0) >> 4);
01031 }
01032 disk_io (WRITE, FAT_START, raw_fat, fat_size);
01033 disk_io (WRITE, FAT_START + fat_size, raw_fat, fat_size);
01034 }
01035 }
01036
01037
01038
01039
01040 void link_fat(cl_1, cl_2)
01041 unsigned int cl_1;
01042 unsigned int cl_2;
01043 {
01044 if (cl_1 < fat_low || cl_1 > fat_high) {
01045 if (fat_dirty) flush_fat ();
01046 read_fat (cl_1);
01047 }
01048 cooked_fat [cl_1 - fat_low] = cl_2;
01049 fat_dirty = TRUE;
01050 }
01051
01052
01053 unsigned short next_cluster(cl_no)
01054 register unsigned int cl_no;
01055 {
01056 if (cl_no < fat_low || cl_no > fat_high) {
01057 if (fat_dirty) flush_fat ();
01058 read_fat (cl_no);
01059 }
01060 return cooked_fat [cl_no - fat_low];
01061 }
01062
01063 char *slash(str)
01064 register char *str;
01065 {
01066 register char *result = str;
01067
01068 while (*str)
01069 if (*str++ == '/') result = str;
01070
01071 return result;
01072 }
01073
01074 void add_path(file, slash_fl)
01075 char *file;
01076 BOOL slash_fl;
01077 {
01078 register char *ptr = path;
01079
01080 while (*ptr) ptr++;
01081
01082 if (file == NIL_PTR) {
01083 if (ptr != path) ptr--;
01084 if (ptr != path) do {
01085 ptr--;
01086 } while (*ptr != '/' && ptr != path);
01087 if (ptr != path && !slash_fl) *ptr++ = '/';
01088 *ptr = '\0';
01089 } else
01090 strcpy (ptr, file);
01091 }
01092
01093
01094 void disk_io(op, seek, address, bytes)
01095 register BOOL op;
01096 unsigned long seek;
01097 void *address;
01098 register unsigned bytes;
01099 {
01100 unsigned int r;
01101
01102 if (lseek(disk, seek, SEEK_SET) < 0L) {
01103 fflush (stdout);
01104 fprintf (stderr, "%s: Bad lseek: %s\n", cmnd, strerror (errno));
01105 exit(1);
01106 }
01107 if (op == READ)
01108 r = read(disk, (char *) address, bytes);
01109 else {
01110 r = write(disk, (char *) address, bytes);
01111 }
01112
01113 if (r != bytes) {
01114 fprintf (stderr, "%s: read error: %s\n", cmnd, strerror (errno));
01115 exit (1);
01116 }
01117 }
01118
01119 char dosread_c_rcs_id [] =
01120 "$Id: dosread.c 5628 2009-11-09 10:26:00Z thruby $";