diff -ur qemu-0.9.0/block-qcow.c qemu/block-qcow.c
--- qemu-0.9.0/block-qcow.c	2007-02-06 00:01:54.000000000 +0100
+++ qemu/block-qcow.c	2007-07-30 14:30:18.000000000 +0200
@@ -69,10 +69,12 @@
     uint8_t *cluster_cache;
     uint8_t *cluster_data;
     uint64_t cluster_cache_offset;
+#ifndef X49GP
     uint32_t crypt_method; /* current crypt method, 0 if no key yet */
     uint32_t crypt_method_header;
     AES_KEY aes_encrypt_key;
     AES_KEY aes_decrypt_key;
+#endif
 } BDRVQcowState;
 
 static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset);
@@ -115,9 +117,11 @@
         goto fail;
     if (header.crypt_method > QCOW_CRYPT_AES)
         goto fail;
+#ifndef X49GP
     s->crypt_method_header = header.crypt_method;
     if (s->crypt_method_header)
         bs->encrypted = 1;
+#endif
     s->cluster_bits = header.cluster_bits;
     s->cluster_size = 1 << s->cluster_bits;
     s->cluster_sectors = 1 << (s->cluster_bits - 9);
@@ -172,6 +176,8 @@
     return -1;
 }
 
+#ifndef X49GP
+
 static int qcow_set_key(BlockDriverState *bs, const char *key)
 {
     BDRVQcowState *s = bs->opaque;
@@ -239,6 +245,8 @@
     }
 }
 
+#endif /* !(X49GP) */
+
 /* 'allocate' is:
  *
  * 0 to not allocate.
@@ -344,6 +352,7 @@
                 cluster_offset = (cluster_offset + s->cluster_size - 1) & 
                     ~(s->cluster_size - 1);
                 bdrv_truncate(s->hd, cluster_offset + s->cluster_size);
+#ifndef X49GP
                 /* if encrypted, we must initialize the cluster
                    content which won't be written */
                 if (s->crypt_method && 
@@ -363,6 +372,7 @@
                         }
                     }
                 }
+#endif /* !(X49GP) */
             } else {
                 cluster_offset |= QCOW_OFLAG_COMPRESSED | 
                     (uint64_t)compressed_size << (63 - s->cluster_bits);
@@ -442,7 +452,7 @@
     return 0;
 }
 
-#if 0
+#ifdef X49GP
 
 static int qcow_read(BlockDriverState *bs, int64_t sector_num, 
                      uint8_t *buf, int nb_sectors)
@@ -474,10 +484,12 @@
             ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
             if (ret != n * 512) 
                 return -1;
+#ifndef X49GP
             if (s->crypt_method) {
                 encrypt_sectors(s, sector_num, buf, buf, n, 0, 
                                 &s->aes_decrypt_key);
             }
+#endif /* !(X49GP) */
         }
         nb_sectors -= n;
         sector_num += n;
@@ -485,7 +497,8 @@
     }
     return 0;
 }
-#endif
+
+#endif /* X49GP */
 
 static int qcow_write(BlockDriverState *bs, int64_t sector_num, 
                      const uint8_t *buf, int nb_sectors)
@@ -504,12 +517,15 @@
                                             index_in_cluster + n);
         if (!cluster_offset)
             return -1;
+#ifndef X49GP
         if (s->crypt_method) {
             encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
                             &s->aes_encrypt_key);
             ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, 
                               s->cluster_data, n * 512);
-        } else {
+        } else
+#endif /* !(X49GP) */
+	{
             ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
         }
         if (ret != n * 512) 
@@ -522,6 +538,8 @@
     return 0;
 }
 
+#ifndef X49GP
+
 typedef struct QCowAIOCB {
     BlockDriverAIOCB common;
     int64_t sector_num;
@@ -554,12 +572,14 @@
         /* nothing to do */
     } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
         /* nothing to do */
+#ifndef X49GP
     } else {
         if (s->crypt_method) {
             encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf, 
                             acb->n, 0, 
                             &s->aes_decrypt_key);
         }
+#endif
     }
 
     acb->nb_sectors -= acb->n;
@@ -673,6 +693,7 @@
         ret = -EIO;
         goto fail;
     }
+#ifndef X49GP
     if (s->crypt_method) {
         if (!acb->cluster_data) {
             acb->cluster_data = qemu_mallocz(s->cluster_size);
@@ -684,7 +705,9 @@
         encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf, 
                         acb->n, 1, &s->aes_encrypt_key);
         src_buf = acb->cluster_data;
-    } else {
+    } else
+#endif /* !(X49GP) */
+    {
         src_buf = acb->buf;
     }
     acb->hd_aiocb = bdrv_aio_write(s->hd,
@@ -725,6 +748,8 @@
     qemu_aio_release(acb);
 }
 
+#endif /* !(X49GP) */
+
 static void qcow_close(BlockDriverState *bs)
 {
     BDRVQcowState *s = bs->opaque;
@@ -887,19 +912,30 @@
     sizeof(BDRVQcowState),
     qcow_probe,
     qcow_open,
+#ifdef X49GP
+    qcow_read,
+    qcow_write,
+#else
     NULL,
     NULL,
+#endif
     qcow_close,
     qcow_create,
     qcow_flush,
     qcow_is_allocated,
+#ifndef X49GP
     qcow_set_key,
+#else
+    NULL,
+#endif
     qcow_make_empty,
 
+#ifndef X49GP
     .bdrv_aio_read = qcow_aio_read,
     .bdrv_aio_write = qcow_aio_write,
     .bdrv_aio_cancel = qcow_aio_cancel,
     .aiocb_size = sizeof(QCowAIOCB),
+#endif
     .bdrv_write_compressed = qcow_write_compressed,
     .bdrv_get_info = qcow_get_info,
 };
