add missing cm_iclken3_core register read function
[qemu] / block-vvfat.c
index 9dedf91..01e9c04 100644 (file)
@@ -1,9 +1,9 @@
 /* vim:set shiftwidth=4 ts=8: */
 /*
  * QEMU Block driver for virtual VFAT (shadows a local directory)
- * 
+ *
  * Copyright (c) 2004,2005 Johannes E. Schindelin
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -25,7 +25,7 @@
 #include <sys/stat.h>
 #include <dirent.h>
 #include <assert.h>
-#include "vl.h"
+#include "qemu-common.h"
 #include "block_int.h"
 
 #ifndef S_IWGRP
@@ -38,7 +38,7 @@
 /* TODO: add ":bootsector=blabla.img:" */
 /* LATER TODO: add automatic boot sector generation from
     BOOTEASY.ASM and Ranish Partition Manager
-    Note that DOS assumes the system files to be the first files in the 
+    Note that DOS assumes the system files to be the first files in the
     file system (test if the boot sector still relies on that fact)! */
 /* MAYBE TODO: write block-visofs.c */
 /* TODO: call try_commit() only after a timeout */
@@ -53,7 +53,7 @@
 #define stderr STDERR
 FILE* stderr = NULL;
 
-static void checkpoint();
+static void checkpoint(void);
 
 #ifdef __MINGW32__
 void nonono(const char* file, int line, const char* msg) {
@@ -61,7 +61,7 @@ void nonono(const char* file, int line, const char* msg) {
     exit(-5);
 }
 #undef assert
-#define assert(a) if (!(a)) nonono(__FILE__, __LINE__, #a)
+#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
 #endif
 
 #else
@@ -78,7 +78,7 @@ typedef struct array_t {
 
 static inline void array_init(array_t* array,unsigned int item_size)
 {
-    array->pointer=0;
+    array->pointer = NULL;
     array->size=0;
     array->next=0;
     array->item_size=item_size;
@@ -93,7 +93,6 @@ static inline void array_free(array_t* array)
 
 /* does not automatically grow */
 static inline void* array_get(array_t* array,unsigned int index) {
-    assert(index >= 0);
     assert(index < array->next);
     return array->pointer + index * array->item_size;
 }
@@ -102,7 +101,7 @@ 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;
-       array->pointer = realloc(array->pointer, new_size);
+       array->pointer = qemu_realloc(array->pointer, new_size);
        if (!array->pointer)
            return -1;
        array->size = new_size;
@@ -128,9 +127,9 @@ static inline void* array_get_next(array_t* array) {
 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=realloc(array->pointer,array->size+increment);
+       array->pointer=qemu_realloc(array->pointer,array->size+increment);
        if(!array->pointer)
-           return 0;
+            return NULL;
        array->size+=increment;
     }
     memmove(array->pointer+(index+count)*array->item_size,
@@ -153,21 +152,21 @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun
            index_to<0 || index_to>=array->next ||
            index_from<0 || index_from>=array->next)
        return -1;
-    
+
     if(index_to==index_from)
        return 0;
 
     is=array->item_size;
     from=array->pointer+index_from*is;
     to=array->pointer+index_to*is;
-    buf=malloc(is*count);
+    buf=qemu_malloc(is*count);
     memcpy(buf,from,is*count);
 
     if(index_to<index_from)
        memmove(to+is*count,to,from-to);
     else
        memmove(from,from+is*count,to-from);
-    
+
     memcpy(to,buf,is*count);
 
     free(buf);
@@ -175,7 +174,7 @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun
     return 0;
 }
 
-inline int array_remove_slice(array_t* array,int index, int count)
+static inline int array_remove_slice(array_t* array,int index, int count)
 {
     assert(index >=0);
     assert(count > 0);
@@ -186,16 +185,15 @@ inline int array_remove_slice(array_t* array,int index, int count)
     return 0;
 }
 
-int array_remove(array_t* 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 */
-int array_index(array_t* array, void* pointer)
+static int array_index(array_t* array, void* pointer)
 {
     size_t offset = (char*)pointer - array->pointer;
-    assert(offset >= 0);
     assert((offset % array->item_size) == 0);
     assert(offset/array->item_size < array->next);
     return offset/array->item_size;
@@ -242,21 +240,25 @@ typedef struct bootsector_t {
     uint8_t magic[2];
 } __attribute__((packed)) bootsector_t;
 
+typedef struct {
+    uint8_t head;
+    uint8_t sector;
+    uint8_t cylinder;
+} mbr_chs_t;
+
 typedef struct partition_t {
     uint8_t attributes; /* 0x80 = bootable */
-    uint8_t start_head;
-    uint8_t start_sector;
-    uint8_t start_cylinder;
-    uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xb = FAT32 */
-    uint8_t end_head;
-    uint8_t end_sector;
-    uint8_t end_cylinder;
+    mbr_chs_t start_CHS;
+    uint8_t   fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
+    mbr_chs_t end_CHS;
     uint32_t start_sector_long;
-    uint32_t end_sector_long;
+    uint32_t length_sector_long;
 } __attribute__((packed)) partition_t;
 
 typedef struct mbr_t {
-    uint8_t ignored[0x1be];
+    uint8_t ignored[0x1b8];
+    uint32_t nt_id;
+    uint8_t ignored2[2];
     partition_t partition[4];
     uint8_t magic[2];
 } __attribute__((packed)) mbr_t;
@@ -319,10 +321,10 @@ typedef struct BDRVVVFATState {
     BlockDriverState* bs; /* pointer to parent */
     unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
     unsigned char first_sectors[0x40*0x200];
-    
+
     int fat_type; /* 16 or 32 */
     array_t fat,directory,mapping;
-   
+
     unsigned int cluster_size;
     unsigned int sectors_per_cluster;
     unsigned int sectors_per_fat;
@@ -332,7 +334,7 @@ typedef struct BDRVVVFATState {
     uint32_t sector_count; /* total number of sectors of the partition */
     uint32_t cluster_count; /* total number of clusters of this partition */
     uint32_t max_fat_value;
-   
+
     int current_fd;
     mapping_t* current_mapping;
     unsigned char* cluster; /* points to current cluster */
@@ -350,11 +352,26 @@ typedef struct BDRVVVFATState {
     int downcase_short_names;
 } BDRVVVFATState;
 
-
-static int vvfat_probe(const uint8_t *buf, int buf_size, const char *filename)
-{
-    if (strstart(filename, "fat:", NULL))
-       return 100;
+/* take the sector position spos and convert it to Cylinder/Head/Sector position
+ * if the position is outside the specified geometry, fill maximum value for CHS
+ * and return 1 to signal overflow.
+ */
+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;
+    if(spos >= bs->cyls){
+        /* Overflow,
+        it happens if 32bit sector positions are used, while CHS is only 24bit.
+        Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
+        chs->head     = 0xFF;
+        chs->sector   = 0xFF;
+        chs->cylinder = 0xFF;
+        return 1;
+    }
+    chs->head     = (uint8_t)head;
+    chs->sector   = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
+    chs->cylinder = (uint8_t)spos;
     return 0;
 }
 
@@ -363,20 +380,29 @@ static void init_mbr(BDRVVVFATState* s)
     /* TODO: if the files mbr.img and bootsect.img exist, use them */
     mbr_t* real_mbr=(mbr_t*)s->first_sectors;
     partition_t* partition=&(real_mbr->partition[0]);
+    int lba;
 
     memset(s->first_sectors,0,512);
-   
+
+    /* Win NT Disk Signature */
+    real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
+
     partition->attributes=0x80; /* bootable */
-    partition->start_head=1;
-    partition->start_sector=1;
-    partition->start_cylinder=0;
+
+    /* LBA is used when partition is outside the CHS geometry */
+    lba = sector2CHS(s->bs, &partition->start_CHS, s->first_sectors_number-1);
+    lba|= sector2CHS(s->bs, &partition->end_CHS,   s->sector_count);
+
+    /*LBA partitions are identified only by start/length_sector_long not by CHS*/
+    partition->start_sector_long =cpu_to_le32(s->first_sectors_number-1);
+    partition->length_sector_long=cpu_to_le32(s->sector_count - s->first_sectors_number+1);
+
     /* FAT12/FAT16/FAT32 */
-    partition->fs_type=(s->fat_type==12?0x1:s->fat_type==16?0x6:0xb);
-    partition->end_head=s->bs->heads-1;
-    partition->end_sector=0xff; /* end sector & upper 2 bits of cylinder */;
-    partition->end_cylinder=0xff; /* lower 8 bits of end cylinder */;
-    partition->start_sector_long=cpu_to_le32(s->bs->secs);
-    partition->end_sector_long=cpu_to_le32(s->sector_count);
+    /* DOS uses different types when partition is LBA,
+       probably to prevent older versions from using CHS on them */
+    partition->fs_type= s->fat_type==12 ? 0x1:
+                        s->fat_type==16 ? (lba?0xe:0x06):
+                         /*fat_tyoe==32*/ (lba?0xc:0x0b);
 
     real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
 }
@@ -384,17 +410,19 @@ static void init_mbr(BDRVVVFATState* s)
 /* direntry functions */
 
 /* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
-static inline int short2long_name(unsigned char* dest,const char* src)
+static inline int short2long_name(char* dest,const char* src)
 {
     int i;
+    int len;
     for(i=0;i<129 && src[i];i++) {
         dest[2*i]=src[i];
        dest[2*i+1]=0;
     }
+    len=2*i;
     dest[2*i]=dest[2*i+1]=0;
     for(i=2*i+2;(i%26);i++)
        dest[i]=0xff;
-    return i;
+    return len;
 }
 
 static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
@@ -411,7 +439,7 @@ static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* fil
        entry->begin=0;
        entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
     }
-    for(i=0;i<length;i++) {
+    for(i=0;i<26*number_of_entries;i++) {
        int offset=(i%26);
        if(offset<10) offset=1+offset;
        else if(offset<22) offset=14+offset-10;
@@ -424,8 +452,7 @@ static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* fil
 
 static char is_free(const direntry_t* direntry)
 {
-    /* return direntry->name[0]==0 ; */
-    return direntry->attributes == 0 || direntry->name[0]==0xe5;
+    return direntry->name[0]==0xe5 || direntry->name[0]==0x00;
 }
 
 static char is_volume_label(const direntry_t* direntry)
@@ -485,7 +512,7 @@ static inline uint8_t fat_chksum(const direntry_t* entry)
     for(i=0;i<11;i++)
        chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0))
            +(unsigned char)entry->name[i];
-    
+
     return chksum;
 }
 
@@ -537,7 +564,7 @@ static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
        uint16_t* entry=array_get(&(s->fat),cluster);
        return le16_to_cpu(*entry);
     } else {
-       const uint8_t* x=s->fat.pointer+cluster*3/2;
+       const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
        return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
     }
 }
@@ -561,7 +588,7 @@ static inline void init_fat(BDRVVVFATState* s)
                s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
     }
     memset(s->fat.pointer,0,s->fat.size);
-    
+
     switch(s->fat_type) {
        case 12: s->max_fat_value=0xfff; break;
        case 16: s->max_fat_value=0xffff; break;
@@ -577,8 +604,8 @@ 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;
-    direntry_t* entry=0;
-    direntry_t* entry_long=0;
+    direntry_t* entry = NULL;
+    direntry_t* entry_long = NULL;
 
     if(is_dot) {
        entry=array_get_next(&(s->directory));
@@ -586,10 +613,10 @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
        memcpy(entry->name,filename,strlen(filename));
        return entry;
     }
-    
+
     entry_long=create_long_filename(s,filename);
-  
-    i = strlen(filename); 
+
+    i = strlen(filename);
     for(j = i - 1; j>0  && filename[j]!='.';j--);
     if (j > 0)
        i = (j > 8 ? 8 : j);
@@ -598,8 +625,8 @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
 
     entry=array_get_next(&(s->directory));
     memset(entry->name,0x20,11);
-    strncpy(entry->name,filename,i);
-    
+    memcpy(entry->name, filename, i);
+
     if(j > 0)
        for (i = 0; i < 3 && filename[j+1+i]; i++)
            entry->extension[i] = filename[j+1+i];
@@ -625,7 +652,7 @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
        if(entry1==entry) /* no dupe found */
            break;
 
-       /* use all 8 characters of name */      
+       /* use all 8 characters of name */
        if(entry->name[7]==' ') {
            int j;
            for(j=6;j>0 && entry->name[j]==' ';j--)
@@ -669,7 +696,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
     int first_cluster = mapping->begin;
     int parent_index = mapping->info.dir.parent_mapping_index;
     mapping_t* parent_mapping = (mapping_t*)
-       (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : 0);
+        (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL);
     int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
 
     DIR* dir=opendir(dirname);
@@ -682,11 +709,11 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
        mapping->end = mapping->begin;
        return -1;
     }
-   
+
     i = mapping->info.dir.first_dir_index =
            first_cluster == 0 ? 0 : s->directory.next;
 
-    /* actually read the directory, and allocate the mappings */ 
+    /* actually read the directory, and allocate the mappings */
     while((entry=readdir(dir))) {
        unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
         char* buffer;
@@ -697,9 +724,8 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
 
        if(first_cluster == 0 && (is_dotdot || is_dot))
            continue;
-       
-       buffer=(char*)malloc(length);
-       assert(buffer);
+
+       buffer=(char*)qemu_malloc(length);
        snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
 
        if(stat(buffer,&st)<0) {
@@ -772,7 +798,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
        memset(array_get(&(s->directory), cur), 0,
                (ROOT_ENTRIES - cur) * sizeof(direntry_t));
     }
-       
+
      /* reget the mapping, since s->mapping was possibly realloc()ed */
     mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
     first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
@@ -781,7 +807,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
 
     direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
     set_begin_of_direntry(direntry, mapping->begin);
-   
+
     return 0;
 }
 
@@ -820,8 +846,7 @@ static int init_directories(BDRVVVFATState* s,
     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);
+    s->cluster_buffer=qemu_malloc(s->cluster_size);
 
     /*
      * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
@@ -832,7 +857,7 @@ static int init_directories(BDRVVVFATState* s,
      */
     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));
 
@@ -840,7 +865,7 @@ static int init_directories(BDRVVVFATState* s,
     {
        direntry_t* entry=array_get_next(&(s->directory));
        entry->attributes=0x28; /* archive | volume label */
-       snprintf(entry->name,11,"QEMU VVFAT");
+       snprintf((char*)entry->name,11,"QEMU VVFAT");
     }
 
     /* Now build FAT, and write back information into directory */
@@ -863,8 +888,7 @@ static int init_directories(BDRVVVFATState* s,
     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 
+       /* 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);
@@ -896,20 +920,25 @@ static int init_directories(BDRVVVFATState* s,
 
        assert(mapping->begin < mapping->end);
 
+       /* next free cluster */
+       cluster = mapping->end;
+
+       if(cluster > s->cluster_count) {
+           fprintf(stderr,"Directory does not fit in FAT%d (capacity %s)\n",
+                   s->fat_type,
+                   s->fat_type == 12 ? s->sector_count == 2880 ? "1.44 MB"
+                                                               : "2.88 MB"
+                                     : "504MB");
+           return -EINVAL;
+       }
+
        /* 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);
        }
-
-       /* 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);
@@ -954,18 +983,22 @@ static int init_directories(BDRVVVFATState* s,
     return 0;
 }
 
+#ifdef DEBUG
 static BDRVVVFATState *vvv = NULL;
+#endif
 
 static int enable_write_target(BDRVVVFATState *s);
 static int is_consistent(BDRVVVFATState *s);
 
-static int vvfat_open(BlockDriverState *bs, const char* dirname)
+static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
 {
     BDRVVVFATState *s = bs->opaque;
     int floppy = 0;
     int i;
 
+#ifdef DEBUG
     vvv = s;
+#endif
 
 DLOG(if (stderr == NULL) {
     stderr = fopen("vvfat.log", "a");
@@ -976,10 +1009,9 @@ DLOG(if (stderr == NULL) {
 
     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;
+    /* 504MB disk*/
+    bs->cyls=1024; bs->heads=16; bs->secs=63;
 
     s->current_cluster=0xffffffff;
 
@@ -990,16 +1022,10 @@ DLOG(if (stderr == 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;
@@ -1008,6 +1034,8 @@ DLOG(if (stderr == NULL) {
        bs->cyls = 80; bs->heads = 2; bs->secs = 36;
     }
 
+    s->sector_count=bs->cyls*bs->heads*bs->secs;
+
     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;
@@ -1018,20 +1046,27 @@ DLOG(if (stderr == NULL) {
        s->sector_count=2880;
     }
 
+    if (strstr(dirname, ":rw:")) {
+       if (enable_write_target(s))
+           return -1;
+       bs->read_only = 0;
+    }
+
     i = strrchr(dirname, ':') - dirname;
     assert(i >= 3);
-    if (dirname[i-2] == ':' && isalpha(dirname[i-1]))
+    if (dirname[i-2] == ':' && qemu_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;
 
+    s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
+
     if(s->first_sectors_number==0x40)
        init_mbr(s);
 
@@ -1040,7 +1075,6 @@ DLOG(if (stderr == NULL) {
        bs->heads = bs->cyls = bs->secs = 0;
 
     //    assert(is_consistent(s));
-
     return 0;
 }
 
@@ -1080,7 +1114,7 @@ static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num
        assert(index1<=index2);
        DLOG(mapping=array_get(&(s->mapping),index1);
        assert(mapping->begin<=cluster_num);
-       assert(index2 >= s->mapping.next || 
+       assert(index2 >= s->mapping.next ||
                ((mapping = array_get(&(s->mapping),index2)) &&
                mapping->end>cluster_num)));
     }
@@ -1091,10 +1125,10 @@ static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_
     int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
     mapping_t* mapping;
     if(index>=s->mapping.next)
-       return 0;
+        return NULL;
     mapping=array_get(&(s->mapping),index);
     if(mapping->begin>cluster_num)
-       return 0;
+        return NULL;
     assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
     return mapping;
 }
@@ -1154,7 +1188,7 @@ static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
                s->current_mapping = mapping;
 read_cluster_directory:
                offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
-               s->cluster = s->directory.pointer+offset
+               s->cluster = (unsigned char*)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);
@@ -1213,7 +1247,7 @@ static void print_direntry(const direntry_t* 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] = '°'; j++;}
+#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
            ADD_CHAR(c[i]);
        for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
            ADD_CHAR(c[i]);
@@ -1243,7 +1277,7 @@ static void print_mapping(const mapping_t* mapping)
 }
 #endif
 
-static int vvfat_read(BlockDriverState *bs, int64_t sector_num, 
+static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
                     uint8_t *buf, int nb_sectors)
 {
     BDRVVVFATState *s = bs->opaque;
@@ -1376,7 +1410,12 @@ static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
 }
 
 typedef struct {
-    unsigned char name[1024];
+    /*
+     * Since the sequence number is at most 0x3f, and the filename
+     * length is at most 13 times the sequence number, the maximal
+     * filename length is 0x3f * 13 bytes.
+     */
+    unsigned char name[0x3f * 13 + 1];
     int checksum, len;
     int sequence_number;
 } long_file_name;
@@ -1401,6 +1440,7 @@ static int parse_long_name(long_file_name* lfn,
        lfn->sequence_number = pointer[0] & 0x3f;
        lfn->checksum = pointer[13];
        lfn->name[0] = 0;
+       lfn->name[lfn->sequence_number * 13] = 0;
     } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
        return -1;
     else if (pointer[13] != lfn->checksum)
@@ -1424,7 +1464,7 @@ static int parse_long_name(long_file_name* lfn,
     }
 
     if (pointer[0] & 0x40)
-       lfn->len = offset + strlen(lfn->name + offset);
+       lfn->len = offset + strlen((char*)lfn->name + offset);
 
     return 0;
 }
@@ -1443,7 +1483,7 @@ static int parse_short_name(BDRVVVFATState* s,
        if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
            return -1;
        else if (s->downcase_short_names)
-           lfn->name[i] = tolower(direntry->name[i]);
+           lfn->name[i] = qemu_tolower(direntry->name[i]);
        else
            lfn->name[i] = direntry->name[i];
     }
@@ -1456,14 +1496,14 @@ static int parse_short_name(BDRVVVFATState* s,
            if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
                return -2;
            else if (s->downcase_short_names)
-               lfn->name[i + j] = tolower(direntry->extension[j]);
+               lfn->name[i + j] = qemu_tolower(direntry->extension[j]);
            else
                lfn->name[i + j] = direntry->extension[j];
        }
     } else
        lfn->name[i + j + 1] = '\0';
 
-    lfn->len = strlen(lfn->name);
+    lfn->len = strlen((char*)lfn->name);
 
     return 0;
 }
@@ -1678,7 +1718,7 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
 }
 
 /*
- * This function looks at the modified data (qcow). 
+ * This function looks at the modified data (qcow).
  * It returns 0 upon inconsistency or error, and the number of clusters
  * used by the directory, its subdirectories and their files.
  */
