tests/vm: avoid image presence check and removal
[qemu/ar7.git] / block / vvfat.c
blobf6c28805dda4a78e687a28c3a914d09cd4dfa8e4
1 /* vim:set shiftwidth=4 ts=4: */
2 /*
3 * QEMU Block driver for virtual VFAT (shadows a local directory)
5 * Copyright (c) 2004,2005 Johannes E. Schindelin
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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.
26 #include "qemu/osdep.h"
27 #include <dirent.h>
28 #include "qapi/error.h"
29 #include "block/block_int.h"
30 #include "block/qdict.h"
31 #include "qemu/module.h"
32 #include "qemu/option.h"
33 #include "qemu/bswap.h"
34 #include "migration/blocker.h"
35 #include "qapi/qmp/qdict.h"
36 #include "qapi/qmp/qstring.h"
37 #include "qemu/ctype.h"
38 #include "qemu/cutils.h"
39 #include "qemu/error-report.h"
41 #ifndef S_IWGRP
42 #define S_IWGRP 0
43 #endif
44 #ifndef S_IWOTH
45 #define S_IWOTH 0
46 #endif
48 /* TODO: add ":bootsector=blabla.img:" */
49 /* LATER TODO: add automatic boot sector generation from
50 BOOTEASY.ASM and Ranish Partition Manager
51 Note that DOS assumes the system files to be the first files in the
52 file system (test if the boot sector still relies on that fact)! */
53 /* MAYBE TODO: write block-visofs.c */
54 /* TODO: call try_commit() only after a timeout */
56 /* #define DEBUG */
58 #ifdef DEBUG
60 #define DLOG(a) a
62 static void checkpoint(void);
64 #else
66 #define DLOG(a)
68 #endif
70 /* bootsector OEM name. see related compatibility problems at:
71 * https://jdebp.eu/FGA/volume-boot-block-oem-name-field.html
72 * http://seasip.info/Misc/oemid.html
74 #define BOOTSECTOR_OEM_NAME "MSWIN4.1"
76 #define DIR_DELETED 0xe5
77 #define DIR_KANJI DIR_DELETED
78 #define DIR_KANJI_FAKE 0x05
79 #define DIR_FREE 0x00
81 /* dynamic array functions */
82 typedef struct array_t {
83 char* pointer;
84 unsigned int size,next,item_size;
85 } array_t;
87 static inline void array_init(array_t* array,unsigned int item_size)
89 array->pointer = NULL;
90 array->size=0;
91 array->next=0;
92 array->item_size=item_size;
95 static inline void array_free(array_t* array)
97 g_free(array->pointer);
98 array->size=array->next=0;
101 /* does not automatically grow */
102 static inline void* array_get(array_t* array,unsigned int index) {
103 assert(index < array->next);
104 assert(array->pointer);
105 return array->pointer + index * array->item_size;
108 static inline void array_ensure_allocated(array_t *array, int index)
110 if((index + 1) * array->item_size > array->size) {
111 int new_size = (index + 32) * array->item_size;
112 array->pointer = g_realloc(array->pointer, new_size);
113 assert(array->pointer);
114 memset(array->pointer + array->size, 0, new_size - array->size);
115 array->size = new_size;
116 array->next = index + 1;
120 static inline void* array_get_next(array_t* array) {
121 unsigned int next = array->next;
123 array_ensure_allocated(array, next);
124 array->next = next + 1;
125 return array_get(array, next);
128 static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
129 if((array->next+count)*array->item_size>array->size) {
130 int increment=count*array->item_size;
131 array->pointer=g_realloc(array->pointer,array->size+increment);
132 if(!array->pointer)
133 return NULL;
134 array->size+=increment;
136 memmove(array->pointer+(index+count)*array->item_size,
137 array->pointer+index*array->item_size,
138 (array->next-index)*array->item_size);
139 array->next+=count;
140 return array->pointer+index*array->item_size;
143 /* this performs a "roll", so that the element which was at index_from becomes
144 * index_to, but the order of all other elements is preserved. */
145 static inline int array_roll(array_t* array,int index_to,int index_from,int count)
147 char* buf;
148 char* from;
149 char* to;
150 int is;
152 if(!array ||
153 index_to<0 || index_to>=array->next ||
154 index_from<0 || index_from>=array->next)
155 return -1;
157 if(index_to==index_from)
158 return 0;
160 is=array->item_size;
161 from=array->pointer+index_from*is;
162 to=array->pointer+index_to*is;
163 buf=g_malloc(is*count);
164 memcpy(buf,from,is*count);
166 if(index_to<index_from)
167 memmove(to+is*count,to,from-to);
168 else
169 memmove(from,from+is*count,to-from);
171 memcpy(to,buf,is*count);
173 g_free(buf);
175 return 0;
178 static inline int array_remove_slice(array_t* array,int index, int count)
180 assert(index >=0);
181 assert(count > 0);
182 assert(index + count <= array->next);
183 if(array_roll(array,array->next-1,index,count))
184 return -1;
185 array->next -= count;
186 return 0;
189 static int array_remove(array_t* array,int index)
191 return array_remove_slice(array, index, 1);
194 /* return the index for a given member */
195 static int array_index(array_t* array, void* pointer)
197 size_t offset = (char*)pointer - array->pointer;
198 assert((offset % array->item_size) == 0);
199 assert(offset/array->item_size < array->next);
200 return offset/array->item_size;
203 /* These structures are used to fake a disk and the VFAT filesystem.
204 * For this reason we need to use QEMU_PACKED. */
206 typedef struct bootsector_t {
207 uint8_t jump[3];
208 uint8_t name[8];
209 uint16_t sector_size;
210 uint8_t sectors_per_cluster;
211 uint16_t reserved_sectors;
212 uint8_t number_of_fats;
213 uint16_t root_entries;
214 uint16_t total_sectors16;
215 uint8_t media_type;
216 uint16_t sectors_per_fat;
217 uint16_t sectors_per_track;
218 uint16_t number_of_heads;
219 uint32_t hidden_sectors;
220 uint32_t total_sectors;
221 union {
222 struct {
223 uint8_t drive_number;
224 uint8_t reserved1;
225 uint8_t signature;
226 uint32_t id;
227 uint8_t volume_label[11];
228 uint8_t fat_type[8];
229 uint8_t ignored[0x1c0];
230 } QEMU_PACKED fat16;
231 struct {
232 uint32_t sectors_per_fat;
233 uint16_t flags;
234 uint8_t major,minor;
235 uint32_t first_cluster_of_root_dir;
236 uint16_t info_sector;
237 uint16_t backup_boot_sector;
238 uint8_t reserved[12];
239 uint8_t drive_number;
240 uint8_t reserved1;
241 uint8_t signature;
242 uint32_t id;
243 uint8_t volume_label[11];
244 uint8_t fat_type[8];
245 uint8_t ignored[0x1a4];
246 } QEMU_PACKED fat32;
247 } u;
248 uint8_t magic[2];
249 } QEMU_PACKED bootsector_t;
251 typedef struct {
252 uint8_t head;
253 uint8_t sector;
254 uint8_t cylinder;
255 } mbr_chs_t;
257 typedef struct partition_t {
258 uint8_t attributes; /* 0x80 = bootable */
259 mbr_chs_t start_CHS;
260 uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
261 mbr_chs_t end_CHS;
262 uint32_t start_sector_long;
263 uint32_t length_sector_long;
264 } QEMU_PACKED partition_t;
266 typedef struct mbr_t {
267 uint8_t ignored[0x1b8];
268 uint32_t nt_id;
269 uint8_t ignored2[2];
270 partition_t partition[4];
271 uint8_t magic[2];
272 } QEMU_PACKED mbr_t;
274 typedef struct direntry_t {
275 uint8_t name[8 + 3];
276 uint8_t attributes;
277 uint8_t reserved[2];
278 uint16_t ctime;
279 uint16_t cdate;
280 uint16_t adate;
281 uint16_t begin_hi;
282 uint16_t mtime;
283 uint16_t mdate;
284 uint16_t begin;
285 uint32_t size;
286 } QEMU_PACKED direntry_t;
288 /* this structure are used to transparently access the files */
290 typedef struct mapping_t {
291 /* begin is the first cluster, end is the last+1 */
292 uint32_t begin,end;
293 /* as s->directory is growable, no pointer may be used here */
294 unsigned int dir_index;
295 /* the clusters of a file may be in any order; this points to the first */
296 int first_mapping_index;
297 union {
298 /* offset is
299 * - the offset in the file (in clusters) for a file, or
300 * - the next cluster of the directory for a directory
302 struct {
303 uint32_t offset;
304 } file;
305 struct {
306 int parent_mapping_index;
307 int first_dir_index;
308 } dir;
309 } info;
310 /* path contains the full path, i.e. it always starts with s->path */
311 char* path;
313 enum {
314 MODE_UNDEFINED = 0,
315 MODE_NORMAL = 1,
316 MODE_MODIFIED = 2,
317 MODE_DIRECTORY = 4,
318 MODE_DELETED = 8,
319 } mode;
320 int read_only;
321 } mapping_t;
323 #ifdef DEBUG
324 static void print_direntry(const struct direntry_t*);
325 static void print_mapping(const struct mapping_t* mapping);
326 #endif
328 /* here begins the real VVFAT driver */
330 typedef struct BDRVVVFATState {
331 CoMutex lock;
332 BlockDriverState* bs; /* pointer to parent */
333 unsigned char first_sectors[0x40*0x200];
335 int fat_type; /* 16 or 32 */
336 array_t fat,directory,mapping;
337 char volume_label[11];
339 uint32_t offset_to_bootsector; /* 0 for floppy, 0x3f for disk */
341 unsigned int cluster_size;
342 unsigned int sectors_per_cluster;
343 unsigned int sectors_per_fat;
344 uint32_t last_cluster_of_root_directory;
345 /* how many entries are available in root directory (0 for FAT32) */
346 uint16_t root_entries;
347 uint32_t sector_count; /* total number of sectors of the partition */
348 uint32_t cluster_count; /* total number of clusters of this partition */
349 uint32_t max_fat_value;
350 uint32_t offset_to_fat;
351 uint32_t offset_to_root_dir;
353 int current_fd;
354 mapping_t* current_mapping;
355 unsigned char* cluster; /* points to current cluster */
356 unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
357 unsigned int current_cluster;
359 /* write support */
360 char* qcow_filename;
361 BdrvChild* qcow;
362 void* fat2;
363 char* used_clusters;
364 array_t commits;
365 const char* path;
366 int downcase_short_names;
368 Error *migration_blocker;
369 } BDRVVVFATState;
371 /* take the sector position spos and convert it to Cylinder/Head/Sector position
372 * if the position is outside the specified geometry, fill maximum value for CHS
373 * and return 1 to signal overflow.
375 static int sector2CHS(mbr_chs_t *chs, int spos, int cyls, int heads, int secs)
377 int head,sector;
378 sector = spos % secs; spos /= secs;
379 head = spos % heads; spos /= heads;
380 if (spos >= cyls) {
381 /* Overflow,
382 it happens if 32bit sector positions are used, while CHS is only 24bit.
383 Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
384 chs->head = 0xFF;
385 chs->sector = 0xFF;
386 chs->cylinder = 0xFF;
387 return 1;
389 chs->head = (uint8_t)head;
390 chs->sector = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
391 chs->cylinder = (uint8_t)spos;
392 return 0;
395 static void init_mbr(BDRVVVFATState *s, int cyls, int heads, int secs)
397 /* TODO: if the files mbr.img and bootsect.img exist, use them */
398 mbr_t* real_mbr=(mbr_t*)s->first_sectors;
399 partition_t* partition = &(real_mbr->partition[0]);
400 int lba;
402 memset(s->first_sectors,0,512);
404 /* Win NT Disk Signature */
405 real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
407 partition->attributes=0x80; /* bootable */
409 /* LBA is used when partition is outside the CHS geometry */
410 lba = sector2CHS(&partition->start_CHS, s->offset_to_bootsector,
411 cyls, heads, secs);
412 lba |= sector2CHS(&partition->end_CHS, s->bs->total_sectors - 1,
413 cyls, heads, secs);
415 /*LBA partitions are identified only by start/length_sector_long not by CHS*/
416 partition->start_sector_long = cpu_to_le32(s->offset_to_bootsector);
417 partition->length_sector_long = cpu_to_le32(s->bs->total_sectors
418 - s->offset_to_bootsector);
420 /* FAT12/FAT16/FAT32 */
421 /* DOS uses different types when partition is LBA,
422 probably to prevent older versions from using CHS on them */
423 partition->fs_type = s->fat_type == 12 ? 0x1 :
424 s->fat_type == 16 ? (lba ? 0xe : 0x06) :
425 /*s->fat_type == 32*/ (lba ? 0xc : 0x0b);
427 real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
430 /* direntry functions */
432 static direntry_t *create_long_filename(BDRVVVFATState *s, const char *filename)
434 int number_of_entries, i;
435 glong length;
436 direntry_t *entry;
438 gunichar2 *longname = g_utf8_to_utf16(filename, -1, NULL, &length, NULL);
439 if (!longname) {
440 fprintf(stderr, "vvfat: invalid UTF-8 name: %s\n", filename);
441 return NULL;
444 number_of_entries = DIV_ROUND_UP(length * 2, 26);
446 for(i=0;i<number_of_entries;i++) {
447 entry=array_get_next(&(s->directory));
448 entry->attributes=0xf;
449 entry->reserved[0]=0;
450 entry->begin=0;
451 entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
453 for(i=0;i<26*number_of_entries;i++) {
454 int offset=(i%26);
455 if(offset<10) offset=1+offset;
456 else if(offset<22) offset=14+offset-10;
457 else offset=28+offset-22;
458 entry=array_get(&(s->directory),s->directory.next-1-(i/26));
459 if (i >= 2 * length + 2) {
460 entry->name[offset] = 0xff;
461 } else if (i % 2 == 0) {
462 entry->name[offset] = longname[i / 2] & 0xff;
463 } else {
464 entry->name[offset] = longname[i / 2] >> 8;
467 g_free(longname);
468 return array_get(&(s->directory),s->directory.next-number_of_entries);
471 static char is_free(const direntry_t* direntry)
473 return direntry->name[0] == DIR_DELETED || direntry->name[0] == DIR_FREE;
476 static char is_volume_label(const direntry_t* direntry)
478 return direntry->attributes == 0x28;
481 static char is_long_name(const direntry_t* direntry)
483 return direntry->attributes == 0xf;
486 static char is_short_name(const direntry_t* direntry)
488 return !is_volume_label(direntry) && !is_long_name(direntry)
489 && !is_free(direntry);
492 static char is_directory(const direntry_t* direntry)
494 return direntry->attributes & 0x10 && direntry->name[0] != DIR_DELETED;
497 static inline char is_dot(const direntry_t* direntry)
499 return is_short_name(direntry) && direntry->name[0] == '.';
502 static char is_file(const direntry_t* direntry)
504 return is_short_name(direntry) && !is_directory(direntry);
507 static inline uint32_t begin_of_direntry(const direntry_t* direntry)
509 return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
512 static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
514 return le32_to_cpu(direntry->size);
517 static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
519 direntry->begin = cpu_to_le16(begin & 0xffff);
520 direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
523 static uint8_t to_valid_short_char(gunichar c)
525 c = g_unichar_toupper(c);
526 if ((c >= '0' && c <= '9') ||
527 (c >= 'A' && c <= 'Z') ||
528 strchr("$%'-_@~`!(){}^#&", c) != 0) {
529 return c;
530 } else {
531 return 0;
535 static direntry_t *create_short_filename(BDRVVVFATState *s,
536 const char *filename,
537 unsigned int directory_start)
539 int i, j = 0;
540 direntry_t *entry = array_get_next(&(s->directory));
541 const gchar *p, *last_dot = NULL;
542 gunichar c;
543 bool lossy_conversion = false;
544 char tail[8];
546 if (!entry) {
547 return NULL;
549 memset(entry->name, 0x20, sizeof(entry->name));
551 /* copy filename and search last dot */
552 for (p = filename; ; p = g_utf8_next_char(p)) {
553 c = g_utf8_get_char(p);
554 if (c == '\0') {
555 break;
556 } else if (c == '.') {
557 if (j == 0) {
558 /* '.' at start of filename */
559 lossy_conversion = true;
560 } else {
561 if (last_dot) {
562 lossy_conversion = true;
564 last_dot = p;
566 } else if (!last_dot) {
567 /* first part of the name; copy it */
568 uint8_t v = to_valid_short_char(c);
569 if (j < 8 && v) {
570 entry->name[j++] = v;
571 } else {
572 lossy_conversion = true;
577 /* copy extension (if any) */
578 if (last_dot) {
579 j = 0;
580 for (p = g_utf8_next_char(last_dot); ; p = g_utf8_next_char(p)) {
581 c = g_utf8_get_char(p);
582 if (c == '\0') {
583 break;
584 } else {
585 /* extension; copy it */
586 uint8_t v = to_valid_short_char(c);
587 if (j < 3 && v) {
588 entry->name[8 + (j++)] = v;
589 } else {
590 lossy_conversion = true;
596 if (entry->name[0] == DIR_KANJI) {
597 entry->name[0] = DIR_KANJI_FAKE;
600 /* numeric-tail generation */
601 for (j = 0; j < 8; j++) {
602 if (entry->name[j] == ' ') {
603 break;
606 for (i = lossy_conversion ? 1 : 0; i < 999999; i++) {
607 direntry_t *entry1;
608 if (i > 0) {
609 int len = snprintf(tail, sizeof(tail), "~%u", (unsigned)i);
610 assert(len <= 7);
611 memcpy(entry->name + MIN(j, 8 - len), tail, len);
613 for (entry1 = array_get(&(s->directory), directory_start);
614 entry1 < entry; entry1++) {
615 if (!is_long_name(entry1) &&
616 !memcmp(entry1->name, entry->name, 11)) {
617 break; /* found dupe */
620 if (entry1 == entry) {
621 /* no dupe found */
622 return entry;
625 return NULL;
628 /* fat functions */
630 static inline uint8_t fat_chksum(const direntry_t* entry)
632 uint8_t chksum=0;
633 int i;
635 for (i = 0; i < ARRAY_SIZE(entry->name); i++) {
636 chksum = (((chksum & 0xfe) >> 1) |
637 ((chksum & 0x01) ? 0x80 : 0)) + entry->name[i];
640 return chksum;
643 /* if return_time==0, this returns the fat_date, else the fat_time */
644 static uint16_t fat_datetime(time_t time,int return_time) {
645 struct tm* t;
646 struct tm t1;
647 t = &t1;
648 localtime_r(&time,t);
649 if(return_time)
650 return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
651 return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
654 static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
656 if(s->fat_type==32) {
657 uint32_t* entry=array_get(&(s->fat),cluster);
658 *entry=cpu_to_le32(value);
659 } else if(s->fat_type==16) {
660 uint16_t* entry=array_get(&(s->fat),cluster);
661 *entry=cpu_to_le16(value&0xffff);
662 } else {
663 int offset = (cluster*3/2);
664 unsigned char* p = array_get(&(s->fat), offset);
665 switch (cluster&1) {
666 case 0:
667 p[0] = value&0xff;
668 p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
669 break;
670 case 1:
671 p[0] = (p[0]&0xf) | ((value&0xf)<<4);
672 p[1] = (value>>4);
673 break;
678 static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
680 if(s->fat_type==32) {
681 uint32_t* entry=array_get(&(s->fat),cluster);
682 return le32_to_cpu(*entry);
683 } else if(s->fat_type==16) {
684 uint16_t* entry=array_get(&(s->fat),cluster);
685 return le16_to_cpu(*entry);
686 } else {
687 const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
688 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
692 static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
694 if(fat_entry>s->max_fat_value-8)
695 return -1;
696 return 0;
699 static inline void init_fat(BDRVVVFATState* s)
701 if (s->fat_type == 12) {
702 array_init(&(s->fat),1);
703 array_ensure_allocated(&(s->fat),
704 s->sectors_per_fat * 0x200 * 3 / 2 - 1);
705 } else {
706 array_init(&(s->fat),(s->fat_type==32?4:2));
707 array_ensure_allocated(&(s->fat),
708 s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
710 memset(s->fat.pointer,0,s->fat.size);
712 switch(s->fat_type) {
713 case 12: s->max_fat_value=0xfff; break;
714 case 16: s->max_fat_value=0xffff; break;
715 case 32: s->max_fat_value=0x0fffffff; break;
716 default: s->max_fat_value=0; /* error... */
721 static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
722 unsigned int directory_start, const char* filename, int is_dot)
724 int long_index = s->directory.next;
725 direntry_t* entry = NULL;
726 direntry_t* entry_long = NULL;
728 if(is_dot) {
729 entry=array_get_next(&(s->directory));
730 memset(entry->name, 0x20, sizeof(entry->name));
731 memcpy(entry->name,filename,strlen(filename));
732 return entry;
735 entry_long=create_long_filename(s,filename);
736 entry = create_short_filename(s, filename, directory_start);
738 /* calculate checksum; propagate to long name */
739 if(entry_long) {
740 uint8_t chksum=fat_chksum(entry);
742 /* calculate anew, because realloc could have taken place */
743 entry_long=array_get(&(s->directory),long_index);
744 while(entry_long<entry && is_long_name(entry_long)) {
745 entry_long->reserved[1]=chksum;
746 entry_long++;
750 return entry;
754 * Read a directory. (the index of the corresponding mapping must be passed).
756 static int read_directory(BDRVVVFATState* s, int mapping_index)
758 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
759 direntry_t* direntry;
760 const char* dirname = mapping->path;
761 int first_cluster = mapping->begin;
762 int parent_index = mapping->info.dir.parent_mapping_index;
763 mapping_t* parent_mapping = (mapping_t*)
764 (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL);
765 int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
767 DIR* dir=opendir(dirname);
768 struct dirent* entry;
769 int i;
771 assert(mapping->mode & MODE_DIRECTORY);
773 if(!dir) {
774 mapping->end = mapping->begin;
775 return -1;
778 i = mapping->info.dir.first_dir_index =
779 first_cluster == 0 ? 0 : s->directory.next;
781 if (first_cluster != 0) {
782 /* create the top entries of a subdirectory */
783 (void)create_short_and_long_name(s, i, ".", 1);
784 (void)create_short_and_long_name(s, i, "..", 1);
787 /* actually read the directory, and allocate the mappings */
788 while((entry=readdir(dir))) {
789 unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
790 char* buffer;
791 direntry_t* direntry;
792 struct stat st;
793 int is_dot=!strcmp(entry->d_name,".");
794 int is_dotdot=!strcmp(entry->d_name,"..");
796 if (first_cluster == 0 && s->directory.next >= s->root_entries - 1) {
797 fprintf(stderr, "Too many entries in root directory\n");
798 closedir(dir);
799 return -2;
802 if(first_cluster == 0 && (is_dotdot || is_dot))
803 continue;
805 buffer = g_malloc(length);
806 snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
808 if(stat(buffer,&st)<0) {
809 g_free(buffer);
810 continue;
813 /* create directory entry for this file */
814 if (!is_dot && !is_dotdot) {
815 direntry = create_short_and_long_name(s, i, entry->d_name, 0);
816 } else {
817 direntry = array_get(&(s->directory), is_dot ? i : i + 1);
819 direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
820 direntry->reserved[0]=direntry->reserved[1]=0;
821 direntry->ctime=fat_datetime(st.st_ctime,1);
822 direntry->cdate=fat_datetime(st.st_ctime,0);
823 direntry->adate=fat_datetime(st.st_atime,0);
824 direntry->begin_hi=0;
825 direntry->mtime=fat_datetime(st.st_mtime,1);
826 direntry->mdate=fat_datetime(st.st_mtime,0);
827 if(is_dotdot)
828 set_begin_of_direntry(direntry, first_cluster_of_parent);
829 else if(is_dot)
830 set_begin_of_direntry(direntry, first_cluster);
831 else
832 direntry->begin=0; /* do that later */
833 if (st.st_size > 0x7fffffff) {
834 fprintf(stderr, "File %s is larger than 2GB\n", buffer);
835 g_free(buffer);
836 closedir(dir);
837 return -2;
839 direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
841 /* create mapping for this file */
842 if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
843 s->current_mapping = array_get_next(&(s->mapping));
844 s->current_mapping->begin=0;
845 s->current_mapping->end=st.st_size;
847 * we get the direntry of the most recent direntry, which
848 * contains the short name and all the relevant information.
850 s->current_mapping->dir_index=s->directory.next-1;
851 s->current_mapping->first_mapping_index = -1;
852 if (S_ISDIR(st.st_mode)) {
853 s->current_mapping->mode = MODE_DIRECTORY;
854 s->current_mapping->info.dir.parent_mapping_index =
855 mapping_index;
856 } else {
857 s->current_mapping->mode = MODE_UNDEFINED;
858 s->current_mapping->info.file.offset = 0;
860 s->current_mapping->path=buffer;
861 s->current_mapping->read_only =
862 (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
863 } else {
864 g_free(buffer);
867 closedir(dir);
869 /* fill with zeroes up to the end of the cluster */
870 while(s->directory.next%(0x10*s->sectors_per_cluster)) {
871 direntry_t* direntry=array_get_next(&(s->directory));
872 memset(direntry,0,sizeof(direntry_t));
875 if (s->fat_type != 32 &&
876 mapping_index == 0 &&
877 s->directory.next < s->root_entries) {
878 /* root directory */
879 int cur = s->directory.next;
880 array_ensure_allocated(&(s->directory), s->root_entries - 1);
881 s->directory.next = s->root_entries;
882 memset(array_get(&(s->directory), cur), 0,
883 (s->root_entries - cur) * sizeof(direntry_t));
886 /* re-get the mapping, since s->mapping was possibly realloc()ed */
887 mapping = array_get(&(s->mapping), mapping_index);
888 first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
889 * 0x20 / s->cluster_size;
890 mapping->end = first_cluster;
892 direntry = array_get(&(s->directory), mapping->dir_index);
893 set_begin_of_direntry(direntry, mapping->begin);
895 return 0;
898 static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
900 return (sector_num - s->offset_to_root_dir) / s->sectors_per_cluster;
903 static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
905 return s->offset_to_root_dir + s->sectors_per_cluster * cluster_num;
908 static int init_directories(BDRVVVFATState* s,
909 const char *dirname, int heads, int secs,
910 Error **errp)
912 bootsector_t* bootsector;
913 mapping_t* mapping;
914 unsigned int i;
915 unsigned int cluster;
917 memset(&(s->first_sectors[0]),0,0x40*0x200);
919 s->cluster_size=s->sectors_per_cluster*0x200;
920 s->cluster_buffer=g_malloc(s->cluster_size);
923 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
924 * where sc is sector_count,
925 * spf is sectors_per_fat,
926 * spc is sectors_per_clusters, and
927 * fat_type = 12, 16 or 32.
929 i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
930 s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
932 s->offset_to_fat = s->offset_to_bootsector + 1;
933 s->offset_to_root_dir = s->offset_to_fat + s->sectors_per_fat * 2;
935 array_init(&(s->mapping),sizeof(mapping_t));
936 array_init(&(s->directory),sizeof(direntry_t));
938 /* add volume label */
940 direntry_t* entry=array_get_next(&(s->directory));
941 entry->attributes=0x28; /* archive | volume label */
942 memcpy(entry->name, s->volume_label, sizeof(entry->name));
945 /* Now build FAT, and write back information into directory */
946 init_fat(s);
948 /* TODO: if there are more entries, bootsector has to be adjusted! */
949 s->root_entries = 0x02 * 0x10 * s->sectors_per_cluster;
950 s->cluster_count=sector2cluster(s, s->sector_count);
952 mapping = array_get_next(&(s->mapping));
953 mapping->begin = 0;
954 mapping->dir_index = 0;
955 mapping->info.dir.parent_mapping_index = -1;
956 mapping->first_mapping_index = -1;
957 mapping->path = g_strdup(dirname);
958 i = strlen(mapping->path);
959 if (i > 0 && mapping->path[i - 1] == '/')
960 mapping->path[i - 1] = '\0';
961 mapping->mode = MODE_DIRECTORY;
962 mapping->read_only = 0;
963 s->path = mapping->path;
965 for (i = 0, cluster = 0; i < s->mapping.next; i++) {
966 /* MS-DOS expects the FAT to be 0 for the root directory
967 * (except for the media byte). */
968 /* LATER TODO: still true for FAT32? */
969 int fix_fat = (i != 0);
970 mapping = array_get(&(s->mapping), i);
972 if (mapping->mode & MODE_DIRECTORY) {
973 char *path = mapping->path;
974 mapping->begin = cluster;
975 if(read_directory(s, i)) {
976 error_setg(errp, "Could not read directory %s", path);
977 return -1;
979 mapping = array_get(&(s->mapping), i);
980 } else {
981 assert(mapping->mode == MODE_UNDEFINED);
982 mapping->mode=MODE_NORMAL;
983 mapping->begin = cluster;
984 if (mapping->end > 0) {
985 direntry_t* direntry = array_get(&(s->directory),
986 mapping->dir_index);
988 mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
989 set_begin_of_direntry(direntry, mapping->begin);
990 } else {
991 mapping->end = cluster + 1;
992 fix_fat = 0;
996 assert(mapping->begin < mapping->end);
998 /* next free cluster */
999 cluster = mapping->end;
1001 if(cluster > s->cluster_count) {
1002 error_setg(errp,
1003 "Directory does not fit in FAT%d (capacity %.2f MB)",
1004 s->fat_type, s->sector_count / 2000.0);
1005 return -1;
1008 /* fix fat for entry */
1009 if (fix_fat) {
1010 int j;
1011 for(j = mapping->begin; j < mapping->end - 1; j++)
1012 fat_set(s, j, j+1);
1013 fat_set(s, mapping->end - 1, s->max_fat_value);
1017 mapping = array_get(&(s->mapping), 0);
1018 s->last_cluster_of_root_directory = mapping->end;
1020 /* the FAT signature */
1021 fat_set(s,0,s->max_fat_value);
1022 fat_set(s,1,s->max_fat_value);
1024 s->current_mapping = NULL;
1026 bootsector = (bootsector_t *)(s->first_sectors
1027 + s->offset_to_bootsector * 0x200);
1028 bootsector->jump[0]=0xeb;
1029 bootsector->jump[1]=0x3e;
1030 bootsector->jump[2]=0x90;
1031 memcpy(bootsector->name, BOOTSECTOR_OEM_NAME, 8);
1032 bootsector->sector_size=cpu_to_le16(0x200);
1033 bootsector->sectors_per_cluster=s->sectors_per_cluster;
1034 bootsector->reserved_sectors=cpu_to_le16(1);
1035 bootsector->number_of_fats=0x2; /* number of FATs */
1036 bootsector->root_entries = cpu_to_le16(s->root_entries);
1037 bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
1038 /* media descriptor: hard disk=0xf8, floppy=0xf0 */
1039 bootsector->media_type = (s->offset_to_bootsector > 0 ? 0xf8 : 0xf0);
1040 s->fat.pointer[0] = bootsector->media_type;
1041 bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
1042 bootsector->sectors_per_track = cpu_to_le16(secs);
1043 bootsector->number_of_heads = cpu_to_le16(heads);
1044 bootsector->hidden_sectors = cpu_to_le32(s->offset_to_bootsector);
1045 bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
1047 /* LATER TODO: if FAT32, this is wrong */
1048 /* drive_number: fda=0, hda=0x80 */
1049 bootsector->u.fat16.drive_number = s->offset_to_bootsector == 0 ? 0 : 0x80;
1050 bootsector->u.fat16.signature=0x29;
1051 bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
1053 memcpy(bootsector->u.fat16.volume_label, s->volume_label,
1054 sizeof(bootsector->u.fat16.volume_label));
1055 memcpy(bootsector->u.fat16.fat_type,
1056 s->fat_type == 12 ? "FAT12 " : "FAT16 ", 8);
1057 bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
1059 return 0;
1062 #ifdef DEBUG
1063 static BDRVVVFATState *vvv = NULL;
1064 #endif
1066 static int enable_write_target(BlockDriverState *bs, Error **errp);
1067 static int is_consistent(BDRVVVFATState *s);
1069 static QemuOptsList runtime_opts = {
1070 .name = "vvfat",
1071 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
1072 .desc = {
1074 .name = "dir",
1075 .type = QEMU_OPT_STRING,
1076 .help = "Host directory to map to the vvfat device",
1079 .name = "fat-type",
1080 .type = QEMU_OPT_NUMBER,
1081 .help = "FAT type (12, 16 or 32)",
1084 .name = "floppy",
1085 .type = QEMU_OPT_BOOL,
1086 .help = "Create a floppy rather than a hard disk image",
1089 .name = "label",
1090 .type = QEMU_OPT_STRING,
1091 .help = "Use a volume label other than QEMU VVFAT",
1094 .name = "rw",
1095 .type = QEMU_OPT_BOOL,
1096 .help = "Make the image writable",
1098 { /* end of list */ }
1102 static void vvfat_parse_filename(const char *filename, QDict *options,
1103 Error **errp)
1105 int fat_type = 0;
1106 bool floppy = false;
1107 bool rw = false;
1108 int i;
1110 if (!strstart(filename, "fat:", NULL)) {
1111 error_setg(errp, "File name string must start with 'fat:'");
1112 return;
1115 /* Parse options */
1116 if (strstr(filename, ":32:")) {
1117 fat_type = 32;
1118 } else if (strstr(filename, ":16:")) {
1119 fat_type = 16;
1120 } else if (strstr(filename, ":12:")) {
1121 fat_type = 12;
1124 if (strstr(filename, ":floppy:")) {
1125 floppy = true;
1128 if (strstr(filename, ":rw:")) {
1129 rw = true;
1132 /* Get the directory name without options */
1133 i = strrchr(filename, ':') - filename;
1134 assert(i >= 3);
1135 if (filename[i - 2] == ':' && qemu_isalpha(filename[i - 1])) {
1136 /* workaround for DOS drive names */
1137 filename += i - 1;
1138 } else {
1139 filename += i + 1;
1142 /* Fill in the options QDict */
1143 qdict_put_str(options, "dir", filename);
1144 qdict_put_int(options, "fat-type", fat_type);
1145 qdict_put_bool(options, "floppy", floppy);
1146 qdict_put_bool(options, "rw", rw);
1149 static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
1150 Error **errp)
1152 BDRVVVFATState *s = bs->opaque;
1153 int cyls, heads, secs;
1154 bool floppy;
1155 const char *dirname, *label;
1156 QemuOpts *opts;
1157 Error *local_err = NULL;
1158 int ret;
1160 #ifdef DEBUG
1161 vvv = s;
1162 #endif
1164 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
1165 qemu_opts_absorb_qdict(opts, options, &local_err);
1166 if (local_err) {
1167 error_propagate(errp, local_err);
1168 ret = -EINVAL;
1169 goto fail;
1172 dirname = qemu_opt_get(opts, "dir");
1173 if (!dirname) {
1174 error_setg(errp, "vvfat block driver requires a 'dir' option");
1175 ret = -EINVAL;
1176 goto fail;
1179 s->fat_type = qemu_opt_get_number(opts, "fat-type", 0);
1180 floppy = qemu_opt_get_bool(opts, "floppy", false);
1182 memset(s->volume_label, ' ', sizeof(s->volume_label));
1183 label = qemu_opt_get(opts, "label");
1184 if (label) {
1185 size_t label_length = strlen(label);
1186 if (label_length > 11) {
1187 error_setg(errp, "vvfat label cannot be longer than 11 bytes");
1188 ret = -EINVAL;
1189 goto fail;
1191 memcpy(s->volume_label, label, label_length);
1192 } else {
1193 memcpy(s->volume_label, "QEMU VVFAT", 10);
1196 if (floppy) {
1197 /* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */
1198 if (!s->fat_type) {
1199 s->fat_type = 12;
1200 secs = 36;
1201 s->sectors_per_cluster = 2;
1202 } else {
1203 secs = s->fat_type == 12 ? 18 : 36;
1204 s->sectors_per_cluster = 1;
1206 cyls = 80;
1207 heads = 2;
1208 } else {
1209 /* 32MB or 504MB disk*/
1210 if (!s->fat_type) {
1211 s->fat_type = 16;
1213 s->offset_to_bootsector = 0x3f;
1214 cyls = s->fat_type == 12 ? 64 : 1024;
1215 heads = 16;
1216 secs = 63;
1219 switch (s->fat_type) {
1220 case 32:
1221 warn_report("FAT32 has not been tested. You are welcome to do so!");
1222 break;
1223 case 16:
1224 case 12:
1225 break;
1226 default:
1227 error_setg(errp, "Valid FAT types are only 12, 16 and 32");
1228 ret = -EINVAL;
1229 goto fail;
1233 s->bs = bs;
1235 /* LATER TODO: if FAT32, adjust */
1236 s->sectors_per_cluster=0x10;
1238 s->current_cluster=0xffffffff;
1240 s->qcow = NULL;
1241 s->qcow_filename = NULL;
1242 s->fat2 = NULL;
1243 s->downcase_short_names = 1;
1245 DLOG(fprintf(stderr, "vvfat %s chs %d,%d,%d\n",
1246 dirname, cyls, heads, secs));
1248 s->sector_count = cyls * heads * secs - s->offset_to_bootsector;
1250 if (qemu_opt_get_bool(opts, "rw", false)) {
1251 if (!bdrv_is_read_only(bs)) {
1252 ret = enable_write_target(bs, errp);
1253 if (ret < 0) {
1254 goto fail;
1256 } else {
1257 ret = -EPERM;
1258 error_setg(errp,
1259 "Unable to set VVFAT to 'rw' when drive is read-only");
1260 goto fail;
1262 } else {
1263 ret = bdrv_apply_auto_read_only(bs, NULL, errp);
1264 if (ret < 0) {
1265 goto fail;
1269 bs->total_sectors = cyls * heads * secs;
1271 if (init_directories(s, dirname, heads, secs, errp)) {
1272 ret = -EIO;
1273 goto fail;
1276 s->sector_count = s->offset_to_root_dir
1277 + s->sectors_per_cluster * s->cluster_count;
1279 /* Disable migration when vvfat is used rw */
1280 if (s->qcow) {
1281 error_setg(&s->migration_blocker,
1282 "The vvfat (rw) format used by node '%s' "
1283 "does not support live migration",
1284 bdrv_get_device_or_node_name(bs));
1285 ret = migrate_add_blocker(s->migration_blocker, &local_err);
1286 if (local_err) {
1287 error_propagate(errp, local_err);
1288 error_free(s->migration_blocker);
1289 goto fail;
1293 if (s->offset_to_bootsector > 0) {
1294 init_mbr(s, cyls, heads, secs);
1297 qemu_co_mutex_init(&s->lock);
1299 ret = 0;
1300 fail:
1301 qemu_opts_del(opts);
1302 return ret;
1305 static void vvfat_refresh_limits(BlockDriverState *bs, Error **errp)
1307 bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */
1310 static inline void vvfat_close_current_file(BDRVVVFATState *s)
1312 if(s->current_mapping) {
1313 s->current_mapping = NULL;
1314 if (s->current_fd) {
1315 qemu_close(s->current_fd);
1316 s->current_fd = 0;
1319 s->current_cluster = -1;
1322 /* mappings between index1 and index2-1 are supposed to be ordered
1323 * return value is the index of the last mapping for which end>cluster_num
1325 static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1327 while(1) {
1328 int index3;
1329 mapping_t* mapping;
1330 index3=(index1+index2)/2;
1331 mapping=array_get(&(s->mapping),index3);
1332 assert(mapping->begin < mapping->end);
1333 if(mapping->begin>=cluster_num) {
1334 assert(index2!=index3 || index2==0);
1335 if(index2==index3)
1336 return index1;
1337 index2=index3;
1338 } else {
1339 if(index1==index3)
1340 return mapping->end<=cluster_num ? index2 : index1;
1341 index1=index3;
1343 assert(index1<=index2);
1344 DLOG(mapping=array_get(&(s->mapping),index1);
1345 assert(mapping->begin<=cluster_num);
1346 assert(index2 >= s->mapping.next ||
1347 ((mapping = array_get(&(s->mapping),index2)) &&
1348 mapping->end>cluster_num)));
1352 static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
1354 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
1355 mapping_t* mapping;
1356 if(index>=s->mapping.next)
1357 return NULL;
1358 mapping=array_get(&(s->mapping),index);
1359 if(mapping->begin>cluster_num)
1360 return NULL;
1361 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
1362 return mapping;
1365 static int open_file(BDRVVVFATState* s,mapping_t* mapping)
1367 if(!mapping)
1368 return -1;
1369 if(!s->current_mapping ||
1370 strcmp(s->current_mapping->path,mapping->path)) {
1371 /* open file */
1372 int fd = qemu_open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
1373 if(fd<0)
1374 return -1;
1375 vvfat_close_current_file(s);
1376 s->current_fd = fd;
1377 s->current_mapping = mapping;
1379 return 0;
1382 static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1384 if(s->current_cluster != cluster_num) {
1385 int result=0;
1386 off_t offset;
1387 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
1388 if(!s->current_mapping
1389 || s->current_mapping->begin>cluster_num
1390 || s->current_mapping->end<=cluster_num) {
1391 /* binary search of mappings for file */
1392 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
1394 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1396 if (mapping && mapping->mode & MODE_DIRECTORY) {
1397 vvfat_close_current_file(s);
1398 s->current_mapping = mapping;
1399 read_cluster_directory:
1400 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
1401 s->cluster = (unsigned char*)s->directory.pointer+offset
1402 + 0x20*s->current_mapping->info.dir.first_dir_index;
1403 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1404 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1405 s->current_cluster = cluster_num;
1406 return 0;
1409 if(open_file(s,mapping))
1410 return -2;
1411 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1412 goto read_cluster_directory;
1414 assert(s->current_fd);
1416 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
1417 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1418 return -3;
1419 s->cluster=s->cluster_buffer;
1420 result=read(s->current_fd,s->cluster,s->cluster_size);
1421 if(result<0) {
1422 s->current_cluster = -1;
1423 return -1;
1425 s->current_cluster = cluster_num;
1427 return 0;
1430 #ifdef DEBUG
1431 static void print_direntry(const direntry_t* direntry)
1433 int j = 0;
1434 char buffer[1024];
1436 fprintf(stderr, "direntry %p: ", direntry);
1437 if(!direntry)
1438 return;
1439 if(is_long_name(direntry)) {
1440 unsigned char* c=(unsigned char*)direntry;
1441 int i;
1442 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
1443 #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
1444 ADD_CHAR(c[i]);
1445 for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
1446 ADD_CHAR(c[i]);
1447 for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
1448 ADD_CHAR(c[i]);
1449 buffer[j] = 0;
1450 fprintf(stderr, "%s\n", buffer);
1451 } else {
1452 int i;
1453 for(i=0;i<11;i++)
1454 ADD_CHAR(direntry->name[i]);
1455 buffer[j] = 0;
1456 fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1457 buffer,
1458 direntry->attributes,
1459 begin_of_direntry(direntry),le32_to_cpu(direntry->size));
1463 static void print_mapping(const mapping_t* mapping)
1465 fprintf(stderr, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1466 "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1467 mapping, mapping->begin, mapping->end, mapping->dir_index,
1468 mapping->first_mapping_index, mapping->path, mapping->mode);
1470 if (mapping->mode & MODE_DIRECTORY)
1471 fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1472 else
1473 fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
1475 #endif
1477 static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
1478 uint8_t *buf, int nb_sectors)
1480 BDRVVVFATState *s = bs->opaque;
1481 int i;
1483 for(i=0;i<nb_sectors;i++,sector_num++) {
1484 if (sector_num >= bs->total_sectors)
1485 return -1;
1486 if (s->qcow) {
1487 int64_t n;
1488 int ret;
1489 ret = bdrv_is_allocated(s->qcow->bs, sector_num * BDRV_SECTOR_SIZE,
1490 (nb_sectors - i) * BDRV_SECTOR_SIZE, &n);
1491 if (ret < 0) {
1492 return ret;
1494 if (ret) {
1495 DLOG(fprintf(stderr, "sectors %" PRId64 "+%" PRId64
1496 " allocated\n", sector_num,
1497 n >> BDRV_SECTOR_BITS));
1498 if (bdrv_pread(s->qcow, sector_num * BDRV_SECTOR_SIZE,
1499 buf + i * 0x200, n) < 0) {
1500 return -1;
1502 i += (n >> BDRV_SECTOR_BITS) - 1;
1503 sector_num += (n >> BDRV_SECTOR_BITS) - 1;
1504 continue;
1506 DLOG(fprintf(stderr, "sector %" PRId64 " not allocated\n",
1507 sector_num));
1509 if (sector_num < s->offset_to_root_dir) {
1510 if (sector_num < s->offset_to_fat) {
1511 memcpy(buf + i * 0x200,
1512 &(s->first_sectors[sector_num * 0x200]),
1513 0x200);
1514 } else if (sector_num < s->offset_to_fat + s->sectors_per_fat) {
1515 memcpy(buf + i * 0x200,
1516 &(s->fat.pointer[(sector_num
1517 - s->offset_to_fat) * 0x200]),
1518 0x200);
1519 } else if (sector_num < s->offset_to_root_dir) {
1520 memcpy(buf + i * 0x200,
1521 &(s->fat.pointer[(sector_num - s->offset_to_fat
1522 - s->sectors_per_fat) * 0x200]),
1523 0x200);
1525 } else {
1526 uint32_t sector = sector_num - s->offset_to_root_dir,
1527 sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1528 cluster_num=sector/s->sectors_per_cluster;
1529 if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) {
1530 /* LATER TODO: strict: return -1; */
1531 memset(buf+i*0x200,0,0x200);
1532 continue;
1534 memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
1537 return 0;
1540 static int coroutine_fn
1541 vvfat_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
1542 QEMUIOVector *qiov, int flags)
1544 int ret;
1545 BDRVVVFATState *s = bs->opaque;
1546 uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
1547 int nb_sectors = bytes >> BDRV_SECTOR_BITS;
1548 void *buf;
1550 assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
1551 assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
1553 buf = g_try_malloc(bytes);
1554 if (bytes && buf == NULL) {
1555 return -ENOMEM;
1558 qemu_co_mutex_lock(&s->lock);
1559 ret = vvfat_read(bs, sector_num, buf, nb_sectors);
1560 qemu_co_mutex_unlock(&s->lock);
1562 qemu_iovec_from_buf(qiov, 0, buf, bytes);
1563 g_free(buf);
1565 return ret;
1568 /* LATER TODO: statify all functions */
1571 * Idea of the write support (use snapshot):
1573 * 1. check if all data is consistent, recording renames, modifications,
1574 * new files and directories (in s->commits).
1576 * 2. if the data is not consistent, stop committing
1578 * 3. handle renames, and create new files and directories (do not yet
1579 * write their contents)
1581 * 4. walk the directories, fixing the mapping and direntries, and marking
1582 * the handled mappings as not deleted
1584 * 5. commit the contents of the files
1586 * 6. handle deleted files and directories
1590 typedef struct commit_t {
1591 char* path;
1592 union {
1593 struct { uint32_t cluster; } rename;
1594 struct { int dir_index; uint32_t modified_offset; } writeout;
1595 struct { uint32_t first_cluster; } new_file;
1596 struct { uint32_t cluster; } mkdir;
1597 } param;
1598 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1599 enum {
1600 ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1601 } action;
1602 } commit_t;
1604 static void clear_commits(BDRVVVFATState* s)
1606 int i;
1607 DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1608 for (i = 0; i < s->commits.next; i++) {
1609 commit_t* commit = array_get(&(s->commits), i);
1610 assert(commit->path || commit->action == ACTION_WRITEOUT);
1611 if (commit->action != ACTION_WRITEOUT) {
1612 assert(commit->path);
1613 g_free(commit->path);
1614 } else
1615 assert(commit->path == NULL);
1617 s->commits.next = 0;
1620 static void schedule_rename(BDRVVVFATState* s,
1621 uint32_t cluster, char* new_path)
1623 commit_t* commit = array_get_next(&(s->commits));
1624 commit->path = new_path;
1625 commit->param.rename.cluster = cluster;
1626 commit->action = ACTION_RENAME;
1629 static void schedule_writeout(BDRVVVFATState* s,
1630 int dir_index, uint32_t modified_offset)
1632 commit_t* commit = array_get_next(&(s->commits));
1633 commit->path = NULL;
1634 commit->param.writeout.dir_index = dir_index;
1635 commit->param.writeout.modified_offset = modified_offset;
1636 commit->action = ACTION_WRITEOUT;
1639 static void schedule_new_file(BDRVVVFATState* s,
1640 char* path, uint32_t first_cluster)
1642 commit_t* commit = array_get_next(&(s->commits));
1643 commit->path = path;
1644 commit->param.new_file.first_cluster = first_cluster;
1645 commit->action = ACTION_NEW_FILE;
1648 static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1650 commit_t* commit = array_get_next(&(s->commits));
1651 commit->path = path;
1652 commit->param.mkdir.cluster = cluster;
1653 commit->action = ACTION_MKDIR;
1656 typedef struct {
1658 * Since the sequence number is at most 0x3f, and the filename
1659 * length is at most 13 times the sequence number, the maximal
1660 * filename length is 0x3f * 13 bytes.
1662 unsigned char name[0x3f * 13 + 1];
1663 gunichar2 name2[0x3f * 13 + 1];
1664 int checksum, len;
1665 int sequence_number;
1666 } long_file_name;
1668 static void lfn_init(long_file_name* lfn)
1670 lfn->sequence_number = lfn->len = 0;
1671 lfn->checksum = 0x100;
1674 /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1675 static int parse_long_name(long_file_name* lfn,
1676 const direntry_t* direntry)
1678 int i, j, offset;
1679 const unsigned char* pointer = (const unsigned char*)direntry;
1681 if (!is_long_name(direntry))
1682 return 1;
1684 if (pointer[0] & 0x40) {
1685 /* first entry; do some initialization */
1686 lfn->sequence_number = pointer[0] & 0x3f;
1687 lfn->checksum = pointer[13];
1688 lfn->name[0] = 0;
1689 lfn->name[lfn->sequence_number * 13] = 0;
1690 } else if ((pointer[0] & 0x3f) != --lfn->sequence_number) {
1691 /* not the expected sequence number */
1692 return -1;
1693 } else if (pointer[13] != lfn->checksum) {
1694 /* not the expected checksum */
1695 return -2;
1696 } else if (pointer[12] || pointer[26] || pointer[27]) {
1697 /* invalid zero fields */
1698 return -3;
1701 offset = 13 * (lfn->sequence_number - 1);
1702 for (i = 0, j = 1; i < 13; i++, j+=2) {
1703 if (j == 11)
1704 j = 14;
1705 else if (j == 26)
1706 j = 28;
1708 if (pointer[j] == 0 && pointer[j + 1] == 0) {
1709 /* end of long file name */
1710 break;
1712 gunichar2 c = (pointer[j + 1] << 8) + pointer[j];
1713 lfn->name2[offset + i] = c;
1716 if (pointer[0] & 0x40) {
1717 /* first entry; set len */
1718 lfn->len = offset + i;
1720 if ((pointer[0] & 0x3f) == 0x01) {
1721 /* last entry; finalize entry */
1722 glong olen;
1723 gchar *utf8 = g_utf16_to_utf8(lfn->name2, lfn->len, NULL, &olen, NULL);
1724 if (!utf8) {
1725 return -4;
1727 lfn->len = olen;
1728 memcpy(lfn->name, utf8, olen + 1);
1729 g_free(utf8);
1732 return 0;
1735 /* returns 0 if successful, >0 if no short_name, and <0 on error */
1736 static int parse_short_name(BDRVVVFATState* s,
1737 long_file_name* lfn, direntry_t* direntry)
1739 int i, j;
1741 if (!is_short_name(direntry))
1742 return 1;
1744 for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1745 for (i = 0; i <= j; i++) {
1746 uint8_t c = direntry->name[i];
1747 if (c != to_valid_short_char(c)) {
1748 return -1;
1749 } else if (s->downcase_short_names) {
1750 lfn->name[i] = qemu_tolower(direntry->name[i]);
1751 } else {
1752 lfn->name[i] = direntry->name[i];
1756 for (j = 2; j >= 0 && direntry->name[8 + j] == ' '; j--) {
1758 if (j >= 0) {
1759 lfn->name[i++] = '.';
1760 lfn->name[i + j + 1] = '\0';
1761 for (;j >= 0; j--) {
1762 uint8_t c = direntry->name[8 + j];
1763 if (c != to_valid_short_char(c)) {
1764 return -2;
1765 } else if (s->downcase_short_names) {
1766 lfn->name[i + j] = qemu_tolower(c);
1767 } else {
1768 lfn->name[i + j] = c;
1771 } else
1772 lfn->name[i + j + 1] = '\0';
1774 if (lfn->name[0] == DIR_KANJI_FAKE) {
1775 lfn->name[0] = DIR_KANJI;
1777 lfn->len = strlen((char*)lfn->name);
1779 return 0;
1782 static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1783 unsigned int cluster)
1785 if (cluster < s->last_cluster_of_root_directory) {
1786 if (cluster + 1 == s->last_cluster_of_root_directory)
1787 return s->max_fat_value;
1788 else
1789 return cluster + 1;
1792 if (s->fat_type==32) {
1793 uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1794 return le32_to_cpu(*entry);
1795 } else if (s->fat_type==16) {
1796 uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1797 return le16_to_cpu(*entry);
1798 } else {
1799 const uint8_t* x=s->fat2+cluster*3/2;
1800 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1804 static inline bool cluster_was_modified(BDRVVVFATState *s,
1805 uint32_t cluster_num)
1807 int was_modified = 0;
1808 int i;
1810 if (s->qcow == NULL) {
1811 return 0;
1814 for (i = 0; !was_modified && i < s->sectors_per_cluster; i++) {
1815 was_modified = bdrv_is_allocated(s->qcow->bs,
1816 (cluster2sector(s, cluster_num) +
1817 i) * BDRV_SECTOR_SIZE,
1818 BDRV_SECTOR_SIZE, NULL);
1822 * Note that this treats failures to learn allocation status the
1823 * same as if an allocation has occurred. It's as safe as
1824 * anything else, given that a failure to learn allocation status
1825 * will probably result in more failures.
1827 return !!was_modified;
1830 static const char* get_basename(const char* path)
1832 char* basename = strrchr(path, '/');
1833 if (basename == NULL)
1834 return path;
1835 else
1836 return basename + 1; /* strip '/' */
1840 * The array s->used_clusters holds the states of the clusters. If it is
1841 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1842 * was modified, bit 3 is set.
1843 * If any cluster is allocated, but not part of a file or directory, this
1844 * driver refuses to commit.
1846 typedef enum {
1847 USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
1848 } used_t;
1851 * get_cluster_count_for_direntry() not only determines how many clusters
1852 * are occupied by direntry, but also if it was renamed or modified.
1854 * A file is thought to be renamed *only* if there already was a file with
1855 * exactly the same first cluster, but a different name.
1857 * Further, the files/directories handled by this function are
1858 * assumed to be *not* deleted (and *only* those).
1860 static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
1861 direntry_t* direntry, const char* path)
1864 * This is a little bit tricky:
1865 * IF the guest OS just inserts a cluster into the file chain,
1866 * and leaves the rest alone, (i.e. the original file had clusters
1867 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1869 * - do_commit will write the cluster into the file at the given
1870 * offset, but
1872 * - the cluster which is overwritten should be moved to a later
1873 * position in the file.
1875 * I am not aware that any OS does something as braindead, but this
1876 * situation could happen anyway when not committing for a long time.
1877 * Just to be sure that this does not bite us, detect it, and copy the
1878 * contents of the clusters to-be-overwritten into the qcow.
1880 int copy_it = 0;
1881 int was_modified = 0;
1882 int32_t ret = 0;
1884 uint32_t cluster_num = begin_of_direntry(direntry);
1885 uint32_t offset = 0;
1886 int first_mapping_index = -1;
1887 mapping_t* mapping = NULL;
1888 const char* basename2 = NULL;
1890 vvfat_close_current_file(s);
1892 /* the root directory */
1893 if (cluster_num == 0)
1894 return 0;
1896 /* write support */
1897 if (s->qcow) {
1898 basename2 = get_basename(path);
1900 mapping = find_mapping_for_cluster(s, cluster_num);
1902 if (mapping) {
1903 const char* basename;
1905 assert(mapping->mode & MODE_DELETED);
1906 mapping->mode &= ~MODE_DELETED;
1908 basename = get_basename(mapping->path);
1910 assert(mapping->mode & MODE_NORMAL);
1912 /* rename */
1913 if (strcmp(basename, basename2))
1914 schedule_rename(s, cluster_num, g_strdup(path));
1915 } else if (is_file(direntry))
1916 /* new file */
1917 schedule_new_file(s, g_strdup(path), cluster_num);
1918 else {
1919 abort();
1920 return 0;
1924 while(1) {
1925 if (s->qcow) {
1926 if (!copy_it && cluster_was_modified(s, cluster_num)) {
1927 if (mapping == NULL ||
1928 mapping->begin > cluster_num ||
1929 mapping->end <= cluster_num)
1930 mapping = find_mapping_for_cluster(s, cluster_num);
1933 if (mapping &&
1934 (mapping->mode & MODE_DIRECTORY) == 0) {
1936 /* was modified in qcow */
1937 if (offset != mapping->info.file.offset + s->cluster_size
1938 * (cluster_num - mapping->begin)) {
1939 /* offset of this cluster in file chain has changed */
1940 abort();
1941 copy_it = 1;
1942 } else if (offset == 0) {
1943 const char* basename = get_basename(mapping->path);
1945 if (strcmp(basename, basename2))
1946 copy_it = 1;
1947 first_mapping_index = array_index(&(s->mapping), mapping);
1950 if (mapping->first_mapping_index != first_mapping_index
1951 && mapping->info.file.offset > 0) {
1952 abort();
1953 copy_it = 1;
1956 /* need to write out? */
1957 if (!was_modified && is_file(direntry)) {
1958 was_modified = 1;
1959 schedule_writeout(s, mapping->dir_index, offset);
1964 if (copy_it) {
1965 int i;
1967 * This is horribly inefficient, but that is okay, since
1968 * it is rarely executed, if at all.
1970 int64_t offset = cluster2sector(s, cluster_num);
1972 vvfat_close_current_file(s);
1973 for (i = 0; i < s->sectors_per_cluster; i++) {
1974 int res;
1976 res = bdrv_is_allocated(s->qcow->bs,
1977 (offset + i) * BDRV_SECTOR_SIZE,
1978 BDRV_SECTOR_SIZE, NULL);
1979 if (res < 0) {
1980 return -1;
1982 if (!res) {
1983 res = vvfat_read(s->bs, offset, s->cluster_buffer, 1);
1984 if (res) {
1985 return -1;
1987 res = bdrv_pwrite(s->qcow, offset * BDRV_SECTOR_SIZE,
1988 s->cluster_buffer, BDRV_SECTOR_SIZE);
1989 if (res < 0) {
1990 return -2;
1997 ret++;
1998 if (s->used_clusters[cluster_num] & USED_ANY)
1999 return 0;
2000 s->used_clusters[cluster_num] = USED_FILE;
2002 cluster_num = modified_fat_get(s, cluster_num);
2004 if (fat_eof(s, cluster_num))
2005 return ret;
2006 else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
2007 return -1;
2009 offset += s->cluster_size;
2014 * This function looks at the modified data (qcow).
2015 * It returns 0 upon inconsistency or error, and the number of clusters
2016 * used by the directory, its subdirectories and their files.
2018 static int check_directory_consistency(BDRVVVFATState *s,
2019 int cluster_num, const char* path)
2021 int ret = 0;
2022 unsigned char* cluster = g_malloc(s->cluster_size);
2023 direntry_t* direntries = (direntry_t*)cluster;
2024 mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
2026 long_file_name lfn;
2027 int path_len = strlen(path);
2028 char path2[PATH_MAX + 1];
2030 assert(path_len < PATH_MAX); /* len was tested before! */
2031 pstrcpy(path2, sizeof(path2), path);
2032 path2[path_len] = '/';
2033 path2[path_len + 1] = '\0';
2035 if (mapping) {
2036 const char* basename = get_basename(mapping->path);
2037 const char* basename2 = get_basename(path);
2039 assert(mapping->mode & MODE_DIRECTORY);
2041 assert(mapping->mode & MODE_DELETED);
2042 mapping->mode &= ~MODE_DELETED;
2044 if (strcmp(basename, basename2))
2045 schedule_rename(s, cluster_num, g_strdup(path));
2046 } else
2047 /* new directory */
2048 schedule_mkdir(s, cluster_num, g_strdup(path));
2050 lfn_init(&lfn);
2051 do {
2052 int i;
2053 int subret = 0;
2055 ret++;
2057 if (s->used_clusters[cluster_num] & USED_ANY) {
2058 fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
2059 goto fail;
2061 s->used_clusters[cluster_num] = USED_DIRECTORY;
2063 DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
2064 subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
2065 s->sectors_per_cluster);
2066 if (subret) {
2067 fprintf(stderr, "Error fetching direntries\n");
2068 fail:
2069 g_free(cluster);
2070 return 0;
2073 for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
2074 int cluster_count = 0;
2076 DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i));
2077 if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
2078 is_free(direntries + i))
2079 continue;
2081 subret = parse_long_name(&lfn, direntries + i);
2082 if (subret < 0) {
2083 fprintf(stderr, "Error in long name\n");
2084 goto fail;
2086 if (subret == 0 || is_free(direntries + i))
2087 continue;
2089 if (fat_chksum(direntries+i) != lfn.checksum) {
2090 subret = parse_short_name(s, &lfn, direntries + i);
2091 if (subret < 0) {
2092 fprintf(stderr, "Error in short name (%d)\n", subret);
2093 goto fail;
2095 if (subret > 0 || !strcmp((char*)lfn.name, ".")
2096 || !strcmp((char*)lfn.name, ".."))
2097 continue;
2099 lfn.checksum = 0x100; /* cannot use long name twice */
2101 if (path_len + 1 + lfn.len >= PATH_MAX) {
2102 fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
2103 goto fail;
2105 pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
2106 (char*)lfn.name);
2108 if (is_directory(direntries + i)) {
2109 if (begin_of_direntry(direntries + i) == 0) {
2110 DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
2111 goto fail;
2113 cluster_count = check_directory_consistency(s,
2114 begin_of_direntry(direntries + i), path2);
2115 if (cluster_count == 0) {
2116 DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
2117 goto fail;
2119 } else if (is_file(direntries + i)) {
2120 /* check file size with FAT */
2121 cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
2122 if (cluster_count !=
2123 DIV_ROUND_UP(le32_to_cpu(direntries[i].size), s->cluster_size)) {
2124 DLOG(fprintf(stderr, "Cluster count mismatch\n"));
2125 goto fail;
2127 } else
2128 abort(); /* cluster_count = 0; */
2130 ret += cluster_count;
2133 cluster_num = modified_fat_get(s, cluster_num);
2134 } while(!fat_eof(s, cluster_num));
2136 g_free(cluster);
2137 return ret;
2140 /* returns 1 on success */
2141 static int is_consistent(BDRVVVFATState* s)
2143 int i, check;
2144 int used_clusters_count = 0;
2146 DLOG(checkpoint());
2148 * - get modified FAT
2149 * - compare the two FATs (TODO)
2150 * - get buffer for marking used clusters
2151 * - recurse direntries from root (using bs->bdrv_read to make
2152 * sure to get the new data)
2153 * - check that the FAT agrees with the size
2154 * - count the number of clusters occupied by this directory and
2155 * its files
2156 * - check that the cumulative used cluster count agrees with the
2157 * FAT
2158 * - if all is fine, return number of used clusters
2160 if (s->fat2 == NULL) {
2161 int size = 0x200 * s->sectors_per_fat;
2162 s->fat2 = g_malloc(size);
2163 memcpy(s->fat2, s->fat.pointer, size);
2165 check = vvfat_read(s->bs,
2166 s->offset_to_fat, s->fat2, s->sectors_per_fat);
2167 if (check) {
2168 fprintf(stderr, "Could not copy fat\n");
2169 return 0;
2171 assert (s->used_clusters);
2172 for (i = 0; i < sector2cluster(s, s->sector_count); i++)
2173 s->used_clusters[i] &= ~USED_ANY;
2175 clear_commits(s);
2177 /* mark every mapped file/directory as deleted.
2178 * (check_directory_consistency() will unmark those still present). */
2179 if (s->qcow)
2180 for (i = 0; i < s->mapping.next; i++) {
2181 mapping_t* mapping = array_get(&(s->mapping), i);
2182 if (mapping->first_mapping_index < 0)
2183 mapping->mode |= MODE_DELETED;
2186 used_clusters_count = check_directory_consistency(s, 0, s->path);
2187 if (used_clusters_count <= 0) {
2188 DLOG(fprintf(stderr, "problem in directory\n"));
2189 return 0;
2192 check = s->last_cluster_of_root_directory;
2193 for (i = check; i < sector2cluster(s, s->sector_count); i++) {
2194 if (modified_fat_get(s, i)) {
2195 if(!s->used_clusters[i]) {
2196 DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
2197 return 0;
2199 check++;
2202 if (s->used_clusters[i] == USED_ALLOCATED) {
2203 /* allocated, but not used... */
2204 DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
2205 return 0;
2209 if (check != used_clusters_count)
2210 return 0;
2212 return used_clusters_count;
2215 static inline void adjust_mapping_indices(BDRVVVFATState* s,
2216 int offset, int adjust)
2218 int i;
2220 for (i = 0; i < s->mapping.next; i++) {
2221 mapping_t* mapping = array_get(&(s->mapping), i);
2223 #define ADJUST_MAPPING_INDEX(name) \
2224 if (mapping->name >= offset) \
2225 mapping->name += adjust
2227 ADJUST_MAPPING_INDEX(first_mapping_index);
2228 if (mapping->mode & MODE_DIRECTORY)
2229 ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
2233 /* insert or update mapping */
2234 static mapping_t* insert_mapping(BDRVVVFATState* s,
2235 uint32_t begin, uint32_t end)
2238 * - find mapping where mapping->begin >= begin,
2239 * - if mapping->begin > begin: insert
2240 * - adjust all references to mappings!
2241 * - else: adjust
2242 * - replace name
2244 int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
2245 mapping_t* mapping = NULL;
2246 mapping_t* first_mapping = array_get(&(s->mapping), 0);
2248 if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
2249 && mapping->begin < begin) {
2250 mapping->end = begin;
2251 index++;
2252 mapping = array_get(&(s->mapping), index);
2254 if (index >= s->mapping.next || mapping->begin > begin) {
2255 mapping = array_insert(&(s->mapping), index, 1);
2256 mapping->path = NULL;
2257 adjust_mapping_indices(s, index, +1);
2260 mapping->begin = begin;
2261 mapping->end = end;
2263 DLOG(mapping_t* next_mapping;
2264 assert(index + 1 >= s->mapping.next ||
2265 ((next_mapping = array_get(&(s->mapping), index + 1)) &&
2266 next_mapping->begin >= end)));
2268 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
2269 s->current_mapping = array_get(&(s->mapping),
2270 s->current_mapping - first_mapping);
2272 return mapping;
2275 static int remove_mapping(BDRVVVFATState* s, int mapping_index)
2277 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
2278 mapping_t* first_mapping = array_get(&(s->mapping), 0);
2280 /* free mapping */
2281 if (mapping->first_mapping_index < 0) {
2282 g_free(mapping->path);
2285 /* remove from s->mapping */
2286 array_remove(&(s->mapping), mapping_index);
2288 /* adjust all references to mappings */
2289 adjust_mapping_indices(s, mapping_index, -1);
2291 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
2292 s->current_mapping = array_get(&(s->mapping),
2293 s->current_mapping - first_mapping);
2295 return 0;
2298 static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
2300 int i;
2301 for (i = 0; i < s->mapping.next; i++) {
2302 mapping_t* mapping = array_get(&(s->mapping), i);
2303 if (mapping->dir_index >= offset)
2304 mapping->dir_index += adjust;
2305 if ((mapping->mode & MODE_DIRECTORY) &&
2306 mapping->info.dir.first_dir_index >= offset)
2307 mapping->info.dir.first_dir_index += adjust;
2311 static direntry_t* insert_direntries(BDRVVVFATState* s,
2312 int dir_index, int count)
2315 * make room in s->directory,
2316 * adjust_dirindices
2318 direntry_t* result = array_insert(&(s->directory), dir_index, count);
2319 if (result == NULL)
2320 return NULL;
2321 adjust_dirindices(s, dir_index, count);
2322 return result;
2325 static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
2327 int ret = array_remove_slice(&(s->directory), dir_index, count);
2328 if (ret)
2329 return ret;
2330 adjust_dirindices(s, dir_index, -count);
2331 return 0;
2335 * Adapt the mappings of the cluster chain starting at first cluster
2336 * (i.e. if a file starts at first_cluster, the chain is followed according
2337 * to the modified fat, and the corresponding entries in s->mapping are
2338 * adjusted)
2340 static int commit_mappings(BDRVVVFATState* s,
2341 uint32_t first_cluster, int dir_index)
2343 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2344 direntry_t* direntry = array_get(&(s->directory), dir_index);
2345 uint32_t cluster = first_cluster;
2347 vvfat_close_current_file(s);
2349 assert(mapping);
2350 assert(mapping->begin == first_cluster);
2351 mapping->first_mapping_index = -1;
2352 mapping->dir_index = dir_index;
2353 mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2354 MODE_DIRECTORY : MODE_NORMAL;
2356 while (!fat_eof(s, cluster)) {
2357 uint32_t c, c1;
2359 for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2360 c = c1, c1 = modified_fat_get(s, c1));
2362 c++;
2363 if (c > mapping->end) {
2364 int index = array_index(&(s->mapping), mapping);
2365 int i, max_i = s->mapping.next - index;
2366 for (i = 1; i < max_i && mapping[i].begin < c; i++);
2367 while (--i > 0)
2368 remove_mapping(s, index + 1);
2370 assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2371 || mapping[1].begin >= c);
2372 mapping->end = c;
2374 if (!fat_eof(s, c1)) {
2375 int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2376 mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2377 array_get(&(s->mapping), i);
2379 if (next_mapping == NULL || next_mapping->begin > c1) {
2380 int i1 = array_index(&(s->mapping), mapping);
2382 next_mapping = insert_mapping(s, c1, c1+1);
2384 if (c1 < c)
2385 i1++;
2386 mapping = array_get(&(s->mapping), i1);
2389 next_mapping->dir_index = mapping->dir_index;
2390 next_mapping->first_mapping_index =
2391 mapping->first_mapping_index < 0 ?
2392 array_index(&(s->mapping), mapping) :
2393 mapping->first_mapping_index;
2394 next_mapping->path = mapping->path;
2395 next_mapping->mode = mapping->mode;
2396 next_mapping->read_only = mapping->read_only;
2397 if (mapping->mode & MODE_DIRECTORY) {
2398 next_mapping->info.dir.parent_mapping_index =
2399 mapping->info.dir.parent_mapping_index;
2400 next_mapping->info.dir.first_dir_index =
2401 mapping->info.dir.first_dir_index +
2402 0x10 * s->sectors_per_cluster *
2403 (mapping->end - mapping->begin);
2404 } else
2405 next_mapping->info.file.offset = mapping->info.file.offset +
2406 mapping->end - mapping->begin;
2408 mapping = next_mapping;
2411 cluster = c1;
2414 return 0;
2417 static int commit_direntries(BDRVVVFATState* s,
2418 int dir_index, int parent_mapping_index)
2420 direntry_t* direntry = array_get(&(s->directory), dir_index);
2421 uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
2422 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2423 int factor = 0x10 * s->sectors_per_cluster;
2424 int old_cluster_count, new_cluster_count;
2425 int current_dir_index;
2426 int first_dir_index;
2427 int ret, i;
2428 uint32_t c;
2430 assert(direntry);
2431 assert(mapping);
2432 assert(mapping->begin == first_cluster);
2433 assert(mapping->info.dir.first_dir_index < s->directory.next);
2434 assert(mapping->mode & MODE_DIRECTORY);
2435 assert(dir_index == 0 || is_directory(direntry));
2437 DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n",
2438 mapping->path, parent_mapping_index));
2440 current_dir_index = mapping->info.dir.first_dir_index;
2441 first_dir_index = current_dir_index;
2442 mapping->info.dir.parent_mapping_index = parent_mapping_index;
2444 if (first_cluster == 0) {
2445 old_cluster_count = new_cluster_count =
2446 s->last_cluster_of_root_directory;
2447 } else {
2448 for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2449 c = fat_get(s, c))
2450 old_cluster_count++;
2452 for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2453 c = modified_fat_get(s, c))
2454 new_cluster_count++;
2457 if (new_cluster_count > old_cluster_count) {
2458 if (insert_direntries(s,
2459 current_dir_index + factor * old_cluster_count,
2460 factor * (new_cluster_count - old_cluster_count)) == NULL)
2461 return -1;
2462 } else if (new_cluster_count < old_cluster_count)
2463 remove_direntries(s,
2464 current_dir_index + factor * new_cluster_count,
2465 factor * (old_cluster_count - new_cluster_count));
2467 for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
2468 direntry_t *first_direntry;
2469 void* direntry = array_get(&(s->directory), current_dir_index);
2470 int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2471 s->sectors_per_cluster);
2472 if (ret)
2473 return ret;
2475 /* The first directory entry on the filesystem is the volume name */
2476 first_direntry = (direntry_t*) s->directory.pointer;
2477 assert(!memcmp(first_direntry->name, s->volume_label, 11));
2479 current_dir_index += factor;
2482 ret = commit_mappings(s, first_cluster, dir_index);
2483 if (ret)
2484 return ret;
2486 /* recurse */
2487 for (i = 0; i < factor * new_cluster_count; i++) {
2488 direntry = array_get(&(s->directory), first_dir_index + i);
2489 if (is_directory(direntry) && !is_dot(direntry)) {
2490 mapping = find_mapping_for_cluster(s, first_cluster);
2491 if (mapping == NULL) {
2492 return -1;
2494 assert(mapping->mode & MODE_DIRECTORY);
2495 ret = commit_direntries(s, first_dir_index + i,
2496 array_index(&(s->mapping), mapping));
2497 if (ret)
2498 return ret;
2502 return 0;
2505 /* commit one file (adjust contents, adjust mapping),
2506 return first_mapping_index */
2507 static int commit_one_file(BDRVVVFATState* s,
2508 int dir_index, uint32_t offset)
2510 direntry_t* direntry = array_get(&(s->directory), dir_index);
2511 uint32_t c = begin_of_direntry(direntry);
2512 uint32_t first_cluster = c;
2513 mapping_t* mapping = find_mapping_for_cluster(s, c);
2514 uint32_t size = filesize_of_direntry(direntry);
2515 char *cluster;
2516 uint32_t i;
2517 int fd = 0;
2519 assert(offset < size);
2520 assert((offset % s->cluster_size) == 0);
2522 if (mapping == NULL) {
2523 return -1;
2526 for (i = s->cluster_size; i < offset; i += s->cluster_size)
2527 c = modified_fat_get(s, c);
2529 fd = qemu_open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
2530 if (fd < 0) {
2531 fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2532 strerror(errno), errno);
2533 return fd;
2535 if (offset > 0) {
2536 if (lseek(fd, offset, SEEK_SET) != offset) {
2537 qemu_close(fd);
2538 return -3;
2542 cluster = g_malloc(s->cluster_size);
2544 while (offset < size) {
2545 uint32_t c1;
2546 int rest_size = (size - offset > s->cluster_size ?
2547 s->cluster_size : size - offset);
2548 int ret;
2550 c1 = modified_fat_get(s, c);
2552 assert((size - offset == 0 && fat_eof(s, c)) ||
2553 (size > offset && c >=2 && !fat_eof(s, c)));
2555 ret = vvfat_read(s->bs, cluster2sector(s, c),
2556 (uint8_t*)cluster, DIV_ROUND_UP(rest_size, 0x200));
2558 if (ret < 0) {
2559 qemu_close(fd);
2560 g_free(cluster);
2561 return ret;
2564 if (write(fd, cluster, rest_size) < 0) {
2565 qemu_close(fd);
2566 g_free(cluster);
2567 return -2;
2570 offset += rest_size;
2571 c = c1;
2574 if (ftruncate(fd, size)) {
2575 perror("ftruncate()");
2576 qemu_close(fd);
2577 g_free(cluster);
2578 return -4;
2580 qemu_close(fd);
2581 g_free(cluster);
2583 return commit_mappings(s, first_cluster, dir_index);
2586 #ifdef DEBUG
2587 /* test, if all mappings point to valid direntries */
2588 static void check1(BDRVVVFATState* s)
2590 int i;
2591 for (i = 0; i < s->mapping.next; i++) {
2592 mapping_t* mapping = array_get(&(s->mapping), i);
2593 if (mapping->mode & MODE_DELETED) {
2594 fprintf(stderr, "deleted\n");
2595 continue;
2597 assert(mapping->dir_index < s->directory.next);
2598 direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2599 assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2600 if (mapping->mode & MODE_DIRECTORY) {
2601 assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2602 assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2607 /* test, if all direntries have mappings */
2608 static void check2(BDRVVVFATState* s)
2610 int i;
2611 int first_mapping = -1;
2613 for (i = 0; i < s->directory.next; i++) {
2614 direntry_t* direntry = array_get(&(s->directory), i);
2616 if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2617 mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2618 assert(mapping);
2619 assert(mapping->dir_index == i || is_dot(direntry));
2620 assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2623 if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2624 /* cluster start */
2625 int j, count = 0;
2627 for (j = 0; j < s->mapping.next; j++) {
2628 mapping_t* mapping = array_get(&(s->mapping), j);
2629 if (mapping->mode & MODE_DELETED)
2630 continue;
2631 if (mapping->mode & MODE_DIRECTORY) {
2632 if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2633 assert(++count == 1);
2634 if (mapping->first_mapping_index == -1)
2635 first_mapping = array_index(&(s->mapping), mapping);
2636 else
2637 assert(first_mapping == mapping->first_mapping_index);
2638 if (mapping->info.dir.parent_mapping_index < 0)
2639 assert(j == 0);
2640 else {
2641 mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2642 assert(parent->mode & MODE_DIRECTORY);
2643 assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2648 if (count == 0)
2649 first_mapping = -1;
2653 #endif
2655 static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2657 int i;
2659 #ifdef DEBUG
2660 fprintf(stderr, "handle_renames\n");
2661 for (i = 0; i < s->commits.next; i++) {
2662 commit_t* commit = array_get(&(s->commits), i);
2663 fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
2665 #endif
2667 for (i = 0; i < s->commits.next;) {
2668 commit_t* commit = array_get(&(s->commits), i);
2669 if (commit->action == ACTION_RENAME) {
2670 mapping_t* mapping = find_mapping_for_cluster(s,
2671 commit->param.rename.cluster);
2672 char *old_path;
2674 if (mapping == NULL) {
2675 return -1;
2677 old_path = mapping->path;
2678 assert(commit->path);
2679 mapping->path = commit->path;
2680 if (rename(old_path, mapping->path))
2681 return -2;
2683 if (mapping->mode & MODE_DIRECTORY) {
2684 int l1 = strlen(mapping->path);
2685 int l2 = strlen(old_path);
2686 int diff = l1 - l2;
2687 direntry_t* direntry = array_get(&(s->directory),
2688 mapping->info.dir.first_dir_index);
2689 uint32_t c = mapping->begin;
2690 int i = 0;
2692 /* recurse */
2693 while (!fat_eof(s, c)) {
2694 do {
2695 direntry_t* d = direntry + i;
2697 if (is_file(d) || (is_directory(d) && !is_dot(d))) {
2698 int l;
2699 char *new_path;
2700 mapping_t* m = find_mapping_for_cluster(s,
2701 begin_of_direntry(d));
2702 if (m == NULL) {
2703 return -1;
2705 l = strlen(m->path);
2706 new_path = g_malloc(l + diff + 1);
2708 assert(!strncmp(m->path, mapping->path, l2));
2710 pstrcpy(new_path, l + diff + 1, mapping->path);
2711 pstrcpy(new_path + l1, l + diff + 1 - l1,
2712 m->path + l2);
2714 schedule_rename(s, m->begin, new_path);
2716 i++;
2717 } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2718 c = fat_get(s, c);
2722 g_free(old_path);
2723 array_remove(&(s->commits), i);
2724 continue;
2725 } else if (commit->action == ACTION_MKDIR) {
2726 mapping_t* mapping;
2727 int j, parent_path_len;
2729 #ifdef __MINGW32__
2730 if (mkdir(commit->path))
2731 return -5;
2732 #else
2733 if (mkdir(commit->path, 0755))
2734 return -5;
2735 #endif
2737 mapping = insert_mapping(s, commit->param.mkdir.cluster,
2738 commit->param.mkdir.cluster + 1);
2739 if (mapping == NULL)
2740 return -6;
2742 mapping->mode = MODE_DIRECTORY;
2743 mapping->read_only = 0;
2744 mapping->path = commit->path;
2745 j = s->directory.next;
2746 assert(j);
2747 insert_direntries(s, s->directory.next,
2748 0x10 * s->sectors_per_cluster);
2749 mapping->info.dir.first_dir_index = j;
2751 parent_path_len = strlen(commit->path)
2752 - strlen(get_basename(commit->path)) - 1;
2753 for (j = 0; j < s->mapping.next; j++) {
2754 mapping_t* m = array_get(&(s->mapping), j);
2755 if (m->first_mapping_index < 0 && m != mapping &&
2756 !strncmp(m->path, mapping->path, parent_path_len) &&
2757 strlen(m->path) == parent_path_len)
2758 break;
2760 assert(j < s->mapping.next);
2761 mapping->info.dir.parent_mapping_index = j;
2763 array_remove(&(s->commits), i);
2764 continue;
2767 i++;
2769 return 0;
2773 * TODO: make sure that the short name is not matching *another* file
2775 static int handle_commits(BDRVVVFATState* s)
2777 int i, fail = 0;
2779 vvfat_close_current_file(s);
2781 for (i = 0; !fail && i < s->commits.next; i++) {
2782 commit_t* commit = array_get(&(s->commits), i);
2783 switch(commit->action) {
2784 case ACTION_RENAME: case ACTION_MKDIR:
2785 abort();
2786 fail = -2;
2787 break;
2788 case ACTION_WRITEOUT: {
2789 #ifndef NDEBUG
2790 /* these variables are only used by assert() below */
2791 direntry_t* entry = array_get(&(s->directory),
2792 commit->param.writeout.dir_index);
2793 uint32_t begin = begin_of_direntry(entry);
2794 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2795 #endif
2797 assert(mapping);
2798 assert(mapping->begin == begin);
2799 assert(commit->path == NULL);
2801 if (commit_one_file(s, commit->param.writeout.dir_index,
2802 commit->param.writeout.modified_offset))
2803 fail = -3;
2805 break;
2807 case ACTION_NEW_FILE: {
2808 int begin = commit->param.new_file.first_cluster;
2809 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2810 direntry_t* entry;
2811 int i;
2813 /* find direntry */
2814 for (i = 0; i < s->directory.next; i++) {
2815 entry = array_get(&(s->directory), i);
2816 if (is_file(entry) && begin_of_direntry(entry) == begin)
2817 break;
2820 if (i >= s->directory.next) {
2821 fail = -6;
2822 continue;
2825 /* make sure there exists an initial mapping */
2826 if (mapping && mapping->begin != begin) {
2827 mapping->end = begin;
2828 mapping = NULL;
2830 if (mapping == NULL) {
2831 mapping = insert_mapping(s, begin, begin+1);
2833 /* most members will be fixed in commit_mappings() */
2834 assert(commit->path);
2835 mapping->path = commit->path;
2836 mapping->read_only = 0;
2837 mapping->mode = MODE_NORMAL;
2838 mapping->info.file.offset = 0;
2840 if (commit_one_file(s, i, 0))
2841 fail = -7;
2843 break;
2845 default:
2846 abort();
2849 if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2850 return -1;
2851 return fail;
2854 static int handle_deletes(BDRVVVFATState* s)
2856 int i, deferred = 1, deleted = 1;
2858 /* delete files corresponding to mappings marked as deleted */
2859 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2860 while (deferred && deleted) {
2861 deferred = 0;
2862 deleted = 0;
2864 for (i = 1; i < s->mapping.next; i++) {
2865 mapping_t* mapping = array_get(&(s->mapping), i);
2866 if (mapping->mode & MODE_DELETED) {
2867 direntry_t* entry = array_get(&(s->directory),
2868 mapping->dir_index);
2870 if (is_free(entry)) {
2871 /* remove file/directory */
2872 if (mapping->mode & MODE_DIRECTORY) {
2873 int j, next_dir_index = s->directory.next,
2874 first_dir_index = mapping->info.dir.first_dir_index;
2876 if (rmdir(mapping->path) < 0) {
2877 if (errno == ENOTEMPTY) {
2878 deferred++;
2879 continue;
2880 } else
2881 return -5;
2884 for (j = 1; j < s->mapping.next; j++) {
2885 mapping_t* m = array_get(&(s->mapping), j);
2886 if (m->mode & MODE_DIRECTORY &&
2887 m->info.dir.first_dir_index >
2888 first_dir_index &&
2889 m->info.dir.first_dir_index <
2890 next_dir_index)
2891 next_dir_index =
2892 m->info.dir.first_dir_index;
2894 remove_direntries(s, first_dir_index,
2895 next_dir_index - first_dir_index);
2897 deleted++;
2899 } else {
2900 if (unlink(mapping->path))
2901 return -4;
2902 deleted++;
2904 DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2905 remove_mapping(s, i);
2910 return 0;
2914 * synchronize mapping with new state:
2916 * - copy FAT (with bdrv_read)
2917 * - mark all filenames corresponding to mappings as deleted
2918 * - recurse direntries from root (using bs->bdrv_read)
2919 * - delete files corresponding to mappings marked as deleted
2921 static int do_commit(BDRVVVFATState* s)
2923 int ret = 0;
2925 /* the real meat are the commits. Nothing to do? Move along! */
2926 if (s->commits.next == 0)
2927 return 0;
2929 vvfat_close_current_file(s);
2931 ret = handle_renames_and_mkdirs(s);
2932 if (ret) {
2933 fprintf(stderr, "Error handling renames (%d)\n", ret);
2934 abort();
2935 return ret;
2938 /* copy FAT (with bdrv_read) */
2939 memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2941 /* recurse direntries from root (using bs->bdrv_read) */
2942 ret = commit_direntries(s, 0, -1);
2943 if (ret) {
2944 fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
2945 abort();
2946 return ret;
2949 ret = handle_commits(s);
2950 if (ret) {
2951 fprintf(stderr, "Error handling commits (%d)\n", ret);
2952 abort();
2953 return ret;
2956 ret = handle_deletes(s);
2957 if (ret) {
2958 fprintf(stderr, "Error deleting\n");
2959 abort();
2960 return ret;
2963 if (s->qcow->bs->drv && s->qcow->bs->drv->bdrv_make_empty) {
2964 s->qcow->bs->drv->bdrv_make_empty(s->qcow->bs);
2967 memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2969 DLOG(checkpoint());
2970 return 0;
2973 static int try_commit(BDRVVVFATState* s)
2975 vvfat_close_current_file(s);
2976 DLOG(checkpoint());
2977 if(!is_consistent(s))
2978 return -1;
2979 return do_commit(s);
2982 static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
2983 const uint8_t *buf, int nb_sectors)
2985 BDRVVVFATState *s = bs->opaque;
2986 int i, ret;
2988 DLOG(checkpoint());
2990 /* Check if we're operating in read-only mode */
2991 if (s->qcow == NULL) {
2992 return -EACCES;
2995 vvfat_close_current_file(s);
2998 * Some sanity checks:
2999 * - do not allow writing to the boot sector
3002 if (sector_num < s->offset_to_fat)
3003 return -1;
3005 for (i = sector2cluster(s, sector_num);
3006 i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
3007 mapping_t* mapping = find_mapping_for_cluster(s, i);
3008 if (mapping) {
3009 if (mapping->read_only) {
3010 fprintf(stderr, "Tried to write to write-protected file %s\n",
3011 mapping->path);
3012 return -1;
3015 if (mapping->mode & MODE_DIRECTORY) {
3016 int begin = cluster2sector(s, i);
3017 int end = begin + s->sectors_per_cluster, k;
3018 int dir_index;
3019 const direntry_t* direntries;
3020 long_file_name lfn;
3022 lfn_init(&lfn);
3024 if (begin < sector_num)
3025 begin = sector_num;
3026 if (end > sector_num + nb_sectors)
3027 end = sector_num + nb_sectors;
3028 dir_index = mapping->dir_index +
3029 0x10 * (begin - mapping->begin * s->sectors_per_cluster);
3030 direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
3032 for (k = 0; k < (end - begin) * 0x10; k++) {
3033 /* no access to the direntry of a read-only file */
3034 if (is_short_name(direntries + k) &&
3035 (direntries[k].attributes & 1)) {
3036 if (memcmp(direntries + k,
3037 array_get(&(s->directory), dir_index + k),
3038 sizeof(direntry_t))) {
3039 warn_report("tried to write to write-protected "
3040 "file");
3041 return -1;
3046 i = mapping->end;
3047 } else
3048 i++;
3052 * Use qcow backend. Commit later.
3054 DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
3055 ret = bdrv_pwrite(s->qcow, sector_num * BDRV_SECTOR_SIZE, buf,
3056 nb_sectors * BDRV_SECTOR_SIZE);
3057 if (ret < 0) {
3058 fprintf(stderr, "Error writing to qcow backend\n");
3059 return ret;
3062 for (i = sector2cluster(s, sector_num);
3063 i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
3064 if (i >= 0)
3065 s->used_clusters[i] |= USED_ALLOCATED;
3067 DLOG(checkpoint());
3068 /* TODO: add timeout */
3069 try_commit(s);
3071 DLOG(checkpoint());
3072 return 0;
3075 static int coroutine_fn
3076 vvfat_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
3077 QEMUIOVector *qiov, int flags)
3079 int ret;
3080 BDRVVVFATState *s = bs->opaque;
3081 uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
3082 int nb_sectors = bytes >> BDRV_SECTOR_BITS;
3083 void *buf;
3085 assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
3086 assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
3088 buf = g_try_malloc(bytes);
3089 if (bytes && buf == NULL) {
3090 return -ENOMEM;
3092 qemu_iovec_to_buf(qiov, 0, buf, bytes);
3094 qemu_co_mutex_lock(&s->lock);
3095 ret = vvfat_write(bs, sector_num, buf, nb_sectors);
3096 qemu_co_mutex_unlock(&s->lock);
3098 g_free(buf);
3100 return ret;
3103 static int coroutine_fn vvfat_co_block_status(BlockDriverState *bs,
3104 bool want_zero, int64_t offset,
3105 int64_t bytes, int64_t *n,
3106 int64_t *map,
3107 BlockDriverState **file)
3109 *n = bytes;
3110 return BDRV_BLOCK_DATA;
3113 static int coroutine_fn
3114 write_target_commit(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
3115 QEMUIOVector *qiov, int flags)
3117 int ret;
3119 BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
3120 qemu_co_mutex_lock(&s->lock);
3121 ret = try_commit(s);
3122 qemu_co_mutex_unlock(&s->lock);
3124 return ret;
3127 static void write_target_close(BlockDriverState *bs) {
3128 BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
3129 bdrv_unref_child(s->bs, s->qcow);
3130 g_free(s->qcow_filename);
3133 static BlockDriver vvfat_write_target = {
3134 .format_name = "vvfat_write_target",
3135 .instance_size = sizeof(void*),
3136 .bdrv_co_pwritev = write_target_commit,
3137 .bdrv_close = write_target_close,
3140 static void vvfat_qcow_options(int *child_flags, QDict *child_options,
3141 int parent_flags, QDict *parent_options)
3143 qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off");
3144 qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off");
3145 qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on");
3148 static const BdrvChildRole child_vvfat_qcow = {
3149 .parent_is_bds = true,
3150 .inherit_options = vvfat_qcow_options,
3153 static int enable_write_target(BlockDriverState *bs, Error **errp)
3155 BDRVVVFATState *s = bs->opaque;
3156 BlockDriver *bdrv_qcow = NULL;
3157 BlockDriverState *backing;
3158 QemuOpts *opts = NULL;
3159 int ret;
3160 int size = sector2cluster(s, s->sector_count);
3161 QDict *options;
3163 s->used_clusters = calloc(size, 1);
3165 array_init(&(s->commits), sizeof(commit_t));
3167 s->qcow_filename = g_malloc(PATH_MAX);
3168 ret = get_tmp_filename(s->qcow_filename, PATH_MAX);
3169 if (ret < 0) {
3170 error_setg_errno(errp, -ret, "can't create temporary file");
3171 goto err;
3174 bdrv_qcow = bdrv_find_format("qcow");
3175 if (!bdrv_qcow) {
3176 error_setg(errp, "Failed to locate qcow driver");
3177 ret = -ENOENT;
3178 goto err;
3181 opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort);
3182 qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512,
3183 &error_abort);
3184 qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:", &error_abort);
3186 ret = bdrv_create(bdrv_qcow, s->qcow_filename, opts, errp);
3187 qemu_opts_del(opts);
3188 if (ret < 0) {
3189 goto err;
3192 options = qdict_new();
3193 qdict_put_str(options, "write-target.driver", "qcow");
3194 s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs,
3195 &child_vvfat_qcow, false, errp);
3196 qobject_unref(options);
3197 if (!s->qcow) {
3198 ret = -EINVAL;
3199 goto err;
3202 #ifndef _WIN32
3203 unlink(s->qcow_filename);
3204 #endif
3206 backing = bdrv_new_open_driver(&vvfat_write_target, NULL, BDRV_O_ALLOW_RDWR,
3207 &error_abort);
3208 *(void**) backing->opaque = s;
3210 bdrv_set_backing_hd(s->bs, backing, &error_abort);
3211 bdrv_unref(backing);
3213 return 0;
3215 err:
3216 g_free(s->qcow_filename);
3217 s->qcow_filename = NULL;
3218 return ret;
3221 static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c,
3222 const BdrvChildRole *role,
3223 BlockReopenQueue *reopen_queue,
3224 uint64_t perm, uint64_t shared,
3225 uint64_t *nperm, uint64_t *nshared)
3227 BDRVVVFATState *s = bs->opaque;
3229 assert(c == s->qcow || role == &child_backing);
3231 if (c == s->qcow) {
3232 /* This is a private node, nobody should try to attach to it */
3233 *nperm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE;
3234 *nshared = BLK_PERM_WRITE_UNCHANGED;
3235 } else {
3236 /* The backing file is there so 'commit' can use it. vvfat doesn't
3237 * access it in any way. */
3238 *nperm = 0;
3239 *nshared = BLK_PERM_ALL;
3243 static void vvfat_close(BlockDriverState *bs)
3245 BDRVVVFATState *s = bs->opaque;
3247 vvfat_close_current_file(s);
3248 array_free(&(s->fat));
3249 array_free(&(s->directory));
3250 array_free(&(s->mapping));
3251 g_free(s->cluster_buffer);
3253 if (s->qcow) {
3254 migrate_del_blocker(s->migration_blocker);
3255 error_free(s->migration_blocker);
3259 static const char *const vvfat_strong_runtime_opts[] = {
3260 "dir",
3261 "fat-type",
3262 "floppy",
3263 "label",
3264 "rw",
3266 NULL
3269 static BlockDriver bdrv_vvfat = {
3270 .format_name = "vvfat",
3271 .protocol_name = "fat",
3272 .instance_size = sizeof(BDRVVVFATState),
3274 .bdrv_parse_filename = vvfat_parse_filename,
3275 .bdrv_file_open = vvfat_open,
3276 .bdrv_refresh_limits = vvfat_refresh_limits,
3277 .bdrv_close = vvfat_close,
3278 .bdrv_child_perm = vvfat_child_perm,
3280 .bdrv_co_preadv = vvfat_co_preadv,
3281 .bdrv_co_pwritev = vvfat_co_pwritev,
3282 .bdrv_co_block_status = vvfat_co_block_status,
3284 .strong_runtime_opts = vvfat_strong_runtime_opts,
3287 static void bdrv_vvfat_init(void)
3289 bdrv_register(&bdrv_vvfat);
3292 block_init(bdrv_vvfat_init);
3294 #ifdef DEBUG
3295 static void checkpoint(void)
3297 assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
3298 check1(vvv);
3299 check2(vvv);
3300 assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
3302 #endif