diff -ur qemu-0.9.0/block-raw.c qemu/block-raw.c
--- qemu-0.9.0/block-raw.c	2007-02-06 00:01:54.000000000 +0100
+++ qemu/block-raw.c	2007-07-30 14:30:18.000000000 +0200
@@ -27,6 +27,10 @@
 #ifndef _WIN32
 #include <aio.h>
 
+#ifdef X49GP
+#define QEMU_TOOL
+#endif
+
 #ifndef QEMU_TOOL
 #include "exec-all.h"
 #endif
@@ -157,6 +161,7 @@
     return ret;
 }
 
+#ifndef X49GP
 /***********************************************************/
 /* Unix AIO using POSIX AIO */
 
@@ -379,6 +384,7 @@
         pacb = &acb->next;
     }
 }
+#endif /* !(X49GP) */
 
 static void raw_close(BlockDriverState *bs)
 {
@@ -479,11 +485,12 @@
     raw_close,
     raw_create,
     raw_flush,
-    
+#ifndef X49GP
     .bdrv_aio_read = raw_aio_read,
     .bdrv_aio_write = raw_aio_write,
     .bdrv_aio_cancel = raw_aio_cancel,
     .aiocb_size = sizeof(RawAIOCB),
+#endif
     .protocol_name = "file",
     .bdrv_pread = raw_pread,
     .bdrv_pwrite = raw_pwrite,
@@ -815,11 +822,12 @@
     raw_close,
     NULL,
     raw_flush,
-    
+#ifndef X49GP
     .bdrv_aio_read = raw_aio_read,
     .bdrv_aio_write = raw_aio_write,
     .bdrv_aio_cancel = raw_aio_cancel,
     .aiocb_size = sizeof(RawAIOCB),
+#endif
     .bdrv_pread = raw_pread,
     .bdrv_pwrite = raw_pwrite,
     .bdrv_getlength = raw_getlength,
diff -ur qemu-0.9.0/block-vvfat.c qemu/block-vvfat.c
--- qemu-0.9.0/block-vvfat.c	2007-02-06 00:01:54.000000000 +0100
+++ qemu/block-vvfat.c	2007-07-30 16:04:03.000000000 +0200
@@ -41,9 +41,9 @@
     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 */
 
-/* #define DEBUG */
+#define DEBUG
+#undef DEBUG_SECTORS
 
 #ifdef DEBUG
 
@@ -53,7 +53,7 @@
 #define stderr STDERR
 FILE* stderr = NULL;
 
-static void checkpoint();
+static void checkpoint(const char *where);
 
 #ifdef __MINGW32__
 void nonono(const char* file, int line, const char* msg) {
@@ -70,9 +70,15 @@
 
 #endif
 
+#ifdef X49GP
+#define VOLUME_LABEL	"X49GP-VVFAT"
+#else
+#define VOLUME_LABEL	"QEMU-VVFAT"
+#endif
+
 /* dynamic array functions */
 typedef struct array_t {
-    char* pointer;
+    unsigned char* pointer;
     unsigned int size,next,item_size;
 } array_t;
 
@@ -144,9 +150,9 @@
  * index_to, but the order of all other elements is preserved. */
 static inline int array_roll(array_t* array,int index_to,int index_from,int count)
 {
-    char* buf;
-    char* from;
-    char* to;
+    unsigned char* buf;
+    unsigned char* from;
+    unsigned char* to;
     int is;
 
     if(!array ||
@@ -194,7 +200,7 @@
 /* return the index for a given member */
 int array_index(array_t* array, void* pointer)
 {
-    size_t offset = (char*)pointer - array->pointer;
+    size_t offset = (unsigned char*)pointer - array->pointer;
     assert(offset >= 0);
     assert((offset % array->item_size) == 0);
     assert(offset/array->item_size < array->next);
@@ -204,6 +210,18 @@
 /* These structures are used to fake a disk and the VFAT filesystem.
  * For this reason we need to use __attribute__((packed)). */
 
+#define BOOTCODE_SIZE		448
+#define BOOTCODE_FAT32_SIZE	420
+
+typedef struct msdos_volume_info {
+	uint8_t drive_number;
+	uint8_t ignored;
+	uint8_t signature;
+	uint32_t id;
+	uint8_t volume_label[11];
+	uint8_t fs_type[8];
+} __attribute__((packed)) msdos_volume_info_t;
+
 typedef struct bootsector_t {
     uint8_t jump[3];
     uint8_t name[8];
@@ -221,11 +239,8 @@
     uint32_t total_sectors;
     union {
         struct {
-	    uint8_t drive_number;
-	    uint8_t current_head;
-	    uint8_t signature;
-	    uint32_t id;
-	    uint8_t volume_label[11];
+	    msdos_volume_info_t vi;
+	    uint8_t boot_code[BOOTCODE_SIZE];
 	} __attribute__((packed)) fat16;
 	struct {
 	    uint32_t sectors_per_fat;
@@ -234,14 +249,43 @@
 	    uint32_t first_cluster_of_root_directory;
 	    uint16_t info_sector;
 	    uint16_t backup_boot_sector;
-	    uint16_t ignored;
+	    uint16_t ignored[6];
+	    msdos_volume_info_t vi;
+	    uint8_t boot_code[BOOTCODE_FAT32_SIZE];
 	} __attribute__((packed)) fat32;
     } u;
-    uint8_t fat_type[8];
-    uint8_t ignored[0x1c0];
     uint8_t magic[2];
 } __attribute__((packed)) bootsector_t;
 
+uint8_t dummy_boot_jump[3] = { 0xeb, 0x3c, 0x90 };
+
+uint8_t dummy_boot_code[BOOTCODE_SIZE] =
+	"\x0e"			/* push	cs */
+	"\x1f"			/* pop	ds */
+	"\xbe\x5b\x7c"		/* mov	si, <offset message_text> */
+/* write_msg: */
+	"\xac"			/* lodsb */
+	"\x22\xc0"		/* and	al, al */
+	"\x74\x0b"		/* jz	key_press */
+	"\x56"			/* push	si */
+	"\xb4\x0e"		/* mov	ah, 0eh */
+	"\xbb\x07\x00"		/* mov	bx, 0007h */
+	"\xcd\x10"		/* int	10h */
+	"\x5e"			/* pop	si */
+	"\xeb\xf0"		/* jmp	write_msg */
+/* key_press: */
+	"\x32\xe4"		/* xor	ah, ah */
+	"\xcd\x16"		/* int	16h */
+	"\xcd\x19"		/* int	19h */
+/* foo: */
+	"\xeb\xfe"		/* jmp	foo */
+/* message_text: */
+	"This is not a bootable disk. Please insert a bootable floppy and\r\n"
+	"press any key to try again...\r\n";
+
+#define MSG_OFFSET_OFFSET	3
+#define MESSAGE_OFFSET		29	/* Offset of message in above code */
+
 typedef struct partition_t {
     uint8_t attributes; /* 0x80 = bootable */
     uint8_t start_head;
@@ -340,7 +384,6 @@
     unsigned int current_cluster;
 
     /* write support */
-    BlockDriverState* write_target;
     char* qcow_filename;
     BlockDriverState* qcow;
     void* fat2;
@@ -348,6 +391,7 @@
     array_t commits;
     const char* path;
     int downcase_short_names;
+    QEMUTimer *write_timer;
 } BDRVVVFATState;
 
 
@@ -377,7 +421,7 @@
 /* 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;
     for(i=0;i<129 && src[i];i++) {
@@ -423,7 +467,7 @@
 
 static char is_volume_label(const direntry_t* direntry)
 {
-    return direntry->attributes == 0x28;
+    return (direntry->attributes & 0x1f) == 0x08;
 }
 
 static char is_long_name(const direntry_t* direntry)
@@ -501,13 +545,16 @@
 {
     if(s->fat_type==32) {
 	uint32_t* entry=array_get(&(s->fat),cluster);
+        DLOG(fprintf(stderr, "%s:%u: cluster %u: %08x\n", __FUNCTION__, __LINE__, cluster, value));
 	*entry=cpu_to_le32(value);
     } else if(s->fat_type==16) {
 	uint16_t* entry=array_get(&(s->fat),cluster);
+        DLOG(fprintf(stderr, "%s:%u: cluster %u: %04x\n", __FUNCTION__, __LINE__, cluster, value & 0xffff));
 	*entry=cpu_to_le16(value&0xffff);
     } else {
 	int offset = (cluster*3/2);
 	unsigned char* p = array_get(&(s->fat), offset);
+        DLOG(fprintf(stderr, "%s:%u: cluster %u: %03x\n", __FUNCTION__, __LINE__, cluster, value & 0xfff));
         switch (cluster&1) {
 	case 0:
 		p[0] = value&0xff;
@@ -561,7 +608,6 @@
 	case 32: s->max_fat_value=0x0fffffff; break;
 	default: s->max_fat_value=0; /* error... */
     }
-
 }
 
 /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
@@ -575,7 +621,7 @@
 
     if(is_dot) {
 	entry=array_get_next(&(s->directory));
-	memset(entry->name,0x20,11);
+	memset(entry->name,' ',11);
 	memcpy(entry->name,filename,strlen(filename));
 	return entry;
     }
@@ -590,8 +636,8 @@
 	i = 8;
 
     entry=array_get_next(&(s->directory));
-    memset(entry->name,0x20,11);
-    strncpy(entry->name,filename,i);
+    memset(entry->name,' ',11);
+    strncpy((char *) entry->name,filename,i);
     
     if(j > 0)
 	for (i = 0; i < 3 && filename[j+1+i]; i++)
@@ -700,6 +746,8 @@
             continue;
 	}
 
+	DLOG(fprintf(stderr, "%s:%u: create direntry for '%s'\n", __FUNCTION__, __LINE__, entry->d_name));
+
 	/* create directory entry for this file */
 	direntry=create_short_and_long_name(s, i, entry->d_name,
 		is_dot || is_dotdot);
@@ -726,6 +774,8 @@
 
 	/* create mapping for this file */
 	if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
+	    DLOG(fprintf(stderr, "%s:%u: create mapping for '%s'\n", __FUNCTION__, __LINE__, entry->d_name));
+
 	    s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
 	    s->current_mapping->begin=0;
 	    s->current_mapping->end=st.st_size;
@@ -778,9 +828,9 @@
     return 0;
 }
 
-static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
+static inline int32_t sector2cluster(BDRVVVFATState* s, off_t sector_num)
 {
-    return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
+    return (sector_num - s->faked_sectors) / s->sectors_per_cluster;
 }
 
 static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
@@ -805,15 +855,19 @@
 static int init_directories(BDRVVVFATState* s,
 	const char* dirname)
 {
+    msdos_volume_info_t *vi;
     bootsector_t* bootsector;
     mapping_t* mapping;
     unsigned int i;
     unsigned int cluster;
+    direntry_t *entry;
+    struct stat st;
+    size_t namelen;
 
     memset(&(s->first_sectors[0]),0,0x40*0x200);
 
-    s->cluster_size=s->sectors_per_cluster*0x200;
-    s->cluster_buffer=malloc(s->cluster_size);
+    s->cluster_size = s->sectors_per_cluster * 0x200;
+    s->cluster_buffer = malloc(s->cluster_size);
     assert(s->cluster_buffer);
 
     /*
@@ -823,18 +877,32 @@
      * spc is sectors_per_clusters, and
      * fat_type = 12, 16 or 32.
      */
-    i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
-    s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
+    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));
 
