#endif
/* dynamic array functions */
-typedef struct array {
+typedef struct array_t {
char* pointer;
unsigned int size,next,item_size;
-} an_array;
+} array_t;
-static inline void array_init(an_array* array,unsigned int item_size)
+static inline void array_init(array_t* array,unsigned int item_size)
{
array->pointer = NULL;
array->size=0;
array->item_size=item_size;
}
-static inline void array_free(an_array* array)
+static inline void array_free(array_t* array)
{
if(array->pointer)
free(array->pointer);
}
/* does not automatically grow */
-static inline void* array_get(an_array* array,unsigned int index) {
+static inline void* array_get(array_t* array,unsigned int index) {
assert(index < array->next);
return array->pointer + index * array->item_size;
}
-static inline int array_ensure_allocated(an_array* array, int index)
+static inline int array_ensure_allocated(array_t* array, int index)
{
if((index + 1) * array->item_size > array->size) {
int new_size = (index + 32) * array->item_size;
return 0;
}
-static inline void* array_get_next(an_array* array) {
+static inline void* array_get_next(array_t* array) {
unsigned int next = array->next;
void* result;
return result;
}
-static inline void* array_insert(an_array* array,unsigned int index,unsigned int count) {
+static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
if((array->next+count)*array->item_size>array->size) {
int increment=count*array->item_size;
array->pointer=qemu_realloc(array->pointer,array->size+increment);
/* this performs a "roll", so that the element which was at index_from becomes
* index_to, but the order of all other elements is preserved. */
-static inline int array_roll(an_array* array,int index_to,int index_from,int count)
+static inline int array_roll(array_t* array,int index_to,int index_from,int count)
{
char* buf;
char* from;
return 0;
}
-static inline int array_remove_slice(an_array* array,int index, int count)
+static inline int array_remove_slice(array_t* array,int index, int count)
{
assert(index >=0);
assert(count > 0);
return 0;
}
-static int array_remove(an_array* array,int index)
+static int array_remove(array_t* array,int index)
{
return array_remove_slice(array, index, 1);
}
/* return the index for a given member */
-static int array_index(an_array* array, void* pointer)
+static int array_index(array_t* array, void* pointer)
{
size_t offset = (char*)pointer - array->pointer;
assert((offset % array->item_size) == 0);
/* These structures are used to fake a disk and the VFAT filesystem.
* For this reason we need to use __attribute__((packed)). */
-typedef struct bootsector {
+typedef struct bootsector_t {
uint8_t jump[3];
uint8_t name[8];
uint16_t sector_size;
uint8_t fat_type[8];
uint8_t ignored[0x1c0];
uint8_t magic[2];
-} __attribute__((packed)) a_bootsector;
+} __attribute__((packed)) bootsector_t;
typedef struct {
uint8_t head;
uint8_t sector;
uint8_t cylinder;
-} a_mbr_chs;
+} mbr_chs_t;
-typedef struct partition {
+typedef struct partition_t {
uint8_t attributes; /* 0x80 = bootable */
- a_mbr_chs start_CHS;
+ mbr_chs_t start_CHS;
uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
- a_mbr_chs end_CHS;
+ mbr_chs_t end_CHS;
uint32_t start_sector_long;
uint32_t length_sector_long;
-} __attribute__((packed)) a_partition;
+} __attribute__((packed)) partition_t;
-typedef struct mbr {
+typedef struct mbr_t {
uint8_t ignored[0x1b8];
uint32_t nt_id;
uint8_t ignored2[2];
- a_partition partition[4];
+ partition_t partition[4];
uint8_t magic[2];
-} __attribute__((packed)) a_mbr;
+} __attribute__((packed)) mbr_t;
-typedef struct direntry {
+typedef struct direntry_t {
uint8_t name[8];
uint8_t extension[3];
uint8_t attributes;
uint16_t mdate;
uint16_t begin;
uint32_t size;
-} __attribute__((packed)) a_direntry;
+} __attribute__((packed)) direntry_t;
/* this structure are used to transparently access the files */
-typedef struct mapping {
+typedef struct mapping_t {
/* begin is the first cluster, end is the last+1 */
uint32_t begin,end;
/* as s->directory is growable, no pointer may be used here */
MODE_DIRECTORY = 4, MODE_FAKED = 8,
MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
int read_only;
-} a_mapping;
+} mapping_t;
#ifdef DEBUG
-static void print_direntry(const struct a_direntry*);
-static void print_mapping(const struct a_mapping* mapping);
+static void print_direntry(const struct direntry_t*);
+static void print_mapping(const struct mapping_t* mapping);
#endif
/* here begins the real VVFAT driver */
unsigned char first_sectors[0x40*0x200];
int fat_type; /* 16 or 32 */
- an_array fat,directory,mapping;
+ array_t fat,directory,mapping;
unsigned int cluster_size;
unsigned int sectors_per_cluster;
uint32_t max_fat_value;
int current_fd;
- a_mapping* current_mapping;
+ mapping_t* current_mapping;
unsigned char* cluster; /* points to current cluster */
unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
unsigned int current_cluster;
BlockDriverState* qcow;
void* fat2;
char* used_clusters;
- an_array commits;
+ array_t commits;
const char* path;
int downcase_short_names;
} BDRVVVFATState;
* if the position is outside the specified geometry, fill maximum value for CHS
* and return 1 to signal overflow.
*/
-static int sector2CHS(BlockDriverState* bs, a_mbr_chs * chs, int spos){
+static int sector2CHS(BlockDriverState* bs, mbr_chs_t * chs, int spos){
int head,sector;
sector = spos % (bs->secs); spos/= bs->secs;
head = spos % (bs->heads); spos/= bs->heads;
static void init_mbr(BDRVVVFATState* s)
{
/* TODO: if the files mbr.img and bootsect.img exist, use them */
- a_mbr* real_mbr=(a_mbr*)s->first_sectors;
- a_partition* partition = &(real_mbr->partition[0]);
+ mbr_t* real_mbr=(mbr_t*)s->first_sectors;
+ partition_t* partition = &(real_mbr->partition[0]);
int lba;
memset(s->first_sectors,0,512);
return len;
}
-static inline a_direntry* create_long_filename(BDRVVVFATState* s,const char* filename)
+static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
{
char buffer[258];
int length=short2long_name(buffer,filename),
number_of_entries=(length+25)/26,i;
- a_direntry* entry;
+ direntry_t* entry;
for(i=0;i<number_of_entries;i++) {
entry=array_get_next(&(s->directory));
return array_get(&(s->directory),s->directory.next-number_of_entries);
}
-static char is_free(const a_direntry* direntry)
+static char is_free(const direntry_t* direntry)
{
return direntry->name[0]==0xe5 || direntry->name[0]==0x00;
}
-static char is_volume_label(const a_direntry* direntry)
+static char is_volume_label(const direntry_t* direntry)
{
return direntry->attributes == 0x28;
}
-static char is_long_name(const a_direntry* direntry)
+static char is_long_name(const direntry_t* direntry)
{
return direntry->attributes == 0xf;
}
-static char is_short_name(const a_direntry* direntry)
+static char is_short_name(const direntry_t* direntry)
{
return !is_volume_label(direntry) && !is_long_name(direntry)
&& !is_free(direntry);
}
-static char is_directory(const a_direntry* direntry)
+static char is_directory(const direntry_t* direntry)
{
return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
}
-static inline char is_dot(const a_direntry* direntry)
+static inline char is_dot(const direntry_t* direntry)
{
return is_short_name(direntry) && direntry->name[0] == '.';
}
-static char is_file(const a_direntry* direntry)
+static char is_file(const direntry_t* direntry)
{
return is_short_name(direntry) && !is_directory(direntry);
}
-static inline uint32_t begin_of_direntry(const a_direntry* direntry)
+static inline uint32_t begin_of_direntry(const direntry_t* direntry)
{
return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
}
-static inline uint32_t filesize_of_direntry(const a_direntry* direntry)
+static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
{
return le32_to_cpu(direntry->size);
}
-static void set_begin_of_direntry(a_direntry* direntry, uint32_t begin)
+static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
{
direntry->begin = cpu_to_le16(begin & 0xffff);
direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
/* fat functions */
-static inline uint8_t fat_chksum(const a_direntry* entry)
+static inline uint8_t fat_chksum(const direntry_t* entry)
{
uint8_t chksum=0;
int i;
for(i=0;i<11;i++) {
unsigned char c;
- c = (i <= 8) ? entry->name[i] : entry->extension[i-8];
+ c = (i < 8) ? entry->name[i] : entry->extension[i-8];
chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0)) + c;
}
/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
/* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
-static inline a_direntry* create_short_and_long_name(BDRVVVFATState* s,
+static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
unsigned int directory_start, const char* filename, int is_dot)
{
int i,j,long_index=s->directory.next;
- a_direntry* entry = NULL;
- a_direntry* entry_long = NULL;
+ direntry_t* entry = NULL;
+ direntry_t* entry_long = NULL;
if(is_dot) {
entry=array_get_next(&(s->directory));
/* mangle duplicates */
while(1) {
- a_direntry* entry1=array_get(&(s->directory),directory_start);
+ direntry_t* entry1=array_get(&(s->directory),directory_start);
int j;
for(;entry1<entry;entry1++)
*/
static int read_directory(BDRVVVFATState* s, int mapping_index)
{
- a_mapping* mapping = array_get(&(s->mapping), mapping_index);
- a_direntry* direntry;
+ mapping_t* mapping = array_get(&(s->mapping), mapping_index);
+ direntry_t* direntry;
const char* dirname = mapping->path;
int first_cluster = mapping->begin;
int parent_index = mapping->info.dir.parent_mapping_index;
- a_mapping* parent_mapping = (a_mapping*)
+ mapping_t* parent_mapping = (mapping_t*)
(parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL);
int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
while((entry=readdir(dir))) {
unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
char* buffer;
- a_direntry* direntry;
+ direntry_t* direntry;
struct stat st;
int is_dot=!strcmp(entry->d_name,".");
int is_dotdot=!strcmp(entry->d_name,"..");
if (st.st_size > 0x7fffffff) {
fprintf(stderr, "File %s is larger than 2GB\n", buffer);
free(buffer);
+ closedir(dir);
return -2;
}
direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
/* create mapping for this file */
if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
- s->current_mapping=(a_mapping*)array_get_next(&(s->mapping));
+ s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
s->current_mapping->begin=0;
s->current_mapping->end=st.st_size;
/*
/* fill with zeroes up to the end of the cluster */
while(s->directory.next%(0x10*s->sectors_per_cluster)) {
- a_direntry* direntry=array_get_next(&(s->directory));
- memset(direntry,0,sizeof(a_direntry));
+ direntry_t* direntry=array_get_next(&(s->directory));
+ memset(direntry,0,sizeof(direntry_t));
}
/* TODO: if there are more entries, bootsector has to be adjusted! */
int cur = s->directory.next;
array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
memset(array_get(&(s->directory), cur), 0,
- (ROOT_ENTRIES - cur) * sizeof(a_direntry));
+ (ROOT_ENTRIES - cur) * sizeof(direntry_t));
}
/* reget the mapping, since s->mapping was possibly realloc()ed */
- mapping = (a_mapping*)array_get(&(s->mapping), mapping_index);
+ mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
* 0x20 / s->cluster_size;
mapping->end = first_cluster;
- direntry = (a_direntry*)array_get(&(s->directory), mapping->dir_index);
+ direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
set_begin_of_direntry(direntry, mapping->begin);
return 0;
}
#ifdef DBG
-static a_direntry* get_direntry_for_mapping(BDRVVVFATState* s,a_mapping* mapping)
+static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
{
if(mapping->mode==MODE_UNDEFINED)
return 0;
- return (a_direntry*)(s->directory.pointer+sizeof(a_direntry)*mapping->dir_index);
+ return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
}
#endif
static int init_directories(BDRVVVFATState* s,
const char* dirname)
{
- a_bootsector* bootsector;
- a_mapping* mapping;
+ bootsector_t* bootsector;
+ mapping_t* mapping;
unsigned int i;
unsigned int cluster;
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(a_mapping));
- array_init(&(s->directory),sizeof(a_direntry));
+ array_init(&(s->mapping),sizeof(mapping_t));
+ array_init(&(s->directory),sizeof(direntry_t));
/* add volume label */
{
- a_direntry* entry=array_get_next(&(s->directory));
+ direntry_t* entry=array_get_next(&(s->directory));
entry->attributes=0x28; /* archive | volume label */
- snprintf((char*)entry->name,11,"QEMU VVFAT");
+ memcpy(entry->name,"QEMU VVF",8);
+ memcpy(entry->extension,"AT ",3);
}
/* Now build FAT, and write back information into directory */
mapping->dir_index = 0;
mapping->info.dir.parent_mapping_index = -1;
mapping->first_mapping_index = -1;
- mapping->path = strdup(dirname);
+ mapping->path = qemu_strdup(dirname);
i = strlen(mapping->path);
if (i > 0 && mapping->path[i - 1] == '/')
mapping->path[i - 1] = '\0';
mapping->mode=MODE_NORMAL;
mapping->begin = cluster;
if (mapping->end > 0) {
- a_direntry* direntry = array_get(&(s->directory),
+ direntry_t* direntry = array_get(&(s->directory),
mapping->dir_index);
mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
s->current_mapping = NULL;
- bootsector=(a_bootsector*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
+ bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
bootsector->jump[0]=0xeb;
bootsector->jump[1]=0x3e;
bootsector->jump[2]=0x90;
*/
static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
{
- int index3=index1+1;
while(1) {
- a_mapping* mapping;
+ int index3;
+ mapping_t* mapping;
index3=(index1+index2)/2;
mapping=array_get(&(s->mapping),index3);
assert(mapping->begin < mapping->end);
}
}
-static inline a_mapping* find_mapping_for_cluster(BDRVVVFATState* s,int 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);
- a_mapping* mapping;
+ mapping_t* mapping;
if(index>=s->mapping.next)
return NULL;
mapping=array_get(&(s->mapping),index);
* This function simply compares path == mapping->path. Since the mappings
* are sorted by cluster, this is expensive: O(n).
*/
-static inline a_mapping* find_mapping_for_path(BDRVVVFATState* s,
+static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
const char* path)
{
int i;
for (i = 0; i < s->mapping.next; i++) {
- a_mapping* mapping = array_get(&(s->mapping), 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,a_mapping* mapping)
+static int open_file(BDRVVVFATState* s,mapping_t* mapping)
{
if(!mapping)
return -1;
|| s->current_mapping->begin>cluster_num
|| s->current_mapping->end<=cluster_num) {
/* binary search of mappings for file */
- a_mapping* mapping=find_mapping_for_cluster(s,cluster_num);
+ mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
}
}
-static void print_direntry(const a_direntry* direntry)
+static void print_direntry(const direntry_t* direntry)
{
int j = 0;
char buffer[1024];
- fprintf(stderr, "direntry 0x%x: ", (int)direntry);
+ fprintf(stderr, "direntry %p: ", direntry);
if(!direntry)
return;
if(is_long_name(direntry)) {
}
}
-static void print_mapping(const a_mapping* mapping)
+static void print_mapping(const mapping_t* mapping)
{
- fprintf(stderr, "mapping (0x%x): begin, end = %d, %d, dir_index = %d, first_mapping_index = %d, name = %s, mode = 0x%x, " , (int)mapping, mapping->begin, mapping->end, mapping->dir_index, mapping->first_mapping_index, mapping->path, mapping->mode);
+ fprintf(stderr, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
+ "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
+ mapping, mapping->begin, mapping->end, mapping->dir_index,
+ mapping->first_mapping_index, mapping->path, mapping->mode);
+
if (mapping->mode & MODE_DIRECTORY)
fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
else
*
*/
-typedef struct commit {
+typedef struct commit_t {
char* path;
union {
struct { uint32_t cluster; } rename;
enum {
ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
} action;
-} a_commit;
+} commit_t;
static void clear_commits(BDRVVVFATState* s)
{
int i;
DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
for (i = 0; i < s->commits.next; i++) {
- a_commit* commit = array_get(&(s->commits), i);
+ commit_t* commit = array_get(&(s->commits), i);
assert(commit->path || commit->action == ACTION_WRITEOUT);
if (commit->action != ACTION_WRITEOUT) {
assert(commit->path);
static void schedule_rename(BDRVVVFATState* s,
uint32_t cluster, char* new_path)
{
- a_commit* commit = array_get_next(&(s->commits));
+ commit_t* commit = array_get_next(&(s->commits));
commit->path = new_path;
commit->param.rename.cluster = cluster;
commit->action = ACTION_RENAME;
static void schedule_writeout(BDRVVVFATState* s,
int dir_index, uint32_t modified_offset)
{
- a_commit* commit = array_get_next(&(s->commits));
+ commit_t* commit = array_get_next(&(s->commits));
commit->path = NULL;
commit->param.writeout.dir_index = dir_index;
commit->param.writeout.modified_offset = modified_offset;
static void schedule_new_file(BDRVVVFATState* s,
char* path, uint32_t first_cluster)
{
- a_commit* commit = array_get_next(&(s->commits));
+ commit_t* commit = array_get_next(&(s->commits));
commit->path = path;
commit->param.new_file.first_cluster = first_cluster;
commit->action = ACTION_NEW_FILE;
static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
{
- a_commit* commit = array_get_next(&(s->commits));
+ commit_t* commit = array_get_next(&(s->commits));
commit->path = path;
commit->param.mkdir.cluster = cluster;
commit->action = ACTION_MKDIR;
/* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
static int parse_long_name(long_file_name* lfn,
- const a_direntry* direntry)
+ const direntry_t* direntry)
{
int i, j, offset;
const unsigned char* pointer = (const unsigned char*)direntry;
/* returns 0 if successful, >0 if no short_name, and <0 on error */
static int parse_short_name(BDRVVVFATState* s,
- long_file_name* lfn, a_direntry* direntry)
+ long_file_name* lfn, direntry_t* direntry)
{
int i, j;
*/
typedef enum {
USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
-} e_used;
+} used_t;
/*
* get_cluster_count_for_direntry() not only determines how many clusters
* assumed to be *not* deleted (and *only* those).
*/
static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
- a_direntry* direntry, const char* path)
+ direntry_t* direntry, const char* path)
{
/*
* This is a little bit tricky:
uint32_t cluster_num = begin_of_direntry(direntry);
uint32_t offset = 0;
int first_mapping_index = -1;
- a_mapping* mapping = NULL;
+ mapping_t* mapping = NULL;
const char* basename2 = NULL;
vvfat_close_current_file(s);
/* rename */
if (strcmp(basename, basename2))
- schedule_rename(s, cluster_num, strdup(path));
+ schedule_rename(s, cluster_num, qemu_strdup(path));
} else if (is_file(direntry))
/* new file */
- schedule_new_file(s, strdup(path), cluster_num);
+ schedule_new_file(s, qemu_strdup(path), cluster_num);
else {
- assert(0);
+ abort();
return 0;
}
}
if (offset != mapping->info.file.offset + s->cluster_size
* (cluster_num - mapping->begin)) {
/* offset of this cluster in file chain has changed */
- assert(0);
+ abort();
copy_it = 1;
} else if (offset == 0) {
const char* basename = get_basename(mapping->path);
if (mapping->first_mapping_index != first_mapping_index
&& mapping->info.file.offset > 0) {
- assert(0);
+ abort();
copy_it = 1;
}
{
int ret = 0;
unsigned char* cluster = qemu_malloc(s->cluster_size);
- a_direntry* direntries = (a_direntry*)cluster;
- a_mapping* mapping = find_mapping_for_cluster(s, cluster_num);
+ direntry_t* direntries = (direntry_t*)cluster;
+ mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
long_file_name lfn;
int path_len = strlen(path);
mapping->mode &= ~MODE_DELETED;
if (strcmp(basename, basename2))
- schedule_rename(s, cluster_num, strdup(path));
+ schedule_rename(s, cluster_num, qemu_strdup(path));
} else
/* new directory */
- schedule_mkdir(s, cluster_num, strdup(path));
+ schedule_mkdir(s, cluster_num, qemu_strdup(path));
lfn_init(&lfn);
do {
goto fail;
}
} else
- assert(0); /* cluster_count = 0; */
+ abort(); /* cluster_count = 0; */
ret += cluster_count;
}
* (check_directory_consistency() will unmark those still present). */
if (s->qcow)
for (i = 0; i < s->mapping.next; i++) {
- a_mapping* mapping = array_get(&(s->mapping), i);
+ mapping_t* mapping = array_get(&(s->mapping), i);
if (mapping->first_mapping_index < 0)
mapping->mode |= MODE_DELETED;
}
int i;
for (i = 0; i < s->mapping.next; i++) {
- a_mapping* mapping = array_get(&(s->mapping), i);
+ mapping_t* mapping = array_get(&(s->mapping), i);
#define ADJUST_MAPPING_INDEX(name) \
if (mapping->name >= offset) \
}
/* insert or update mapping */
-static a_mapping* insert_mapping(BDRVVVFATState* s,
+static mapping_t* insert_mapping(BDRVVVFATState* s,
uint32_t begin, uint32_t end)
{
/*
* - replace name
*/
int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
- a_mapping* mapping = NULL;
- a_mapping* first_mapping = array_get(&(s->mapping), 0);
+ mapping_t* mapping = NULL;
+ mapping_t* first_mapping = array_get(&(s->mapping), 0);
if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
&& mapping->begin < begin) {
mapping->begin = begin;
mapping->end = end;
-DLOG(a_mapping* next_mapping;
+DLOG(mapping_t* next_mapping;
assert(index + 1 >= s->mapping.next ||
((next_mapping = array_get(&(s->mapping), index + 1)) &&
next_mapping->begin >= end)));
- if (s->current_mapping && first_mapping != (a_mapping*)s->mapping.pointer)
+ if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
s->current_mapping = array_get(&(s->mapping),
s->current_mapping - first_mapping);
static int remove_mapping(BDRVVVFATState* s, int mapping_index)
{
- a_mapping* mapping = array_get(&(s->mapping), mapping_index);
- a_mapping* first_mapping = array_get(&(s->mapping), 0);
+ mapping_t* mapping = array_get(&(s->mapping), mapping_index);
+ mapping_t* first_mapping = array_get(&(s->mapping), 0);
/* free mapping */
if (mapping->first_mapping_index < 0)
/* adjust all references to mappings */
adjust_mapping_indices(s, mapping_index, -1);
- if (s->current_mapping && first_mapping != (a_mapping*)s->mapping.pointer)
+ if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
s->current_mapping = array_get(&(s->mapping),
s->current_mapping - first_mapping);
{
int i;
for (i = 0; i < s->mapping.next; i++) {
- a_mapping* mapping = array_get(&(s->mapping), i);
+ mapping_t* mapping = array_get(&(s->mapping), i);
if (mapping->dir_index >= offset)
mapping->dir_index += adjust;
if ((mapping->mode & MODE_DIRECTORY) &&
}
}
-static a_direntry* insert_direntries(BDRVVVFATState* s,
+static direntry_t* insert_direntries(BDRVVVFATState* s,
int dir_index, int count)
{
/*
* make room in s->directory,
* adjust_dirindices
*/
- a_direntry* result = array_insert(&(s->directory), dir_index, count);
+ direntry_t* result = array_insert(&(s->directory), dir_index, count);
if (result == NULL)
return NULL;
adjust_dirindices(s, dir_index, count);
static int commit_mappings(BDRVVVFATState* s,
uint32_t first_cluster, int dir_index)
{
- a_mapping* mapping = find_mapping_for_cluster(s, first_cluster);
- a_direntry* direntry = array_get(&(s->directory), dir_index);
+ mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
+ direntry_t* direntry = array_get(&(s->directory), dir_index);
uint32_t cluster = first_cluster;
vvfat_close_current_file(s);
if (!fat_eof(s, c1)) {
int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
- a_mapping* next_mapping = i >= s->mapping.next ? NULL :
+ mapping_t* next_mapping = i >= s->mapping.next ? NULL :
array_get(&(s->mapping), i);
if (next_mapping == NULL || next_mapping->begin > c1) {
static int commit_direntries(BDRVVVFATState* s,
int dir_index, int parent_mapping_index)
{
- a_direntry* direntry = array_get(&(s->directory), dir_index);
+ direntry_t* direntry = array_get(&(s->directory), dir_index);
uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
- a_mapping* mapping = find_mapping_for_cluster(s, first_cluster);
+ mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
int factor = 0x10 * s->sectors_per_cluster;
int old_cluster_count, new_cluster_count;
static int commit_one_file(BDRVVVFATState* s,
int dir_index, uint32_t offset)
{
- a_direntry* direntry = array_get(&(s->directory), dir_index);
+ direntry_t* direntry = array_get(&(s->directory), dir_index);
uint32_t c = begin_of_direntry(direntry);
uint32_t first_cluster = c;
- a_mapping* mapping = find_mapping_for_cluster(s, c);
+ mapping_t* mapping = find_mapping_for_cluster(s, c);
uint32_t size = filesize_of_direntry(direntry);
char* cluster = qemu_malloc(s->cluster_size);
uint32_t i;
c = c1;
}
- ftruncate(fd, size);
+ if (ftruncate(fd, size)) {
+ perror("ftruncate()");
+ close(fd);
+ return -4;
+ }
close(fd);
return commit_mappings(s, first_cluster, dir_index);
{
int i;
for (i = 0; i < s->mapping.next; i++) {
- a_mapping* mapping = array_get(&(s->mapping), i);
+ mapping_t* mapping = array_get(&(s->mapping), i);
if (mapping->mode & MODE_DELETED) {
fprintf(stderr, "deleted\n");
continue;
}
- assert(mapping->dir_index >= 0);
assert(mapping->dir_index < s->directory.next);
- a_direntry* direntry = array_get(&(s->directory), mapping->dir_index);
+ direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
if (mapping->mode & MODE_DIRECTORY) {
assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
int first_mapping = -1;
for (i = 0; i < s->directory.next; i++) {
- a_direntry* direntry = array_get(&(s->directory), i);
+ direntry_t* direntry = array_get(&(s->directory), i);
if (is_short_name(direntry) && begin_of_direntry(direntry)) {
- a_mapping* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
+ mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
assert(mapping);
assert(mapping->dir_index == i || is_dot(direntry));
assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
int j, count = 0;
for (j = 0; j < s->mapping.next; j++) {
- a_mapping* mapping = array_get(&(s->mapping), j);
+ mapping_t* mapping = array_get(&(s->mapping), j);
if (mapping->mode & MODE_DELETED)
continue;
if (mapping->mode & MODE_DIRECTORY) {
if (mapping->info.dir.parent_mapping_index < 0)
assert(j == 0);
else {
- a_mapping* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
+ mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
assert(parent->mode & MODE_DIRECTORY);
assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
}
#ifdef DEBUG
fprintf(stderr, "handle_renames\n");
for (i = 0; i < s->commits.next; i++) {
- a_commit* commit = array_get(&(s->commits), i);
+ commit_t* commit = array_get(&(s->commits), i);
fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
}
#endif
for (i = 0; i < s->commits.next;) {
- a_commit* commit = array_get(&(s->commits), i);
+ commit_t* commit = array_get(&(s->commits), i);
if (commit->action == ACTION_RENAME) {
- a_mapping* mapping = find_mapping_for_cluster(s,
+ mapping_t* mapping = find_mapping_for_cluster(s,
commit->param.rename.cluster);
char* old_path = mapping->path;
int l1 = strlen(mapping->path);
int l2 = strlen(old_path);
int diff = l1 - l2;
- a_direntry* direntry = array_get(&(s->directory),
+ direntry_t* direntry = array_get(&(s->directory),
mapping->info.dir.first_dir_index);
uint32_t c = mapping->begin;
int i = 0;
/* recurse */
while (!fat_eof(s, c)) {
do {
- a_direntry* d = direntry + i;
+ direntry_t* d = direntry + i;
if (is_file(d) || (is_directory(d) && !is_dot(d))) {
- a_mapping* m = find_mapping_for_cluster(s,
+ mapping_t* m = find_mapping_for_cluster(s,
begin_of_direntry(d));
int l = strlen(m->path);
char* new_path = qemu_malloc(l + diff + 1);
array_remove(&(s->commits), i);
continue;
} else if (commit->action == ACTION_MKDIR) {
- a_mapping* mapping;
+ mapping_t* mapping;
int j, parent_path_len;
#ifdef __MINGW32__
parent_path_len = strlen(commit->path)
- strlen(get_basename(commit->path)) - 1;
for (j = 0; j < s->mapping.next; j++) {
- a_mapping* m = array_get(&(s->mapping), j);
+ mapping_t* m = array_get(&(s->mapping), j);
if (m->first_mapping_index < 0 && m != mapping &&
!strncmp(m->path, mapping->path, parent_path_len) &&
strlen(m->path) == parent_path_len)
vvfat_close_current_file(s);
for (i = 0; !fail && i < s->commits.next; i++) {
- a_commit* commit = array_get(&(s->commits), i);
+ commit_t* commit = array_get(&(s->commits), i);
switch(commit->action) {
case ACTION_RENAME: case ACTION_MKDIR:
- assert(0);
+ abort();
fail = -2;
break;
case ACTION_WRITEOUT: {
- a_direntry* entry = array_get(&(s->directory),
+#ifndef NDEBUG
+ /* these variables are only used by assert() below */
+ direntry_t* entry = array_get(&(s->directory),
commit->param.writeout.dir_index);
uint32_t begin = begin_of_direntry(entry);
- a_mapping* mapping = find_mapping_for_cluster(s, begin);
+ mapping_t* mapping = find_mapping_for_cluster(s, begin);
+#endif
assert(mapping);
assert(mapping->begin == begin);
}
case ACTION_NEW_FILE: {
int begin = commit->param.new_file.first_cluster;
- a_mapping* mapping = find_mapping_for_cluster(s, begin);
- a_direntry* entry;
+ mapping_t* mapping = find_mapping_for_cluster(s, begin);
+ direntry_t* entry;
int i;
/* find direntry */
break;
}
default:
- assert(0);
+ abort();
}
}
if (i > 0 && array_remove_slice(&(s->commits), 0, i))
deleted = 0;
for (i = 1; i < s->mapping.next; i++) {
- a_mapping* mapping = array_get(&(s->mapping), i);
+ mapping_t* mapping = array_get(&(s->mapping), i);
if (mapping->mode & MODE_DELETED) {
- a_direntry* entry = array_get(&(s->directory),
+ direntry_t* entry = array_get(&(s->directory),
mapping->dir_index);
if (is_free(entry)) {
}
for (j = 1; j < s->mapping.next; j++) {
- a_mapping* m = array_get(&(s->mapping), j);
+ mapping_t* m = array_get(&(s->mapping), j);
if (m->mode & MODE_DIRECTORY &&
m->info.dir.first_dir_index >
first_dir_index &&
ret = handle_renames_and_mkdirs(s);
if (ret) {
fprintf(stderr, "Error handling renames (%d)\n", ret);
- assert(0);
+ abort();
return ret;
}
ret = commit_direntries(s, 0, -1);
if (ret) {
fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
- assert(0);
+ abort();
return ret;
}
ret = handle_commits(s);
if (ret) {
fprintf(stderr, "Error handling commits (%d)\n", ret);
- assert(0);
+ abort();
return ret;
}
ret = handle_deletes(s);
if (ret) {
fprintf(stderr, "Error deleting\n");
- assert(0);
+ abort();
return ret;
}
DLOG(checkpoint());
+ /* Check if we're operating in read-only mode */
+ if (s->qcow == NULL) {
+ return -EACCES;
+ }
+
vvfat_close_current_file(s);
/*
for (i = sector2cluster(s, sector_num);
i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
- a_mapping* mapping = find_mapping_for_cluster(s, i);
+ mapping_t* mapping = find_mapping_for_cluster(s, i);
if (mapping) {
if (mapping->read_only) {
fprintf(stderr, "Tried to write to write-protected file %s\n",
int begin = cluster2sector(s, i);
int end = begin + s->sectors_per_cluster, k;
int dir_index;
- const a_direntry* direntries;
+ const direntry_t* direntries;
long_file_name lfn;
lfn_init(&lfn);
end = sector_num + nb_sectors;
dir_index = mapping->dir_index +
0x10 * (begin - mapping->begin * s->sectors_per_cluster);
- direntries = (a_direntry*)(buf + 0x200 * (begin - sector_num));
+ direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
for (k = 0; k < (end - begin) * 0x10; k++) {
/* do not allow non-ASCII filenames */
(direntries[k].attributes & 1)) {
if (memcmp(direntries + k,
array_get(&(s->directory), dir_index + k),
- sizeof(a_direntry))) {
+ sizeof(direntry_t))) {
fprintf(stderr, "Warning: tried to write to write-protected file\n");
return -1;
}
static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
const uint8_t* buffer, int nb_sectors) {
- BDRVVVFATState* s = bs->opaque;
+ BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
return try_commit(s);
}
static void write_target_close(BlockDriverState *bs) {
- BDRVVVFATState* s = bs->opaque;
+ BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
bdrv_delete(s->qcow);
free(s->qcow_filename);
}
{
BlockDriver *bdrv_qcow;
QEMUOptionParameter *options;
+ int ret;
int size = sector2cluster(s, s->sector_count);
s->used_clusters = calloc(size, 1);
- array_init(&(s->commits), sizeof(a_commit));
+ array_init(&(s->commits), sizeof(commit_t));
s->qcow_filename = qemu_malloc(1024);
get_tmp_filename(s->qcow_filename, 1024);
if (bdrv_create(bdrv_qcow, s->qcow_filename, options) < 0)
return -1;
+
s->qcow = bdrv_new("");
- if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
- return -1;
+ if (s->qcow == NULL) {
+ return -1;
+ }
+
+ ret = bdrv_open(s->qcow, s->qcow_filename,
+ BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, bdrv_qcow);
+ if (ret < 0) {
+ return ret;
+ }
#ifndef _WIN32
unlink(s->qcow_filename);
s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
s->bs->backing_hd->drv = &vvfat_write_target;
- s->bs->backing_hd->opaque = s;
+ s->bs->backing_hd->opaque = qemu_malloc(sizeof(void*));
+ *(void**)s->bs->backing_hd->opaque = s;
return 0;
}
static BlockDriver bdrv_vvfat = {
.format_name = "vvfat",
.instance_size = sizeof(BDRVVVFATState),
- .bdrv_open = vvfat_open,
+ .bdrv_file_open = vvfat_open,
.bdrv_read = vvfat_read,
.bdrv_write = vvfat_write,
.bdrv_close = vvfat_close,
#ifdef DEBUG
static void checkpoint(void) {
- assert(((a_mapping*)array_get(&(vvv->mapping), 0))->end == 2);
+ assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
check1(vvv);
check2(vvv);
assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
#if 0
- if (((a_direntry*)vvv->directory.pointer)[1].attributes != 0xf)
+ if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
fprintf(stderr, "Nonono!\n");
- a_mapping* mapping;
- a_direntry* direntry;
+ mapping_t* mapping;
+ direntry_t* direntry;
assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
if (vvv->mapping.next<47)
return;
/* avoid compiler warnings: */
hexdump(NULL, 100);
- remove_mapping(vvv, NULL);
+ remove_mapping(vvv, 0);
print_mapping(NULL);
print_direntry(NULL);
}