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