+    DLOG(fprintf(stderr, "%s:%u: create direntry for '%s'\n", __FUNCTION__, __LINE__, dirname));
+
     /* add volume label */
-    {
-	direntry_t* entry=array_get_next(&(s->directory));
-	entry->attributes=0x28; /* archive | volume label */
-	snprintf(entry->name,11,"QEMU VVFAT");
-    }
+    stat(dirname, &st);
+    entry = array_get_next(&(s->directory));
+    entry->attributes = 0x08; /* archive | volume label */
+    memset(entry->name, ' ', 11);
+    namelen = strlen(VOLUME_LABEL);
+    if (namelen > 11)
+	namelen = 11;
+    memcpy(entry->name, VOLUME_LABEL, namelen);
+    entry->reserved[0] = entry->reserved[1] = 0;
+    entry->ctime = fat_datetime(st.st_ctime, 1);
+    entry->cdate = fat_datetime(st.st_ctime, 0);
+    entry->adate = fat_datetime(st.st_atime, 0);
+    entry->begin_hi = 0;
+    entry->mtime = fat_datetime(st.st_ctime, 1);
+    entry->mdate = fat_datetime(st.st_ctime, 0);
+    entry->begin = 0;
+    entry->size = 0;
 
     /* Now build FAT, and write back information into directory */
     init_fat(s);
