📄 dosread.c
字号:
/* dos{dir|read|write} - {list|read|write} MS-DOS disks Author: M. Huisjes *//* 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. */#include <assert.h>#include <ctype.h>#include <errno.h>#include <limits.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <time.h>#include <sys/times.h>#include <unistd.h>#define MAX_CLUSTER_SIZE 4096#define MAX_ROOT_ENTRIES 512#define FAT_START 512L /* After bootsector */#define ROOTADDR (FAT_START + 2L * 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_CLUSTER12 0xFFF#define LAST_CLUSTER 0xFFFF#define FREE 0x000#define BAD 0xFF0#define BAD16 0xFFF0typedef int 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 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 STD_OUT 1char *cmnd;static int disk; /* File descriptor for disk I/O */static DIRECTORY root[MAX_ROOT_ENTRIES];static DIRECTORY save_entry;static char drive[] = "/dev/dosX";#define DRIVE_NR (sizeof (drive) - 2)static char null[MAX_CLUSTER_SIZE], *device = drive, path[128];static long data_start;static long mark; /* offset of directory entry to be written */static unsigned short total_clusters, cluster_size, root_entries, sub_entries;static unsigned long fat_size;static BOOL Rflag, Lflag, Aflag, dos_read, dos_write, dos_dir, fat_16 = 0;static BOOL big_endian;/* maximum size of a cooked 12bit FAT. Also Size of 16bit FAT cache * if not enough memory for whole FAT */#define COOKED_SIZE 8192/* raw FAT. Only used for 12bit FAT to make conversion easier */static unsigned char *raw_fat;/* Cooked FAT. May be only part of the FAT for 16 bit FATs */static unsigned short *cooked_fat;/* lowest and highest entry in fat cache */static unsigned short fat_low = USHRT_MAX, fat_high = 0;static BOOL fat_dirty = FALSE;static unsigned int cache_size;/* Prototypes. */_PROTOTYPE(void usage, (char *prog_name) );_PROTOTYPE(unsigned c2u2, (unsigned char *ucarray) );_PROTOTYPE(unsigned long c4u4, (unsigned char *ucarray) );_PROTOTYPE(void determine, (void));_PROTOTYPE(int main, (int argc, char *argv []));_PROTOTYPE(DIRECTORY *directory, (DIRECTORY *dir, int entries, BOOL function, char *pathname) );_PROTOTYPE(void extract, (DIRECTORY *entry) );_PROTOTYPE(void make_file, (DIRECTORY *dir_ptr, int entries, char *name) );_PROTOTYPE(void fill_date, (DIRECTORY *entry) );_PROTOTYPE(char *make_name, (DIRECTORY *dir_ptr, int dir_fl) );_PROTOTYPE(int fill, (char *buffer, size_t size) );_PROTOTYPE(void xmodes, (int mode) );_PROTOTYPE(void show, (DIRECTORY *dir_ptr, char *name) );_PROTOTYPE(void free_blocks, (void));_PROTOTYPE(DIRECTORY *read_cluster, (unsigned int cluster) );_PROTOTYPE(unsigned short free_cluster, (BOOL leave_fl) );_PROTOTYPE(void link_fat, (unsigned int cl_1, unsigned int cl_2) );_PROTOTYPE(unsigned short next_cluster, (unsigned int cl_no) );_PROTOTYPE(char *slash, (char *str) );_PROTOTYPE(void add_path, (char *file, BOOL slash_fl) );_PROTOTYPE(void disk_io, (BOOL op, unsigned long seek, void *address, unsigned bytes) );_PROTOTYPE(void flush_fat, (void));_PROTOTYPE(void read_fat, (unsigned int cl_no));_PROTOTYPE(BOOL free_range, (unsigned short *first, unsigned short *last));_PROTOTYPE(long lmin, (long a, long b));void usage(prog_name)register char *prog_name;{ fprintf (stderr, "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 */}unsigned long c4u4(ucarray)unsigned char *ucarray;{ return ucarray[0] + ((unsigned long) ucarray[1] << 8) + ((unsigned long) ucarray[2] << 16) + ((unsigned long) ucarray[3] << 24);}void 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]; unsigned char dos4hidd2[2]; unsigned char dos4totsec[4]; /* Char fill[476]; */ } boot; unsigned short boot_magic; /* last of boot block */ unsigned bytepers, reservsec, dirents; unsigned secpfat, secptrack, heads, hiddensec; unsigned long totsec; unsigned char fat_info, fat_check; unsigned short endiantest = 1; int errcount = 0; big_endian = !(*(unsigned char *)&endiantest); /* Read Bios-Parameterblock */ disk_io(READ, 0L, &boot, sizeof boot); disk_io(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); if (totsec == 0) totsec = c4u4(boot.dos4totsec); secpfat = c2u2(boot.csecpfat); secptrack = c2u2(boot.csecptrack); heads = c2u2(boot.cheads); /* The `hidden sectors' are the sectors before the partition. * The calculation here is probably wrong (I think the dos4hidd2 * bytes are the msbs), but that doesn't matter, since the * value isn't used anyway */ hiddensec = c2u2(boot.chiddensec); if (hiddensec == 0) hiddensec = c2u2 (boot.dos4hidd2); /* Safety checking */ if (boot_magic != 0xAA55) { fprintf (stderr, "%s: magic != 0xAA55\n", cmnd); ++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) { fprintf (stderr, "%s: %d sectors per track not supported\n", cmnd, secptrack); ++errcount; } if (bytepers == 0) { fprintf (stderr, "%s: bytes per sector == 0\n", cmnd); ++errcount; } if (boot.secpclus == 0) { fprintf (stderr, "%s: sectors per cluster == 0\n", cmnd); ++errcount; } if (boot.fats != 2 && dos_write) { fprintf (stderr, "%s: fats != 2\n", cmnd); ++errcount; } if (reservsec != 1) { fprintf (stderr, "%s: reserved != 1\n", cmnd); ++errcount; } if (errcount != 0) { fprintf (stderr, "%s: Can't handle disk\n", cmnd); exit(2); } /* Calculate everything. */ if (boot.secpclus == 0) boot.secpclus = 1; total_clusters = (totsec - boot.fats * secpfat - reservsec - dirents * 32L / bytepers ) / boot.secpclus + 2; /* first 2 entries in FAT aren't used */ cluster_size = bytepers * boot.secpclus; fat_size = (unsigned long) secpfat * (unsigned long) bytepers; data_start = (long) bytepers + (long) boot.fats * fat_size + (long) dirents *32L; root_entries = dirents; sub_entries = boot.secpclus * bytepers / 32; if (total_clusters > 4096) fat_16 = 1; /* Further safety checking */ if (cluster_size > MAX_CLUSTER_SIZE) { fprintf (stderr, "%s: cluster size too big\n", cmnd); ++errcount; } disk_io(READ, FAT_START, &fat_info, 1); disk_io(READ, FAT_START + fat_size, &fat_check, 1); if (fat_check != fat_info) { fprintf (stderr, "%s: Disk type in FAT copy differs from disk type in FAT original.\n", cmnd); ++errcount; } if (errcount != 0) { fprintf (stderr, "%s: Can't handle disk\n", cmnd); exit(2); }}int main(argc, argv)int argc;register char *argv[];{ register char *arg_ptr = slash(argv[0]); DIRECTORY *entry; short idx = 1; char dev_nr = '0'; cmnd = arg_ptr; /* needed for error messages */ 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 { fprintf (stderr, "%s: Program should be named dosread, doswrite or dosdir.\n", cmnd); 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) { assert ('\n' == 10); assert ('\r' == 13); Aflag = TRUE; } else { usage(argv[0]); } } idx++; } if (idx == argc) usage(argv[0]); if (strlen(argv[idx]) > 1) { device = argv[idx++]; /* If the device does not contain a / we assume that it * is the name of a device in /dev. Instead of prepending * /dev/ we try to chdir there. */ if (strchr(device, '/') == NULL && chdir("/dev") < 0) { perror("/dev"); exit(1); } } else { if ((dev_nr = toupper (*argv[idx++])) < 'A' || dev_nr > 'Z') usage(argv[0]); device[DRIVE_NR] = dev_nr; } if ((disk = open(device, dos_write ? O_RDWR : O_RDONLY)) < 0) { fprintf (stderr, "%s: cannot open %s: %s\n", cmnd, device, strerror (errno)); exit(1); } determine(); disk_io(READ, ROOTADDR, root, DIR_SIZE * root_entries); if (dos_dir && Lflag) { entry = label(); printf ("Volume in drive %c ", dev_nr); if (entry == NIL_DIR) printf("has no label.\n\n"); else printf ("is %.11s\n\n", entry->d_name); } if (argv[idx] == NIL_PTR) { if (!dos_dir) usage(argv[0]); if (Lflag) printf ("Root directory:\n"); list_dir(root, root_entries, FALSE); if (Lflag) free_blocks(); fflush (stdout); exit(0); } for (arg_ptr = argv[idx]; *arg_ptr; arg_ptr++) if (*arg_ptr == '\\') *arg_ptr = '/'; else *arg_ptr = toupper (*arg_ptr); if (*--arg_ptr == '/') *arg_ptr = '\0'; /* skip trailing '/' */ add_path(argv[idx], FALSE); add_path("/", FALSE); if (dos_dir && Lflag) printf ( "Directory %s:\n", path); entry = find_entry(root, root_entries, argv[idx]); if (dos_dir) { list_dir(entry, sub_entries, FALSE); if (Lflag) free_blocks(); } else if (dos_read) extract(entry); else { if (entry != NIL_DIR) { fflush (stdout); if (is_dir(entry)) fprintf (stderr, "%s: %s is a directory.\n", cmnd, path); else fprintf (stderr, "%s: %s already exists.\n", cmnd, argv[idx]); exit(1); } add_path(NIL_PTR, TRUE); if (*path) make_file(find_entry(root, root_entries, path), sub_entries, slash(argv[idx])); else make_file(root, root_entries, argv[idx]); } (void) close(disk); fflush (stdout); exit(0); return(0);}/* General directory search routine. * * dir: * Points to one or more directory entries * entries: * number of entries * if entries == root_entries, dir points to the entire * root directory. Otherwise it points to a single directory * entry describing the directory to be searched. * * function: * FIND ... find pathname relative to directory dir. * LABEL ... find first label entry in dir. * ENTRY ... create a new empty entry. * FALSE ... list directory * * pathname: * name of the file to be found or directory to be listed. * must be in upper case, pathname components must be * separated by slashes, but can be longer than than * 8+3 characters (The rest is ignored). */DIRECTORY *directory(dir, entries, function, pathname)DIRECTORY *dir;int entries;int function;register char *pathname;{ register DIRECTORY *dir_ptr = dir; DIRECTORY *mem = NIL_DIR; unsigned short cl_no = dir->d_cluster; unsigned short type, last = 0; char file_name[14]; char *name; int i = 0; if (function == FIND) { while (*pathname != '/' && *pathname != '.' && *pathname && i < 8) { file_name[i++] = *pathname++; } if (*pathname == '.') { int j = 0; file_name[i++] = *pathname++; while (*pathname != '/' && *pathname != '.' && *pathname && j++ < 3) { 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) { fflush (stdout); fprintf (stderr, "%s: Not a directory: %s\n", cmnd, file_name); exit(1); } } else if (*pathname == '\0' && dos_read) { fflush (stdout); fprintf (stderr, "%s: %s is a directory.\n", cmnd, path); exit(1); } if (*pathname) { dir_ptr = find_entry(dir_ptr, sub_entries, pathname + 1); } if (mem) { if (dir_ptr) { memcpy((char *)&save_entry, (char *)dir_ptr, DIR_SIZE); dir_ptr = &save_entry; } free( (void *) mem); } return dir_ptr; } else { if (function == FALSE) { show(dir_ptr, name); } else if (type) { /* Recursive */ printf ( "Directory %s%s:\n", path, name); add_path(name, FALSE); list_dir(dir_ptr, sub_entries, FALSE); add_path(NIL_PTR, FALSE); } } } if (mem) free( (void *) mem); } while (cl_no != LAST_CLUSTER && mem); switch (function) { case FIND: if (dos_write && *pathname == '\0') return NIL_DIR; fflush (stdout); fprintf (stderr, "%s: Cannot find `%s'.\n", cmnd, file_name); exit(1); case LABEL: return NIL_DIR; case ENTRY: if (!mem) { fflush (stdout); fprintf (stderr, "%s: No entries left in root directory.\n", cmnd); exit(1); } cl_no = free_cluster(TRUE); link_fat(last, cl_no); link_fat(cl_no, LAST_CLUSTER); disk_io(WRITE, clus_add(cl_no), null, cluster_size); return new_entry(dir, entries); case FALSE: if (Rflag) { printf ("\n"); list_dir(dir, entries, TRUE); } } return NULL;}void extract(entry)register DIRECTORY *entry;{ register unsigned short cl_no = entry->d_cluster; char buffer[MAX_CLUSTER_SIZE]; int rest, i; if (entry->d_size == 0) /* Empty file */ return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -