⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dosread.c

📁 操作系统源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* 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 + -