@@ -842,6 +910,8 @@
     s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
     s->cluster_count=sector2cluster(s, s->sector_count);
 
+    DLOG(fprintf(stderr, "%s:%u: create mapping for '%s'\n", __FUNCTION__, __LINE__, dirname));
+
     mapping = array_get_next(&(s->mapping));
     mapping->begin = 0;
     mapping->dir_index = 0;
@@ -910,16 +980,39 @@
     s->last_cluster_of_root_directory = mapping->end;
 
     /* the FAT signature */
-    fat_set(s,0,s->max_fat_value);
+    switch (s->fat_type) {
+	case 12: fat_set(s, 0, s->sector_count == 5760 ? 0xff9 : 0xff8); break;
+	case 16: fat_set(s, 0, 0xfff8); break;
+	case 32: fat_set(s, 0, 0x0ffffff0); break;
+	default: fat_set(s,0,s->max_fat_value); break;
+    }
     fat_set(s,1,s->max_fat_value);
 
     s->current_mapping = NULL;
 
     bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
-    bootsector->jump[0]=0xeb;
-    bootsector->jump[1]=0x3e;
-    bootsector->jump[2]=0x90;
+
+    memcpy(bootsector->jump, dummy_boot_jump, 3);
+    bootsector->jump[1] = ((s->fat_type == 32 ?
+    				(char *) &bootsector->u.fat32.boot_code :
+    				(char *) &bootsector->u.fat16.boot_code) -
+				(char *) &bootsector) - 2;
+    if (s->fat_type == 32) {
+    	int offset = (char *) &bootsector->u.fat32.boot_code -
+		     (char *) &bootsector + MESSAGE_OFFSET + 0x7c00;
+    	memcpy(bootsector->u.fat32.boot_code, dummy_boot_code,
+	       BOOTCODE_FAT32_SIZE);
+	bootsector->u.fat32.boot_code[MSG_OFFSET_OFFSET + 0] = offset & 0xff;
+	bootsector->u.fat32.boot_code[MSG_OFFSET_OFFSET + 1] = offset >> 8;
+    } else {
+    	memcpy(bootsector->u.fat16.boot_code, dummy_boot_code, BOOTCODE_SIZE);
+    }
+
+#ifdef X49GP
+    memcpy(bootsector->name,"X49GP   ",8);
+#else
     memcpy(bootsector->name,"QEMU    ",8);
+#endif
     bootsector->sector_size=cpu_to_le16(0x200);
     bootsector->sectors_per_cluster=s->sectors_per_cluster;
     bootsector->reserved_sectors=cpu_to_le16(1);
@@ -927,7 +1020,6 @@
     bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
     bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
     bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
-    s->fat.pointer[0] = bootsector->media_type;
     bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
     bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
     bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
@@ -935,15 +1027,25 @@
     bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
 
     /* LATER TODO: if FAT32, this is wrong */
-    bootsector->u.fat16.drive_number=s->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=cpu_to_le32(0xfabe1afd);
+    if (s->fat_type == 32) {
+    	vi = &bootsector->u.fat32.vi;
+        memcpy(vi->fs_type, "FAT32   ", 8);
+    } else {
+    	vi = &bootsector->u.fat16.vi;
+        memcpy(vi->fs_type, (s->fat_type == 12 ? "FAT12   " : "FAT16   "), 8);
+    }
 
