]> git.proxmox.com Git - mirror_qemu.git/blame - block/vvfat.c
util/hbitmap: Add an API to reset all set bits in hbitmap
[mirror_qemu.git] / block / vvfat.c
CommitLineData
7ad9be64 1/* vim:set shiftwidth=4 ts=4: */
de167e41
FB
2/*
3 * QEMU Block driver for virtual VFAT (shadows a local directory)
5fafdf24 4 *
a046433a 5 * Copyright (c) 2004,2005 Johannes E. Schindelin
5fafdf24 6 *
de167e41
FB
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25#include <sys/stat.h>
26#include <dirent.h>
faf07963 27#include "qemu-common.h"
737e150e 28#include "block/block_int.h"
1de7afc9 29#include "qemu/module.h"
caf71f86 30#include "migration/migration.h"
7ad9be64
KW
31#include "qapi/qmp/qint.h"
32#include "qapi/qmp/qbool.h"
d49b6836 33#include "qapi/qmp/qstring.h"
de167e41 34
a046433a
FB
35#ifndef S_IWGRP
36#define S_IWGRP 0
37#endif
38#ifndef S_IWOTH
39#define S_IWOTH 0
40#endif
41
42/* TODO: add ":bootsector=blabla.img:" */
43/* LATER TODO: add automatic boot sector generation from
44 BOOTEASY.ASM and Ranish Partition Manager
5fafdf24 45 Note that DOS assumes the system files to be the first files in the
a046433a
FB
46 file system (test if the boot sector still relies on that fact)! */
47/* MAYBE TODO: write block-visofs.c */
48/* TODO: call try_commit() only after a timeout */
49
50/* #define DEBUG */
51
52#ifdef DEBUG
53
54#define DLOG(a) a
55
3f47aa8c 56static void checkpoint(void);
de167e41 57
a046433a
FB
58#ifdef __MINGW32__
59void nonono(const char* file, int line, const char* msg) {
60 fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg);
61 exit(-5);
62}
63#undef assert
6bcb76c3 64#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
a046433a
FB
65#endif
66
67#else
68
69#define DLOG(a)
70
71#endif
de167e41
FB
72
73/* dynamic array functions */
c227f099 74typedef struct array_t {
de167e41
FB
75 char* pointer;
76 unsigned int size,next,item_size;
c227f099 77} array_t;
de167e41 78
c227f099 79static inline void array_init(array_t* array,unsigned int item_size)
de167e41 80{
511d2b14 81 array->pointer = NULL;
de167e41
FB
82 array->size=0;
83 array->next=0;
84 array->item_size=item_size;
85}
86
c227f099 87static inline void array_free(array_t* array)
de167e41 88{
ce137829 89 g_free(array->pointer);
de167e41
FB
90 array->size=array->next=0;
91}
92
a046433a 93/* does not automatically grow */
c227f099 94static inline void* array_get(array_t* array,unsigned int index) {
a046433a
FB
95 assert(index < array->next);
96 return array->pointer + index * array->item_size;
97}
98
c227f099 99static inline int array_ensure_allocated(array_t* array, int index)
a046433a
FB
100{
101 if((index + 1) * array->item_size > array->size) {
102 int new_size = (index + 32) * array->item_size;
7267c094 103 array->pointer = g_realloc(array->pointer, new_size);
a046433a
FB
104 if (!array->pointer)
105 return -1;
106 array->size = new_size;
107 array->next = index + 1;
de167e41 108 }
a046433a
FB
109
110 return 0;
de167e41
FB
111}
112
c227f099 113static inline void* array_get_next(array_t* array) {
a046433a
FB
114 unsigned int next = array->next;
115 void* result;
116
117 if (array_ensure_allocated(array, next) < 0)
118 return NULL;
119
120 array->next = next + 1;
121 result = array_get(array, next);
122
de167e41
FB
123 return result;
124}
125
c227f099 126static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
de167e41
FB
127 if((array->next+count)*array->item_size>array->size) {
128 int increment=count*array->item_size;
7267c094 129 array->pointer=g_realloc(array->pointer,array->size+increment);
de167e41 130 if(!array->pointer)
511d2b14 131 return NULL;
de167e41
FB
132 array->size+=increment;
133 }
134 memmove(array->pointer+(index+count)*array->item_size,
135 array->pointer+index*array->item_size,
136 (array->next-index)*array->item_size);
137 array->next+=count;
138 return array->pointer+index*array->item_size;
139}
140
141/* this performs a "roll", so that the element which was at index_from becomes
142 * index_to, but the order of all other elements is preserved. */
c227f099 143static inline int array_roll(array_t* array,int index_to,int index_from,int count)
de167e41
FB
144{
145 char* buf;
146 char* from;
147 char* to;
148 int is;
149
150 if(!array ||
151 index_to<0 || index_to>=array->next ||
152 index_from<0 || index_from>=array->next)
153 return -1;
3b46e624 154
de167e41
FB
155 if(index_to==index_from)
156 return 0;
157
158 is=array->item_size;
159 from=array->pointer+index_from*is;
160 to=array->pointer+index_to*is;
7267c094 161 buf=g_malloc(is*count);
de167e41
FB
162 memcpy(buf,from,is*count);
163
164 if(index_to<index_from)
165 memmove(to+is*count,to,from-to);
166 else
167 memmove(from,from+is*count,to-from);
3b46e624 168
de167e41
FB
169 memcpy(to,buf,is*count);
170
ce137829 171 g_free(buf);
de167e41
FB
172
173 return 0;
174}
175
c227f099 176static inline int array_remove_slice(array_t* array,int index, int count)
de167e41 177{
a046433a
FB
178 assert(index >=0);
179 assert(count > 0);
180 assert(index + count <= array->next);
181 if(array_roll(array,array->next-1,index,count))
de167e41 182 return -1;
a046433a 183 array->next -= count;
de167e41
FB
184 return 0;
185}
186
c227f099 187static int array_remove(array_t* array,int index)
a046433a
FB
188{
189 return array_remove_slice(array, index, 1);
190}
191
192/* return the index for a given member */
c227f099 193static int array_index(array_t* array, void* pointer)
a046433a
FB
194{
195 size_t offset = (char*)pointer - array->pointer;
a046433a
FB
196 assert((offset % array->item_size) == 0);
197 assert(offset/array->item_size < array->next);
198 return offset/array->item_size;
199}
200
de167e41 201/* These structures are used to fake a disk and the VFAT filesystem.
541dc0d4 202 * For this reason we need to use QEMU_PACKED. */
de167e41 203
c227f099 204typedef struct bootsector_t {
de167e41
FB
205 uint8_t jump[3];
206 uint8_t name[8];
207 uint16_t sector_size;
208 uint8_t sectors_per_cluster;
209 uint16_t reserved_sectors;
210 uint8_t number_of_fats;
211 uint16_t root_entries;
a046433a 212 uint16_t total_sectors16;
de167e41
FB
213 uint8_t media_type;
214 uint16_t sectors_per_fat;
215 uint16_t sectors_per_track;
216 uint16_t number_of_heads;
217 uint32_t hidden_sectors;
218 uint32_t total_sectors;
219 union {
220 struct {
221 uint8_t drive_number;
222 uint8_t current_head;
223 uint8_t signature;
224 uint32_t id;
225 uint8_t volume_label[11];
541dc0d4 226 } QEMU_PACKED fat16;
de167e41
FB
227 struct {
228 uint32_t sectors_per_fat;
229 uint16_t flags;
230 uint8_t major,minor;
231 uint32_t first_cluster_of_root_directory;
232 uint16_t info_sector;
233 uint16_t backup_boot_sector;
234 uint16_t ignored;
541dc0d4 235 } QEMU_PACKED fat32;
de167e41
FB
236 } u;
237 uint8_t fat_type[8];
238 uint8_t ignored[0x1c0];
239 uint8_t magic[2];
541dc0d4 240} QEMU_PACKED bootsector_t;
de167e41 241
b570094d
TS
242typedef struct {
243 uint8_t head;
244 uint8_t sector;
245 uint8_t cylinder;
c227f099 246} mbr_chs_t;
b570094d 247
c227f099 248typedef struct partition_t {
de167e41 249 uint8_t attributes; /* 0x80 = bootable */
c227f099 250 mbr_chs_t start_CHS;
b570094d 251 uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
c227f099 252 mbr_chs_t end_CHS;
de167e41 253 uint32_t start_sector_long;
b570094d 254 uint32_t length_sector_long;
541dc0d4 255} QEMU_PACKED partition_t;
de167e41 256
c227f099 257typedef struct mbr_t {
b570094d
TS
258 uint8_t ignored[0x1b8];
259 uint32_t nt_id;
260 uint8_t ignored2[2];
c227f099 261 partition_t partition[4];
de167e41 262 uint8_t magic[2];
541dc0d4 263} QEMU_PACKED mbr_t;
de167e41 264
c227f099 265typedef struct direntry_t {
f671d173 266 uint8_t name[8 + 3];
de167e41
FB
267 uint8_t attributes;
268 uint8_t reserved[2];
269 uint16_t ctime;
270 uint16_t cdate;
271 uint16_t adate;
272 uint16_t begin_hi;
273 uint16_t mtime;
274 uint16_t mdate;
275 uint16_t begin;
276 uint32_t size;
541dc0d4 277} QEMU_PACKED direntry_t;
de167e41
FB
278
279/* this structure are used to transparently access the files */
280
c227f099 281typedef struct mapping_t {
a046433a
FB
282 /* begin is the first cluster, end is the last+1 */
283 uint32_t begin,end;
de167e41
FB
284 /* as s->directory is growable, no pointer may be used here */
285 unsigned int dir_index;
a046433a
FB
286 /* the clusters of a file may be in any order; this points to the first */
287 int first_mapping_index;
288 union {
289 /* offset is
290 * - the offset in the file (in clusters) for a file, or
291 * - the next cluster of the directory for a directory, and
292 * - the address of the buffer for a faked entry
293 */
294 struct {
295 uint32_t offset;
296 } file;
297 struct {
298 int parent_mapping_index;
299 int first_dir_index;
300 } dir;
301 } info;
302 /* path contains the full path, i.e. it always starts with s->path */
303 char* path;
304
305 enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2,
306 MODE_DIRECTORY = 4, MODE_FAKED = 8,
307 MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
308 int read_only;
c227f099 309} mapping_t;
de167e41 310
a046433a 311#ifdef DEBUG
c227f099
AL
312static void print_direntry(const struct direntry_t*);
313static void print_mapping(const struct mapping_t* mapping);
a046433a 314#endif
de167e41
FB
315
316/* here begins the real VVFAT driver */
317
318typedef struct BDRVVVFATState {
848c66e8 319 CoMutex lock;
a046433a 320 BlockDriverState* bs; /* pointer to parent */
de167e41
FB
321 unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
322 unsigned char first_sectors[0x40*0x200];
3b46e624 323
de167e41 324 int fat_type; /* 16 or 32 */
c227f099 325 array_t fat,directory,mapping;
3b46e624 326
de167e41
FB
327 unsigned int cluster_size;
328 unsigned int sectors_per_cluster;
329 unsigned int sectors_per_fat;
330 unsigned int sectors_of_root_directory;
a046433a 331 uint32_t last_cluster_of_root_directory;
de167e41
FB
332 unsigned int faked_sectors; /* how many sectors are faked before file data */
333 uint32_t sector_count; /* total number of sectors of the partition */
334 uint32_t cluster_count; /* total number of clusters of this partition */
de167e41 335 uint32_t max_fat_value;
3b46e624 336
de167e41 337 int current_fd;
c227f099 338 mapping_t* current_mapping;
a046433a
FB
339 unsigned char* cluster; /* points to current cluster */
340 unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
de167e41
FB
341 unsigned int current_cluster;
342
343 /* write support */
a046433a
FB
344 BlockDriverState* write_target;
345 char* qcow_filename;
346 BlockDriverState* qcow;
347 void* fat2;
348 char* used_clusters;
c227f099 349 array_t commits;
a046433a
FB
350 const char* path;
351 int downcase_short_names;
3397f0cb
KW
352
353 Error *migration_blocker;
de167e41
FB
354} BDRVVVFATState;
355
b570094d
TS
356/* take the sector position spos and convert it to Cylinder/Head/Sector position
357 * if the position is outside the specified geometry, fill maximum value for CHS
358 * and return 1 to signal overflow.
359 */
4480e0f9
MA
360static int sector2CHS(mbr_chs_t *chs, int spos, int cyls, int heads, int secs)
361{
b570094d 362 int head,sector;
4480e0f9
MA
363 sector = spos % secs; spos /= secs;
364 head = spos % heads; spos /= heads;
365 if (spos >= cyls) {
b570094d
TS
366 /* Overflow,
367 it happens if 32bit sector positions are used, while CHS is only 24bit.
368 Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
369 chs->head = 0xFF;
370 chs->sector = 0xFF;
371 chs->cylinder = 0xFF;
372 return 1;
373 }
374 chs->head = (uint8_t)head;
375 chs->sector = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
376 chs->cylinder = (uint8_t)spos;
377 return 0;
378}
de167e41 379
4480e0f9 380static void init_mbr(BDRVVVFATState *s, int cyls, int heads, int secs)
de167e41
FB
381{
382 /* TODO: if the files mbr.img and bootsect.img exist, use them */
c227f099
AL
383 mbr_t* real_mbr=(mbr_t*)s->first_sectors;
384 partition_t* partition = &(real_mbr->partition[0]);
b570094d 385 int lba;
de167e41
FB
386
387 memset(s->first_sectors,0,512);
3b46e624 388
b570094d
TS
389 /* Win NT Disk Signature */
390 real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
391
de167e41 392 partition->attributes=0x80; /* bootable */
b570094d
TS
393
394 /* LBA is used when partition is outside the CHS geometry */
4480e0f9
MA
395 lba = sector2CHS(&partition->start_CHS, s->first_sectors_number - 1,
396 cyls, heads, secs);
397 lba |= sector2CHS(&partition->end_CHS, s->bs->total_sectors - 1,
398 cyls, heads, secs);
b570094d
TS
399
400 /*LBA partitions are identified only by start/length_sector_long not by CHS*/
f91cbefe
MA
401 partition->start_sector_long = cpu_to_le32(s->first_sectors_number - 1);
402 partition->length_sector_long = cpu_to_le32(s->bs->total_sectors
403 - s->first_sectors_number + 1);
b570094d 404
a046433a 405 /* FAT12/FAT16/FAT32 */
b570094d
TS
406 /* DOS uses different types when partition is LBA,
407 probably to prevent older versions from using CHS on them */
408 partition->fs_type= s->fat_type==12 ? 0x1:
409 s->fat_type==16 ? (lba?0xe:0x06):
410 /*fat_tyoe==32*/ (lba?0xc:0x0b);
de167e41
FB
411
412 real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
413}
414
a046433a
FB
415/* direntry functions */
416
de167e41 417/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
60fe76f3 418static inline int short2long_name(char* dest,const char* src)
de167e41
FB
419{
420 int i;
1e080d5d 421 int len;
de167e41
FB
422 for(i=0;i<129 && src[i];i++) {
423 dest[2*i]=src[i];
424 dest[2*i+1]=0;
425 }
1e080d5d 426 len=2*i;
de167e41
FB
427 dest[2*i]=dest[2*i+1]=0;
428 for(i=2*i+2;(i%26);i++)
429 dest[i]=0xff;
1e080d5d 430 return len;
de167e41
FB
431}
432
c227f099 433static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
de167e41
FB
434{
435 char buffer[258];
436 int length=short2long_name(buffer,filename),
437 number_of_entries=(length+25)/26,i;
c227f099 438 direntry_t* entry;
de167e41
FB
439
440 for(i=0;i<number_of_entries;i++) {
441 entry=array_get_next(&(s->directory));
442 entry->attributes=0xf;
443 entry->reserved[0]=0;
444 entry->begin=0;
445 entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
446 }
1e080d5d 447 for(i=0;i<26*number_of_entries;i++) {
de167e41
FB
448 int offset=(i%26);
449 if(offset<10) offset=1+offset;
450 else if(offset<22) offset=14+offset-10;
451 else offset=28+offset-22;
452 entry=array_get(&(s->directory),s->directory.next-1-(i/26));
453 entry->name[offset]=buffer[i];
454 }
455 return array_get(&(s->directory),s->directory.next-number_of_entries);
456}
457
c227f099 458static char is_free(const direntry_t* direntry)
a046433a 459{
ad1a897e 460 return direntry->name[0]==0xe5 || direntry->name[0]==0x00;
a046433a
FB
461}
462
c227f099 463static char is_volume_label(const direntry_t* direntry)
a046433a
FB
464{
465 return direntry->attributes == 0x28;
466}
467
c227f099 468static char is_long_name(const direntry_t* direntry)
a046433a
FB
469{
470 return direntry->attributes == 0xf;
471}
472
c227f099 473static char is_short_name(const direntry_t* direntry)
a046433a
FB
474{
475 return !is_volume_label(direntry) && !is_long_name(direntry)
476 && !is_free(direntry);
477}
478
c227f099 479static char is_directory(const direntry_t* direntry)
a046433a
FB
480{
481 return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
482}
483
c227f099 484static inline char is_dot(const direntry_t* direntry)
a046433a
FB
485{
486 return is_short_name(direntry) && direntry->name[0] == '.';
487}
488
c227f099 489static char is_file(const direntry_t* direntry)
a046433a
FB
490{
491 return is_short_name(direntry) && !is_directory(direntry);
492}
493
c227f099 494static inline uint32_t begin_of_direntry(const direntry_t* direntry)
a046433a
FB
495{
496 return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
497}
498
c227f099 499static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
a046433a
FB
500{
501 return le32_to_cpu(direntry->size);
502}
503
c227f099 504static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
a046433a
FB
505{
506 direntry->begin = cpu_to_le16(begin & 0xffff);
507 direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
508}
509
de167e41
FB
510/* fat functions */
511
c227f099 512static inline uint8_t fat_chksum(const direntry_t* entry)
de167e41
FB
513{
514 uint8_t chksum=0;
515 int i;
516
f671d173
SW
517 for (i = 0; i < ARRAY_SIZE(entry->name); i++) {
518 chksum = (((chksum & 0xfe) >> 1) |
519 ((chksum & 0x01) ? 0x80 : 0)) + entry->name[i];
5606c220 520 }
3b46e624 521
de167e41
FB
522 return chksum;
523}
524
525/* if return_time==0, this returns the fat_date, else the fat_time */
526static uint16_t fat_datetime(time_t time,int return_time) {
527 struct tm* t;
de167e41 528 struct tm t1;
6ab00cee 529 t = &t1;
de167e41 530 localtime_r(&time,t);
de167e41
FB
531 if(return_time)
532 return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
533 return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
534}
535
536static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
537{
a046433a
FB
538 if(s->fat_type==32) {
539 uint32_t* entry=array_get(&(s->fat),cluster);
540 *entry=cpu_to_le32(value);
de167e41
FB
541 } else if(s->fat_type==16) {
542 uint16_t* entry=array_get(&(s->fat),cluster);
543 *entry=cpu_to_le16(value&0xffff);
544 } else {
a046433a
FB
545 int offset = (cluster*3/2);
546 unsigned char* p = array_get(&(s->fat), offset);
547 switch (cluster&1) {
548 case 0:
549 p[0] = value&0xff;
550 p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
551 break;
552 case 1:
553 p[0] = (p[0]&0xf) | ((value&0xf)<<4);
554 p[1] = (value>>4);
555 break;
556 }
de167e41
FB
557 }
558}
559
560static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
561{
a046433a
FB
562 if(s->fat_type==32) {
563 uint32_t* entry=array_get(&(s->fat),cluster);
564 return le32_to_cpu(*entry);
de167e41
FB
565 } else if(s->fat_type==16) {
566 uint16_t* entry=array_get(&(s->fat),cluster);
567 return le16_to_cpu(*entry);
568 } else {
ffe8ab83 569 const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
a046433a 570 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
de167e41
FB
571 }
572}
573
574static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
575{
576 if(fat_entry>s->max_fat_value-8)
577 return -1;
578 return 0;
579}
580
581static inline void init_fat(BDRVVVFATState* s)
582{
a046433a
FB
583 if (s->fat_type == 12) {
584 array_init(&(s->fat),1);
585 array_ensure_allocated(&(s->fat),
586 s->sectors_per_fat * 0x200 * 3 / 2 - 1);
587 } else {
588 array_init(&(s->fat),(s->fat_type==32?4:2));
589 array_ensure_allocated(&(s->fat),
590 s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
591 }
de167e41 592 memset(s->fat.pointer,0,s->fat.size);
3b46e624 593
de167e41
FB
594 switch(s->fat_type) {
595 case 12: s->max_fat_value=0xfff; break;
596 case 16: s->max_fat_value=0xffff; break;
a046433a 597 case 32: s->max_fat_value=0x0fffffff; break;
de167e41
FB
598 default: s->max_fat_value=0; /* error... */
599 }
600
601}
602
a046433a
FB
603/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
604/* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
c227f099 605static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
a046433a 606 unsigned int directory_start, const char* filename, int is_dot)
de167e41 607{
a046433a 608 int i,j,long_index=s->directory.next;
c227f099
AL
609 direntry_t* entry = NULL;
610 direntry_t* entry_long = NULL;
de167e41
FB
611
612 if(is_dot) {
613 entry=array_get_next(&(s->directory));
f671d173 614 memset(entry->name, 0x20, sizeof(entry->name));
de167e41
FB
615 memcpy(entry->name,filename,strlen(filename));
616 return entry;
617 }
3b46e624 618
de167e41 619 entry_long=create_long_filename(s,filename);
3b46e624 620
5fafdf24 621 i = strlen(filename);
a046433a
FB
622 for(j = i - 1; j>0 && filename[j]!='.';j--);
623 if (j > 0)
624 i = (j > 8 ? 8 : j);
625 else if (i > 8)
626 i = 8;
627
de167e41 628 entry=array_get_next(&(s->directory));
f671d173 629 memset(entry->name, 0x20, sizeof(entry->name));
51a0f568 630 memcpy(entry->name, filename, i);
3b46e624 631
f671d173
SW
632 if (j > 0) {
633 for (i = 0; i < 3 && filename[j + 1 + i]; i++) {
634 entry->name[8 + i] = filename[j + 1 + i];
635 }
636 }
de167e41
FB
637
638 /* upcase & remove unwanted characters */
639 for(i=10;i>=0;i--) {
a046433a 640 if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
de167e41 641 if(entry->name[i]<=' ' || entry->name[i]>0x7f
a046433a 642 || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
de167e41
FB
643 entry->name[i]='_';
644 else if(entry->name[i]>='a' && entry->name[i]<='z')
645 entry->name[i]+='A'-'a';
646 }
647
648 /* mangle duplicates */
649 while(1) {
c227f099 650 direntry_t* entry1=array_get(&(s->directory),directory_start);
de167e41
FB
651 int j;
652
653 for(;entry1<entry;entry1++)
a046433a 654 if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
de167e41
FB
655 break; /* found dupe */
656 if(entry1==entry) /* no dupe found */
657 break;
658
5fafdf24 659 /* use all 8 characters of name */
de167e41
FB
660 if(entry->name[7]==' ') {
661 int j;
662 for(j=6;j>0 && entry->name[j]==' ';j--)
663 entry->name[j]='~';
664 }
665
666 /* increment number */
667 for(j=7;j>0 && entry->name[j]=='9';j--)
668 entry->name[j]='0';
669 if(j>0) {
670 if(entry->name[j]<'0' || entry->name[j]>'9')
671 entry->name[j]='0';
672 else
673 entry->name[j]++;
674 }
675 }
676
677 /* calculate checksum; propagate to long name */
678 if(entry_long) {
679 uint8_t chksum=fat_chksum(entry);
680
681 /* calculate anew, because realloc could have taken place */
682 entry_long=array_get(&(s->directory),long_index);
a046433a 683 while(entry_long<entry && is_long_name(entry_long)) {
de167e41
FB
684 entry_long->reserved[1]=chksum;
685 entry_long++;
686 }
687 }
688
689 return entry;
690}
691
a046433a
FB
692/*
693 * Read a directory. (the index of the corresponding mapping must be passed).
694 */
695static int read_directory(BDRVVVFATState* s, int mapping_index)
de167e41 696{
c227f099
AL
697 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
698 direntry_t* direntry;
a046433a
FB
699 const char* dirname = mapping->path;
700 int first_cluster = mapping->begin;
701 int parent_index = mapping->info.dir.parent_mapping_index;
c227f099 702 mapping_t* parent_mapping = (mapping_t*)
511d2b14 703 (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL);
a046433a 704 int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
de167e41
FB
705
706 DIR* dir=opendir(dirname);
707 struct dirent* entry;
de167e41
FB
708 int i;
709
a046433a
FB
710 assert(mapping->mode & MODE_DIRECTORY);
711
712 if(!dir) {
713 mapping->end = mapping->begin;
de167e41 714 return -1;
a046433a 715 }
3b46e624 716
a046433a
FB
717 i = mapping->info.dir.first_dir_index =
718 first_cluster == 0 ? 0 : s->directory.next;
719
5fafdf24 720 /* actually read the directory, and allocate the mappings */
de167e41
FB
721 while((entry=readdir(dir))) {
722 unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
723 char* buffer;
c227f099 724 direntry_t* direntry;
a046433a 725 struct stat st;
de167e41
FB
726 int is_dot=!strcmp(entry->d_name,".");
727 int is_dotdot=!strcmp(entry->d_name,"..");
728
a046433a 729 if(first_cluster == 0 && (is_dotdot || is_dot))
de167e41 730 continue;
5fafdf24 731
d4df3dbc 732 buffer = g_malloc(length);
de167e41
FB
733 snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
734
735 if(stat(buffer,&st)<0) {
ce137829 736 g_free(buffer);
de167e41
FB
737 continue;
738 }
739
740 /* create directory entry for this file */
a046433a
FB
741 direntry=create_short_and_long_name(s, i, entry->d_name,
742 is_dot || is_dotdot);
de167e41
FB
743 direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
744 direntry->reserved[0]=direntry->reserved[1]=0;
745 direntry->ctime=fat_datetime(st.st_ctime,1);
746 direntry->cdate=fat_datetime(st.st_ctime,0);
747 direntry->adate=fat_datetime(st.st_atime,0);
748 direntry->begin_hi=0;
749 direntry->mtime=fat_datetime(st.st_mtime,1);
750 direntry->mdate=fat_datetime(st.st_mtime,0);
751 if(is_dotdot)
a046433a 752 set_begin_of_direntry(direntry, first_cluster_of_parent);
de167e41 753 else if(is_dot)
a046433a 754 set_begin_of_direntry(direntry, first_cluster);
de167e41 755 else
a046433a
FB
756 direntry->begin=0; /* do that later */
757 if (st.st_size > 0x7fffffff) {
758 fprintf(stderr, "File %s is larger than 2GB\n", buffer);
ce137829 759 g_free(buffer);
08089edc 760 closedir(dir);
a046433a
FB
761 return -2;
762 }
763 direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
de167e41
FB
764
765 /* create mapping for this file */
a046433a 766 if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
d4df3dbc 767 s->current_mapping = array_get_next(&(s->mapping));
de167e41
FB
768 s->current_mapping->begin=0;
769 s->current_mapping->end=st.st_size;
a046433a
FB
770 /*
771 * we get the direntry of the most recent direntry, which
772 * contains the short name and all the relevant information.
773 */
de167e41 774 s->current_mapping->dir_index=s->directory.next-1;
a046433a
FB
775 s->current_mapping->first_mapping_index = -1;
776 if (S_ISDIR(st.st_mode)) {
777 s->current_mapping->mode = MODE_DIRECTORY;
778 s->current_mapping->info.dir.parent_mapping_index =
779 mapping_index;
780 } else {
781 s->current_mapping->mode = MODE_UNDEFINED;
782 s->current_mapping->info.file.offset = 0;
783 }
784 s->current_mapping->path=buffer;
785 s->current_mapping->read_only =
786 (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
b122c3b6
MA
787 } else {
788 g_free(buffer);
789 }
de167e41
FB
790 }
791 closedir(dir);
792
793 /* fill with zeroes up to the end of the cluster */
794 while(s->directory.next%(0x10*s->sectors_per_cluster)) {
c227f099
AL
795 direntry_t* direntry=array_get_next(&(s->directory));
796 memset(direntry,0,sizeof(direntry_t));
de167e41
FB
797 }
798
a046433a
FB
799/* TODO: if there are more entries, bootsector has to be adjusted! */
800#define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
801 if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
802 /* root directory */
803 int cur = s->directory.next;
804 array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
2b6a43a8 805 s->directory.next = ROOT_ENTRIES;
a046433a 806 memset(array_get(&(s->directory), cur), 0,
c227f099 807 (ROOT_ENTRIES - cur) * sizeof(direntry_t));
de167e41 808 }
5fafdf24 809
a046433a 810 /* reget the mapping, since s->mapping was possibly realloc()ed */
d4df3dbc 811 mapping = array_get(&(s->mapping), mapping_index);
a046433a
FB
812 first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
813 * 0x20 / s->cluster_size;
814 mapping->end = first_cluster;
815
d4df3dbc 816 direntry = array_get(&(s->directory), mapping->dir_index);
a046433a 817 set_begin_of_direntry(direntry, mapping->begin);
3b46e624 818
a046433a
FB
819 return 0;
820}
de167e41 821
a046433a
FB
822static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
823{
824 return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
825}
de167e41 826
a046433a
FB
827static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
828{
829 return s->faked_sectors + s->sectors_per_cluster * cluster_num;
830}
de167e41 831
a046433a 832static int init_directories(BDRVVVFATState* s,
d11c8917
MA
833 const char *dirname, int heads, int secs,
834 Error **errp)
de167e41 835{
c227f099
AL
836 bootsector_t* bootsector;
837 mapping_t* mapping;
de167e41
FB
838 unsigned int i;
839 unsigned int cluster;
840
841 memset(&(s->first_sectors[0]),0,0x40*0x200);
842
de167e41 843 s->cluster_size=s->sectors_per_cluster*0x200;
7267c094 844 s->cluster_buffer=g_malloc(s->cluster_size);
a046433a
FB
845
846 /*
847 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
848 * where sc is sector_count,
849 * spf is sectors_per_fat,
850 * spc is sectors_per_clusters, and
851 * fat_type = 12, 16 or 32.
852 */
853 i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
854 s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
3b46e624 855
c227f099
AL
856 array_init(&(s->mapping),sizeof(mapping_t));
857 array_init(&(s->directory),sizeof(direntry_t));
de167e41
FB
858
859 /* add volume label */
860 {
c227f099 861 direntry_t* entry=array_get_next(&(s->directory));
de167e41 862 entry->attributes=0x28; /* archive | volume label */
f671d173 863 memcpy(entry->name, "QEMU VVFAT ", sizeof(entry->name));
de167e41
FB
864 }
865
de167e41
FB
866 /* Now build FAT, and write back information into directory */
867 init_fat(s);
868
a046433a
FB
869 s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
870 s->cluster_count=sector2cluster(s, s->sector_count);
871
872 mapping = array_get_next(&(s->mapping));
873 mapping->begin = 0;
874 mapping->dir_index = 0;
875 mapping->info.dir.parent_mapping_index = -1;
876 mapping->first_mapping_index = -1;
7267c094 877 mapping->path = g_strdup(dirname);
a046433a
FB
878 i = strlen(mapping->path);
879 if (i > 0 && mapping->path[i - 1] == '/')
880 mapping->path[i - 1] = '\0';
881 mapping->mode = MODE_DIRECTORY;
882 mapping->read_only = 0;
883 s->path = mapping->path;
884
885 for (i = 0, cluster = 0; i < s->mapping.next; i++) {
5fafdf24 886 /* MS-DOS expects the FAT to be 0 for the root directory
a046433a
FB
887 * (except for the media byte). */
888 /* LATER TODO: still true for FAT32? */
889 int fix_fat = (i != 0);
890 mapping = array_get(&(s->mapping), i);
891
892 if (mapping->mode & MODE_DIRECTORY) {
893 mapping->begin = cluster;
894 if(read_directory(s, i)) {
d11c8917
MA
895 error_setg(errp, "Could not read directory %s",
896 mapping->path);
de167e41
FB
897 return -1;
898 }
a046433a
FB
899 mapping = array_get(&(s->mapping), i);
900 } else {
901 assert(mapping->mode == MODE_UNDEFINED);
de167e41 902 mapping->mode=MODE_NORMAL;
a046433a
FB
903 mapping->begin = cluster;
904 if (mapping->end > 0) {
c227f099 905 direntry_t* direntry = array_get(&(s->directory),
a046433a
FB
906 mapping->dir_index);
907
908 mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
909 set_begin_of_direntry(direntry, mapping->begin);
910 } else {
911 mapping->end = cluster + 1;
912 fix_fat = 0;
de167e41 913 }
a046433a
FB
914 }
915
916 assert(mapping->begin < mapping->end);
917
8ce0f869
AZ
918 /* next free cluster */
919 cluster = mapping->end;
920
921 if(cluster > s->cluster_count) {
d11c8917
MA
922 error_setg(errp,
923 "Directory does not fit in FAT%d (capacity %.2f MB)",
924 s->fat_type, s->sector_count / 2000.0);
925 return -1;
8ce0f869
AZ
926 }
927
a046433a
FB
928 /* fix fat for entry */
929 if (fix_fat) {
8ce0f869 930 int j;
a046433a
FB
931 for(j = mapping->begin; j < mapping->end - 1; j++)
932 fat_set(s, j, j+1);
933 fat_set(s, mapping->end - 1, s->max_fat_value);
934 }
de167e41
FB
935 }
936
a046433a
FB
937 mapping = array_get(&(s->mapping), 0);
938 s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
939 s->last_cluster_of_root_directory = mapping->end;
940
941 /* the FAT signature */
942 fat_set(s,0,s->max_fat_value);
943 fat_set(s,1,s->max_fat_value);
de167e41 944
a046433a
FB
945 s->current_mapping = NULL;
946
c227f099 947 bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
de167e41
FB
948 bootsector->jump[0]=0xeb;
949 bootsector->jump[1]=0x3e;
950 bootsector->jump[2]=0x90;
951 memcpy(bootsector->name,"QEMU ",8);
952 bootsector->sector_size=cpu_to_le16(0x200);
953 bootsector->sectors_per_cluster=s->sectors_per_cluster;
954 bootsector->reserved_sectors=cpu_to_le16(1);
955 bootsector->number_of_fats=0x2; /* number of FATs */
956 bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
a046433a 957 bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
aad37c06 958 bootsector->media_type=(s->first_sectors_number>1?0xf8:0xf0); /* media descriptor (f8=hd, f0=3.5 fd)*/
a046433a 959 s->fat.pointer[0] = bootsector->media_type;
de167e41 960 bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
4480e0f9
MA
961 bootsector->sectors_per_track = cpu_to_le16(secs);
962 bootsector->number_of_heads = cpu_to_le16(heads);
de167e41 963 bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
a046433a 964 bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
de167e41 965
a046433a 966 /* LATER TODO: if FAT32, this is wrong */
aad37c06 967 bootsector->u.fat16.drive_number=s->first_sectors_number==1?0:0x80; /* fda=0, hda=0x80 */
de167e41
FB
968 bootsector->u.fat16.current_head=0;
969 bootsector->u.fat16.signature=0x29;
970 bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
971
972 memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
973 memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12 ":s->fat_type==16?"FAT16 ":"FAT32 "),8);
974 bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
975
976 return 0;
977}
978
83f64091 979#ifdef DEBUG
a046433a 980static BDRVVVFATState *vvv = NULL;
83f64091 981#endif
a046433a 982
68c70af1 983static int enable_write_target(BDRVVVFATState *s, Error **errp);
a046433a
FB
984static int is_consistent(BDRVVVFATState *s);
985
e023b2e2
PB
986static void vvfat_rebind(BlockDriverState *bs)
987{
988 BDRVVVFATState *s = bs->opaque;
989 s->bs = bs;
990}
991
7ad9be64
KW
992static QemuOptsList runtime_opts = {
993 .name = "vvfat",
994 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
995 .desc = {
996 {
997 .name = "dir",
998 .type = QEMU_OPT_STRING,
999 .help = "Host directory to map to the vvfat device",
1000 },
1001 {
1002 .name = "fat-type",
1003 .type = QEMU_OPT_NUMBER,
1004 .help = "FAT type (12, 16 or 32)",
1005 },
1006 {
1007 .name = "floppy",
1008 .type = QEMU_OPT_BOOL,
1009 .help = "Create a floppy rather than a hard disk image",
1010 },
1011 {
1012 .name = "rw",
1013 .type = QEMU_OPT_BOOL,
1014 .help = "Make the image writable",
1015 },
1016 { /* end of list */ }
1017 },
1018};
1019
1020static void vvfat_parse_filename(const char *filename, QDict *options,
1021 Error **errp)
1022{
1023 int fat_type = 0;
1024 bool floppy = false;
1025 bool rw = false;
1026 int i;
1027
1028 if (!strstart(filename, "fat:", NULL)) {
1029 error_setg(errp, "File name string must start with 'fat:'");
1030 return;
1031 }
1032
1033 /* Parse options */
1034 if (strstr(filename, ":32:")) {
1035 fat_type = 32;
1036 } else if (strstr(filename, ":16:")) {
1037 fat_type = 16;
1038 } else if (strstr(filename, ":12:")) {
1039 fat_type = 12;
1040 }
1041
1042 if (strstr(filename, ":floppy:")) {
1043 floppy = true;
1044 }
1045
1046 if (strstr(filename, ":rw:")) {
1047 rw = true;
1048 }
1049
1050 /* Get the directory name without options */
1051 i = strrchr(filename, ':') - filename;
1052 assert(i >= 3);
1053 if (filename[i - 2] == ':' && qemu_isalpha(filename[i - 1])) {
1054 /* workaround for DOS drive names */
1055 filename += i - 1;
1056 } else {
1057 filename += i + 1;
1058 }
1059
1060 /* Fill in the options QDict */
1061 qdict_put(options, "dir", qstring_from_str(filename));
1062 qdict_put(options, "fat-type", qint_from_int(fat_type));
fc48ffc3
EB
1063 qdict_put(options, "floppy", qbool_from_bool(floppy));
1064 qdict_put(options, "rw", qbool_from_bool(rw));
7ad9be64
KW
1065}
1066
015a1036
HR
1067static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
1068 Error **errp)
de167e41
FB
1069{
1070 BDRVVVFATState *s = bs->opaque;
7ad9be64
KW
1071 int cyls, heads, secs;
1072 bool floppy;
1073 const char *dirname;
1074 QemuOpts *opts;
1075 Error *local_err = NULL;
1076 int ret;
de167e41 1077
83f64091 1078#ifdef DEBUG
a046433a 1079 vvv = s;
83f64091 1080#endif
a046433a 1081
87ea75d5 1082 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
7ad9be64 1083 qemu_opts_absorb_qdict(opts, options, &local_err);
84d18f06 1084 if (local_err) {
c0f92b52 1085 error_propagate(errp, local_err);
7ad9be64
KW
1086 ret = -EINVAL;
1087 goto fail;
1088 }
1089
1090 dirname = qemu_opt_get(opts, "dir");
1091 if (!dirname) {
c0f92b52 1092 error_setg(errp, "vvfat block driver requires a 'dir' option");
7ad9be64
KW
1093 ret = -EINVAL;
1094 goto fail;
1095 }
1096
1097 s->fat_type = qemu_opt_get_number(opts, "fat-type", 0);
1098 floppy = qemu_opt_get_bool(opts, "floppy", false);
1099
1100 if (floppy) {
1101 /* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */
1102 if (!s->fat_type) {
1103 s->fat_type = 12;
1104 secs = 36;
1105 s->sectors_per_cluster = 2;
1106 } else {
1107 secs = s->fat_type == 12 ? 18 : 36;
1108 s->sectors_per_cluster = 1;
1109 }
1110 s->first_sectors_number = 1;
1111 cyls = 80;
1112 heads = 2;
1113 } else {
1114 /* 32MB or 504MB disk*/
1115 if (!s->fat_type) {
1116 s->fat_type = 16;
1117 }
4c709660 1118 s->first_sectors_number = 0x40;
7ad9be64
KW
1119 cyls = s->fat_type == 12 ? 64 : 1024;
1120 heads = 16;
1121 secs = 63;
1122 }
1123
1124 switch (s->fat_type) {
1125 case 32:
1126 fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. "
1127 "You are welcome to do so!\n");
1128 break;
1129 case 16:
1130 case 12:
1131 break;
1132 default:
c0f92b52 1133 error_setg(errp, "Valid FAT types are only 12, 16 and 32");
7ad9be64
KW
1134 ret = -EINVAL;
1135 goto fail;
1136 }
1137
1138
a046433a
FB
1139 s->bs = bs;
1140
a046433a 1141 /* LATER TODO: if FAT32, adjust */
a046433a 1142 s->sectors_per_cluster=0x10;
de167e41
FB
1143
1144 s->current_cluster=0xffffffff;
de167e41 1145
a046433a
FB
1146 /* read only is the default for safety */
1147 bs->read_only = 1;
1148 s->qcow = s->write_target = NULL;
1149 s->qcow_filename = NULL;
1150 s->fat2 = NULL;
1151 s->downcase_short_names = 1;
3b46e624 1152
4480e0f9
MA
1153 fprintf(stderr, "vvfat %s chs %d,%d,%d\n",
1154 dirname, cyls, heads, secs);
a046433a 1155
4480e0f9 1156 s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
5a742b55 1157
7ad9be64 1158 if (qemu_opt_get_bool(opts, "rw", false)) {
68c70af1 1159 ret = enable_write_target(s, errp);
78f27bd0 1160 if (ret < 0) {
7ad9be64
KW
1161 goto fail;
1162 }
1163 bs->read_only = 0;
b570094d
TS
1164 }
1165
4480e0f9 1166 bs->total_sectors = cyls * heads * secs;
b570094d 1167
d11c8917 1168 if (init_directories(s, dirname, heads, secs, errp)) {
7ad9be64
KW
1169 ret = -EIO;
1170 goto fail;
4480e0f9 1171 }
de167e41 1172
b570094d
TS
1173 s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
1174
4480e0f9
MA
1175 if (s->first_sectors_number == 0x40) {
1176 init_mbr(s, cyls, heads, secs);
273e4e03 1177 }
a046433a
FB
1178
1179 // assert(is_consistent(s));
848c66e8 1180 qemu_co_mutex_init(&s->lock);
3397f0cb
KW
1181
1182 /* Disable migration when vvfat is used rw */
1183 if (s->qcow) {
81e5f78a
AG
1184 error_setg(&s->migration_blocker,
1185 "The vvfat (rw) format used by node '%s' "
1186 "does not support live migration",
1187 bdrv_get_device_or_node_name(bs));
3397f0cb
KW
1188 migrate_add_blocker(s->migration_blocker);
1189 }
1190
7ad9be64
KW
1191 ret = 0;
1192fail:
1193 qemu_opts_del(opts);
1194 return ret;
de167e41
FB
1195}
1196
1197static inline void vvfat_close_current_file(BDRVVVFATState *s)
1198{
1199 if(s->current_mapping) {
a046433a
FB
1200 s->current_mapping = NULL;
1201 if (s->current_fd) {
2e1e79da 1202 qemu_close(s->current_fd);
a046433a
FB
1203 s->current_fd = 0;
1204 }
de167e41 1205 }
a046433a 1206 s->current_cluster = -1;
de167e41
FB
1207}
1208
1209/* mappings between index1 and index2-1 are supposed to be ordered
1210 * return value is the index of the last mapping for which end>cluster_num
1211 */
1212static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1213{
de167e41 1214 while(1) {
88bf7950 1215 int index3;
c227f099 1216 mapping_t* mapping;
de167e41
FB
1217 index3=(index1+index2)/2;
1218 mapping=array_get(&(s->mapping),index3);
a046433a
FB
1219 assert(mapping->begin < mapping->end);
1220 if(mapping->begin>=cluster_num) {
de167e41
FB
1221 assert(index2!=index3 || index2==0);
1222 if(index2==index3)
a046433a 1223 return index1;
de167e41
FB
1224 index2=index3;
1225 } else {
1226 if(index1==index3)
a046433a 1227 return mapping->end<=cluster_num ? index2 : index1;
de167e41
FB
1228 index1=index3;
1229 }
1230 assert(index1<=index2);
a046433a
FB
1231 DLOG(mapping=array_get(&(s->mapping),index1);
1232 assert(mapping->begin<=cluster_num);
5fafdf24 1233 assert(index2 >= s->mapping.next ||
a046433a
FB
1234 ((mapping = array_get(&(s->mapping),index2)) &&
1235 mapping->end>cluster_num)));
de167e41
FB
1236 }
1237}
1238
c227f099 1239static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
de167e41
FB
1240{
1241 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
c227f099 1242 mapping_t* mapping;
de167e41 1243 if(index>=s->mapping.next)
511d2b14 1244 return NULL;
de167e41
FB
1245 mapping=array_get(&(s->mapping),index);
1246 if(mapping->begin>cluster_num)
511d2b14 1247 return NULL;
a046433a 1248 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
de167e41
FB
1249 return mapping;
1250}
1251
c227f099 1252static int open_file(BDRVVVFATState* s,mapping_t* mapping)
de167e41
FB
1253{
1254 if(!mapping)
1255 return -1;
de167e41 1256 if(!s->current_mapping ||
a046433a 1257 strcmp(s->current_mapping->path,mapping->path)) {
de167e41 1258 /* open file */
6165f4d8 1259 int fd = qemu_open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
de167e41
FB
1260 if(fd<0)
1261 return -1;
1262 vvfat_close_current_file(s);
1263 s->current_fd = fd;
de167e41
FB
1264 s->current_mapping = mapping;
1265 }
1266 return 0;
1267}
1268
1269static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1270{
1271 if(s->current_cluster != cluster_num) {
1272 int result=0;
1273 off_t offset;
a046433a 1274 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
de167e41
FB
1275 if(!s->current_mapping
1276 || s->current_mapping->begin>cluster_num
1277 || s->current_mapping->end<=cluster_num) {
1278 /* binary search of mappings for file */
c227f099 1279 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
a046433a
FB
1280
1281 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1282
1283 if (mapping && mapping->mode & MODE_DIRECTORY) {
1284 vvfat_close_current_file(s);
1285 s->current_mapping = mapping;
1286read_cluster_directory:
1287 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
ffe8ab83 1288 s->cluster = (unsigned char*)s->directory.pointer+offset
a046433a
FB
1289 + 0x20*s->current_mapping->info.dir.first_dir_index;
1290 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1291 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1292 s->current_cluster = cluster_num;
1293 return 0;
1294 }
1295
1296 if(open_file(s,mapping))
de167e41 1297 return -2;
a046433a
FB
1298 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1299 goto read_cluster_directory;
de167e41 1300
a046433a
FB
1301 assert(s->current_fd);
1302
1303 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
de167e41
FB
1304 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1305 return -3;
a046433a 1306 s->cluster=s->cluster_buffer;
de167e41
FB
1307 result=read(s->current_fd,s->cluster,s->cluster_size);
1308 if(result<0) {
1309 s->current_cluster = -1;
1310 return -1;
1311 }
1312 s->current_cluster = cluster_num;
1313 }
1314 return 0;
1315}
1316
a046433a 1317#ifdef DEBUG
c227f099 1318static void print_direntry(const direntry_t* direntry)
de167e41 1319{
a046433a
FB
1320 int j = 0;
1321 char buffer[1024];
1322
3e89cb04 1323 fprintf(stderr, "direntry %p: ", direntry);
de167e41
FB
1324 if(!direntry)
1325 return;
a046433a 1326 if(is_long_name(direntry)) {
de167e41
FB
1327 unsigned char* c=(unsigned char*)direntry;
1328 int i;
1329 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
3891b370 1330#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
a046433a 1331 ADD_CHAR(c[i]);
de167e41 1332 for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
a046433a 1333 ADD_CHAR(c[i]);
de167e41 1334 for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
a046433a
FB
1335 ADD_CHAR(c[i]);
1336 buffer[j] = 0;
1337 fprintf(stderr, "%s\n", buffer);
de167e41
FB
1338 } else {
1339 int i;
1340 for(i=0;i<11;i++)
a046433a
FB
1341 ADD_CHAR(direntry->name[i]);
1342 buffer[j] = 0;
1343 fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1344 buffer,
de167e41 1345 direntry->attributes,
a046433a 1346 begin_of_direntry(direntry),le32_to_cpu(direntry->size));
de167e41
FB
1347 }
1348}
1349
c227f099 1350static void print_mapping(const mapping_t* mapping)
de167e41 1351{
3e89cb04
KW
1352 fprintf(stderr, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1353 "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1354 mapping, mapping->begin, mapping->end, mapping->dir_index,
1355 mapping->first_mapping_index, mapping->path, mapping->mode);
1356
a046433a
FB
1357 if (mapping->mode & MODE_DIRECTORY)
1358 fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1359 else
1360 fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
de167e41 1361}
a046433a 1362#endif
de167e41 1363
5fafdf24 1364static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
a046433a 1365 uint8_t *buf, int nb_sectors)
de167e41 1366{
a046433a 1367 BDRVVVFATState *s = bs->opaque;
de167e41 1368 int i;
de167e41 1369
a046433a 1370 for(i=0;i<nb_sectors;i++,sector_num++) {
e654bfe4 1371 if (sector_num >= bs->total_sectors)
a046433a
FB
1372 return -1;
1373 if (s->qcow) {
1374 int n;
7704df98 1375 if (bdrv_is_allocated(s->qcow, sector_num, nb_sectors-i, &n)) {
a046433a 1376DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
7704df98
KW
1377 if (bdrv_read(s->qcow, sector_num, buf + i*0x200, n)) {
1378 return -1;
1379 }
1380 i += n - 1;
1381 sector_num += n - 1;
1382 continue;
1383 }
a046433a 1384DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
de167e41 1385 }
a046433a
FB
1386 if(sector_num<s->faked_sectors) {
1387 if(sector_num<s->first_sectors_number)
1388 memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
1389 else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
1390 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
1391 else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
1392 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
1393 } else {
1394 uint32_t sector=sector_num-s->faked_sectors,
1395 sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1396 cluster_num=sector/s->sectors_per_cluster;
e654bfe4 1397 if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) {
a046433a
FB
1398 /* LATER TODO: strict: return -1; */
1399 memset(buf+i*0x200,0,0x200);
1400 continue;
de167e41 1401 }
a046433a 1402 memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
de167e41
FB
1403 }
1404 }
de167e41
FB
1405 return 0;
1406}
1407
2914caa0
PB
1408static coroutine_fn int vvfat_co_read(BlockDriverState *bs, int64_t sector_num,
1409 uint8_t *buf, int nb_sectors)
1410{
1411 int ret;
1412 BDRVVVFATState *s = bs->opaque;
1413 qemu_co_mutex_lock(&s->lock);
1414 ret = vvfat_read(bs, sector_num, buf, nb_sectors);
1415 qemu_co_mutex_unlock(&s->lock);
1416 return ret;
1417}
1418
a046433a 1419/* LATER TODO: statify all functions */
de167e41 1420
a046433a
FB
1421/*
1422 * Idea of the write support (use snapshot):
de167e41 1423 *
a046433a
FB
1424 * 1. check if all data is consistent, recording renames, modifications,
1425 * new files and directories (in s->commits).
de167e41 1426 *
a046433a 1427 * 2. if the data is not consistent, stop committing
de167e41 1428 *
a046433a
FB
1429 * 3. handle renames, and create new files and directories (do not yet
1430 * write their contents)
de167e41 1431 *
a046433a
FB
1432 * 4. walk the directories, fixing the mapping and direntries, and marking
1433 * the handled mappings as not deleted
de167e41 1434 *
a046433a 1435 * 5. commit the contents of the files
de167e41 1436 *
a046433a 1437 * 6. handle deleted files and directories
de167e41
FB
1438 *
1439 */
1440
c227f099 1441typedef struct commit_t {
a046433a
FB
1442 char* path;
1443 union {
1444 struct { uint32_t cluster; } rename;
1445 struct { int dir_index; uint32_t modified_offset; } writeout;
1446 struct { uint32_t first_cluster; } new_file;
1447 struct { uint32_t cluster; } mkdir;
1448 } param;
1449 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1450 enum {
1451 ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1452 } action;
c227f099 1453} commit_t;
de167e41 1454
a046433a 1455static void clear_commits(BDRVVVFATState* s)
de167e41
FB
1456{
1457 int i;
a046433a
FB
1458DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1459 for (i = 0; i < s->commits.next; i++) {
c227f099 1460 commit_t* commit = array_get(&(s->commits), i);
a046433a
FB
1461 assert(commit->path || commit->action == ACTION_WRITEOUT);
1462 if (commit->action != ACTION_WRITEOUT) {
1463 assert(commit->path);
ce137829 1464 g_free(commit->path);
a046433a
FB
1465 } else
1466 assert(commit->path == NULL);
de167e41 1467 }
a046433a 1468 s->commits.next = 0;
de167e41
FB
1469}
1470
a046433a
FB
1471static void schedule_rename(BDRVVVFATState* s,
1472 uint32_t cluster, char* new_path)
de167e41 1473{
c227f099 1474 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1475 commit->path = new_path;
1476 commit->param.rename.cluster = cluster;
1477 commit->action = ACTION_RENAME;
de167e41
FB
1478}
1479
a046433a
FB
1480static void schedule_writeout(BDRVVVFATState* s,
1481 int dir_index, uint32_t modified_offset)
de167e41 1482{
c227f099 1483 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1484 commit->path = NULL;
1485 commit->param.writeout.dir_index = dir_index;
1486 commit->param.writeout.modified_offset = modified_offset;
1487 commit->action = ACTION_WRITEOUT;
de167e41
FB
1488}
1489
a046433a
FB
1490static void schedule_new_file(BDRVVVFATState* s,
1491 char* path, uint32_t first_cluster)
de167e41 1492{
c227f099 1493 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1494 commit->path = path;
1495 commit->param.new_file.first_cluster = first_cluster;
1496 commit->action = ACTION_NEW_FILE;
1497}
1498
1499static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1500{
c227f099 1501 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1502 commit->path = path;
1503 commit->param.mkdir.cluster = cluster;
1504 commit->action = ACTION_MKDIR;
1505}
1506
1507typedef struct {
64eaabda
TS
1508 /*
1509 * Since the sequence number is at most 0x3f, and the filename
1510 * length is at most 13 times the sequence number, the maximal
1511 * filename length is 0x3f * 13 bytes.
1512 */
1513 unsigned char name[0x3f * 13 + 1];
a046433a
FB
1514 int checksum, len;
1515 int sequence_number;
1516} long_file_name;
1517
1518static void lfn_init(long_file_name* lfn)
1519{
1520 lfn->sequence_number = lfn->len = 0;
1521 lfn->checksum = 0x100;
1522}
1523
1524/* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1525static int parse_long_name(long_file_name* lfn,
c227f099 1526 const direntry_t* direntry)
a046433a
FB
1527{
1528 int i, j, offset;
1529 const unsigned char* pointer = (const unsigned char*)direntry;
1530
1531 if (!is_long_name(direntry))
1532 return 1;
1533
1534 if (pointer[0] & 0x40) {
1535 lfn->sequence_number = pointer[0] & 0x3f;
1536 lfn->checksum = pointer[13];
1537 lfn->name[0] = 0;
59fdb018 1538 lfn->name[lfn->sequence_number * 13] = 0;
a046433a
FB
1539 } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
1540 return -1;
1541 else if (pointer[13] != lfn->checksum)
1542 return -2;
1543 else if (pointer[12] || pointer[26] || pointer[27])
1544 return -3;
1545
1546 offset = 13 * (lfn->sequence_number - 1);
1547 for (i = 0, j = 1; i < 13; i++, j+=2) {
1548 if (j == 11)
1549 j = 14;
1550 else if (j == 26)
1551 j = 28;
1552
1553 if (pointer[j+1] == 0)
1554 lfn->name[offset + i] = pointer[j];
1555 else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1556 return -4;
1557 else
1558 lfn->name[offset + i] = 0;
de167e41 1559 }
a046433a
FB
1560
1561 if (pointer[0] & 0x40)
ffe8ab83 1562 lfn->len = offset + strlen((char*)lfn->name + offset);
a046433a 1563
de167e41
FB
1564 return 0;
1565}
1566
a046433a
FB
1567/* returns 0 if successful, >0 if no short_name, and <0 on error */
1568static int parse_short_name(BDRVVVFATState* s,
c227f099 1569 long_file_name* lfn, direntry_t* direntry)
de167e41 1570{
a046433a 1571 int i, j;
de167e41 1572
a046433a
FB
1573 if (!is_short_name(direntry))
1574 return 1;
1575
1576 for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1577 for (i = 0; i <= j; i++) {
1578 if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
1579 return -1;
1580 else if (s->downcase_short_names)
47398b9c 1581 lfn->name[i] = qemu_tolower(direntry->name[i]);
a046433a
FB
1582 else
1583 lfn->name[i] = direntry->name[i];
de167e41
FB
1584 }
1585
f671d173
SW
1586 for (j = 2; j >= 0 && direntry->name[8 + j] == ' '; j--) {
1587 }
a046433a
FB
1588 if (j >= 0) {
1589 lfn->name[i++] = '.';
1590 lfn->name[i + j + 1] = '\0';
1591 for (;j >= 0; j--) {
f671d173
SW
1592 uint8_t c = direntry->name[8 + j];
1593 if (c <= ' ' || c > 0x7f) {
1594 return -2;
1595 } else if (s->downcase_short_names) {
1596 lfn->name[i + j] = qemu_tolower(c);
1597 } else {
1598 lfn->name[i + j] = c;
1599 }
a046433a
FB
1600 }
1601 } else
1602 lfn->name[i + j + 1] = '\0';
1603
ffe8ab83 1604 lfn->len = strlen((char*)lfn->name);
a046433a
FB
1605
1606 return 0;
de167e41
FB
1607}
1608
a046433a
FB
1609static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1610 unsigned int cluster)
de167e41 1611{
a046433a
FB
1612 if (cluster < s->last_cluster_of_root_directory) {
1613 if (cluster + 1 == s->last_cluster_of_root_directory)
1614 return s->max_fat_value;
1615 else
1616 return cluster + 1;
1617 }
1618
1619 if (s->fat_type==32) {
1620 uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1621 return le32_to_cpu(*entry);
1622 } else if (s->fat_type==16) {
1623 uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1624 return le16_to_cpu(*entry);
1625 } else {
1626 const uint8_t* x=s->fat2+cluster*3/2;
1627 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1628 }
1629}
1630
1631static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1632{
1633 int was_modified = 0;
1634 int i, dummy;
1635
1636 if (s->qcow == NULL)
de167e41 1637 return 0;
a046433a
FB
1638
1639 for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
7704df98 1640 was_modified = bdrv_is_allocated(s->qcow,
a046433a
FB
1641 cluster2sector(s, cluster_num) + i, 1, &dummy);
1642
1643 return was_modified;
de167e41
FB
1644}
1645
a046433a 1646static const char* get_basename(const char* path)
de167e41 1647{
a046433a
FB
1648 char* basename = strrchr(path, '/');
1649 if (basename == NULL)
1650 return path;
1651 else
1652 return basename + 1; /* strip '/' */
de167e41
FB
1653}
1654
a046433a
FB
1655/*
1656 * The array s->used_clusters holds the states of the clusters. If it is
1657 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1658 * was modified, bit 3 is set.
1659 * If any cluster is allocated, but not part of a file or directory, this
1660 * driver refuses to commit.
1661 */
1662typedef enum {
1663 USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
c227f099 1664} used_t;
de167e41 1665
a046433a
FB
1666/*
1667 * get_cluster_count_for_direntry() not only determines how many clusters
1668 * are occupied by direntry, but also if it was renamed or modified.
1669 *
1670 * A file is thought to be renamed *only* if there already was a file with
1671 * exactly the same first cluster, but a different name.
1672 *
1673 * Further, the files/directories handled by this function are
1674 * assumed to be *not* deleted (and *only* those).
1675 */
1676static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
c227f099 1677 direntry_t* direntry, const char* path)
de167e41 1678{
a046433a
FB
1679 /*
1680 * This is a little bit tricky:
1681 * IF the guest OS just inserts a cluster into the file chain,
1682 * and leaves the rest alone, (i.e. the original file had clusters
1683 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1684 *
1685 * - do_commit will write the cluster into the file at the given
1686 * offset, but
1687 *
1688 * - the cluster which is overwritten should be moved to a later
1689 * position in the file.
1690 *
1691 * I am not aware that any OS does something as braindead, but this
1692 * situation could happen anyway when not committing for a long time.
1693 * Just to be sure that this does not bite us, detect it, and copy the
1694 * contents of the clusters to-be-overwritten into the qcow.
1695 */
1696 int copy_it = 0;
1697 int was_modified = 0;
1698 int32_t ret = 0;
1699
1700 uint32_t cluster_num = begin_of_direntry(direntry);
1701 uint32_t offset = 0;
1702 int first_mapping_index = -1;
c227f099 1703 mapping_t* mapping = NULL;
a046433a 1704 const char* basename2 = NULL;
de167e41 1705
a046433a 1706 vvfat_close_current_file(s);
de167e41 1707
a046433a
FB
1708 /* the root directory */
1709 if (cluster_num == 0)
de167e41 1710 return 0;
de167e41 1711
a046433a
FB
1712 /* write support */
1713 if (s->qcow) {
1714 basename2 = get_basename(path);
de167e41 1715
a046433a
FB
1716 mapping = find_mapping_for_cluster(s, cluster_num);
1717
1718 if (mapping) {
da2414e9
FB
1719 const char* basename;
1720
a046433a
FB
1721 assert(mapping->mode & MODE_DELETED);
1722 mapping->mode &= ~MODE_DELETED;
1723
da2414e9 1724 basename = get_basename(mapping->path);
a046433a
FB
1725
1726 assert(mapping->mode & MODE_NORMAL);
1727
1728 /* rename */
1729 if (strcmp(basename, basename2))
7267c094 1730 schedule_rename(s, cluster_num, g_strdup(path));
a046433a
FB
1731 } else if (is_file(direntry))
1732 /* new file */
7267c094 1733 schedule_new_file(s, g_strdup(path), cluster_num);
a046433a 1734 else {
43dc2a64 1735 abort();
a046433a
FB
1736 return 0;
1737 }
de167e41
FB
1738 }
1739
a046433a
FB
1740 while(1) {
1741 if (s->qcow) {
1742 if (!copy_it && cluster_was_modified(s, cluster_num)) {
1743 if (mapping == NULL ||
1744 mapping->begin > cluster_num ||
1745 mapping->end <= cluster_num)
1746 mapping = find_mapping_for_cluster(s, cluster_num);
de167e41 1747
a046433a
FB
1748
1749 if (mapping &&
1750 (mapping->mode & MODE_DIRECTORY) == 0) {
1751
1752 /* was modified in qcow */
1753 if (offset != mapping->info.file.offset + s->cluster_size
1754 * (cluster_num - mapping->begin)) {
1755 /* offset of this cluster in file chain has changed */
43dc2a64 1756 abort();
a046433a
FB
1757 copy_it = 1;
1758 } else if (offset == 0) {
1759 const char* basename = get_basename(mapping->path);
1760
1761 if (strcmp(basename, basename2))
1762 copy_it = 1;
1763 first_mapping_index = array_index(&(s->mapping), mapping);
1764 }
1765
1766 if (mapping->first_mapping_index != first_mapping_index
1767 && mapping->info.file.offset > 0) {
43dc2a64 1768 abort();
a046433a
FB
1769 copy_it = 1;
1770 }
1771
1772 /* need to write out? */
1773 if (!was_modified && is_file(direntry)) {
1774 was_modified = 1;
1775 schedule_writeout(s, mapping->dir_index, offset);
1776 }
1777 }
1778 }
1779
1780 if (copy_it) {
1781 int i, dummy;
1782 /*
1783 * This is horribly inefficient, but that is okay, since
1784 * it is rarely executed, if at all.
1785 */
1786 int64_t offset = cluster2sector(s, cluster_num);
1787
1788 vvfat_close_current_file(s);
7704df98
KW
1789 for (i = 0; i < s->sectors_per_cluster; i++) {
1790 if (!bdrv_is_allocated(s->qcow, offset + i, 1, &dummy)) {
1791 if (vvfat_read(s->bs, offset, s->cluster_buffer, 1)) {
1792 return -1;
1793 }
1794 if (bdrv_write(s->qcow, offset, s->cluster_buffer, 1)) {
1795 return -2;
1796 }
1797 }
1798 }
a046433a
FB
1799 }
1800 }
1801
1802 ret++;
1803 if (s->used_clusters[cluster_num] & USED_ANY)
1804 return 0;
1805 s->used_clusters[cluster_num] = USED_FILE;
1806
1807 cluster_num = modified_fat_get(s, cluster_num);
1808
1809 if (fat_eof(s, cluster_num))
1810 return ret;
1811 else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
1812 return -1;
1813
1814 offset += s->cluster_size;
1815 }
de167e41
FB
1816}
1817
a046433a 1818/*
5fafdf24 1819 * This function looks at the modified data (qcow).
a046433a
FB
1820 * It returns 0 upon inconsistency or error, and the number of clusters
1821 * used by the directory, its subdirectories and their files.
1822 */
1823static int check_directory_consistency(BDRVVVFATState *s,
1824 int cluster_num, const char* path)
de167e41 1825{
a046433a 1826 int ret = 0;
7267c094 1827 unsigned char* cluster = g_malloc(s->cluster_size);
c227f099
AL
1828 direntry_t* direntries = (direntry_t*)cluster;
1829 mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
a046433a
FB
1830
1831 long_file_name lfn;
1832 int path_len = strlen(path);
0d460d6f 1833 char path2[PATH_MAX + 1];
a046433a
FB
1834
1835 assert(path_len < PATH_MAX); /* len was tested before! */
363a37d5 1836 pstrcpy(path2, sizeof(path2), path);
a046433a
FB
1837 path2[path_len] = '/';
1838 path2[path_len + 1] = '\0';
1839
1840 if (mapping) {
1841 const char* basename = get_basename(mapping->path);
1842 const char* basename2 = get_basename(path);
1843
1844 assert(mapping->mode & MODE_DIRECTORY);
1845
1846 assert(mapping->mode & MODE_DELETED);
1847 mapping->mode &= ~MODE_DELETED;
1848
1849 if (strcmp(basename, basename2))
7267c094 1850 schedule_rename(s, cluster_num, g_strdup(path));
a046433a
FB
1851 } else
1852 /* new directory */
7267c094 1853 schedule_mkdir(s, cluster_num, g_strdup(path));
3b46e624 1854
a046433a
FB
1855 lfn_init(&lfn);
1856 do {
de167e41 1857 int i;
a046433a
FB
1858 int subret = 0;
1859
1860 ret++;
1861
1862 if (s->used_clusters[cluster_num] & USED_ANY) {
1863 fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
6262bbd3 1864 goto fail;
a046433a
FB
1865 }
1866 s->used_clusters[cluster_num] = USED_DIRECTORY;
1867
1868DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
1869 subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
1870 s->sectors_per_cluster);
1871 if (subret) {
1872 fprintf(stderr, "Error fetching direntries\n");
1873 fail:
ce137829 1874 g_free(cluster);
a046433a
FB
1875 return 0;
1876 }
1877
1878 for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
3f4cb3d3 1879 int cluster_count = 0;
a046433a 1880
b2bedb21 1881DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i));
a046433a
FB
1882 if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
1883 is_free(direntries + i))
1884 continue;
1885
1886 subret = parse_long_name(&lfn, direntries + i);
1887 if (subret < 0) {
1888 fprintf(stderr, "Error in long name\n");
1889 goto fail;
de167e41 1890 }
a046433a
FB
1891 if (subret == 0 || is_free(direntries + i))
1892 continue;
1893
1894 if (fat_chksum(direntries+i) != lfn.checksum) {
1895 subret = parse_short_name(s, &lfn, direntries + i);
1896 if (subret < 0) {
1897 fprintf(stderr, "Error in short name (%d)\n", subret);
1898 goto fail;
1899 }
ffe8ab83
TS
1900 if (subret > 0 || !strcmp((char*)lfn.name, ".")
1901 || !strcmp((char*)lfn.name, ".."))
a046433a
FB
1902 continue;
1903 }
1904 lfn.checksum = 0x100; /* cannot use long name twice */
1905
1906 if (path_len + 1 + lfn.len >= PATH_MAX) {
1907 fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
1908 goto fail;
1909 }
363a37d5
BS
1910 pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
1911 (char*)lfn.name);
a046433a
FB
1912
1913 if (is_directory(direntries + i)) {
1914 if (begin_of_direntry(direntries + i) == 0) {
1915 DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
1916 goto fail;
1917 }
1918 cluster_count = check_directory_consistency(s,
1919 begin_of_direntry(direntries + i), path2);
1920 if (cluster_count == 0) {
1921 DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
1922 goto fail;
1923 }
1924 } else if (is_file(direntries + i)) {
1925 /* check file size with FAT */
1926 cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
1927 if (cluster_count !=
1928 (le32_to_cpu(direntries[i].size) + s->cluster_size
1929 - 1) / s->cluster_size) {
1930 DLOG(fprintf(stderr, "Cluster count mismatch\n"));
1931 goto fail;
1932 }
1933 } else
43dc2a64 1934 abort(); /* cluster_count = 0; */
a046433a
FB
1935
1936 ret += cluster_count;
de167e41 1937 }
de167e41 1938
a046433a
FB
1939 cluster_num = modified_fat_get(s, cluster_num);
1940 } while(!fat_eof(s, cluster_num));
de167e41 1941
ce137829 1942 g_free(cluster);
a046433a
FB
1943 return ret;
1944}
1945
1946/* returns 1 on success */
1947static int is_consistent(BDRVVVFATState* s)
1948{
1949 int i, check;
1950 int used_clusters_count = 0;
1951
1952DLOG(checkpoint());
1953 /*
1954 * - get modified FAT
1955 * - compare the two FATs (TODO)
1956 * - get buffer for marking used clusters
1957 * - recurse direntries from root (using bs->bdrv_read to make
1958 * sure to get the new data)
1959 * - check that the FAT agrees with the size
1960 * - count the number of clusters occupied by this directory and
1961 * its files
1962 * - check that the cumulative used cluster count agrees with the
1963 * FAT
1964 * - if all is fine, return number of used clusters
1965 */
1966 if (s->fat2 == NULL) {
1967 int size = 0x200 * s->sectors_per_fat;
7267c094 1968 s->fat2 = g_malloc(size);
a046433a
FB
1969 memcpy(s->fat2, s->fat.pointer, size);
1970 }
1971 check = vvfat_read(s->bs,
1972 s->first_sectors_number, s->fat2, s->sectors_per_fat);
1973 if (check) {
1974 fprintf(stderr, "Could not copy fat\n");
1975 return 0;
1976 }
1977 assert (s->used_clusters);
1978 for (i = 0; i < sector2cluster(s, s->sector_count); i++)
1979 s->used_clusters[i] &= ~USED_ANY;
1980
1981 clear_commits(s);
1982
1983 /* mark every mapped file/directory as deleted.
1984 * (check_directory_consistency() will unmark those still present). */
1985 if (s->qcow)
1986 for (i = 0; i < s->mapping.next; i++) {
c227f099 1987 mapping_t* mapping = array_get(&(s->mapping), i);
a046433a
FB
1988 if (mapping->first_mapping_index < 0)
1989 mapping->mode |= MODE_DELETED;
de167e41 1990 }
a046433a
FB
1991
1992 used_clusters_count = check_directory_consistency(s, 0, s->path);
1993 if (used_clusters_count <= 0) {
1994 DLOG(fprintf(stderr, "problem in directory\n"));
1995 return 0;
de167e41
FB
1996 }
1997
a046433a
FB
1998 check = s->last_cluster_of_root_directory;
1999 for (i = check; i < sector2cluster(s, s->sector_count); i++) {
2000 if (modified_fat_get(s, i)) {
2001 if(!s->used_clusters[i]) {
2002 DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
2003 return 0;
2004 }
2005 check++;
2006 }
2007
2008 if (s->used_clusters[i] == USED_ALLOCATED) {
2009 /* allocated, but not used... */
2010 DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
2011 return 0;
2012 }
2013 }
2014
2015 if (check != used_clusters_count)
2016 return 0;
2017
2018 return used_clusters_count;
2019}
2020
2021static inline void adjust_mapping_indices(BDRVVVFATState* s,
2022 int offset, int adjust)
2023{
2024 int i;
2025
2026 for (i = 0; i < s->mapping.next; i++) {
c227f099 2027 mapping_t* mapping = array_get(&(s->mapping), i);
a046433a
FB
2028
2029#define ADJUST_MAPPING_INDEX(name) \
2030 if (mapping->name >= offset) \
2031 mapping->name += adjust
2032
2033 ADJUST_MAPPING_INDEX(first_mapping_index);
2034 if (mapping->mode & MODE_DIRECTORY)
2035 ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
de167e41 2036 }
a046433a
FB
2037}
2038
2039/* insert or update mapping */
c227f099 2040static mapping_t* insert_mapping(BDRVVVFATState* s,
a046433a
FB
2041 uint32_t begin, uint32_t end)
2042{
2043 /*
2044 * - find mapping where mapping->begin >= begin,
2045 * - if mapping->begin > begin: insert
2046 * - adjust all references to mappings!
2047 * - else: adjust
2048 * - replace name
2049 */
2050 int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
c227f099
AL
2051 mapping_t* mapping = NULL;
2052 mapping_t* first_mapping = array_get(&(s->mapping), 0);
a046433a
FB
2053
2054 if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
2055 && mapping->begin < begin) {
2056 mapping->end = begin;
2057 index++;
2058 mapping = array_get(&(s->mapping), index);
2059 }
2060 if (index >= s->mapping.next || mapping->begin > begin) {
2061 mapping = array_insert(&(s->mapping), index, 1);
2062 mapping->path = NULL;
2063 adjust_mapping_indices(s, index, +1);
2064 }
2065
2066 mapping->begin = begin;
2067 mapping->end = end;
de167e41 2068
c227f099 2069DLOG(mapping_t* next_mapping;
a046433a
FB
2070assert(index + 1 >= s->mapping.next ||
2071((next_mapping = array_get(&(s->mapping), index + 1)) &&
2072 next_mapping->begin >= end)));
2073
c227f099 2074 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
a046433a
FB
2075 s->current_mapping = array_get(&(s->mapping),
2076 s->current_mapping - first_mapping);
2077
2078 return mapping;
2079}
2080
2081static int remove_mapping(BDRVVVFATState* s, int mapping_index)
2082{
c227f099
AL
2083 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
2084 mapping_t* first_mapping = array_get(&(s->mapping), 0);
a046433a
FB
2085
2086 /* free mapping */
ce137829
SW
2087 if (mapping->first_mapping_index < 0) {
2088 g_free(mapping->path);
2089 }
a046433a
FB
2090
2091 /* remove from s->mapping */
2092 array_remove(&(s->mapping), mapping_index);
2093
2094 /* adjust all references to mappings */
2095 adjust_mapping_indices(s, mapping_index, -1);
2096
c227f099 2097 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
a046433a
FB
2098 s->current_mapping = array_get(&(s->mapping),
2099 s->current_mapping - first_mapping);
de167e41 2100
de167e41
FB
2101 return 0;
2102}
2103
a046433a
FB
2104static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
2105{
2106 int i;
2107 for (i = 0; i < s->mapping.next; i++) {
c227f099 2108 mapping_t* mapping = array_get(&(s->mapping), i);
a046433a
FB
2109 if (mapping->dir_index >= offset)
2110 mapping->dir_index += adjust;
2111 if ((mapping->mode & MODE_DIRECTORY) &&
2112 mapping->info.dir.first_dir_index >= offset)
2113 mapping->info.dir.first_dir_index += adjust;
2114 }
2115}
de167e41 2116
c227f099 2117static direntry_t* insert_direntries(BDRVVVFATState* s,
a046433a 2118 int dir_index, int count)
de167e41 2119{
a046433a
FB
2120 /*
2121 * make room in s->directory,
2122 * adjust_dirindices
2123 */
c227f099 2124 direntry_t* result = array_insert(&(s->directory), dir_index, count);
a046433a
FB
2125 if (result == NULL)
2126 return NULL;
2127 adjust_dirindices(s, dir_index, count);
de167e41
FB
2128 return result;
2129}
2130
a046433a
FB
2131static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
2132{
2133 int ret = array_remove_slice(&(s->directory), dir_index, count);
2134 if (ret)
2135 return ret;
2136 adjust_dirindices(s, dir_index, -count);
2137 return 0;
2138}
de167e41 2139
a046433a
FB
2140/*
2141 * Adapt the mappings of the cluster chain starting at first cluster
2142 * (i.e. if a file starts at first_cluster, the chain is followed according
2143 * to the modified fat, and the corresponding entries in s->mapping are
2144 * adjusted)
2145 */
2146static int commit_mappings(BDRVVVFATState* s,
2147 uint32_t first_cluster, int dir_index)
de167e41 2148{
c227f099
AL
2149 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2150 direntry_t* direntry = array_get(&(s->directory), dir_index);
a046433a
FB
2151 uint32_t cluster = first_cluster;
2152
2153 vvfat_close_current_file(s);
2154
2155 assert(mapping);
2156 assert(mapping->begin == first_cluster);
2157 mapping->first_mapping_index = -1;
2158 mapping->dir_index = dir_index;
2159 mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2160 MODE_DIRECTORY : MODE_NORMAL;
2161
2162 while (!fat_eof(s, cluster)) {
2163 uint32_t c, c1;
2164
2165 for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2166 c = c1, c1 = modified_fat_get(s, c1));
2167
2168 c++;
2169 if (c > mapping->end) {
2170 int index = array_index(&(s->mapping), mapping);
2171 int i, max_i = s->mapping.next - index;
2172 for (i = 1; i < max_i && mapping[i].begin < c; i++);
2173 while (--i > 0)
2174 remove_mapping(s, index + 1);
2175 }
2176 assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2177 || mapping[1].begin >= c);
2178 mapping->end = c;
2179
2180 if (!fat_eof(s, c1)) {
2181 int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
c227f099 2182 mapping_t* next_mapping = i >= s->mapping.next ? NULL :
a046433a
FB
2183 array_get(&(s->mapping), i);
2184
2185 if (next_mapping == NULL || next_mapping->begin > c1) {
2186 int i1 = array_index(&(s->mapping), mapping);
2187
2188 next_mapping = insert_mapping(s, c1, c1+1);
2189
2190 if (c1 < c)
2191 i1++;
2192 mapping = array_get(&(s->mapping), i1);
2193 }
2194
2195 next_mapping->dir_index = mapping->dir_index;
5fafdf24 2196 next_mapping->first_mapping_index =
a046433a
FB
2197 mapping->first_mapping_index < 0 ?
2198 array_index(&(s->mapping), mapping) :
2199 mapping->first_mapping_index;
2200 next_mapping->path = mapping->path;
2201 next_mapping->mode = mapping->mode;
2202 next_mapping->read_only = mapping->read_only;
2203 if (mapping->mode & MODE_DIRECTORY) {
2204 next_mapping->info.dir.parent_mapping_index =
2205 mapping->info.dir.parent_mapping_index;
2206 next_mapping->info.dir.first_dir_index =
2207 mapping->info.dir.first_dir_index +
2208 0x10 * s->sectors_per_cluster *
2209 (mapping->end - mapping->begin);
2210 } else
2211 next_mapping->info.file.offset = mapping->info.file.offset +
2212 mapping->end - mapping->begin;
2213
2214 mapping = next_mapping;
2215 }
3b46e624 2216
a046433a
FB
2217 cluster = c1;
2218 }
de167e41 2219
de167e41
FB
2220 return 0;
2221}
2222
a046433a
FB
2223static int commit_direntries(BDRVVVFATState* s,
2224 int dir_index, int parent_mapping_index)
de167e41 2225{
c227f099 2226 direntry_t* direntry = array_get(&(s->directory), dir_index);
a046433a 2227 uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
c227f099 2228 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
a046433a
FB
2229
2230 int factor = 0x10 * s->sectors_per_cluster;
2231 int old_cluster_count, new_cluster_count;
2232 int current_dir_index = mapping->info.dir.first_dir_index;
2233 int first_dir_index = current_dir_index;
2234 int ret, i;
2235 uint32_t c;
2236
2237DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
2238
2239 assert(direntry);
2240 assert(mapping);
2241 assert(mapping->begin == first_cluster);
2242 assert(mapping->info.dir.first_dir_index < s->directory.next);
2243 assert(mapping->mode & MODE_DIRECTORY);
2244 assert(dir_index == 0 || is_directory(direntry));
2245
2246 mapping->info.dir.parent_mapping_index = parent_mapping_index;
2247
2248 if (first_cluster == 0) {
2249 old_cluster_count = new_cluster_count =
2250 s->last_cluster_of_root_directory;
2251 } else {
2252 for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2253 c = fat_get(s, c))
2254 old_cluster_count++;
de167e41 2255
a046433a
FB
2256 for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2257 c = modified_fat_get(s, c))
2258 new_cluster_count++;
2259 }
de167e41 2260
a046433a
FB
2261 if (new_cluster_count > old_cluster_count) {
2262 if (insert_direntries(s,
2263 current_dir_index + factor * old_cluster_count,
2264 factor * (new_cluster_count - old_cluster_count)) == NULL)
2265 return -1;
2266 } else if (new_cluster_count < old_cluster_count)
2267 remove_direntries(s,
2268 current_dir_index + factor * new_cluster_count,
2269 factor * (old_cluster_count - new_cluster_count));
2270
2271 for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
2272 void* direntry = array_get(&(s->directory), current_dir_index);
2273 int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2274 s->sectors_per_cluster);
2275 if (ret)
2276 return ret;
2277 assert(!strncmp(s->directory.pointer, "QEMU", 4));
2278 current_dir_index += factor;
2279 }
de167e41 2280
a046433a
FB
2281 ret = commit_mappings(s, first_cluster, dir_index);
2282 if (ret)
2283 return ret;
2284
2285 /* recurse */
2286 for (i = 0; i < factor * new_cluster_count; i++) {
2287 direntry = array_get(&(s->directory), first_dir_index + i);
2288 if (is_directory(direntry) && !is_dot(direntry)) {
2289 mapping = find_mapping_for_cluster(s, first_cluster);
2290 assert(mapping->mode & MODE_DIRECTORY);
2291 ret = commit_direntries(s, first_dir_index + i,
2292 array_index(&(s->mapping), mapping));
2293 if (ret)
2294 return ret;
2295 }
2296 }
de167e41 2297
a046433a
FB
2298 return 0;
2299}
de167e41 2300
a046433a
FB
2301/* commit one file (adjust contents, adjust mapping),
2302 return first_mapping_index */
2303static int commit_one_file(BDRVVVFATState* s,
2304 int dir_index, uint32_t offset)
2305{
c227f099 2306 direntry_t* direntry = array_get(&(s->directory), dir_index);
a046433a
FB
2307 uint32_t c = begin_of_direntry(direntry);
2308 uint32_t first_cluster = c;
c227f099 2309 mapping_t* mapping = find_mapping_for_cluster(s, c);
a046433a 2310 uint32_t size = filesize_of_direntry(direntry);
7267c094 2311 char* cluster = g_malloc(s->cluster_size);
a046433a
FB
2312 uint32_t i;
2313 int fd = 0;
2314
2315 assert(offset < size);
2316 assert((offset % s->cluster_size) == 0);
2317
2318 for (i = s->cluster_size; i < offset; i += s->cluster_size)
2319 c = modified_fat_get(s, c);
2320
6165f4d8 2321 fd = qemu_open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
a046433a
FB
2322 if (fd < 0) {
2323 fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2324 strerror(errno), errno);
ce137829 2325 g_free(cluster);
a046433a 2326 return fd;
de167e41 2327 }
ce137829
SW
2328 if (offset > 0) {
2329 if (lseek(fd, offset, SEEK_SET) != offset) {
2e1e79da 2330 qemu_close(fd);
ce137829
SW
2331 g_free(cluster);
2332 return -3;
2333 }
2334 }
a046433a
FB
2335
2336 while (offset < size) {
2337 uint32_t c1;
2338 int rest_size = (size - offset > s->cluster_size ?
2339 s->cluster_size : size - offset);
2340 int ret;
2341
2342 c1 = modified_fat_get(s, c);
2343
2344 assert((size - offset == 0 && fat_eof(s, c)) ||
2345 (size > offset && c >=2 && !fat_eof(s, c)));
a046433a
FB
2346
2347 ret = vvfat_read(s->bs, cluster2sector(s, c),
ffe8ab83 2348 (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
a046433a 2349
ce137829 2350 if (ret < 0) {
2e1e79da 2351 qemu_close(fd);
ce137829
SW
2352 g_free(cluster);
2353 return ret;
2354 }
a046433a 2355
ce137829 2356 if (write(fd, cluster, rest_size) < 0) {
2e1e79da 2357 qemu_close(fd);
ce137829
SW
2358 g_free(cluster);
2359 return -2;
2360 }
a046433a
FB
2361
2362 offset += rest_size;
2363 c = c1;
2364 }
2365
2dedf83e
KS
2366 if (ftruncate(fd, size)) {
2367 perror("ftruncate()");
2e1e79da 2368 qemu_close(fd);
ce137829 2369 g_free(cluster);
2dedf83e
KS
2370 return -4;
2371 }
2e1e79da 2372 qemu_close(fd);
ce137829 2373 g_free(cluster);
a046433a
FB
2374
2375 return commit_mappings(s, first_cluster, dir_index);
2376}
2377
2378#ifdef DEBUG
2379/* test, if all mappings point to valid direntries */
2380static void check1(BDRVVVFATState* s)
2381{
2382 int i;
2383 for (i = 0; i < s->mapping.next; i++) {
c227f099 2384 mapping_t* mapping = array_get(&(s->mapping), i);
a046433a
FB
2385 if (mapping->mode & MODE_DELETED) {
2386 fprintf(stderr, "deleted\n");
2387 continue;
2388 }
a046433a 2389 assert(mapping->dir_index < s->directory.next);
c227f099 2390 direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
a046433a
FB
2391 assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2392 if (mapping->mode & MODE_DIRECTORY) {
2393 assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2394 assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
de167e41
FB
2395 }
2396 }
de167e41
FB
2397}
2398
a046433a
FB
2399/* test, if all direntries have mappings */
2400static void check2(BDRVVVFATState* s)
de167e41 2401{
de167e41 2402 int i;
a046433a 2403 int first_mapping = -1;
de167e41 2404
a046433a 2405 for (i = 0; i < s->directory.next; i++) {
c227f099 2406 direntry_t* direntry = array_get(&(s->directory), i);
de167e41 2407
a046433a 2408 if (is_short_name(direntry) && begin_of_direntry(direntry)) {
c227f099 2409 mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
a046433a
FB
2410 assert(mapping);
2411 assert(mapping->dir_index == i || is_dot(direntry));
2412 assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2413 }
de167e41 2414
a046433a
FB
2415 if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2416 /* cluster start */
2417 int j, count = 0;
de167e41 2418
a046433a 2419 for (j = 0; j < s->mapping.next; j++) {
c227f099 2420 mapping_t* mapping = array_get(&(s->mapping), j);
a046433a 2421 if (mapping->mode & MODE_DELETED)
de167e41 2422 continue;
a046433a
FB
2423 if (mapping->mode & MODE_DIRECTORY) {
2424 if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2425 assert(++count == 1);
2426 if (mapping->first_mapping_index == -1)
2427 first_mapping = array_index(&(s->mapping), mapping);
2428 else
2429 assert(first_mapping == mapping->first_mapping_index);
2430 if (mapping->info.dir.parent_mapping_index < 0)
2431 assert(j == 0);
2432 else {
c227f099 2433 mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
a046433a
FB
2434 assert(parent->mode & MODE_DIRECTORY);
2435 assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2436 }
2437 }
de167e41 2438 }
a046433a
FB
2439 }
2440 if (count == 0)
2441 first_mapping = -1;
2442 }
2443 }
2444}
2445#endif
de167e41 2446
a046433a
FB
2447static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2448{
2449 int i;
de167e41 2450
a046433a
FB
2451#ifdef DEBUG
2452 fprintf(stderr, "handle_renames\n");
2453 for (i = 0; i < s->commits.next; i++) {
c227f099 2454 commit_t* commit = array_get(&(s->commits), i);
a046433a
FB
2455 fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
2456 }
2457#endif
2458
2459 for (i = 0; i < s->commits.next;) {
c227f099 2460 commit_t* commit = array_get(&(s->commits), i);
a046433a 2461 if (commit->action == ACTION_RENAME) {
c227f099 2462 mapping_t* mapping = find_mapping_for_cluster(s,
a046433a
FB
2463 commit->param.rename.cluster);
2464 char* old_path = mapping->path;
2465
2466 assert(commit->path);
2467 mapping->path = commit->path;
2468 if (rename(old_path, mapping->path))
2469 return -2;
2470
2471 if (mapping->mode & MODE_DIRECTORY) {
2472 int l1 = strlen(mapping->path);
2473 int l2 = strlen(old_path);
2474 int diff = l1 - l2;
c227f099 2475 direntry_t* direntry = array_get(&(s->directory),
a046433a
FB
2476 mapping->info.dir.first_dir_index);
2477 uint32_t c = mapping->begin;
2478 int i = 0;
2479
2480 /* recurse */
2481 while (!fat_eof(s, c)) {
2482 do {
c227f099 2483 direntry_t* d = direntry + i;
a046433a
FB
2484
2485 if (is_file(d) || (is_directory(d) && !is_dot(d))) {
c227f099 2486 mapping_t* m = find_mapping_for_cluster(s,
a046433a
FB
2487 begin_of_direntry(d));
2488 int l = strlen(m->path);
7267c094 2489 char* new_path = g_malloc(l + diff + 1);
a046433a
FB
2490
2491 assert(!strncmp(m->path, mapping->path, l2));
2492
363a37d5
BS
2493 pstrcpy(new_path, l + diff + 1, mapping->path);
2494 pstrcpy(new_path + l1, l + diff + 1 - l1,
2495 m->path + l2);
a046433a
FB
2496
2497 schedule_rename(s, m->begin, new_path);
de167e41 2498 }
a046433a
FB
2499 i++;
2500 } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2501 c = fat_get(s, c);
de167e41
FB
2502 }
2503 }
de167e41 2504
ce137829 2505 g_free(old_path);
a046433a
FB
2506 array_remove(&(s->commits), i);
2507 continue;
2508 } else if (commit->action == ACTION_MKDIR) {
c227f099 2509 mapping_t* mapping;
a046433a
FB
2510 int j, parent_path_len;
2511
48c2f068
FB
2512#ifdef __MINGW32__
2513 if (mkdir(commit->path))
2514 return -5;
2515#else
2516 if (mkdir(commit->path, 0755))
2517 return -5;
2518#endif
a046433a
FB
2519
2520 mapping = insert_mapping(s, commit->param.mkdir.cluster,
2521 commit->param.mkdir.cluster + 1);
2522 if (mapping == NULL)
2523 return -6;
2524
2525 mapping->mode = MODE_DIRECTORY;
2526 mapping->read_only = 0;
2527 mapping->path = commit->path;
2528 j = s->directory.next;
2529 assert(j);
2530 insert_direntries(s, s->directory.next,
2531 0x10 * s->sectors_per_cluster);
2532 mapping->info.dir.first_dir_index = j;
2533
2534 parent_path_len = strlen(commit->path)
2535 - strlen(get_basename(commit->path)) - 1;
2536 for (j = 0; j < s->mapping.next; j++) {
c227f099 2537 mapping_t* m = array_get(&(s->mapping), j);
a046433a
FB
2538 if (m->first_mapping_index < 0 && m != mapping &&
2539 !strncmp(m->path, mapping->path, parent_path_len) &&
2540 strlen(m->path) == parent_path_len)
2541 break;
2542 }
2543 assert(j < s->mapping.next);
2544 mapping->info.dir.parent_mapping_index = j;
2545
2546 array_remove(&(s->commits), i);
2547 continue;
2548 }
2549
2550 i++;
2551 }
2552 return 0;
2553}
2554
2555/*
2556 * TODO: make sure that the short name is not matching *another* file
2557 */
2558static int handle_commits(BDRVVVFATState* s)
2559{
2560 int i, fail = 0;
2561
2562 vvfat_close_current_file(s);
2563
2564 for (i = 0; !fail && i < s->commits.next; i++) {
c227f099 2565 commit_t* commit = array_get(&(s->commits), i);
a046433a
FB
2566 switch(commit->action) {
2567 case ACTION_RENAME: case ACTION_MKDIR:
43dc2a64 2568 abort();
a046433a
FB
2569 fail = -2;
2570 break;
2571 case ACTION_WRITEOUT: {
a6c6f76c
BS
2572#ifndef NDEBUG
2573 /* these variables are only used by assert() below */
c227f099 2574 direntry_t* entry = array_get(&(s->directory),
a046433a
FB
2575 commit->param.writeout.dir_index);
2576 uint32_t begin = begin_of_direntry(entry);
c227f099 2577 mapping_t* mapping = find_mapping_for_cluster(s, begin);
a6c6f76c 2578#endif
a046433a
FB
2579
2580 assert(mapping);
2581 assert(mapping->begin == begin);
2582 assert(commit->path == NULL);
2583
2584 if (commit_one_file(s, commit->param.writeout.dir_index,
2585 commit->param.writeout.modified_offset))
2586 fail = -3;
2587
2588 break;
2589 }
2590 case ACTION_NEW_FILE: {
2591 int begin = commit->param.new_file.first_cluster;
c227f099
AL
2592 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2593 direntry_t* entry;
a046433a 2594 int i;
de167e41 2595
a046433a
FB
2596 /* find direntry */
2597 for (i = 0; i < s->directory.next; i++) {
2598 entry = array_get(&(s->directory), i);
2599 if (is_file(entry) && begin_of_direntry(entry) == begin)
2600 break;
de167e41 2601 }
de167e41 2602
a046433a
FB
2603 if (i >= s->directory.next) {
2604 fail = -6;
2605 continue;
2606 }
de167e41 2607
a046433a
FB
2608 /* make sure there exists an initial mapping */
2609 if (mapping && mapping->begin != begin) {
2610 mapping->end = begin;
2611 mapping = NULL;
2612 }
2613 if (mapping == NULL) {
2614 mapping = insert_mapping(s, begin, begin+1);
2615 }
2616 /* most members will be fixed in commit_mappings() */
2617 assert(commit->path);
2618 mapping->path = commit->path;
2619 mapping->read_only = 0;
2620 mapping->mode = MODE_NORMAL;
2621 mapping->info.file.offset = 0;
2622
2623 if (commit_one_file(s, i, 0))
2624 fail = -7;
2625
2626 break;
2627 }
2628 default:
43dc2a64 2629 abort();
a046433a
FB
2630 }
2631 }
2632 if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2633 return -1;
2634 return fail;
2635}
2636
2637static int handle_deletes(BDRVVVFATState* s)
2638{
2639 int i, deferred = 1, deleted = 1;
2640
2641 /* delete files corresponding to mappings marked as deleted */
2642 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2643 while (deferred && deleted) {
2644 deferred = 0;
2645 deleted = 0;
2646
2647 for (i = 1; i < s->mapping.next; i++) {
c227f099 2648 mapping_t* mapping = array_get(&(s->mapping), i);
a046433a 2649 if (mapping->mode & MODE_DELETED) {
c227f099 2650 direntry_t* entry = array_get(&(s->directory),
a046433a
FB
2651 mapping->dir_index);
2652
2653 if (is_free(entry)) {
2654 /* remove file/directory */
2655 if (mapping->mode & MODE_DIRECTORY) {
2656 int j, next_dir_index = s->directory.next,
2657 first_dir_index = mapping->info.dir.first_dir_index;
2658
2659 if (rmdir(mapping->path) < 0) {
2660 if (errno == ENOTEMPTY) {
2661 deferred++;
2662 continue;
2663 } else
2664 return -5;
de167e41 2665 }
a046433a
FB
2666
2667 for (j = 1; j < s->mapping.next; j++) {
c227f099 2668 mapping_t* m = array_get(&(s->mapping), j);
a046433a
FB
2669 if (m->mode & MODE_DIRECTORY &&
2670 m->info.dir.first_dir_index >
2671 first_dir_index &&
2672 m->info.dir.first_dir_index <
2673 next_dir_index)
2674 next_dir_index =
2675 m->info.dir.first_dir_index;
de167e41 2676 }
a046433a
FB
2677 remove_direntries(s, first_dir_index,
2678 next_dir_index - first_dir_index);
de167e41 2679
a046433a 2680 deleted++;
de167e41 2681 }
a046433a
FB
2682 } else {
2683 if (unlink(mapping->path))
2684 return -4;
2685 deleted++;
de167e41 2686 }
a046433a
FB
2687 DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2688 remove_mapping(s, i);
de167e41
FB
2689 }
2690 }
2691 }
a046433a
FB
2692
2693 return 0;
2694}
2695
2696/*
2697 * synchronize mapping with new state:
2698 *
2699 * - copy FAT (with bdrv_read)
2700 * - mark all filenames corresponding to mappings as deleted
2701 * - recurse direntries from root (using bs->bdrv_read)
2702 * - delete files corresponding to mappings marked as deleted
2703 */
2704static int do_commit(BDRVVVFATState* s)
2705{
2706 int ret = 0;
2707
2708 /* the real meat are the commits. Nothing to do? Move along! */
2709 if (s->commits.next == 0)
2710 return 0;
2711
2712 vvfat_close_current_file(s);
2713
2714 ret = handle_renames_and_mkdirs(s);
2715 if (ret) {
2716 fprintf(stderr, "Error handling renames (%d)\n", ret);
43dc2a64 2717 abort();
a046433a
FB
2718 return ret;
2719 }
2720
5fafdf24 2721 /* copy FAT (with bdrv_read) */
a046433a
FB
2722 memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2723
2724 /* recurse direntries from root (using bs->bdrv_read) */
2725 ret = commit_direntries(s, 0, -1);
2726 if (ret) {
2727 fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
43dc2a64 2728 abort();
a046433a
FB
2729 return ret;
2730 }
2731
2732 ret = handle_commits(s);
2733 if (ret) {
2734 fprintf(stderr, "Error handling commits (%d)\n", ret);
43dc2a64 2735 abort();
a046433a
FB
2736 return ret;
2737 }
2738
2739 ret = handle_deletes(s);
2740 if (ret) {
2741 fprintf(stderr, "Error deleting\n");
43dc2a64 2742 abort();
a046433a
FB
2743 return ret;
2744 }
2745
7704df98
KW
2746 if (s->qcow->drv->bdrv_make_empty) {
2747 s->qcow->drv->bdrv_make_empty(s->qcow);
2748 }
a046433a
FB
2749
2750 memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2751
2752DLOG(checkpoint());
2753 return 0;
2754}
2755
2756static int try_commit(BDRVVVFATState* s)
2757{
2758 vvfat_close_current_file(s);
2759DLOG(checkpoint());
2760 if(!is_consistent(s))
2761 return -1;
2762 return do_commit(s);
2763}
2764
5fafdf24 2765static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
a046433a
FB
2766 const uint8_t *buf, int nb_sectors)
2767{
5fafdf24 2768 BDRVVVFATState *s = bs->opaque;
a046433a
FB
2769 int i, ret;
2770
2771DLOG(checkpoint());
2772
ac48e389
KW
2773 /* Check if we're operating in read-only mode */
2774 if (s->qcow == NULL) {
2775 return -EACCES;
2776 }
2777
a046433a
FB
2778 vvfat_close_current_file(s);
2779
2780 /*
2781 * Some sanity checks:
2782 * - do not allow writing to the boot sector
2783 * - do not allow to write non-ASCII filenames
2784 */
2785
2786 if (sector_num < s->first_sectors_number)
2787 return -1;
2788
2789 for (i = sector2cluster(s, sector_num);
2790 i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
c227f099 2791 mapping_t* mapping = find_mapping_for_cluster(s, i);
a046433a
FB
2792 if (mapping) {
2793 if (mapping->read_only) {
2794 fprintf(stderr, "Tried to write to write-protected file %s\n",
2795 mapping->path);
2796 return -1;
2797 }
2798
2799 if (mapping->mode & MODE_DIRECTORY) {
2800 int begin = cluster2sector(s, i);
2801 int end = begin + s->sectors_per_cluster, k;
2802 int dir_index;
c227f099 2803 const direntry_t* direntries;
a046433a
FB
2804 long_file_name lfn;
2805
2806 lfn_init(&lfn);
2807
2808 if (begin < sector_num)
2809 begin = sector_num;
2810 if (end > sector_num + nb_sectors)
2811 end = sector_num + nb_sectors;
5fafdf24 2812 dir_index = mapping->dir_index +
a046433a 2813 0x10 * (begin - mapping->begin * s->sectors_per_cluster);
c227f099 2814 direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
a046433a
FB
2815
2816 for (k = 0; k < (end - begin) * 0x10; k++) {
2817 /* do not allow non-ASCII filenames */
2818 if (parse_long_name(&lfn, direntries + k) < 0) {
2819 fprintf(stderr, "Warning: non-ASCII filename\n");
2820 return -1;
2821 }
2822 /* no access to the direntry of a read-only file */
2823 else if (is_short_name(direntries+k) &&
2824 (direntries[k].attributes & 1)) {
2825 if (memcmp(direntries + k,
2826 array_get(&(s->directory), dir_index + k),
c227f099 2827 sizeof(direntry_t))) {
a046433a
FB
2828 fprintf(stderr, "Warning: tried to write to write-protected file\n");
2829 return -1;
2830 }
2831 }
2832 }
2833 }
2834 i = mapping->end;
2835 } else
2836 i++;
2837 }
2838
2839 /*
2840 * Use qcow backend. Commit later.
2841 */
2842DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
7704df98 2843 ret = bdrv_write(s->qcow, sector_num, buf, nb_sectors);
a046433a
FB
2844 if (ret < 0) {
2845 fprintf(stderr, "Error writing to qcow backend\n");
2846 return ret;
2847 }
2848
2849 for (i = sector2cluster(s, sector_num);
2850 i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
2851 if (i >= 0)
2852 s->used_clusters[i] |= USED_ALLOCATED;
2853
2854DLOG(checkpoint());
2855 /* TODO: add timeout */
2856 try_commit(s);
2857
2858DLOG(checkpoint());
2859 return 0;
2860}
2861
e183ef75
PB
2862static coroutine_fn int vvfat_co_write(BlockDriverState *bs, int64_t sector_num,
2863 const uint8_t *buf, int nb_sectors)
2864{
2865 int ret;
2866 BDRVVVFATState *s = bs->opaque;
2867 qemu_co_mutex_lock(&s->lock);
2868 ret = vvfat_write(bs, sector_num, buf, nb_sectors);
2869 qemu_co_mutex_unlock(&s->lock);
2870 return ret;
2871}
2872
b6b8a333 2873static int64_t coroutine_fn vvfat_co_get_block_status(BlockDriverState *bs,
a046433a
FB
2874 int64_t sector_num, int nb_sectors, int* n)
2875{
2876 BDRVVVFATState* s = bs->opaque;
2877 *n = s->sector_count - sector_num;
4bc74be9
PB
2878 if (*n > nb_sectors) {
2879 *n = nb_sectors;
2880 } else if (*n < 0) {
2881 return 0;
2882 }
2883 return BDRV_BLOCK_DATA;
a046433a
FB
2884}
2885
2886static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
2887 const uint8_t* buffer, int nb_sectors) {
9217e26f 2888 BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
a046433a
FB
2889 return try_commit(s);
2890}
2891
2892static void write_target_close(BlockDriverState *bs) {
9217e26f 2893 BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
4f6fd349 2894 bdrv_unref(s->qcow);
ce137829 2895 g_free(s->qcow_filename);
a046433a
FB
2896}
2897
2898static BlockDriver vvfat_write_target = {
f9e96436
CH
2899 .format_name = "vvfat_write_target",
2900 .bdrv_write = write_target_commit,
2901 .bdrv_close = write_target_close,
a046433a
FB
2902};
2903
68c70af1 2904static int enable_write_target(BDRVVVFATState *s, Error **errp)
a046433a 2905{
facdbb02 2906 BlockDriver *bdrv_qcow = NULL;
facdbb02 2907 QemuOpts *opts = NULL;
a655211a 2908 int ret;
a046433a
FB
2909 int size = sector2cluster(s, s->sector_count);
2910 s->used_clusters = calloc(size, 1);
2911
c227f099 2912 array_init(&(s->commits), sizeof(commit_t));
a046433a 2913
9a29e18f
JC
2914 s->qcow_filename = g_malloc(PATH_MAX);
2915 ret = get_tmp_filename(s->qcow_filename, PATH_MAX);
eba25057 2916 if (ret < 0) {
68c70af1 2917 error_setg_errno(errp, -ret, "can't create temporary file");
78f27bd0 2918 goto err;
eba25057 2919 }
91a073a9
KW
2920
2921 bdrv_qcow = bdrv_find_format("qcow");
1bcb15cf
HR
2922 if (!bdrv_qcow) {
2923 error_setg(errp, "Failed to locate qcow driver");
2924 ret = -ENOENT;
2925 goto err;
2926 }
2927
c282e1fd 2928 opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort);
39101f25
MA
2929 qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512,
2930 &error_abort);
f43e47db 2931 qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:", &error_abort);
91a073a9 2932
c282e1fd 2933 ret = bdrv_create(bdrv_qcow, s->qcow_filename, opts, errp);
facdbb02 2934 qemu_opts_del(opts);
78f27bd0
FZ
2935 if (ret < 0) {
2936 goto err;
2937 }
a655211a 2938
f67503e5 2939 s->qcow = NULL;
ddf5636d 2940 ret = bdrv_open(&s->qcow, s->qcow_filename, NULL, NULL,
68c70af1
MA
2941 BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH,
2942 bdrv_qcow, errp);
a655211a 2943 if (ret < 0) {
78f27bd0 2944 goto err;
d6e9098e 2945 }
a046433a
FB
2946
2947#ifndef _WIN32
2948 unlink(s->qcow_filename);
2949#endif
2950
e4e9986b 2951 bdrv_set_backing_hd(s->bs, bdrv_new());
a046433a 2952 s->bs->backing_hd->drv = &vvfat_write_target;
5839e53b 2953 s->bs->backing_hd->opaque = g_new(void *, 1);
9217e26f 2954 *(void**)s->bs->backing_hd->opaque = s;
a046433a 2955
de167e41 2956 return 0;
78f27bd0
FZ
2957
2958err:
2959 g_free(s->qcow_filename);
2960 s->qcow_filename = NULL;
2961 return ret;
de167e41
FB
2962}
2963
2964static void vvfat_close(BlockDriverState *bs)
2965{
2966 BDRVVVFATState *s = bs->opaque;
2967
2968 vvfat_close_current_file(s);
2969 array_free(&(s->fat));
2970 array_free(&(s->directory));
2971 array_free(&(s->mapping));
ce137829 2972 g_free(s->cluster_buffer);
3397f0cb
KW
2973
2974 if (s->qcow) {
2975 migrate_del_blocker(s->migration_blocker);
2976 error_free(s->migration_blocker);
2977 }
de167e41
FB
2978}
2979
5efa9d5a 2980static BlockDriver bdrv_vvfat = {
7ad9be64
KW
2981 .format_name = "vvfat",
2982 .protocol_name = "fat",
2983 .instance_size = sizeof(BDRVVVFATState),
2984
2985 .bdrv_parse_filename = vvfat_parse_filename,
2986 .bdrv_file_open = vvfat_open,
2987 .bdrv_close = vvfat_close,
2988 .bdrv_rebind = vvfat_rebind,
2989
2990 .bdrv_read = vvfat_co_read,
2991 .bdrv_write = vvfat_co_write,
b6b8a333 2992 .bdrv_co_get_block_status = vvfat_co_get_block_status,
de167e41
FB
2993};
2994
5efa9d5a
AL
2995static void bdrv_vvfat_init(void)
2996{
2997 bdrv_register(&bdrv_vvfat);
2998}
2999
3000block_init(bdrv_vvfat_init);
3001
a046433a 3002#ifdef DEBUG
3f47aa8c 3003static void checkpoint(void) {
c227f099 3004 assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
a046433a
FB
3005 check1(vvv);
3006 check2(vvv);
3007 assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
3008#if 0
c227f099 3009 if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
a046433a 3010 fprintf(stderr, "Nonono!\n");
c227f099
AL
3011 mapping_t* mapping;
3012 direntry_t* direntry;
a046433a
FB
3013 assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
3014 assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
3015 if (vvv->mapping.next<47)
3016 return;
3017 assert((mapping = array_get(&(vvv->mapping), 47)));
3018 assert(mapping->dir_index < vvv->directory.next);
3019 direntry = array_get(&(vvv->directory), mapping->dir_index);
3020 assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0);
3021#endif
a046433a
FB
3022}
3023#endif