--------------------------- cut here -------------------------------- /* * 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. */ #ifdef debug /* usually avoid stdio, what a nuisance */ #include <stdio.h> #undef EOF /* one-off stdio redefines it different */ #endif #include <sys/stat.h> #define DRIVE "/dev/dosX" #define DRIVE_NR 8 #define MAX_CLUSTER_SIZE 4096 #define MAX_ROOT_ENTRIES 512 #define FAT_START 512L /* After bootsector */ #define ROOTADDR (FAT_START + 2L * (long) fat_size) #define clus_add(cl_no) ((long) (((long) cl_no - 2L) \ * (long) cluster_size \ + 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 0xFFFF #define MASK 0xFF8 #define MASK16 0xFFF8 #define FREE 0x000 #define BAD 0xFF0 #define BAD16 0xFFF0 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 get_fat(f, b) buf_read(FAT_START + f, b, 1) #define put_fat(f, b) { disk_io(WRITE, FAT_START + f, b, 1); \ disk_io(WRITE, FAT_START + f + fat_size, b, 1);} #define put_fat16(f, b) { disk_io(WRITE, FAT_START + f, b, 2); \ disk_io(WRITE, FAT_START + f + fat_size, b, 2);} #define get_fat16(f, b) buf_read(FAT_START + f, b, 2) #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; unsigned char fat_info; DIRECTORY root[MAX_ROOT_ENTRIES]; DIRECTORY save_entry; char null[MAX_CLUSTER_SIZE], device[] = DRIVE, path[128]; long data_start, mark; unsigned short total_clusters, cluster_size, fat_size, root_entries, sub_entries; BOOL Rflag, Lflag, Aflag, dos_read, dos_write, dos_dir, fat_16 = 0; char disk_written = 1, buf_buf[1025]; long buf_addr = 0; DIRECTORY *directory(), *read_cluster(); unsigned short free_cluster(), next_cluster(); char *make_name(), *num_out(), *slash(), *brk(); long lseek(), time(); 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); } unsigned c2u2( ucarray ) unsigned char *ucarray; { return ucarray[0] + (ucarray[1] << 8); /* parens vital */ } determine() { struct dosboot { unsigned char cjump[2]; /* unsigneds avoid bugs */ unsigned char nop; unsigned char name[8]; unsigned char cbytepers[2]; /* don't use shorts, etc */ unsigned char secpclus; /* to avoid struct member */ unsigned char creservsec[2]; /* alignment and byte */ unsigned char fats; /* order bugs */ unsigned char cdirents[2]; unsigned char ctotsec[2]; unsigned char media; unsigned char csecpfat[2]; unsigned char csecptrack[2]; unsigned char cheads[2]; unsigned char chiddensec[2]; /* char fill[482]; */ } boot; unsigned short boot_magic; /* last of boot block */ unsigned bytepers, reservsec, dirents, totsec; unsigned secpfat, secptrack, heads, hiddensec; int errcount = 0; /* read Bios-Parameterblock */ disk_read(0L, &boot, sizeof boot); disk_read(0x1FEL, &boot_magic, sizeof boot_magic); /* convert some arrays */ bytepers = c2u2(boot.cbytepers); reservsec = c2u2(boot.creservsec); dirents = c2u2(boot.cdirents); totsec = c2u2(boot.ctotsec); secpfat = c2u2(boot.csecpfat); secptrack = c2u2(boot.csecptrack); heads = c2u2(boot.cheads); hiddensec = c2u2(boot.chiddensec); /* calculate everything before checking for debugging print */ total_clusters = totsec / (boot.secpclus == 0 ? 1 : boot.secpclus); cluster_size = bytepers * boot.secpclus; fat_size = secpfat * bytepers; data_start = (long)bytepers + (long)boot.fats * (long)fat_size + (long)dirents * 32L; root_entries = dirents; sub_entries = boot.secpclus * bytepers / 32; if (total_clusters > 4096) fat_16 = 1; #ifdef debug /* This used to help find foolish sign extensions and op precedences. * It remains useful for looking at nonstandard formats. */ fprintf(stderr, "OEM = %8.8s\n", boot.name); fprintf(stderr, "Bytes/sector = %u\n", bytepers); fprintf(stderr, "Sectors/cluster = %u\n", boot.secpclus); fprintf(stderr, "Number of Reserved Clusters = %u\n", reservsec); fprintf(stderr, "Number of FAT's = %u\n", boot.fats); fprintf(stderr, "Number of root-directory entries = %u\n", dirents); fprintf(stderr, "Total sectors in logical volume = %u\n", totsec); fprintf(stderr, "Media descriptor = 0x%02x\n", boot.media); fprintf(stderr, "Number of sectors/FAT = %u\n", secpfat); fprintf(stderr, "Sectors/track = %u\n", secptrack); fprintf(stderr, "Number of heads = %u\n", heads); fprintf(stderr, "Number of hidden sectors = %u\n", hiddensec); fprintf(stderr, "Bootblock magic number = 0x%04x\n", boot_magic); #endif /* safety checking */ if (boot_magic != 0xAA55) { print_string(TRUE, "magic != 0xAA55\n"); ++errcount; } /* check sectors per track instead of inadequate media byte */ if (secptrack < 15 && /* assume > 15 hard disk & wini OK */ #ifdef SECT10 /* BIOS modified for 10 sec/track */ secptrack != 10 && #endif #ifdef SECT8 /* BIOS modified for 8 sec/track */ secptrack != 8 && #endif secptrack != 9) { print_string(TRUE, "sectors per track not supported\n"); ++errcount; } if (boot.secpclus == 0) { print_string(TRUE, "sectors per cluster == 0\n"); ++errcount; } if (boot.fats != 2 && dos_write) { print_string (TRUE, "fats != 2\n"); ++errcount; } if (reservsec != 1) { print_string (TRUE, "reserved != 1\n"); ++errcount; } if (cluster_size > MAX_CLUSTER_SIZE) { print_string (TRUE, "cluster size too big\n"); ++errcount; } if (errcount != 0) { print_string (TRUE, "Can't handle disk\n"); leave (2); } } main(argc, argv) int argc; register char *argv[]; { register char *arg_ptr = slash(argv[0]); DIRECTORY *entry; short index = 1; char dev_nr = '0'; unsigned char fat_check; 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]); if ((dev_nr = (0x5f & *argv[index++])) < 'A' || dev_nr > 'Z') usage(argv[0]); device[DRIVE_NR] = dev_nr; if ((disk = open(device, dos_write ? 2 : 0)) < 0) { print_string(TRUE, "Cannot open %s\n", device); exit(1); } disk_read(FAT_START, &fat_info, 1); determine(); disk_read(FAT_START + (long) fat_size, &fat_check, sizeof(fat_check)); if (fat_check != fat_info) { print_string(TRUE, "Disk type in FAT copy differs from disk type in FAT original.\n"); leave(1); } disk_read(ROOTADDR, root, DIR_SIZE * root_entries); if (dos_dir && Lflag) { 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]); if (Lflag) print(STD_OUT, "Root directory:\n", 0); list_dir(root, root_entries, FALSE); if (Lflag) 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 && Lflag) print_string(FALSE, "Directory %s:\n", path); entry = find_entry(root, root_entries, argv[index]); if (dos_dir) { list_dir(entry, sub_entries, FALSE); if (Lflag) 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); } 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) { if (!mem) mark = ROOTADDR + (long) i * (long) DIR_SIZE; else mark = clus_add(last) + (long) i * (long) DIR_SIZE; 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 (cl_no != LAST_CLUSTER && 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); link_fat(cl_no, LAST_CLUSTER); 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 (cl_no == (fat_16? BAD16: BAD)) { flush(); print_string(TRUE, "Reserved cluster value encountered.\n"); leave(1); } } while (entry->d_size && cl_no != LAST_CLUSTER); if (cl_no != LAST_CLUSTER) 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, "Diskette 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) link_fat(cl_no, LAST_CLUSTER); entry->d_size = Aflag ? (size - 1) : size; /* Strip added ^Z */ fill_date(entry); disk_write(mark, entry, DIR_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) 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; long free = 0; long bad = 0; for (cl_no = 2; cl_no <= total_clusters; cl_no++) { switch (next_cluster(cl_no)) { case FREE: free++; break; case BAD16: bad++; break; case BAD: if(!fat_16) bad++; } } print_string(FALSE, "Free space: %L bytes.\n", free * (long) cluster_size); if (bad) print_string(FALSE, "Bad sectors: %L bytes.\n", 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); } 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; while (cl_index <= total_clusters && next_cluster(cl_index) != FREE) cl_index++; if (leave_fl && cl_index > total_clusters) { flush(); print_string(TRUE, "Diskette full. File not added.\n"); leave(1); } return cl_index++; } link_fat(cl_1, cl_2) unsigned short cl_1; register unsigned short cl_2; { register unsigned fat_index; unsigned char pad; unsigned pad16; if(fat_16) { pad16 = cl_2; put_fat16((long)(cl_1 << 1), &pad16); return; } fat_index = (cl_1 >> 1) * 3 + 1; if (cl_1 & 0x01) { pad = cl_2 >> 4; put_fat((long)(fat_index + 1), &pad); get_fat((long)fat_index, &pad); pad = (pad & 0x0F) | ((cl_2 & 0x0F) << 4); put_fat((long)fat_index, &pad); } else { pad = cl_2; put_fat((long)(fat_index - 1), &pad); get_fat((long)fat_index, &pad); pad = (pad & 0xF0) | (0xf & (cl_2 >> 8)); put_fat((long)fat_index, &pad); } } unsigned short next_cluster(cl_no) register unsigned short cl_no; { register unsigned fat_index; unsigned char pad; unsigned pad16; unsigned mask = MASK16; unsigned bad = BAD16; if(!fat_16) { fat_index = (cl_no >> 1) * 3 + 1; get_fat((long)fat_index, &pad); if (cl_no & 0x01) { pad16 = 0x0f & (pad >> 4); get_fat((long)(fat_index + 1), &pad); cl_no = (((short)pad) << 4) | pad16; } else { pad16 = (0x0f & pad) << 8; get_fat((long)(fat_index - 1), &pad); cl_no = (short)pad | pad16; } mask = MASK; bad = BAD; } else { get_fat16((long)(cl_no << 1), &pad16); cl_no = pad16; } if ((cl_no & mask) == mask) cl_no = LAST_CLUSTER; else if ((cl_no & bad) == bad) cl_no = bad; 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) { if(ptr != path) ptr--; if(ptr != path) 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 { disk_written = 1; r = write(disk, address, bytes); } if (r != bytes) bad(); } bad() { flush(); perror("I/O error"); leave(1); } buf_read(seek, b, c) long seek; register char *b; int c; { if(disk_written || (seek & (~0x3ffL)) != buf_addr) { disk_written = 0; disk_io(READ, buf_addr = seek & (~0x3ffL), buf_buf, 1025); } seek &= 0x3ffL; *b++ = buf_buf[seek++]; if(c == 2) *b = buf_buf[seek]; } ------------------------------------- cut here -----------------------