-    memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
-    memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12   ":s->fat_type==16?"FAT16   ":"FAT32   "),8);
-    bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
+    /* assume this is hda (TODO) */
+    vi->drive_number = s->fat_type == 12 ? 0 : 0x80;
+    vi->signature = 0x29;
+    vi->id = cpu_to_le32(0xfabe1afd);
+    memset(vi->volume_label, ' ', 11);
+    namelen = strlen(VOLUME_LABEL);
+    if (namelen > 11)
+	namelen = 11;
+    memcpy(vi->volume_label, VOLUME_LABEL, namelen);
 
+    bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
     return 0;
 }
 
@@ -951,7 +1053,7 @@
 static BDRVVVFATState *vvv = NULL;
 #endif
 
-static int enable_write_target(BDRVVVFATState *s);
+static int enable_write(BDRVVVFATState *s);
 static int is_consistent(BDRVVVFATState *s);
 
 static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
@@ -964,10 +1066,10 @@
     vvv = s;
 #endif
 
-DLOG(if (stderr == NULL) {
-    stderr = fopen("vvfat.log", "a");
-    setbuf(stderr, NULL);
-})
+    DLOG(if (stderr == NULL) {
+	stderr = fopen("vvfat.log", "a");
+	setbuf(stderr, NULL);
+    })
 
     s->bs = bs;
 
@@ -983,17 +1085,20 @@
     s->first_sectors_number=0x40;
     /* read only is the default for safety */
     bs->read_only = 1;
-    s->qcow = s->write_target = NULL;
+    s->qcow = NULL;
     s->qcow_filename = NULL;
     s->fat2 = NULL;
     s->downcase_short_names = 1;
     
-    if (!strstart(dirname, "fat:", NULL))
+    if (!strstart(dirname, "fat:", NULL)) {
+	DLOG(fprintf(stderr, "%s:%u: dirname '%s' not \"fat:\"\n", __FUNCTION__, __LINE__, dirname));
 	return -1;
+    }
 
     if (strstr(dirname, ":rw:")) {
-	if (enable_write_target(s))
+	if (enable_write(s)) {
 	    return -1;
+	}
 	bs->read_only = 0;
     }
 
@@ -1026,8 +1131,11 @@
     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))
+
+    if (init_directories(s, dirname)) {
+	DLOG(fprintf(stderr, "%s:%u: init_directories failed\n", __FUNCTION__, __LINE__));
 	return -1;
+    }
 
     if(s->first_sectors_number==0x40)
 	init_mbr(s);
@@ -1037,6 +1145,8 @@
 	bs->heads = bs->cyls = bs->secs = 0;
 
     //    assert(is_consistent(s));
+
+    DLOG(fprintf(stderr, "%s:%u: return 0\n", __FUNCTION__, __LINE__));
     return 0;
 }
 
@@ -1153,7 +1263,7 @@
 		s->cluster = 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);
+		assert(s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
 		s->current_cluster = cluster_num;
 		return 0;
 	    }
@@ -1227,6 +1337,18 @@
 		direntry->attributes,
 		begin_of_direntry(direntry),le32_to_cpu(direntry->size));
     }
+    {
+    	unsigned char *p = (void *) direntry;
+	int i;
+
+	fprintf(stderr, "%p:\t", p);
+	for (i = 0; i < 16; i++)
+		fprintf(stderr, " %02x", *p++);
+	fprintf(stderr, "\n%p:\t", p);
+	for ( ; i < 32; i++)
+		fprintf(stderr, " %02x", *p++);
+	fprintf(stderr, "\n");
+    }
 }
 
 static void print_mapping(const mapping_t* mapping)
@@ -1243,6 +1365,9 @@
                     uint8_t *buf, int nb_sectors)
 {
     BDRVVVFATState *s = bs->opaque;
+#ifdef DEBUG_SECTORS
+    int32_t orig_sector = sector_num;
+#endif
     int i;
 
     for(i=0;i<nb_sectors;i++,sector_num++) {
@@ -1259,7 +1384,7 @@
 		sector_num += n - 1;
 		continue;
 	    }
-DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
+// DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
 	}
 	if(sector_num<s->faked_sectors) {
 	    if(sector_num<s->first_sectors_number)
@@ -1280,6 +1405,14 @@
 	    memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
 	}
     }
+
+#ifdef DEBUG_SECTORS
+    for (i = 0; i < nb_sectors; i++) {
+	fprintf(stderr, "%s:%u: sector %u:\n", __FUNCTION__, __LINE__, orig_sector + i);
+	hexdump(buf + i * 0x200, 0x200);
+    }
+#endif
+
     return 0;
 }
 
@@ -1372,7 +1505,7 @@
 }
 
 typedef struct {
-    unsigned char name[1024];
+    char name[1024];
     int checksum, len;
     int sequence_number;
 } long_file_name;
@@ -1577,6 +1710,7 @@
 	    const char* basename;
 
 	    assert(mapping->mode & MODE_DELETED);
+	    DLOG(fprintf(stderr, "%s:%u: clear delete: ", __FUNCTION__, __LINE__); print_mapping(mapping));
 	    mapping->mode &= ~MODE_DELETED;
 
 	    basename = get_basename(mapping->path);
@@ -1702,6 +1836,7 @@
 	assert(mapping->mode & MODE_DIRECTORY);
 
 	assert(mapping->mode & MODE_DELETED);
+	DLOG(fprintf(stderr, "%s:%u: clear delete: ", __FUNCTION__, __LINE__); print_mapping(mapping));
 	mapping->mode &= ~MODE_DELETED;
 
 	if (strcmp(basename, basename2))
