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