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