@@ -1736,9 +1871,9 @@
 	for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
 	    int cluster_count;
 
-DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
-	    if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
-		    is_free(direntries + i))
+DLOG(if (!is_free(direntries + i)) { fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i); })
+
+	    if (is_volume_label(direntries + i) || is_dot(direntries + i) || is_free(direntries + i))
 		continue;
 
 	    subret = parse_long_name(&lfn, direntries + i);
@@ -1806,7 +1941,10 @@
     int i, check;
     int used_clusters_count = 0;
 
-DLOG(checkpoint());
+DLOG(checkpoint(__FUNCTION__));
+
+    DLOG(fprintf(stderr, "%s:%u:\n", __FUNCTION__, __LINE__));
+
     /*
      * - get modified FAT
      * - compare the two FATs (TODO)
@@ -1825,10 +1963,11 @@
 	s->fat2 = malloc(size);
 	memcpy(s->fat2, s->fat.pointer, size);
     }
-    check = vvfat_read(s->bs,
-	    s->first_sectors_number, s->fat2, s->sectors_per_fat);
+    check = vvfat_read(s->bs, s->first_sectors_number,
+    		       s->fat2, s->sectors_per_fat);
     if (check) {
 	fprintf(stderr, "Could not copy fat\n");
+        DLOG(fprintf(stderr, "%s:%u: copy fat failed\n", __FUNCTION__, __LINE__));
 	return 0;
     }
     assert (s->used_clusters);
@@ -1839,12 +1978,15 @@
 
     /* mark every mapped file/directory as deleted.
      * (check_directory_consistency() will unmark those still present). */
-    if (s->qcow)
+    if (s->qcow) {
 	for (i = 0; i < s->mapping.next; i++) {
 	    mapping_t* mapping = array_get(&(s->mapping), i);
-	    if (mapping->first_mapping_index < 0)
+	    if (mapping->first_mapping_index < 0) {
+		DLOG(fprintf(stderr, "%s:%u: mark delete: ", __FUNCTION__, __LINE__); print_mapping(mapping));
 		mapping->mode |= MODE_DELETED;
+	    }
 	}
+    }
 
     used_clusters_count = check_directory_consistency(s, 0, s->path);
     if (used_clusters_count <= 0) {
@@ -1869,9 +2011,12 @@
 	}
     }
 
-    if (check != used_clusters_count)
+    if (check != used_clusters_count) {
+        DLOG(fprintf(stderr, "%s:%u: check: %u, used %u\n", __FUNCTION__, __LINE__, check, used_clusters_count));
 	return 0;
+    }
 
+    DLOG(fprintf(stderr, "%s:%u: return used %u\n", __FUNCTION__, __LINE__, used_clusters_count));
     return used_clusters_count;
 }
 
@@ -1928,6 +2073,8 @@
 ((next_mapping = array_get(&(s->mapping), index + 1)) &&
  next_mapping->begin >= end)));
 
+    DLOG(fprintf(stderr, "insert mapping %u:\n", index); print_mapping(mapping));
+
     if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
 	s->current_mapping = array_get(&(s->mapping),
 		s->current_mapping - first_mapping);
@@ -1940,6 +2087,8 @@
     mapping_t* mapping = array_get(&(s->mapping), mapping_index);
     mapping_t* first_mapping = array_get(&(s->mapping), 0);
 
+    DLOG(fprintf(stderr, "remove mapping %u:\n", mapping_index); print_mapping(mapping));
+
     /* free mapping */
     if (mapping->first_mapping_index < 0)
 	free(mapping->path);
@@ -2090,7 +2239,7 @@
     int ret, i;
     uint32_t c;
 
-DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
+    DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
 
     assert(direntry);
     assert(mapping);
@@ -2130,7 +2279,7 @@
 		s->sectors_per_cluster);
 	if (ret)
 	    return ret;
-	assert(!strncmp(s->directory.pointer, "QEMU", 4));
+	assert(!strncmp((char *) s->directory.pointer, VOLUME_LABEL, strlen(VOLUME_LABEL)));
 	current_dir_index += factor;
     }
 
@@ -2164,7 +2313,7 @@
     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);
+    unsigned char* cluster = malloc(s->cluster_size);
     uint32_t i;
     int fd = 0;
 
@@ -2217,13 +2366,13 @@
 
 #ifdef DEBUG
 /* test, if all mappings point to valid direntries */
-static void check1(BDRVVVFATState* s)
+static void check1(BDRVVVFATState* s, const char *where)
 {
     int i;
     for (i = 0; i < s->mapping.next; i++) {
 	mapping_t* mapping = array_get(&(s->mapping), i);
 	if (mapping->mode & MODE_DELETED) {
-	    fprintf(stderr, "deleted\n");
+	    DLOG(fprintf(stderr, "%s: deleted\n", where); print_mapping(mapping));
 	    continue;
 	}
 	assert(mapping->dir_index >= 0);
@@ -2238,7 +2387,7 @@
 }
 
 /* test, if all direntries have mappings */
-static void check2(BDRVVVFATState* s)
+static void check2(BDRVVVFATState* s, const char *where)
 {
     int i;
     int first_mapping = -1;
@@ -2485,7 +2634,9 @@
 	    mapping_t* mapping = array_get(&(s->mapping), i);
 	    if (mapping->mode & MODE_DELETED) {
 		direntry_t* entry = array_get(&(s->directory),
-			mapping->dir_index);
+					      mapping->dir_index);
+
+		DLOG(fprintf(stderr, "%s:%u: ", __FUNCTION__, __LINE__); print_mapping(mapping); print_direntry(entry));
 
 		if (is_free(entry)) {
 		    /* remove file/directory */
@@ -2515,14 +2666,15 @@
 				next_dir_index - first_dir_index);
 
 			deleted++;
+		    } else {
+			if (unlink(mapping->path))
+			    return -4;
+			deleted++;
 		    }
-		} else {
-		    if (unlink(mapping->path))
-			return -4;
-		    deleted++;
+
+		    DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
+		    remove_mapping(s, i);
 		}
-		DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
-		remove_mapping(s, i);
 	    }
 	}
     }
@@ -2530,6 +2682,20 @@
     return 0;
 }
 
+static int have_deletes(BDRVVVFATState* s)
+{
+    int i;
+
+    for (i = 0; i < s->mapping.next; i++) {
+	mapping_t* mapping = array_get(&(s->mapping), i);
+	if (mapping->mode & MODE_DELETED) {
+	    return 1;
+	}
+    }
+
+    return 0;
+}
+
 /*
  * synchronize mapping with new state:
  *
@@ -2543,8 +2709,10 @@
     int ret = 0;
 
     /* the real meat are the commits. Nothing to do? Move along! */
-    if (s->commits.next == 0)
+    if ((0 == s->commits.next) && (0 == have_deletes(s))) {
+	DLOG(fprintf(stderr, "%s:%u: nothing to do\n", __FUNCTION__, __LINE__));
 	return 0;
+    }
 
     vvfat_close_current_file(s);
 
@@ -2584,26 +2752,48 @@
 
     memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
 
-DLOG(checkpoint());
+DLOG(checkpoint(__FUNCTION__));
     return 0;
 }
 
 static int try_commit(BDRVVVFATState* s)
 {
     vvfat_close_current_file(s);
-DLOG(checkpoint());
+
+DLOG(checkpoint(__FUNCTION__));
+
     if(!is_consistent(s))
 	return -1;
+
     return do_commit(s);
 }
 
+static void
+vvfat_write_timer(void *opaque)
+{
+    BDRVVVFATState *s = opaque; 
+
+    DLOG(fprintf(stderr, "%s:%u:\n", __FUNCTION__, __LINE__));
+
+DLOG(checkpoint("vvfat_write_timer: before try_commits"));
+
+    try_commit(s);
+
+DLOG(checkpoint("vvfat_write_timer: after try_commits"));
+}
+
 static int vvfat_write(BlockDriverState *bs, int64_t sector_num, 
                     const uint8_t *buf, int nb_sectors)
 {
     BDRVVVFATState *s = bs->opaque; 
+    mapping_t* mapping;
+#ifdef DEBUG_SECTORS
+    int32_t orig_sector = sector_num;
+#endif
+    int64_t start_cluster, end_cluster;
     int i, ret;
 
-DLOG(checkpoint());
+DLOG(checkpoint(__FUNCTION__));
 
     vvfat_close_current_file(s);
 
@@ -2613,12 +2803,35 @@
      * - do not allow to write non-ASCII filenames
      */
 
-    if (sector_num < s->first_sectors_number)
+    if (sector_num < s->first_sectors_number) {
+        DLOG(fprintf(stderr, "%s:%u: sector: %u nb %u (first: %u)\n", __FUNCTION__, __LINE__, (int) sector_num, nb_sectors, s->first_sectors_number));
 	return -1;
+    }
 
-    for (i = sector2cluster(s, sector_num);
-	    i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
-	mapping_t* mapping = find_mapping_for_cluster(s, i);
+#ifdef DEBUG_SECTORS
+    for (i = 0; i < nb_sectors; i++) {
+	fprintf(stderr, "%s:%u: sector %u:\n", __FUNCTION__, __LINE__, orig_sector + i);
+	hexdump(buf + i * 0x200, 0x200);
+    }
+#endif
+
+    DLOG(fprintf(stderr, "%s:%u: check mappings, sector: %u nb %u (faked: %u)\n", __FUNCTION__, __LINE__, (int) sector_num, nb_sectors, s->faked_sectors));
+
+    if (sector_num >= s->faked_sectors) {
+    	start_cluster = sector2cluster(s, sector_num);
+    } else {
+        start_cluster = 0;
+    }
+    if (sector_num + nb_sectors - 1 >= s->faked_sectors) {
+    	end_cluster = sector2cluster(s, sector_num + nb_sectors - 1);
+    } else {
+        end_cluster = -1;
+    }
+
+    for (i = start_cluster; i <= end_cluster; ) {
+	DLOG(fprintf(stderr, "%s:%u: cluster %u\n", __FUNCTION__, __LINE__, i));
+	mapping = find_mapping_for_cluster(s, i);
+	DLOG(fprintf(stderr, "%s:%u: mapping %p\n", __FUNCTION__, __LINE__, mapping));
 	if (mapping) {
 	    if (mapping->read_only) {
 		fprintf(stderr, "Tried to write to write-protected file %s\n",
@@ -2662,30 +2875,25 @@
 		}
 	    }
 	    i = mapping->end;
-	} else
+	} else {
 	    i++;
+	}
     }
 
     /*
      * Use qcow backend. Commit later.
      */
-DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
+    DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
     ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
     if (ret < 0) {
 	fprintf(stderr, "Error writing to qcow backend\n");
 	return ret;
     }
 
-    for (i = sector2cluster(s, sector_num);
-	    i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
-	if (i >= 0)
-	    s->used_clusters[i] |= USED_ALLOCATED;
-
-DLOG(checkpoint());
-    /* TODO: add timeout */
-    try_commit(s);
+    for (i = start_cluster; i <= end_cluster; i++)
+	s->used_clusters[i] |= USED_ALLOCATED;
 
-DLOG(checkpoint());
+    qemu_mod_timer(s->write_timer, qemu_get_clock(rt_clock) + ticks_per_sec);
     return 0;
 }
 
@@ -2701,49 +2909,62 @@
     return 1;	
 }
 
