static int init_directories(BDRVVVFATState* s, const char *dirname, int heads, int secs, Error **errp) { 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=g_malloc(s->cluster_size); /* * 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 */ s->offset_to_fat = s->offset_to_bootsector + 1; s->offset_to_root_dir = s->offset_to_fat + s->sectors_per_fat * 2; 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 */ memcpy(entry->name, s->volume_label, sizeof(entry->name)); } /* Now build FAT, and write back information into directory */ init_fat(s); 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 = g_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++) { /* 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)) { error_setg(errp, "Could not read directory %s", 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); /* next free cluster */ cluster = mapping->end; if(cluster > s->cluster_count) { error_setg(errp, "Directory does not fit in FAT%d (capacity %.2f MB)", s->fat_type, s->sector_count / 2000.0); return -1; } /* fix fat for entry */ if (fix_fat) { int j; 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); } } 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->offset_to_bootsector * 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); /* media descriptor: hard disk=0xf8, floppy=0xf0 */ bootsector->media_type = (s->offset_to_bootsector > 0 ? 0xf8 : 0xf0); 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(secs); bootsector->number_of_heads = cpu_to_le16(heads); bootsector->hidden_sectors = cpu_to_le32(s->offset_to_bootsector); bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0); /* LATER TODO: if FAT32, this is wrong */ /* drive_number: fda=0, hda=0x80 */ bootsector->u.fat16.drive_number = s->offset_to_bootsector == 0 ? 0 : 0x80; bootsector->u.fat16.signature=0x29; bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd); memcpy(bootsector->u.fat16.volume_label, s->volume_label, sizeof(bootsector->u.fat16.volume_label)); memcpy(bootsector->u.fat16.fat_type, s->fat_type == 12 ? "FAT12 " : "FAT16 ", 8); bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa; return 0; }