- more fixes for configurable disk geometry

- check the root entries limit of FAT16
- some work on the FAT32 support (not yet complete)
- report volume creation date and time
- some other small fixes
This commit is contained in:
Volker Ruppert 2010-12-26 23:13:29 +00:00
parent fd5558d4be
commit a8ced63e31
2 changed files with 107 additions and 59 deletions

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: vvfat.cc,v 1.2 2010-12-24 20:47:22 vruppert Exp $
// $Id: vvfat.cc,v 1.3 2010-12-26 23:13:29 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2010 The Bochs Project
@ -24,7 +24,7 @@
// ADDITIONS:
// - win32 specific directory functions (required for MSVC)
// - configurable disk geometry (not yet complete)
// - configurable disk geometry
// TODO:
// - write support
@ -213,10 +213,12 @@ typedef
#endif
struct {
Bit8u drive_number;
Bit8u current_head;
Bit8u reserved;
Bit8u signature;
Bit32u id;
Bit8u volume_label[11];
Bit8u fat_type[8];
Bit8u ignored[0x1c0];
}
#if !defined(_MSC_VER)
GCC_ATTRIBUTE((packed))
@ -229,18 +231,23 @@ typedef
Bit32u sectors_per_fat;
Bit16u flags;
Bit8u major, minor;
Bit32u first_cluster_of_root_directory;
Bit32u first_cluster_of_root_dir;
Bit16u info_sector;
Bit16u backup_boot_sector;
Bit16u ignored;
Bit8u reserved1[12];
Bit8u drive_number;
Bit8u reserved2;
Bit8u signature;
Bit32u id;
Bit8u volume_label[11];
Bit8u fat_type[8];
Bit8u ignored[0x1a4];
}
#if !defined(_MSC_VER)
GCC_ATTRIBUTE((packed))
#endif
fat32;
} u;
Bit8u fat_type[8];
Bit8u ignored[0x1c0];
Bit8u magic[2];
}
#if !defined(_MSC_VER)
@ -334,12 +341,12 @@ void vvfat_image_t::init_mbr(void)
partition->attributes = 0x80; // bootable
// LBA is used when partition is outside the CHS geometry
lba = sector2CHS(n_first_sectors - 1, &partition->start_CHS);
lba = sector2CHS(offset_to_bootsector, &partition->start_CHS);
lba |= sector2CHS(sector_count, &partition->end_CHS);
// LBA partitions are identified only by start/length_sector_long not by CHS
partition->start_sector_long = htod32(n_first_sectors - 1);
partition->length_sector_long = htod32(sector_count - n_first_sectors + 1);
partition->start_sector_long = htod32(offset_to_bootsector);
partition->length_sector_long = htod32(sector_count - offset_to_bootsector);
/* FAT12/FAT16/FAT32 */
/* DOS uses different types when partition is LBA,
@ -590,6 +597,7 @@ int vvfat_image_t::read_directory(int mapping_index)
mapping_t* parent_mapping = (mapping_t*)
(parent_index >= 0 ? array_get(&this->mapping, parent_index) : NULL);
int first_cluster_of_parent = parent_mapping ? (int)parent_mapping->begin : -1;
int count = 0;
#ifndef WIN32
DIR* dir = opendir(dirname);
@ -608,6 +616,10 @@ int vvfat_image_t::read_directory(int mapping_index)
// actually read the directory, and allocate the mappings
while ((entry=readdir(dir))) {
if ((first_cluster == 0) && (directory.next >= (Bit16u)(root_entries - 1))) {
BX_ERROR(("Too many entries in root directory, using only %d", count));
break;
}
unsigned int length = strlen(dirname) + 2 + strlen(entry->d_name);
char* buffer;
direntry_t* direntry;
@ -631,6 +643,8 @@ int vvfat_image_t::read_directory(int mapping_index)
free(buffer);
continue;
}
count++;
// create directory entry for this file
direntry = create_short_and_long_name(i, entry->d_name, is_dot || is_dotdot);
direntry->attributes = (S_ISDIR(st.st_mode) ? 0x10 : 0x20);
@ -698,6 +712,10 @@ int vvfat_image_t::read_directory(int mapping_index)
// actually read the directory, and allocate the mappings
do {
if ((first_cluster == 0) && (directory.next >= (Bit16u)(root_entries - 1))) {
BX_ERROR(("Too many entries in root directory, using only %d", count));
break;
}
unsigned int length = lstrlen(dirname) + 2 + lstrlen(finddata.cFileName);
char* buffer;
direntry_t* direntry;
@ -713,6 +731,7 @@ int vvfat_image_t::read_directory(int mapping_index)
buffer = (char*)malloc(length);
snprintf(buffer, length, "%s/%s", dirname, finddata.cFileName);
count++;
// create directory entry for this file
direntry = create_short_and_long_name(i, finddata.cFileName, is_dot || is_dotdot);
direntry->attributes = ((finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 0x10 : 0x20);
@ -768,20 +787,24 @@ int vvfat_image_t::read_directory(int mapping_index)
memset(direntry, 0, sizeof(direntry_t));
}
// TODO: if there are more entries, bootsector has to be adjusted!
#define ROOT_ENTRIES (0x02 * 0x10 * sectors_per_cluster)
if ((mapping_index == 0) && (directory.next < (unsigned int)ROOT_ENTRIES)) {
// root directory
int cur = directory.next;
array_ensure_allocated(&directory, ROOT_ENTRIES - 1);
memset(array_get(&directory, cur), 0,
(ROOT_ENTRIES - cur) * sizeof(direntry_t));
if (fat_type != 32) {
if ((mapping_index == 0) && (directory.next < root_entries)) {
// root directory
int cur = directory.next;
array_ensure_allocated(&directory, root_entries - 1);
memset(array_get(&directory, cur), 0,
(root_entries - cur) * sizeof(direntry_t));
}
}
// reget the mapping, since s->mapping was possibly realloc()ed
mapping = (mapping_t*)array_get(&this->mapping, mapping_index);
first_cluster += (directory.next - mapping->info.dir.first_dir_index)
* 0x20 / cluster_size;
if (first_cluster == 0) {
first_cluster = 2;
} else {
first_cluster += (directory.next - mapping->info.dir.first_dir_index)
* 0x20 / cluster_size;
}
mapping->end = first_cluster;
direntry = (direntry_t*)array_get(&directory, mapping->dir_index);
@ -792,7 +815,7 @@ int vvfat_image_t::read_directory(int mapping_index)
Bit32u vvfat_image_t::sector2cluster(off_t sector_num)
{
return (Bit32u)(sector_num - faked_sectors) / sectors_per_cluster;
return (Bit32u)(sector_num - offset_to_root_dir) / sectors_per_cluster;
}
int vvfat_image_t::init_directories(const char* dirname)
@ -825,6 +848,8 @@ int vvfat_image_t::init_directories(const char* dirname)
{
direntry_t *entry = (direntry_t*)array_get_next(&directory);
entry->attributes = 0x28; // archive | volume label
entry->mdate = 0x3d81; // 01.12.2010
entry->mtime = 0x6000; // 12:00:00
memcpy(entry->name, "BOCHS VV", 8);
memcpy(entry->extension, "FAT", 3);
}
@ -832,7 +857,7 @@ int vvfat_image_t::init_directories(const char* dirname)
// Now build FAT, and write back information into directory
init_fat();
faked_sectors = n_first_sectors + sectors_per_fat * 2;
offset_to_root_dir = offset_to_bootsector + sectors_per_fat * 2 + 1;
cluster_count = sector2cluster(sector_count);
mapping = (mapping_t*)array_get_next(&this->mapping);
@ -883,7 +908,7 @@ int vvfat_image_t::init_directories(const char* dirname)
cluster = mapping->end;
if (cluster > cluster_count) {
sprintf(size_txt, "%dMB", sector_count * 512);
sprintf(size_txt, "%dMB", (sector_count >> 11));
BX_ERROR(("Directory does not fit in FAT%d (capacity %s)",
fat_type,
(fat_type == 12) ? (sector_count == 2880) ? "1.44 MB":"2.88 MB"
@ -901,8 +926,12 @@ int vvfat_image_t::init_directories(const char* dirname)
}
mapping = (mapping_t*)array_get(&this->mapping, 0);
sectors_of_root_directory = mapping->end * sectors_per_cluster;
last_cluster_of_root_directory = mapping->end;
assert((fat_type == 32) || (mapping->end == 2));
if (fat_type != 32) {
offset_to_data = offset_to_root_dir + root_entries / 16;
} else {
offset_to_data = offset_to_root_dir;
}
// the FAT signature
fat_set(0, max_fat_value);
@ -910,7 +939,7 @@ int vvfat_image_t::init_directories(const char* dirname)
current_mapping = NULL;
bootsector = (bootsector_t*)(first_sectors+(n_first_sectors - 1) * 0x200);
bootsector = (bootsector_t*)(first_sectors + offset_to_bootsector * 0x200);
bootsector->jump[0] = 0xeb;
bootsector->jump[1] = 0x3e;
bootsector->jump[2] = 0x90;
@ -919,24 +948,36 @@ int vvfat_image_t::init_directories(const char* dirname)
bootsector->sectors_per_cluster = sectors_per_cluster;
bootsector->reserved_sectors = htod16(1);
bootsector->number_of_fats = 0x2;
bootsector->root_entries = htod16(sectors_of_root_directory * 0x10);
if (fat_type != 32) {
bootsector->root_entries = htod16(root_entries);
}
bootsector->total_sectors16 = (sector_count > 0xffff) ? 0:htod16(sector_count);
bootsector->media_type = ((fat_type != 12) ? 0xf8:(sector_count==5760) ? 0xf9:0xf8);
bootsector->media_type = ((fat_type != 12) ? 0xf8:0xf0);
fat.pointer[0] = bootsector->media_type;
bootsector->sectors_per_fat = htod16(sectors_per_fat);
if (fat_type != 32) {
bootsector->sectors_per_fat = htod16(sectors_per_fat);
}
bootsector->sectors_per_track = htod16(sectors);
bootsector->number_of_heads = htod16(heads);
bootsector->hidden_sectors = htod32(n_first_sectors - 1);
bootsector->hidden_sectors = htod32(offset_to_bootsector);
bootsector->total_sectors = htod32((sector_count > 0xffff) ? sector_count:0);
// LATER TODO: if FAT32, this is wrong
bootsector->u.fat16.drive_number = (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 = htod32(0xfabe1afd);
if (fat_type != 32) {
bootsector->u.fat16.drive_number = (fat_type == 12) ? 0:0x80; // assume this is hda (TODO)
bootsector->u.fat16.signature = 0x29;
bootsector->u.fat16.id = htod32(0xfabe1afd);
memcpy(bootsector->u.fat16.volume_label, "BOCHS VVFAT", 11);
memcpy(bootsector->u.fat16.fat_type, (fat_type==12) ? "FAT12 ":"FAT16 ", 8);
} else {
bootsector->u.fat32.sectors_per_fat = htod32(sectors_per_fat);
bootsector->u.fat32.first_cluster_of_root_dir = first_cluster_of_root_dir;
bootsector->u.fat32.backup_boot_sector = 6;
bootsector->u.fat32.drive_number = 0x80; // assume this is hda (TODO)
bootsector->u.fat32.signature = 0x29;
bootsector->u.fat32.id = htod32(0xfabe1afd);
memcpy(bootsector->u.fat32.fat_type, "FAT32 ", 8);
}
memcpy(bootsector->u.fat16.volume_label, "BOCHS VVFAT", 11);
memcpy(bootsector->fat_type, ((fat_type==12) ? "FAT12 ":(fat_type==16) ? "FAT16 ":"FAT32 "), 8);
bootsector->magic[0] = 0x55;
bootsector->magic[1] = 0xaa;
@ -953,13 +994,15 @@ int vvfat_image_t::open(const char* dirname)
heads = 16;
sectors = 63;
}
n_first_sectors = sectors + 1;
offset_to_bootsector = sectors;
sector_count = cylinders * heads * sectors;
hd_size = sector_count * 512;
size_in_mb = (Bit32u)(hd_size >> 20);
if (size_in_mb >= 2047) {
fat_type = 32;
sectors_per_cluster = 8;
first_cluster_of_root_dir = 2;
root_entries = 0;
BX_PANIC(("FAT32 required, but not supported yet"));
} else {
fat_type = 16;
@ -972,15 +1015,17 @@ int vvfat_image_t::open(const char* dirname)
} else {
sectors_per_cluster = 8;
}
first_cluster_of_root_dir = 0;
root_entries = 512;
}
current_cluster = 0xffff;
init_directories(dirname);
sector_count = faked_sectors + sectors_per_cluster * cluster_count;
sector_count = offset_to_root_dir + sectors_per_cluster * cluster_count;
if (n_first_sectors > 1)
if (offset_to_bootsector > 0)
init_mbr();
return 0;
@ -1140,19 +1185,21 @@ ssize_t vvfat_image_t::read(void* buf, size_t count)
Bit32u scount = (Bit32u)(count / 512);
while (scount-- > 0) {
if (sector_num < faked_sectors) {
if (sector_num < n_first_sectors)
memcpy(buf, &first_sectors[sector_num * 0x200], 0x200);
else if (sector_num - n_first_sectors < sectors_per_fat)
memcpy(buf, &fat.pointer[(sector_num - n_first_sectors) * 0x200], 0x200);
else if ((sector_num - n_first_sectors - sectors_per_fat) < sectors_per_fat)
memcpy(buf, &fat.pointer[(sector_num - n_first_sectors - sectors_per_fat) * 0x200], 0x200);
if (sector_num < offset_to_data) {
if (sector_num < (offset_to_bootsector + 1))
memcpy(cbuf, &first_sectors[sector_num * 0x200], 0x200);
else if ((sector_num - offset_to_bootsector - 1) < sectors_per_fat)
memcpy(cbuf, &fat.pointer[(sector_num - offset_to_bootsector - 1) * 0x200], 0x200);
else if ((sector_num - offset_to_bootsector - sectors_per_fat - 1) < sectors_per_fat)
memcpy(cbuf, &fat.pointer[(sector_num - offset_to_bootsector - sectors_per_fat - 1) * 0x200], 0x200);
else
memcpy(cbuf, &directory.pointer[(sector_num - offset_to_root_dir) * 0x200], 0x200);
} else {
Bit32u sector = sector_num - faked_sectors,
Bit32u sector = sector_num - offset_to_data,
sector_offset_in_cluster = (sector % sectors_per_cluster),
cluster_num = sector / sectors_per_cluster;
cluster_num = sector / sectors_per_cluster + 2;
if (read_cluster(cluster_num) != 0) {
memset(buf, 0, 0x200);
memset(cbuf, 0, 0x200);
} else {
memcpy(cbuf, cluster + sector_offset_in_cluster * 0x200, 0x200);
}
@ -1168,7 +1215,7 @@ ssize_t vvfat_image_t::write(const void* buf, size_t count)
{
Bit32u scount = (Bit32u)(count / 512);
if (sector_num < n_first_sectors)
if (sector_num < (offset_to_bootsector + 1))
return -1;
BX_ERROR(("VVFAT write not supported yet: sector=%d, count=%d", sector_num, scount));

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: vvfat.h,v 1.1 2010-12-23 16:17:12 vruppert Exp $
// $Id: vvfat.h,v 1.2 2010-12-26 23:13:29 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2010 The Bochs Project
@ -136,21 +136,22 @@ class vvfat_image_t : public device_image_t
mapping_t* find_mapping_for_cluster(int cluster_num);
int read_cluster(int cluster_num);
Bit32u n_first_sectors;
Bit8u *first_sectors;
Bit8u fat_type;
array_t fat, directory, mapping;
Bit32u offset_to_bootsector;
Bit32u offset_to_root_dir;
Bit32u offset_to_data;
Bit16u cluster_size;
Bit8u sectors_per_cluster;
Bit8u sectors_per_fat;
Bit16u sectors_of_root_directory;
Bit32u last_cluster_of_root_directory;
Bit16u faked_sectors; // how many sectors are faked before file data
Bit32u sector_count;
Bit32u cluster_count; // total number of clusters of this partition
Bit32u max_fat_value;
Bit32u first_cluster_of_root_dir;
Bit16u root_entries;
Bit8u fat_type;
array_t fat, directory, mapping;
int current_fd;
mapping_t* current_mapping;