ast@cs.vu.nl (Andy Tanenbaum) (07/20/88)
Here is an improved version of dosread/dosdir/doswrite modified by Tim Kachel for hard disks etc. I don't have a DOS partition on any of my hard disks, so I can't test it easily. If anyone finds any problems, please post them. Andy Tanenbaum (ast@cs.vu.nl) /* * dosdir - list MS-DOS directories. * doswrite - write stdin to DOS-file * dosread - read DOS-file to stdout * * Author: Michiel Huisjes. * * Usage: dos... [-lra] drive [file/dir] * l: Give long listing. * r: List recursively. * a: Set ASCII bit. * * Modified by Tim Kachel 4-88 * drive can be 0,1, a, b, c, d, e, f * program will automatically configure to different hard disks * and the partitions for such (could change drive name for * a send hard disk if you have one) * (has been tested on a 16 bit FAT AT drive) * (High density AT diskettes and regular 360K) * compile with cc -O -i * hard disk is named /dev/hd_0 to avoid accidents * To test FAT sizes on your hard disk first try dir -lr c * (or what ever your dos partition is) if this works * properly then all the rest should be okay. * If there are any problems there is debugging information * in fdinit() -- please let me know of any problems */ #include "stat.h" #define DRIVE0 "/dev/at0" #define DRIVE1 "/dev/at1" #define FDRIVE "/dev/hd_0" #define DDDD 0xFD #define DDHD 0xF9 #define DDFD 0xF8 #define MAX_CLUSTER_SIZE 4096 #define MAX_FAT_SIZE 23552 /* 46 sectoren */ #define HMASK 0xFF00 #define LMASK 0x00FF #define MAX_ROOT_ENTRIES 512 /* 32 sectoren */ #define FAT_START 512L /* After bootsector */ #define clus_add(cl_no) ((long) (((long) cl_no - 2L) \ * (long) cluster_size \ + (long) data_start \ )) struct dir_entry { unsigned char d_name[8]; unsigned char d_ext[3]; unsigned char d_attribute; unsigned char d_reserved[10]; unsigned short d_time; unsigned short d_date; unsigned short d_cluster; unsigned long d_size; }; typedef struct dir_entry DIRECTORY; #define NOT_USED 0x00 #define ERASED 0xE5 #define DIR 0x2E #define DIR_SIZE (sizeof (struct dir_entry)) #define SUB_DIR 0x10 #define NIL_DIR ((DIRECTORY *) 0) #define LAST_CLUSTER 0x0FFF #define MASK 0xFF8 /* FF8 - FFF are last cluster */ #define FREE 0x000 #define BAD 0xFF0 /* Includes reserved */ #define LAST_16 0xFFFF #define MASK_16 0xFFF8 #define FREE_16 0x0000 #define BAD_16 0xFFF0 /* Includes reserved */ typedef char BOOL; #define TRUE 1 #define FALSE 0 #define NIL_PTR ((char *) 0) #define DOS_TIME 315532800L /* 1970 - 1980 */ #define READ 0 #define WRITE 1 #define disk_read(s, a, b) disk_io(READ, s, a, b) #define disk_write(s, a, b) disk_io(WRITE, s, a, b) #define FIND 3 #define LABEL 4 #define ENTRY 5 #define find_entry(d, e, p) directory(d, e, FIND, p) #define list_dir(d, e, f) (void) directory(d, e, f, NIL_PTR) #define label() directory(root, root_entries, LABEL, NIL_PTR) #define new_entry(d, e) directory(d, e, ENTRY, NIL_PTR) #define is_dir(d) ((d)->d_attribute & SUB_DIR) #define EOF 0400 #define EOF_MARK '\032' #define STD_OUT 1 #define flush() print(STD_OUT, NIL_PTR, 0) short disk; union tbl { unsigned char twelve[4096]; unsigned short sixteen[MAX_FAT_SIZE / 2 ]; } fat; DIRECTORY root[MAX_ROOT_ENTRIES], save_entry, *directory(), *read_cluster(); char null[MAX_CLUSTER_SIZE], *device, path[128]; short total_clusters, cluster_size, fat_size, root_entries, sub_entries; BOOL Rflag, Lflag, Aflag, dos_read, dos_write, dos_dir, Tfat = TRUE; unsigned short free_cluster(), next_cluster(); char *make_name(), *num_out(), *slash(), *brk(); long mark, data_start, lseek(), time(), f_start; leave(nr) short nr; { (void) umount(device); exit(nr); } usage(prog_name) register char *prog_name; { print_string(TRUE, "Usage: %s [%s\n", prog_name, dos_dir ? "-lr] drive [dir]" : "-a] drive file"); exit(1); } main(argc, argv) int argc; register char *argv[]; { register char *arg_ptr = slash(argv[0]); DIRECTORY *entry; short index = 1; char dev_nr; unsigned char fat_type, fat_check; BOOL fdisk = FALSE; int i; if (!strcmp(arg_ptr, "dosdir")) dos_dir = TRUE; else if (!strcmp(arg_ptr, "dosread")) dos_read = TRUE; else if (!strcmp(arg_ptr, "doswrite")) dos_write = TRUE; else { print_string(TRUE, "Program should be named dosread, doswrite or dosdir.\n"); exit(1); } if (argc == 1) usage(argv[0]); if (argv[1][0] == '-') { for (arg_ptr = &argv[1][1]; *arg_ptr; arg_ptr++) { if (*arg_ptr == 'l' && dos_dir) Lflag = TRUE; else if (*arg_ptr == 'r' && dos_dir) Rflag = TRUE; else if (*arg_ptr == 'a' && !dos_dir) Aflag = TRUE; else usage(argv[0]); } index++; } if (index == argc) usage(argv[0]); switch (dev_nr = *argv[index++]) { case '0': case 'a': device = DRIVE0; break; case '1': case 'b': device = DRIVE1; break; case 'c': case 'd': case 'e': case 'f': fdisk = TRUE; device = FDRIVE; break; default : usage(argv[0]); } if ((disk = open(device, 2)) < 0) { print_string(TRUE, "Cannot open %s\n", device); exit(1); } if (fdisk) { /* fixed disk */ fdinit(dev_nr); disk_read(f_start, &fat_type, sizeof(fat_type)); if (fat_type != DDFD) { print_string(TRUE, "Fixed disk is not DOS\n"); leave(1); } } else { /* use standard start for floppies */ f_start = FAT_START; disk_read(f_start, &fat_type, sizeof(fat_type)); if (fat_type == DDDD) { /* Double-sided double-density 9 s/t */ total_clusters = 355; /* 720 - 7 - 2 - 2 - 1 */ cluster_size = 1024; /* 2 sectors per cluster */ fat_size = 1024; /* 2 sectors */ data_start = 6144L; /* Starts on sector #12 */ root_entries = 112; sub_entries = 32; /* 1024 / 32 */ } else if (fat_type == DDHD) { /* Double-sided high-density 15 s/t */ total_clusters = 2372; /* 2400 - 14 - 7 - 7 - 1 */ cluster_size = 512; /* 1 sector per cluster */ fat_size = 3584; /* 7 sectors */ data_start = 14848L; /* Starts on sector #29 */ root_entries = 224; sub_entries = 16; /* 512 / 32 */ } else { print_string(TRUE, "Diskette is not DOS 2.0 360K or 1.2M\n"); leave(1); } } disk_read(f_start + (long) fat_size, &fat_check, sizeof(fat_check)); if (fat_check != fat_type) { print_string(TRUE, "Disk type in FAT copy differs from disk type in FAT original.\n"); leave(1); } if (Tfat) /* twelve bit FAT entries */ disk_read(f_start, fat.twelve, fat_size); else /* sixteen bit */ disk_read(f_start, fat.sixteen, fat_size); /******* for (i=0; i<= 30; i++){ printf("%x\t%c", fat.sixteen[i], (i % 10) ? ' ':'\n'); } leave(1); /*******/ disk_read(f_start + 2L * (long) fat_size, root, DIR_SIZE * root_entries); /******* for (i=0; i<2; i++){ printf("%s d_name\n", root[i].d_name); printf("%s d_ext\n", root[i].d_ext); printf("%d d_attr\n", root[i].d_attribute); printf("%s d_reserved\n", root[i].d_reserved); printf("%d d_time\n", root[i].d_time); printf("%d d_date\n", root[i].d_date); printf("%d d_cluster\n", root[i].d_cluster); printf("%D d_size\n", root[i].d_size); } /*********/ if (dos_dir) { entry = label(); print_string(FALSE, "Volume in drive %c ", dev_nr); if (entry == NIL_DIR) print(STD_OUT, "has no label.\n\n", 0); else print_string(FALSE, "is %S\n\n", entry->d_name); } if (argv[index] == NIL_PTR) { if (!dos_dir) usage(argv[0]); print(STD_OUT, "Root directory:\n", 0); list_dir(root, root_entries, FALSE); free_blocks(); flush(); leave(0); } for (arg_ptr = argv[index]; *arg_ptr; arg_ptr++) if (*arg_ptr == '\\') *arg_ptr = '/'; else if (*arg_ptr >= 'a' && *arg_ptr <= 'z') *arg_ptr += ('A' - 'a'); if (*--arg_ptr == '/') *arg_ptr = '\0'; /* skip trailing '/' */ add_path(argv[index], FALSE); add_path("/", FALSE); if (dos_dir) print_string(FALSE, "Directory %s:\n", path); entry = find_entry(root, root_entries, argv[index]); if (dos_dir) { list_dir(entry, sub_entries, FALSE); free_blocks(); } else if (dos_read) extract(entry); else { if (entry != NIL_DIR) { flush(); if (is_dir(entry)) print_string(TRUE, "%s is a directory.\n", path); else print_string(TRUE, "%s already exists.\n", argv[index]); leave(1); } add_path(NIL_PTR, TRUE); if (*path) make_file(find_entry(root, root_entries, path), sub_entries, slash(argv[index])); else make_file(root, root_entries, argv[index]); } (void) close(disk); flush(); leave(0); } fdinit(part_nr) /* Fixed Disk Initializations */ char part_nr; { #define SECSIZE 512 /* sector size */ #define TABLEOFFSET 0x1be /* offset in boot sector*/ /* * Description of entry in partition table */ struct part_entry { char bootind; /* boot indicator 0/0x80 */ char start_head; /* head value for first sector */ char start_sec; /* sector value for first sector*/ char start_cyl; /* track value for first sector */ char sysind; /* system indicator 00=?? 01=DOS*/ char last_head; /* head value for last sector */ char last_sec; /* sector value for last sector */ char last_cyl; /* track value for last sector */ long lowsec; /* logical first sector */ long size; /* size of partion in sectors */ } *pe; char secbuf[SECSIZE]; /* * Description of the boot block */ struct { unsigned char jump[3]; unsigned char oem[8]; unsigned char bytes_sector[2]; unsigned char cluster_size; unsigned char res_sectors[2]; unsigned char num_fats; unsigned char root_entries[2]; unsigned char logical_sectors[2]; unsigned char media_type; unsigned char fat_sectors[2]; unsigned char track_sectors[2]; unsigned char num_heads[2]; unsigned char hidden_sectors[2]; } boot; short block_size, reserved; long boot_loc; disk_read(0L, secbuf, SECSIZE); /* get boot sector */ /* offset into boot sector for the partition table */ pe = (struct part_entry *)&secbuf[TABLEOFFSET]; /* get the proper partition */ switch(part_nr) { case 'f': pe++; case 'e': pe++; case 'd': pe++; case 'c': boot_loc = pe->lowsec * 512L; break; default: printf("Error: unknown partition\n"); leave(); } /* now read the boot block for the partition needed */ disk_read(boot_loc, &boot, sizeof(boot)); /* this section can be used to print drive information */ /************** printf("OEM = %s\n", boot.oem); printf("Bytes/sector = %d\n", (boot.bytes_sector[1] << 8 & HMASK) + (boot.bytes_sector[0] & LMASK)); printf("Sectors/cluster = %d\n", boot.cluster_size); printf("Number of Reserved Clusters = %d\n", (boot.res_sectors[1] << 8 & HMASK) + (boot.res_sectors[0] & LMASK)); printf("Number of FAT's = %d\n", boot.num_fats); printf("Number of root-directory entries = %d\n", (boot.root_entries[1] << 8 & HMASK) + (boot.root_entries[0] & LMASK)); printf("Total sectors in logical volume = %D\n", (long) (boot.logical_sectors[1] << 8 & HMASK) + (boot.logical_sectors[0] & LMASK)); printf("Media Descriptor = %x\n", boot.media_type); printf("Number of sectors/FAT = %d\n", (boot.fat_sectors[1] << 8 & HMASK) + (boot.fat_sectors[0] & LMASK)); printf("Sectors/track = %d\n", (boot.track_sectors[1] << 8 & HMASK) + (boot.track_sectors[0] & LMASK)); printf("Number of Heads = %d\n", (boot.num_heads[1] << 8 & HMASK) + (boot.num_heads[0] & LMASK)); printf("Number of hidden sectors = %d\n", (boot.hidden_sectors[1] << 8 & HMASK) + (boot.hidden_sectors[0] & LMASK)); leave(1); /**************/ if (boot.media_type != DDFD) { printf("DISK is not DOS Format.\n"); leave(1); } if (boot.num_fats != 2) { printf("Disk does not have two FAT Tables!\n"); leave(1); } block_size = (boot.bytes_sector[1] << 8 & HMASK) + (boot.bytes_sector[0] & LMASK); if ((cluster_size = block_size * boot.cluster_size) > MAX_CLUSTER_SIZE) { printf("Cluster size is larger than MAX_CLUSTER_SIZE.\n"); leave(1); } reserved = ((boot.res_sectors[1] << 8 & HMASK) + (boot.res_sectors[0] & LMASK)); f_start = boot_loc + (long) block_size * (long) reserved; root_entries = (boot.root_entries[1] << 8 & HMASK) + (boot.root_entries[0] & LMASK); fat_size = (boot.fat_sectors[1] << 8 & HMASK) + (boot.fat_sectors[0] & LMASK); /* (sectors - rootdir - fats - reserved) / blocks/cluster */ total_clusters = (int) ((long) ((boot.logical_sectors[1] << 8 & HMASK) + (boot.logical_sectors[0] & LMASK)) - (root_entries * 32 / block_size) - (fat_size * 2) - reserved) / boot.cluster_size; if (total_clusters > 4096) Tfat = FALSE; /* sixteen bit fat entries */ if ( (fat_size *= block_size) > MAX_FAT_SIZE) { printf("Disk FAT is larger than MAX_FAT_SIZE.\n"); leave(1); } sub_entries = cluster_size / 32; data_start = f_start + (long) (fat_size * 2L) + (long) (root_entries * 32L); /********** printf("f_start = %D\n", f_start); printf("total_clusters = %d\n", total_clusters); printf("cluster_size = %d\n", cluster_size); printf("fat_size = %d\n", fat_size); printf("data_start = %D\n", data_start); printf("root_entries = %d\n", root_entries); printf("sub_entries = %d\n", sub_entries); printf("Tfat = %d\n", Tfat); leave(1); /*********/ } DIRECTORY *directory(dir, entries, function, pathname) DIRECTORY *dir; short entries; BOOL function; register char *pathname; { register DIRECTORY *dir_ptr = dir; DIRECTORY *mem = NIL_DIR; unsigned short cl_no = dir->d_cluster; unsigned short type, last; char file_name[14]; char *name; int i = 0; if (function == FIND) { while (*pathname != '/' && *pathname && i < 12) file_name[i++] = *pathname++; while (*pathname != '/' && *pathname) pathname++; file_name[i] = '\0'; } do { if (entries != root_entries) { mem = dir_ptr = read_cluster(cl_no); last = cl_no; cl_no = next_cluster(cl_no); } for (i = 0; i < entries; i++, dir_ptr++) { type = dir_ptr->d_name[0] & 0x0FF; if (function == ENTRY) { if (type == NOT_USED || type == ERASED) { mark = lseek(disk, 0L, 1) - (long) cluster_size + (long) i * (long) DIR_SIZE; if (!mem) mark += (long) cluster_size - (long) (root_entries * sizeof (DIRECTORY)); return dir_ptr; } continue; } if (type == NOT_USED) break; if (dir_ptr->d_attribute & 0x08) { if (function == LABEL) return dir_ptr; continue; } if (type == DIR || type == ERASED || function == LABEL) continue; type = is_dir(dir_ptr); name = make_name(dir_ptr, (function == FIND) ? FALSE : type); if (function == FIND) { if (strcmp(file_name, name) != 0) continue; if (!type) { if (dos_dir || *pathname) { flush(); print_string(TRUE, "Not a directory: %s\n", file_name); leave(1); } } else if (*pathname == '\0' && dos_read) { flush(); print_string(TRUE, "%s is a directory.\n", path); leave(1); } if (*pathname) { dir_ptr = find_entry(dir_ptr, sub_entries, pathname + 1); } if (mem) { if (dir_ptr) { bcopy(dir_ptr, &save_entry, DIR_SIZE); dir_ptr = &save_entry; } (void) brk(mem); } return dir_ptr; } else { if (function == FALSE) show(dir_ptr, name); else if (type) { /* Recursive */ print_string(FALSE, "Directory %s%s:\n", path, name); add_path(name, FALSE); list_dir(dir_ptr, sub_entries, FALSE); add_path(NIL_PTR, FALSE); } } } if (mem) (void) brk(mem); } while ((Tfat && cl_no != LAST_CLUSTER && mem) || (!Tfat && cl_no != LAST_16 && mem)); switch (function) { case FIND: if (dos_write && *pathname == '\0') return NIL_DIR; flush(); print_string(TRUE, "Cannot find `%s'.\n", file_name); leave(1); case LABEL: return NIL_DIR; case ENTRY: if (!mem) { flush(); print_string(TRUE, "No entries left in root directory.\n"); leave(1); } cl_no = free_cluster(TRUE); link_fat(last, cl_no); if (Tfat) link_fat(cl_no, LAST_CLUSTER); else link_fat(cl_no, LAST_16); disk_write(clus_add(cl_no), null, cluster_size); return new_entry(dir, entries); case FALSE: if (Rflag) { print(STD_OUT, "\n", 0); list_dir(dir, entries, TRUE); } } } extract(entry) register DIRECTORY *entry; { register unsigned short cl_no = entry->d_cluster; char buffer[MAX_CLUSTER_SIZE]; short rest; if (entry->d_size == 0) /* Empty file */ return; do { disk_read(clus_add(cl_no), buffer, cluster_size); rest = (entry->d_size > (long) cluster_size) ? cluster_size : (short) entry->d_size; print(STD_OUT, buffer, rest); entry->d_size -= (long) rest; cl_no = next_cluster(cl_no); if ((Tfat && cl_no == BAD) || (!Tfat && cl_no == BAD_16)){ flush(); print_string(TRUE, "Reserved cluster value encountered.\n"); leave(1); } } while ((Tfat && entry->d_size && cl_no != LAST_CLUSTER) || (!Tfat && entry->d_size && cl_no != LAST_16)); if ((Tfat && cl_no != LAST_CLUSTER) || (!Tfat && cl_no != LAST_16)) print_string(TRUE, "Too many clusters allocated for file.\n"); else if (entry->d_size != 0) print_string(TRUE, "Premature EOF: %L bytes left.\n", entry->d_size); } print(fd, buffer, bytes) short fd; register char *buffer; register short bytes; { static short index; static BOOL lf_pending = FALSE; static char output[MAX_CLUSTER_SIZE + 1]; if (buffer == NIL_PTR) { if (dos_read && Aflag && lf_pending) { output[index++] = '\r'; lf_pending = FALSE; } if (write(fd, output, index) != index) bad(); index = 0; return; } if (bytes == 0) bytes = strlen(buffer); while (bytes--) { if (index >= MAX_CLUSTER_SIZE) { if (write(fd, output, index) != index) bad (); index = 0; } if (dos_read && Aflag) { if (*buffer == '\r') { if (lf_pending) output[index++] = *buffer++; else { lf_pending = TRUE; buffer++; } } else if (*buffer == '\n') { output[index++] = *buffer++; lf_pending = FALSE; } else if (lf_pending) { output[index++] = '\r'; output[index++] = *buffer++; } else if ((output[index++] = *buffer++) == EOF_MARK) { if (lf_pending) { output[index - 1] = '\r'; index++; lf_pending = FALSE; } index--; return; } } else output[index++] = *buffer++; } } make_file(dir_ptr, entries, name) DIRECTORY *dir_ptr; int entries; char *name; { register DIRECTORY *entry = new_entry(dir_ptr, entries); register char *ptr; char buffer[MAX_CLUSTER_SIZE]; unsigned short cl_no, next; short i, r; long size = 0L; bcopy(" ",&entry->d_name[0],11); /* clear entry */ for (i = 0, ptr = name; i < 8 && *ptr != '.' && *ptr; i++) entry->d_name[i] = *ptr++; while (*ptr != '.' && *ptr) ptr++; if (*ptr == '.') ptr++; for (i=0;i < 3 && *ptr; i++) entry->d_ext[i] = *ptr++; for (i = 0; i < 10; i++) entry->d_reserved[i] = '\0'; entry->d_attribute = '\0'; entry->d_cluster = 0; while ((r = fill(buffer)) > 0) { if ((next = free_cluster(FALSE)) > total_clusters) { print_string(TRUE, "Disk full. File truncated.\n"); break; } disk_write(clus_add(next), buffer, r); if (entry->d_cluster == 0) cl_no = entry->d_cluster = next; else { link_fat(cl_no, next); cl_no = next; } size += r; } if (entry->d_cluster != 0) { if (Tfat) link_fat(cl_no, LAST_CLUSTER); else link_fat(cl_no, LAST_16); } entry->d_size = Aflag ? (size - 1) : size; /* Strip added ^Z */ fill_date(entry); disk_write(mark, entry, DIR_SIZE); if (Tfat) { disk_write(f_start, fat.twelve, fat_size); disk_write(f_start + (long) fat_size, fat.twelve, fat_size); } else { disk_write(f_start, fat.sixteen, fat_size); disk_write(f_start + (long) fat_size, fat.sixteen, fat_size); } } #define SEC_MIN 60L #define SEC_HOUR (60L * SEC_MIN) #define SEC_DAY (24L * SEC_HOUR) #define SEC_YEAR (365L * SEC_DAY) #define SEC_LYEAR (366L * SEC_DAY) short mon_len[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; fill_date(entry) DIRECTORY *entry; { register long cur_time = time((long *) 0) - DOS_TIME; unsigned short year = 0, month = 1, day, hour, minutes, seconds; int i; long tmp; if (cur_time < 0) /* Date not set on booting ... */ cur_time = 0; for (;;) { tmp = (year % 4 == 0) ? SEC_LYEAR : SEC_YEAR; if (cur_time < tmp) break; cur_time -= tmp; year++; } day = (unsigned short) (cur_time / SEC_DAY); cur_time -= (long) day *SEC_DAY; hour = (unsigned short) (cur_time / SEC_HOUR); cur_time -= (long) hour *SEC_HOUR; minutes = (unsigned short) (cur_time / SEC_MIN); cur_time -= (long) minutes *SEC_MIN; seconds = (unsigned short) cur_time; mon_len[1] = (year % 4 == 0) ? 29 : 28; i = 0; while (day >= mon_len[i]) { month++; day -= mon_len[i++]; } day++; entry->d_date = (year << 9) | (month << 5) | day; entry->d_time = (hour << 11) | (minutes << 5) | seconds; } char *make_name(dir_ptr, dir_fl) register DIRECTORY *dir_ptr; short dir_fl; { static char name_buf[14]; register char *ptr = name_buf; short i; for (i = 0; i < 8; i++) *ptr++ = dir_ptr->d_name[i]; while (*--ptr == ' '); ptr++; if (dir_ptr->d_ext[0] != ' ') { *ptr++ = '.'; for (i = 0; i < 3; i++) *ptr++ = dir_ptr->d_ext[i]; while (*--ptr == ' '); ptr++; } if (dir_fl) *ptr++ = '/'; *ptr = '\0'; return name_buf; } fill(buffer) register char *buffer; { static BOOL eof_mark = FALSE; char *last = &buffer[cluster_size]; char *begin = buffer; register short c; if (eof_mark) return 0; while (buffer < last) { if ((c = get_char()) == EOF) { eof_mark = TRUE; if (Aflag) *buffer++ = EOF_MARK; break; } *buffer++ = c; } return (int) (buffer - begin); } get_char() { static short read_chars, index; static char input[MAX_CLUSTER_SIZE]; static BOOL new_line = FALSE; if (new_line == TRUE) { new_line = FALSE; return '\n'; } if (index == read_chars) { if ((read_chars = read(0, input, cluster_size)) == 0) return EOF; index = 0; } if (Aflag && input[index] == '\n') { new_line = TRUE; index++; return '\r'; } return input[index++]; } #define HOUR 0xF800 /* Upper 5 bits */ #define MIN 0x07E0 /* Middle 6 bits */ #define YEAR 0xFE00 /* Upper 7 bits */ #define MONTH 0x01E0 /* Mid 4 bits */ #define DAY 0x01F /* Lowest 5 bits */ char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; modes(mode) register unsigned char mode; { print_string(FALSE, "\t%c%c%c%c%c", (mode & SUB_DIR) ? 'd' : '-', (mode & 02) ? 'h' : '-', (mode & 04) ? 's' : '-', (mode & 01) ? '-' : 'w', (mode & 0x20) ? 'a' : '-'); } show(dir_ptr, name) DIRECTORY *dir_ptr; char *name; { register unsigned short e_date = dir_ptr->d_date; register unsigned short e_time = dir_ptr->d_time; unsigned short next; char bname[20]; short i = 0; while (*name && *name != '/') bname[i++] = *name++; bname[i] = '\0'; if (!Lflag) { print_string(FALSE, "%s\n", bname); return; } modes(dir_ptr->d_attribute); print_string(FALSE, "\t%s%s", bname, strlen(bname) < 8 ? "\t\t" : "\t"); i = 1; if (is_dir(dir_ptr)) { next = dir_ptr->d_cluster; while (((next = next_cluster(next)) != LAST_CLUSTER && Tfat) || (!Tfat && next != LAST_16)) i++; print_string(FALSE, "%L", (long) i * (long) cluster_size); } else print_string(FALSE, "%L", dir_ptr->d_size); print_string(FALSE, "\t%N:%N %P %s %d\n", ((e_time & HOUR) >> 11), ((e_time & MIN) >> 5), (e_date & DAY), month[((e_date & MONTH) >> 5) - 1], ((e_date & YEAR) >> 9) + 1980); } free_blocks() { register unsigned short cl_no; register short free = 0; short bad = 0; if (Tfat) for (cl_no = 2; cl_no <= total_clusters; cl_no++) { switch (next_cluster(cl_no)) { case FREE: free++; break; case BAD: bad++; } } else for (cl_no = 2; cl_no <= total_clusters; cl_no++) { switch (next_cluster(cl_no)) { case FREE_16: free++; break; case BAD_16: bad++; } } print_string(FALSE, "Free space: %L bytes.\n", (long) free * (long) cluster_size); if (bad) print_string(FALSE, "Bad sectors: %L bytes.\n", (long) bad * (long) cluster_size); } char *num_out(number) register long number; { static char num_buf[13]; char temp[13]; register short i = 0; short j; if (number == 0) temp[i++] = '0'; while (number) { temp[i++] = (char) (number % 10L + '0'); number /= 10L; } for (j = 0; j < 11; j++) num_buf[j] = temp[i - j - 1]; num_buf[i] = '\0'; return num_buf; } /* VARARGS */ print_string(err_fl, fmt, args) BOOL err_fl; char *fmt; int args; { char buf[200]; register char *buf_ptr = buf; char *scan_ptr; register int *arg_ptr = &args; short i; while (*fmt) { if (*fmt == '%') { fmt++; if (*fmt == 'c') { *buf_ptr++ = (char) *arg_ptr++; fmt++; continue; } if (*fmt == 'S') { scan_ptr = (char *) *arg_ptr; for (i = 0; i < 11; i++) *buf_ptr++ = *scan_ptr++; fmt++; continue; } if (*fmt == 's') scan_ptr = (char *) *arg_ptr; else if (*fmt == 'L') { scan_ptr = num_out(*((long *) arg_ptr)); arg_ptr++; } else { scan_ptr = num_out((long) *arg_ptr); if (*fmt == 'P' && *arg_ptr < 10) *buf_ptr++ = ' '; else if (*fmt == 'N' && *arg_ptr < 10) *buf_ptr++ = '0'; } while (*buf_ptr++ = *scan_ptr++); buf_ptr--; arg_ptr++; fmt++; } else *buf_ptr++ = *fmt++; } *buf_ptr = '\0'; if (err_fl) { flush(); write(2, buf, (int) (buf_ptr - buf)); } else print(STD_OUT, buf, 0); flush(); } DIRECTORY *read_cluster(cluster) register unsigned short cluster; { register DIRECTORY *sub_dir; extern char *sbrk(); if ((sub_dir = (DIRECTORY *) sbrk(cluster_size)) < 0) { print_string(TRUE, "Cannot set break!\n"); leave(1); } disk_read(clus_add(cluster), sub_dir, cluster_size); return sub_dir; } unsigned short free_cluster(leave_fl) BOOL leave_fl; { static unsigned short cl_index = 2; if (Tfat) while (cl_index <= total_clusters && next_cluster(cl_index) != FREE) cl_index++; else /* Sixteen bit */ while (cl_index <= total_clusters && next_cluster(cl_index) != FREE_16) cl_index++; if (leave_fl && cl_index > total_clusters) { flush(); print_string(TRUE, "Disk full. File not added.\n"); leave(1); } return cl_index++; } /* ****************FIX FOR SIXTEEN BIT ***************** */ link_fat(cl_1, cl_2) unsigned short cl_1; register unsigned short cl_2; { if (Tfat) { register unsigned char *fat_index = &fat.twelve[(cl_1 >> 1) * 3 + 1]; if (cl_1 & 0x01) { *(fat_index + 1) = cl_2 >> 4; *fat_index = (*fat_index & 0x0F) | ((cl_2 & 0x0F) << 4); } else { *(fat_index - 1) = cl_2 & 0x0FF; *fat_index = (*fat_index & 0xF0) | (cl_2 >> 8); } } else { fat.sixteen[cl_1] = cl_2; } } unsigned short next_cluster(cl_no) register unsigned short cl_no; { if (Tfat) { register unsigned char *fat_index = &fat.twelve[(cl_no >> 1) * 3 + 1]; if (cl_no & 0x01) cl_no = (*(fat_index + 1) << 4) | (*fat_index >> 4); else cl_no = ((*fat_index & 0x0F) << 8) | *(fat_index - 1); if ((cl_no & MASK) == MASK) cl_no = LAST_CLUSTER; else if ((cl_no & BAD) == BAD) cl_no = BAD; } else { /*cl_no = fat.sixteen[cl_no << 1];*/ cl_no = fat.sixteen[cl_no]; if ((cl_no & MASK_16) == MASK_16) cl_no = LAST_16; else if ((cl_no & BAD_16) == BAD_16) cl_no = BAD_16; } return cl_no; } char *slash(str) register char *str; { register char *result = str; while (*str) if (*str++ == '/') result = str; return result; } add_path(file, slash_fl) register char *file; BOOL slash_fl; { register char *ptr = path; while (*ptr) ptr++; if (file == NIL_PTR) { ptr--; do { ptr--; } while (*ptr != '/' && ptr != path); if (ptr != path && !slash_fl) ptr++; *ptr = '\0'; } else while (*ptr++ = *file++); } bcopy(src, dest, bytes) register char *src, *dest; short bytes; { while (bytes--) *dest++ = *src++; } disk_io(op, seek, address, bytes) register BOOL op; unsigned long seek; DIRECTORY *address; register unsigned bytes; { unsigned int r; if (lseek(disk, seek, 0) < 0L) { flush(); print_string(TRUE, "Bad lseek\n"); leave(1); } if (op == READ) r = read(disk, address, bytes); else r = write(disk, address, bytes); if (r != bytes) bad(); } bad() { flush(); perror("I/O error"); leave(1); }