mirror of
https://github.com/gwenhael-le-moine/x49gp.git
synced 2024-12-27 21:58:33 +01:00
1302 lines
37 KiB
Diff
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);
|
|
}
|