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