@@ -1686,7 +1726,7 @@ static int check_directory_consistency(BDRVVVFATState *s,
        int cluster_num, const char* path)
 {
     int ret = 0;
-    unsigned char* cluster = malloc(s->cluster_size);
+    unsigned char* cluster = qemu_malloc(s->cluster_size);
     direntry_t* direntries = (direntry_t*)cluster;
     mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
 
@@ -1695,7 +1735,7 @@ static int check_directory_consistency(BDRVVVFATState *s,
     char path2[PATH_MAX];
 
     assert(path_len < PATH_MAX); /* len was tested before! */
-    strcpy(path2, path);
+    pstrcpy(path2, sizeof(path2), path);
     path2[path_len] = '/';
     path2[path_len + 1] = '\0';
 
@@ -1713,7 +1753,7 @@ static int check_directory_consistency(BDRVVVFATState *s,
     } else
        /* new directory */
        schedule_mkdir(s, cluster_num, strdup(path));
-               
+
     lfn_init(&lfn);
     do {
        int i;
@@ -1759,8 +1799,8 @@ DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i)
                    fprintf(stderr, "Error in short name (%d)\n", subret);
                    goto fail;
                }
-               if (subret > 0 || !strcmp(lfn.name, ".")
-                       || !strcmp(lfn.name, ".."))
+               if (subret > 0 || !strcmp((char*)lfn.name, ".")
+                       || !strcmp((char*)lfn.name, ".."))
                    continue;
            }
            lfn.checksum = 0x100; /* cannot use long name twice */
