acpi: move declarations from pc.h to acpi.h
[qemu/ar7.git] / block / vvfat.c
blobef74c30bfed431a5d3b27b23f6ed8c4593c75857
1 /* vim:set shiftwidth=4 ts=8: */
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.
25 #include <sys/stat.h>
26 #include <dirent.h>
27 #include "qemu-common.h"
28 #include "block/block_int.h"
29 #include "qemu/module.h"
30 #include "migration/migration.h"
32 #ifndef S_IWGRP
33 #define S_IWGRP 0
34 #endif
35 #ifndef S_IWOTH
36 #define S_IWOTH 0
37 #endif
39 /* TODO: add ":bootsector=blabla.img:" */
40 /* LATER TODO: add automatic boot sector generation from
41 BOOTEASY.ASM and Ranish Partition Manager
42 Note that DOS assumes the system files to be the first files in the
43 file system (test if the boot sector still relies on that fact)! */
44 /* MAYBE TODO: write block-visofs.c */
45 /* TODO: call try_commit() only after a timeout */
47 /* #define DEBUG */
49 #ifdef DEBUG
51 #define DLOG(a) a
53 #undef stderr
54 #define stderr STDERR
55 FILE* stderr = NULL;
57 static void checkpoint(void);
59 #ifdef __MINGW32__
60 void nonono(const char* file, int line, const char* msg) {
61 fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg);
62 exit(-5);
64 #undef assert
65 #define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
66 #endif
68 #else
70 #define DLOG(a)
72 #endif
74 /* dynamic array functions */
75 typedef struct array_t {
76 char* pointer;
77 unsigned int size,next,item_size;
78 } array_t;
80 static inline void array_init(array_t* array,unsigned int item_size)
82 array->pointer = NULL;
83 array->size=0;
84 array->next=0;
85 array->item_size=item_size;
88 static inline void array_free(array_t* array)
90 g_free(array->pointer);
91 array->size=array->next=0;
94 /* does not automatically grow */
95 static inline void* array_get(array_t* array,unsigned int index) {
96 assert(index < array->next);
97 return array->pointer + index * array->item_size;
100 static inline int array_ensure_allocated(array_t* array, int index)
102 if((index + 1) * array->item_size > array->size) {
103 int new_size = (index + 32) * array->item_size;
104 array->pointer = g_realloc(array->pointer, new_size);
105 if (!array->pointer)
106 return -1;
107 array->size = new_size;
108 array->next = index + 1;
111 return 0;
114 static inline void* array_get_next(array_t* array) {
115 unsigned int next = array->next;
116 void* result;
118 if (array_ensure_allocated(array, next) < 0)
119 return NULL;
121 array->next = next + 1;
122 result = array_get(array, next);
124 return result;
127 static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
128 if((array->next+count)*array->item_size>array->size) {
129 int increment=count*array->item_size;
130 array->pointer=g_realloc(array->pointer,array->size+increment);
131 if(!array->pointer)
132 return NULL;
133 array->size+=increment;
135 memmove(array->pointer+(index+count)*array->item_size,
136 array->pointer+index*array->item_size,
137 (array->next-index)*array->item_size);
138 array->next+=count;
139 return array->pointer+index*array->item_size;
142 /* this performs a "roll", so that the element which was at index_from becomes
143 * index_to, but the order of all other elements is preserved. */
144 static inline int array_roll(array_t* array,int index_to,int index_from,int count)
146 char* buf;
147 char* from;
148 char* to;
149 int is;
151 if(!array ||
152 index_to<0 || index_to>=array->next ||
153 index_from<0 || index_from>=array->next)
154 return -1;
156 if(index_to==index_from)
157 return 0;
159 is=array->item_size;
160 from=array->pointer+index_from*is;
161 to=array->pointer+index_to*is;
162 buf=g_malloc(is*count);
163 memcpy(buf,from,is*count);
165 if(index_to<index_from)
166 memmove(to+is*count,to,from-to);
167 else
168 memmove(from,from+is*count,to-from);
170 memcpy(to,buf,is*count);
172 g_free(buf);
174 return 0;
177 static inline int array_remove_slice(array_t* array,int index, int count)
179 assert(index >=0);
180 assert(count > 0);
181 assert(index + count <= array->next);
182 if(array_roll(array,array->next-1,index,count))
183 return -1;
184 array->next -= count;
185 return 0;
188 static int array_remove(array_t* array,int index)
190 return array_remove_slice(array, index, 1);
193 /* return the index for a given member */
194 static int array_index(array_t* array, void* pointer)
196 size_t offset = (char*)pointer - array->pointer;
197 assert((offset % array->item_size) == 0);
198 assert(offset/array->item_size < array->next);
199 return offset/array->item_size;
202 /* These structures are used to fake a disk and the VFAT filesystem.
203 * For this reason we need to use QEMU_PACKED. */
205 typedef struct bootsector_t {
206 uint8_t jump[3];
207 uint8_t name[8];
208 uint16_t sector_size;
209 uint8_t sectors_per_cluster;
210 uint16_t reserved_sectors;
211 uint8_t number_of_fats;
212 uint16_t root_entries;
213 uint16_t total_sectors16;
214 uint8_t media_type;
215 uint16_t sectors_per_fat;
216 uint16_t sectors_per_track;
217 uint16_t number_of_heads;
218 uint32_t hidden_sectors;
219 uint32_t total_sectors;
220 union {
221 struct {
222 uint8_t drive_number;
223 uint8_t current_head;
224 uint8_t signature;
225 uint32_t id;
226 uint8_t volume_label[11];
227 } QEMU_PACKED fat16;
228 struct {
229 uint32_t sectors_per_fat;
230 uint16_t flags;
231 uint8_t major,minor;
232 uint32_t first_cluster_of_root_directory;
233 uint16_t info_sector;
234 uint16_t backup_boot_sector;
235 uint16_t ignored;
236 } QEMU_PACKED fat32;
237 } u;
238 uint8_t fat_type[8];
239 uint8_t ignored[0x1c0];
240 uint8_t magic[2];
241 } QEMU_PACKED bootsector_t;
243 typedef struct {
244 uint8_t head;
245 uint8_t sector;
246 uint8_t cylinder;
247 } mbr_chs_t;
249 typedef struct partition_t {
250 uint8_t attributes; /* 0x80 = bootable */
251 mbr_chs_t start_CHS;
252 uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
253 mbr_chs_t end_CHS;
254 uint32_t start_sector_long;
255 uint32_t length_sector_long;
256 } QEMU_PACKED partition_t;
258 typedef struct mbr_t {
259 uint8_t ignored[0x1b8];
260 uint32_t nt_id;
261 uint8_t ignored2[2];
262 partition_t partition[4];
263 uint8_t magic[2];
264 } QEMU_PACKED mbr_t;
266 typedef struct direntry_t {
267 uint8_t name[8];
268 uint8_t extension[3];
269 uint8_t attributes;
270 uint8_t reserved[2];
271 uint16_t ctime;
272 uint16_t cdate;
273 uint16_t adate;
274 uint16_t begin_hi;
275 uint16_t mtime;
276 uint16_t mdate;
277 uint16_t begin;
278 uint32_t size;
279 } QEMU_PACKED direntry_t;
281 /* this structure are used to transparently access the files */
283 typedef struct mapping_t {
284 /* begin is the first cluster, end is the last+1 */
285 uint32_t begin,end;
286 /* as s->directory is growable, no pointer may be used here */
287 unsigned int dir_index;
288 /* the clusters of a file may be in any order; this points to the first */
289 int first_mapping_index;
290 union {
291 /* offset is
292 * - the offset in the file (in clusters) for a file, or
293 * - the next cluster of the directory for a directory, and
294 * - the address of the buffer for a faked entry
296 struct {
297 uint32_t offset;
298 } file;
299 struct {
300 int parent_mapping_index;
301 int first_dir_index;
302 } dir;
303 } info;
304 /* path contains the full path, i.e. it always starts with s->path */
305 char* path;
307 enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2,
308 MODE_DIRECTORY = 4, MODE_FAKED = 8,
309 MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
310 int read_only;
311 } mapping_t;
313 #ifdef DEBUG
314 static void print_direntry(const struct direntry_t*);
315 static void print_mapping(const struct mapping_t* mapping);
316 #endif
318 /* here begins the real VVFAT driver */
320 typedef struct BDRVVVFATState {
321 CoMutex lock;
322 BlockDriverState* bs; /* pointer to parent */
323 unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
324 unsigned char first_sectors[0x40*0x200];
326 int fat_type; /* 16 or 32 */
327 array_t fat,directory,mapping;
329 unsigned int cluster_size;
330 unsigned int sectors_per_cluster;
331 unsigned int sectors_per_fat;
332 unsigned int sectors_of_root_directory;
333 uint32_t last_cluster_of_root_directory;
334 unsigned int faked_sectors; /* how many sectors are faked before file data */
335 uint32_t sector_count; /* total number of sectors of the partition */
336 uint32_t cluster_count; /* total number of clusters of this partition */
337 uint32_t max_fat_value;
339 int current_fd;
340 mapping_t* current_mapping;
341 unsigned char* cluster; /* points to current cluster */
342 unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
343 unsigned int current_cluster;
345 /* write support */
346 BlockDriverState* write_target;
347 char* qcow_filename;
348 BlockDriverState* qcow;
349 void* fat2;
350 char* used_clusters;
351 array_t commits;
352 const char* path;
353 int downcase_short_names;
355 Error *migration_blocker;
356 } BDRVVVFATState;
358 /* take the sector position spos and convert it to Cylinder/Head/Sector position
359 * if the position is outside the specified geometry, fill maximum value for CHS
360 * and return 1 to signal overflow.
362 static int sector2CHS(mbr_chs_t *chs, int spos, int cyls, int heads, int secs)
364 int head,sector;
365 sector = spos % secs; spos /= secs;
366 head = spos % heads; spos /= heads;
367 if (spos >= cyls) {
368 /* Overflow,
369 it happens if 32bit sector positions are used, while CHS is only 24bit.
370 Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
371 chs->head = 0xFF;
372 chs->sector = 0xFF;
373 chs->cylinder = 0xFF;
374 return 1;
376 chs->head = (uint8_t)head;
377 chs->sector = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
378 chs->cylinder = (uint8_t)spos;
379 return 0;
382 static void init_mbr(BDRVVVFATState *s, int cyls, int heads, int secs)
384 /* TODO: if the files mbr.img and bootsect.img exist, use them */
385 mbr_t* real_mbr=(mbr_t*)s->first_sectors;
386 partition_t* partition = &(real_mbr->partition[0]);
387 int lba;
389 memset(s->first_sectors,0,512);
391 /* Win NT Disk Signature */
392 real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
394 partition->attributes=0x80; /* bootable */
396 /* LBA is used when partition is outside the CHS geometry */
397 lba = sector2CHS(&partition->start_CHS, s->first_sectors_number - 1,
398 cyls, heads, secs);
399 lba |= sector2CHS(&partition->end_CHS, s->bs->total_sectors - 1,
400 cyls, heads, secs);
402 /*LBA partitions are identified only by start/length_sector_long not by CHS*/
403 partition->start_sector_long = cpu_to_le32(s->first_sectors_number - 1);
404 partition->length_sector_long = cpu_to_le32(s->bs->total_sectors
405 - s->first_sectors_number + 1);
407 /* FAT12/FAT16/FAT32 */
408 /* DOS uses different types when partition is LBA,
409 probably to prevent older versions from using CHS on them */
410 partition->fs_type= s->fat_type==12 ? 0x1:
411 s->fat_type==16 ? (lba?0xe:0x06):
412 /*fat_tyoe==32*/ (lba?0xc:0x0b);
414 real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
417 /* direntry functions */
419 /* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
420 static inline int short2long_name(char* dest,const char* src)
422 int i;
423 int len;
424 for(i=0;i<129 && src[i];i++) {
425 dest[2*i]=src[i];
426 dest[2*i+1]=0;
428 len=2*i;
429 dest[2*i]=dest[2*i+1]=0;
430 for(i=2*i+2;(i%26);i++)
431 dest[i]=0xff;
432 return len;
435 static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
437 char buffer[258];
438 int length=short2long_name(buffer,filename),
439 number_of_entries=(length+25)/26,i;
440 direntry_t* entry;
442 for(i=0;i<number_of_entries;i++) {
443 entry=array_get_next(&(s->directory));
444 entry->attributes=0xf;
445 entry->reserved[0]=0;
446 entry->begin=0;
447 entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
449 for(i=0;i<26*number_of_entries;i++) {
450 int offset=(i%26);
451 if(offset<10) offset=1+offset;
452 else if(offset<22) offset=14+offset-10;
453 else offset=28+offset-22;
454 entry=array_get(&(s->directory),s->directory.next-1-(i/26));
455 entry->name[offset]=buffer[i];
457 return array_get(&(s->directory),s->directory.next-number_of_entries);
460 static char is_free(const direntry_t* direntry)
462 return direntry->name[0]==0xe5 || direntry->name[0]==0x00;
465 static char is_volume_label(const direntry_t* direntry)
467 return direntry->attributes == 0x28;
470 static char is_long_name(const direntry_t* direntry)
472 return direntry->attributes == 0xf;
475 static char is_short_name(const direntry_t* direntry)
477 return !is_volume_label(direntry) && !is_long_name(direntry)
478 && !is_free(direntry);
481 static char is_directory(const direntry_t* direntry)
483 return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
486 static inline char is_dot(const direntry_t* direntry)
488 return is_short_name(direntry) && direntry->name[0] == '.';
491 static char is_file(const direntry_t* direntry)
493 return is_short_name(direntry) && !is_directory(direntry);
496 static inline uint32_t begin_of_direntry(const direntry_t* direntry)
498 return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
501 static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
503 return le32_to_cpu(direntry->size);
506 static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
508 direntry->begin = cpu_to_le16(begin & 0xffff);
509 direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
512 /* fat functions */
514 static inline uint8_t fat_chksum(const direntry_t* entry)
516 uint8_t chksum=0;
517 int i;
519 for(i=0;i<11;i++) {
520 unsigned char c;
522 c = (i < 8) ? entry->name[i] : entry->extension[i-8];
523 chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0)) + c;
526 return chksum;
529 /* if return_time==0, this returns the fat_date, else the fat_time */
530 static uint16_t fat_datetime(time_t time,int return_time) {
531 struct tm* t;
532 struct tm t1;
533 t = &t1;
534 localtime_r(&time,t);
535 if(return_time)
536 return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
537 return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
540 static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
542 if(s->fat_type==32) {
543 uint32_t* entry=array_get(&(s->fat),cluster);
544 *entry=cpu_to_le32(value);
545 } else if(s->fat_type==16) {
546 uint16_t* entry=array_get(&(s->fat),cluster);
547 *entry=cpu_to_le16(value&0xffff);
548 } else {
549 int offset = (cluster*3/2);
550 unsigned char* p = array_get(&(s->fat), offset);
551 switch (cluster&1) {
552 case 0:
553 p[0] = value&0xff;
554 p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
555 break;
556 case 1:
557 p[0] = (p[0]&0xf) | ((value&0xf)<<4);
558 p[1] = (value>>4);
559 break;
564 static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
566 if(s->fat_type==32) {
567 uint32_t* entry=array_get(&(s->fat),cluster);
568 return le32_to_cpu(*entry);
569 } else if(s->fat_type==16) {
570 uint16_t* entry=array_get(&(s->fat),cluster);
571 return le16_to_cpu(*entry);
572 } else {
573 const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
574 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
578 static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
580 if(fat_entry>s->max_fat_value-8)
581 return -1;
582 return 0;
585 static inline void init_fat(BDRVVVFATState* s)
587 if (s->fat_type == 12) {
588 array_init(&(s->fat),1);
589 array_ensure_allocated(&(s->fat),
590 s->sectors_per_fat * 0x200 * 3 / 2 - 1);
591 } else {
592 array_init(&(s->fat),(s->fat_type==32?4:2));
593 array_ensure_allocated(&(s->fat),
594 s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
596 memset(s->fat.pointer,0,s->fat.size);
598 switch(s->fat_type) {
599 case 12: s->max_fat_value=0xfff; break;
600 case 16: s->max_fat_value=0xffff; break;
601 case 32: s->max_fat_value=0x0fffffff; break;
602 default: s->max_fat_value=0; /* error... */
607 /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
608 /* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
609 static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
610 unsigned int directory_start, const char* filename, int is_dot)
612 int i,j,long_index=s->directory.next;
613 direntry_t* entry = NULL;
614 direntry_t* entry_long = NULL;
616 if(is_dot) {
617 entry=array_get_next(&(s->directory));
618 memset(entry->name,0x20,11);
619 memcpy(entry->name,filename,strlen(filename));
620 return entry;
623 entry_long=create_long_filename(s,filename);
625 i = strlen(filename);
626 for(j = i - 1; j>0 && filename[j]!='.';j--);
627 if (j > 0)
628 i = (j > 8 ? 8 : j);
629 else if (i > 8)
630 i = 8;
632 entry=array_get_next(&(s->directory));
633 memset(entry->name,0x20,11);
634 memcpy(entry->name, filename, i);
636 if(j > 0)
637 for (i = 0; i < 3 && filename[j+1+i]; i++)
638 entry->extension[i] = filename[j+1+i];
640 /* upcase & remove unwanted characters */
641 for(i=10;i>=0;i--) {
642 if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
643 if(entry->name[i]<=' ' || entry->name[i]>0x7f
644 || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
645 entry->name[i]='_';
646 else if(entry->name[i]>='a' && entry->name[i]<='z')
647 entry->name[i]+='A'-'a';
650 /* mangle duplicates */
651 while(1) {
652 direntry_t* entry1=array_get(&(s->directory),directory_start);
653 int j;
655 for(;entry1<entry;entry1++)
656 if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
657 break; /* found dupe */
658 if(entry1==entry) /* no dupe found */
659 break;
661 /* use all 8 characters of name */
662 if(entry->name[7]==' ') {
663 int j;
664 for(j=6;j>0 && entry->name[j]==' ';j--)
665 entry->name[j]='~';
668 /* increment number */
669 for(j=7;j>0 && entry->name[j]=='9';j--)
670 entry->name[j]='0';
671 if(j>0) {
672 if(entry->name[j]<'0' || entry->name[j]>'9')
673 entry->name[j]='0';
674 else
675 entry->name[j]++;
679 /* calculate checksum; propagate to long name */
680 if(entry_long) {
681 uint8_t chksum=fat_chksum(entry);
683 /* calculate anew, because realloc could have taken place */
684 entry_long=array_get(&(s->directory),long_index);
685 while(entry_long<entry && is_long_name(entry_long)) {
686 entry_long->reserved[1]=chksum;
687 entry_long++;
691 return entry;
695 * Read a directory. (the index of the corresponding mapping must be passed).
697 static int read_directory(BDRVVVFATState* s, int mapping_index)
699 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
700 direntry_t* direntry;
701 const char* dirname = mapping->path;
702 int first_cluster = mapping->begin;
703 int parent_index = mapping->info.dir.parent_mapping_index;
704 mapping_t* parent_mapping = (mapping_t*)
705 (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL);
706 int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
708 DIR* dir=opendir(dirname);
709 struct dirent* entry;
710 int i;
712 assert(mapping->mode & MODE_DIRECTORY);
714 if(!dir) {
715 mapping->end = mapping->begin;
716 return -1;
719 i = mapping->info.dir.first_dir_index =
720 first_cluster == 0 ? 0 : s->directory.next;
722 /* actually read the directory, and allocate the mappings */
723 while((entry=readdir(dir))) {
724 unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
725 char* buffer;
726 direntry_t* direntry;
727 struct stat st;
728 int is_dot=!strcmp(entry->d_name,".");
729 int is_dotdot=!strcmp(entry->d_name,"..");
731 if(first_cluster == 0 && (is_dotdot || is_dot))
732 continue;
734 buffer=(char*)g_malloc(length);
735 snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
737 if(stat(buffer,&st)<0) {
738 g_free(buffer);
739 continue;
742 /* create directory entry for this file */
743 direntry=create_short_and_long_name(s, i, entry->d_name,
744 is_dot || is_dotdot);
745 direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
746 direntry->reserved[0]=direntry->reserved[1]=0;
747 direntry->ctime=fat_datetime(st.st_ctime,1);
748 direntry->cdate=fat_datetime(st.st_ctime,0);
749 direntry->adate=fat_datetime(st.st_atime,0);
750 direntry->begin_hi=0;
751 direntry->mtime=fat_datetime(st.st_mtime,1);
752 direntry->mdate=fat_datetime(st.st_mtime,0);
753 if(is_dotdot)
754 set_begin_of_direntry(direntry, first_cluster_of_parent);
755 else if(is_dot)
756 set_begin_of_direntry(direntry, first_cluster);
757 else
758 direntry->begin=0; /* do that later */
759 if (st.st_size > 0x7fffffff) {
760 fprintf(stderr, "File %s is larger than 2GB\n", buffer);
761 g_free(buffer);
762 closedir(dir);
763 return -2;
765 direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
767 /* create mapping for this file */
768 if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
769 s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
770 s->current_mapping->begin=0;
771 s->current_mapping->end=st.st_size;
773 * we get the direntry of the most recent direntry, which
774 * contains the short name and all the relevant information.
776 s->current_mapping->dir_index=s->directory.next-1;
777 s->current_mapping->first_mapping_index = -1;
778 if (S_ISDIR(st.st_mode)) {
779 s->current_mapping->mode = MODE_DIRECTORY;
780 s->current_mapping->info.dir.parent_mapping_index =
781 mapping_index;
782 } else {
783 s->current_mapping->mode = MODE_UNDEFINED;
784 s->current_mapping->info.file.offset = 0;
786 s->current_mapping->path=buffer;
787 s->current_mapping->read_only =
788 (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
791 closedir(dir);
793 /* fill with zeroes up to the end of the cluster */
794 while(s->directory.next%(0x10*s->sectors_per_cluster)) {
795 direntry_t* direntry=array_get_next(&(s->directory));
796 memset(direntry,0,sizeof(direntry_t));
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);
805 s->directory.next = ROOT_ENTRIES;
806 memset(array_get(&(s->directory), cur), 0,
807 (ROOT_ENTRIES - cur) * sizeof(direntry_t));
810 /* reget the mapping, since s->mapping was possibly realloc()ed */
811 mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
812 first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
813 * 0x20 / s->cluster_size;
814 mapping->end = first_cluster;
816 direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
817 set_begin_of_direntry(direntry, mapping->begin);
819 return 0;
822 static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
824 return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
827 static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
829 return s->faked_sectors + s->sectors_per_cluster * cluster_num;
832 static int init_directories(BDRVVVFATState* s,
833 const char *dirname, int heads, int secs)
835 bootsector_t* bootsector;
836 mapping_t* mapping;
837 unsigned int i;
838 unsigned int cluster;
840 memset(&(s->first_sectors[0]),0,0x40*0x200);
842 s->cluster_size=s->sectors_per_cluster*0x200;
843 s->cluster_buffer=g_malloc(s->cluster_size);
846 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
847 * where sc is sector_count,
848 * spf is sectors_per_fat,
849 * spc is sectors_per_clusters, and
850 * fat_type = 12, 16 or 32.
852 i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
853 s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
855 array_init(&(s->mapping),sizeof(mapping_t));
856 array_init(&(s->directory),sizeof(direntry_t));
858 /* add volume label */
860 direntry_t* entry=array_get_next(&(s->directory));
861 entry->attributes=0x28; /* archive | volume label */
862 memcpy(entry->name,"QEMU VVF",8);
863 memcpy(entry->extension,"AT ",3);
866 /* Now build FAT, and write back information into directory */
867 init_fat(s);
869 s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
870 s->cluster_count=sector2cluster(s, s->sector_count);
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;
877 mapping->path = g_strdup(dirname);
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;
885 for (i = 0, cluster = 0; i < s->mapping.next; i++) {
886 /* MS-DOS expects the FAT to be 0 for the root directory
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);
892 if (mapping->mode & MODE_DIRECTORY) {
893 mapping->begin = cluster;
894 if(read_directory(s, i)) {
895 fprintf(stderr, "Could not read directory %s\n",
896 mapping->path);
897 return -1;
899 mapping = array_get(&(s->mapping), i);
900 } else {
901 assert(mapping->mode == MODE_UNDEFINED);
902 mapping->mode=MODE_NORMAL;
903 mapping->begin = cluster;
904 if (mapping->end > 0) {
905 direntry_t* direntry = array_get(&(s->directory),
906 mapping->dir_index);
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;
916 assert(mapping->begin < mapping->end);
918 /* next free cluster */
919 cluster = mapping->end;
921 if(cluster > s->cluster_count) {
922 fprintf(stderr,"Directory does not fit in FAT%d (capacity %.2f MB)\n",
923 s->fat_type, s->sector_count / 2000.0);
924 return -EINVAL;
927 /* fix fat for entry */
928 if (fix_fat) {
929 int j;
930 for(j = mapping->begin; j < mapping->end - 1; j++)
931 fat_set(s, j, j+1);
932 fat_set(s, mapping->end - 1, s->max_fat_value);
936 mapping = array_get(&(s->mapping), 0);
937 s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
938 s->last_cluster_of_root_directory = mapping->end;
940 /* the FAT signature */
941 fat_set(s,0,s->max_fat_value);
942 fat_set(s,1,s->max_fat_value);
944 s->current_mapping = NULL;
946 bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
947 bootsector->jump[0]=0xeb;
948 bootsector->jump[1]=0x3e;
949 bootsector->jump[2]=0x90;
950 memcpy(bootsector->name,"QEMU ",8);
951 bootsector->sector_size=cpu_to_le16(0x200);
952 bootsector->sectors_per_cluster=s->sectors_per_cluster;
953 bootsector->reserved_sectors=cpu_to_le16(1);
954 bootsector->number_of_fats=0x2; /* number of FATs */
955 bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
956 bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
957 bootsector->media_type=(s->first_sectors_number>1?0xf8:0xf0); /* media descriptor (f8=hd, f0=3.5 fd)*/
958 s->fat.pointer[0] = bootsector->media_type;
959 bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
960 bootsector->sectors_per_track = cpu_to_le16(secs);
961 bootsector->number_of_heads = cpu_to_le16(heads);
962 bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
963 bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
965 /* LATER TODO: if FAT32, this is wrong */
966 bootsector->u.fat16.drive_number=s->first_sectors_number==1?0:0x80; /* fda=0, hda=0x80 */
967 bootsector->u.fat16.current_head=0;
968 bootsector->u.fat16.signature=0x29;
969 bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
971 memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
972 memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12 ":s->fat_type==16?"FAT16 ":"FAT32 "),8);
973 bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
975 return 0;
978 #ifdef DEBUG
979 static BDRVVVFATState *vvv = NULL;
980 #endif
982 static int enable_write_target(BDRVVVFATState *s);
983 static int is_consistent(BDRVVVFATState *s);
985 static void vvfat_rebind(BlockDriverState *bs)
987 BDRVVVFATState *s = bs->opaque;
988 s->bs = bs;
991 static int vvfat_open(BlockDriverState *bs, const char* dirname,
992 QDict *options, int flags)
994 BDRVVVFATState *s = bs->opaque;
995 int i, cyls, heads, secs;
997 #ifdef DEBUG
998 vvv = s;
999 #endif
1001 DLOG(if (stderr == NULL) {
1002 stderr = fopen("vvfat.log", "a");
1003 setbuf(stderr, NULL);
1006 s->bs = bs;
1008 /* LATER TODO: if FAT32, adjust */
1009 s->sectors_per_cluster=0x10;
1011 s->current_cluster=0xffffffff;
1013 s->first_sectors_number=0x40;
1014 /* read only is the default for safety */
1015 bs->read_only = 1;
1016 s->qcow = s->write_target = NULL;
1017 s->qcow_filename = NULL;
1018 s->fat2 = NULL;
1019 s->downcase_short_names = 1;
1021 if (!strstart(dirname, "fat:", NULL))
1022 return -1;
1024 if (strstr(dirname, ":32:")) {
1025 fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1026 s->fat_type = 32;
1027 } else if (strstr(dirname, ":16:")) {
1028 s->fat_type = 16;
1029 } else if (strstr(dirname, ":12:")) {
1030 s->fat_type = 12;
1033 if (strstr(dirname, ":floppy:")) {
1034 /* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */
1035 if (!s->fat_type) {
1036 s->fat_type = 12;
1037 secs = 36;
1038 s->sectors_per_cluster=2;
1039 } else {
1040 secs = s->fat_type == 12 ? 18 : 36;
1041 s->sectors_per_cluster=1;
1043 s->first_sectors_number = 1;
1044 cyls = 80;
1045 heads = 2;
1046 } else {
1047 /* 32MB or 504MB disk*/
1048 if (!s->fat_type) {
1049 s->fat_type = 16;
1051 cyls = s->fat_type == 12 ? 64 : 1024;
1052 heads = 16;
1053 secs = 63;
1055 fprintf(stderr, "vvfat %s chs %d,%d,%d\n",
1056 dirname, cyls, heads, secs);
1058 s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
1060 if (strstr(dirname, ":rw:")) {
1061 if (enable_write_target(s))
1062 return -1;
1063 bs->read_only = 0;
1066 i = strrchr(dirname, ':') - dirname;
1067 assert(i >= 3);
1068 if (dirname[i-2] == ':' && qemu_isalpha(dirname[i-1]))
1069 /* workaround for DOS drive names */
1070 dirname += i-1;
1071 else
1072 dirname += i+1;
1074 bs->total_sectors = cyls * heads * secs;
1076 if (init_directories(s, dirname, heads, secs)) {
1077 return -1;
1080 s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
1082 if (s->first_sectors_number == 0x40) {
1083 init_mbr(s, cyls, heads, secs);
1086 // assert(is_consistent(s));
1087 qemu_co_mutex_init(&s->lock);
1089 /* Disable migration when vvfat is used rw */
1090 if (s->qcow) {
1091 error_set(&s->migration_blocker,
1092 QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
1093 "vvfat (rw)", bs->device_name, "live migration");
1094 migrate_add_blocker(s->migration_blocker);
1097 return 0;
1100 static inline void vvfat_close_current_file(BDRVVVFATState *s)
1102 if(s->current_mapping) {
1103 s->current_mapping = NULL;
1104 if (s->current_fd) {
1105 qemu_close(s->current_fd);
1106 s->current_fd = 0;
1109 s->current_cluster = -1;
1112 /* mappings between index1 and index2-1 are supposed to be ordered
1113 * return value is the index of the last mapping for which end>cluster_num
1115 static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1117 while(1) {
1118 int index3;
1119 mapping_t* mapping;
1120 index3=(index1+index2)/2;
1121 mapping=array_get(&(s->mapping),index3);
1122 assert(mapping->begin < mapping->end);
1123 if(mapping->begin>=cluster_num) {
1124 assert(index2!=index3 || index2==0);
1125 if(index2==index3)
1126 return index1;
1127 index2=index3;
1128 } else {
1129 if(index1==index3)
1130 return mapping->end<=cluster_num ? index2 : index1;
1131 index1=index3;
1133 assert(index1<=index2);
1134 DLOG(mapping=array_get(&(s->mapping),index1);
1135 assert(mapping->begin<=cluster_num);
1136 assert(index2 >= s->mapping.next ||
1137 ((mapping = array_get(&(s->mapping),index2)) &&
1138 mapping->end>cluster_num)));
1142 static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
1144 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
1145 mapping_t* mapping;
1146 if(index>=s->mapping.next)
1147 return NULL;
1148 mapping=array_get(&(s->mapping),index);
1149 if(mapping->begin>cluster_num)
1150 return NULL;
1151 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
1152 return mapping;
1155 static int open_file(BDRVVVFATState* s,mapping_t* mapping)
1157 if(!mapping)
1158 return -1;
1159 if(!s->current_mapping ||
1160 strcmp(s->current_mapping->path,mapping->path)) {
1161 /* open file */
1162 int fd = qemu_open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
1163 if(fd<0)
1164 return -1;
1165 vvfat_close_current_file(s);
1166 s->current_fd = fd;
1167 s->current_mapping = mapping;
1169 return 0;
1172 static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1174 if(s->current_cluster != cluster_num) {
1175 int result=0;
1176 off_t offset;
1177 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
1178 if(!s->current_mapping
1179 || s->current_mapping->begin>cluster_num
1180 || s->current_mapping->end<=cluster_num) {
1181 /* binary search of mappings for file */
1182 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
1184 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1186 if (mapping && mapping->mode & MODE_DIRECTORY) {
1187 vvfat_close_current_file(s);
1188 s->current_mapping = mapping;
1189 read_cluster_directory:
1190 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
1191 s->cluster = (unsigned char*)s->directory.pointer+offset
1192 + 0x20*s->current_mapping->info.dir.first_dir_index;
1193 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1194 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1195 s->current_cluster = cluster_num;
1196 return 0;
1199 if(open_file(s,mapping))
1200 return -2;
1201 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1202 goto read_cluster_directory;
1204 assert(s->current_fd);
1206 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
1207 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1208 return -3;
1209 s->cluster=s->cluster_buffer;
1210 result=read(s->current_fd,s->cluster,s->cluster_size);
1211 if(result<0) {
1212 s->current_cluster = -1;
1213 return -1;
1215 s->current_cluster = cluster_num;
1217 return 0;
1220 #ifdef DEBUG
1221 static void print_direntry(const direntry_t* direntry)
1223 int j = 0;
1224 char buffer[1024];
1226 fprintf(stderr, "direntry %p: ", direntry);
1227 if(!direntry)
1228 return;
1229 if(is_long_name(direntry)) {
1230 unsigned char* c=(unsigned char*)direntry;
1231 int i;
1232 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
1233 #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
1234 ADD_CHAR(c[i]);
1235 for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
1236 ADD_CHAR(c[i]);
1237 for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
1238 ADD_CHAR(c[i]);
1239 buffer[j] = 0;
1240 fprintf(stderr, "%s\n", buffer);
1241 } else {
1242 int i;
1243 for(i=0;i<11;i++)
1244 ADD_CHAR(direntry->name[i]);
1245 buffer[j] = 0;
1246 fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1247 buffer,
1248 direntry->attributes,
1249 begin_of_direntry(direntry),le32_to_cpu(direntry->size));
1253 static void print_mapping(const mapping_t* mapping)
1255 fprintf(stderr, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1256 "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1257 mapping, mapping->begin, mapping->end, mapping->dir_index,
1258 mapping->first_mapping_index, mapping->path, mapping->mode);
1260 if (mapping->mode & MODE_DIRECTORY)
1261 fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1262 else
1263 fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
1265 #endif
1267 static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
1268 uint8_t *buf, int nb_sectors)
1270 BDRVVVFATState *s = bs->opaque;
1271 int i;
1273 for(i=0;i<nb_sectors;i++,sector_num++) {
1274 if (sector_num >= bs->total_sectors)
1275 return -1;
1276 if (s->qcow) {
1277 int n;
1278 if (bdrv_is_allocated(s->qcow, sector_num, nb_sectors-i, &n)) {
1279 DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
1280 if (bdrv_read(s->qcow, sector_num, buf + i*0x200, n)) {
1281 return -1;
1283 i += n - 1;
1284 sector_num += n - 1;
1285 continue;
1287 DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
1289 if(sector_num<s->faked_sectors) {
1290 if(sector_num<s->first_sectors_number)
1291 memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
1292 else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
1293 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
1294 else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
1295 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
1296 } else {
1297 uint32_t sector=sector_num-s->faked_sectors,
1298 sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1299 cluster_num=sector/s->sectors_per_cluster;
1300 if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) {
1301 /* LATER TODO: strict: return -1; */
1302 memset(buf+i*0x200,0,0x200);
1303 continue;
1305 memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
1308 return 0;
1311 static coroutine_fn int vvfat_co_read(BlockDriverState *bs, int64_t sector_num,
1312 uint8_t *buf, int nb_sectors)
1314 int ret;
1315 BDRVVVFATState *s = bs->opaque;
1316 qemu_co_mutex_lock(&s->lock);
1317 ret = vvfat_read(bs, sector_num, buf, nb_sectors);
1318 qemu_co_mutex_unlock(&s->lock);
1319 return ret;
1322 /* LATER TODO: statify all functions */
1325 * Idea of the write support (use snapshot):
1327 * 1. check if all data is consistent, recording renames, modifications,
1328 * new files and directories (in s->commits).
1330 * 2. if the data is not consistent, stop committing
1332 * 3. handle renames, and create new files and directories (do not yet
1333 * write their contents)
1335 * 4. walk the directories, fixing the mapping and direntries, and marking
1336 * the handled mappings as not deleted
1338 * 5. commit the contents of the files
1340 * 6. handle deleted files and directories
1344 typedef struct commit_t {
1345 char* path;
1346 union {
1347 struct { uint32_t cluster; } rename;
1348 struct { int dir_index; uint32_t modified_offset; } writeout;
1349 struct { uint32_t first_cluster; } new_file;
1350 struct { uint32_t cluster; } mkdir;
1351 } param;
1352 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1353 enum {
1354 ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1355 } action;
1356 } commit_t;
1358 static void clear_commits(BDRVVVFATState* s)
1360 int i;
1361 DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1362 for (i = 0; i < s->commits.next; i++) {
1363 commit_t* commit = array_get(&(s->commits), i);
1364 assert(commit->path || commit->action == ACTION_WRITEOUT);
1365 if (commit->action != ACTION_WRITEOUT) {
1366 assert(commit->path);
1367 g_free(commit->path);
1368 } else
1369 assert(commit->path == NULL);
1371 s->commits.next = 0;
1374 static void schedule_rename(BDRVVVFATState* s,
1375 uint32_t cluster, char* new_path)
1377 commit_t* commit = array_get_next(&(s->commits));
1378 commit->path = new_path;
1379 commit->param.rename.cluster = cluster;
1380 commit->action = ACTION_RENAME;
1383 static void schedule_writeout(BDRVVVFATState* s,
1384 int dir_index, uint32_t modified_offset)
1386 commit_t* commit = array_get_next(&(s->commits));
1387 commit->path = NULL;
1388 commit->param.writeout.dir_index = dir_index;
1389 commit->param.writeout.modified_offset = modified_offset;
1390 commit->action = ACTION_WRITEOUT;
1393 static void schedule_new_file(BDRVVVFATState* s,
1394 char* path, uint32_t first_cluster)
1396 commit_t* commit = array_get_next(&(s->commits));
1397 commit->path = path;
1398 commit->param.new_file.first_cluster = first_cluster;
1399 commit->action = ACTION_NEW_FILE;
1402 static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1404 commit_t* commit = array_get_next(&(s->commits));
1405 commit->path = path;
1406 commit->param.mkdir.cluster = cluster;
1407 commit->action = ACTION_MKDIR;
1410 typedef struct {
1412 * Since the sequence number is at most 0x3f, and the filename
1413 * length is at most 13 times the sequence number, the maximal
1414 * filename length is 0x3f * 13 bytes.
1416 unsigned char name[0x3f * 13 + 1];
1417 int checksum, len;
1418 int sequence_number;
1419 } long_file_name;
1421 static void lfn_init(long_file_name* lfn)
1423 lfn->sequence_number = lfn->len = 0;
1424 lfn->checksum = 0x100;
1427 /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1428 static int parse_long_name(long_file_name* lfn,
1429 const direntry_t* direntry)
1431 int i, j, offset;
1432 const unsigned char* pointer = (const unsigned char*)direntry;
1434 if (!is_long_name(direntry))
1435 return 1;
1437 if (pointer[0] & 0x40) {
1438 lfn->sequence_number = pointer[0] & 0x3f;
1439 lfn->checksum = pointer[13];
1440 lfn->name[0] = 0;
1441 lfn->name[lfn->sequence_number * 13] = 0;
1442 } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
1443 return -1;
1444 else if (pointer[13] != lfn->checksum)
1445 return -2;
1446 else if (pointer[12] || pointer[26] || pointer[27])
1447 return -3;
1449 offset = 13 * (lfn->sequence_number - 1);
1450 for (i = 0, j = 1; i < 13; i++, j+=2) {
1451 if (j == 11)
1452 j = 14;
1453 else if (j == 26)
1454 j = 28;
1456 if (pointer[j+1] == 0)
1457 lfn->name[offset + i] = pointer[j];
1458 else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1459 return -4;
1460 else
1461 lfn->name[offset + i] = 0;
1464 if (pointer[0] & 0x40)
1465 lfn->len = offset + strlen((char*)lfn->name + offset);
1467 return 0;
1470 /* returns 0 if successful, >0 if no short_name, and <0 on error */
1471 static int parse_short_name(BDRVVVFATState* s,
1472 long_file_name* lfn, direntry_t* direntry)
1474 int i, j;
1476 if (!is_short_name(direntry))
1477 return 1;
1479 for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1480 for (i = 0; i <= j; i++) {
1481 if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
1482 return -1;
1483 else if (s->downcase_short_names)
1484 lfn->name[i] = qemu_tolower(direntry->name[i]);
1485 else
1486 lfn->name[i] = direntry->name[i];
1489 for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
1490 if (j >= 0) {
1491 lfn->name[i++] = '.';
1492 lfn->name[i + j + 1] = '\0';
1493 for (;j >= 0; j--) {
1494 if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
1495 return -2;
1496 else if (s->downcase_short_names)
1497 lfn->name[i + j] = qemu_tolower(direntry->extension[j]);
1498 else
1499 lfn->name[i + j] = direntry->extension[j];
1501 } else
1502 lfn->name[i + j + 1] = '\0';
1504 lfn->len = strlen((char*)lfn->name);
1506 return 0;
1509 static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1510 unsigned int cluster)
1512 if (cluster < s->last_cluster_of_root_directory) {
1513 if (cluster + 1 == s->last_cluster_of_root_directory)
1514 return s->max_fat_value;
1515 else
1516 return cluster + 1;
1519 if (s->fat_type==32) {
1520 uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1521 return le32_to_cpu(*entry);
1522 } else if (s->fat_type==16) {
1523 uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1524 return le16_to_cpu(*entry);
1525 } else {
1526 const uint8_t* x=s->fat2+cluster*3/2;
1527 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1531 static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1533 int was_modified = 0;
1534 int i, dummy;
1536 if (s->qcow == NULL)
1537 return 0;
1539 for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
1540 was_modified = bdrv_is_allocated(s->qcow,
1541 cluster2sector(s, cluster_num) + i, 1, &dummy);
1543 return was_modified;
1546 static const char* get_basename(const char* path)
1548 char* basename = strrchr(path, '/');
1549 if (basename == NULL)
1550 return path;
1551 else
1552 return basename + 1; /* strip '/' */
1556 * The array s->used_clusters holds the states of the clusters. If it is
1557 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1558 * was modified, bit 3 is set.
1559 * If any cluster is allocated, but not part of a file or directory, this
1560 * driver refuses to commit.
1562 typedef enum {
1563 USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
1564 } used_t;
1567 * get_cluster_count_for_direntry() not only determines how many clusters
1568 * are occupied by direntry, but also if it was renamed or modified.
1570 * A file is thought to be renamed *only* if there already was a file with
1571 * exactly the same first cluster, but a different name.
1573 * Further, the files/directories handled by this function are
1574 * assumed to be *not* deleted (and *only* those).
1576 static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
1577 direntry_t* direntry, const char* path)
1580 * This is a little bit tricky:
1581 * IF the guest OS just inserts a cluster into the file chain,
1582 * and leaves the rest alone, (i.e. the original file had clusters
1583 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1585 * - do_commit will write the cluster into the file at the given
1586 * offset, but
1588 * - the cluster which is overwritten should be moved to a later
1589 * position in the file.
1591 * I am not aware that any OS does something as braindead, but this
1592 * situation could happen anyway when not committing for a long time.
1593 * Just to be sure that this does not bite us, detect it, and copy the
1594 * contents of the clusters to-be-overwritten into the qcow.
1596 int copy_it = 0;
1597 int was_modified = 0;
1598 int32_t ret = 0;
1600 uint32_t cluster_num = begin_of_direntry(direntry);
1601 uint32_t offset = 0;
1602 int first_mapping_index = -1;
1603 mapping_t* mapping = NULL;
1604 const char* basename2 = NULL;
1606 vvfat_close_current_file(s);
1608 /* the root directory */
1609 if (cluster_num == 0)
1610 return 0;
1612 /* write support */
1613 if (s->qcow) {
1614 basename2 = get_basename(path);
1616 mapping = find_mapping_for_cluster(s, cluster_num);
1618 if (mapping) {
1619 const char* basename;
1621 assert(mapping->mode & MODE_DELETED);
1622 mapping->mode &= ~MODE_DELETED;
1624 basename = get_basename(mapping->path);
1626 assert(mapping->mode & MODE_NORMAL);
1628 /* rename */
1629 if (strcmp(basename, basename2))
1630 schedule_rename(s, cluster_num, g_strdup(path));
1631 } else if (is_file(direntry))
1632 /* new file */
1633 schedule_new_file(s, g_strdup(path), cluster_num);
1634 else {
1635 abort();
1636 return 0;
1640 while(1) {
1641 if (s->qcow) {
1642 if (!copy_it && cluster_was_modified(s, cluster_num)) {
1643 if (mapping == NULL ||
1644 mapping->begin > cluster_num ||
1645 mapping->end <= cluster_num)
1646 mapping = find_mapping_for_cluster(s, cluster_num);
1649 if (mapping &&
1650 (mapping->mode & MODE_DIRECTORY) == 0) {
1652 /* was modified in qcow */
1653 if (offset != mapping->info.file.offset + s->cluster_size
1654 * (cluster_num - mapping->begin)) {
1655 /* offset of this cluster in file chain has changed */
1656 abort();
1657 copy_it = 1;
1658 } else if (offset == 0) {
1659 const char* basename = get_basename(mapping->path);
1661 if (strcmp(basename, basename2))
1662 copy_it = 1;
1663 first_mapping_index = array_index(&(s->mapping), mapping);
1666 if (mapping->first_mapping_index != first_mapping_index
1667 && mapping->info.file.offset > 0) {
1668 abort();
1669 copy_it = 1;
1672 /* need to write out? */
1673 if (!was_modified && is_file(direntry)) {
1674 was_modified = 1;
1675 schedule_writeout(s, mapping->dir_index, offset);
1680 if (copy_it) {
1681 int i, dummy;
1683 * This is horribly inefficient, but that is okay, since
1684 * it is rarely executed, if at all.
1686 int64_t offset = cluster2sector(s, cluster_num);
1688 vvfat_close_current_file(s);
1689 for (i = 0; i < s->sectors_per_cluster; i++) {
1690 if (!bdrv_is_allocated(s->qcow, offset + i, 1, &dummy)) {
1691 if (vvfat_read(s->bs, offset, s->cluster_buffer, 1)) {
1692 return -1;
1694 if (bdrv_write(s->qcow, offset, s->cluster_buffer, 1)) {
1695 return -2;
1702 ret++;
1703 if (s->used_clusters[cluster_num] & USED_ANY)
1704 return 0;
1705 s->used_clusters[cluster_num] = USED_FILE;
1707 cluster_num = modified_fat_get(s, cluster_num);
1709 if (fat_eof(s, cluster_num))
1710 return ret;
1711 else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
1712 return -1;
1714 offset += s->cluster_size;
1719 * This function looks at the modified data (qcow).
1720 * It returns 0 upon inconsistency or error, and the number of clusters
1721 * used by the directory, its subdirectories and their files.
1723 static int check_directory_consistency(BDRVVVFATState *s,
1724 int cluster_num, const char* path)
1726 int ret = 0;
1727 unsigned char* cluster = g_malloc(s->cluster_size);
1728 direntry_t* direntries = (direntry_t*)cluster;
1729 mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
1731 long_file_name lfn;
1732 int path_len = strlen(path);
1733 char path2[PATH_MAX + 1];
1735 assert(path_len < PATH_MAX); /* len was tested before! */
1736 pstrcpy(path2, sizeof(path2), path);
1737 path2[path_len] = '/';
1738 path2[path_len + 1] = '\0';
1740 if (mapping) {
1741 const char* basename = get_basename(mapping->path);
1742 const char* basename2 = get_basename(path);
1744 assert(mapping->mode & MODE_DIRECTORY);
1746 assert(mapping->mode & MODE_DELETED);
1747 mapping->mode &= ~MODE_DELETED;
1749 if (strcmp(basename, basename2))
1750 schedule_rename(s, cluster_num, g_strdup(path));
1751 } else
1752 /* new directory */
1753 schedule_mkdir(s, cluster_num, g_strdup(path));
1755 lfn_init(&lfn);
1756 do {
1757 int i;
1758 int subret = 0;
1760 ret++;
1762 if (s->used_clusters[cluster_num] & USED_ANY) {
1763 fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
1764 return 0;
1766 s->used_clusters[cluster_num] = USED_DIRECTORY;
1768 DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
1769 subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
1770 s->sectors_per_cluster);
1771 if (subret) {
1772 fprintf(stderr, "Error fetching direntries\n");
1773 fail:
1774 g_free(cluster);
1775 return 0;
1778 for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
1779 int cluster_count = 0;
1781 DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i));
1782 if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
1783 is_free(direntries + i))
1784 continue;
1786 subret = parse_long_name(&lfn, direntries + i);
1787 if (subret < 0) {
1788 fprintf(stderr, "Error in long name\n");
1789 goto fail;
1791 if (subret == 0 || is_free(direntries + i))
1792 continue;
1794 if (fat_chksum(direntries+i) != lfn.checksum) {
1795 subret = parse_short_name(s, &lfn, direntries + i);
1796 if (subret < 0) {
1797 fprintf(stderr, "Error in short name (%d)\n", subret);
1798 goto fail;
1800 if (subret > 0 || !strcmp((char*)lfn.name, ".")
1801 || !strcmp((char*)lfn.name, ".."))
1802 continue;
1804 lfn.checksum = 0x100; /* cannot use long name twice */
1806 if (path_len + 1 + lfn.len >= PATH_MAX) {
1807 fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
1808 goto fail;
1810 pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
1811 (char*)lfn.name);
1813 if (is_directory(direntries + i)) {
1814 if (begin_of_direntry(direntries + i) == 0) {
1815 DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
1816 goto fail;
1818 cluster_count = check_directory_consistency(s,
1819 begin_of_direntry(direntries + i), path2);
1820 if (cluster_count == 0) {
1821 DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
1822 goto fail;
1824 } else if (is_file(direntries + i)) {
1825 /* check file size with FAT */
1826 cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
1827 if (cluster_count !=
1828 (le32_to_cpu(direntries[i].size) + s->cluster_size
1829 - 1) / s->cluster_size) {
1830 DLOG(fprintf(stderr, "Cluster count mismatch\n"));
1831 goto fail;
1833 } else
1834 abort(); /* cluster_count = 0; */
1836 ret += cluster_count;
1839 cluster_num = modified_fat_get(s, cluster_num);
1840 } while(!fat_eof(s, cluster_num));
1842 g_free(cluster);
1843 return ret;
1846 /* returns 1 on success */
1847 static int is_consistent(BDRVVVFATState* s)
1849 int i, check;
1850 int used_clusters_count = 0;
1852 DLOG(checkpoint());
1854 * - get modified FAT
1855 * - compare the two FATs (TODO)
1856 * - get buffer for marking used clusters
1857 * - recurse direntries from root (using bs->bdrv_read to make
1858 * sure to get the new data)
1859 * - check that the FAT agrees with the size
1860 * - count the number of clusters occupied by this directory and
1861 * its files
1862 * - check that the cumulative used cluster count agrees with the
1863 * FAT
1864 * - if all is fine, return number of used clusters
1866 if (s->fat2 == NULL) {
1867 int size = 0x200 * s->sectors_per_fat;
1868 s->fat2 = g_malloc(size);
1869 memcpy(s->fat2, s->fat.pointer, size);
1871 check = vvfat_read(s->bs,
1872 s->first_sectors_number, s->fat2, s->sectors_per_fat);
1873 if (check) {
1874 fprintf(stderr, "Could not copy fat\n");
1875 return 0;
1877 assert (s->used_clusters);
1878 for (i = 0; i < sector2cluster(s, s->sector_count); i++)
1879 s->used_clusters[i] &= ~USED_ANY;
1881 clear_commits(s);
1883 /* mark every mapped file/directory as deleted.
1884 * (check_directory_consistency() will unmark those still present). */
1885 if (s->qcow)
1886 for (i = 0; i < s->mapping.next; i++) {
1887 mapping_t* mapping = array_get(&(s->mapping), i);
1888 if (mapping->first_mapping_index < 0)
1889 mapping->mode |= MODE_DELETED;
1892 used_clusters_count = check_directory_consistency(s, 0, s->path);
1893 if (used_clusters_count <= 0) {
1894 DLOG(fprintf(stderr, "problem in directory\n"));
1895 return 0;
1898 check = s->last_cluster_of_root_directory;
1899 for (i = check; i < sector2cluster(s, s->sector_count); i++) {
1900 if (modified_fat_get(s, i)) {
1901 if(!s->used_clusters[i]) {
1902 DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
1903 return 0;
1905 check++;
1908 if (s->used_clusters[i] == USED_ALLOCATED) {
1909 /* allocated, but not used... */
1910 DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
1911 return 0;
1915 if (check != used_clusters_count)
1916 return 0;
1918 return used_clusters_count;
1921 static inline void adjust_mapping_indices(BDRVVVFATState* s,
1922 int offset, int adjust)
1924 int i;
1926 for (i = 0; i < s->mapping.next; i++) {
1927 mapping_t* mapping = array_get(&(s->mapping), i);
1929 #define ADJUST_MAPPING_INDEX(name) \
1930 if (mapping->name >= offset) \
1931 mapping->name += adjust
1933 ADJUST_MAPPING_INDEX(first_mapping_index);
1934 if (mapping->mode & MODE_DIRECTORY)
1935 ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
1939 /* insert or update mapping */
1940 static mapping_t* insert_mapping(BDRVVVFATState* s,
1941 uint32_t begin, uint32_t end)
1944 * - find mapping where mapping->begin >= begin,
1945 * - if mapping->begin > begin: insert
1946 * - adjust all references to mappings!
1947 * - else: adjust
1948 * - replace name
1950 int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
1951 mapping_t* mapping = NULL;
1952 mapping_t* first_mapping = array_get(&(s->mapping), 0);
1954 if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
1955 && mapping->begin < begin) {
1956 mapping->end = begin;
1957 index++;
1958 mapping = array_get(&(s->mapping), index);
1960 if (index >= s->mapping.next || mapping->begin > begin) {
1961 mapping = array_insert(&(s->mapping), index, 1);
1962 mapping->path = NULL;
1963 adjust_mapping_indices(s, index, +1);
1966 mapping->begin = begin;
1967 mapping->end = end;
1969 DLOG(mapping_t* next_mapping;
1970 assert(index + 1 >= s->mapping.next ||
1971 ((next_mapping = array_get(&(s->mapping), index + 1)) &&
1972 next_mapping->begin >= end)));
1974 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1975 s->current_mapping = array_get(&(s->mapping),
1976 s->current_mapping - first_mapping);
1978 return mapping;
1981 static int remove_mapping(BDRVVVFATState* s, int mapping_index)
1983 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
1984 mapping_t* first_mapping = array_get(&(s->mapping), 0);
1986 /* free mapping */
1987 if (mapping->first_mapping_index < 0) {
1988 g_free(mapping->path);
1991 /* remove from s->mapping */
1992 array_remove(&(s->mapping), mapping_index);
1994 /* adjust all references to mappings */
1995 adjust_mapping_indices(s, mapping_index, -1);
1997 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1998 s->current_mapping = array_get(&(s->mapping),
1999 s->current_mapping - first_mapping);
2001 return 0;
2004 static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
2006 int i;
2007 for (i = 0; i < s->mapping.next; i++) {
2008 mapping_t* mapping = array_get(&(s->mapping), i);
2009 if (mapping->dir_index >= offset)
2010 mapping->dir_index += adjust;
2011 if ((mapping->mode & MODE_DIRECTORY) &&
2012 mapping->info.dir.first_dir_index >= offset)
2013 mapping->info.dir.first_dir_index += adjust;
2017 static direntry_t* insert_direntries(BDRVVVFATState* s,
2018 int dir_index, int count)
2021 * make room in s->directory,
2022 * adjust_dirindices
2024 direntry_t* result = array_insert(&(s->directory), dir_index, count);
2025 if (result == NULL)
2026 return NULL;
2027 adjust_dirindices(s, dir_index, count);
2028 return result;
2031 static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
2033 int ret = array_remove_slice(&(s->directory), dir_index, count);
2034 if (ret)
2035 return ret;
2036 adjust_dirindices(s, dir_index, -count);
2037 return 0;
2041 * Adapt the mappings of the cluster chain starting at first cluster
2042 * (i.e. if a file starts at first_cluster, the chain is followed according
2043 * to the modified fat, and the corresponding entries in s->mapping are
2044 * adjusted)
2046 static int commit_mappings(BDRVVVFATState* s,
2047 uint32_t first_cluster, int dir_index)
2049 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2050 direntry_t* direntry = array_get(&(s->directory), dir_index);
2051 uint32_t cluster = first_cluster;
2053 vvfat_close_current_file(s);
2055 assert(mapping);
2056 assert(mapping->begin == first_cluster);
2057 mapping->first_mapping_index = -1;
2058 mapping->dir_index = dir_index;
2059 mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2060 MODE_DIRECTORY : MODE_NORMAL;
2062 while (!fat_eof(s, cluster)) {
2063 uint32_t c, c1;
2065 for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2066 c = c1, c1 = modified_fat_get(s, c1));
2068 c++;
2069 if (c > mapping->end) {
2070 int index = array_index(&(s->mapping), mapping);
2071 int i, max_i = s->mapping.next - index;
2072 for (i = 1; i < max_i && mapping[i].begin < c; i++);
2073 while (--i > 0)
2074 remove_mapping(s, index + 1);
2076 assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2077 || mapping[1].begin >= c);
2078 mapping->end = c;
2080 if (!fat_eof(s, c1)) {
2081 int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2082 mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2083 array_get(&(s->mapping), i);
2085 if (next_mapping == NULL || next_mapping->begin > c1) {
2086 int i1 = array_index(&(s->mapping), mapping);
2088 next_mapping = insert_mapping(s, c1, c1+1);
2090 if (c1 < c)
2091 i1++;
2092 mapping = array_get(&(s->mapping), i1);
2095 next_mapping->dir_index = mapping->dir_index;
2096 next_mapping->first_mapping_index =
2097 mapping->first_mapping_index < 0 ?
2098 array_index(&(s->mapping), mapping) :
2099 mapping->first_mapping_index;
2100 next_mapping->path = mapping->path;
2101 next_mapping->mode = mapping->mode;
2102 next_mapping->read_only = mapping->read_only;
2103 if (mapping->mode & MODE_DIRECTORY) {
2104 next_mapping->info.dir.parent_mapping_index =
2105 mapping->info.dir.parent_mapping_index;
2106 next_mapping->info.dir.first_dir_index =
2107 mapping->info.dir.first_dir_index +
2108 0x10 * s->sectors_per_cluster *
2109 (mapping->end - mapping->begin);
2110 } else
2111 next_mapping->info.file.offset = mapping->info.file.offset +
2112 mapping->end - mapping->begin;
2114 mapping = next_mapping;
2117 cluster = c1;
2120 return 0;
2123 static int commit_direntries(BDRVVVFATState* s,
2124 int dir_index, int parent_mapping_index)
2126 direntry_t* direntry = array_get(&(s->directory), dir_index);
2127 uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
2128 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2130 int factor = 0x10 * s->sectors_per_cluster;
2131 int old_cluster_count, new_cluster_count;
2132 int current_dir_index = mapping->info.dir.first_dir_index;
2133 int first_dir_index = current_dir_index;
2134 int ret, i;
2135 uint32_t c;
2137 DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
2139 assert(direntry);
2140 assert(mapping);
2141 assert(mapping->begin == first_cluster);
2142 assert(mapping->info.dir.first_dir_index < s->directory.next);
2143 assert(mapping->mode & MODE_DIRECTORY);
2144 assert(dir_index == 0 || is_directory(direntry));
2146 mapping->info.dir.parent_mapping_index = parent_mapping_index;
2148 if (first_cluster == 0) {
2149 old_cluster_count = new_cluster_count =
2150 s->last_cluster_of_root_directory;
2151 } else {
2152 for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2153 c = fat_get(s, c))
2154 old_cluster_count++;
2156 for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2157 c = modified_fat_get(s, c))
2158 new_cluster_count++;
2161 if (new_cluster_count > old_cluster_count) {
2162 if (insert_direntries(s,
2163 current_dir_index + factor * old_cluster_count,
2164 factor * (new_cluster_count - old_cluster_count)) == NULL)
2165 return -1;
2166 } else if (new_cluster_count < old_cluster_count)
2167 remove_direntries(s,
2168 current_dir_index + factor * new_cluster_count,
2169 factor * (old_cluster_count - new_cluster_count));
2171 for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
2172 void* direntry = array_get(&(s->directory), current_dir_index);
2173 int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2174 s->sectors_per_cluster);
2175 if (ret)
2176 return ret;
2177 assert(!strncmp(s->directory.pointer, "QEMU", 4));
2178 current_dir_index += factor;
2181 ret = commit_mappings(s, first_cluster, dir_index);
2182 if (ret)
2183 return ret;
2185 /* recurse */
2186 for (i = 0; i < factor * new_cluster_count; i++) {
2187 direntry = array_get(&(s->directory), first_dir_index + i);
2188 if (is_directory(direntry) && !is_dot(direntry)) {
2189 mapping = find_mapping_for_cluster(s, first_cluster);
2190 assert(mapping->mode & MODE_DIRECTORY);
2191 ret = commit_direntries(s, first_dir_index + i,
2192 array_index(&(s->mapping), mapping));
2193 if (ret)
2194 return ret;
2198 return 0;
2201 /* commit one file (adjust contents, adjust mapping),
2202 return first_mapping_index */
2203 static int commit_one_file(BDRVVVFATState* s,
2204 int dir_index, uint32_t offset)
2206 direntry_t* direntry = array_get(&(s->directory), dir_index);
2207 uint32_t c = begin_of_direntry(direntry);
2208 uint32_t first_cluster = c;
2209 mapping_t* mapping = find_mapping_for_cluster(s, c);
2210 uint32_t size = filesize_of_direntry(direntry);
2211 char* cluster = g_malloc(s->cluster_size);
2212 uint32_t i;
2213 int fd = 0;
2215 assert(offset < size);
2216 assert((offset % s->cluster_size) == 0);
2218 for (i = s->cluster_size; i < offset; i += s->cluster_size)
2219 c = modified_fat_get(s, c);
2221 fd = qemu_open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
2222 if (fd < 0) {
2223 fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2224 strerror(errno), errno);
2225 g_free(cluster);
2226 return fd;
2228 if (offset > 0) {
2229 if (lseek(fd, offset, SEEK_SET) != offset) {
2230 qemu_close(fd);
2231 g_free(cluster);
2232 return -3;
2236 while (offset < size) {
2237 uint32_t c1;
2238 int rest_size = (size - offset > s->cluster_size ?
2239 s->cluster_size : size - offset);
2240 int ret;
2242 c1 = modified_fat_get(s, c);
2244 assert((size - offset == 0 && fat_eof(s, c)) ||
2245 (size > offset && c >=2 && !fat_eof(s, c)));
2247 ret = vvfat_read(s->bs, cluster2sector(s, c),
2248 (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
2250 if (ret < 0) {
2251 qemu_close(fd);
2252 g_free(cluster);
2253 return ret;
2256 if (write(fd, cluster, rest_size) < 0) {
2257 qemu_close(fd);
2258 g_free(cluster);
2259 return -2;
2262 offset += rest_size;
2263 c = c1;
2266 if (ftruncate(fd, size)) {
2267 perror("ftruncate()");
2268 qemu_close(fd);
2269 g_free(cluster);
2270 return -4;
2272 qemu_close(fd);
2273 g_free(cluster);
2275 return commit_mappings(s, first_cluster, dir_index);
2278 #ifdef DEBUG
2279 /* test, if all mappings point to valid direntries */
2280 static void check1(BDRVVVFATState* s)
2282 int i;
2283 for (i = 0; i < s->mapping.next; i++) {
2284 mapping_t* mapping = array_get(&(s->mapping), i);
2285 if (mapping->mode & MODE_DELETED) {
2286 fprintf(stderr, "deleted\n");
2287 continue;
2289 assert(mapping->dir_index < s->directory.next);
2290 direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2291 assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2292 if (mapping->mode & MODE_DIRECTORY) {
2293 assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2294 assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2299 /* test, if all direntries have mappings */
2300 static void check2(BDRVVVFATState* s)
2302 int i;
2303 int first_mapping = -1;
2305 for (i = 0; i < s->directory.next; i++) {
2306 direntry_t* direntry = array_get(&(s->directory), i);
2308 if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2309 mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2310 assert(mapping);
2311 assert(mapping->dir_index == i || is_dot(direntry));
2312 assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2315 if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2316 /* cluster start */
2317 int j, count = 0;
2319 for (j = 0; j < s->mapping.next; j++) {
2320 mapping_t* mapping = array_get(&(s->mapping), j);
2321 if (mapping->mode & MODE_DELETED)
2322 continue;
2323 if (mapping->mode & MODE_DIRECTORY) {
2324 if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2325 assert(++count == 1);
2326 if (mapping->first_mapping_index == -1)
2327 first_mapping = array_index(&(s->mapping), mapping);
2328 else
2329 assert(first_mapping == mapping->first_mapping_index);
2330 if (mapping->info.dir.parent_mapping_index < 0)
2331 assert(j == 0);
2332 else {
2333 mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2334 assert(parent->mode & MODE_DIRECTORY);
2335 assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2340 if (count == 0)
2341 first_mapping = -1;
2345 #endif
2347 static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2349 int i;
2351 #ifdef DEBUG
2352 fprintf(stderr, "handle_renames\n");
2353 for (i = 0; i < s->commits.next; i++) {
2354 commit_t* commit = array_get(&(s->commits), i);
2355 fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
2357 #endif
2359 for (i = 0; i < s->commits.next;) {
2360 commit_t* commit = array_get(&(s->commits), i);
2361 if (commit->action == ACTION_RENAME) {
2362 mapping_t* mapping = find_mapping_for_cluster(s,
2363 commit->param.rename.cluster);
2364 char* old_path = mapping->path;
2366 assert(commit->path);
2367 mapping->path = commit->path;
2368 if (rename(old_path, mapping->path))
2369 return -2;
2371 if (mapping->mode & MODE_DIRECTORY) {
2372 int l1 = strlen(mapping->path);
2373 int l2 = strlen(old_path);
2374 int diff = l1 - l2;
2375 direntry_t* direntry = array_get(&(s->directory),
2376 mapping->info.dir.first_dir_index);
2377 uint32_t c = mapping->begin;
2378 int i = 0;
2380 /* recurse */
2381 while (!fat_eof(s, c)) {
2382 do {
2383 direntry_t* d = direntry + i;
2385 if (is_file(d) || (is_directory(d) && !is_dot(d))) {
2386 mapping_t* m = find_mapping_for_cluster(s,
2387 begin_of_direntry(d));
2388 int l = strlen(m->path);
2389 char* new_path = g_malloc(l + diff + 1);
2391 assert(!strncmp(m->path, mapping->path, l2));
2393 pstrcpy(new_path, l + diff + 1, mapping->path);
2394 pstrcpy(new_path + l1, l + diff + 1 - l1,
2395 m->path + l2);
2397 schedule_rename(s, m->begin, new_path);
2399 i++;
2400 } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2401 c = fat_get(s, c);
2405 g_free(old_path);
2406 array_remove(&(s->commits), i);
2407 continue;
2408 } else if (commit->action == ACTION_MKDIR) {
2409 mapping_t* mapping;
2410 int j, parent_path_len;
2412 #ifdef __MINGW32__
2413 if (mkdir(commit->path))
2414 return -5;
2415 #else
2416 if (mkdir(commit->path, 0755))
2417 return -5;
2418 #endif
2420 mapping = insert_mapping(s, commit->param.mkdir.cluster,
2421 commit->param.mkdir.cluster + 1);
2422 if (mapping == NULL)
2423 return -6;
2425 mapping->mode = MODE_DIRECTORY;
2426 mapping->read_only = 0;
2427 mapping->path = commit->path;
2428 j = s->directory.next;
2429 assert(j);
2430 insert_direntries(s, s->directory.next,
2431 0x10 * s->sectors_per_cluster);
2432 mapping->info.dir.first_dir_index = j;
2434 parent_path_len = strlen(commit->path)
2435 - strlen(get_basename(commit->path)) - 1;
2436 for (j = 0; j < s->mapping.next; j++) {
2437 mapping_t* m = array_get(&(s->mapping), j);
2438 if (m->first_mapping_index < 0 && m != mapping &&
2439 !strncmp(m->path, mapping->path, parent_path_len) &&
2440 strlen(m->path) == parent_path_len)
2441 break;
2443 assert(j < s->mapping.next);
2444 mapping->info.dir.parent_mapping_index = j;
2446 array_remove(&(s->commits), i);
2447 continue;
2450 i++;
2452 return 0;
2456 * TODO: make sure that the short name is not matching *another* file
2458 static int handle_commits(BDRVVVFATState* s)
2460 int i, fail = 0;
2462 vvfat_close_current_file(s);
2464 for (i = 0; !fail && i < s->commits.next; i++) {
2465 commit_t* commit = array_get(&(s->commits), i);
2466 switch(commit->action) {
2467 case ACTION_RENAME: case ACTION_MKDIR:
2468 abort();
2469 fail = -2;
2470 break;
2471 case ACTION_WRITEOUT: {
2472 #ifndef NDEBUG
2473 /* these variables are only used by assert() below */
2474 direntry_t* entry = array_get(&(s->directory),
2475 commit->param.writeout.dir_index);
2476 uint32_t begin = begin_of_direntry(entry);
2477 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2478 #endif
2480 assert(mapping);
2481 assert(mapping->begin == begin);
2482 assert(commit->path == NULL);
2484 if (commit_one_file(s, commit->param.writeout.dir_index,
2485 commit->param.writeout.modified_offset))
2486 fail = -3;
2488 break;
2490 case ACTION_NEW_FILE: {
2491 int begin = commit->param.new_file.first_cluster;
2492 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2493 direntry_t* entry;
2494 int i;
2496 /* find direntry */
2497 for (i = 0; i < s->directory.next; i++) {
2498 entry = array_get(&(s->directory), i);
2499 if (is_file(entry) && begin_of_direntry(entry) == begin)
2500 break;
2503 if (i >= s->directory.next) {
2504 fail = -6;
2505 continue;
2508 /* make sure there exists an initial mapping */
2509 if (mapping && mapping->begin != begin) {
2510 mapping->end = begin;
2511 mapping = NULL;
2513 if (mapping == NULL) {
2514 mapping = insert_mapping(s, begin, begin+1);
2516 /* most members will be fixed in commit_mappings() */
2517 assert(commit->path);
2518 mapping->path = commit->path;
2519 mapping->read_only = 0;
2520 mapping->mode = MODE_NORMAL;
2521 mapping->info.file.offset = 0;
2523 if (commit_one_file(s, i, 0))
2524 fail = -7;
2526 break;
2528 default:
2529 abort();
2532 if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2533 return -1;
2534 return fail;
2537 static int handle_deletes(BDRVVVFATState* s)
2539 int i, deferred = 1, deleted = 1;
2541 /* delete files corresponding to mappings marked as deleted */
2542 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2543 while (deferred && deleted) {
2544 deferred = 0;
2545 deleted = 0;
2547 for (i = 1; i < s->mapping.next; i++) {
2548 mapping_t* mapping = array_get(&(s->mapping), i);
2549 if (mapping->mode & MODE_DELETED) {
2550 direntry_t* entry = array_get(&(s->directory),
2551 mapping->dir_index);
2553 if (is_free(entry)) {
2554 /* remove file/directory */
2555 if (mapping->mode & MODE_DIRECTORY) {
2556 int j, next_dir_index = s->directory.next,
2557 first_dir_index = mapping->info.dir.first_dir_index;
2559 if (rmdir(mapping->path) < 0) {
2560 if (errno == ENOTEMPTY) {
2561 deferred++;
2562 continue;
2563 } else
2564 return -5;
2567 for (j = 1; j < s->mapping.next; j++) {
2568 mapping_t* m = array_get(&(s->mapping), j);
2569 if (m->mode & MODE_DIRECTORY &&
2570 m->info.dir.first_dir_index >
2571 first_dir_index &&
2572 m->info.dir.first_dir_index <
2573 next_dir_index)
2574 next_dir_index =
2575 m->info.dir.first_dir_index;
2577 remove_direntries(s, first_dir_index,
2578 next_dir_index - first_dir_index);
2580 deleted++;
2582 } else {
2583 if (unlink(mapping->path))
2584 return -4;
2585 deleted++;
2587 DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2588 remove_mapping(s, i);
2593 return 0;
2597 * synchronize mapping with new state:
2599 * - copy FAT (with bdrv_read)
2600 * - mark all filenames corresponding to mappings as deleted
2601 * - recurse direntries from root (using bs->bdrv_read)
2602 * - delete files corresponding to mappings marked as deleted
2604 static int do_commit(BDRVVVFATState* s)
2606 int ret = 0;
2608 /* the real meat are the commits. Nothing to do? Move along! */
2609 if (s->commits.next == 0)
2610 return 0;
2612 vvfat_close_current_file(s);
2614 ret = handle_renames_and_mkdirs(s);
2615 if (ret) {
2616 fprintf(stderr, "Error handling renames (%d)\n", ret);
2617 abort();
2618 return ret;
2621 /* copy FAT (with bdrv_read) */
2622 memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2624 /* recurse direntries from root (using bs->bdrv_read) */
2625 ret = commit_direntries(s, 0, -1);
2626 if (ret) {
2627 fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
2628 abort();
2629 return ret;
2632 ret = handle_commits(s);
2633 if (ret) {
2634 fprintf(stderr, "Error handling commits (%d)\n", ret);
2635 abort();
2636 return ret;
2639 ret = handle_deletes(s);
2640 if (ret) {
2641 fprintf(stderr, "Error deleting\n");
2642 abort();
2643 return ret;
2646 if (s->qcow->drv->bdrv_make_empty) {
2647 s->qcow->drv->bdrv_make_empty(s->qcow);
2650 memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2652 DLOG(checkpoint());
2653 return 0;
2656 static int try_commit(BDRVVVFATState* s)
2658 vvfat_close_current_file(s);
2659 DLOG(checkpoint());
2660 if(!is_consistent(s))
2661 return -1;
2662 return do_commit(s);
2665 static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
2666 const uint8_t *buf, int nb_sectors)
2668 BDRVVVFATState *s = bs->opaque;
2669 int i, ret;
2671 DLOG(checkpoint());
2673 /* Check if we're operating in read-only mode */
2674 if (s->qcow == NULL) {
2675 return -EACCES;
2678 vvfat_close_current_file(s);
2681 * Some sanity checks:
2682 * - do not allow writing to the boot sector
2683 * - do not allow to write non-ASCII filenames
2686 if (sector_num < s->first_sectors_number)
2687 return -1;
2689 for (i = sector2cluster(s, sector_num);
2690 i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
2691 mapping_t* mapping = find_mapping_for_cluster(s, i);
2692 if (mapping) {
2693 if (mapping->read_only) {
2694 fprintf(stderr, "Tried to write to write-protected file %s\n",
2695 mapping->path);
2696 return -1;
2699 if (mapping->mode & MODE_DIRECTORY) {
2700 int begin = cluster2sector(s, i);
2701 int end = begin + s->sectors_per_cluster, k;
2702 int dir_index;
2703 const direntry_t* direntries;
2704 long_file_name lfn;
2706 lfn_init(&lfn);
2708 if (begin < sector_num)
2709 begin = sector_num;
2710 if (end > sector_num + nb_sectors)
2711 end = sector_num + nb_sectors;
2712 dir_index = mapping->dir_index +
2713 0x10 * (begin - mapping->begin * s->sectors_per_cluster);
2714 direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
2716 for (k = 0; k < (end - begin) * 0x10; k++) {
2717 /* do not allow non-ASCII filenames */
2718 if (parse_long_name(&lfn, direntries + k) < 0) {
2719 fprintf(stderr, "Warning: non-ASCII filename\n");
2720 return -1;
2722 /* no access to the direntry of a read-only file */
2723 else if (is_short_name(direntries+k) &&
2724 (direntries[k].attributes & 1)) {
2725 if (memcmp(direntries + k,
2726 array_get(&(s->directory), dir_index + k),
2727 sizeof(direntry_t))) {
2728 fprintf(stderr, "Warning: tried to write to write-protected file\n");
2729 return -1;
2734 i = mapping->end;
2735 } else
2736 i++;
2740 * Use qcow backend. Commit later.
2742 DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
2743 ret = bdrv_write(s->qcow, sector_num, buf, nb_sectors);
2744 if (ret < 0) {
2745 fprintf(stderr, "Error writing to qcow backend\n");
2746 return ret;
2749 for (i = sector2cluster(s, sector_num);
2750 i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
2751 if (i >= 0)
2752 s->used_clusters[i] |= USED_ALLOCATED;
2754 DLOG(checkpoint());
2755 /* TODO: add timeout */
2756 try_commit(s);
2758 DLOG(checkpoint());
2759 return 0;
2762 static coroutine_fn int vvfat_co_write(BlockDriverState *bs, int64_t sector_num,
2763 const uint8_t *buf, int nb_sectors)
2765 int ret;
2766 BDRVVVFATState *s = bs->opaque;
2767 qemu_co_mutex_lock(&s->lock);
2768 ret = vvfat_write(bs, sector_num, buf, nb_sectors);
2769 qemu_co_mutex_unlock(&s->lock);
2770 return ret;
2773 static int coroutine_fn vvfat_co_is_allocated(BlockDriverState *bs,
2774 int64_t sector_num, int nb_sectors, int* n)
2776 BDRVVVFATState* s = bs->opaque;
2777 *n = s->sector_count - sector_num;
2778 if (*n > nb_sectors)
2779 *n = nb_sectors;
2780 else if (*n < 0)
2781 return 0;
2782 return 1;
2785 static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
2786 const uint8_t* buffer, int nb_sectors) {
2787 BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
2788 return try_commit(s);
2791 static void write_target_close(BlockDriverState *bs) {
2792 BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
2793 bdrv_delete(s->qcow);
2794 g_free(s->qcow_filename);
2797 static BlockDriver vvfat_write_target = {
2798 .format_name = "vvfat_write_target",
2799 .bdrv_write = write_target_commit,
2800 .bdrv_close = write_target_close,
2803 static int enable_write_target(BDRVVVFATState *s)
2805 BlockDriver *bdrv_qcow;
2806 QEMUOptionParameter *options;
2807 int ret;
2808 int size = sector2cluster(s, s->sector_count);
2809 s->used_clusters = calloc(size, 1);
2811 array_init(&(s->commits), sizeof(commit_t));
2813 s->qcow_filename = g_malloc(1024);
2814 ret = get_tmp_filename(s->qcow_filename, 1024);
2815 if (ret < 0) {
2816 g_free(s->qcow_filename);
2817 s->qcow_filename = NULL;
2818 return ret;
2821 bdrv_qcow = bdrv_find_format("qcow");
2822 options = parse_option_parameters("", bdrv_qcow->create_options, NULL);
2823 set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512);
2824 set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:");
2826 if (bdrv_create(bdrv_qcow, s->qcow_filename, options) < 0)
2827 return -1;
2829 s->qcow = bdrv_new("");
2830 if (s->qcow == NULL) {
2831 return -1;
2834 ret = bdrv_open(s->qcow, s->qcow_filename, NULL,
2835 BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, bdrv_qcow);
2836 if (ret < 0) {
2837 return ret;
2840 #ifndef _WIN32
2841 unlink(s->qcow_filename);
2842 #endif
2844 s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
2845 s->bs->backing_hd->drv = &vvfat_write_target;
2846 s->bs->backing_hd->opaque = g_malloc(sizeof(void*));
2847 *(void**)s->bs->backing_hd->opaque = s;
2849 return 0;
2852 static void vvfat_close(BlockDriverState *bs)
2854 BDRVVVFATState *s = bs->opaque;
2856 vvfat_close_current_file(s);
2857 array_free(&(s->fat));
2858 array_free(&(s->directory));
2859 array_free(&(s->mapping));
2860 g_free(s->cluster_buffer);
2862 if (s->qcow) {
2863 migrate_del_blocker(s->migration_blocker);
2864 error_free(s->migration_blocker);
2868 static BlockDriver bdrv_vvfat = {
2869 .format_name = "vvfat",
2870 .instance_size = sizeof(BDRVVVFATState),
2871 .bdrv_file_open = vvfat_open,
2872 .bdrv_rebind = vvfat_rebind,
2873 .bdrv_read = vvfat_co_read,
2874 .bdrv_write = vvfat_co_write,
2875 .bdrv_close = vvfat_close,
2876 .bdrv_co_is_allocated = vvfat_co_is_allocated,
2877 .protocol_name = "fat",
2880 static void bdrv_vvfat_init(void)
2882 bdrv_register(&bdrv_vvfat);
2885 block_init(bdrv_vvfat_init);
2887 #ifdef DEBUG
2888 static void checkpoint(void) {
2889 assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
2890 check1(vvv);
2891 check2(vvv);
2892 assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
2893 #if 0
2894 if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
2895 fprintf(stderr, "Nonono!\n");
2896 mapping_t* mapping;
2897 direntry_t* direntry;
2898 assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
2899 assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
2900 if (vvv->mapping.next<47)
2901 return;
2902 assert((mapping = array_get(&(vvv->mapping), 47)));
2903 assert(mapping->dir_index < vvv->directory.next);
2904 direntry = array_get(&(vvv->directory), mapping->dir_index);
2905 assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0);
2906 #endif
2908 #endif