x49gp/qemu/patches/qemu-0.9.0-x49gp-block.patch

1302 lines
37 KiB
Diff

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);
}