static inline void array_free(array_t* array)
{
- if(array->pointer)
- free(array->pointer);
+ g_free(array->pointer);
array->size=array->next=0;
}
memcpy(to,buf,is*count);
- free(buf);
+ g_free(buf);
return 0;
}
/* here begins the real VVFAT driver */
typedef struct BDRVVVFATState {
+ CoMutex lock;
BlockDriverState* bs; /* pointer to parent */
unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
unsigned char first_sectors[0x40*0x200];
snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
if(stat(buffer,&st)<0) {
- free(buffer);
+ g_free(buffer);
continue;
}
direntry->begin=0; /* do that later */
if (st.st_size > 0x7fffffff) {
fprintf(stderr, "File %s is larger than 2GB\n", buffer);
- free(buffer);
+ g_free(buffer);
closedir(dir);
return -2;
}
/* root directory */
int cur = s->directory.next;
array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
+ s->directory.next = ROOT_ENTRIES;
memset(array_get(&(s->directory), cur), 0,
(ROOT_ENTRIES - cur) * sizeof(direntry_t));
}
return s->faked_sectors + s->sectors_per_cluster * cluster_num;
}
-static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
-{
- return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
-}
-
-#ifdef DBG
-static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
-{
- if(mapping->mode==MODE_UNDEFINED)
- return 0;
- return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
-}
-#endif
-
static int init_directories(BDRVVVFATState* s,
const char* dirname)
{
cluster = mapping->end;
if(cluster > s->cluster_count) {
- fprintf(stderr,"Directory does not fit in FAT%d (capacity %s)\n",
- s->fat_type,
- s->fat_type == 12 ? s->sector_count == 2880 ? "1.44 MB"
- : "2.88 MB"
- : "504MB");
+ fprintf(stderr,"Directory does not fit in FAT%d (capacity %.2f MB)\n",
+ s->fat_type, s->sector_count / 2000.0);
return -EINVAL;
}
bootsector->number_of_fats=0x2; /* number of FATs */
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 */
+ bootsector->media_type=(s->first_sectors_number>1?0xf8:0xf0); /* media descriptor (f8=hd, f0=3.5 fd)*/
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->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.drive_number=s->first_sectors_number==1?0:0x80; /* fda=0, hda=0x80 */
bootsector->u.fat16.current_head=0;
bootsector->u.fat16.signature=0x29;
bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
{
BDRVVVFATState *s = bs->opaque;
- int floppy = 0;
int i;
#ifdef DEBUG
s->bs = bs;
- s->fat_type=16;
/* LATER TODO: if FAT32, adjust */
s->sectors_per_cluster=0x10;
- /* 504MB disk*/
- bs->cyls=1024; bs->heads=16; bs->secs=63;
s->current_cluster=0xffffffff;
if (!strstart(dirname, "fat:", NULL))
return -1;
- if (strstr(dirname, ":floppy:")) {
- floppy = 1;
- s->fat_type = 12;
- s->first_sectors_number = 1;
- s->sectors_per_cluster=2;
- bs->cyls = 80; bs->heads = 2; bs->secs = 36;
- }
-
- s->sector_count=bs->cyls*bs->heads*bs->secs;
-
if (strstr(dirname, ":32:")) {
fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
s->fat_type = 32;
s->fat_type = 16;
} else if (strstr(dirname, ":12:")) {
s->fat_type = 12;
- s->sector_count=2880;
}
+ if (strstr(dirname, ":floppy:")) {
+ /* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */
+ if (!s->fat_type) {
+ s->fat_type = 12;
+ bs->secs = 36;
+ s->sectors_per_cluster=2;
+ } else {
+ bs->secs=(s->fat_type == 12 ? 18 : 36);
+ s->sectors_per_cluster=1;
+ }
+ s->first_sectors_number = 1;
+ bs->cyls=80; bs->heads=2;
+ } else {
+ /* 32MB or 504MB disk*/
+ if (!s->fat_type) {
+ s->fat_type = 16;
+ }
+ bs->cyls=(s->fat_type == 12 ? 64 : 1024);
+ bs->heads=16; bs->secs=63;
+ }
+
+ s->sector_count=bs->cyls*bs->heads*bs->secs-(s->first_sectors_number-1);
+
if (strstr(dirname, ":rw:")) {
if (enable_write_target(s))
return -1;
if(s->first_sectors_number==0x40)
init_mbr(s);
-
- /* for some reason or other, MS-DOS does not like to know about CHS... */
- if (floppy)
+ else {
+ /* MS-DOS does not like to know about CHS (?). */
bs->heads = bs->cyls = bs->secs = 0;
+ }
// assert(is_consistent(s));
+ qemu_co_mutex_init(&s->lock);
return 0;
}
return mapping;
}
-/*
- * This function simply compares path == mapping->path. Since the mappings
- * are sorted by cluster, this is expensive: O(n).
- */
-static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
- const char* path)
-{
- int i;
-
- for (i = 0; i < s->mapping.next; i++) {
- mapping_t* mapping = array_get(&(s->mapping), i);
- if (mapping->first_mapping_index < 0 &&
- !strcmp(path, mapping->path))
- return mapping;
- }
-
- return NULL;
-}
-
static int open_file(BDRVVVFATState* s,mapping_t* mapping)
{
if(!mapping)
}
#ifdef DEBUG
-static void hexdump(const void* address, uint32_t len)
-{
- const unsigned char* p = address;
- int i, j;
-
- for (i = 0; i < len; i += 16) {
- for (j = 0; j < 16 && i + j < len; j++)
- fprintf(stderr, "%02x ", p[i + j]);
- for (; j < 16; j++)
- fprintf(stderr, " ");
- fprintf(stderr, " ");
- for (j = 0; j < 16 && i + j < len; j++)
- fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
- fprintf(stderr, "\n");
- }
-}
-
static void print_direntry(const direntry_t* direntry)
{
int j = 0;
int i;
for(i=0;i<nb_sectors;i++,sector_num++) {
- if (sector_num >= s->sector_count)
+ if (sector_num >= bs->total_sectors)
return -1;
if (s->qcow) {
int n;
- if (s->qcow->drv->bdrv_is_allocated(s->qcow,
- sector_num, nb_sectors-i, &n)) {
+ if (bdrv_is_allocated(s->qcow, sector_num, nb_sectors-i, &n)) {
DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
- if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
- return -1;
- i += n - 1;
- sector_num += n - 1;
- continue;
- }
+ if (bdrv_read(s->qcow, sector_num, buf + i*0x200, n)) {
+ return -1;
+ }
+ i += n - 1;
+ sector_num += n - 1;
+ continue;
+ }
DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
}
if(sector_num<s->faked_sectors) {
uint32_t sector=sector_num-s->faked_sectors,
sector_offset_in_cluster=(sector%s->sectors_per_cluster),
cluster_num=sector/s->sectors_per_cluster;
- if(read_cluster(s, cluster_num) != 0) {
+ if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) {
/* LATER TODO: strict: return -1; */
memset(buf+i*0x200,0,0x200);
continue;
return 0;
}
+static coroutine_fn int vvfat_co_read(BlockDriverState *bs, int64_t sector_num,
+ uint8_t *buf, int nb_sectors)
+{
+ int ret;
+ BDRVVVFATState *s = bs->opaque;
+ qemu_co_mutex_lock(&s->lock);
+ ret = vvfat_read(bs, sector_num, buf, nb_sectors);
+ qemu_co_mutex_unlock(&s->lock);
+ return ret;
+}
+
/* LATER TODO: statify all functions */
/*
assert(commit->path || commit->action == ACTION_WRITEOUT);
if (commit->action != ACTION_WRITEOUT) {
assert(commit->path);
- free(commit->path);
+ g_free(commit->path);
} else
assert(commit->path == NULL);
}
return 0;
for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
- was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
+ was_modified = bdrv_is_allocated(s->qcow,
cluster2sector(s, cluster_num) + i, 1, &dummy);
return was_modified;
int64_t offset = cluster2sector(s, cluster_num);
vvfat_close_current_file(s);
- for (i = 0; i < s->sectors_per_cluster; i++)
- if (!s->qcow->drv->bdrv_is_allocated(s->qcow,
- offset + i, 1, &dummy)) {
- if (vvfat_read(s->bs,
- offset, s->cluster_buffer, 1))
- return -1;
- if (s->qcow->drv->bdrv_write(s->qcow,
- offset, s->cluster_buffer, 1))
- return -2;
- }
+ for (i = 0; i < s->sectors_per_cluster; i++) {
+ if (!bdrv_is_allocated(s->qcow, offset + i, 1, &dummy)) {
+ if (vvfat_read(s->bs, offset, s->cluster_buffer, 1)) {
+ return -1;
+ }
+ if (bdrv_write(s->qcow, offset, s->cluster_buffer, 1)) {
+ return -2;
+ }
+ }
+ }
}
}
long_file_name lfn;
int path_len = strlen(path);
- char path2[PATH_MAX];
+ char path2[PATH_MAX + 1];
assert(path_len < PATH_MAX); /* len was tested before! */
pstrcpy(path2, sizeof(path2), path);
if (subret) {
fprintf(stderr, "Error fetching direntries\n");
fail:
- free(cluster);
+ g_free(cluster);
return 0;
}
cluster_num = modified_fat_get(s, cluster_num);
} while(!fat_eof(s, cluster_num));
- free(cluster);
+ g_free(cluster);
return ret;
}
mapping_t* first_mapping = array_get(&(s->mapping), 0);
/* free mapping */
- if (mapping->first_mapping_index < 0)
- free(mapping->path);
+ if (mapping->first_mapping_index < 0) {
+ g_free(mapping->path);
+ }
/* remove from s->mapping */
array_remove(&(s->mapping), mapping_index);
if (fd < 0) {
fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
strerror(errno), errno);
+ g_free(cluster);
return fd;
}
- if (offset > 0)
- if (lseek(fd, offset, SEEK_SET) != offset)
- return -3;
+ if (offset > 0) {
+ if (lseek(fd, offset, SEEK_SET) != offset) {
+ g_free(cluster);
+ return -3;
+ }
+ }
while (offset < size) {
uint32_t c1;
ret = vvfat_read(s->bs, cluster2sector(s, c),
(uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ g_free(cluster);
+ return ret;
+ }
- if (write(fd, cluster, rest_size) < 0)
- return -2;
+ if (write(fd, cluster, rest_size) < 0) {
+ g_free(cluster);
+ return -2;
+ }
offset += rest_size;
c = c1;
if (ftruncate(fd, size)) {
perror("ftruncate()");
close(fd);
+ g_free(cluster);
return -4;
}
close(fd);
+ g_free(cluster);
return commit_mappings(s, first_cluster, dir_index);
}
}
}
- free(old_path);
+ g_free(old_path);
array_remove(&(s->commits), i);
continue;
} else if (commit->action == ACTION_MKDIR) {
return ret;
}
- s->qcow->drv->bdrv_make_empty(s->qcow);
+ if (s->qcow->drv->bdrv_make_empty) {
+ s->qcow->drv->bdrv_make_empty(s->qcow);
+ }
memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
* Use qcow backend. Commit later.
*/
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);
+ ret = bdrv_write(s->qcow, sector_num, buf, nb_sectors);
if (ret < 0) {
fprintf(stderr, "Error writing to qcow backend\n");
return ret;
return 0;
}
+static coroutine_fn int vvfat_co_write(BlockDriverState *bs, int64_t sector_num,
+ const uint8_t *buf, int nb_sectors)
+{
+ int ret;
+ BDRVVVFATState *s = bs->opaque;
+ qemu_co_mutex_lock(&s->lock);
+ ret = vvfat_write(bs, sector_num, buf, nb_sectors);
+ qemu_co_mutex_unlock(&s->lock);
+ return ret;
+}
+
static int vvfat_is_allocated(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, int* n)
{
static void write_target_close(BlockDriverState *bs) {
BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
bdrv_delete(s->qcow);
- free(s->qcow_filename);
+ g_free(s->qcow_filename);
}
static BlockDriver vvfat_write_target = {
array_free(&(s->fat));
array_free(&(s->directory));
array_free(&(s->mapping));
- if(s->cluster_buffer)
- free(s->cluster_buffer);
+ g_free(s->cluster_buffer);
}
static BlockDriver bdrv_vvfat = {
.format_name = "vvfat",
.instance_size = sizeof(BDRVVVFATState),
.bdrv_file_open = vvfat_open,
- .bdrv_read = vvfat_read,
- .bdrv_write = vvfat_write,
+ .bdrv_read = vvfat_co_read,
+ .bdrv_write = vvfat_co_write,
.bdrv_close = vvfat_close,
.bdrv_is_allocated = vvfat_is_allocated,
.protocol_name = "fat",
direntry = array_get(&(vvv->directory), mapping->dir_index);
assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0);
#endif
- return;
- /* avoid compiler warnings: */
- hexdump(NULL, 100);
- remove_mapping(vvv, 0);
- print_mapping(NULL);
- print_direntry(NULL);
}
#endif