-static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
-	const uint8_t* buffer, int nb_sectors) {
-    BDRVVVFATState* s = bs->opaque;
-    return try_commit(s);
-}
-
-static void write_target_close(BlockDriverState *bs) {
-    BDRVVVFATState* s = bs->opaque;
-    bdrv_delete(s->qcow);
-    free(s->qcow_filename);
-}
-
-static BlockDriver vvfat_write_target = {
-    "vvfat_write_target", 0, NULL, NULL, NULL,
-    write_target_commit,
-    write_target_close,
-    NULL, NULL, NULL
-};
-
-static int enable_write_target(BDRVVVFATState *s)
+static int enable_write(BDRVVVFATState *s)
 {
-    int size = sector2cluster(s, s->sector_count);
+    int error;
+    int size;
+    
+    DLOG(fprintf(stderr, "%s:%u:\n", __FUNCTION__, __LINE__));
+
+    size = sector2cluster(s, s->sector_count);
     s->used_clusters = calloc(size, 1);
 
     array_init(&(s->commits), sizeof(commit_t));
 
     s->qcow_filename = malloc(1024);
     get_tmp_filename(s->qcow_filename, 1024);
-    if (bdrv_create(&bdrv_qcow,
-		s->qcow_filename, s->sector_count, "fat:", 0) < 0)
+    error = bdrv_create(&bdrv_qcow, s->qcow_filename, s->sector_count, "", 0);
+    if (error < 0) {
+	DLOG(fprintf(stderr, "%s:%u: bdrv_create '%s': %d\n", __FUNCTION__, __LINE__, s->qcow_filename, error));
 	return -1;
+    }
+
     s->qcow = bdrv_new("");
-    if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
+    if (s->qcow == NULL) {
+	DLOG(fprintf(stderr, "%s:%u: bdrv_new: Out of memory\n", __FUNCTION__, __LINE__));
+#ifndef _WIN32
+	unlink(s->qcow_filename);
+#endif
 	return -1;
+    }
 
+    error = bdrv_open(s->qcow, s->qcow_filename, 0);
+    if (error < 0) {
+	DLOG(fprintf(stderr, "%s:%u: bdrv_open '%s': %d\n", __FUNCTION__, __LINE__, s->qcow_filename, error));
 #ifndef _WIN32
-    unlink(s->qcow_filename);
+	unlink(s->qcow_filename);
 #endif
+	bdrv_delete(s->qcow);
+	return -1;
+    }
 
-    s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
-    s->bs->backing_hd->drv = &vvfat_write_target;
-    s->bs->backing_hd->opaque = s;
+    s->write_timer = qemu_new_timer(rt_clock, vvfat_write_timer, s);
+    if (NULL == s->write_timer) {
+	DLOG(fprintf(stderr, "%s:%u: write_timer: Out of memory\n", __FUNCTION__, __LINE__));
+#ifndef _WIN32
+	unlink(s->qcow_filename);
+#endif
+	bdrv_delete(s->qcow);
+	return -1;
+    }
+
+    s->qcow->is_temporary = 1;
+
+#ifndef _WIN32
+    unlink(s->qcow_filename);
+#endif
 
+    DLOG(fprintf(stderr, "%s:%u: write enabled\n", __FUNCTION__, __LINE__));
     return 0;
 }
 
@@ -2751,10 +2972,24 @@
 {
     BDRVVVFATState *s = bs->opaque;
 
+    if (qemu_timer_pending(s->write_timer)) {
+    	qemu_del_timer(s->write_timer);
+	vvfat_write_timer(s);
+    }
+
     vvfat_close_current_file(s);
+
+    if (s->qcow) {
+    	qemu_free(s->qcow_filename);
+
+	bdrv_delete(s->qcow);
+	s->qcow = NULL;
+    }
+
     array_free(&(s->fat));
     array_free(&(s->directory));
     array_free(&(s->mapping));
+
     if(s->cluster_buffer)
         free(s->cluster_buffer);
 }
@@ -2774,10 +3009,16 @@
 };
 
 #ifdef DEBUG
-static void checkpoint() {
+static void
+checkpoint(const char *where)
+{
+    DLOG(fprintf(stderr, "%s:%u: checkpoint(%s)\n", __FUNCTION__, __LINE__, where));
+
     assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
-    check1(vvv);
-    check2(vvv);
+    DLOG(fprintf(stderr, "checkpoint(%s): call check1()\n", where));
+    check1(vvv, where);
+    DLOG(fprintf(stderr, "checkpoint(%s): call check2()\n", where));
+    check2(vvv, where);
     assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
 #if 0
     if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
@@ -2793,10 +3034,11 @@
     direntry = array_get(&(vvv->directory), mapping->dir_index);
     assert(!memcmp(direntry->name, "USB     H  ", 11) || direntry->name[0]==0);
 #endif
+    DLOG(fprintf(stderr, "checkpoint(%s): done\n", where));
     return;
     /* avoid compiler warnings: */
     hexdump(NULL, 100);
-    remove_mapping(vvv, NULL);
+    remove_mapping(vvv, 0);
     print_mapping(NULL);
     print_direntry(NULL);
 }