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

📄 block-vvfat.c

📁 qemu虚拟机代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	const char* dirname){    bootsector_t* bootsector;    mapping_t* mapping;    unsigned int i;    unsigned int cluster;    memset(&(s->first_sectors[0]),0,0x40*0x200);    s->cluster_size=s->sectors_per_cluster*0x200;    s->cluster_buffer=malloc(s->cluster_size);    assert(s->cluster_buffer);    /*     * The formula: sc = spf+1+spf*spc*(512*8/fat_type),     * where sc is sector_count,     * spf is sectors_per_fat,     * spc is sectors_per_clusters, and     * fat_type = 12, 16 or 32.     */    i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;    s->sectors_per_fat=(s->sector_count+i)/i; /* round up */        array_init(&(s->mapping),sizeof(mapping_t));    array_init(&(s->directory),sizeof(direntry_t));    /* add volume label */    {	direntry_t* entry=array_get_next(&(s->directory));	entry->attributes=0x28; /* archive | volume label */	snprintf(entry->name,11,"QEMU VVFAT");    }    /* Now build FAT, and write back information into directory */    init_fat(s);    s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;    s->cluster_count=sector2cluster(s, s->sector_count);    mapping = array_get_next(&(s->mapping));    mapping->begin = 0;    mapping->dir_index = 0;    mapping->info.dir.parent_mapping_index = -1;    mapping->first_mapping_index = -1;    mapping->path = strdup(dirname);    i = strlen(mapping->path);    if (i > 0 && mapping->path[i - 1] == '/')	mapping->path[i - 1] = '\0';    mapping->mode = MODE_DIRECTORY;    mapping->read_only = 0;    s->path = mapping->path;    for (i = 0, cluster = 0; i < s->mapping.next; i++) {	int j;	/* MS-DOS expects the FAT to be 0 for the root directory 	 * (except for the media byte). */	/* LATER TODO: still true for FAT32? */	int fix_fat = (i != 0);	mapping = array_get(&(s->mapping), i);        if (mapping->mode & MODE_DIRECTORY) {	    mapping->begin = cluster;	    if(read_directory(s, i)) {		fprintf(stderr, "Could not read directory %s\n",			mapping->path);		return -1;	    }	    mapping = array_get(&(s->mapping), i);	} else {	    assert(mapping->mode == MODE_UNDEFINED);	    mapping->mode=MODE_NORMAL;	    mapping->begin = cluster;	    if (mapping->end > 0) {		direntry_t* direntry = array_get(&(s->directory),			mapping->dir_index);		mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;		set_begin_of_direntry(direntry, mapping->begin);	    } else {		mapping->end = cluster + 1;		fix_fat = 0;	    }	}	assert(mapping->begin < mapping->end);	/* fix fat for entry */	if (fix_fat) {	    for(j = mapping->begin; j < mapping->end - 1; j++)		fat_set(s, j, j+1);	    fat_set(s, mapping->end - 1, s->max_fat_value);	}	/* next free cluster */	cluster = mapping->end;	if(cluster > s->cluster_count) {	    fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type);	    return -1;	}    }    mapping = array_get(&(s->mapping), 0);    s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;    s->last_cluster_of_root_directory = mapping->end;    /* the FAT signature */    fat_set(s,0,s->max_fat_value);    fat_set(s,1,s->max_fat_value);    s->current_mapping = NULL;    bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);    bootsector->jump[0]=0xeb;    bootsector->jump[1]=0x3e;    bootsector->jump[2]=0x90;    memcpy(bootsector->name,"QEMU    ",8);    bootsector->sector_size=cpu_to_le16(0x200);    bootsector->sectors_per_cluster=s->sectors_per_cluster;    bootsector->reserved_sectors=cpu_to_le16(1);    bootsector->number_of_fats=0x2; /* number of FATs */    bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);    bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);    bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */    s->fat.pointer[0] = bootsector->media_type;    bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);    bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);    bootsector->number_of_heads=cpu_to_le16(s->bs->heads);    bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);    bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);    /* LATER TODO: if FAT32, this is wrong */    bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */    bootsector->u.fat16.current_head=0;    bootsector->u.fat16.signature=0x29;    bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);    memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);    memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12   ":s->fat_type==16?"FAT16   ":"FAT32   "),8);    bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;    return 0;}static BDRVVVFATState *vvv = NULL;static int enable_write_target(BDRVVVFATState *s);static int is_consistent(BDRVVVFATState *s);static int vvfat_open(BlockDriverState *bs, const char* dirname){    BDRVVVFATState *s = bs->opaque;    int floppy = 0;    int i;    vvv = s;DLOG(if (stderr == NULL) {    stderr = fopen("vvfat.log", "a");    setbuf(stderr, NULL);})    s->bs = bs;    s->fat_type=16;    /* LATER TODO: if FAT32, adjust */    s->sector_count=0xec04f;    s->sectors_per_cluster=0x10;    /* LATER TODO: this could be wrong for FAT32 */    bs->cyls=1023; bs->heads=15; bs->secs=63;    s->current_cluster=0xffffffff;    s->first_sectors_number=0x40;    /* read only is the default for safety */    bs->read_only = 1;    s->qcow = s->write_target = NULL;    s->qcow_filename = NULL;    s->fat2 = NULL;    s->downcase_short_names = 1;        if (!strstart(dirname, "fat:", NULL))	return -1;    if (strstr(dirname, ":rw:")) {	if (enable_write_target(s))	    return -1;	bs->read_only = 0;    }    if (strstr(dirname, ":floppy:")) {	floppy = 1;	s->fat_type = 12;	s->first_sectors_number = 1;	s->sectors_per_cluster=2;	bs->cyls = 80; bs->heads = 2; bs->secs = 36;    }    if (strstr(dirname, ":32:")) {	fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");	s->fat_type = 32;    } else if (strstr(dirname, ":16:")) {	s->fat_type = 16;    } else if (strstr(dirname, ":12:")) {	s->fat_type = 12;	s->sector_count=2880;    }    i = strrchr(dirname, ':') - dirname;    assert(i >= 3);    if (dirname[i-2] == ':' && isalpha(dirname[i-1]))	/* workaround for DOS drive names */	dirname += i-1;    else	dirname += i+1;    bs->total_sectors=bs->cyls*bs->heads*bs->secs;    if (s->sector_count > bs->total_sectors)	s->sector_count = bs->total_sectors;    if(init_directories(s, dirname))	return -1;    if(s->first_sectors_number==0x40)	init_mbr(s);    /* for some reason or other, MS-DOS does not like to know about CHS... */    if (floppy)	bs->heads = bs->cyls = bs->secs = 0;    //    assert(is_consistent(s));    return 0;}static inline void vvfat_close_current_file(BDRVVVFATState *s){    if(s->current_mapping) {	s->current_mapping = NULL;	if (s->current_fd) {		close(s->current_fd);		s->current_fd = 0;	}    }    s->current_cluster = -1;}/* mappings between index1 and index2-1 are supposed to be ordered * return value is the index of the last mapping for which end>cluster_num */static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2){    int index3=index1+1;    while(1) {	mapping_t* mapping;	index3=(index1+index2)/2;	mapping=array_get(&(s->mapping),index3);	assert(mapping->begin < mapping->end);	if(mapping->begin>=cluster_num) {	    assert(index2!=index3 || index2==0);	    if(index2==index3)		return index1;	    index2=index3;	} else {	    if(index1==index3)		return mapping->end<=cluster_num ? index2 : index1;	    index1=index3;	}	assert(index1<=index2);	DLOG(mapping=array_get(&(s->mapping),index1);	assert(mapping->begin<=cluster_num);	assert(index2 >= s->mapping.next || 		((mapping = array_get(&(s->mapping),index2)) &&		mapping->end>cluster_num)));    }}static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num){    int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);    mapping_t* mapping;    if(index>=s->mapping.next)	return 0;    mapping=array_get(&(s->mapping),index);    if(mapping->begin>cluster_num)	return 0;    assert(mapping->begin<=cluster_num && mapping->end>cluster_num);    return mapping;}/* * This function simply compares path == mapping->path. Since the mappings * are sorted by cluster, this is expensive: O(n). */static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,	const char* path){    int i;    for (i = 0; i < s->mapping.next; i++) {	mapping_t* mapping = array_get(&(s->mapping), i);	if (mapping->first_mapping_index < 0 &&		!strcmp(path, mapping->path))	    return mapping;    }    return NULL;}static int open_file(BDRVVVFATState* s,mapping_t* mapping){    if(!mapping)	return -1;    if(!s->current_mapping ||	    strcmp(s->current_mapping->path,mapping->path)) {	/* open file */	int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);	if(fd<0)	    return -1;	vvfat_close_current_file(s);	s->current_fd = fd;	s->current_mapping = mapping;    }    return 0;}static inline int read_cluster(BDRVVVFATState *s,int cluster_num){    if(s->current_cluster != cluster_num) {	int result=0;	off_t offset;	assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));	if(!s->current_mapping		|| s->current_mapping->begin>cluster_num		|| s->current_mapping->end<=cluster_num) {	    /* binary search of mappings for file */	    mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);	    assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));	    if (mapping && mapping->mode & MODE_DIRECTORY) {		vvfat_close_current_file(s);		s->current_mapping = mapping;read_cluster_directory:		offset = s->cluster_size*(cluster_num-s->current_mapping->begin);		s->cluster = s->directory.pointer+offset			+ 0x20*s->current_mapping->info.dir.first_dir_index;		assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);		assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);		s->current_cluster = cluster_num;		return 0;	    }	    if(open_file(s,mapping))		return -2;	} else if (s->current_mapping->mode & MODE_DIRECTORY)	    goto read_cluster_directory;	assert(s->current_fd);	offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;	if(lseek(s->current_fd, offset, SEEK_SET)!=offset)	    return -3;	s->cluster=s->cluster_buffer;	result=read(s->current_fd,s->cluster,s->cluster_size);	if(result<0) {	    s->current_cluster = -1;	    return -1;	}	s->current_cluster = cluster_num;    }    return 0;}#ifdef DEBUGstatic void hexdump(const void* address, uint32_t len){    const unsigned char* p = address;    int i, j;    for (i = 0; i < len; i += 16) {	for (j = 0; j < 16 && i + j < len; j++)	    fprintf(stderr, "%02x ", p[i + j]);	for (; j < 16; j++)	    fprintf(stderr, "   ");	fprintf(stderr, " ");	for (j = 0; j < 16 && i + j < len; j++)	    fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);	fprintf(stderr, "\n");    }}static void print_direntry(const direntry_t* direntry){    int j = 0;    char buffer[1024];    fprintf(stderr, "direntry 0x%x: ", (int)direntry);    if(!direntry)	return;    if(is_long_name(direntry)) {	unsigned char* c=(unsigned char*)direntry;	int i;	for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = '

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -