1
1
/* vim:set shiftwidth=4 ts=8: */
3
3
* QEMU Block driver for virtual VFAT (shadows a local directory)
5
5
* Copyright (c) 2004,2005 Johannes E. Schindelin
7
7
* Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
* of this software and associated documentation files (the "Software"), to deal
9
9
* in the Software without restriction, including without limitation the rights
38
38
/* TODO: add ":bootsector=blabla.img:" */
39
39
/* LATER TODO: add automatic boot sector generation from
40
40
BOOTEASY.ASM and Ranish Partition Manager
41
Note that DOS assumes the system files to be the first files in the
41
Note that DOS assumes the system files to be the first files in the
42
42
file system (test if the boot sector still relies on that fact)! */
43
43
/* MAYBE TODO: write block-visofs.c */
44
44
/* TODO: call try_commit() only after a timeout */
189
static int array_remove(array_t* array,int index)
189
int array_remove(array_t* array,int index)
191
191
return array_remove_slice(array, index, 1);
194
194
/* return the index for a given member */
195
static int array_index(array_t* array, void* pointer)
195
int array_index(array_t* array, void* pointer)
197
197
size_t offset = (char*)pointer - array->pointer;
198
198
assert(offset >= 0);
242
242
uint8_t magic[2];
243
243
} __attribute__((packed)) bootsector_t;
251
245
typedef struct partition_t {
252
246
uint8_t attributes; /* 0x80 = bootable */
254
uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
248
uint8_t start_sector;
249
uint8_t start_cylinder;
250
uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xb = FAT32 */
253
uint8_t end_cylinder;
256
254
uint32_t start_sector_long;
257
uint32_t length_sector_long;
255
uint32_t end_sector_long;
258
256
} __attribute__((packed)) partition_t;
260
258
typedef struct mbr_t {
261
uint8_t ignored[0x1b8];
259
uint8_t ignored[0x1be];
264
260
partition_t partition[4];
265
261
uint8_t magic[2];
266
262
} __attribute__((packed)) mbr_t;
323
319
BlockDriverState* bs; /* pointer to parent */
324
320
unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
325
321
unsigned char first_sectors[0x40*0x200];
327
323
int fat_type; /* 16 or 32 */
328
324
array_t fat,directory,mapping;
330
326
unsigned int cluster_size;
331
327
unsigned int sectors_per_cluster;
332
328
unsigned int sectors_per_fat;
354
350
int downcase_short_names;
355
351
} BDRVVVFATState;
357
/* take the sector position spos and convert it to Cylinder/Head/Sector position
358
* if the position is outside the specified geometry, fill maximum value for CHS
359
* and return 1 to signal overflow.
361
static int sector2CHS(BlockDriverState* bs, mbr_chs_t * chs, int spos){
363
sector = spos % (bs->secs); spos/= bs->secs;
364
head = spos % (bs->heads); spos/= bs->heads;
365
if(spos >= bs->cyls){
367
it happens if 32bit sector positions are used, while CHS is only 24bit.
368
Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
371
chs->cylinder = 0xFF;
374
chs->head = (uint8_t)head;
375
chs->sector = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
376
chs->cylinder = (uint8_t)spos;
380
354
static void init_mbr(BDRVVVFATState* s)
382
356
/* TODO: if the files mbr.img and bootsect.img exist, use them */
383
357
mbr_t* real_mbr=(mbr_t*)s->first_sectors;
384
358
partition_t* partition=&(real_mbr->partition[0]);
387
360
memset(s->first_sectors,0,512);
389
/* Win NT Disk Signature */
390
real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
392
362
partition->attributes=0x80; /* bootable */
394
/* LBA is used when partition is outside the CHS geometry */
395
lba = sector2CHS(s->bs, &partition->start_CHS, s->first_sectors_number-1);
396
lba|= sector2CHS(s->bs, &partition->end_CHS, s->sector_count);
398
/*LBA partitions are identified only by start/length_sector_long not by CHS*/
399
partition->start_sector_long =cpu_to_le32(s->first_sectors_number-1);
400
partition->length_sector_long=cpu_to_le32(s->sector_count - s->first_sectors_number+1);
363
partition->start_head=1;
364
partition->start_sector=1;
365
partition->start_cylinder=0;
402
366
/* FAT12/FAT16/FAT32 */
403
/* DOS uses different types when partition is LBA,
404
probably to prevent older versions from using CHS on them */
405
partition->fs_type= s->fat_type==12 ? 0x1:
406
s->fat_type==16 ? (lba?0xe:0x06):
407
/*fat_tyoe==32*/ (lba?0xc:0x0b);
367
partition->fs_type=(s->fat_type==12?0x1:s->fat_type==16?0x6:0xb);
368
partition->end_head=s->bs->heads-1;
369
partition->end_sector=0xff; /* end sector & upper 2 bits of cylinder */;
370
partition->end_cylinder=0xff; /* lower 8 bits of end cylinder */;
371
partition->start_sector_long=cpu_to_le32(s->bs->secs);
372
partition->end_sector_long=cpu_to_le32(s->sector_count);
409
374
real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
412
377
/* direntry functions */
414
379
/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
415
static inline int short2long_name(char* dest,const char* src)
380
static inline int short2long_name(unsigned char* dest,const char* src)
419
383
for(i=0;i<129 && src[i];i++) {
420
384
dest[2*i]=src[i];
424
387
dest[2*i]=dest[2*i+1]=0;
425
388
for(i=2*i+2;(i%26);i++)
430
393
static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
629
592
entry=array_get_next(&(s->directory));
630
593
memset(entry->name,0x20,11);
631
strncpy((char*)entry->name,filename,i);
594
strncpy(entry->name,filename,i);
634
597
for (i = 0; i < 3 && filename[j+1+i]; i++)
635
598
entry->extension[i] = filename[j+1+i];
712
675
mapping->end = mapping->begin;
716
679
i = mapping->info.dir.first_dir_index =
717
680
first_cluster == 0 ? 0 : s->directory.next;
719
/* actually read the directory, and allocate the mappings */
682
/* actually read the directory, and allocate the mappings */
720
683
while((entry=readdir(dir))) {
721
684
unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
802
765
memset(array_get(&(s->directory), cur), 0,
803
766
(ROOT_ENTRIES - cur) * sizeof(direntry_t));
806
769
/* reget the mapping, since s->mapping was possibly realloc()ed */
807
770
mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
808
771
first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
871
834
direntry_t* entry=array_get_next(&(s->directory));
872
835
entry->attributes=0x28; /* archive | volume label */
873
snprintf((char*)entry->name,11,"QEMU VVFAT");
836
snprintf(entry->name,11,"QEMU VVFAT");
876
839
/* Now build FAT, and write back information into directory */
1012
975
/* LATER TODO: if FAT32, adjust */
976
s->sector_count=0xec04f;
1013
977
s->sectors_per_cluster=0x10;
1015
bs->cyls=1024; bs->heads=16; bs->secs=63;
978
/* LATER TODO: this could be wrong for FAT32 */
979
bs->cyls=1023; bs->heads=15; bs->secs=63;
1017
981
s->current_cluster=0xffffffff;
1023
987
s->qcow_filename = NULL;
1025
989
s->downcase_short_names = 1;
1027
991
if (!strstart(dirname, "fat:", NULL))
994
if (strstr(dirname, ":rw:")) {
995
if (enable_write_target(s))
1030
1000
if (strstr(dirname, ":floppy:")) {
1032
1002
s->fat_type = 12;
1062
1024
dirname += i+1;
1064
1026
bs->total_sectors=bs->cyls*bs->heads*bs->secs;
1027
if (s->sector_count > bs->total_sectors)
1028
s->sector_count = bs->total_sectors;
1066
1029
if(init_directories(s, dirname))
1069
s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
1071
1032
if(s->first_sectors_number==0x40)
1115
1076
assert(index1<=index2);
1116
1077
DLOG(mapping=array_get(&(s->mapping),index1);
1117
1078
assert(mapping->begin<=cluster_num);
1118
assert(index2 >= s->mapping.next ||
1079
assert(index2 >= s->mapping.next ||
1119
1080
((mapping = array_get(&(s->mapping),index2)) &&
1120
1081
mapping->end>cluster_num)));
1189
1150
s->current_mapping = mapping;
1190
1151
read_cluster_directory:
1191
1152
offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
1192
s->cluster = (unsigned char*)s->directory.pointer+offset
1153
s->cluster = s->directory.pointer+offset
1193
1154
+ 0x20*s->current_mapping->info.dir.first_dir_index;
1194
1155
assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1195
1156
assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1281
static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
1242
static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
1282
1243
uint8_t *buf, int nb_sectors)
1284
1245
BDRVVVFATState *s = bs->opaque;
1794
1755
fprintf(stderr, "Error in short name (%d)\n", subret);
1797
if (subret > 0 || !strcmp((char*)lfn.name, ".")
1798
|| !strcmp((char*)lfn.name, ".."))
1758
if (subret > 0 || !strcmp(lfn.name, ".")
1759
|| !strcmp(lfn.name, ".."))
1801
1762
lfn.checksum = 0x100; /* cannot use long name twice */
1804
1765
fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
1807
strcpy(path2 + path_len + 1, (char*)lfn.name);
1768
strcpy(path2 + path_len + 1, lfn.name);
1809
1770
if (is_directory(direntries + i)) {
1810
1771
if (begin_of_direntry(direntries + i) == 0) {
2090
2051
next_mapping->dir_index = mapping->dir_index;
2091
next_mapping->first_mapping_index =
2052
next_mapping->first_mapping_index =
2092
2053
mapping->first_mapping_index < 0 ?
2093
2054
array_index(&(s->mapping), mapping) :
2094
2055
mapping->first_mapping_index;
2636
2597
return do_commit(s);
2639
static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
2600
static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
2640
2601
const uint8_t *buf, int nb_sectors)
2642
BDRVVVFATState *s = bs->opaque;
2603
BDRVVVFATState *s = bs->opaque;
2645
2606
DLOG(checkpoint());