]> Git Repo - qemu.git/blame - block/vvfat.c
block: Set request_alignment during .bdrv_refresh_limits()
[qemu.git] / block / vvfat.c
CommitLineData
7ad9be64 1/* vim:set shiftwidth=4 ts=4: */
de167e41
FB
2/*
3 * QEMU Block driver for virtual VFAT (shadows a local directory)
5fafdf24 4 *
a046433a 5 * Copyright (c) 2004,2005 Johannes E. Schindelin
5fafdf24 6 *
de167e41
FB
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
80c71a24 25#include "qemu/osdep.h"
de167e41 26#include <dirent.h>
da34e65c 27#include "qapi/error.h"
737e150e 28#include "block/block_int.h"
1de7afc9 29#include "qemu/module.h"
58369e22 30#include "qemu/bswap.h"
caf71f86 31#include "migration/migration.h"
7ad9be64
KW
32#include "qapi/qmp/qint.h"
33#include "qapi/qmp/qbool.h"
d49b6836 34#include "qapi/qmp/qstring.h"
f348b6d1 35#include "qemu/cutils.h"
de167e41 36
a046433a
FB
37#ifndef S_IWGRP
38#define S_IWGRP 0
39#endif
40#ifndef S_IWOTH
41#define S_IWOTH 0
42#endif
43
44/* TODO: add ":bootsector=blabla.img:" */
45/* LATER TODO: add automatic boot sector generation from
46 BOOTEASY.ASM and Ranish Partition Manager
5fafdf24 47 Note that DOS assumes the system files to be the first files in the
a046433a
FB
48 file system (test if the boot sector still relies on that fact)! */
49/* MAYBE TODO: write block-visofs.c */
50/* TODO: call try_commit() only after a timeout */
51
52/* #define DEBUG */
53
54#ifdef DEBUG
55
56#define DLOG(a) a
57
3f47aa8c 58static void checkpoint(void);
de167e41 59
a046433a
FB
60#ifdef __MINGW32__
61void nonono(const char* file, int line, const char* msg) {
62 fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg);
63 exit(-5);
64}
65#undef assert
6bcb76c3 66#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
a046433a
FB
67#endif
68
69#else
70
71#define DLOG(a)
72
73#endif
de167e41
FB
74
75/* dynamic array functions */
c227f099 76typedef struct array_t {
de167e41
FB
77 char* pointer;
78 unsigned int size,next,item_size;
c227f099 79} array_t;
de167e41 80
c227f099 81static inline void array_init(array_t* array,unsigned int item_size)
de167e41 82{
511d2b14 83 array->pointer = NULL;
de167e41
FB
84 array->size=0;
85 array->next=0;
86 array->item_size=item_size;
87}
88
c227f099 89static inline void array_free(array_t* array)
de167e41 90{
ce137829 91 g_free(array->pointer);
de167e41
FB
92 array->size=array->next=0;
93}
94
a046433a 95/* does not automatically grow */
c227f099 96static inline void* array_get(array_t* array,unsigned int index) {
a046433a
FB
97 assert(index < array->next);
98 return array->pointer + index * array->item_size;
99}
100
c227f099 101static inline int array_ensure_allocated(array_t* array, int index)
a046433a
FB
102{
103 if((index + 1) * array->item_size > array->size) {
104 int new_size = (index + 32) * array->item_size;
7267c094 105 array->pointer = g_realloc(array->pointer, new_size);
a046433a
FB
106 if (!array->pointer)
107 return -1;
108 array->size = new_size;
109 array->next = index + 1;
de167e41 110 }
a046433a
FB
111
112 return 0;
de167e41
FB
113}
114
c227f099 115static inline void* array_get_next(array_t* array) {
a046433a 116 unsigned int next = array->next;
a046433a
FB
117
118 if (array_ensure_allocated(array, next) < 0)
119 return NULL;
120
121 array->next = next + 1;
9be38598 122 return array_get(array, next);
de167e41
FB
123}
124
c227f099 125static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
de167e41
FB
126 if((array->next+count)*array->item_size>array->size) {
127 int increment=count*array->item_size;
7267c094 128 array->pointer=g_realloc(array->pointer,array->size+increment);
de167e41 129 if(!array->pointer)
511d2b14 130 return NULL;
de167e41
FB
131 array->size+=increment;
132 }
133 memmove(array->pointer+(index+count)*array->item_size,
134 array->pointer+index*array->item_size,
135 (array->next-index)*array->item_size);
136 array->next+=count;
137 return array->pointer+index*array->item_size;
138}
139
140/* this performs a "roll", so that the element which was at index_from becomes
141 * index_to, but the order of all other elements is preserved. */
c227f099 142static inline int array_roll(array_t* array,int index_to,int index_from,int count)
de167e41
FB
143{
144 char* buf;
145 char* from;
146 char* to;
147 int is;
148
149 if(!array ||
150 index_to<0 || index_to>=array->next ||
151 index_from<0 || index_from>=array->next)
152 return -1;
3b46e624 153
de167e41
FB
154 if(index_to==index_from)
155 return 0;
156
157 is=array->item_size;
158 from=array->pointer+index_from*is;
159 to=array->pointer+index_to*is;
7267c094 160 buf=g_malloc(is*count);
de167e41
FB
161 memcpy(buf,from,is*count);
162
163 if(index_to<index_from)
164 memmove(to+is*count,to,from-to);
165 else
166 memmove(from,from+is*count,to-from);
3b46e624 167
de167e41
FB
168 memcpy(to,buf,is*count);
169
ce137829 170 g_free(buf);
de167e41
FB
171
172 return 0;
173}
174
c227f099 175static inline int array_remove_slice(array_t* array,int index, int count)
de167e41 176{
a046433a
FB
177 assert(index >=0);
178 assert(count > 0);
179 assert(index + count <= array->next);
180 if(array_roll(array,array->next-1,index,count))
de167e41 181 return -1;
a046433a 182 array->next -= count;
de167e41
FB
183 return 0;
184}
185
c227f099 186static int array_remove(array_t* array,int index)
a046433a
FB
187{
188 return array_remove_slice(array, index, 1);
189}
190
191/* return the index for a given member */
c227f099 192static int array_index(array_t* array, void* pointer)
a046433a
FB
193{
194 size_t offset = (char*)pointer - array->pointer;
a046433a
FB
195 assert((offset % array->item_size) == 0);
196 assert(offset/array->item_size < array->next);
197 return offset/array->item_size;
198}
199
de167e41 200/* These structures are used to fake a disk and the VFAT filesystem.
541dc0d4 201 * For this reason we need to use QEMU_PACKED. */
de167e41 202
c227f099 203typedef struct bootsector_t {
de167e41
FB
204 uint8_t jump[3];
205 uint8_t name[8];
206 uint16_t sector_size;
207 uint8_t sectors_per_cluster;
208 uint16_t reserved_sectors;
209 uint8_t number_of_fats;
210 uint16_t root_entries;
a046433a 211 uint16_t total_sectors16;
de167e41
FB
212 uint8_t media_type;
213 uint16_t sectors_per_fat;
214 uint16_t sectors_per_track;
215 uint16_t number_of_heads;
216 uint32_t hidden_sectors;
217 uint32_t total_sectors;
218 union {
219 struct {
220 uint8_t drive_number;
221 uint8_t current_head;
222 uint8_t signature;
223 uint32_t id;
224 uint8_t volume_label[11];
541dc0d4 225 } QEMU_PACKED fat16;
de167e41
FB
226 struct {
227 uint32_t sectors_per_fat;
228 uint16_t flags;
229 uint8_t major,minor;
230 uint32_t first_cluster_of_root_directory;
231 uint16_t info_sector;
232 uint16_t backup_boot_sector;
233 uint16_t ignored;
541dc0d4 234 } QEMU_PACKED fat32;
de167e41
FB
235 } u;
236 uint8_t fat_type[8];
237 uint8_t ignored[0x1c0];
238 uint8_t magic[2];
541dc0d4 239} QEMU_PACKED bootsector_t;
de167e41 240
b570094d
TS
241typedef struct {
242 uint8_t head;
243 uint8_t sector;
244 uint8_t cylinder;
c227f099 245} mbr_chs_t;
b570094d 246
c227f099 247typedef struct partition_t {
de167e41 248 uint8_t attributes; /* 0x80 = bootable */
c227f099 249 mbr_chs_t start_CHS;
b570094d 250 uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
c227f099 251 mbr_chs_t end_CHS;
de167e41 252 uint32_t start_sector_long;
b570094d 253 uint32_t length_sector_long;
541dc0d4 254} QEMU_PACKED partition_t;
de167e41 255
c227f099 256typedef struct mbr_t {
b570094d
TS
257 uint8_t ignored[0x1b8];
258 uint32_t nt_id;
259 uint8_t ignored2[2];
c227f099 260 partition_t partition[4];
de167e41 261 uint8_t magic[2];
541dc0d4 262} QEMU_PACKED mbr_t;
de167e41 263
c227f099 264typedef struct direntry_t {
f671d173 265 uint8_t name[8 + 3];
de167e41
FB
266 uint8_t attributes;
267 uint8_t reserved[2];
268 uint16_t ctime;
269 uint16_t cdate;
270 uint16_t adate;
271 uint16_t begin_hi;
272 uint16_t mtime;
273 uint16_t mdate;
274 uint16_t begin;
275 uint32_t size;
541dc0d4 276} QEMU_PACKED direntry_t;
de167e41
FB
277
278/* this structure are used to transparently access the files */
279
c227f099 280typedef struct mapping_t {
a046433a
FB
281 /* begin is the first cluster, end is the last+1 */
282 uint32_t begin,end;
de167e41
FB
283 /* as s->directory is growable, no pointer may be used here */
284 unsigned int dir_index;
a046433a
FB
285 /* the clusters of a file may be in any order; this points to the first */
286 int first_mapping_index;
287 union {
288 /* offset is
289 * - the offset in the file (in clusters) for a file, or
290 * - the next cluster of the directory for a directory, and
291 * - the address of the buffer for a faked entry
292 */
293 struct {
294 uint32_t offset;
295 } file;
296 struct {
297 int parent_mapping_index;
298 int first_dir_index;
299 } dir;
300 } info;
301 /* path contains the full path, i.e. it always starts with s->path */
302 char* path;
303
304 enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2,
305 MODE_DIRECTORY = 4, MODE_FAKED = 8,
306 MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
307 int read_only;
c227f099 308} mapping_t;
de167e41 309
a046433a 310#ifdef DEBUG
c227f099
AL
311static void print_direntry(const struct direntry_t*);
312static void print_mapping(const struct mapping_t* mapping);
a046433a 313#endif
de167e41
FB
314
315/* here begins the real VVFAT driver */
316
317typedef struct BDRVVVFATState {
848c66e8 318 CoMutex lock;
a046433a 319 BlockDriverState* bs; /* pointer to parent */
de167e41
FB
320 unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
321 unsigned char first_sectors[0x40*0x200];
3b46e624 322
de167e41 323 int fat_type; /* 16 or 32 */
c227f099 324 array_t fat,directory,mapping;
d5941dda 325 char volume_label[11];
3b46e624 326
de167e41
FB
327 unsigned int cluster_size;
328 unsigned int sectors_per_cluster;
329 unsigned int sectors_per_fat;
330 unsigned int sectors_of_root_directory;
a046433a 331 uint32_t last_cluster_of_root_directory;
de167e41
FB
332 unsigned int faked_sectors; /* how many sectors are faked before file data */
333 uint32_t sector_count; /* total number of sectors of the partition */
334 uint32_t cluster_count; /* total number of clusters of this partition */
de167e41 335 uint32_t max_fat_value;
3b46e624 336
de167e41 337 int current_fd;
c227f099 338 mapping_t* current_mapping;
a046433a
FB
339 unsigned char* cluster; /* points to current cluster */
340 unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
de167e41
FB
341 unsigned int current_cluster;
342
343 /* write support */
a046433a
FB
344 BlockDriverState* write_target;
345 char* qcow_filename;
346 BlockDriverState* qcow;
347 void* fat2;
348 char* used_clusters;
c227f099 349 array_t commits;
a046433a
FB
350 const char* path;
351 int downcase_short_names;
3397f0cb
KW
352
353 Error *migration_blocker;
de167e41
FB
354} BDRVVVFATState;
355
b570094d
TS
356/* take the sector position spos and convert it to Cylinder/Head/Sector position
357 * if the position is outside the specified geometry, fill maximum value for CHS
358 * and return 1 to signal overflow.
359 */
4480e0f9
MA
360static int sector2CHS(mbr_chs_t *chs, int spos, int cyls, int heads, int secs)
361{
b570094d 362 int head,sector;
4480e0f9
MA
363 sector = spos % secs; spos /= secs;
364 head = spos % heads; spos /= heads;
365 if (spos >= cyls) {
b570094d
TS
366 /* Overflow,
367 it happens if 32bit sector positions are used, while CHS is only 24bit.
368 Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
369 chs->head = 0xFF;
370 chs->sector = 0xFF;
371 chs->cylinder = 0xFF;
372 return 1;
373 }
374 chs->head = (uint8_t)head;
375 chs->sector = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
376 chs->cylinder = (uint8_t)spos;
377 return 0;
378}
de167e41 379
4480e0f9 380static void init_mbr(BDRVVVFATState *s, int cyls, int heads, int secs)
de167e41
FB
381{
382 /* TODO: if the files mbr.img and bootsect.img exist, use them */
c227f099
AL
383 mbr_t* real_mbr=(mbr_t*)s->first_sectors;
384 partition_t* partition = &(real_mbr->partition[0]);
b570094d 385 int lba;
de167e41
FB
386
387 memset(s->first_sectors,0,512);
3b46e624 388
b570094d
TS
389 /* Win NT Disk Signature */
390 real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
391
de167e41 392 partition->attributes=0x80; /* bootable */
b570094d
TS
393
394 /* LBA is used when partition is outside the CHS geometry */
4480e0f9
MA
395 lba = sector2CHS(&partition->start_CHS, s->first_sectors_number - 1,
396 cyls, heads, secs);
397 lba |= sector2CHS(&partition->end_CHS, s->bs->total_sectors - 1,
398 cyls, heads, secs);
b570094d
TS
399
400 /*LBA partitions are identified only by start/length_sector_long not by CHS*/
f91cbefe
MA
401 partition->start_sector_long = cpu_to_le32(s->first_sectors_number - 1);
402 partition->length_sector_long = cpu_to_le32(s->bs->total_sectors
403 - s->first_sectors_number + 1);
b570094d 404
a046433a 405 /* FAT12/FAT16/FAT32 */
b570094d
TS
406 /* DOS uses different types when partition is LBA,
407 probably to prevent older versions from using CHS on them */
408 partition->fs_type= s->fat_type==12 ? 0x1:
409 s->fat_type==16 ? (lba?0xe:0x06):
410 /*fat_tyoe==32*/ (lba?0xc:0x0b);
de167e41
FB
411
412 real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
413}
414
a046433a
FB
415/* direntry functions */
416
de167e41 417/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
60fe76f3 418static inline int short2long_name(char* dest,const char* src)
de167e41
FB
419{
420 int i;
1e080d5d 421 int len;
de167e41
FB
422 for(i=0;i<129 && src[i];i++) {
423 dest[2*i]=src[i];
424 dest[2*i+1]=0;
425 }
1e080d5d 426 len=2*i;
de167e41
FB
427 dest[2*i]=dest[2*i+1]=0;
428 for(i=2*i+2;(i%26);i++)
429 dest[i]=0xff;
1e080d5d 430 return len;
de167e41
FB
431}
432
c227f099 433static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
de167e41
FB
434{
435 char buffer[258];
436 int length=short2long_name(buffer,filename),
437 number_of_entries=(length+25)/26,i;
c227f099 438 direntry_t* entry;
de167e41
FB
439
440 for(i=0;i<number_of_entries;i++) {
441 entry=array_get_next(&(s->directory));
442 entry->attributes=0xf;
443 entry->reserved[0]=0;
444 entry->begin=0;
445 entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
446 }
1e080d5d 447 for(i=0;i<26*number_of_entries;i++) {
de167e41
FB
448 int offset=(i%26);
449 if(offset<10) offset=1+offset;
450 else if(offset<22) offset=14+offset-10;
451 else offset=28+offset-22;
452 entry=array_get(&(s->directory),s->directory.next-1-(i/26));
453 entry->name[offset]=buffer[i];
454 }
455 return array_get(&(s->directory),s->directory.next-number_of_entries);
456}
457
c227f099 458static char is_free(const direntry_t* direntry)
a046433a 459{
ad1a897e 460 return direntry->name[0]==0xe5 || direntry->name[0]==0x00;
a046433a
FB
461}
462
c227f099 463static char is_volume_label(const direntry_t* direntry)
a046433a
FB
464{
465 return direntry->attributes == 0x28;
466}
467
c227f099 468static char is_long_name(const direntry_t* direntry)
a046433a
FB
469{
470 return direntry->attributes == 0xf;
471}
472
c227f099 473static char is_short_name(const direntry_t* direntry)
a046433a
FB
474{
475 return !is_volume_label(direntry) && !is_long_name(direntry)
476 && !is_free(direntry);
477}
478
c227f099 479static char is_directory(const direntry_t* direntry)
a046433a
FB
480{
481 return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
482}
483
c227f099 484static inline char is_dot(const direntry_t* direntry)
a046433a
FB
485{
486 return is_short_name(direntry) && direntry->name[0] == '.';
487}
488
c227f099 489static char is_file(const direntry_t* direntry)
a046433a
FB
490{
491 return is_short_name(direntry) && !is_directory(direntry);
492}
493
c227f099 494static inline uint32_t begin_of_direntry(const direntry_t* direntry)
a046433a
FB
495{
496 return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
497}
498
c227f099 499static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
a046433a
FB
500{
501 return le32_to_cpu(direntry->size);
502}
503
c227f099 504static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
a046433a
FB
505{
506 direntry->begin = cpu_to_le16(begin & 0xffff);
507 direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
508}
509
de167e41
FB
510/* fat functions */
511
c227f099 512static inline uint8_t fat_chksum(const direntry_t* entry)
de167e41
FB
513{
514 uint8_t chksum=0;
515 int i;
516
f671d173
SW
517 for (i = 0; i < ARRAY_SIZE(entry->name); i++) {
518 chksum = (((chksum & 0xfe) >> 1) |
519 ((chksum & 0x01) ? 0x80 : 0)) + entry->name[i];
5606c220 520 }
3b46e624 521
de167e41
FB
522 return chksum;
523}
524
525/* if return_time==0, this returns the fat_date, else the fat_time */
526static uint16_t fat_datetime(time_t time,int return_time) {
527 struct tm* t;
de167e41 528 struct tm t1;
6ab00cee 529 t = &t1;
de167e41 530 localtime_r(&time,t);
de167e41
FB
531 if(return_time)
532 return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
533 return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
534}
535
536static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
537{
a046433a
FB
538 if(s->fat_type==32) {
539 uint32_t* entry=array_get(&(s->fat),cluster);
540 *entry=cpu_to_le32(value);
de167e41
FB
541 } else if(s->fat_type==16) {
542 uint16_t* entry=array_get(&(s->fat),cluster);
543 *entry=cpu_to_le16(value&0xffff);
544 } else {
a046433a
FB
545 int offset = (cluster*3/2);
546 unsigned char* p = array_get(&(s->fat), offset);
547 switch (cluster&1) {
548 case 0:
549 p[0] = value&0xff;
550 p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
551 break;
552 case 1:
553 p[0] = (p[0]&0xf) | ((value&0xf)<<4);
554 p[1] = (value>>4);
555 break;
556 }
de167e41
FB
557 }
558}
559
560static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
561{
a046433a
FB
562 if(s->fat_type==32) {
563 uint32_t* entry=array_get(&(s->fat),cluster);
564 return le32_to_cpu(*entry);
de167e41
FB
565 } else if(s->fat_type==16) {
566 uint16_t* entry=array_get(&(s->fat),cluster);
567 return le16_to_cpu(*entry);
568 } else {
ffe8ab83 569 const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
a046433a 570 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
de167e41
FB
571 }
572}
573
574static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
575{
576 if(fat_entry>s->max_fat_value-8)
577 return -1;
578 return 0;
579}
580
581static inline void init_fat(BDRVVVFATState* s)
582{
a046433a
FB
583 if (s->fat_type == 12) {
584 array_init(&(s->fat),1);
585 array_ensure_allocated(&(s->fat),
586 s->sectors_per_fat * 0x200 * 3 / 2 - 1);
587 } else {
588 array_init(&(s->fat),(s->fat_type==32?4:2));
589 array_ensure_allocated(&(s->fat),
590 s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
591 }
de167e41 592 memset(s->fat.pointer,0,s->fat.size);
3b46e624 593
de167e41
FB
594 switch(s->fat_type) {
595 case 12: s->max_fat_value=0xfff; break;
596 case 16: s->max_fat_value=0xffff; break;
a046433a 597 case 32: s->max_fat_value=0x0fffffff; break;
de167e41
FB
598 default: s->max_fat_value=0; /* error... */
599 }
600
601}
602
a046433a
FB
603/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
604/* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
c227f099 605static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
a046433a 606 unsigned int directory_start, const char* filename, int is_dot)
de167e41 607{
a046433a 608 int i,j,long_index=s->directory.next;
c227f099
AL
609 direntry_t* entry = NULL;
610 direntry_t* entry_long = NULL;
de167e41
FB
611
612 if(is_dot) {
613 entry=array_get_next(&(s->directory));
f671d173 614 memset(entry->name, 0x20, sizeof(entry->name));
de167e41
FB
615 memcpy(entry->name,filename,strlen(filename));
616 return entry;
617 }
3b46e624 618
de167e41 619 entry_long=create_long_filename(s,filename);
3b46e624 620
5fafdf24 621 i = strlen(filename);
a046433a
FB
622 for(j = i - 1; j>0 && filename[j]!='.';j--);
623 if (j > 0)
624 i = (j > 8 ? 8 : j);
625 else if (i > 8)
626 i = 8;
627
de167e41 628 entry=array_get_next(&(s->directory));
f671d173 629 memset(entry->name, 0x20, sizeof(entry->name));
51a0f568 630 memcpy(entry->name, filename, i);
3b46e624 631
f671d173
SW
632 if (j > 0) {
633 for (i = 0; i < 3 && filename[j + 1 + i]; i++) {
634 entry->name[8 + i] = filename[j + 1 + i];
635 }
636 }
de167e41
FB
637
638 /* upcase & remove unwanted characters */
639 for(i=10;i>=0;i--) {
a046433a 640 if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
de167e41 641 if(entry->name[i]<=' ' || entry->name[i]>0x7f
a046433a 642 || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
de167e41
FB
643 entry->name[i]='_';
644 else if(entry->name[i]>='a' && entry->name[i]<='z')
645 entry->name[i]+='A'-'a';
646 }
647
648 /* mangle duplicates */
649 while(1) {
c227f099 650 direntry_t* entry1=array_get(&(s->directory),directory_start);
de167e41
FB
651 int j;
652
653 for(;entry1<entry;entry1++)
a046433a 654 if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
de167e41
FB
655 break; /* found dupe */
656 if(entry1==entry) /* no dupe found */
657 break;
658
5fafdf24 659 /* use all 8 characters of name */
de167e41
FB
660 if(entry->name[7]==' ') {
661 int j;
662 for(j=6;j>0 && entry->name[j]==' ';j--)
663 entry->name[j]='~';
664 }
665
666 /* increment number */
667 for(j=7;j>0 && entry->name[j]=='9';j--)
668 entry->name[j]='0';
669 if(j>0) {
670 if(entry->name[j]<'0' || entry->name[j]>'9')
671 entry->name[j]='0';
672 else
673 entry->name[j]++;
674 }
675 }
676
677 /* calculate checksum; propagate to long name */
678 if(entry_long) {
679 uint8_t chksum=fat_chksum(entry);
680
681 /* calculate anew, because realloc could have taken place */
682 entry_long=array_get(&(s->directory),long_index);
a046433a 683 while(entry_long<entry && is_long_name(entry_long)) {
de167e41
FB
684 entry_long->reserved[1]=chksum;
685 entry_long++;
686 }
687 }
688
689 return entry;
690}
691
a046433a
FB
692/*
693 * Read a directory. (the index of the corresponding mapping must be passed).
694 */
695static int read_directory(BDRVVVFATState* s, int mapping_index)
de167e41 696{
c227f099
AL
697 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
698 direntry_t* direntry;
a046433a
FB
699 const char* dirname = mapping->path;
700 int first_cluster = mapping->begin;
701 int parent_index = mapping->info.dir.parent_mapping_index;
c227f099 702 mapping_t* parent_mapping = (mapping_t*)
511d2b14 703 (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL);
a046433a 704 int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
de167e41
FB
705
706 DIR* dir=opendir(dirname);
707 struct dirent* entry;
de167e41
FB
708 int i;
709
a046433a
FB
710 assert(mapping->mode & MODE_DIRECTORY);
711
712 if(!dir) {
713 mapping->end = mapping->begin;
de167e41 714 return -1;
a046433a 715 }
3b46e624 716
a046433a
FB
717 i = mapping->info.dir.first_dir_index =
718 first_cluster == 0 ? 0 : s->directory.next;
719
5fafdf24 720 /* actually read the directory, and allocate the mappings */
de167e41
FB
721 while((entry=readdir(dir))) {
722 unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
723 char* buffer;
c227f099 724 direntry_t* direntry;
a046433a 725 struct stat st;
de167e41
FB
726 int is_dot=!strcmp(entry->d_name,".");
727 int is_dotdot=!strcmp(entry->d_name,"..");
728
a046433a 729 if(first_cluster == 0 && (is_dotdot || is_dot))
de167e41 730 continue;
5fafdf24 731
d4df3dbc 732 buffer = g_malloc(length);
de167e41
FB
733 snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
734
735 if(stat(buffer,&st)<0) {
ce137829 736 g_free(buffer);
de167e41
FB
737 continue;
738 }
739
740 /* create directory entry for this file */
a046433a
FB
741 direntry=create_short_and_long_name(s, i, entry->d_name,
742 is_dot || is_dotdot);
de167e41
FB
743 direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
744 direntry->reserved[0]=direntry->reserved[1]=0;
745 direntry->ctime=fat_datetime(st.st_ctime,1);
746 direntry->cdate=fat_datetime(st.st_ctime,0);
747 direntry->adate=fat_datetime(st.st_atime,0);
748 direntry->begin_hi=0;
749 direntry->mtime=fat_datetime(st.st_mtime,1);
750 direntry->mdate=fat_datetime(st.st_mtime,0);
751 if(is_dotdot)
a046433a 752 set_begin_of_direntry(direntry, first_cluster_of_parent);
de167e41 753 else if(is_dot)
a046433a 754 set_begin_of_direntry(direntry, first_cluster);
de167e41 755 else
a046433a
FB
756 direntry->begin=0; /* do that later */
757 if (st.st_size > 0x7fffffff) {
758 fprintf(stderr, "File %s is larger than 2GB\n", buffer);
ce137829 759 g_free(buffer);
08089edc 760 closedir(dir);
a046433a
FB
761 return -2;
762 }
763 direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
de167e41
FB
764
765 /* create mapping for this file */
a046433a 766 if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
d4df3dbc 767 s->current_mapping = array_get_next(&(s->mapping));
de167e41
FB
768 s->current_mapping->begin=0;
769 s->current_mapping->end=st.st_size;
a046433a
FB
770 /*
771 * we get the direntry of the most recent direntry, which
772 * contains the short name and all the relevant information.
773 */
de167e41 774 s->current_mapping->dir_index=s->directory.next-1;
a046433a
FB
775 s->current_mapping->first_mapping_index = -1;
776 if (S_ISDIR(st.st_mode)) {
777 s->current_mapping->mode = MODE_DIRECTORY;
778 s->current_mapping->info.dir.parent_mapping_index =
779 mapping_index;
780 } else {
781 s->current_mapping->mode = MODE_UNDEFINED;
782 s->current_mapping->info.file.offset = 0;
783 }
784 s->current_mapping->path=buffer;
785 s->current_mapping->read_only =
786 (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
b122c3b6
MA
787 } else {
788 g_free(buffer);
789 }
de167e41
FB
790 }
791 closedir(dir);
792
793 /* fill with zeroes up to the end of the cluster */
794 while(s->directory.next%(0x10*s->sectors_per_cluster)) {
c227f099
AL
795 direntry_t* direntry=array_get_next(&(s->directory));
796 memset(direntry,0,sizeof(direntry_t));
de167e41
FB
797 }
798
a046433a
FB
799/* TODO: if there are more entries, bootsector has to be adjusted! */
800#define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
801 if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
802 /* root directory */
803 int cur = s->directory.next;
804 array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
2b6a43a8 805 s->directory.next = ROOT_ENTRIES;
a046433a 806 memset(array_get(&(s->directory), cur), 0,
c227f099 807 (ROOT_ENTRIES - cur) * sizeof(direntry_t));
de167e41 808 }
5fafdf24 809
a046433a 810 /* reget the mapping, since s->mapping was possibly realloc()ed */
d4df3dbc 811 mapping = array_get(&(s->mapping), mapping_index);
a046433a
FB
812 first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
813 * 0x20 / s->cluster_size;
814 mapping->end = first_cluster;
815
d4df3dbc 816 direntry = array_get(&(s->directory), mapping->dir_index);
a046433a 817 set_begin_of_direntry(direntry, mapping->begin);
3b46e624 818
a046433a
FB
819 return 0;
820}
de167e41 821
a046433a
FB
822static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
823{
824 return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
825}
de167e41 826
a046433a
FB
827static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
828{
829 return s->faked_sectors + s->sectors_per_cluster * cluster_num;
830}
de167e41 831
a046433a 832static int init_directories(BDRVVVFATState* s,
d11c8917
MA
833 const char *dirname, int heads, int secs,
834 Error **errp)
de167e41 835{
c227f099
AL
836 bootsector_t* bootsector;
837 mapping_t* mapping;
de167e41
FB
838 unsigned int i;
839 unsigned int cluster;
840
841 memset(&(s->first_sectors[0]),0,0x40*0x200);
842
de167e41 843 s->cluster_size=s->sectors_per_cluster*0x200;
7267c094 844 s->cluster_buffer=g_malloc(s->cluster_size);
a046433a
FB
845
846 /*
847 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
848 * where sc is sector_count,
849 * spf is sectors_per_fat,
850 * spc is sectors_per_clusters, and
851 * fat_type = 12, 16 or 32.
852 */
853 i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
854 s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
3b46e624 855
c227f099
AL
856 array_init(&(s->mapping),sizeof(mapping_t));
857 array_init(&(s->directory),sizeof(direntry_t));
de167e41
FB
858
859 /* add volume label */
860 {
c227f099 861 direntry_t* entry=array_get_next(&(s->directory));
de167e41 862 entry->attributes=0x28; /* archive | volume label */
d5941dda 863 memcpy(entry->name, s->volume_label, sizeof(entry->name));
de167e41
FB
864 }
865
de167e41
FB
866 /* Now build FAT, and write back information into directory */
867 init_fat(s);
868
a046433a
FB
869 s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
870 s->cluster_count=sector2cluster(s, s->sector_count);
871
872 mapping = array_get_next(&(s->mapping));
873 mapping->begin = 0;
874 mapping->dir_index = 0;
875 mapping->info.dir.parent_mapping_index = -1;
876 mapping->first_mapping_index = -1;
7267c094 877 mapping->path = g_strdup(dirname);
a046433a
FB
878 i = strlen(mapping->path);
879 if (i > 0 && mapping->path[i - 1] == '/')
880 mapping->path[i - 1] = '\0';
881 mapping->mode = MODE_DIRECTORY;
882 mapping->read_only = 0;
883 s->path = mapping->path;
884
885 for (i = 0, cluster = 0; i < s->mapping.next; i++) {
5fafdf24 886 /* MS-DOS expects the FAT to be 0 for the root directory
a046433a
FB
887 * (except for the media byte). */
888 /* LATER TODO: still true for FAT32? */
889 int fix_fat = (i != 0);
890 mapping = array_get(&(s->mapping), i);
891
892 if (mapping->mode & MODE_DIRECTORY) {
893 mapping->begin = cluster;
894 if(read_directory(s, i)) {
d11c8917
MA
895 error_setg(errp, "Could not read directory %s",
896 mapping->path);
de167e41
FB
897 return -1;
898 }
a046433a
FB
899 mapping = array_get(&(s->mapping), i);
900 } else {
901 assert(mapping->mode == MODE_UNDEFINED);
de167e41 902 mapping->mode=MODE_NORMAL;
a046433a
FB
903 mapping->begin = cluster;
904 if (mapping->end > 0) {
c227f099 905 direntry_t* direntry = array_get(&(s->directory),
a046433a
FB
906 mapping->dir_index);
907
908 mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
909 set_begin_of_direntry(direntry, mapping->begin);
910 } else {
911 mapping->end = cluster + 1;
912 fix_fat = 0;
de167e41 913 }
a046433a
FB
914 }
915
916 assert(mapping->begin < mapping->end);
917
8ce0f869
AZ
918 /* next free cluster */
919 cluster = mapping->end;
920
921 if(cluster > s->cluster_count) {
d11c8917
MA
922 error_setg(errp,
923 "Directory does not fit in FAT%d (capacity %.2f MB)",
924 s->fat_type, s->sector_count / 2000.0);
925 return -1;
8ce0f869
AZ
926 }
927
a046433a
FB
928 /* fix fat for entry */
929 if (fix_fat) {
8ce0f869 930 int j;
a046433a
FB
931 for(j = mapping->begin; j < mapping->end - 1; j++)
932 fat_set(s, j, j+1);
933 fat_set(s, mapping->end - 1, s->max_fat_value);
934 }
de167e41
FB
935 }
936
a046433a
FB
937 mapping = array_get(&(s->mapping), 0);
938 s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
939 s->last_cluster_of_root_directory = mapping->end;
940
941 /* the FAT signature */
942 fat_set(s,0,s->max_fat_value);
943 fat_set(s,1,s->max_fat_value);
de167e41 944
a046433a
FB
945 s->current_mapping = NULL;
946
c227f099 947 bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
de167e41
FB
948 bootsector->jump[0]=0xeb;
949 bootsector->jump[1]=0x3e;
950 bootsector->jump[2]=0x90;
951 memcpy(bootsector->name,"QEMU ",8);
952 bootsector->sector_size=cpu_to_le16(0x200);
953 bootsector->sectors_per_cluster=s->sectors_per_cluster;
954 bootsector->reserved_sectors=cpu_to_le16(1);
955 bootsector->number_of_fats=0x2; /* number of FATs */
956 bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
a046433a 957 bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
aad37c06 958 bootsector->media_type=(s->first_sectors_number>1?0xf8:0xf0); /* media descriptor (f8=hd, f0=3.5 fd)*/
a046433a 959 s->fat.pointer[0] = bootsector->media_type;
de167e41 960 bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
4480e0f9
MA
961 bootsector->sectors_per_track = cpu_to_le16(secs);
962 bootsector->number_of_heads = cpu_to_le16(heads);
de167e41 963 bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
a046433a 964 bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
de167e41 965
a046433a 966 /* LATER TODO: if FAT32, this is wrong */
aad37c06 967 bootsector->u.fat16.drive_number=s->first_sectors_number==1?0:0x80; /* fda=0, hda=0x80 */
de167e41
FB
968 bootsector->u.fat16.current_head=0;
969 bootsector->u.fat16.signature=0x29;
970 bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
971
d5941dda
WB
972 memcpy(bootsector->u.fat16.volume_label, s->volume_label,
973 sizeof(bootsector->u.fat16.volume_label));
de167e41
FB
974 memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12 ":s->fat_type==16?"FAT16 ":"FAT32 "),8);
975 bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
976
977 return 0;
978}
979
83f64091 980#ifdef DEBUG
a046433a 981static BDRVVVFATState *vvv = NULL;
83f64091 982#endif
a046433a 983
68c70af1 984static int enable_write_target(BDRVVVFATState *s, Error **errp);
a046433a
FB
985static int is_consistent(BDRVVVFATState *s);
986
7ad9be64
KW
987static QemuOptsList runtime_opts = {
988 .name = "vvfat",
989 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
990 .desc = {
991 {
992 .name = "dir",
993 .type = QEMU_OPT_STRING,
994 .help = "Host directory to map to the vvfat device",
995 },
996 {
997 .name = "fat-type",
998 .type = QEMU_OPT_NUMBER,
999 .help = "FAT type (12, 16 or 32)",
1000 },
1001 {
1002 .name = "floppy",
1003 .type = QEMU_OPT_BOOL,
1004 .help = "Create a floppy rather than a hard disk image",
1005 },
d5941dda
WB
1006 {
1007 .name = "label",
1008 .type = QEMU_OPT_STRING,
1009 .help = "Use a volume label other than QEMU VVFAT",
1010 },
7ad9be64
KW
1011 {
1012 .name = "rw",
1013 .type = QEMU_OPT_BOOL,
1014 .help = "Make the image writable",
1015 },
1016 { /* end of list */ }
1017 },
1018};
1019
1020static void vvfat_parse_filename(const char *filename, QDict *options,
1021 Error **errp)
1022{
1023 int fat_type = 0;
1024 bool floppy = false;
1025 bool rw = false;
1026 int i;
1027
1028 if (!strstart(filename, "fat:", NULL)) {
1029 error_setg(errp, "File name string must start with 'fat:'");
1030 return;
1031 }
1032
1033 /* Parse options */
1034 if (strstr(filename, ":32:")) {
1035 fat_type = 32;
1036 } else if (strstr(filename, ":16:")) {
1037 fat_type = 16;
1038 } else if (strstr(filename, ":12:")) {
1039 fat_type = 12;
1040 }
1041
1042 if (strstr(filename, ":floppy:")) {
1043 floppy = true;
1044 }
1045
1046 if (strstr(filename, ":rw:")) {
1047 rw = true;
1048 }
1049
1050 /* Get the directory name without options */
1051 i = strrchr(filename, ':') - filename;
1052 assert(i >= 3);
1053 if (filename[i - 2] == ':' && qemu_isalpha(filename[i - 1])) {
1054 /* workaround for DOS drive names */
1055 filename += i - 1;
1056 } else {
1057 filename += i + 1;
1058 }
1059
1060 /* Fill in the options QDict */
1061 qdict_put(options, "dir", qstring_from_str(filename));
1062 qdict_put(options, "fat-type", qint_from_int(fat_type));
fc48ffc3
EB
1063 qdict_put(options, "floppy", qbool_from_bool(floppy));
1064 qdict_put(options, "rw", qbool_from_bool(rw));
7ad9be64
KW
1065}
1066
015a1036
HR
1067static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
1068 Error **errp)
de167e41
FB
1069{
1070 BDRVVVFATState *s = bs->opaque;
7ad9be64
KW
1071 int cyls, heads, secs;
1072 bool floppy;
d5941dda 1073 const char *dirname, *label;
7ad9be64
KW
1074 QemuOpts *opts;
1075 Error *local_err = NULL;
1076 int ret;
de167e41 1077
83f64091 1078#ifdef DEBUG
a046433a 1079 vvv = s;
83f64091 1080#endif
a046433a 1081
87ea75d5 1082 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
7ad9be64 1083 qemu_opts_absorb_qdict(opts, options, &local_err);
84d18f06 1084 if (local_err) {
c0f92b52 1085 error_propagate(errp, local_err);
7ad9be64
KW
1086 ret = -EINVAL;
1087 goto fail;
1088 }
1089
1090 dirname = qemu_opt_get(opts, "dir");
1091 if (!dirname) {
c0f92b52 1092 error_setg(errp, "vvfat block driver requires a 'dir' option");
7ad9be64
KW
1093 ret = -EINVAL;
1094 goto fail;
1095 }
1096
1097 s->fat_type = qemu_opt_get_number(opts, "fat-type", 0);
1098 floppy = qemu_opt_get_bool(opts, "floppy", false);
1099
d5941dda
WB
1100 memset(s->volume_label, ' ', sizeof(s->volume_label));
1101 label = qemu_opt_get(opts, "label");
1102 if (label) {
1103 size_t label_length = strlen(label);
1104 if (label_length > 11) {
1105 error_setg(errp, "vvfat label cannot be longer than 11 bytes");
1106 ret = -EINVAL;
1107 goto fail;
1108 }
1109 memcpy(s->volume_label, label, label_length);
d208c50d
KW
1110 } else {
1111 memcpy(s->volume_label, "QEMU VVFAT", 10);
d5941dda
WB
1112 }
1113
7ad9be64
KW
1114 if (floppy) {
1115 /* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */
1116 if (!s->fat_type) {
1117 s->fat_type = 12;
1118 secs = 36;
1119 s->sectors_per_cluster = 2;
1120 } else {
1121 secs = s->fat_type == 12 ? 18 : 36;
1122 s->sectors_per_cluster = 1;
1123 }
1124 s->first_sectors_number = 1;
1125 cyls = 80;
1126 heads = 2;
1127 } else {
1128 /* 32MB or 504MB disk*/
1129 if (!s->fat_type) {
1130 s->fat_type = 16;
1131 }
4c709660 1132 s->first_sectors_number = 0x40;
7ad9be64
KW
1133 cyls = s->fat_type == 12 ? 64 : 1024;
1134 heads = 16;
1135 secs = 63;
1136 }
1137
1138 switch (s->fat_type) {
1139 case 32:
1140 fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. "
1141 "You are welcome to do so!\n");
1142 break;
1143 case 16:
1144 case 12:
1145 break;
1146 default:
c0f92b52 1147 error_setg(errp, "Valid FAT types are only 12, 16 and 32");
7ad9be64
KW
1148 ret = -EINVAL;
1149 goto fail;
1150 }
1151
1152
a046433a
FB
1153 s->bs = bs;
1154
a046433a 1155 /* LATER TODO: if FAT32, adjust */
a046433a 1156 s->sectors_per_cluster=0x10;
de167e41
FB
1157
1158 s->current_cluster=0xffffffff;
de167e41 1159
a046433a
FB
1160 /* read only is the default for safety */
1161 bs->read_only = 1;
1162 s->qcow = s->write_target = NULL;
1163 s->qcow_filename = NULL;
1164 s->fat2 = NULL;
1165 s->downcase_short_names = 1;
3b46e624 1166
4480e0f9
MA
1167 fprintf(stderr, "vvfat %s chs %d,%d,%d\n",
1168 dirname, cyls, heads, secs);
a046433a 1169
4480e0f9 1170 s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
5a742b55 1171
7ad9be64 1172 if (qemu_opt_get_bool(opts, "rw", false)) {
68c70af1 1173 ret = enable_write_target(s, errp);
78f27bd0 1174 if (ret < 0) {
7ad9be64
KW
1175 goto fail;
1176 }
1177 bs->read_only = 0;
b570094d
TS
1178 }
1179
4480e0f9 1180 bs->total_sectors = cyls * heads * secs;
b570094d 1181
d11c8917 1182 if (init_directories(s, dirname, heads, secs, errp)) {
7ad9be64
KW
1183 ret = -EIO;
1184 goto fail;
4480e0f9 1185 }
de167e41 1186
b570094d
TS
1187 s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
1188
4480e0f9
MA
1189 if (s->first_sectors_number == 0x40) {
1190 init_mbr(s, cyls, heads, secs);
273e4e03 1191 }
a046433a
FB
1192
1193 // assert(is_consistent(s));
848c66e8 1194 qemu_co_mutex_init(&s->lock);
3397f0cb
KW
1195
1196 /* Disable migration when vvfat is used rw */
1197 if (s->qcow) {
81e5f78a
AG
1198 error_setg(&s->migration_blocker,
1199 "The vvfat (rw) format used by node '%s' "
1200 "does not support live migration",
1201 bdrv_get_device_or_node_name(bs));
3397f0cb
KW
1202 migrate_add_blocker(s->migration_blocker);
1203 }
1204
7ad9be64
KW
1205 ret = 0;
1206fail:
1207 qemu_opts_del(opts);
1208 return ret;
de167e41
FB
1209}
1210
a6506481
EB
1211static void vvfat_refresh_limits(BlockDriverState *bs, Error **errp)
1212{
1213 bs->request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O supported */
1214}
1215
de167e41
FB
1216static inline void vvfat_close_current_file(BDRVVVFATState *s)
1217{
1218 if(s->current_mapping) {
a046433a
FB
1219 s->current_mapping = NULL;
1220 if (s->current_fd) {
2e1e79da 1221 qemu_close(s->current_fd);
a046433a
FB
1222 s->current_fd = 0;
1223 }
de167e41 1224 }
a046433a 1225 s->current_cluster = -1;
de167e41
FB
1226}
1227
1228/* mappings between index1 and index2-1 are supposed to be ordered
1229 * return value is the index of the last mapping for which end>cluster_num
1230 */
1231static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1232{
de167e41 1233 while(1) {
88bf7950 1234 int index3;
c227f099 1235 mapping_t* mapping;
de167e41
FB
1236 index3=(index1+index2)/2;
1237 mapping=array_get(&(s->mapping),index3);
a046433a
FB
1238 assert(mapping->begin < mapping->end);
1239 if(mapping->begin>=cluster_num) {
de167e41
FB
1240 assert(index2!=index3 || index2==0);
1241 if(index2==index3)
a046433a 1242 return index1;
de167e41
FB
1243 index2=index3;
1244 } else {
1245 if(index1==index3)
a046433a 1246 return mapping->end<=cluster_num ? index2 : index1;
de167e41
FB
1247 index1=index3;
1248 }
1249 assert(index1<=index2);
a046433a
FB
1250 DLOG(mapping=array_get(&(s->mapping),index1);
1251 assert(mapping->begin<=cluster_num);
5fafdf24 1252 assert(index2 >= s->mapping.next ||
a046433a
FB
1253 ((mapping = array_get(&(s->mapping),index2)) &&
1254 mapping->end>cluster_num)));
de167e41
FB
1255 }
1256}
1257
c227f099 1258static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
de167e41
FB
1259{
1260 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
c227f099 1261 mapping_t* mapping;
de167e41 1262 if(index>=s->mapping.next)
511d2b14 1263 return NULL;
de167e41
FB
1264 mapping=array_get(&(s->mapping),index);
1265 if(mapping->begin>cluster_num)
511d2b14 1266 return NULL;
a046433a 1267 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
de167e41
FB
1268 return mapping;
1269}
1270
c227f099 1271static int open_file(BDRVVVFATState* s,mapping_t* mapping)
de167e41
FB
1272{
1273 if(!mapping)
1274 return -1;
de167e41 1275 if(!s->current_mapping ||
a046433a 1276 strcmp(s->current_mapping->path,mapping->path)) {
de167e41 1277 /* open file */
6165f4d8 1278 int fd = qemu_open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
de167e41
FB
1279 if(fd<0)
1280 return -1;
1281 vvfat_close_current_file(s);
1282 s->current_fd = fd;
de167e41
FB
1283 s->current_mapping = mapping;
1284 }
1285 return 0;
1286}
1287
1288static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1289{
1290 if(s->current_cluster != cluster_num) {
1291 int result=0;
1292 off_t offset;
a046433a 1293 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
de167e41
FB
1294 if(!s->current_mapping
1295 || s->current_mapping->begin>cluster_num
1296 || s->current_mapping->end<=cluster_num) {
1297 /* binary search of mappings for file */
c227f099 1298 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
a046433a
FB
1299
1300 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1301
1302 if (mapping && mapping->mode & MODE_DIRECTORY) {
1303 vvfat_close_current_file(s);
1304 s->current_mapping = mapping;
1305read_cluster_directory:
1306 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
ffe8ab83 1307 s->cluster = (unsigned char*)s->directory.pointer+offset
a046433a
FB
1308 + 0x20*s->current_mapping->info.dir.first_dir_index;
1309 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1310 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1311 s->current_cluster = cluster_num;
1312 return 0;
1313 }
1314
1315 if(open_file(s,mapping))
de167e41 1316 return -2;
a046433a
FB
1317 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1318 goto read_cluster_directory;
de167e41 1319
a046433a
FB
1320 assert(s->current_fd);
1321
1322 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
de167e41
FB
1323 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1324 return -3;
a046433a 1325 s->cluster=s->cluster_buffer;
de167e41
FB
1326 result=read(s->current_fd,s->cluster,s->cluster_size);
1327 if(result<0) {
1328 s->current_cluster = -1;
1329 return -1;
1330 }
1331 s->current_cluster = cluster_num;
1332 }
1333 return 0;
1334}
1335
a046433a 1336#ifdef DEBUG
c227f099 1337static void print_direntry(const direntry_t* direntry)
de167e41 1338{
a046433a
FB
1339 int j = 0;
1340 char buffer[1024];
1341
3e89cb04 1342 fprintf(stderr, "direntry %p: ", direntry);
de167e41
FB
1343 if(!direntry)
1344 return;
a046433a 1345 if(is_long_name(direntry)) {
de167e41
FB
1346 unsigned char* c=(unsigned char*)direntry;
1347 int i;
1348 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
3891b370 1349#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
a046433a 1350 ADD_CHAR(c[i]);
de167e41 1351 for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
a046433a 1352 ADD_CHAR(c[i]);
de167e41 1353 for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
a046433a
FB
1354 ADD_CHAR(c[i]);
1355 buffer[j] = 0;
1356 fprintf(stderr, "%s\n", buffer);
de167e41
FB
1357 } else {
1358 int i;
1359 for(i=0;i<11;i++)
a046433a
FB
1360 ADD_CHAR(direntry->name[i]);
1361 buffer[j] = 0;
1362 fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1363 buffer,
de167e41 1364 direntry->attributes,
a046433a 1365 begin_of_direntry(direntry),le32_to_cpu(direntry->size));
de167e41
FB
1366 }
1367}
1368
c227f099 1369static void print_mapping(const mapping_t* mapping)
de167e41 1370{
3e89cb04
KW
1371 fprintf(stderr, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1372 "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1373 mapping, mapping->begin, mapping->end, mapping->dir_index,
1374 mapping->first_mapping_index, mapping->path, mapping->mode);
1375
a046433a
FB
1376 if (mapping->mode & MODE_DIRECTORY)
1377 fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1378 else
1379 fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
de167e41 1380}
a046433a 1381#endif
de167e41 1382
5fafdf24 1383static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
a046433a 1384 uint8_t *buf, int nb_sectors)
de167e41 1385{
a046433a 1386 BDRVVVFATState *s = bs->opaque;
de167e41 1387 int i;
de167e41 1388
a046433a 1389 for(i=0;i<nb_sectors;i++,sector_num++) {
e654bfe4 1390 if (sector_num >= bs->total_sectors)
a046433a
FB
1391 return -1;
1392 if (s->qcow) {
1393 int n;
7704df98 1394 if (bdrv_is_allocated(s->qcow, sector_num, nb_sectors-i, &n)) {
a046433a 1395DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
7704df98
KW
1396 if (bdrv_read(s->qcow, sector_num, buf + i*0x200, n)) {
1397 return -1;
1398 }
1399 i += n - 1;
1400 sector_num += n - 1;
1401 continue;
1402 }
a046433a 1403DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
de167e41 1404 }
a046433a
FB
1405 if(sector_num<s->faked_sectors) {
1406 if(sector_num<s->first_sectors_number)
1407 memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
1408 else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
1409 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
1410 else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
1411 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
1412 } else {
1413 uint32_t sector=sector_num-s->faked_sectors,
1414 sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1415 cluster_num=sector/s->sectors_per_cluster;
e654bfe4 1416 if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) {
a046433a
FB
1417 /* LATER TODO: strict: return -1; */
1418 memset(buf+i*0x200,0,0x200);
1419 continue;
de167e41 1420 }
a046433a 1421 memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
de167e41
FB
1422 }
1423 }
de167e41
FB
1424 return 0;
1425}
1426
4575eb49
KW
1427static int coroutine_fn
1428vvfat_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
1429 QEMUIOVector *qiov, int flags)
2914caa0
PB
1430{
1431 int ret;
1432 BDRVVVFATState *s = bs->opaque;
4575eb49
KW
1433 uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
1434 int nb_sectors = bytes >> BDRV_SECTOR_BITS;
1435 void *buf;
1436
1437 assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
1438 assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
1439
1440 buf = g_try_malloc(bytes);
1441 if (bytes && buf == NULL) {
1442 return -ENOMEM;
1443 }
1444
2914caa0
PB
1445 qemu_co_mutex_lock(&s->lock);
1446 ret = vvfat_read(bs, sector_num, buf, nb_sectors);
1447 qemu_co_mutex_unlock(&s->lock);
4575eb49
KW
1448
1449 qemu_iovec_from_buf(qiov, 0, buf, bytes);
1450 g_free(buf);
1451
2914caa0
PB
1452 return ret;
1453}
1454
a046433a 1455/* LATER TODO: statify all functions */
de167e41 1456
a046433a
FB
1457/*
1458 * Idea of the write support (use snapshot):
de167e41 1459 *
a046433a
FB
1460 * 1. check if all data is consistent, recording renames, modifications,
1461 * new files and directories (in s->commits).
de167e41 1462 *
a046433a 1463 * 2. if the data is not consistent, stop committing
de167e41 1464 *
a046433a
FB
1465 * 3. handle renames, and create new files and directories (do not yet
1466 * write their contents)
de167e41 1467 *
a046433a
FB
1468 * 4. walk the directories, fixing the mapping and direntries, and marking
1469 * the handled mappings as not deleted
de167e41 1470 *
a046433a 1471 * 5. commit the contents of the files
de167e41 1472 *
a046433a 1473 * 6. handle deleted files and directories
de167e41
FB
1474 *
1475 */
1476
c227f099 1477typedef struct commit_t {
a046433a
FB
1478 char* path;
1479 union {
1480 struct { uint32_t cluster; } rename;
1481 struct { int dir_index; uint32_t modified_offset; } writeout;
1482 struct { uint32_t first_cluster; } new_file;
1483 struct { uint32_t cluster; } mkdir;
1484 } param;
1485 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1486 enum {
1487 ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1488 } action;
c227f099 1489} commit_t;
de167e41 1490
a046433a 1491static void clear_commits(BDRVVVFATState* s)
de167e41
FB
1492{
1493 int i;
a046433a
FB
1494DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1495 for (i = 0; i < s->commits.next; i++) {
c227f099 1496 commit_t* commit = array_get(&(s->commits), i);
a046433a
FB
1497 assert(commit->path || commit->action == ACTION_WRITEOUT);
1498 if (commit->action != ACTION_WRITEOUT) {
1499 assert(commit->path);
ce137829 1500 g_free(commit->path);
a046433a
FB
1501 } else
1502 assert(commit->path == NULL);
de167e41 1503 }
a046433a 1504 s->commits.next = 0;
de167e41
FB
1505}
1506
a046433a
FB
1507static void schedule_rename(BDRVVVFATState* s,
1508 uint32_t cluster, char* new_path)
de167e41 1509{
c227f099 1510 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1511 commit->path = new_path;
1512 commit->param.rename.cluster = cluster;
1513 commit->action = ACTION_RENAME;
de167e41
FB
1514}
1515
a046433a
FB
1516static void schedule_writeout(BDRVVVFATState* s,
1517 int dir_index, uint32_t modified_offset)
de167e41 1518{
c227f099 1519 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1520 commit->path = NULL;
1521 commit->param.writeout.dir_index = dir_index;
1522 commit->param.writeout.modified_offset = modified_offset;
1523 commit->action = ACTION_WRITEOUT;
de167e41
FB
1524}
1525
a046433a
FB
1526static void schedule_new_file(BDRVVVFATState* s,
1527 char* path, uint32_t first_cluster)
de167e41 1528{
c227f099 1529 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1530 commit->path = path;
1531 commit->param.new_file.first_cluster = first_cluster;
1532 commit->action = ACTION_NEW_FILE;
1533}
1534
1535static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1536{
c227f099 1537 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1538 commit->path = path;
1539 commit->param.mkdir.cluster = cluster;
1540 commit->action = ACTION_MKDIR;
1541}
1542
1543typedef struct {
64eaabda
TS
1544 /*
1545 * Since the sequence number is at most 0x3f, and the filename
1546 * length is at most 13 times the sequence number, the maximal
1547 * filename length is 0x3f * 13 bytes.
1548 */
1549 unsigned char name[0x3f * 13 + 1];
a046433a
FB
1550 int checksum, len;
1551 int sequence_number;
1552} long_file_name;
1553
1554static void lfn_init(long_file_name* lfn)
1555{
1556 lfn->sequence_number = lfn->len = 0;
1557 lfn->checksum = 0x100;
1558}
1559
1560/* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1561static int parse_long_name(long_file_name* lfn,
c227f099 1562 const direntry_t* direntry)
a046433a
FB
1563{
1564 int i, j, offset;
1565 const unsigned char* pointer = (const unsigned char*)direntry;
1566
1567 if (!is_long_name(direntry))
1568 return 1;
1569
1570 if (pointer[0] & 0x40) {
1571 lfn->sequence_number = pointer[0] & 0x3f;
1572 lfn->checksum = pointer[13];
1573 lfn->name[0] = 0;
59fdb018 1574 lfn->name[lfn->sequence_number * 13] = 0;
a046433a
FB
1575 } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
1576 return -1;
1577 else if (pointer[13] != lfn->checksum)
1578 return -2;
1579 else if (pointer[12] || pointer[26] || pointer[27])
1580 return -3;
1581
1582 offset = 13 * (lfn->sequence_number - 1);
1583 for (i = 0, j = 1; i < 13; i++, j+=2) {
1584 if (j == 11)
1585 j = 14;
1586 else if (j == 26)
1587 j = 28;
1588
1589 if (pointer[j+1] == 0)
1590 lfn->name[offset + i] = pointer[j];
1591 else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1592 return -4;
1593 else
1594 lfn->name[offset + i] = 0;
de167e41 1595 }
a046433a
FB
1596
1597 if (pointer[0] & 0x40)
ffe8ab83 1598 lfn->len = offset + strlen((char*)lfn->name + offset);
a046433a 1599
de167e41
FB
1600 return 0;
1601}
1602
a046433a
FB
1603/* returns 0 if successful, >0 if no short_name, and <0 on error */
1604static int parse_short_name(BDRVVVFATState* s,
c227f099 1605 long_file_name* lfn, direntry_t* direntry)
de167e41 1606{
a046433a 1607 int i, j;
de167e41 1608
a046433a
FB
1609 if (!is_short_name(direntry))
1610 return 1;
1611
1612 for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1613 for (i = 0; i <= j; i++) {
1614 if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
1615 return -1;
1616 else if (s->downcase_short_names)
47398b9c 1617 lfn->name[i] = qemu_tolower(direntry->name[i]);
a046433a
FB
1618 else
1619 lfn->name[i] = direntry->name[i];
de167e41
FB
1620 }
1621
f671d173
SW
1622 for (j = 2; j >= 0 && direntry->name[8 + j] == ' '; j--) {
1623 }
a046433a
FB
1624 if (j >= 0) {
1625 lfn->name[i++] = '.';
1626 lfn->name[i + j + 1] = '\0';
1627 for (;j >= 0; j--) {
f671d173
SW
1628 uint8_t c = direntry->name[8 + j];
1629 if (c <= ' ' || c > 0x7f) {
1630 return -2;
1631 } else if (s->downcase_short_names) {
1632 lfn->name[i + j] = qemu_tolower(c);
1633 } else {
1634 lfn->name[i + j] = c;
1635 }
a046433a
FB
1636 }
1637 } else
1638 lfn->name[i + j + 1] = '\0';
1639
ffe8ab83 1640 lfn->len = strlen((char*)lfn->name);
a046433a
FB
1641
1642 return 0;
de167e41
FB
1643}
1644
a046433a
FB
1645static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1646 unsigned int cluster)
de167e41 1647{
a046433a
FB
1648 if (cluster < s->last_cluster_of_root_directory) {
1649 if (cluster + 1 == s->last_cluster_of_root_directory)
1650 return s->max_fat_value;
1651 else
1652 return cluster + 1;
1653 }
1654
1655 if (s->fat_type==32) {
1656 uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1657 return le32_to_cpu(*entry);
1658 } else if (s->fat_type==16) {
1659 uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1660 return le16_to_cpu(*entry);
1661 } else {
1662 const uint8_t* x=s->fat2+cluster*3/2;
1663 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1664 }
1665}
1666
1667static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1668{
1669 int was_modified = 0;
1670 int i, dummy;
1671
1672 if (s->qcow == NULL)
de167e41 1673 return 0;
a046433a
FB
1674
1675 for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
7704df98 1676 was_modified = bdrv_is_allocated(s->qcow,
a046433a
FB
1677 cluster2sector(s, cluster_num) + i, 1, &dummy);
1678
1679 return was_modified;
de167e41
FB
1680}
1681
a046433a 1682static const char* get_basename(const char* path)
de167e41 1683{
a046433a
FB
1684 char* basename = strrchr(path, '/');
1685 if (basename == NULL)
1686 return path;
1687 else
1688 return basename + 1; /* strip '/' */
de167e41
FB
1689}
1690
a046433a
FB
1691/*
1692 * The array s->used_clusters holds the states of the clusters. If it is
1693 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1694 * was modified, bit 3 is set.
1695 * If any cluster is allocated, but not part of a file or directory, this
1696 * driver refuses to commit.
1697 */
1698typedef enum {
1699 USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
c227f099 1700} used_t;
de167e41 1701
a046433a
FB
1702/*
1703 * get_cluster_count_for_direntry() not only determines how many clusters
1704 * are occupied by direntry, but also if it was renamed or modified.
1705 *
1706 * A file is thought to be renamed *only* if there already was a file with
1707 * exactly the same first cluster, but a different name.
1708 *
1709 * Further, the files/directories handled by this function are
1710 * assumed to be *not* deleted (and *only* those).
1711 */
1712static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
c227f099 1713 direntry_t* direntry, const char* path)
de167e41 1714{
a046433a
FB
1715 /*
1716 * This is a little bit tricky:
1717 * IF the guest OS just inserts a cluster into the file chain,
1718 * and leaves the rest alone, (i.e. the original file had clusters
1719 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1720 *
1721 * - do_commit will write the cluster into the file at the given
1722 * offset, but
1723 *
1724 * - the cluster which is overwritten should be moved to a later
1725 * position in the file.
1726 *
1727 * I am not aware that any OS does something as braindead, but this
1728 * situation could happen anyway when not committing for a long time.
1729 * Just to be sure that this does not bite us, detect it, and copy the
1730 * contents of the clusters to-be-overwritten into the qcow.
1731 */
1732 int copy_it = 0;
1733 int was_modified = 0;
1734 int32_t ret = 0;
1735
1736 uint32_t cluster_num = begin_of_direntry(direntry);
1737 uint32_t offset = 0;
1738 int first_mapping_index = -1;
c227f099 1739 mapping_t* mapping = NULL;
a046433a 1740 const char* basename2 = NULL;
de167e41 1741
a046433a 1742 vvfat_close_current_file(s);
de167e41 1743
a046433a
FB
1744 /* the root directory */
1745 if (cluster_num == 0)
de167e41 1746 return 0;
de167e41 1747
a046433a
FB
1748 /* write support */
1749 if (s->qcow) {
1750 basename2 = get_basename(path);
de167e41 1751
a046433a
FB
1752 mapping = find_mapping_for_cluster(s, cluster_num);
1753
1754 if (mapping) {
da2414e9
FB
1755 const char* basename;
1756
a046433a
FB
1757 assert(mapping->mode & MODE_DELETED);
1758 mapping->mode &= ~MODE_DELETED;
1759
da2414e9 1760 basename = get_basename(mapping->path);
a046433a
FB
1761
1762 assert(mapping->mode & MODE_NORMAL);
1763
1764 /* rename */
1765 if (strcmp(basename, basename2))
7267c094 1766 schedule_rename(s, cluster_num, g_strdup(path));
a046433a
FB
1767 } else if (is_file(direntry))
1768 /* new file */
7267c094 1769 schedule_new_file(s, g_strdup(path), cluster_num);
a046433a 1770 else {
43dc2a64 1771 abort();
a046433a
FB
1772 return 0;
1773 }
de167e41
FB
1774 }
1775
a046433a
FB
1776 while(1) {
1777 if (s->qcow) {
1778 if (!copy_it && cluster_was_modified(s, cluster_num)) {
1779 if (mapping == NULL ||
1780 mapping->begin > cluster_num ||
1781 mapping->end <= cluster_num)
1782 mapping = find_mapping_for_cluster(s, cluster_num);
de167e41 1783
a046433a
FB
1784
1785 if (mapping &&
1786 (mapping->mode & MODE_DIRECTORY) == 0) {
1787
1788 /* was modified in qcow */
1789 if (offset != mapping->info.file.offset + s->cluster_size
1790 * (cluster_num - mapping->begin)) {
1791 /* offset of this cluster in file chain has changed */
43dc2a64 1792 abort();
a046433a
FB
1793 copy_it = 1;
1794 } else if (offset == 0) {
1795 const char* basename = get_basename(mapping->path);
1796
1797 if (strcmp(basename, basename2))
1798 copy_it = 1;
1799 first_mapping_index = array_index(&(s->mapping), mapping);
1800 }
1801
1802 if (mapping->first_mapping_index != first_mapping_index
1803 && mapping->info.file.offset > 0) {
43dc2a64 1804 abort();
a046433a
FB
1805 copy_it = 1;
1806 }
1807
1808 /* need to write out? */
1809 if (!was_modified && is_file(direntry)) {
1810 was_modified = 1;
1811 schedule_writeout(s, mapping->dir_index, offset);
1812 }
1813 }
1814 }
1815
1816 if (copy_it) {
1817 int i, dummy;
1818 /*
1819 * This is horribly inefficient, but that is okay, since
1820 * it is rarely executed, if at all.
1821 */
1822 int64_t offset = cluster2sector(s, cluster_num);
1823
1824 vvfat_close_current_file(s);
7704df98
KW
1825 for (i = 0; i < s->sectors_per_cluster; i++) {
1826 if (!bdrv_is_allocated(s->qcow, offset + i, 1, &dummy)) {
1827 if (vvfat_read(s->bs, offset, s->cluster_buffer, 1)) {
1828 return -1;
1829 }
1830 if (bdrv_write(s->qcow, offset, s->cluster_buffer, 1)) {
1831 return -2;
1832 }
1833 }
1834 }
a046433a
FB
1835 }
1836 }
1837
1838 ret++;
1839 if (s->used_clusters[cluster_num] & USED_ANY)
1840 return 0;
1841 s->used_clusters[cluster_num] = USED_FILE;
1842
1843 cluster_num = modified_fat_get(s, cluster_num);
1844
1845 if (fat_eof(s, cluster_num))
1846 return ret;
1847 else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
1848 return -1;
1849
1850 offset += s->cluster_size;
1851 }
de167e41
FB
1852}
1853
a046433a 1854/*
5fafdf24 1855 * This function looks at the modified data (qcow).
a046433a
FB
1856 * It returns 0 upon inconsistency or error, and the number of clusters
1857 * used by the directory, its subdirectories and their files.
1858 */
1859static int check_directory_consistency(BDRVVVFATState *s,
1860 int cluster_num, const char* path)
de167e41 1861{
a046433a 1862 int ret = 0;
7267c094 1863 unsigned char* cluster = g_malloc(s->cluster_size);
c227f099
AL
1864 direntry_t* direntries = (direntry_t*)cluster;
1865 mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
a046433a
FB
1866
1867 long_file_name lfn;
1868 int path_len = strlen(path);
0d460d6f 1869 char path2[PATH_MAX + 1];
a046433a
FB
1870
1871 assert(path_len < PATH_MAX); /* len was tested before! */
363a37d5 1872 pstrcpy(path2, sizeof(path2), path);
a046433a
FB
1873 path2[path_len] = '/';
1874 path2[path_len + 1] = '\0';
1875
1876 if (mapping) {
1877 const char* basename = get_basename(mapping->path);
1878 const char* basename2 = get_basename(path);
1879
1880 assert(mapping->mode & MODE_DIRECTORY);
1881
1882 assert(mapping->mode & MODE_DELETED);
1883 mapping->mode &= ~MODE_DELETED;
1884
1885 if (strcmp(basename, basename2))
7267c094 1886 schedule_rename(s, cluster_num, g_strdup(path));
a046433a
FB
1887 } else
1888 /* new directory */
7267c094 1889 schedule_mkdir(s, cluster_num, g_strdup(path));
3b46e624 1890
a046433a
FB
1891 lfn_init(&lfn);
1892 do {
de167e41 1893 int i;
a046433a
FB
1894 int subret = 0;
1895
1896 ret++;
1897
1898 if (s->used_clusters[cluster_num] & USED_ANY) {
1899 fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
6262bbd3 1900 goto fail;
a046433a
FB
1901 }
1902 s->used_clusters[cluster_num] = USED_DIRECTORY;
1903
1904DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
1905 subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
1906 s->sectors_per_cluster);
1907 if (subret) {
1908 fprintf(stderr, "Error fetching direntries\n");
1909 fail:
ce137829 1910 g_free(cluster);
a046433a
FB
1911 return 0;
1912 }
1913
1914 for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
3f4cb3d3 1915 int cluster_count = 0;
a046433a 1916
b2bedb21 1917DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i));
a046433a
FB
1918 if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
1919 is_free(direntries + i))
1920 continue;
1921
1922 subret = parse_long_name(&lfn, direntries + i);
1923 if (subret < 0) {
1924 fprintf(stderr, "Error in long name\n");
1925 goto fail;
de167e41 1926 }
a046433a
FB
1927 if (subret == 0 || is_free(direntries + i))
1928 continue;
1929
1930 if (fat_chksum(direntries+i) != lfn.checksum) {
1931 subret = parse_short_name(s, &lfn, direntries + i);
1932 if (subret < 0) {
1933 fprintf(stderr, "Error in short name (%d)\n", subret);
1934 goto fail;
1935 }
ffe8ab83
TS
1936 if (subret > 0 || !strcmp((char*)lfn.name, ".")
1937 || !strcmp((char*)lfn.name, ".."))
a046433a
FB
1938 continue;
1939 }
1940 lfn.checksum = 0x100; /* cannot use long name twice */
1941
1942 if (path_len + 1 + lfn.len >= PATH_MAX) {
1943 fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
1944 goto fail;
1945 }
363a37d5
BS
1946 pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
1947 (char*)lfn.name);
a046433a
FB
1948
1949 if (is_directory(direntries + i)) {
1950 if (begin_of_direntry(direntries + i) == 0) {
1951 DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
1952 goto fail;
1953 }
1954 cluster_count = check_directory_consistency(s,
1955 begin_of_direntry(direntries + i), path2);
1956 if (cluster_count == 0) {
1957 DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
1958 goto fail;
1959 }
1960 } else if (is_file(direntries + i)) {
1961 /* check file size with FAT */
1962 cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
1963 if (cluster_count !=
13385ae1 1964 DIV_ROUND_UP(le32_to_cpu(direntries[i].size), s->cluster_size)) {
a046433a
FB
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
e6641719
HR
3001 options = qdict_new();
3002 qdict_put(options, "driver", qstring_from_str("qcow"));
5b363937
HR
3003 s->qcow = bdrv_open(s->qcow_filename, NULL, options,
3004 BDRV_O_RDWR | BDRV_O_NO_FLUSH, errp);
3005 if (!s->qcow) {
3006 ret = -EINVAL;
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,
a6506481 3053 .bdrv_refresh_limits = vvfat_refresh_limits,
7ad9be64 3054 .bdrv_close = vvfat_close,
7ad9be64 3055
4575eb49
KW
3056 .bdrv_co_preadv = vvfat_co_preadv,
3057 .bdrv_co_pwritev = vvfat_co_pwritev,
b6b8a333 3058 .bdrv_co_get_block_status = vvfat_co_get_block_status,
de167e41
FB
3059};
3060
5efa9d5a
AL
3061static void bdrv_vvfat_init(void)
3062{
3063 bdrv_register(&bdrv_vvfat);
3064}
3065
3066block_init(bdrv_vvfat_init);
3067
a046433a 3068#ifdef DEBUG
3f47aa8c 3069static void checkpoint(void) {
c227f099 3070 assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
a046433a
FB
3071 check1(vvv);
3072 check2(vvv);
3073 assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
3074#if 0
c227f099 3075 if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
a046433a 3076 fprintf(stderr, "Nonono!\n");
c227f099
AL
3077 mapping_t* mapping;
3078 direntry_t* direntry;
a046433a
FB
3079 assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
3080 assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
3081 if (vvv->mapping.next<47)
3082 return;
3083 assert((mapping = array_get(&(vvv->mapping), 47)));
3084 assert(mapping->dir_index < vvv->directory.next);
3085 direntry = array_get(&(vvv->directory), mapping->dir_index);
3086 assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0);
3087#endif
a046433a
FB
3088}
3089#endif
This page took 1.05337 seconds and 4 git commands to generate.