]> git.proxmox.com Git - mirror_qemu.git/blame - block/vvfat.c
nvdimm acpi: use common macros instead of magic names
[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
4480e0f9
MA
1188 if (s->first_sectors_number == 0x40) {
1189 init_mbr(s, cyls, heads, secs);
273e4e03 1190 }
a046433a
FB
1191
1192 // assert(is_consistent(s));
848c66e8 1193 qemu_co_mutex_init(&s->lock);
3397f0cb
KW
1194
1195 /* Disable migration when vvfat is used rw */
1196 if (s->qcow) {
81e5f78a
AG
1197 error_setg(&s->migration_blocker,
1198 "The vvfat (rw) format used by node '%s' "
1199 "does not support live migration",
1200 bdrv_get_device_or_node_name(bs));
3397f0cb
KW
1201 migrate_add_blocker(s->migration_blocker);
1202 }
1203
7ad9be64
KW
1204 ret = 0;
1205fail:
1206 qemu_opts_del(opts);
1207 return ret;
de167e41
FB
1208}
1209
a6506481
EB
1210static void vvfat_refresh_limits(BlockDriverState *bs, Error **errp)
1211{
a5b8dd2c 1212 bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */
a6506481
EB
1213}
1214
de167e41
FB
1215static inline void vvfat_close_current_file(BDRVVVFATState *s)
1216{
1217 if(s->current_mapping) {
a046433a
FB
1218 s->current_mapping = NULL;
1219 if (s->current_fd) {
2e1e79da 1220 qemu_close(s->current_fd);
a046433a
FB
1221 s->current_fd = 0;
1222 }
de167e41 1223 }
a046433a 1224 s->current_cluster = -1;
de167e41
FB
1225}
1226
1227/* mappings between index1 and index2-1 are supposed to be ordered
1228 * return value is the index of the last mapping for which end>cluster_num
1229 */
1230static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1231{
de167e41 1232 while(1) {
88bf7950 1233 int index3;
c227f099 1234 mapping_t* mapping;
de167e41
FB
1235 index3=(index1+index2)/2;
1236 mapping=array_get(&(s->mapping),index3);
a046433a
FB
1237 assert(mapping->begin < mapping->end);
1238 if(mapping->begin>=cluster_num) {
de167e41
FB
1239 assert(index2!=index3 || index2==0);
1240 if(index2==index3)
a046433a 1241 return index1;
de167e41
FB
1242 index2=index3;
1243 } else {
1244 if(index1==index3)
a046433a 1245 return mapping->end<=cluster_num ? index2 : index1;
de167e41
FB
1246 index1=index3;
1247 }
1248 assert(index1<=index2);
a046433a
FB
1249 DLOG(mapping=array_get(&(s->mapping),index1);
1250 assert(mapping->begin<=cluster_num);
5fafdf24 1251 assert(index2 >= s->mapping.next ||
a046433a
FB
1252 ((mapping = array_get(&(s->mapping),index2)) &&
1253 mapping->end>cluster_num)));
de167e41
FB
1254 }
1255}
1256
c227f099 1257static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
de167e41
FB
1258{
1259 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
c227f099 1260 mapping_t* mapping;
de167e41 1261 if(index>=s->mapping.next)
511d2b14 1262 return NULL;
de167e41
FB
1263 mapping=array_get(&(s->mapping),index);
1264 if(mapping->begin>cluster_num)
511d2b14 1265 return NULL;
a046433a 1266 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
de167e41
FB
1267 return mapping;
1268}
1269
c227f099 1270static int open_file(BDRVVVFATState* s,mapping_t* mapping)
de167e41
FB
1271{
1272 if(!mapping)
1273 return -1;
de167e41 1274 if(!s->current_mapping ||
a046433a 1275 strcmp(s->current_mapping->path,mapping->path)) {
de167e41 1276 /* open file */
6165f4d8 1277 int fd = qemu_open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
de167e41
FB
1278 if(fd<0)
1279 return -1;
1280 vvfat_close_current_file(s);
1281 s->current_fd = fd;
de167e41
FB
1282 s->current_mapping = mapping;
1283 }
1284 return 0;
1285}
1286
1287static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1288{
1289 if(s->current_cluster != cluster_num) {
1290 int result=0;
1291 off_t offset;
a046433a 1292 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
de167e41
FB
1293 if(!s->current_mapping
1294 || s->current_mapping->begin>cluster_num
1295 || s->current_mapping->end<=cluster_num) {
1296 /* binary search of mappings for file */
c227f099 1297 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
a046433a
FB
1298
1299 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1300
1301 if (mapping && mapping->mode & MODE_DIRECTORY) {
1302 vvfat_close_current_file(s);
1303 s->current_mapping = mapping;
1304read_cluster_directory:
1305 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
ffe8ab83 1306 s->cluster = (unsigned char*)s->directory.pointer+offset
a046433a
FB
1307 + 0x20*s->current_mapping->info.dir.first_dir_index;
1308 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1309 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1310 s->current_cluster = cluster_num;
1311 return 0;
1312 }
1313
1314 if(open_file(s,mapping))
de167e41 1315 return -2;
a046433a
FB
1316 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1317 goto read_cluster_directory;
de167e41 1318
a046433a
FB
1319 assert(s->current_fd);
1320
1321 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
de167e41
FB
1322 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1323 return -3;
a046433a 1324 s->cluster=s->cluster_buffer;
de167e41
FB
1325 result=read(s->current_fd,s->cluster,s->cluster_size);
1326 if(result<0) {
1327 s->current_cluster = -1;
1328 return -1;
1329 }
1330 s->current_cluster = cluster_num;
1331 }
1332 return 0;
1333}
1334
a046433a 1335#ifdef DEBUG
c227f099 1336static void print_direntry(const direntry_t* direntry)
de167e41 1337{
a046433a
FB
1338 int j = 0;
1339 char buffer[1024];
1340
3e89cb04 1341 fprintf(stderr, "direntry %p: ", direntry);
de167e41
FB
1342 if(!direntry)
1343 return;
a046433a 1344 if(is_long_name(direntry)) {
de167e41
FB
1345 unsigned char* c=(unsigned char*)direntry;
1346 int i;
1347 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
3891b370 1348#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
a046433a 1349 ADD_CHAR(c[i]);
de167e41 1350 for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
a046433a 1351 ADD_CHAR(c[i]);
de167e41 1352 for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
a046433a
FB
1353 ADD_CHAR(c[i]);
1354 buffer[j] = 0;
1355 fprintf(stderr, "%s\n", buffer);
de167e41
FB
1356 } else {
1357 int i;
1358 for(i=0;i<11;i++)
a046433a
FB
1359 ADD_CHAR(direntry->name[i]);
1360 buffer[j] = 0;
1361 fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1362 buffer,
de167e41 1363 direntry->attributes,
a046433a 1364 begin_of_direntry(direntry),le32_to_cpu(direntry->size));
de167e41
FB
1365 }
1366}
1367
c227f099 1368static void print_mapping(const mapping_t* mapping)
de167e41 1369{
3e89cb04
KW
1370 fprintf(stderr, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1371 "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1372 mapping, mapping->begin, mapping->end, mapping->dir_index,
1373 mapping->first_mapping_index, mapping->path, mapping->mode);
1374
a046433a
FB
1375 if (mapping->mode & MODE_DIRECTORY)
1376 fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1377 else
1378 fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
de167e41 1379}
a046433a 1380#endif
de167e41 1381
5fafdf24 1382static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
a046433a 1383 uint8_t *buf, int nb_sectors)
de167e41 1384{
a046433a 1385 BDRVVVFATState *s = bs->opaque;
de167e41 1386 int i;
de167e41 1387
a046433a 1388 for(i=0;i<nb_sectors;i++,sector_num++) {
e654bfe4 1389 if (sector_num >= bs->total_sectors)
a046433a
FB
1390 return -1;
1391 if (s->qcow) {
1392 int n;
eecc7747
KW
1393 if (bdrv_is_allocated(s->qcow->bs, sector_num, nb_sectors-i, &n)) {
1394 DLOG(fprintf(stderr, "sectors %d+%d allocated\n",
1395 (int)sector_num, n));
fbcbbf4e 1396 if (bdrv_read(s->qcow, sector_num, buf + i * 0x200, n)) {
7704df98
KW
1397 return -1;
1398 }
1399 i += n - 1;
1400 sector_num += n - 1;
1401 continue;
1402 }
a046433a 1403DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
de167e41 1404 }
a046433a
FB
1405 if(sector_num<s->faked_sectors) {
1406 if(sector_num<s->first_sectors_number)
1407 memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
1408 else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
1409 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
1410 else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
1411 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
1412 } else {
1413 uint32_t sector=sector_num-s->faked_sectors,
1414 sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1415 cluster_num=sector/s->sectors_per_cluster;
e654bfe4 1416 if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) {
a046433a
FB
1417 /* LATER TODO: strict: return -1; */
1418 memset(buf+i*0x200,0,0x200);
1419 continue;
de167e41 1420 }
a046433a 1421 memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
de167e41
FB
1422 }
1423 }
de167e41
FB
1424 return 0;
1425}
1426
4575eb49
KW
1427static int coroutine_fn
1428vvfat_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
1429 QEMUIOVector *qiov, int flags)
2914caa0
PB
1430{
1431 int ret;
1432 BDRVVVFATState *s = bs->opaque;
4575eb49
KW
1433 uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
1434 int nb_sectors = bytes >> BDRV_SECTOR_BITS;
1435 void *buf;
1436
1437 assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
1438 assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
1439
1440 buf = g_try_malloc(bytes);
1441 if (bytes && buf == NULL) {
1442 return -ENOMEM;
1443 }
1444
2914caa0
PB
1445 qemu_co_mutex_lock(&s->lock);
1446 ret = vvfat_read(bs, sector_num, buf, nb_sectors);
1447 qemu_co_mutex_unlock(&s->lock);
4575eb49
KW
1448
1449 qemu_iovec_from_buf(qiov, 0, buf, bytes);
1450 g_free(buf);
1451
2914caa0
PB
1452 return ret;
1453}
1454
a046433a 1455/* LATER TODO: statify all functions */
de167e41 1456
a046433a
FB
1457/*
1458 * Idea of the write support (use snapshot):
de167e41 1459 *
a046433a
FB
1460 * 1. check if all data is consistent, recording renames, modifications,
1461 * new files and directories (in s->commits).
de167e41 1462 *
a046433a 1463 * 2. if the data is not consistent, stop committing
de167e41 1464 *
a046433a
FB
1465 * 3. handle renames, and create new files and directories (do not yet
1466 * write their contents)
de167e41 1467 *
a046433a
FB
1468 * 4. walk the directories, fixing the mapping and direntries, and marking
1469 * the handled mappings as not deleted
de167e41 1470 *
a046433a 1471 * 5. commit the contents of the files
de167e41 1472 *
a046433a 1473 * 6. handle deleted files and directories
de167e41
FB
1474 *
1475 */
1476
c227f099 1477typedef struct commit_t {
a046433a
FB
1478 char* path;
1479 union {
1480 struct { uint32_t cluster; } rename;
1481 struct { int dir_index; uint32_t modified_offset; } writeout;
1482 struct { uint32_t first_cluster; } new_file;
1483 struct { uint32_t cluster; } mkdir;
1484 } param;
1485 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1486 enum {
1487 ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1488 } action;
c227f099 1489} commit_t;
de167e41 1490
a046433a 1491static void clear_commits(BDRVVVFATState* s)
de167e41
FB
1492{
1493 int i;
a046433a
FB
1494DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1495 for (i = 0; i < s->commits.next; i++) {
c227f099 1496 commit_t* commit = array_get(&(s->commits), i);
a046433a
FB
1497 assert(commit->path || commit->action == ACTION_WRITEOUT);
1498 if (commit->action != ACTION_WRITEOUT) {
1499 assert(commit->path);
ce137829 1500 g_free(commit->path);
a046433a
FB
1501 } else
1502 assert(commit->path == NULL);
de167e41 1503 }
a046433a 1504 s->commits.next = 0;
de167e41
FB
1505}
1506
a046433a
FB
1507static void schedule_rename(BDRVVVFATState* s,
1508 uint32_t cluster, char* new_path)
de167e41 1509{
c227f099 1510 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1511 commit->path = new_path;
1512 commit->param.rename.cluster = cluster;
1513 commit->action = ACTION_RENAME;
de167e41
FB
1514}
1515
a046433a
FB
1516static void schedule_writeout(BDRVVVFATState* s,
1517 int dir_index, uint32_t modified_offset)
de167e41 1518{
c227f099 1519 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1520 commit->path = NULL;
1521 commit->param.writeout.dir_index = dir_index;
1522 commit->param.writeout.modified_offset = modified_offset;
1523 commit->action = ACTION_WRITEOUT;
de167e41
FB
1524}
1525
a046433a
FB
1526static void schedule_new_file(BDRVVVFATState* s,
1527 char* path, uint32_t first_cluster)
de167e41 1528{
c227f099 1529 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1530 commit->path = path;
1531 commit->param.new_file.first_cluster = first_cluster;
1532 commit->action = ACTION_NEW_FILE;
1533}
1534
1535static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1536{
c227f099 1537 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1538 commit->path = path;
1539 commit->param.mkdir.cluster = cluster;
1540 commit->action = ACTION_MKDIR;
1541}
1542
1543typedef struct {
64eaabda
TS
1544 /*
1545 * Since the sequence number is at most 0x3f, and the filename
1546 * length is at most 13 times the sequence number, the maximal
1547 * filename length is 0x3f * 13 bytes.
1548 */
1549 unsigned char name[0x3f * 13 + 1];
a046433a
FB
1550 int checksum, len;
1551 int sequence_number;
1552} long_file_name;
1553
1554static void lfn_init(long_file_name* lfn)
1555{
1556 lfn->sequence_number = lfn->len = 0;
1557 lfn->checksum = 0x100;
1558}
1559
1560/* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1561static int parse_long_name(long_file_name* lfn,
c227f099 1562 const direntry_t* direntry)
a046433a
FB
1563{
1564 int i, j, offset;
1565 const unsigned char* pointer = (const unsigned char*)direntry;
1566
1567 if (!is_long_name(direntry))
1568 return 1;
1569
1570 if (pointer[0] & 0x40) {
1571 lfn->sequence_number = pointer[0] & 0x3f;
1572 lfn->checksum = pointer[13];
1573 lfn->name[0] = 0;
59fdb018 1574 lfn->name[lfn->sequence_number * 13] = 0;
a046433a
FB
1575 } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
1576 return -1;
1577 else if (pointer[13] != lfn->checksum)
1578 return -2;
1579 else if (pointer[12] || pointer[26] || pointer[27])
1580 return -3;
1581
1582 offset = 13 * (lfn->sequence_number - 1);
1583 for (i = 0, j = 1; i < 13; i++, j+=2) {
1584 if (j == 11)
1585 j = 14;
1586 else if (j == 26)
1587 j = 28;
1588
1589 if (pointer[j+1] == 0)
1590 lfn->name[offset + i] = pointer[j];
1591 else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1592 return -4;
1593 else
1594 lfn->name[offset + i] = 0;
de167e41 1595 }
a046433a
FB
1596
1597 if (pointer[0] & 0x40)
ffe8ab83 1598 lfn->len = offset + strlen((char*)lfn->name + offset);
a046433a 1599
de167e41
FB
1600 return 0;
1601}
1602
a046433a
FB
1603/* returns 0 if successful, >0 if no short_name, and <0 on error */
1604static int parse_short_name(BDRVVVFATState* s,
c227f099 1605 long_file_name* lfn, direntry_t* direntry)
de167e41 1606{
a046433a 1607 int i, j;
de167e41 1608
a046433a
FB
1609 if (!is_short_name(direntry))
1610 return 1;
1611
1612 for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1613 for (i = 0; i <= j; i++) {
1614 if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
1615 return -1;
1616 else if (s->downcase_short_names)
47398b9c 1617 lfn->name[i] = qemu_tolower(direntry->name[i]);
a046433a
FB
1618 else
1619 lfn->name[i] = direntry->name[i];
de167e41
FB
1620 }
1621
f671d173
SW
1622 for (j = 2; j >= 0 && direntry->name[8 + j] == ' '; j--) {
1623 }
a046433a
FB
1624 if (j >= 0) {
1625 lfn->name[i++] = '.';
1626 lfn->name[i + j + 1] = '\0';
1627 for (;j >= 0; j--) {
f671d173
SW
1628 uint8_t c = direntry->name[8 + j];
1629 if (c <= ' ' || c > 0x7f) {
1630 return -2;
1631 } else if (s->downcase_short_names) {
1632 lfn->name[i + j] = qemu_tolower(c);
1633 } else {
1634 lfn->name[i + j] = c;
1635 }
a046433a
FB
1636 }
1637 } else
1638 lfn->name[i + j + 1] = '\0';
1639
ffe8ab83 1640 lfn->len = strlen((char*)lfn->name);
a046433a
FB
1641
1642 return 0;
de167e41
FB
1643}
1644
a046433a
FB
1645static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1646 unsigned int cluster)
de167e41 1647{
a046433a
FB
1648 if (cluster < s->last_cluster_of_root_directory) {
1649 if (cluster + 1 == s->last_cluster_of_root_directory)
1650 return s->max_fat_value;
1651 else
1652 return cluster + 1;
1653 }
1654
1655 if (s->fat_type==32) {
1656 uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1657 return le32_to_cpu(*entry);
1658 } else if (s->fat_type==16) {
1659 uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1660 return le16_to_cpu(*entry);
1661 } else {
1662 const uint8_t* x=s->fat2+cluster*3/2;
1663 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1664 }
1665}
1666
1667static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1668{
1669 int was_modified = 0;
1670 int i, dummy;
1671
eecc7747
KW
1672 if (s->qcow == NULL) {
1673 return 0;
1674 }
a046433a 1675
eecc7747
KW
1676 for (i = 0; !was_modified && i < s->sectors_per_cluster; i++) {
1677 was_modified = bdrv_is_allocated(s->qcow->bs,
1678 cluster2sector(s, cluster_num) + i,
1679 1, &dummy);
1680 }
a046433a
FB
1681
1682 return was_modified;
de167e41
FB
1683}
1684
a046433a 1685static const char* get_basename(const char* path)
de167e41 1686{
a046433a
FB
1687 char* basename = strrchr(path, '/');
1688 if (basename == NULL)
1689 return path;
1690 else
1691 return basename + 1; /* strip '/' */
de167e41
FB
1692}
1693
a046433a
FB
1694/*
1695 * The array s->used_clusters holds the states of the clusters. If it is
1696 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1697 * was modified, bit 3 is set.
1698 * If any cluster is allocated, but not part of a file or directory, this
1699 * driver refuses to commit.
1700 */
1701typedef enum {
1702 USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
c227f099 1703} used_t;
de167e41 1704
a046433a
FB
1705/*
1706 * get_cluster_count_for_direntry() not only determines how many clusters
1707 * are occupied by direntry, but also if it was renamed or modified.
1708 *
1709 * A file is thought to be renamed *only* if there already was a file with
1710 * exactly the same first cluster, but a different name.
1711 *
1712 * Further, the files/directories handled by this function are
1713 * assumed to be *not* deleted (and *only* those).
1714 */
1715static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
c227f099 1716 direntry_t* direntry, const char* path)
de167e41 1717{
a046433a
FB
1718 /*
1719 * This is a little bit tricky:
1720 * IF the guest OS just inserts a cluster into the file chain,
1721 * and leaves the rest alone, (i.e. the original file had clusters
1722 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1723 *
1724 * - do_commit will write the cluster into the file at the given
1725 * offset, but
1726 *
1727 * - the cluster which is overwritten should be moved to a later
1728 * position in the file.
1729 *
1730 * I am not aware that any OS does something as braindead, but this
1731 * situation could happen anyway when not committing for a long time.
1732 * Just to be sure that this does not bite us, detect it, and copy the
1733 * contents of the clusters to-be-overwritten into the qcow.
1734 */
1735 int copy_it = 0;
1736 int was_modified = 0;
1737 int32_t ret = 0;
1738
1739 uint32_t cluster_num = begin_of_direntry(direntry);
1740 uint32_t offset = 0;
1741 int first_mapping_index = -1;
c227f099 1742 mapping_t* mapping = NULL;
a046433a 1743 const char* basename2 = NULL;
de167e41 1744
a046433a 1745 vvfat_close_current_file(s);
de167e41 1746
a046433a
FB
1747 /* the root directory */
1748 if (cluster_num == 0)
de167e41 1749 return 0;
de167e41 1750
a046433a
FB
1751 /* write support */
1752 if (s->qcow) {
1753 basename2 = get_basename(path);
de167e41 1754
a046433a
FB
1755 mapping = find_mapping_for_cluster(s, cluster_num);
1756
1757 if (mapping) {
da2414e9
FB
1758 const char* basename;
1759
a046433a
FB
1760 assert(mapping->mode & MODE_DELETED);
1761 mapping->mode &= ~MODE_DELETED;
1762
da2414e9 1763 basename = get_basename(mapping->path);
a046433a
FB
1764
1765 assert(mapping->mode & MODE_NORMAL);
1766
1767 /* rename */
1768 if (strcmp(basename, basename2))
7267c094 1769 schedule_rename(s, cluster_num, g_strdup(path));
a046433a
FB
1770 } else if (is_file(direntry))
1771 /* new file */
7267c094 1772 schedule_new_file(s, g_strdup(path), cluster_num);
a046433a 1773 else {
43dc2a64 1774 abort();
a046433a
FB
1775 return 0;
1776 }
de167e41
FB
1777 }
1778
a046433a
FB
1779 while(1) {
1780 if (s->qcow) {
1781 if (!copy_it && cluster_was_modified(s, cluster_num)) {
1782 if (mapping == NULL ||
1783 mapping->begin > cluster_num ||
1784 mapping->end <= cluster_num)
1785 mapping = find_mapping_for_cluster(s, cluster_num);
de167e41 1786
a046433a
FB
1787
1788 if (mapping &&
1789 (mapping->mode & MODE_DIRECTORY) == 0) {
1790
1791 /* was modified in qcow */
1792 if (offset != mapping->info.file.offset + s->cluster_size
1793 * (cluster_num - mapping->begin)) {
1794 /* offset of this cluster in file chain has changed */
43dc2a64 1795 abort();
a046433a
FB
1796 copy_it = 1;
1797 } else if (offset == 0) {
1798 const char* basename = get_basename(mapping->path);
1799
1800 if (strcmp(basename, basename2))
1801 copy_it = 1;
1802 first_mapping_index = array_index(&(s->mapping), mapping);
1803 }
1804
1805 if (mapping->first_mapping_index != first_mapping_index
1806 && mapping->info.file.offset > 0) {
43dc2a64 1807 abort();
a046433a
FB
1808 copy_it = 1;
1809 }
1810
1811 /* need to write out? */
1812 if (!was_modified && is_file(direntry)) {
1813 was_modified = 1;
1814 schedule_writeout(s, mapping->dir_index, offset);
1815 }
1816 }
1817 }
1818
1819 if (copy_it) {
1820 int i, dummy;
1821 /*
1822 * This is horribly inefficient, but that is okay, since
1823 * it is rarely executed, if at all.
1824 */
1825 int64_t offset = cluster2sector(s, cluster_num);
1826
1827 vvfat_close_current_file(s);
7704df98 1828 for (i = 0; i < s->sectors_per_cluster; i++) {
eecc7747
KW
1829 int res;
1830
1831 res = bdrv_is_allocated(s->qcow->bs, offset + i, 1, &dummy);
1832 if (!res) {
1833 res = vvfat_read(s->bs, offset, s->cluster_buffer, 1);
1834 if (res) {
7704df98
KW
1835 return -1;
1836 }
18d51c4b 1837 res = bdrv_write(s->qcow, offset, s->cluster_buffer, 1);
eecc7747 1838 if (res) {
7704df98
KW
1839 return -2;
1840 }
1841 }
1842 }
a046433a
FB
1843 }
1844 }
1845
1846 ret++;
1847 if (s->used_clusters[cluster_num] & USED_ANY)
1848 return 0;
1849 s->used_clusters[cluster_num] = USED_FILE;
1850
1851 cluster_num = modified_fat_get(s, cluster_num);
1852
1853 if (fat_eof(s, cluster_num))
1854 return ret;
1855 else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
1856 return -1;
1857
1858 offset += s->cluster_size;
1859 }
de167e41
FB
1860}
1861
a046433a 1862/*
5fafdf24 1863 * This function looks at the modified data (qcow).
a046433a
FB
1864 * It returns 0 upon inconsistency or error, and the number of clusters
1865 * used by the directory, its subdirectories and their files.
1866 */
1867static int check_directory_consistency(BDRVVVFATState *s,
1868 int cluster_num, const char* path)
de167e41 1869{
a046433a 1870 int ret = 0;
7267c094 1871 unsigned char* cluster = g_malloc(s->cluster_size);
c227f099
AL
1872 direntry_t* direntries = (direntry_t*)cluster;
1873 mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
a046433a
FB
1874
1875 long_file_name lfn;
1876 int path_len = strlen(path);
0d460d6f 1877 char path2[PATH_MAX + 1];
a046433a
FB
1878
1879 assert(path_len < PATH_MAX); /* len was tested before! */
363a37d5 1880 pstrcpy(path2, sizeof(path2), path);
a046433a
FB
1881 path2[path_len] = '/';
1882 path2[path_len + 1] = '\0';
1883
1884 if (mapping) {
1885 const char* basename = get_basename(mapping->path);
1886 const char* basename2 = get_basename(path);
1887
1888 assert(mapping->mode & MODE_DIRECTORY);
1889
1890 assert(mapping->mode & MODE_DELETED);
1891 mapping->mode &= ~MODE_DELETED;
1892
1893 if (strcmp(basename, basename2))
7267c094 1894 schedule_rename(s, cluster_num, g_strdup(path));
a046433a
FB
1895 } else
1896 /* new directory */
7267c094 1897 schedule_mkdir(s, cluster_num, g_strdup(path));
3b46e624 1898
a046433a
FB
1899 lfn_init(&lfn);
1900 do {
de167e41 1901 int i;
a046433a
FB
1902 int subret = 0;
1903
1904 ret++;
1905
1906 if (s->used_clusters[cluster_num] & USED_ANY) {
1907 fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
6262bbd3 1908 goto fail;
a046433a
FB
1909 }
1910 s->used_clusters[cluster_num] = USED_DIRECTORY;
1911
1912DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
1913 subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
1914 s->sectors_per_cluster);
1915 if (subret) {
1916 fprintf(stderr, "Error fetching direntries\n");
1917 fail:
ce137829 1918 g_free(cluster);
a046433a
FB
1919 return 0;
1920 }
1921
1922 for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
3f4cb3d3 1923 int cluster_count = 0;
a046433a 1924
b2bedb21 1925DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i));
a046433a
FB
1926 if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
1927 is_free(direntries + i))
1928 continue;
1929
1930 subret = parse_long_name(&lfn, direntries + i);
1931 if (subret < 0) {
1932 fprintf(stderr, "Error in long name\n");
1933 goto fail;
de167e41 1934 }
a046433a
FB
1935 if (subret == 0 || is_free(direntries + i))
1936 continue;
1937
1938 if (fat_chksum(direntries+i) != lfn.checksum) {
1939 subret = parse_short_name(s, &lfn, direntries + i);
1940 if (subret < 0) {
1941 fprintf(stderr, "Error in short name (%d)\n", subret);
1942 goto fail;
1943 }
ffe8ab83
TS
1944 if (subret > 0 || !strcmp((char*)lfn.name, ".")
1945 || !strcmp((char*)lfn.name, ".."))
a046433a
FB
1946 continue;
1947 }
1948 lfn.checksum = 0x100; /* cannot use long name twice */
1949
1950 if (path_len + 1 + lfn.len >= PATH_MAX) {
1951 fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
1952 goto fail;
1953 }
363a37d5
BS
1954 pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
1955 (char*)lfn.name);
a046433a
FB
1956
1957 if (is_directory(direntries + i)) {
1958 if (begin_of_direntry(direntries + i) == 0) {
1959 DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
1960 goto fail;
1961 }
1962 cluster_count = check_directory_consistency(s,
1963 begin_of_direntry(direntries + i), path2);
1964 if (cluster_count == 0) {
1965 DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
1966 goto fail;
1967 }
1968 } else if (is_file(direntries + i)) {
1969 /* check file size with FAT */
1970 cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
1971 if (cluster_count !=
13385ae1 1972 DIV_ROUND_UP(le32_to_cpu(direntries[i].size), s->cluster_size)) {
a046433a
FB
1973 DLOG(fprintf(stderr, "Cluster count mismatch\n"));
1974 goto fail;
1975 }
1976 } else
43dc2a64 1977 abort(); /* cluster_count = 0; */
a046433a
FB
1978
1979 ret += cluster_count;
de167e41 1980 }
de167e41 1981
a046433a
FB
1982 cluster_num = modified_fat_get(s, cluster_num);
1983 } while(!fat_eof(s, cluster_num));
de167e41 1984
ce137829 1985 g_free(cluster);
a046433a
FB
1986 return ret;
1987}
1988
1989/* returns 1 on success */
1990static int is_consistent(BDRVVVFATState* s)
1991{
1992 int i, check;
1993 int used_clusters_count = 0;
1994
1995DLOG(checkpoint());
1996 /*
1997 * - get modified FAT
1998 * - compare the two FATs (TODO)
1999 * - get buffer for marking used clusters
2000 * - recurse direntries from root (using bs->bdrv_read to make
2001 * sure to get the new data)
2002 * - check that the FAT agrees with the size
2003 * - count the number of clusters occupied by this directory and
2004 * its files
2005 * - check that the cumulative used cluster count agrees with the
2006 * FAT
2007 * - if all is fine, return number of used clusters
2008 */
2009 if (s->fat2 == NULL) {
2010 int size = 0x200 * s->sectors_per_fat;
7267c094 2011 s->fat2 = g_malloc(size);
a046433a
FB
2012 memcpy(s->fat2, s->fat.pointer, size);
2013 }
2014 check = vvfat_read(s->bs,
2015 s->first_sectors_number, s->fat2, s->sectors_per_fat);
2016 if (check) {
2017 fprintf(stderr, "Could not copy fat\n");
2018 return 0;
2019 }
2020 assert (s->used_clusters);
2021 for (i = 0; i < sector2cluster(s, s->sector_count); i++)
2022 s->used_clusters[i] &= ~USED_ANY;
2023
2024 clear_commits(s);
2025
2026 /* mark every mapped file/directory as deleted.
2027 * (check_directory_consistency() will unmark those still present). */
2028 if (s->qcow)
2029 for (i = 0; i < s->mapping.next; i++) {
c227f099 2030 mapping_t* mapping = array_get(&(s->mapping), i);
a046433a
FB
2031 if (mapping->first_mapping_index < 0)
2032 mapping->mode |= MODE_DELETED;
de167e41 2033 }
a046433a
FB
2034
2035 used_clusters_count = check_directory_consistency(s, 0, s->path);
2036 if (used_clusters_count <= 0) {
2037 DLOG(fprintf(stderr, "problem in directory\n"));
2038 return 0;
de167e41
FB
2039 }
2040
a046433a
FB
2041 check = s->last_cluster_of_root_directory;
2042 for (i = check; i < sector2cluster(s, s->sector_count); i++) {
2043 if (modified_fat_get(s, i)) {
2044 if(!s->used_clusters[i]) {
2045 DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
2046 return 0;
2047 }
2048 check++;
2049 }
2050
2051 if (s->used_clusters[i] == USED_ALLOCATED) {
2052 /* allocated, but not used... */
2053 DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
2054 return 0;
2055 }
2056 }
2057
2058 if (check != used_clusters_count)
2059 return 0;
2060
2061 return used_clusters_count;
2062}
2063
2064static inline void adjust_mapping_indices(BDRVVVFATState* s,
2065 int offset, int adjust)
2066{
2067 int i;
2068
2069 for (i = 0; i < s->mapping.next; i++) {
c227f099 2070 mapping_t* mapping = array_get(&(s->mapping), i);
a046433a
FB
2071
2072#define ADJUST_MAPPING_INDEX(name) \
2073 if (mapping->name >= offset) \
2074 mapping->name += adjust
2075
2076 ADJUST_MAPPING_INDEX(first_mapping_index);
2077 if (mapping->mode & MODE_DIRECTORY)
2078 ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
de167e41 2079 }
a046433a
FB
2080}
2081
2082/* insert or update mapping */
c227f099 2083static mapping_t* insert_mapping(BDRVVVFATState* s,
a046433a
FB
2084 uint32_t begin, uint32_t end)
2085{
2086 /*
2087 * - find mapping where mapping->begin >= begin,
2088 * - if mapping->begin > begin: insert
2089 * - adjust all references to mappings!
2090 * - else: adjust
2091 * - replace name
2092 */
2093 int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
c227f099
AL
2094 mapping_t* mapping = NULL;
2095 mapping_t* first_mapping = array_get(&(s->mapping), 0);
a046433a
FB
2096
2097 if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
2098 && mapping->begin < begin) {
2099 mapping->end = begin;
2100 index++;
2101 mapping = array_get(&(s->mapping), index);
2102 }
2103 if (index >= s->mapping.next || mapping->begin > begin) {
2104 mapping = array_insert(&(s->mapping), index, 1);
2105 mapping->path = NULL;
2106 adjust_mapping_indices(s, index, +1);
2107 }
2108
2109 mapping->begin = begin;
2110 mapping->end = end;
de167e41 2111
c227f099 2112DLOG(mapping_t* next_mapping;
a046433a
FB
2113assert(index + 1 >= s->mapping.next ||
2114((next_mapping = array_get(&(s->mapping), index + 1)) &&
2115 next_mapping->begin >= end)));
2116
c227f099 2117 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
a046433a
FB
2118 s->current_mapping = array_get(&(s->mapping),
2119 s->current_mapping - first_mapping);
2120
2121 return mapping;
2122}
2123
2124static int remove_mapping(BDRVVVFATState* s, int mapping_index)
2125{
c227f099
AL
2126 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
2127 mapping_t* first_mapping = array_get(&(s->mapping), 0);
a046433a
FB
2128
2129 /* free mapping */
ce137829
SW
2130 if (mapping->first_mapping_index < 0) {
2131 g_free(mapping->path);
2132 }
a046433a
FB
2133
2134 /* remove from s->mapping */
2135 array_remove(&(s->mapping), mapping_index);
2136
2137 /* adjust all references to mappings */
2138 adjust_mapping_indices(s, mapping_index, -1);
2139
c227f099 2140 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
a046433a
FB
2141 s->current_mapping = array_get(&(s->mapping),
2142 s->current_mapping - first_mapping);
de167e41 2143
de167e41
FB
2144 return 0;
2145}
2146
a046433a
FB
2147static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
2148{
2149 int i;
2150 for (i = 0; i < s->mapping.next; i++) {
c227f099 2151 mapping_t* mapping = array_get(&(s->mapping), i);
a046433a
FB
2152 if (mapping->dir_index >= offset)
2153 mapping->dir_index += adjust;
2154 if ((mapping->mode & MODE_DIRECTORY) &&
2155 mapping->info.dir.first_dir_index >= offset)
2156 mapping->info.dir.first_dir_index += adjust;
2157 }
2158}
de167e41 2159
c227f099 2160static direntry_t* insert_direntries(BDRVVVFATState* s,
a046433a 2161 int dir_index, int count)
de167e41 2162{
a046433a
FB
2163 /*
2164 * make room in s->directory,
2165 * adjust_dirindices
2166 */
c227f099 2167 direntry_t* result = array_insert(&(s->directory), dir_index, count);
a046433a
FB
2168 if (result == NULL)
2169 return NULL;
2170 adjust_dirindices(s, dir_index, count);
de167e41
FB
2171 return result;
2172}
2173
a046433a
FB
2174static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
2175{
2176 int ret = array_remove_slice(&(s->directory), dir_index, count);
2177 if (ret)
2178 return ret;
2179 adjust_dirindices(s, dir_index, -count);
2180 return 0;
2181}
de167e41 2182
a046433a
FB
2183/*
2184 * Adapt the mappings of the cluster chain starting at first cluster
2185 * (i.e. if a file starts at first_cluster, the chain is followed according
2186 * to the modified fat, and the corresponding entries in s->mapping are
2187 * adjusted)
2188 */
2189static int commit_mappings(BDRVVVFATState* s,
2190 uint32_t first_cluster, int dir_index)
de167e41 2191{
c227f099
AL
2192 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2193 direntry_t* direntry = array_get(&(s->directory), dir_index);
a046433a
FB
2194 uint32_t cluster = first_cluster;
2195
2196 vvfat_close_current_file(s);
2197
2198 assert(mapping);
2199 assert(mapping->begin == first_cluster);
2200 mapping->first_mapping_index = -1;
2201 mapping->dir_index = dir_index;
2202 mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2203 MODE_DIRECTORY : MODE_NORMAL;
2204
2205 while (!fat_eof(s, cluster)) {
2206 uint32_t c, c1;
2207
2208 for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2209 c = c1, c1 = modified_fat_get(s, c1));
2210
2211 c++;
2212 if (c > mapping->end) {
2213 int index = array_index(&(s->mapping), mapping);
2214 int i, max_i = s->mapping.next - index;
2215 for (i = 1; i < max_i && mapping[i].begin < c; i++);
2216 while (--i > 0)
2217 remove_mapping(s, index + 1);
2218 }
2219 assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2220 || mapping[1].begin >= c);
2221 mapping->end = c;
2222
2223 if (!fat_eof(s, c1)) {
2224 int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
c227f099 2225 mapping_t* next_mapping = i >= s->mapping.next ? NULL :
a046433a
FB
2226 array_get(&(s->mapping), i);
2227
2228 if (next_mapping == NULL || next_mapping->begin > c1) {
2229 int i1 = array_index(&(s->mapping), mapping);
2230
2231 next_mapping = insert_mapping(s, c1, c1+1);
2232
2233 if (c1 < c)
2234 i1++;
2235 mapping = array_get(&(s->mapping), i1);
2236 }
2237
2238 next_mapping->dir_index = mapping->dir_index;
5fafdf24 2239 next_mapping->first_mapping_index =
a046433a
FB
2240 mapping->first_mapping_index < 0 ?
2241 array_index(&(s->mapping), mapping) :
2242 mapping->first_mapping_index;
2243 next_mapping->path = mapping->path;
2244 next_mapping->mode = mapping->mode;
2245 next_mapping->read_only = mapping->read_only;
2246 if (mapping->mode & MODE_DIRECTORY) {
2247 next_mapping->info.dir.parent_mapping_index =
2248 mapping->info.dir.parent_mapping_index;
2249 next_mapping->info.dir.first_dir_index =
2250 mapping->info.dir.first_dir_index +
2251 0x10 * s->sectors_per_cluster *
2252 (mapping->end - mapping->begin);
2253 } else
2254 next_mapping->info.file.offset = mapping->info.file.offset +
2255 mapping->end - mapping->begin;
2256
2257 mapping = next_mapping;
2258 }
3b46e624 2259
a046433a
FB
2260 cluster = c1;
2261 }
de167e41 2262
de167e41
FB
2263 return 0;
2264}
2265
a046433a
FB
2266static int commit_direntries(BDRVVVFATState* s,
2267 int dir_index, int parent_mapping_index)
de167e41 2268{
c227f099 2269 direntry_t* direntry = array_get(&(s->directory), dir_index);
a046433a 2270 uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
c227f099 2271 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
a046433a
FB
2272
2273 int factor = 0x10 * s->sectors_per_cluster;
2274 int old_cluster_count, new_cluster_count;
2275 int current_dir_index = mapping->info.dir.first_dir_index;
2276 int first_dir_index = current_dir_index;
2277 int ret, i;
2278 uint32_t c;
2279
2280DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
2281
2282 assert(direntry);
2283 assert(mapping);
2284 assert(mapping->begin == first_cluster);
2285 assert(mapping->info.dir.first_dir_index < s->directory.next);
2286 assert(mapping->mode & MODE_DIRECTORY);
2287 assert(dir_index == 0 || is_directory(direntry));
2288
2289 mapping->info.dir.parent_mapping_index = parent_mapping_index;
2290
2291 if (first_cluster == 0) {
2292 old_cluster_count = new_cluster_count =
2293 s->last_cluster_of_root_directory;
2294 } else {
2295 for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2296 c = fat_get(s, c))
2297 old_cluster_count++;
de167e41 2298
a046433a
FB
2299 for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2300 c = modified_fat_get(s, c))
2301 new_cluster_count++;
2302 }
de167e41 2303
a046433a
FB
2304 if (new_cluster_count > old_cluster_count) {
2305 if (insert_direntries(s,
2306 current_dir_index + factor * old_cluster_count,
2307 factor * (new_cluster_count - old_cluster_count)) == NULL)
2308 return -1;
2309 } else if (new_cluster_count < old_cluster_count)
2310 remove_direntries(s,
2311 current_dir_index + factor * new_cluster_count,
2312 factor * (old_cluster_count - new_cluster_count));
2313
2314 for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
ebb72c9f 2315 direntry_t *first_direntry;
a046433a
FB
2316 void* direntry = array_get(&(s->directory), current_dir_index);
2317 int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2318 s->sectors_per_cluster);
2319 if (ret)
2320 return ret;
ebb72c9f
KW
2321
2322 /* The first directory entry on the filesystem is the volume name */
2323 first_direntry = (direntry_t*) s->directory.pointer;
2324 assert(!memcmp(first_direntry->name, s->volume_label, 11));
2325
a046433a
FB
2326 current_dir_index += factor;
2327 }
de167e41 2328
a046433a
FB
2329 ret = commit_mappings(s, first_cluster, dir_index);
2330 if (ret)
2331 return ret;
2332
2333 /* recurse */
2334 for (i = 0; i < factor * new_cluster_count; i++) {
2335 direntry = array_get(&(s->directory), first_dir_index + i);
2336 if (is_directory(direntry) && !is_dot(direntry)) {
2337 mapping = find_mapping_for_cluster(s, first_cluster);
2338 assert(mapping->mode & MODE_DIRECTORY);
2339 ret = commit_direntries(s, first_dir_index + i,
2340 array_index(&(s->mapping), mapping));
2341 if (ret)
2342 return ret;
2343 }
2344 }
de167e41 2345
a046433a
FB
2346 return 0;
2347}
de167e41 2348
a046433a
FB
2349/* commit one file (adjust contents, adjust mapping),
2350 return first_mapping_index */
2351static int commit_one_file(BDRVVVFATState* s,
2352 int dir_index, uint32_t offset)
2353{
c227f099 2354 direntry_t* direntry = array_get(&(s->directory), dir_index);
a046433a
FB
2355 uint32_t c = begin_of_direntry(direntry);
2356 uint32_t first_cluster = c;
c227f099 2357 mapping_t* mapping = find_mapping_for_cluster(s, c);
a046433a 2358 uint32_t size = filesize_of_direntry(direntry);
7267c094 2359 char* cluster = g_malloc(s->cluster_size);
a046433a
FB
2360 uint32_t i;
2361 int fd = 0;
2362
2363 assert(offset < size);
2364 assert((offset % s->cluster_size) == 0);
2365
2366 for (i = s->cluster_size; i < offset; i += s->cluster_size)
2367 c = modified_fat_get(s, c);
2368
6165f4d8 2369 fd = qemu_open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
a046433a
FB
2370 if (fd < 0) {
2371 fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2372 strerror(errno), errno);
ce137829 2373 g_free(cluster);
a046433a 2374 return fd;
de167e41 2375 }
ce137829
SW
2376 if (offset > 0) {
2377 if (lseek(fd, offset, SEEK_SET) != offset) {
2e1e79da 2378 qemu_close(fd);
ce137829
SW
2379 g_free(cluster);
2380 return -3;
2381 }
2382 }
a046433a
FB
2383
2384 while (offset < size) {
2385 uint32_t c1;
2386 int rest_size = (size - offset > s->cluster_size ?
2387 s->cluster_size : size - offset);
2388 int ret;
2389
2390 c1 = modified_fat_get(s, c);
2391
2392 assert((size - offset == 0 && fat_eof(s, c)) ||
2393 (size > offset && c >=2 && !fat_eof(s, c)));
a046433a
FB
2394
2395 ret = vvfat_read(s->bs, cluster2sector(s, c),
ffe8ab83 2396 (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
a046433a 2397
ce137829 2398 if (ret < 0) {
2e1e79da 2399 qemu_close(fd);
ce137829
SW
2400 g_free(cluster);
2401 return ret;
2402 }
a046433a 2403
ce137829 2404 if (write(fd, cluster, rest_size) < 0) {
2e1e79da 2405 qemu_close(fd);
ce137829
SW
2406 g_free(cluster);
2407 return -2;
2408 }
a046433a
FB
2409
2410 offset += rest_size;
2411 c = c1;
2412 }
2413
2dedf83e
KS
2414 if (ftruncate(fd, size)) {
2415 perror("ftruncate()");
2e1e79da 2416 qemu_close(fd);
ce137829 2417 g_free(cluster);
2dedf83e
KS
2418 return -4;
2419 }
2e1e79da 2420 qemu_close(fd);
ce137829 2421 g_free(cluster);
a046433a
FB
2422
2423 return commit_mappings(s, first_cluster, dir_index);
2424}
2425
2426#ifdef DEBUG
2427/* test, if all mappings point to valid direntries */
2428static void check1(BDRVVVFATState* s)
2429{
2430 int i;
2431 for (i = 0; i < s->mapping.next; i++) {
c227f099 2432 mapping_t* mapping = array_get(&(s->mapping), i);
a046433a
FB
2433 if (mapping->mode & MODE_DELETED) {
2434 fprintf(stderr, "deleted\n");
2435 continue;
2436 }
a046433a 2437 assert(mapping->dir_index < s->directory.next);
c227f099 2438 direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
a046433a
FB
2439 assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2440 if (mapping->mode & MODE_DIRECTORY) {
2441 assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2442 assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
de167e41
FB
2443 }
2444 }
de167e41
FB
2445}
2446
a046433a
FB
2447/* test, if all direntries have mappings */
2448static void check2(BDRVVVFATState* s)
de167e41 2449{
de167e41 2450 int i;
a046433a 2451 int first_mapping = -1;
de167e41 2452
a046433a 2453 for (i = 0; i < s->directory.next; i++) {
c227f099 2454 direntry_t* direntry = array_get(&(s->directory), i);
de167e41 2455
a046433a 2456 if (is_short_name(direntry) && begin_of_direntry(direntry)) {
c227f099 2457 mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
a046433a
FB
2458 assert(mapping);
2459 assert(mapping->dir_index == i || is_dot(direntry));
2460 assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2461 }
de167e41 2462
a046433a
FB
2463 if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2464 /* cluster start */
2465 int j, count = 0;
de167e41 2466
a046433a 2467 for (j = 0; j < s->mapping.next; j++) {
c227f099 2468 mapping_t* mapping = array_get(&(s->mapping), j);
a046433a 2469 if (mapping->mode & MODE_DELETED)
de167e41 2470 continue;
a046433a
FB
2471 if (mapping->mode & MODE_DIRECTORY) {
2472 if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2473 assert(++count == 1);
2474 if (mapping->first_mapping_index == -1)
2475 first_mapping = array_index(&(s->mapping), mapping);
2476 else
2477 assert(first_mapping == mapping->first_mapping_index);
2478 if (mapping->info.dir.parent_mapping_index < 0)
2479 assert(j == 0);
2480 else {
c227f099 2481 mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
a046433a
FB
2482 assert(parent->mode & MODE_DIRECTORY);
2483 assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2484 }
2485 }
de167e41 2486 }
a046433a
FB
2487 }
2488 if (count == 0)
2489 first_mapping = -1;
2490 }
2491 }
2492}
2493#endif
de167e41 2494
a046433a
FB
2495static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2496{
2497 int i;
de167e41 2498
a046433a
FB
2499#ifdef DEBUG
2500 fprintf(stderr, "handle_renames\n");
2501 for (i = 0; i < s->commits.next; i++) {
c227f099 2502 commit_t* commit = array_get(&(s->commits), i);
a046433a
FB
2503 fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
2504 }
2505#endif
2506
2507 for (i = 0; i < s->commits.next;) {
c227f099 2508 commit_t* commit = array_get(&(s->commits), i);
a046433a 2509 if (commit->action == ACTION_RENAME) {
c227f099 2510 mapping_t* mapping = find_mapping_for_cluster(s,
a046433a
FB
2511 commit->param.rename.cluster);
2512 char* old_path = mapping->path;
2513
2514 assert(commit->path);
2515 mapping->path = commit->path;
2516 if (rename(old_path, mapping->path))
2517 return -2;
2518
2519 if (mapping->mode & MODE_DIRECTORY) {
2520 int l1 = strlen(mapping->path);
2521 int l2 = strlen(old_path);
2522 int diff = l1 - l2;
c227f099 2523 direntry_t* direntry = array_get(&(s->directory),
a046433a
FB
2524 mapping->info.dir.first_dir_index);
2525 uint32_t c = mapping->begin;
2526 int i = 0;
2527
2528 /* recurse */
2529 while (!fat_eof(s, c)) {
2530 do {
c227f099 2531 direntry_t* d = direntry + i;
a046433a
FB
2532
2533 if (is_file(d) || (is_directory(d) && !is_dot(d))) {
c227f099 2534 mapping_t* m = find_mapping_for_cluster(s,
a046433a
FB
2535 begin_of_direntry(d));
2536 int l = strlen(m->path);
7267c094 2537 char* new_path = g_malloc(l + diff + 1);
a046433a
FB
2538
2539 assert(!strncmp(m->path, mapping->path, l2));
2540
363a37d5
BS
2541 pstrcpy(new_path, l + diff + 1, mapping->path);
2542 pstrcpy(new_path + l1, l + diff + 1 - l1,
2543 m->path + l2);
a046433a
FB
2544
2545 schedule_rename(s, m->begin, new_path);
de167e41 2546 }
a046433a
FB
2547 i++;
2548 } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2549 c = fat_get(s, c);
de167e41
FB
2550 }
2551 }
de167e41 2552
ce137829 2553 g_free(old_path);
a046433a
FB
2554 array_remove(&(s->commits), i);
2555 continue;
2556 } else if (commit->action == ACTION_MKDIR) {
c227f099 2557 mapping_t* mapping;
a046433a
FB
2558 int j, parent_path_len;
2559
48c2f068
FB
2560#ifdef __MINGW32__
2561 if (mkdir(commit->path))
2562 return -5;
2563#else
2564 if (mkdir(commit->path, 0755))
2565 return -5;
2566#endif
a046433a
FB
2567
2568 mapping = insert_mapping(s, commit->param.mkdir.cluster,
2569 commit->param.mkdir.cluster + 1);
2570 if (mapping == NULL)
2571 return -6;
2572
2573 mapping->mode = MODE_DIRECTORY;
2574 mapping->read_only = 0;
2575 mapping->path = commit->path;
2576 j = s->directory.next;
2577 assert(j);
2578 insert_direntries(s, s->directory.next,
2579 0x10 * s->sectors_per_cluster);
2580 mapping->info.dir.first_dir_index = j;
2581
2582 parent_path_len = strlen(commit->path)
2583 - strlen(get_basename(commit->path)) - 1;
2584 for (j = 0; j < s->mapping.next; j++) {
c227f099 2585 mapping_t* m = array_get(&(s->mapping), j);
a046433a
FB
2586 if (m->first_mapping_index < 0 && m != mapping &&
2587 !strncmp(m->path, mapping->path, parent_path_len) &&
2588 strlen(m->path) == parent_path_len)
2589 break;
2590 }
2591 assert(j < s->mapping.next);
2592 mapping->info.dir.parent_mapping_index = j;
2593
2594 array_remove(&(s->commits), i);
2595 continue;
2596 }
2597
2598 i++;
2599 }
2600 return 0;
2601}
2602
2603/*
2604 * TODO: make sure that the short name is not matching *another* file
2605 */
2606static int handle_commits(BDRVVVFATState* s)
2607{
2608 int i, fail = 0;
2609
2610 vvfat_close_current_file(s);
2611
2612 for (i = 0; !fail && i < s->commits.next; i++) {
c227f099 2613 commit_t* commit = array_get(&(s->commits), i);
a046433a
FB
2614 switch(commit->action) {
2615 case ACTION_RENAME: case ACTION_MKDIR:
43dc2a64 2616 abort();
a046433a
FB
2617 fail = -2;
2618 break;
2619 case ACTION_WRITEOUT: {
a6c6f76c
BS
2620#ifndef NDEBUG
2621 /* these variables are only used by assert() below */
c227f099 2622 direntry_t* entry = array_get(&(s->directory),
a046433a
FB
2623 commit->param.writeout.dir_index);
2624 uint32_t begin = begin_of_direntry(entry);
c227f099 2625 mapping_t* mapping = find_mapping_for_cluster(s, begin);
a6c6f76c 2626#endif
a046433a
FB
2627
2628 assert(mapping);
2629 assert(mapping->begin == begin);
2630 assert(commit->path == NULL);
2631
2632 if (commit_one_file(s, commit->param.writeout.dir_index,
2633 commit->param.writeout.modified_offset))
2634 fail = -3;
2635
2636 break;
2637 }
2638 case ACTION_NEW_FILE: {
2639 int begin = commit->param.new_file.first_cluster;
c227f099
AL
2640 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2641 direntry_t* entry;
a046433a 2642 int i;
de167e41 2643
a046433a
FB
2644 /* find direntry */
2645 for (i = 0; i < s->directory.next; i++) {
2646 entry = array_get(&(s->directory), i);
2647 if (is_file(entry) && begin_of_direntry(entry) == begin)
2648 break;
de167e41 2649 }
de167e41 2650
a046433a
FB
2651 if (i >= s->directory.next) {
2652 fail = -6;
2653 continue;
2654 }
de167e41 2655
a046433a
FB
2656 /* make sure there exists an initial mapping */
2657 if (mapping && mapping->begin != begin) {
2658 mapping->end = begin;
2659 mapping = NULL;
2660 }
2661 if (mapping == NULL) {
2662 mapping = insert_mapping(s, begin, begin+1);
2663 }
2664 /* most members will be fixed in commit_mappings() */
2665 assert(commit->path);
2666 mapping->path = commit->path;
2667 mapping->read_only = 0;
2668 mapping->mode = MODE_NORMAL;
2669 mapping->info.file.offset = 0;
2670
2671 if (commit_one_file(s, i, 0))
2672 fail = -7;
2673
2674 break;
2675 }
2676 default:
43dc2a64 2677 abort();
a046433a
FB
2678 }
2679 }
2680 if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2681 return -1;
2682 return fail;
2683}
2684
2685static int handle_deletes(BDRVVVFATState* s)
2686{
2687 int i, deferred = 1, deleted = 1;
2688
2689 /* delete files corresponding to mappings marked as deleted */
2690 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2691 while (deferred && deleted) {
2692 deferred = 0;
2693 deleted = 0;
2694
2695 for (i = 1; i < s->mapping.next; i++) {
c227f099 2696 mapping_t* mapping = array_get(&(s->mapping), i);
a046433a 2697 if (mapping->mode & MODE_DELETED) {
c227f099 2698 direntry_t* entry = array_get(&(s->directory),
a046433a
FB
2699 mapping->dir_index);
2700
2701 if (is_free(entry)) {
2702 /* remove file/directory */
2703 if (mapping->mode & MODE_DIRECTORY) {
2704 int j, next_dir_index = s->directory.next,
2705 first_dir_index = mapping->info.dir.first_dir_index;
2706
2707 if (rmdir(mapping->path) < 0) {
2708 if (errno == ENOTEMPTY) {
2709 deferred++;
2710 continue;
2711 } else
2712 return -5;
de167e41 2713 }
a046433a
FB
2714
2715 for (j = 1; j < s->mapping.next; j++) {
c227f099 2716 mapping_t* m = array_get(&(s->mapping), j);
a046433a
FB
2717 if (m->mode & MODE_DIRECTORY &&
2718 m->info.dir.first_dir_index >
2719 first_dir_index &&
2720 m->info.dir.first_dir_index <
2721 next_dir_index)
2722 next_dir_index =
2723 m->info.dir.first_dir_index;
de167e41 2724 }
a046433a
FB
2725 remove_direntries(s, first_dir_index,
2726 next_dir_index - first_dir_index);
de167e41 2727
a046433a 2728 deleted++;
de167e41 2729 }
a046433a
FB
2730 } else {
2731 if (unlink(mapping->path))
2732 return -4;
2733 deleted++;
de167e41 2734 }
a046433a
FB
2735 DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2736 remove_mapping(s, i);
de167e41
FB
2737 }
2738 }
2739 }
a046433a
FB
2740
2741 return 0;
2742}
2743
2744/*
2745 * synchronize mapping with new state:
2746 *
2747 * - copy FAT (with bdrv_read)
2748 * - mark all filenames corresponding to mappings as deleted
2749 * - recurse direntries from root (using bs->bdrv_read)
2750 * - delete files corresponding to mappings marked as deleted
2751 */
2752static int do_commit(BDRVVVFATState* s)
2753{
2754 int ret = 0;
2755
2756 /* the real meat are the commits. Nothing to do? Move along! */
2757 if (s->commits.next == 0)
2758 return 0;
2759
2760 vvfat_close_current_file(s);
2761
2762 ret = handle_renames_and_mkdirs(s);
2763 if (ret) {
2764 fprintf(stderr, "Error handling renames (%d)\n", ret);
43dc2a64 2765 abort();
a046433a
FB
2766 return ret;
2767 }
2768
5fafdf24 2769 /* copy FAT (with bdrv_read) */
a046433a
FB
2770 memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2771
2772 /* recurse direntries from root (using bs->bdrv_read) */
2773 ret = commit_direntries(s, 0, -1);
2774 if (ret) {
2775 fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
43dc2a64 2776 abort();
a046433a
FB
2777 return ret;
2778 }
2779
2780 ret = handle_commits(s);
2781 if (ret) {
2782 fprintf(stderr, "Error handling commits (%d)\n", ret);
43dc2a64 2783 abort();
a046433a
FB
2784 return ret;
2785 }
2786
2787 ret = handle_deletes(s);
2788 if (ret) {
2789 fprintf(stderr, "Error deleting\n");
43dc2a64 2790 abort();
a046433a
FB
2791 return ret;
2792 }
2793
eecc7747
KW
2794 if (s->qcow->bs->drv->bdrv_make_empty) {
2795 s->qcow->bs->drv->bdrv_make_empty(s->qcow->bs);
7704df98 2796 }
a046433a
FB
2797
2798 memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2799
2800DLOG(checkpoint());
2801 return 0;
2802}
2803
2804static int try_commit(BDRVVVFATState* s)
2805{
2806 vvfat_close_current_file(s);
2807DLOG(checkpoint());
2808 if(!is_consistent(s))
2809 return -1;
2810 return do_commit(s);
2811}
2812
5fafdf24 2813static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
a046433a
FB
2814 const uint8_t *buf, int nb_sectors)
2815{
5fafdf24 2816 BDRVVVFATState *s = bs->opaque;
a046433a
FB
2817 int i, ret;
2818
2819DLOG(checkpoint());
2820
ac48e389
KW
2821 /* Check if we're operating in read-only mode */
2822 if (s->qcow == NULL) {
2823 return -EACCES;
2824 }
2825
a046433a
FB
2826 vvfat_close_current_file(s);
2827
2828 /*
2829 * Some sanity checks:
2830 * - do not allow writing to the boot sector
2831 * - do not allow to write non-ASCII filenames
2832 */
2833
2834 if (sector_num < s->first_sectors_number)
2835 return -1;
2836
2837 for (i = sector2cluster(s, sector_num);
2838 i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
c227f099 2839 mapping_t* mapping = find_mapping_for_cluster(s, i);
a046433a
FB
2840 if (mapping) {
2841 if (mapping->read_only) {
2842 fprintf(stderr, "Tried to write to write-protected file %s\n",
2843 mapping->path);
2844 return -1;
2845 }
2846
2847 if (mapping->mode & MODE_DIRECTORY) {
2848 int begin = cluster2sector(s, i);
2849 int end = begin + s->sectors_per_cluster, k;
2850 int dir_index;
c227f099 2851 const direntry_t* direntries;
a046433a
FB
2852 long_file_name lfn;
2853
2854 lfn_init(&lfn);
2855
2856 if (begin < sector_num)
2857 begin = sector_num;
2858 if (end > sector_num + nb_sectors)
2859 end = sector_num + nb_sectors;
5fafdf24 2860 dir_index = mapping->dir_index +
a046433a 2861 0x10 * (begin - mapping->begin * s->sectors_per_cluster);
c227f099 2862 direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
a046433a
FB
2863
2864 for (k = 0; k < (end - begin) * 0x10; k++) {
2865 /* do not allow non-ASCII filenames */
2866 if (parse_long_name(&lfn, direntries + k) < 0) {
2867 fprintf(stderr, "Warning: non-ASCII filename\n");
2868 return -1;
2869 }
2870 /* no access to the direntry of a read-only file */
2871 else if (is_short_name(direntries+k) &&
2872 (direntries[k].attributes & 1)) {
2873 if (memcmp(direntries + k,
2874 array_get(&(s->directory), dir_index + k),
c227f099 2875 sizeof(direntry_t))) {
a046433a
FB
2876 fprintf(stderr, "Warning: tried to write to write-protected file\n");
2877 return -1;
2878 }
2879 }
2880 }
2881 }
2882 i = mapping->end;
2883 } else
2884 i++;
2885 }
2886
2887 /*
2888 * Use qcow backend. Commit later.
2889 */
2890DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
18d51c4b 2891 ret = bdrv_write(s->qcow, sector_num, buf, nb_sectors);
a046433a
FB
2892 if (ret < 0) {
2893 fprintf(stderr, "Error writing to qcow backend\n");
2894 return ret;
2895 }
2896
2897 for (i = sector2cluster(s, sector_num);
2898 i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
2899 if (i >= 0)
2900 s->used_clusters[i] |= USED_ALLOCATED;
2901
2902DLOG(checkpoint());
2903 /* TODO: add timeout */
2904 try_commit(s);
2905
2906DLOG(checkpoint());
2907 return 0;
2908}
2909
4575eb49
KW
2910static int coroutine_fn
2911vvfat_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
2912 QEMUIOVector *qiov, int flags)
e183ef75
PB
2913{
2914 int ret;
2915 BDRVVVFATState *s = bs->opaque;
4575eb49
KW
2916 uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
2917 int nb_sectors = bytes >> BDRV_SECTOR_BITS;
2918 void *buf;
2919
2920 assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
2921 assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
2922
2923 buf = g_try_malloc(bytes);
2924 if (bytes && buf == NULL) {
2925 return -ENOMEM;
2926 }
2927 qemu_iovec_to_buf(qiov, 0, buf, bytes);
2928
e183ef75
PB
2929 qemu_co_mutex_lock(&s->lock);
2930 ret = vvfat_write(bs, sector_num, buf, nb_sectors);
2931 qemu_co_mutex_unlock(&s->lock);
4575eb49
KW
2932
2933 g_free(buf);
2934
e183ef75
PB
2935 return ret;
2936}
2937
b6b8a333 2938static int64_t coroutine_fn vvfat_co_get_block_status(BlockDriverState *bs,
67a0fd2a 2939 int64_t sector_num, int nb_sectors, int *n, BlockDriverState **file)
a046433a
FB
2940{
2941 BDRVVVFATState* s = bs->opaque;
2942 *n = s->sector_count - sector_num;
4bc74be9
PB
2943 if (*n > nb_sectors) {
2944 *n = nb_sectors;
2945 } else if (*n < 0) {
2946 return 0;
2947 }
2948 return BDRV_BLOCK_DATA;
a046433a
FB
2949}
2950
4575eb49
KW
2951static int coroutine_fn
2952write_target_commit(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
2953 QEMUIOVector *qiov, int flags)
2954{
9217e26f 2955 BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
a046433a
FB
2956 return try_commit(s);
2957}
2958
2959static void write_target_close(BlockDriverState *bs) {
9217e26f 2960 BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
eecc7747 2961 bdrv_unref_child(s->bs, s->qcow);
ce137829 2962 g_free(s->qcow_filename);
a046433a
FB
2963}
2964
2965static BlockDriver vvfat_write_target = {
f9e96436 2966 .format_name = "vvfat_write_target",
4575eb49 2967 .bdrv_co_pwritev = write_target_commit,
f9e96436 2968 .bdrv_close = write_target_close,
a046433a
FB
2969};
2970
eecc7747
KW
2971static void vvfat_qcow_options(int *child_flags, QDict *child_options,
2972 int parent_flags, QDict *parent_options)
a046433a 2973{
f87a0e29
AG
2974 qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off");
2975 *child_flags = BDRV_O_NO_FLUSH;
eecc7747
KW
2976}
2977
2978static const BdrvChildRole child_vvfat_qcow = {
2979 .inherit_options = vvfat_qcow_options,
2980};
2981
2982static int enable_write_target(BlockDriverState *bs, Error **errp)
2983{
2984 BDRVVVFATState *s = bs->opaque;
facdbb02 2985 BlockDriver *bdrv_qcow = NULL;
5db15a57 2986 BlockDriverState *backing;
facdbb02 2987 QemuOpts *opts = NULL;
a655211a 2988 int ret;
a046433a 2989 int size = sector2cluster(s, s->sector_count);
e6641719
HR
2990 QDict *options;
2991
a046433a
FB
2992 s->used_clusters = calloc(size, 1);
2993
c227f099 2994 array_init(&(s->commits), sizeof(commit_t));
a046433a 2995
9a29e18f
JC
2996 s->qcow_filename = g_malloc(PATH_MAX);
2997 ret = get_tmp_filename(s->qcow_filename, PATH_MAX);
eba25057 2998 if (ret < 0) {
68c70af1 2999 error_setg_errno(errp, -ret, "can't create temporary file");
78f27bd0 3000 goto err;
eba25057 3001 }
91a073a9
KW
3002
3003 bdrv_qcow = bdrv_find_format("qcow");
1bcb15cf
HR
3004 if (!bdrv_qcow) {
3005 error_setg(errp, "Failed to locate qcow driver");
3006 ret = -ENOENT;
3007 goto err;
3008 }
3009
c282e1fd 3010 opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort);
39101f25
MA
3011 qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512,
3012 &error_abort);
f43e47db 3013 qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:", &error_abort);
91a073a9 3014
c282e1fd 3015 ret = bdrv_create(bdrv_qcow, s->qcow_filename, opts, errp);
facdbb02 3016 qemu_opts_del(opts);
78f27bd0
FZ
3017 if (ret < 0) {
3018 goto err;
3019 }
a655211a 3020
e6641719 3021 options = qdict_new();
c4b48bfd 3022 qdict_put(options, "write-target.driver", qstring_from_str("qcow"));
eecc7747
KW
3023 s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs,
3024 &child_vvfat_qcow, false, errp);
c4b48bfd 3025 QDECREF(options);
5b363937
HR
3026 if (!s->qcow) {
3027 ret = -EINVAL;
78f27bd0 3028 goto err;
d6e9098e 3029 }
a046433a
FB
3030
3031#ifndef _WIN32
3032 unlink(s->qcow_filename);
3033#endif
3034
5db15a57
KW
3035 backing = bdrv_new();
3036 bdrv_set_backing_hd(s->bs, backing);
3037 bdrv_unref(backing);
3038
760e0063
KW
3039 s->bs->backing->bs->drv = &vvfat_write_target;
3040 s->bs->backing->bs->opaque = g_new(void *, 1);
3041 *(void**)s->bs->backing->bs->opaque = s;
a046433a 3042
de167e41 3043 return 0;
78f27bd0
FZ
3044
3045err:
3046 g_free(s->qcow_filename);
3047 s->qcow_filename = NULL;
3048 return ret;
de167e41
FB
3049}
3050
3051static void vvfat_close(BlockDriverState *bs)
3052{
3053 BDRVVVFATState *s = bs->opaque;
3054
3055 vvfat_close_current_file(s);
3056 array_free(&(s->fat));
3057 array_free(&(s->directory));
3058 array_free(&(s->mapping));
ce137829 3059 g_free(s->cluster_buffer);
3397f0cb
KW
3060
3061 if (s->qcow) {
3062 migrate_del_blocker(s->migration_blocker);
3063 error_free(s->migration_blocker);
3064 }
de167e41
FB
3065}
3066
5efa9d5a 3067static BlockDriver bdrv_vvfat = {
7ad9be64
KW
3068 .format_name = "vvfat",
3069 .protocol_name = "fat",
3070 .instance_size = sizeof(BDRVVVFATState),
3071
3072 .bdrv_parse_filename = vvfat_parse_filename,
3073 .bdrv_file_open = vvfat_open,
a6506481 3074 .bdrv_refresh_limits = vvfat_refresh_limits,
7ad9be64 3075 .bdrv_close = vvfat_close,
7ad9be64 3076
4575eb49
KW
3077 .bdrv_co_preadv = vvfat_co_preadv,
3078 .bdrv_co_pwritev = vvfat_co_pwritev,
b6b8a333 3079 .bdrv_co_get_block_status = vvfat_co_get_block_status,
de167e41
FB
3080};
3081
5efa9d5a
AL
3082static void bdrv_vvfat_init(void)
3083{
3084 bdrv_register(&bdrv_vvfat);
3085}
3086
3087block_init(bdrv_vvfat_init);
3088
a046433a 3089#ifdef DEBUG
3f47aa8c 3090static void checkpoint(void) {
c227f099 3091 assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
a046433a
FB
3092 check1(vvv);
3093 check2(vvv);
3094 assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
3095#if 0
c227f099 3096 if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
a046433a 3097 fprintf(stderr, "Nonono!\n");
c227f099
AL
3098 mapping_t* mapping;
3099 direntry_t* direntry;
a046433a
FB
3100 assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
3101 assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
3102 if (vvv->mapping.next<47)
3103 return;
3104 assert((mapping = array_get(&(vvv->mapping), 47)));
3105 assert(mapping->dir_index < vvv->directory.next);
3106 direntry = array_get(&(vvv->directory), mapping->dir_index);
3107 assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0);
3108#endif
a046433a
FB
3109}
3110#endif