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