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