]> git.ipfire.org Git - thirdparty/qemu.git/blame - block/vvfat.c
cpu: move endian-dependent load/store functions to cpu-all.h
[thirdparty/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"
caf71f86 30#include "migration/migration.h"
7ad9be64
KW
31#include "qapi/qmp/qint.h"
32#include "qapi/qmp/qbool.h"
d49b6836 33#include "qapi/qmp/qstring.h"
f348b6d1 34#include "qemu/cutils.h"
de167e41 35
a046433a
FB
36#ifndef S_IWGRP
37#define S_IWGRP 0
38#endif
39#ifndef S_IWOTH
40#define S_IWOTH 0
41#endif
42
43/* TODO: add ":bootsector=blabla.img:" */
44/* LATER TODO: add automatic boot sector generation from
45 BOOTEASY.ASM and Ranish Partition Manager
5fafdf24 46 Note that DOS assumes the system files to be the first files in the
a046433a
FB
47 file system (test if the boot sector still relies on that fact)! */
48/* MAYBE TODO: write block-visofs.c */
49/* TODO: call try_commit() only after a timeout */
50
51/* #define DEBUG */
52
53#ifdef DEBUG
54
55#define DLOG(a) a
56
3f47aa8c 57static void checkpoint(void);
de167e41 58
a046433a
FB
59#ifdef __MINGW32__
60void nonono(const char* file, int line, const char* msg) {
61 fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg);
62 exit(-5);
63}
64#undef assert
6bcb76c3 65#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
a046433a
FB
66#endif
67
68#else
69
70#define DLOG(a)
71
72#endif
de167e41
FB
73
74/* dynamic array functions */
c227f099 75typedef struct array_t {
de167e41
FB
76 char* pointer;
77 unsigned int size,next,item_size;
c227f099 78} array_t;
de167e41 79
c227f099 80static inline void array_init(array_t* array,unsigned int item_size)
de167e41 81{
511d2b14 82 array->pointer = NULL;
de167e41
FB
83 array->size=0;
84 array->next=0;
85 array->item_size=item_size;
86}
87
c227f099 88static inline void array_free(array_t* array)
de167e41 89{
ce137829 90 g_free(array->pointer);
de167e41
FB
91 array->size=array->next=0;
92}
93
a046433a 94/* does not automatically grow */
c227f099 95static inline void* array_get(array_t* array,unsigned int index) {
a046433a
FB
96 assert(index < array->next);
97 return array->pointer + index * array->item_size;
98}
99
c227f099 100static inline int array_ensure_allocated(array_t* array, int index)
a046433a
FB
101{
102 if((index + 1) * array->item_size > array->size) {
103 int new_size = (index + 32) * array->item_size;
7267c094 104 array->pointer = g_realloc(array->pointer, new_size);
a046433a
FB
105 if (!array->pointer)
106 return -1;
107 array->size = new_size;
108 array->next = index + 1;
de167e41 109 }
a046433a
FB
110
111 return 0;
de167e41
FB
112}
113
c227f099 114static inline void* array_get_next(array_t* array) {
a046433a
FB
115 unsigned int next = array->next;
116 void* result;
117
118 if (array_ensure_allocated(array, next) < 0)
119 return NULL;
120
121 array->next = next + 1;
122 result = array_get(array, next);
123
de167e41
FB
124 return result;
125}
126
c227f099 127static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
de167e41
FB
128 if((array->next+count)*array->item_size>array->size) {
129 int increment=count*array->item_size;
7267c094 130 array->pointer=g_realloc(array->pointer,array->size+increment);
de167e41 131 if(!array->pointer)
511d2b14 132 return NULL;
de167e41
FB
133 array->size+=increment;
134 }
135 memmove(array->pointer+(index+count)*array->item_size,
136 array->pointer+index*array->item_size,
137 (array->next-index)*array->item_size);
138 array->next+=count;
139 return array->pointer+index*array->item_size;
140}
141
142/* this performs a "roll", so that the element which was at index_from becomes
143 * index_to, but the order of all other elements is preserved. */
c227f099 144static inline int array_roll(array_t* array,int index_to,int index_from,int count)
de167e41
FB
145{
146 char* buf;
147 char* from;
148 char* to;
149 int is;
150
151 if(!array ||
152 index_to<0 || index_to>=array->next ||
153 index_from<0 || index_from>=array->next)
154 return -1;
3b46e624 155
de167e41
FB
156 if(index_to==index_from)
157 return 0;
158
159 is=array->item_size;
160 from=array->pointer+index_from*is;
161 to=array->pointer+index_to*is;
7267c094 162 buf=g_malloc(is*count);
de167e41
FB
163 memcpy(buf,from,is*count);
164
165 if(index_to<index_from)
166 memmove(to+is*count,to,from-to);
167 else
168 memmove(from,from+is*count,to-from);
3b46e624 169
de167e41
FB
170 memcpy(to,buf,is*count);
171
ce137829 172 g_free(buf);
de167e41
FB
173
174 return 0;
175}
176
c227f099 177static inline int array_remove_slice(array_t* array,int index, int count)
de167e41 178{
a046433a
FB
179 assert(index >=0);
180 assert(count > 0);
181 assert(index + count <= array->next);
182 if(array_roll(array,array->next-1,index,count))
de167e41 183 return -1;
a046433a 184 array->next -= count;
de167e41
FB
185 return 0;
186}
187
c227f099 188static int array_remove(array_t* array,int index)
a046433a
FB
189{
190 return array_remove_slice(array, index, 1);
191}
192
193/* return the index for a given member */
c227f099 194static int array_index(array_t* array, void* pointer)
a046433a
FB
195{
196 size_t offset = (char*)pointer - array->pointer;
a046433a
FB
197 assert((offset % array->item_size) == 0);
198 assert(offset/array->item_size < array->next);
199 return offset/array->item_size;
200}
201
de167e41 202/* These structures are used to fake a disk and the VFAT filesystem.
541dc0d4 203 * For this reason we need to use QEMU_PACKED. */
de167e41 204
c227f099 205typedef struct bootsector_t {
de167e41
FB
206 uint8_t jump[3];
207 uint8_t name[8];
208 uint16_t sector_size;
209 uint8_t sectors_per_cluster;
210 uint16_t reserved_sectors;
211 uint8_t number_of_fats;
212 uint16_t root_entries;
a046433a 213 uint16_t total_sectors16;
de167e41
FB
214 uint8_t media_type;
215 uint16_t sectors_per_fat;
216 uint16_t sectors_per_track;
217 uint16_t number_of_heads;
218 uint32_t hidden_sectors;
219 uint32_t total_sectors;
220 union {
221 struct {
222 uint8_t drive_number;
223 uint8_t current_head;
224 uint8_t signature;
225 uint32_t id;
226 uint8_t volume_label[11];
541dc0d4 227 } QEMU_PACKED fat16;
de167e41
FB
228 struct {
229 uint32_t sectors_per_fat;
230 uint16_t flags;
231 uint8_t major,minor;
232 uint32_t first_cluster_of_root_directory;
233 uint16_t info_sector;
234 uint16_t backup_boot_sector;
235 uint16_t ignored;
541dc0d4 236 } QEMU_PACKED fat32;
de167e41
FB
237 } u;
238 uint8_t fat_type[8];
239 uint8_t ignored[0x1c0];
240 uint8_t magic[2];
541dc0d4 241} QEMU_PACKED bootsector_t;
de167e41 242
b570094d
TS
243typedef struct {
244 uint8_t head;
245 uint8_t sector;
246 uint8_t cylinder;
c227f099 247} mbr_chs_t;
b570094d 248
c227f099 249typedef struct partition_t {
de167e41 250 uint8_t attributes; /* 0x80 = bootable */
c227f099 251 mbr_chs_t start_CHS;
b570094d 252 uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
c227f099 253 mbr_chs_t end_CHS;
de167e41 254 uint32_t start_sector_long;
b570094d 255 uint32_t length_sector_long;
541dc0d4 256} QEMU_PACKED partition_t;
de167e41 257
c227f099 258typedef struct mbr_t {
b570094d
TS
259 uint8_t ignored[0x1b8];
260 uint32_t nt_id;
261 uint8_t ignored2[2];
c227f099 262 partition_t partition[4];
de167e41 263 uint8_t magic[2];
541dc0d4 264} QEMU_PACKED mbr_t;
de167e41 265
c227f099 266typedef struct direntry_t {
f671d173 267 uint8_t name[8 + 3];
de167e41
FB
268 uint8_t attributes;
269 uint8_t reserved[2];
270 uint16_t ctime;
271 uint16_t cdate;
272 uint16_t adate;
273 uint16_t begin_hi;
274 uint16_t mtime;
275 uint16_t mdate;
276 uint16_t begin;
277 uint32_t size;
541dc0d4 278} QEMU_PACKED direntry_t;
de167e41
FB
279
280/* this structure are used to transparently access the files */
281
c227f099 282typedef struct mapping_t {
a046433a
FB
283 /* begin is the first cluster, end is the last+1 */
284 uint32_t begin,end;
de167e41
FB
285 /* as s->directory is growable, no pointer may be used here */
286 unsigned int dir_index;
a046433a
FB
287 /* the clusters of a file may be in any order; this points to the first */
288 int first_mapping_index;
289 union {
290 /* offset is
291 * - the offset in the file (in clusters) for a file, or
292 * - the next cluster of the directory for a directory, and
293 * - the address of the buffer for a faked entry
294 */
295 struct {
296 uint32_t offset;
297 } file;
298 struct {
299 int parent_mapping_index;
300 int first_dir_index;
301 } dir;
302 } info;
303 /* path contains the full path, i.e. it always starts with s->path */
304 char* path;
305
306 enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2,
307 MODE_DIRECTORY = 4, MODE_FAKED = 8,
308 MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
309 int read_only;
c227f099 310} mapping_t;
de167e41 311
a046433a 312#ifdef DEBUG
c227f099
AL
313static void print_direntry(const struct direntry_t*);
314static void print_mapping(const struct mapping_t* mapping);
a046433a 315#endif
de167e41
FB
316
317/* here begins the real VVFAT driver */
318
319typedef struct BDRVVVFATState {
848c66e8 320 CoMutex lock;
a046433a 321 BlockDriverState* bs; /* pointer to parent */
de167e41
FB
322 unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
323 unsigned char first_sectors[0x40*0x200];
3b46e624 324
de167e41 325 int fat_type; /* 16 or 32 */
c227f099 326 array_t fat,directory,mapping;
d5941dda 327 char volume_label[11];
3b46e624 328
de167e41
FB
329 unsigned int cluster_size;
330 unsigned int sectors_per_cluster;
331 unsigned int sectors_per_fat;
332 unsigned int sectors_of_root_directory;
a046433a 333 uint32_t last_cluster_of_root_directory;
de167e41
FB
334 unsigned int faked_sectors; /* how many sectors are faked before file data */
335 uint32_t sector_count; /* total number of sectors of the partition */
336 uint32_t cluster_count; /* total number of clusters of this partition */
de167e41 337 uint32_t max_fat_value;
3b46e624 338
de167e41 339 int current_fd;
c227f099 340 mapping_t* current_mapping;
a046433a
FB
341 unsigned char* cluster; /* points to current cluster */
342 unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
de167e41
FB
343 unsigned int current_cluster;
344
345 /* write support */
a046433a
FB
346 BlockDriverState* write_target;
347 char* qcow_filename;
348 BlockDriverState* qcow;
349 void* fat2;
350 char* used_clusters;
c227f099 351 array_t commits;
a046433a
FB
352 const char* path;
353 int downcase_short_names;
3397f0cb
KW
354
355 Error *migration_blocker;
de167e41
FB
356} BDRVVVFATState;
357
b570094d
TS
358/* take the sector position spos and convert it to Cylinder/Head/Sector position
359 * if the position is outside the specified geometry, fill maximum value for CHS
360 * and return 1 to signal overflow.
361 */
4480e0f9
MA
362static int sector2CHS(mbr_chs_t *chs, int spos, int cyls, int heads, int secs)
363{
b570094d 364 int head,sector;
4480e0f9
MA
365 sector = spos % secs; spos /= secs;
366 head = spos % heads; spos /= heads;
367 if (spos >= cyls) {
b570094d
TS
368 /* Overflow,
369 it happens if 32bit sector positions are used, while CHS is only 24bit.
370 Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
371 chs->head = 0xFF;
372 chs->sector = 0xFF;
373 chs->cylinder = 0xFF;
374 return 1;
375 }
376 chs->head = (uint8_t)head;
377 chs->sector = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
378 chs->cylinder = (uint8_t)spos;
379 return 0;
380}
de167e41 381
4480e0f9 382static void init_mbr(BDRVVVFATState *s, int cyls, int heads, int secs)
de167e41
FB
383{
384 /* TODO: if the files mbr.img and bootsect.img exist, use them */
c227f099
AL
385 mbr_t* real_mbr=(mbr_t*)s->first_sectors;
386 partition_t* partition = &(real_mbr->partition[0]);
b570094d 387 int lba;
de167e41
FB
388
389 memset(s->first_sectors,0,512);
3b46e624 390
b570094d
TS
391 /* Win NT Disk Signature */
392 real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
393
de167e41 394 partition->attributes=0x80; /* bootable */
b570094d
TS
395
396 /* LBA is used when partition is outside the CHS geometry */
4480e0f9
MA
397 lba = sector2CHS(&partition->start_CHS, s->first_sectors_number - 1,
398 cyls, heads, secs);
399 lba |= sector2CHS(&partition->end_CHS, s->bs->total_sectors - 1,
400 cyls, heads, secs);
b570094d
TS
401
402 /*LBA partitions are identified only by start/length_sector_long not by CHS*/
f91cbefe
MA
403 partition->start_sector_long = cpu_to_le32(s->first_sectors_number - 1);
404 partition->length_sector_long = cpu_to_le32(s->bs->total_sectors
405 - s->first_sectors_number + 1);
b570094d 406
a046433a 407 /* FAT12/FAT16/FAT32 */
b570094d
TS
408 /* DOS uses different types when partition is LBA,
409 probably to prevent older versions from using CHS on them */
410 partition->fs_type= s->fat_type==12 ? 0x1:
411 s->fat_type==16 ? (lba?0xe:0x06):
412 /*fat_tyoe==32*/ (lba?0xc:0x0b);
de167e41
FB
413
414 real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
415}
416
a046433a
FB
417/* direntry functions */
418
de167e41 419/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
60fe76f3 420static inline int short2long_name(char* dest,const char* src)
de167e41
FB
421{
422 int i;
1e080d5d 423 int len;
de167e41
FB
424 for(i=0;i<129 && src[i];i++) {
425 dest[2*i]=src[i];
426 dest[2*i+1]=0;
427 }
1e080d5d 428 len=2*i;
de167e41
FB
429 dest[2*i]=dest[2*i+1]=0;
430 for(i=2*i+2;(i%26);i++)
431 dest[i]=0xff;
1e080d5d 432 return len;
de167e41
FB
433}
434
c227f099 435static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
de167e41
FB
436{
437 char buffer[258];
438 int length=short2long_name(buffer,filename),
439 number_of_entries=(length+25)/26,i;
c227f099 440 direntry_t* entry;
de167e41
FB
441
442 for(i=0;i<number_of_entries;i++) {
443 entry=array_get_next(&(s->directory));
444 entry->attributes=0xf;
445 entry->reserved[0]=0;
446 entry->begin=0;
447 entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
448 }
1e080d5d 449 for(i=0;i<26*number_of_entries;i++) {
de167e41
FB
450 int offset=(i%26);
451 if(offset<10) offset=1+offset;
452 else if(offset<22) offset=14+offset-10;
453 else offset=28+offset-22;
454 entry=array_get(&(s->directory),s->directory.next-1-(i/26));
455 entry->name[offset]=buffer[i];
456 }
457 return array_get(&(s->directory),s->directory.next-number_of_entries);
458}
459
c227f099 460static char is_free(const direntry_t* direntry)
a046433a 461{
ad1a897e 462 return direntry->name[0]==0xe5 || direntry->name[0]==0x00;
a046433a
FB
463}
464
c227f099 465static char is_volume_label(const direntry_t* direntry)
a046433a
FB
466{
467 return direntry->attributes == 0x28;
468}
469
c227f099 470static char is_long_name(const direntry_t* direntry)
a046433a
FB
471{
472 return direntry->attributes == 0xf;
473}
474
c227f099 475static char is_short_name(const direntry_t* direntry)
a046433a
FB
476{
477 return !is_volume_label(direntry) && !is_long_name(direntry)
478 && !is_free(direntry);
479}
480
c227f099 481static char is_directory(const direntry_t* direntry)
a046433a
FB
482{
483 return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
484}
485
c227f099 486static inline char is_dot(const direntry_t* direntry)
a046433a
FB
487{
488 return is_short_name(direntry) && direntry->name[0] == '.';
489}
490
c227f099 491static char is_file(const direntry_t* direntry)
a046433a
FB
492{
493 return is_short_name(direntry) && !is_directory(direntry);
494}
495
c227f099 496static inline uint32_t begin_of_direntry(const direntry_t* direntry)
a046433a
FB
497{
498 return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
499}
500
c227f099 501static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
a046433a
FB
502{
503 return le32_to_cpu(direntry->size);
504}
505
c227f099 506static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
a046433a
FB
507{
508 direntry->begin = cpu_to_le16(begin & 0xffff);
509 direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
510}
511
de167e41
FB
512/* fat functions */
513
c227f099 514static inline uint8_t fat_chksum(const direntry_t* entry)
de167e41
FB
515{
516 uint8_t chksum=0;
517 int i;
518
f671d173
SW
519 for (i = 0; i < ARRAY_SIZE(entry->name); i++) {
520 chksum = (((chksum & 0xfe) >> 1) |
521 ((chksum & 0x01) ? 0x80 : 0)) + entry->name[i];
5606c220 522 }
3b46e624 523
de167e41
FB
524 return chksum;
525}
526
527/* if return_time==0, this returns the fat_date, else the fat_time */
528static uint16_t fat_datetime(time_t time,int return_time) {
529 struct tm* t;
de167e41 530 struct tm t1;
6ab00cee 531 t = &t1;
de167e41 532 localtime_r(&time,t);
de167e41
FB
533 if(return_time)
534 return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
535 return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
536}
537
538static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
539{
a046433a
FB
540 if(s->fat_type==32) {
541 uint32_t* entry=array_get(&(s->fat),cluster);
542 *entry=cpu_to_le32(value);
de167e41
FB
543 } else if(s->fat_type==16) {
544 uint16_t* entry=array_get(&(s->fat),cluster);
545 *entry=cpu_to_le16(value&0xffff);
546 } else {
a046433a
FB
547 int offset = (cluster*3/2);
548 unsigned char* p = array_get(&(s->fat), offset);
549 switch (cluster&1) {
550 case 0:
551 p[0] = value&0xff;
552 p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
553 break;
554 case 1:
555 p[0] = (p[0]&0xf) | ((value&0xf)<<4);
556 p[1] = (value>>4);
557 break;
558 }
de167e41
FB
559 }
560}
561
562static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
563{
a046433a
FB
564 if(s->fat_type==32) {
565 uint32_t* entry=array_get(&(s->fat),cluster);
566 return le32_to_cpu(*entry);
de167e41
FB
567 } else if(s->fat_type==16) {
568 uint16_t* entry=array_get(&(s->fat),cluster);
569 return le16_to_cpu(*entry);
570 } else {
ffe8ab83 571 const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
a046433a 572 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
de167e41
FB
573 }
574}
575
576static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
577{
578 if(fat_entry>s->max_fat_value-8)
579 return -1;
580 return 0;
581}
582
583static inline void init_fat(BDRVVVFATState* s)
584{
a046433a
FB
585 if (s->fat_type == 12) {
586 array_init(&(s->fat),1);
587 array_ensure_allocated(&(s->fat),
588 s->sectors_per_fat * 0x200 * 3 / 2 - 1);
589 } else {
590 array_init(&(s->fat),(s->fat_type==32?4:2));
591 array_ensure_allocated(&(s->fat),
592 s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
593 }
de167e41 594 memset(s->fat.pointer,0,s->fat.size);
3b46e624 595
de167e41
FB
596 switch(s->fat_type) {
597 case 12: s->max_fat_value=0xfff; break;
598 case 16: s->max_fat_value=0xffff; break;
a046433a 599 case 32: s->max_fat_value=0x0fffffff; break;
de167e41
FB
600 default: s->max_fat_value=0; /* error... */
601 }
602
603}
604
a046433a
FB
605/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
606/* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
c227f099 607static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
a046433a 608 unsigned int directory_start, const char* filename, int is_dot)
de167e41 609{
a046433a 610 int i,j,long_index=s->directory.next;
c227f099
AL
611 direntry_t* entry = NULL;
612 direntry_t* entry_long = NULL;
de167e41
FB
613
614 if(is_dot) {
615 entry=array_get_next(&(s->directory));
f671d173 616 memset(entry->name, 0x20, sizeof(entry->name));
de167e41
FB
617 memcpy(entry->name,filename,strlen(filename));
618 return entry;
619 }
3b46e624 620
de167e41 621 entry_long=create_long_filename(s,filename);
3b46e624 622
5fafdf24 623 i = strlen(filename);
a046433a
FB
624 for(j = i - 1; j>0 && filename[j]!='.';j--);
625 if (j > 0)
626 i = (j > 8 ? 8 : j);
627 else if (i > 8)
628 i = 8;
629
de167e41 630 entry=array_get_next(&(s->directory));
f671d173 631 memset(entry->name, 0x20, sizeof(entry->name));
51a0f568 632 memcpy(entry->name, filename, i);
3b46e624 633
f671d173
SW
634 if (j > 0) {
635 for (i = 0; i < 3 && filename[j + 1 + i]; i++) {
636 entry->name[8 + i] = filename[j + 1 + i];
637 }
638 }
de167e41
FB
639
640 /* upcase & remove unwanted characters */
641 for(i=10;i>=0;i--) {
a046433a 642 if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
de167e41 643 if(entry->name[i]<=' ' || entry->name[i]>0x7f
a046433a 644 || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
de167e41
FB
645 entry->name[i]='_';
646 else if(entry->name[i]>='a' && entry->name[i]<='z')
647 entry->name[i]+='A'-'a';
648 }
649
650 /* mangle duplicates */
651 while(1) {
c227f099 652 direntry_t* entry1=array_get(&(s->directory),directory_start);
de167e41
FB
653 int j;
654
655 for(;entry1<entry;entry1++)
a046433a 656 if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
de167e41
FB
657 break; /* found dupe */
658 if(entry1==entry) /* no dupe found */
659 break;
660
5fafdf24 661 /* use all 8 characters of name */
de167e41
FB
662 if(entry->name[7]==' ') {
663 int j;
664 for(j=6;j>0 && entry->name[j]==' ';j--)
665 entry->name[j]='~';
666 }
667
668 /* increment number */
669 for(j=7;j>0 && entry->name[j]=='9';j--)
670 entry->name[j]='0';
671 if(j>0) {
672 if(entry->name[j]<'0' || entry->name[j]>'9')
673 entry->name[j]='0';
674 else
675 entry->name[j]++;
676 }
677 }
678
679 /* calculate checksum; propagate to long name */
680 if(entry_long) {
681 uint8_t chksum=fat_chksum(entry);
682
683 /* calculate anew, because realloc could have taken place */
684 entry_long=array_get(&(s->directory),long_index);
a046433a 685 while(entry_long<entry && is_long_name(entry_long)) {
de167e41
FB
686 entry_long->reserved[1]=chksum;
687 entry_long++;
688 }
689 }
690
691 return entry;
692}
693
a046433a
FB
694/*
695 * Read a directory. (the index of the corresponding mapping must be passed).
696 */
697static int read_directory(BDRVVVFATState* s, int mapping_index)
de167e41 698{
c227f099
AL
699 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
700 direntry_t* direntry;
a046433a
FB
701 const char* dirname = mapping->path;
702 int first_cluster = mapping->begin;
703 int parent_index = mapping->info.dir.parent_mapping_index;
c227f099 704 mapping_t* parent_mapping = (mapping_t*)
511d2b14 705 (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL);
a046433a 706 int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
de167e41
FB
707
708 DIR* dir=opendir(dirname);
709 struct dirent* entry;
de167e41
FB
710 int i;
711
a046433a
FB
712 assert(mapping->mode & MODE_DIRECTORY);
713
714 if(!dir) {
715 mapping->end = mapping->begin;
de167e41 716 return -1;
a046433a 717 }
3b46e624 718
a046433a
FB
719 i = mapping->info.dir.first_dir_index =
720 first_cluster == 0 ? 0 : s->directory.next;
721
5fafdf24 722 /* actually read the directory, and allocate the mappings */
de167e41
FB
723 while((entry=readdir(dir))) {
724 unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
725 char* buffer;
c227f099 726 direntry_t* direntry;
a046433a 727 struct stat st;
de167e41
FB
728 int is_dot=!strcmp(entry->d_name,".");
729 int is_dotdot=!strcmp(entry->d_name,"..");
730
a046433a 731 if(first_cluster == 0 && (is_dotdot || is_dot))
de167e41 732 continue;
5fafdf24 733
d4df3dbc 734 buffer = g_malloc(length);
de167e41
FB
735 snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
736
737 if(stat(buffer,&st)<0) {
ce137829 738 g_free(buffer);
de167e41
FB
739 continue;
740 }
741
742 /* create directory entry for this file */
a046433a
FB
743 direntry=create_short_and_long_name(s, i, entry->d_name,
744 is_dot || is_dotdot);
de167e41
FB
745 direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
746 direntry->reserved[0]=direntry->reserved[1]=0;
747 direntry->ctime=fat_datetime(st.st_ctime,1);
748 direntry->cdate=fat_datetime(st.st_ctime,0);
749 direntry->adate=fat_datetime(st.st_atime,0);
750 direntry->begin_hi=0;
751 direntry->mtime=fat_datetime(st.st_mtime,1);
752 direntry->mdate=fat_datetime(st.st_mtime,0);
753 if(is_dotdot)
a046433a 754 set_begin_of_direntry(direntry, first_cluster_of_parent);
de167e41 755 else if(is_dot)
a046433a 756 set_begin_of_direntry(direntry, first_cluster);
de167e41 757 else
a046433a
FB
758 direntry->begin=0; /* do that later */
759 if (st.st_size > 0x7fffffff) {
760 fprintf(stderr, "File %s is larger than 2GB\n", buffer);
ce137829 761 g_free(buffer);
08089edc 762 closedir(dir);
a046433a
FB
763 return -2;
764 }
765 direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
de167e41
FB
766
767 /* create mapping for this file */
a046433a 768 if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
d4df3dbc 769 s->current_mapping = array_get_next(&(s->mapping));
de167e41
FB
770 s->current_mapping->begin=0;
771 s->current_mapping->end=st.st_size;
a046433a
FB
772 /*
773 * we get the direntry of the most recent direntry, which
774 * contains the short name and all the relevant information.
775 */
de167e41 776 s->current_mapping->dir_index=s->directory.next-1;
a046433a
FB
777 s->current_mapping->first_mapping_index = -1;
778 if (S_ISDIR(st.st_mode)) {
779 s->current_mapping->mode = MODE_DIRECTORY;
780 s->current_mapping->info.dir.parent_mapping_index =
781 mapping_index;
782 } else {
783 s->current_mapping->mode = MODE_UNDEFINED;
784 s->current_mapping->info.file.offset = 0;
785 }
786 s->current_mapping->path=buffer;
787 s->current_mapping->read_only =
788 (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
b122c3b6
MA
789 } else {
790 g_free(buffer);
791 }
de167e41
FB
792 }
793 closedir(dir);
794
795 /* fill with zeroes up to the end of the cluster */
796 while(s->directory.next%(0x10*s->sectors_per_cluster)) {
c227f099
AL
797 direntry_t* direntry=array_get_next(&(s->directory));
798 memset(direntry,0,sizeof(direntry_t));
de167e41
FB
799 }
800
a046433a
FB
801/* TODO: if there are more entries, bootsector has to be adjusted! */
802#define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
803 if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
804 /* root directory */
805 int cur = s->directory.next;
806 array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
2b6a43a8 807 s->directory.next = ROOT_ENTRIES;
a046433a 808 memset(array_get(&(s->directory), cur), 0,
c227f099 809 (ROOT_ENTRIES - cur) * sizeof(direntry_t));
de167e41 810 }
5fafdf24 811
a046433a 812 /* reget the mapping, since s->mapping was possibly realloc()ed */
d4df3dbc 813 mapping = array_get(&(s->mapping), mapping_index);
a046433a
FB
814 first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
815 * 0x20 / s->cluster_size;
816 mapping->end = first_cluster;
817
d4df3dbc 818 direntry = array_get(&(s->directory), mapping->dir_index);
a046433a 819 set_begin_of_direntry(direntry, mapping->begin);
3b46e624 820
a046433a
FB
821 return 0;
822}
de167e41 823
a046433a
FB
824static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
825{
826 return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
827}
de167e41 828
a046433a
FB
829static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
830{
831 return s->faked_sectors + s->sectors_per_cluster * cluster_num;
832}
de167e41 833
a046433a 834static int init_directories(BDRVVVFATState* s,
d11c8917
MA
835 const char *dirname, int heads, int secs,
836 Error **errp)
de167e41 837{
c227f099
AL
838 bootsector_t* bootsector;
839 mapping_t* mapping;
de167e41
FB
840 unsigned int i;
841 unsigned int cluster;
842
843 memset(&(s->first_sectors[0]),0,0x40*0x200);
844
de167e41 845 s->cluster_size=s->sectors_per_cluster*0x200;
7267c094 846 s->cluster_buffer=g_malloc(s->cluster_size);
a046433a
FB
847
848 /*
849 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
850 * where sc is sector_count,
851 * spf is sectors_per_fat,
852 * spc is sectors_per_clusters, and
853 * fat_type = 12, 16 or 32.
854 */
855 i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
856 s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
3b46e624 857
c227f099
AL
858 array_init(&(s->mapping),sizeof(mapping_t));
859 array_init(&(s->directory),sizeof(direntry_t));
de167e41
FB
860
861 /* add volume label */
862 {
c227f099 863 direntry_t* entry=array_get_next(&(s->directory));
de167e41 864 entry->attributes=0x28; /* archive | volume label */
d5941dda 865 memcpy(entry->name, s->volume_label, sizeof(entry->name));
de167e41
FB
866 }
867
de167e41
FB
868 /* Now build FAT, and write back information into directory */
869 init_fat(s);
870
a046433a
FB
871 s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
872 s->cluster_count=sector2cluster(s, s->sector_count);
873
874 mapping = array_get_next(&(s->mapping));
875 mapping->begin = 0;
876 mapping->dir_index = 0;
877 mapping->info.dir.parent_mapping_index = -1;
878 mapping->first_mapping_index = -1;
7267c094 879 mapping->path = g_strdup(dirname);
a046433a
FB
880 i = strlen(mapping->path);
881 if (i > 0 && mapping->path[i - 1] == '/')
882 mapping->path[i - 1] = '\0';
883 mapping->mode = MODE_DIRECTORY;
884 mapping->read_only = 0;
885 s->path = mapping->path;
886
887 for (i = 0, cluster = 0; i < s->mapping.next; i++) {
5fafdf24 888 /* MS-DOS expects the FAT to be 0 for the root directory
a046433a
FB
889 * (except for the media byte). */
890 /* LATER TODO: still true for FAT32? */
891 int fix_fat = (i != 0);
892 mapping = array_get(&(s->mapping), i);
893
894 if (mapping->mode & MODE_DIRECTORY) {
895 mapping->begin = cluster;
896 if(read_directory(s, i)) {
d11c8917
MA
897 error_setg(errp, "Could not read directory %s",
898 mapping->path);
de167e41
FB
899 return -1;
900 }
a046433a
FB
901 mapping = array_get(&(s->mapping), i);
902 } else {
903 assert(mapping->mode == MODE_UNDEFINED);
de167e41 904 mapping->mode=MODE_NORMAL;
a046433a
FB
905 mapping->begin = cluster;
906 if (mapping->end > 0) {
c227f099 907 direntry_t* direntry = array_get(&(s->directory),
a046433a
FB
908 mapping->dir_index);
909
910 mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
911 set_begin_of_direntry(direntry, mapping->begin);
912 } else {
913 mapping->end = cluster + 1;
914 fix_fat = 0;
de167e41 915 }
a046433a
FB
916 }
917
918 assert(mapping->begin < mapping->end);
919
8ce0f869
AZ
920 /* next free cluster */
921 cluster = mapping->end;
922
923 if(cluster > s->cluster_count) {
d11c8917
MA
924 error_setg(errp,
925 "Directory does not fit in FAT%d (capacity %.2f MB)",
926 s->fat_type, s->sector_count / 2000.0);
927 return -1;
8ce0f869
AZ
928 }
929
a046433a
FB
930 /* fix fat for entry */
931 if (fix_fat) {
8ce0f869 932 int j;
a046433a
FB
933 for(j = mapping->begin; j < mapping->end - 1; j++)
934 fat_set(s, j, j+1);
935 fat_set(s, mapping->end - 1, s->max_fat_value);
936 }
de167e41
FB
937 }
938
a046433a
FB
939 mapping = array_get(&(s->mapping), 0);
940 s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
941 s->last_cluster_of_root_directory = mapping->end;
942
943 /* the FAT signature */
944 fat_set(s,0,s->max_fat_value);
945 fat_set(s,1,s->max_fat_value);
de167e41 946
a046433a
FB
947 s->current_mapping = NULL;
948
c227f099 949 bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
de167e41
FB
950 bootsector->jump[0]=0xeb;
951 bootsector->jump[1]=0x3e;
952 bootsector->jump[2]=0x90;
953 memcpy(bootsector->name,"QEMU ",8);
954 bootsector->sector_size=cpu_to_le16(0x200);
955 bootsector->sectors_per_cluster=s->sectors_per_cluster;
956 bootsector->reserved_sectors=cpu_to_le16(1);
957 bootsector->number_of_fats=0x2; /* number of FATs */
958 bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
a046433a 959 bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
aad37c06 960 bootsector->media_type=(s->first_sectors_number>1?0xf8:0xf0); /* media descriptor (f8=hd, f0=3.5 fd)*/
a046433a 961 s->fat.pointer[0] = bootsector->media_type;
de167e41 962 bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
4480e0f9
MA
963 bootsector->sectors_per_track = cpu_to_le16(secs);
964 bootsector->number_of_heads = cpu_to_le16(heads);
de167e41 965 bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
a046433a 966 bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
de167e41 967
a046433a 968 /* LATER TODO: if FAT32, this is wrong */
aad37c06 969 bootsector->u.fat16.drive_number=s->first_sectors_number==1?0:0x80; /* fda=0, hda=0x80 */
de167e41
FB
970 bootsector->u.fat16.current_head=0;
971 bootsector->u.fat16.signature=0x29;
972 bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
973
d5941dda
WB
974 memcpy(bootsector->u.fat16.volume_label, s->volume_label,
975 sizeof(bootsector->u.fat16.volume_label));
de167e41
FB
976 memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12 ":s->fat_type==16?"FAT16 ":"FAT32 "),8);
977 bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
978
979 return 0;
980}
981
83f64091 982#ifdef DEBUG
a046433a 983static BDRVVVFATState *vvv = NULL;
83f64091 984#endif
a046433a 985
68c70af1 986static int enable_write_target(BDRVVVFATState *s, Error **errp);
a046433a
FB
987static int is_consistent(BDRVVVFATState *s);
988
7ad9be64
KW
989static QemuOptsList runtime_opts = {
990 .name = "vvfat",
991 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
992 .desc = {
993 {
994 .name = "dir",
995 .type = QEMU_OPT_STRING,
996 .help = "Host directory to map to the vvfat device",
997 },
998 {
999 .name = "fat-type",
1000 .type = QEMU_OPT_NUMBER,
1001 .help = "FAT type (12, 16 or 32)",
1002 },
1003 {
1004 .name = "floppy",
1005 .type = QEMU_OPT_BOOL,
1006 .help = "Create a floppy rather than a hard disk image",
1007 },
d5941dda
WB
1008 {
1009 .name = "label",
1010 .type = QEMU_OPT_STRING,
1011 .help = "Use a volume label other than QEMU VVFAT",
1012 },
7ad9be64
KW
1013 {
1014 .name = "rw",
1015 .type = QEMU_OPT_BOOL,
1016 .help = "Make the image writable",
1017 },
1018 { /* end of list */ }
1019 },
1020};
1021
1022static void vvfat_parse_filename(const char *filename, QDict *options,
1023 Error **errp)
1024{
1025 int fat_type = 0;
1026 bool floppy = false;
1027 bool rw = false;
1028 int i;
1029
1030 if (!strstart(filename, "fat:", NULL)) {
1031 error_setg(errp, "File name string must start with 'fat:'");
1032 return;
1033 }
1034
1035 /* Parse options */
1036 if (strstr(filename, ":32:")) {
1037 fat_type = 32;
1038 } else if (strstr(filename, ":16:")) {
1039 fat_type = 16;
1040 } else if (strstr(filename, ":12:")) {
1041 fat_type = 12;
1042 }
1043
1044 if (strstr(filename, ":floppy:")) {
1045 floppy = true;
1046 }
1047
1048 if (strstr(filename, ":rw:")) {
1049 rw = true;
1050 }
1051
1052 /* Get the directory name without options */
1053 i = strrchr(filename, ':') - filename;
1054 assert(i >= 3);
1055 if (filename[i - 2] == ':' && qemu_isalpha(filename[i - 1])) {
1056 /* workaround for DOS drive names */
1057 filename += i - 1;
1058 } else {
1059 filename += i + 1;
1060 }
1061
1062 /* Fill in the options QDict */
1063 qdict_put(options, "dir", qstring_from_str(filename));
1064 qdict_put(options, "fat-type", qint_from_int(fat_type));
fc48ffc3
EB
1065 qdict_put(options, "floppy", qbool_from_bool(floppy));
1066 qdict_put(options, "rw", qbool_from_bool(rw));
7ad9be64
KW
1067}
1068
015a1036
HR
1069static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
1070 Error **errp)
de167e41
FB
1071{
1072 BDRVVVFATState *s = bs->opaque;
7ad9be64
KW
1073 int cyls, heads, secs;
1074 bool floppy;
d5941dda 1075 const char *dirname, *label;
7ad9be64
KW
1076 QemuOpts *opts;
1077 Error *local_err = NULL;
1078 int ret;
de167e41 1079
83f64091 1080#ifdef DEBUG
a046433a 1081 vvv = s;
83f64091 1082#endif
a046433a 1083
87ea75d5 1084 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
7ad9be64 1085 qemu_opts_absorb_qdict(opts, options, &local_err);
84d18f06 1086 if (local_err) {
c0f92b52 1087 error_propagate(errp, local_err);
7ad9be64
KW
1088 ret = -EINVAL;
1089 goto fail;
1090 }
1091
1092 dirname = qemu_opt_get(opts, "dir");
1093 if (!dirname) {
c0f92b52 1094 error_setg(errp, "vvfat block driver requires a 'dir' option");
7ad9be64
KW
1095 ret = -EINVAL;
1096 goto fail;
1097 }
1098
1099 s->fat_type = qemu_opt_get_number(opts, "fat-type", 0);
1100 floppy = qemu_opt_get_bool(opts, "floppy", false);
1101
d5941dda
WB
1102 memset(s->volume_label, ' ', sizeof(s->volume_label));
1103 label = qemu_opt_get(opts, "label");
1104 if (label) {
1105 size_t label_length = strlen(label);
1106 if (label_length > 11) {
1107 error_setg(errp, "vvfat label cannot be longer than 11 bytes");
1108 ret = -EINVAL;
1109 goto fail;
1110 }
1111 memcpy(s->volume_label, label, label_length);
d208c50d
KW
1112 } else {
1113 memcpy(s->volume_label, "QEMU VVFAT", 10);
d5941dda
WB
1114 }
1115
7ad9be64
KW
1116 if (floppy) {
1117 /* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */
1118 if (!s->fat_type) {
1119 s->fat_type = 12;
1120 secs = 36;
1121 s->sectors_per_cluster = 2;
1122 } else {
1123 secs = s->fat_type == 12 ? 18 : 36;
1124 s->sectors_per_cluster = 1;
1125 }
1126 s->first_sectors_number = 1;
1127 cyls = 80;
1128 heads = 2;
1129 } else {
1130 /* 32MB or 504MB disk*/
1131 if (!s->fat_type) {
1132 s->fat_type = 16;
1133 }
4c709660 1134 s->first_sectors_number = 0x40;
7ad9be64
KW
1135 cyls = s->fat_type == 12 ? 64 : 1024;
1136 heads = 16;
1137 secs = 63;
1138 }
1139
1140 switch (s->fat_type) {
1141 case 32:
1142 fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. "
1143 "You are welcome to do so!\n");
1144 break;
1145 case 16:
1146 case 12:
1147 break;
1148 default:
c0f92b52 1149 error_setg(errp, "Valid FAT types are only 12, 16 and 32");
7ad9be64
KW
1150 ret = -EINVAL;
1151 goto fail;
1152 }
1153
1154
a046433a
FB
1155 s->bs = bs;
1156
a046433a 1157 /* LATER TODO: if FAT32, adjust */
a046433a 1158 s->sectors_per_cluster=0x10;
de167e41
FB
1159
1160 s->current_cluster=0xffffffff;
de167e41 1161
a046433a
FB
1162 /* read only is the default for safety */
1163 bs->read_only = 1;
1164 s->qcow = s->write_target = NULL;
1165 s->qcow_filename = NULL;
1166 s->fat2 = NULL;
1167 s->downcase_short_names = 1;
3b46e624 1168
4480e0f9
MA
1169 fprintf(stderr, "vvfat %s chs %d,%d,%d\n",
1170 dirname, cyls, heads, secs);
a046433a 1171
4480e0f9 1172 s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
5a742b55 1173
7ad9be64 1174 if (qemu_opt_get_bool(opts, "rw", false)) {
68c70af1 1175 ret = enable_write_target(s, errp);
78f27bd0 1176 if (ret < 0) {
7ad9be64
KW
1177 goto fail;
1178 }
1179 bs->read_only = 0;
b570094d
TS
1180 }
1181
4575eb49 1182 bs->request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O supported */
4480e0f9 1183 bs->total_sectors = cyls * heads * secs;
b570094d 1184
d11c8917 1185 if (init_directories(s, dirname, heads, secs, errp)) {
7ad9be64
KW
1186 ret = -EIO;
1187 goto fail;
4480e0f9 1188 }
de167e41 1189
b570094d
TS
1190 s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
1191
4480e0f9
MA
1192 if (s->first_sectors_number == 0x40) {
1193 init_mbr(s, cyls, heads, secs);
273e4e03 1194 }
a046433a
FB
1195
1196 // assert(is_consistent(s));
848c66e8 1197 qemu_co_mutex_init(&s->lock);
3397f0cb
KW
1198
1199 /* Disable migration when vvfat is used rw */
1200 if (s->qcow) {
81e5f78a
AG
1201 error_setg(&s->migration_blocker,
1202 "The vvfat (rw) format used by node '%s' "
1203 "does not support live migration",
1204 bdrv_get_device_or_node_name(bs));
3397f0cb
KW
1205 migrate_add_blocker(s->migration_blocker);
1206 }
1207
7ad9be64
KW
1208 ret = 0;
1209fail:
1210 qemu_opts_del(opts);
1211 return ret;
de167e41
FB
1212}
1213
1214static inline void vvfat_close_current_file(BDRVVVFATState *s)
1215{
1216 if(s->current_mapping) {
a046433a
FB
1217 s->current_mapping = NULL;
1218 if (s->current_fd) {
2e1e79da 1219 qemu_close(s->current_fd);
a046433a
FB
1220 s->current_fd = 0;
1221 }
de167e41 1222 }
a046433a 1223 s->current_cluster = -1;
de167e41
FB
1224}
1225
1226/* mappings between index1 and index2-1 are supposed to be ordered
1227 * return value is the index of the last mapping for which end>cluster_num
1228 */
1229static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1230{
de167e41 1231 while(1) {
88bf7950 1232 int index3;
c227f099 1233 mapping_t* mapping;
de167e41
FB
1234 index3=(index1+index2)/2;
1235 mapping=array_get(&(s->mapping),index3);
a046433a
FB
1236 assert(mapping->begin < mapping->end);
1237 if(mapping->begin>=cluster_num) {
de167e41
FB
1238 assert(index2!=index3 || index2==0);
1239 if(index2==index3)
a046433a 1240 return index1;
de167e41
FB
1241 index2=index3;
1242 } else {
1243 if(index1==index3)
a046433a 1244 return mapping->end<=cluster_num ? index2 : index1;
de167e41
FB
1245 index1=index3;
1246 }
1247 assert(index1<=index2);
a046433a
FB
1248 DLOG(mapping=array_get(&(s->mapping),index1);
1249 assert(mapping->begin<=cluster_num);
5fafdf24 1250 assert(index2 >= s->mapping.next ||
a046433a
FB
1251 ((mapping = array_get(&(s->mapping),index2)) &&
1252 mapping->end>cluster_num)));
de167e41
FB
1253 }
1254}
1255
c227f099 1256static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
de167e41
FB
1257{
1258 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
c227f099 1259 mapping_t* mapping;
de167e41 1260 if(index>=s->mapping.next)
511d2b14 1261 return NULL;
de167e41
FB
1262 mapping=array_get(&(s->mapping),index);
1263 if(mapping->begin>cluster_num)
511d2b14 1264 return NULL;
a046433a 1265 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
de167e41
FB
1266 return mapping;
1267}
1268
c227f099 1269static int open_file(BDRVVVFATState* s,mapping_t* mapping)
de167e41
FB
1270{
1271 if(!mapping)
1272 return -1;
de167e41 1273 if(!s->current_mapping ||
a046433a 1274 strcmp(s->current_mapping->path,mapping->path)) {
de167e41 1275 /* open file */
6165f4d8 1276 int fd = qemu_open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
de167e41
FB
1277 if(fd<0)
1278 return -1;
1279 vvfat_close_current_file(s);
1280 s->current_fd = fd;
de167e41
FB
1281 s->current_mapping = mapping;
1282 }
1283 return 0;
1284}
1285
1286static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1287{
1288 if(s->current_cluster != cluster_num) {
1289 int result=0;
1290 off_t offset;
a046433a 1291 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
de167e41
FB
1292 if(!s->current_mapping
1293 || s->current_mapping->begin>cluster_num
1294 || s->current_mapping->end<=cluster_num) {
1295 /* binary search of mappings for file */
c227f099 1296 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
a046433a
FB
1297
1298 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1299
1300 if (mapping && mapping->mode & MODE_DIRECTORY) {
1301 vvfat_close_current_file(s);
1302 s->current_mapping = mapping;
1303read_cluster_directory:
1304 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
ffe8ab83 1305 s->cluster = (unsigned char*)s->directory.pointer+offset
a046433a
FB
1306 + 0x20*s->current_mapping->info.dir.first_dir_index;
1307 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1308 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1309 s->current_cluster = cluster_num;
1310 return 0;
1311 }
1312
1313 if(open_file(s,mapping))
de167e41 1314 return -2;
a046433a
FB
1315 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1316 goto read_cluster_directory;
de167e41 1317
a046433a
FB
1318 assert(s->current_fd);
1319
1320 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
de167e41
FB
1321 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1322 return -3;
a046433a 1323 s->cluster=s->cluster_buffer;
de167e41
FB
1324 result=read(s->current_fd,s->cluster,s->cluster_size);
1325 if(result<0) {
1326 s->current_cluster = -1;
1327 return -1;
1328 }
1329 s->current_cluster = cluster_num;
1330 }
1331 return 0;
1332}
1333
a046433a 1334#ifdef DEBUG
c227f099 1335static void print_direntry(const direntry_t* direntry)
de167e41 1336{
a046433a
FB
1337 int j = 0;
1338 char buffer[1024];
1339
3e89cb04 1340 fprintf(stderr, "direntry %p: ", direntry);
de167e41
FB
1341 if(!direntry)
1342 return;
a046433a 1343 if(is_long_name(direntry)) {
de167e41
FB
1344 unsigned char* c=(unsigned char*)direntry;
1345 int i;
1346 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
3891b370 1347#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
a046433a 1348 ADD_CHAR(c[i]);
de167e41 1349 for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
a046433a 1350 ADD_CHAR(c[i]);
de167e41 1351 for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
a046433a
FB
1352 ADD_CHAR(c[i]);
1353 buffer[j] = 0;
1354 fprintf(stderr, "%s\n", buffer);
de167e41
FB
1355 } else {
1356 int i;
1357 for(i=0;i<11;i++)
a046433a
FB
1358 ADD_CHAR(direntry->name[i]);
1359 buffer[j] = 0;
1360 fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1361 buffer,
de167e41 1362 direntry->attributes,
a046433a 1363 begin_of_direntry(direntry),le32_to_cpu(direntry->size));
de167e41
FB
1364 }
1365}
1366
c227f099 1367static void print_mapping(const mapping_t* mapping)
de167e41 1368{
3e89cb04
KW
1369 fprintf(stderr, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1370 "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1371 mapping, mapping->begin, mapping->end, mapping->dir_index,
1372 mapping->first_mapping_index, mapping->path, mapping->mode);
1373
a046433a
FB
1374 if (mapping->mode & MODE_DIRECTORY)
1375 fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1376 else
1377 fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
de167e41 1378}
a046433a 1379#endif
de167e41 1380
5fafdf24 1381static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
a046433a 1382 uint8_t *buf, int nb_sectors)
de167e41 1383{
a046433a 1384 BDRVVVFATState *s = bs->opaque;
de167e41 1385 int i;
de167e41 1386
a046433a 1387 for(i=0;i<nb_sectors;i++,sector_num++) {
e654bfe4 1388 if (sector_num >= bs->total_sectors)
a046433a
FB
1389 return -1;
1390 if (s->qcow) {
1391 int n;
7704df98 1392 if (bdrv_is_allocated(s->qcow, sector_num, nb_sectors-i, &n)) {
a046433a 1393DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
7704df98
KW
1394 if (bdrv_read(s->qcow, sector_num, buf + i*0x200, n)) {
1395 return -1;
1396 }
1397 i += n - 1;
1398 sector_num += n - 1;
1399 continue;
1400 }
a046433a 1401DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
de167e41 1402 }
a046433a
FB
1403 if(sector_num<s->faked_sectors) {
1404 if(sector_num<s->first_sectors_number)
1405 memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
1406 else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
1407 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
1408 else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
1409 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
1410 } else {
1411 uint32_t sector=sector_num-s->faked_sectors,
1412 sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1413 cluster_num=sector/s->sectors_per_cluster;
e654bfe4 1414 if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) {
a046433a
FB
1415 /* LATER TODO: strict: return -1; */
1416 memset(buf+i*0x200,0,0x200);
1417 continue;
de167e41 1418 }
a046433a 1419 memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
de167e41
FB
1420 }
1421 }
de167e41
FB
1422 return 0;
1423}
1424
4575eb49
KW
1425static int coroutine_fn
1426vvfat_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
1427 QEMUIOVector *qiov, int flags)
2914caa0
PB
1428{
1429 int ret;
1430 BDRVVVFATState *s = bs->opaque;
4575eb49
KW
1431 uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
1432 int nb_sectors = bytes >> BDRV_SECTOR_BITS;
1433 void *buf;
1434
1435 assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
1436 assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
1437
1438 buf = g_try_malloc(bytes);
1439 if (bytes && buf == NULL) {
1440 return -ENOMEM;
1441 }
1442
2914caa0
PB
1443 qemu_co_mutex_lock(&s->lock);
1444 ret = vvfat_read(bs, sector_num, buf, nb_sectors);
1445 qemu_co_mutex_unlock(&s->lock);
4575eb49
KW
1446
1447 qemu_iovec_from_buf(qiov, 0, buf, bytes);
1448 g_free(buf);
1449
2914caa0
PB
1450 return ret;
1451}
1452
a046433a 1453/* LATER TODO: statify all functions */
de167e41 1454
a046433a
FB
1455/*
1456 * Idea of the write support (use snapshot):
de167e41 1457 *
a046433a
FB
1458 * 1. check if all data is consistent, recording renames, modifications,
1459 * new files and directories (in s->commits).
de167e41 1460 *
a046433a 1461 * 2. if the data is not consistent, stop committing
de167e41 1462 *
a046433a
FB
1463 * 3. handle renames, and create new files and directories (do not yet
1464 * write their contents)
de167e41 1465 *
a046433a
FB
1466 * 4. walk the directories, fixing the mapping and direntries, and marking
1467 * the handled mappings as not deleted
de167e41 1468 *
a046433a 1469 * 5. commit the contents of the files
de167e41 1470 *
a046433a 1471 * 6. handle deleted files and directories
de167e41
FB
1472 *
1473 */
1474
c227f099 1475typedef struct commit_t {
a046433a
FB
1476 char* path;
1477 union {
1478 struct { uint32_t cluster; } rename;
1479 struct { int dir_index; uint32_t modified_offset; } writeout;
1480 struct { uint32_t first_cluster; } new_file;
1481 struct { uint32_t cluster; } mkdir;
1482 } param;
1483 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1484 enum {
1485 ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1486 } action;
c227f099 1487} commit_t;
de167e41 1488
a046433a 1489static void clear_commits(BDRVVVFATState* s)
de167e41
FB
1490{
1491 int i;
a046433a
FB
1492DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1493 for (i = 0; i < s->commits.next; i++) {
c227f099 1494 commit_t* commit = array_get(&(s->commits), i);
a046433a
FB
1495 assert(commit->path || commit->action == ACTION_WRITEOUT);
1496 if (commit->action != ACTION_WRITEOUT) {
1497 assert(commit->path);
ce137829 1498 g_free(commit->path);
a046433a
FB
1499 } else
1500 assert(commit->path == NULL);
de167e41 1501 }
a046433a 1502 s->commits.next = 0;
de167e41
FB
1503}
1504
a046433a
FB
1505static void schedule_rename(BDRVVVFATState* s,
1506 uint32_t cluster, char* new_path)
de167e41 1507{
c227f099 1508 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1509 commit->path = new_path;
1510 commit->param.rename.cluster = cluster;
1511 commit->action = ACTION_RENAME;
de167e41
FB
1512}
1513
a046433a
FB
1514static void schedule_writeout(BDRVVVFATState* s,
1515 int dir_index, uint32_t modified_offset)
de167e41 1516{
c227f099 1517 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1518 commit->path = NULL;
1519 commit->param.writeout.dir_index = dir_index;
1520 commit->param.writeout.modified_offset = modified_offset;
1521 commit->action = ACTION_WRITEOUT;
de167e41
FB
1522}
1523
a046433a
FB
1524static void schedule_new_file(BDRVVVFATState* s,
1525 char* path, uint32_t first_cluster)
de167e41 1526{
c227f099 1527 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1528 commit->path = path;
1529 commit->param.new_file.first_cluster = first_cluster;
1530 commit->action = ACTION_NEW_FILE;
1531}
1532
1533static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1534{
c227f099 1535 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1536 commit->path = path;
1537 commit->param.mkdir.cluster = cluster;
1538 commit->action = ACTION_MKDIR;
1539}
1540
1541typedef struct {
64eaabda
TS
1542 /*
1543 * Since the sequence number is at most 0x3f, and the filename
1544 * length is at most 13 times the sequence number, the maximal
1545 * filename length is 0x3f * 13 bytes.
1546 */
1547 unsigned char name[0x3f * 13 + 1];
a046433a
FB
1548 int checksum, len;
1549 int sequence_number;
1550} long_file_name;
1551
1552static void lfn_init(long_file_name* lfn)
1553{
1554 lfn->sequence_number = lfn->len = 0;
1555 lfn->checksum = 0x100;
1556}
1557
1558/* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1559static int parse_long_name(long_file_name* lfn,
c227f099 1560 const direntry_t* direntry)
a046433a
FB
1561{
1562 int i, j, offset;
1563 const unsigned char* pointer = (const unsigned char*)direntry;
1564
1565 if (!is_long_name(direntry))
1566 return 1;
1567
1568 if (pointer[0] & 0x40) {
1569 lfn->sequence_number = pointer[0] & 0x3f;
1570 lfn->checksum = pointer[13];
1571 lfn->name[0] = 0;
59fdb018 1572 lfn->name[lfn->sequence_number * 13] = 0;
a046433a
FB
1573 } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
1574 return -1;
1575 else if (pointer[13] != lfn->checksum)
1576 return -2;
1577 else if (pointer[12] || pointer[26] || pointer[27])
1578 return -3;
1579
1580 offset = 13 * (lfn->sequence_number - 1);
1581 for (i = 0, j = 1; i < 13; i++, j+=2) {
1582 if (j == 11)
1583 j = 14;
1584 else if (j == 26)
1585 j = 28;
1586
1587 if (pointer[j+1] == 0)
1588 lfn->name[offset + i] = pointer[j];
1589 else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1590 return -4;
1591 else
1592 lfn->name[offset + i] = 0;
de167e41 1593 }
a046433a
FB
1594
1595 if (pointer[0] & 0x40)
ffe8ab83 1596 lfn->len = offset + strlen((char*)lfn->name + offset);
a046433a 1597
de167e41
FB
1598 return 0;
1599}
1600
a046433a
FB
1601/* returns 0 if successful, >0 if no short_name, and <0 on error */
1602static int parse_short_name(BDRVVVFATState* s,
c227f099 1603 long_file_name* lfn, direntry_t* direntry)
de167e41 1604{
a046433a 1605 int i, j;
de167e41 1606
a046433a
FB
1607 if (!is_short_name(direntry))
1608 return 1;
1609
1610 for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1611 for (i = 0; i <= j; i++) {
1612 if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
1613 return -1;
1614 else if (s->downcase_short_names)
47398b9c 1615 lfn->name[i] = qemu_tolower(direntry->name[i]);
a046433a
FB
1616 else
1617 lfn->name[i] = direntry->name[i];
de167e41
FB
1618 }
1619
f671d173
SW
1620 for (j = 2; j >= 0 && direntry->name[8 + j] == ' '; j--) {
1621 }
a046433a
FB
1622 if (j >= 0) {
1623 lfn->name[i++] = '.';
1624 lfn->name[i + j + 1] = '\0';
1625 for (;j >= 0; j--) {
f671d173
SW
1626 uint8_t c = direntry->name[8 + j];
1627 if (c <= ' ' || c > 0x7f) {
1628 return -2;
1629 } else if (s->downcase_short_names) {
1630 lfn->name[i + j] = qemu_tolower(c);
1631 } else {
1632 lfn->name[i + j] = c;
1633 }
a046433a
FB
1634 }
1635 } else
1636 lfn->name[i + j + 1] = '\0';
1637
ffe8ab83 1638 lfn->len = strlen((char*)lfn->name);
a046433a
FB
1639
1640 return 0;
de167e41
FB
1641}
1642
a046433a
FB
1643static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1644 unsigned int cluster)
de167e41 1645{
a046433a
FB
1646 if (cluster < s->last_cluster_of_root_directory) {
1647 if (cluster + 1 == s->last_cluster_of_root_directory)
1648 return s->max_fat_value;
1649 else
1650 return cluster + 1;
1651 }
1652
1653 if (s->fat_type==32) {
1654 uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1655 return le32_to_cpu(*entry);
1656 } else if (s->fat_type==16) {
1657 uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1658 return le16_to_cpu(*entry);
1659 } else {
1660 const uint8_t* x=s->fat2+cluster*3/2;
1661 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1662 }
1663}
1664
1665static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1666{
1667 int was_modified = 0;
1668 int i, dummy;
1669
1670 if (s->qcow == NULL)
de167e41 1671 return 0;
a046433a
FB
1672
1673 for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
7704df98 1674 was_modified = bdrv_is_allocated(s->qcow,
a046433a
FB
1675 cluster2sector(s, cluster_num) + i, 1, &dummy);
1676
1677 return was_modified;
de167e41
FB
1678}
1679
a046433a 1680static const char* get_basename(const char* path)
de167e41 1681{
a046433a
FB
1682 char* basename = strrchr(path, '/');
1683 if (basename == NULL)
1684 return path;
1685 else
1686 return basename + 1; /* strip '/' */
de167e41
FB
1687}
1688
a046433a
FB
1689/*
1690 * The array s->used_clusters holds the states of the clusters. If it is
1691 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1692 * was modified, bit 3 is set.
1693 * If any cluster is allocated, but not part of a file or directory, this
1694 * driver refuses to commit.
1695 */
1696typedef enum {
1697 USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
c227f099 1698} used_t;
de167e41 1699
a046433a
FB
1700/*
1701 * get_cluster_count_for_direntry() not only determines how many clusters
1702 * are occupied by direntry, but also if it was renamed or modified.
1703 *
1704 * A file is thought to be renamed *only* if there already was a file with
1705 * exactly the same first cluster, but a different name.
1706 *
1707 * Further, the files/directories handled by this function are
1708 * assumed to be *not* deleted (and *only* those).
1709 */
1710static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
c227f099 1711 direntry_t* direntry, const char* path)
de167e41 1712{
a046433a
FB
1713 /*
1714 * This is a little bit tricky:
1715 * IF the guest OS just inserts a cluster into the file chain,
1716 * and leaves the rest alone, (i.e. the original file had clusters
1717 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1718 *
1719 * - do_commit will write the cluster into the file at the given
1720 * offset, but
1721 *
1722 * - the cluster which is overwritten should be moved to a later
1723 * position in the file.
1724 *
1725 * I am not aware that any OS does something as braindead, but this
1726 * situation could happen anyway when not committing for a long time.
1727 * Just to be sure that this does not bite us, detect it, and copy the
1728 * contents of the clusters to-be-overwritten into the qcow.
1729 */
1730 int copy_it = 0;
1731 int was_modified = 0;
1732 int32_t ret = 0;
1733
1734 uint32_t cluster_num = begin_of_direntry(direntry);
1735 uint32_t offset = 0;
1736 int first_mapping_index = -1;
c227f099 1737 mapping_t* mapping = NULL;
a046433a 1738 const char* basename2 = NULL;
de167e41 1739
a046433a 1740 vvfat_close_current_file(s);
de167e41 1741
a046433a
FB
1742 /* the root directory */
1743 if (cluster_num == 0)
de167e41 1744 return 0;
de167e41 1745
a046433a
FB
1746 /* write support */
1747 if (s->qcow) {
1748 basename2 = get_basename(path);
de167e41 1749
a046433a
FB
1750 mapping = find_mapping_for_cluster(s, cluster_num);
1751
1752 if (mapping) {
da2414e9
FB
1753 const char* basename;
1754
a046433a
FB
1755 assert(mapping->mode & MODE_DELETED);
1756 mapping->mode &= ~MODE_DELETED;
1757
da2414e9 1758 basename = get_basename(mapping->path);
a046433a
FB
1759
1760 assert(mapping->mode & MODE_NORMAL);
1761
1762 /* rename */
1763 if (strcmp(basename, basename2))
7267c094 1764 schedule_rename(s, cluster_num, g_strdup(path));
a046433a
FB
1765 } else if (is_file(direntry))
1766 /* new file */
7267c094 1767 schedule_new_file(s, g_strdup(path), cluster_num);
a046433a 1768 else {
43dc2a64 1769 abort();
a046433a
FB
1770 return 0;
1771 }
de167e41
FB
1772 }
1773
a046433a
FB
1774 while(1) {
1775 if (s->qcow) {
1776 if (!copy_it && cluster_was_modified(s, cluster_num)) {
1777 if (mapping == NULL ||
1778 mapping->begin > cluster_num ||
1779 mapping->end <= cluster_num)
1780 mapping = find_mapping_for_cluster(s, cluster_num);
de167e41 1781
a046433a
FB
1782
1783 if (mapping &&
1784 (mapping->mode & MODE_DIRECTORY) == 0) {
1785
1786 /* was modified in qcow */
1787 if (offset != mapping->info.file.offset + s->cluster_size
1788 * (cluster_num - mapping->begin)) {
1789 /* offset of this cluster in file chain has changed */
43dc2a64 1790 abort();
a046433a
FB
1791 copy_it = 1;
1792 } else if (offset == 0) {
1793 const char* basename = get_basename(mapping->path);
1794
1795 if (strcmp(basename, basename2))
1796 copy_it = 1;
1797 first_mapping_index = array_index(&(s->mapping), mapping);
1798 }
1799
1800 if (mapping->first_mapping_index != first_mapping_index
1801 && mapping->info.file.offset > 0) {
43dc2a64 1802 abort();
a046433a
FB
1803 copy_it = 1;
1804 }
1805
1806 /* need to write out? */
1807 if (!was_modified && is_file(direntry)) {
1808 was_modified = 1;
1809 schedule_writeout(s, mapping->dir_index, offset);
1810 }
1811 }
1812 }
1813
1814 if (copy_it) {
1815 int i, dummy;
1816 /*
1817 * This is horribly inefficient, but that is okay, since
1818 * it is rarely executed, if at all.
1819 */
1820 int64_t offset = cluster2sector(s, cluster_num);
1821
1822 vvfat_close_current_file(s);
7704df98
KW
1823 for (i = 0; i < s->sectors_per_cluster; i++) {
1824 if (!bdrv_is_allocated(s->qcow, offset + i, 1, &dummy)) {
1825 if (vvfat_read(s->bs, offset, s->cluster_buffer, 1)) {
1826 return -1;
1827 }
1828 if (bdrv_write(s->qcow, offset, s->cluster_buffer, 1)) {
1829 return -2;
1830 }
1831 }
1832 }
a046433a
FB
1833 }
1834 }
1835
1836 ret++;
1837 if (s->used_clusters[cluster_num] & USED_ANY)
1838 return 0;
1839 s->used_clusters[cluster_num] = USED_FILE;
1840
1841 cluster_num = modified_fat_get(s, cluster_num);
1842
1843 if (fat_eof(s, cluster_num))
1844 return ret;
1845 else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
1846 return -1;
1847
1848 offset += s->cluster_size;
1849 }
de167e41
FB
1850}
1851
a046433a 1852/*
5fafdf24 1853 * This function looks at the modified data (qcow).
a046433a
FB
1854 * It returns 0 upon inconsistency or error, and the number of clusters
1855 * used by the directory, its subdirectories and their files.
1856 */
1857static int check_directory_consistency(BDRVVVFATState *s,
1858 int cluster_num, const char* path)
de167e41 1859{
a046433a 1860 int ret = 0;
7267c094 1861 unsigned char* cluster = g_malloc(s->cluster_size);
c227f099
AL
1862 direntry_t* direntries = (direntry_t*)cluster;
1863 mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
a046433a
FB
1864
1865 long_file_name lfn;
1866 int path_len = strlen(path);
0d460d6f 1867 char path2[PATH_MAX + 1];
a046433a
FB
1868
1869 assert(path_len < PATH_MAX); /* len was tested before! */
363a37d5 1870 pstrcpy(path2, sizeof(path2), path);
a046433a
FB
1871 path2[path_len] = '/';
1872 path2[path_len + 1] = '\0';
1873
1874 if (mapping) {
1875 const char* basename = get_basename(mapping->path);
1876 const char* basename2 = get_basename(path);
1877
1878 assert(mapping->mode & MODE_DIRECTORY);
1879
1880 assert(mapping->mode & MODE_DELETED);
1881 mapping->mode &= ~MODE_DELETED;
1882
1883 if (strcmp(basename, basename2))
7267c094 1884 schedule_rename(s, cluster_num, g_strdup(path));
a046433a
FB
1885 } else
1886 /* new directory */
7267c094 1887 schedule_mkdir(s, cluster_num, g_strdup(path));
3b46e624 1888
a046433a
FB
1889 lfn_init(&lfn);
1890 do {
de167e41 1891 int i;
a046433a
FB
1892 int subret = 0;
1893
1894 ret++;
1895
1896 if (s->used_clusters[cluster_num] & USED_ANY) {
1897 fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
6262bbd3 1898 goto fail;
a046433a
FB
1899 }
1900 s->used_clusters[cluster_num] = USED_DIRECTORY;
1901
1902DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
1903 subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
1904 s->sectors_per_cluster);
1905 if (subret) {
1906 fprintf(stderr, "Error fetching direntries\n");
1907 fail:
ce137829 1908 g_free(cluster);
a046433a
FB
1909 return 0;
1910 }
1911
1912 for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
3f4cb3d3 1913 int cluster_count = 0;
a046433a 1914
b2bedb21 1915DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i));
a046433a
FB
1916 if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
1917 is_free(direntries + i))
1918 continue;
1919
1920 subret = parse_long_name(&lfn, direntries + i);
1921 if (subret < 0) {
1922 fprintf(stderr, "Error in long name\n");
1923 goto fail;
de167e41 1924 }
a046433a
FB
1925 if (subret == 0 || is_free(direntries + i))
1926 continue;
1927
1928 if (fat_chksum(direntries+i) != lfn.checksum) {
1929 subret = parse_short_name(s, &lfn, direntries + i);
1930 if (subret < 0) {
1931 fprintf(stderr, "Error in short name (%d)\n", subret);
1932 goto fail;
1933 }
ffe8ab83
TS
1934 if (subret > 0 || !strcmp((char*)lfn.name, ".")
1935 || !strcmp((char*)lfn.name, ".."))
a046433a
FB
1936 continue;
1937 }
1938 lfn.checksum = 0x100; /* cannot use long name twice */
1939
1940 if (path_len + 1 + lfn.len >= PATH_MAX) {
1941 fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
1942 goto fail;
1943 }
363a37d5
BS
1944 pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
1945 (char*)lfn.name);
a046433a
FB
1946
1947 if (is_directory(direntries + i)) {
1948 if (begin_of_direntry(direntries + i) == 0) {
1949 DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
1950 goto fail;
1951 }
1952 cluster_count = check_directory_consistency(s,
1953 begin_of_direntry(direntries + i), path2);
1954 if (cluster_count == 0) {
1955 DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
1956 goto fail;
1957 }
1958 } else if (is_file(direntries + i)) {
1959 /* check file size with FAT */
1960 cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
1961 if (cluster_count !=
1962 (le32_to_cpu(direntries[i].size) + s->cluster_size
1963 - 1) / s->cluster_size) {
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
f67503e5 3000 s->qcow = NULL;
e6641719
HR
3001 options = qdict_new();
3002 qdict_put(options, "driver", qstring_from_str("qcow"));
3003 ret = bdrv_open(&s->qcow, s->qcow_filename, NULL, options,
61de4c68 3004 BDRV_O_RDWR | BDRV_O_NO_FLUSH, errp);
a655211a 3005 if (ret < 0) {
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