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