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 +#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, */ +/* 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;ifaked_sectors) { if(sector_numfirst_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); }