@@ -1769,7 +1809,8 @@ DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i)
                fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
                goto fail;
            }
-           strcpy(path2 + path_len + 1, lfn.name);
+            pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
+                    (char*)lfn.name);
 
            if (is_directory(direntries + i)) {
                if (begin_of_direntry(direntries + i) == 0) {
@@ -1826,7 +1867,7 @@ DLOG(checkpoint());
      */
     if (s->fat2 == NULL) {
        int size = 0x200 * s->sectors_per_fat;
-       s->fat2 = malloc(size);
+       s->fat2 = qemu_malloc(size);
        memcpy(s->fat2, s->fat.pointer, size);
     }
     check = vvfat_read(s->bs,
@@ -2053,7 +2094,7 @@ static int commit_mappings(BDRVVVFATState* s,
            }
 
            next_mapping->dir_index = mapping->dir_index;
-           next_mapping->first_mapping_index = 
+           next_mapping->first_mapping_index =
                mapping->first_mapping_index < 0 ?
                array_index(&(s->mapping), mapping) :
                mapping->first_mapping_index;
@@ -2073,7 +2114,7 @@ static int commit_mappings(BDRVVVFATState* s,
 
            mapping = next_mapping;
        }
-               
+
        cluster = c1;
     }
 
@@ -2168,7 +2209,7 @@ static int commit_one_file(BDRVVVFATState* s,
     uint32_t first_cluster = c;
     mapping_t* mapping = find_mapping_for_cluster(s, c);
     uint32_t size = filesize_of_direntry(direntry);
-    char* cluster = malloc(s->cluster_size);
+    char* cluster = qemu_malloc(s->cluster_size);
     uint32_t i;
     int fd = 0;
 
@@ -2178,7 +2219,7 @@ static int commit_one_file(BDRVVVFATState* s,
     for (i = s->cluster_size; i < offset; i += s->cluster_size)
        c = modified_fat_get(s, c);
 
-    fd = open(mapping->path, O_RDWR | O_CREAT, 0666);
+    fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
     if (fd < 0) {
        fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
                strerror(errno), errno);
@@ -2198,10 +2239,9 @@ static int commit_one_file(BDRVVVFATState* s,
 
        assert((size - offset == 0 && fat_eof(s, c)) ||
                (size > offset && c >=2 && !fat_eof(s, c)));
-       assert(size >= 0);
 
        ret = vvfat_read(s->bs, cluster2sector(s, c),
-           cluster, (rest_size + 0x1ff) / 0x200);
+           (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
 
        if (ret < 0)
            return ret;
@@ -2331,12 +2371,13 @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s)
                            mapping_t* m = find_mapping_for_cluster(s,
                                    begin_of_direntry(d));
                            int l = strlen(m->path);
-                           char* new_path = malloc(l + diff + 1);
+                           char* new_path = qemu_malloc(l + diff + 1);
 
                            assert(!strncmp(m->path, mapping->path, l2));
 
-                           strcpy(new_path, mapping->path);
-                           strcpy(new_path + l1, m->path + l2);
+                            pstrcpy(new_path, l + diff + 1, mapping->path);
+                            pstrcpy(new_path + l1, l + diff + 1 - l1,
+                                    m->path + l2);
 
                            schedule_rename(s, m->begin, new_path);
                        }
@@ -2559,7 +2600,7 @@ static int do_commit(BDRVVVFATState* s)
        return ret;
     }
 
-    /* copy FAT (with bdrv_read) */ 
+    /* copy FAT (with bdrv_read) */
     memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
 
     /* recurse direntries from root (using bs->bdrv_read) */
@@ -2601,10 +2642,10 @@ DLOG(checkpoint());
     return do_commit(s);
 }
 
-static int vvfat_write(BlockDriverState *bs, int64_t sector_num, 
+static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
                     const uint8_t *buf, int nb_sectors)
 {
-    BDRVVVFATState *s = bs->opaque; 
+    BDRVVVFATState *s = bs->opaque;
     int i, ret;
 
 DLOG(checkpoint());
@@ -2643,7 +2684,7 @@ DLOG(checkpoint());
                    begin = sector_num;
                if (end > sector_num + nb_sectors)
                    end = sector_num + nb_sectors;
-               dir_index  = mapping->dir_index + 
+               dir_index  = mapping->dir_index +
                    0x10 * (begin - mapping->begin * s->sectors_per_cluster);
                direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
 
@@ -2702,7 +2743,7 @@ static int vvfat_is_allocated(BlockDriverState *bs,
        *n = nb_sectors;
     else if (*n < 0)
        return 0;
-    return 1;  
+    return 1;
 }
 
 static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
@@ -2731,9 +2772,8 @@ static int enable_write_target(BDRVVVFATState *s)
 
     array_init(&(s->commits), sizeof(commit_t));
 
-    s->qcow_filename = malloc(1024);
-    strcpy(s->qcow_filename, "/tmp/vl.XXXXXX");
-    get_tmp_filename(s->qcow_filename, strlen(s->qcow_filename) + 1);
+    s->qcow_filename = qemu_malloc(1024);
+    get_tmp_filename(s->qcow_filename, 1024);
     if (bdrv_create(&bdrv_qcow,
                s->qcow_filename, s->sector_count, "fat:", 0) < 0)
        return -1;
@@ -2765,20 +2805,18 @@ static void vvfat_close(BlockDriverState *bs)
 }
 
 BlockDriver bdrv_vvfat = {
-    "vvfat",
-    sizeof(BDRVVVFATState),
-    vvfat_probe,
-    vvfat_open,
-    vvfat_read,
-    vvfat_write,
-    vvfat_close,
-    NULL, /* ??? Not sure if we can do any meaningful flushing.  */
-    NULL,
-    vvfat_is_allocated
+    .format_name       = "vvfat",
+    .instance_size     = sizeof(BDRVVVFATState),
+    .bdrv_open         = vvfat_open,
+    .bdrv_read         = vvfat_read,
+    .bdrv_write                = vvfat_write,
+    .bdrv_close                = vvfat_close,
+    .bdrv_is_allocated = vvfat_is_allocated,
+    .protocol_name     = "fat",
 };
 
 #ifdef DEBUG
-static void checkpoint() {
+static void checkpoint(void) {
     assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
     check1(vvv);
     check2(vvv);
@@ -2805,4 +2843,3 @@ static void checkpoint() {
     print_direntry(NULL);
 }
 #endif
-