Add compat macro for gtk_widget_get_realized
[qemu/pbrook.git] / block / vvfat.c
blob06e6654824aaf2ab6e3dc5e248fceff8660af697
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, int flags)
993 BDRVVVFATState *s = bs->opaque;
994 int i, cyls, heads, secs;
996 #ifdef DEBUG
997 vvv = s;
998 #endif
1000 DLOG(if (stderr == NULL) {
1001 stderr = fopen("vvfat.log", "a");
1002 setbuf(stderr, NULL);
1005 s->bs = bs;
1007 /* LATER TODO: if FAT32, adjust */
1008 s->sectors_per_cluster=0x10;
1010 s->current_cluster=0xffffffff;
1012 s->first_sectors_number=0x40;
1013 /* read only is the default for safety */
1014 bs->read_only = 1;
1015 s->qcow = s->write_target = NULL;
1016 s->qcow_filename = NULL;
1017 s->fat2 = NULL;
1018 s->downcase_short_names = 1;
1020 if (!strstart(dirname, "fat:", NULL))
1021 return -1;
1023 if (strstr(dirname, ":32:")) {
1024 fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1025 s->fat_type = 32;
1026 } else if (strstr(dirname, ":16:")) {
1027 s->fat_type = 16;
1028 } else if (strstr(dirname, ":12:")) {
1029 s->fat_type = 12;
1032 if (strstr(dirname, ":floppy:")) {
1033 /* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */
1034 if (!s->fat_type) {
1035 s->fat_type = 12;
1036 secs = 36;
1037 s->sectors_per_cluster=2;
1038 } else {
1039 secs = s->fat_type == 12 ? 18 : 36;
1040 s->sectors_per_cluster=1;
1042 s->first_sectors_number = 1;
1043 cyls = 80;
1044 heads = 2;
1045 } else {
1046 /* 32MB or 504MB disk*/
1047 if (!s->fat_type) {
1048 s->fat_type = 16;
1050 cyls = s->fat_type == 12 ? 64 : 1024;
1051 heads = 16;
1052 secs = 63;
1054 fprintf(stderr, "vvfat %s chs %d,%d,%d\n",
1055 dirname, cyls, heads, secs);
1057 s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
1059 if (strstr(dirname, ":rw:")) {
1060 if (enable_write_target(s))
1061 return -1;
1062 bs->read_only = 0;
1065 i = strrchr(dirname, ':') - dirname;
1066 assert(i >= 3);
1067 if (dirname[i-2] == ':' && qemu_isalpha(dirname[i-1]))
1068 /* workaround for DOS drive names */
1069 dirname += i-1;
1070 else
1071 dirname += i+1;
1073 bs->total_sectors = cyls * heads * secs;
1075 if (init_directories(s, dirname, heads, secs)) {
1076 return -1;
1079 s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
1081 if (s->first_sectors_number == 0x40) {
1082 init_mbr(s, cyls, heads, secs);
1085 // assert(is_consistent(s));
1086 qemu_co_mutex_init(&s->lock);
1088 /* Disable migration when vvfat is used rw */
1089 if (s->qcow) {
1090 error_set(&s->migration_blocker,
1091 QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
1092 "vvfat (rw)", bs->device_name, "live migration");
1093 migrate_add_blocker(s->migration_blocker);
1096 return 0;
1099 static inline void vvfat_close_current_file(BDRVVVFATState *s)
1101 if(s->current_mapping) {
1102 s->current_mapping = NULL;
1103 if (s->current_fd) {
1104 qemu_close(s->current_fd);
1105 s->current_fd = 0;
1108 s->current_cluster = -1;
1111 /* mappings between index1 and index2-1 are supposed to be ordered
1112 * return value is the index of the last mapping for which end>cluster_num
1114 static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1116 while(1) {
1117 int index3;
1118 mapping_t* mapping;
1119 index3=(index1+index2)/2;
1120 mapping=array_get(&(s->mapping),index3);
1121 assert(mapping->begin < mapping->end);
1122 if(mapping->begin>=cluster_num) {
1123 assert(index2!=index3 || index2==0);
1124 if(index2==index3)
1125 return index1;
1126 index2=index3;
1127 } else {
1128 if(index1==index3)
1129 return mapping->end<=cluster_num ? index2 : index1;
1130 index1=index3;
1132 assert(index1<=index2);
1133 DLOG(mapping=array_get(&(s->mapping),index1);
1134 assert(mapping->begin<=cluster_num);
1135 assert(index2 >= s->mapping.next ||
1136 ((mapping = array_get(&(s->mapping),index2)) &&
1137 mapping->end>cluster_num)));
1141 static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
1143 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
1144 mapping_t* mapping;
1145 if(index>=s->mapping.next)
1146 return NULL;
1147 mapping=array_get(&(s->mapping),index);
1148 if(mapping->begin>cluster_num)
1149 return NULL;
1150 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
1151 return mapping;
1154 static int open_file(BDRVVVFATState* s,mapping_t* mapping)
1156 if(!mapping)
1157 return -1;
1158 if(!s->current_mapping ||
1159 strcmp(s->current_mapping->path,mapping->path)) {
1160 /* open file */
1161 int fd = qemu_open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
1162 if(fd<0)
1163 return -1;
1164 vvfat_close_current_file(s);
1165 s->current_fd = fd;
1166 s->current_mapping = mapping;
1168 return 0;
1171 static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1173 if(s->current_cluster != cluster_num) {
1174 int result=0;
1175 off_t offset;
1176 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
1177 if(!s->current_mapping
1178 || s->current_mapping->begin>cluster_num
1179 || s->current_mapping->end<=cluster_num) {
1180 /* binary search of mappings for file */
1181 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
1183 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1185 if (mapping && mapping->mode & MODE_DIRECTORY) {
1186 vvfat_close_current_file(s);
1187 s->current_mapping = mapping;
1188 read_cluster_directory:
1189 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
1190 s->cluster = (unsigned char*)s->directory.pointer+offset
1191 + 0x20*s->current_mapping->info.dir.first_dir_index;
1192 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1193 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1194 s->current_cluster = cluster_num;
1195 return 0;
1198 if(open_file(s,mapping))
1199 return -2;
1200 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1201 goto read_cluster_directory;
1203 assert(s->current_fd);
1205 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
1206 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1207 return -3;
1208 s->cluster=s->cluster_buffer;
1209 result=read(s->current_fd,s->cluster,s->cluster_size);
1210 if(result<0) {
1211 s->current_cluster = -1;
1212 return -1;
1214 s->current_cluster = cluster_num;
1216 return 0;
1219 #ifdef DEBUG
1220 static void print_direntry(const direntry_t* direntry)
1222 int j = 0;
1223 char buffer[1024];
1225 fprintf(stderr, "direntry %p: ", direntry);
1226 if(!direntry)
1227 return;
1228 if(is_long_name(direntry)) {
1229 unsigned char* c=(unsigned char*)direntry;
1230 int i;
1231 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
1232 #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
1233 ADD_CHAR(c[i]);
1234 for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
1235 ADD_CHAR(c[i]);
1236 for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
1237 ADD_CHAR(c[i]);
1238 buffer[j] = 0;
1239 fprintf(stderr, "%s\n", buffer);
1240 } else {
1241 int i;
1242 for(i=0;i<11;i++)
1243 ADD_CHAR(direntry->name[i]);
1244 buffer[j] = 0;
1245 fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1246 buffer,
1247 direntry->attributes,
1248 begin_of_direntry(direntry),le32_to_cpu(direntry->size));
1252 static void print_mapping(const mapping_t* mapping)
1254 fprintf(stderr, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1255 "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1256 mapping, mapping->begin, mapping->end, mapping->dir_index,
1257 mapping->first_mapping_index, mapping->path, mapping->mode);
1259 if (mapping->mode & MODE_DIRECTORY)
1260 fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1261 else
1262 fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
1264 #endif
1266 static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
1267 uint8_t *buf, int nb_sectors)
1269 BDRVVVFATState *s = bs->opaque;
1270 int i;
1272 for(i=0;i<nb_sectors;i++,sector_num++) {
1273 if (sector_num >= bs->total_sectors)
1274 return -1;
1275 if (s->qcow) {
1276 int n;
1277 if (bdrv_is_allocated(s->qcow, sector_num, nb_sectors-i, &n)) {
1278 DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
1279 if (bdrv_read(s->qcow, sector_num, buf + i*0x200, n)) {
1280 return -1;
1282 i += n - 1;
1283 sector_num += n - 1;
1284 continue;
1286 DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
1288 if(sector_num<s->faked_sectors) {
1289 if(sector_num<s->first_sectors_number)
1290 memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
1291 else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
1292 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
1293 else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
1294 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
1295 } else {
1296 uint32_t sector=sector_num-s->faked_sectors,
1297 sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1298 cluster_num=sector/s->sectors_per_cluster;
1299 if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) {
1300 /* LATER TODO: strict: return -1; */
1301 memset(buf+i*0x200,0,0x200);
1302 continue;
1304 memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
1307 return 0;
1310 static coroutine_fn int vvfat_co_read(BlockDriverState *bs, int64_t sector_num,
1311 uint8_t *buf, int nb_sectors)
1313 int ret;
1314 BDRVVVFATState *s = bs->opaque;
1315 qemu_co_mutex_lock(&s->lock);
1316 ret = vvfat_read(bs, sector_num, buf, nb_sectors);
1317 qemu_co_mutex_unlock(&s->lock);
1318 return ret;
1321 /* LATER TODO: statify all functions */
1324 * Idea of the write support (use snapshot):
1326 * 1. check if all data is consistent, recording renames, modifications,
1327 * new files and directories (in s->commits).
1329 * 2. if the data is not consistent, stop committing
1331 * 3. handle renames, and create new files and directories (do not yet
1332 * write their contents)
1334 * 4. walk the directories, fixing the mapping and direntries, and marking
1335 * the handled mappings as not deleted
1337 * 5. commit the contents of the files
1339 * 6. handle deleted files and directories
1343 typedef struct commit_t {
1344 char* path;
1345 union {
1346 struct { uint32_t cluster; } rename;
1347 struct { int dir_index; uint32_t modified_offset; } writeout;
1348 struct { uint32_t first_cluster; } new_file;
1349 struct { uint32_t cluster; } mkdir;
1350 } param;
1351 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1352 enum {
1353 ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1354 } action;
1355 } commit_t;
1357 static void clear_commits(BDRVVVFATState* s)
1359 int i;
1360 DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1361 for (i = 0; i < s->commits.next; i++) {
1362 commit_t* commit = array_get(&(s->commits), i);
1363 assert(commit->path || commit->action == ACTION_WRITEOUT);
1364 if (commit->action != ACTION_WRITEOUT) {
1365 assert(commit->path);
1366 g_free(commit->path);
1367 } else
1368 assert(commit->path == NULL);
1370 s->commits.next = 0;
1373 static void schedule_rename(BDRVVVFATState* s,
1374 uint32_t cluster, char* new_path)
1376 commit_t* commit = array_get_next(&(s->commits));
1377 commit->path = new_path;
1378 commit->param.rename.cluster = cluster;
1379 commit->action = ACTION_RENAME;
1382 static void schedule_writeout(BDRVVVFATState* s,
1383 int dir_index, uint32_t modified_offset)
1385 commit_t* commit = array_get_next(&(s->commits));
1386 commit->path = NULL;
1387 commit->param.writeout.dir_index = dir_index;
1388 commit->param.writeout.modified_offset = modified_offset;
1389 commit->action = ACTION_WRITEOUT;
1392 static void schedule_new_file(BDRVVVFATState* s,
1393 char* path, uint32_t first_cluster)
1395 commit_t* commit = array_get_next(&(s->commits));
1396 commit->path = path;
1397 commit->param.new_file.first_cluster = first_cluster;
1398 commit->action = ACTION_NEW_FILE;
1401 static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1403 commit_t* commit = array_get_next(&(s->commits));
1404 commit->path = path;
1405 commit->param.mkdir.cluster = cluster;
1406 commit->action = ACTION_MKDIR;
1409 typedef struct {
1411 * Since the sequence number is at most 0x3f, and the filename
1412 * length is at most 13 times the sequence number, the maximal
1413 * filename length is 0x3f * 13 bytes.
1415 unsigned char name[0x3f * 13 + 1];
1416 int checksum, len;
1417 int sequence_number;
1418 } long_file_name;
1420 static void lfn_init(long_file_name* lfn)
1422 lfn->sequence_number = lfn->len = 0;
1423 lfn->checksum = 0x100;
1426 /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1427 static int parse_long_name(long_file_name* lfn,
1428 const direntry_t* direntry)
1430 int i, j, offset;
1431 const unsigned char* pointer = (const unsigned char*)direntry;
1433 if (!is_long_name(direntry))
1434 return 1;
1436 if (pointer[0] & 0x40) {
1437 lfn->sequence_number = pointer[0] & 0x3f;
1438 lfn->checksum = pointer[13];
1439 lfn->name[0] = 0;
1440 lfn->name[lfn->sequence_number * 13] = 0;
1441 } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
1442 return -1;
1443 else if (pointer[13] != lfn->checksum)
1444 return -2;
1445 else if (pointer[12] || pointer[26] || pointer[27])
1446 return -3;
1448 offset = 13 * (lfn->sequence_number - 1);
1449 for (i = 0, j = 1; i < 13; i++, j+=2) {
1450 if (j == 11)
1451 j = 14;
1452 else if (j == 26)
1453 j = 28;
1455 if (pointer[j+1] == 0)
1456 lfn->name[offset + i] = pointer[j];
1457 else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1458 return -4;
1459 else
1460 lfn->name[offset + i] = 0;
1463 if (pointer[0] & 0x40)
1464 lfn->len = offset + strlen((char*)lfn->name + offset);
1466 return 0;
1469 /* returns 0 if successful, >0 if no short_name, and <0 on error */
1470 static int parse_short_name(BDRVVVFATState* s,
1471 long_file_name* lfn, direntry_t* direntry)
1473 int i, j;
1475 if (!is_short_name(direntry))
1476 return 1;
1478 for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1479 for (i = 0; i <= j; i++) {
1480 if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
1481 return -1;
1482 else if (s->downcase_short_names)
1483 lfn->name[i] = qemu_tolower(direntry->name[i]);
1484 else
1485 lfn->name[i] = direntry->name[i];
1488 for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
1489 if (j >= 0) {
1490 lfn->name[i++] = '.';
1491 lfn->name[i + j + 1] = '\0';
1492 for (;j >= 0; j--) {
1493 if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
1494 return -2;
1495 else if (s->downcase_short_names)
1496 lfn->name[i + j] = qemu_tolower(direntry->extension[j]);
1497 else
1498 lfn->name[i + j] = direntry->extension[j];
1500 } else
1501 lfn->name[i + j + 1] = '\0';
1503 lfn->len = strlen((char*)lfn->name);
1505 return 0;
1508 static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1509 unsigned int cluster)
1511 if (cluster < s->last_cluster_of_root_directory) {
1512 if (cluster + 1 == s->last_cluster_of_root_directory)
1513 return s->max_fat_value;
1514 else
1515 return cluster + 1;
1518 if (s->fat_type==32) {
1519 uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1520 return le32_to_cpu(*entry);
1521 } else if (s->fat_type==16) {
1522 uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1523 return le16_to_cpu(*entry);
1524 } else {
1525 const uint8_t* x=s->fat2+cluster*3/2;
1526 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1530 static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1532 int was_modified = 0;
1533 int i, dummy;
1535 if (s->qcow == NULL)
1536 return 0;
1538 for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
1539 was_modified = bdrv_is_allocated(s->qcow,
1540 cluster2sector(s, cluster_num) + i, 1, &dummy);
1542 return was_modified;
1545 static const char* get_basename(const char* path)
1547 char* basename = strrchr(path, '/');
1548 if (basename == NULL)
1549 return path;
1550 else
1551 return basename + 1; /* strip '/' */
1555 * The array s->used_clusters holds the states of the clusters. If it is
1556 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1557 * was modified, bit 3 is set.
1558 * If any cluster is allocated, but not part of a file or directory, this
1559 * driver refuses to commit.
1561 typedef enum {
1562 USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
1563 } used_t;
1566 * get_cluster_count_for_direntry() not only determines how many clusters
1567 * are occupied by direntry, but also if it was renamed or modified.
1569 * A file is thought to be renamed *only* if there already was a file with
1570 * exactly the same first cluster, but a different name.
1572 * Further, the files/directories handled by this function are
1573 * assumed to be *not* deleted (and *only* those).
1575 static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
1576 direntry_t* direntry, const char* path)
1579 * This is a little bit tricky:
1580 * IF the guest OS just inserts a cluster into the file chain,
1581 * and leaves the rest alone, (i.e. the original file had clusters
1582 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1584 * - do_commit will write the cluster into the file at the given
1585 * offset, but
1587 * - the cluster which is overwritten should be moved to a later
1588 * position in the file.
1590 * I am not aware that any OS does something as braindead, but this
1591 * situation could happen anyway when not committing for a long time.
1592 * Just to be sure that this does not bite us, detect it, and copy the
1593 * contents of the clusters to-be-overwritten into the qcow.
1595 int copy_it = 0;
1596 int was_modified = 0;
1597 int32_t ret = 0;
1599 uint32_t cluster_num = begin_of_direntry(direntry);
1600 uint32_t offset = 0;
1601 int first_mapping_index = -1;
1602 mapping_t* mapping = NULL;
1603 const char* basename2 = NULL;
1605 vvfat_close_current_file(s);
1607 /* the root directory */
1608 if (cluster_num == 0)
1609 return 0;
1611 /* write support */
1612 if (s->qcow) {
1613 basename2 = get_basename(path);
1615 mapping = find_mapping_for_cluster(s, cluster_num);
1617 if (mapping) {
1618 const char* basename;
1620 assert(mapping->mode & MODE_DELETED);
1621 mapping->mode &= ~MODE_DELETED;
1623 basename = get_basename(mapping->path);
1625 assert(mapping->mode & MODE_NORMAL);
1627 /* rename */
1628 if (strcmp(basename, basename2))
1629 schedule_rename(s, cluster_num, g_strdup(path));
1630 } else if (is_file(direntry))
1631 /* new file */
1632 schedule_new_file(s, g_strdup(path), cluster_num);
1633 else {
1634 abort();
1635 return 0;
1639 while(1) {
1640 if (s->qcow) {
1641 if (!copy_it && cluster_was_modified(s, cluster_num)) {
1642 if (mapping == NULL ||
1643 mapping->begin > cluster_num ||
1644 mapping->end <= cluster_num)
1645 mapping = find_mapping_for_cluster(s, cluster_num);
1648 if (mapping &&
1649 (mapping->mode & MODE_DIRECTORY) == 0) {
1651 /* was modified in qcow */
1652 if (offset != mapping->info.file.offset + s->cluster_size
1653 * (cluster_num - mapping->begin)) {
1654 /* offset of this cluster in file chain has changed */
1655 abort();
1656 copy_it = 1;
1657 } else if (offset == 0) {
1658 const char* basename = get_basename(mapping->path);
1660 if (strcmp(basename, basename2))
1661 copy_it = 1;
1662 first_mapping_index = array_index(&(s->mapping), mapping);
1665 if (mapping->first_mapping_index != first_mapping_index
1666 && mapping->info.file.offset > 0) {
1667 abort();
1668 copy_it = 1;
1671 /* need to write out? */
1672 if (!was_modified && is_file(direntry)) {
1673 was_modified = 1;
1674 schedule_writeout(s, mapping->dir_index, offset);
1679 if (copy_it) {
1680 int i, dummy;
1682 * This is horribly inefficient, but that is okay, since
1683 * it is rarely executed, if at all.
1685 int64_t offset = cluster2sector(s, cluster_num);
1687 vvfat_close_current_file(s);
1688 for (i = 0; i < s->sectors_per_cluster; i++) {
1689 if (!bdrv_is_allocated(s->qcow, offset + i, 1, &dummy)) {
1690 if (vvfat_read(s->bs, offset, s->cluster_buffer, 1)) {
1691 return -1;
1693 if (bdrv_write(s->qcow, offset, s->cluster_buffer, 1)) {
1694 return -2;
1701 ret++;
1702 if (s->used_clusters[cluster_num] & USED_ANY)
1703 return 0;
1704 s->used_clusters[cluster_num] = USED_FILE;
1706 cluster_num = modified_fat_get(s, cluster_num);
1708 if (fat_eof(s, cluster_num))
1709 return ret;
1710 else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
1711 return -1;
1713 offset += s->cluster_size;
1718 * This function looks at the modified data (qcow).
1719 * It returns 0 upon inconsistency or error, and the number of clusters
1720 * used by the directory, its subdirectories and their files.
1722 static int check_directory_consistency(BDRVVVFATState *s,
1723 int cluster_num, const char* path)
1725 int ret = 0;
1726 unsigned char* cluster = g_malloc(s->cluster_size);
1727 direntry_t* direntries = (direntry_t*)cluster;
1728 mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
1730 long_file_name lfn;
1731 int path_len = strlen(path);
1732 char path2[PATH_MAX + 1];
1734 assert(path_len < PATH_MAX); /* len was tested before! */
1735 pstrcpy(path2, sizeof(path2), path);
1736 path2[path_len] = '/';
1737 path2[path_len + 1] = '\0';
1739 if (mapping) {
1740 const char* basename = get_basename(mapping->path);
1741 const char* basename2 = get_basename(path);
1743 assert(mapping->mode & MODE_DIRECTORY);
1745 assert(mapping->mode & MODE_DELETED);
1746 mapping->mode &= ~MODE_DELETED;
1748 if (strcmp(basename, basename2))
1749 schedule_rename(s, cluster_num, g_strdup(path));
1750 } else
1751 /* new directory */
1752 schedule_mkdir(s, cluster_num, g_strdup(path));
1754 lfn_init(&lfn);
1755 do {
1756 int i;
1757 int subret = 0;
1759 ret++;
1761 if (s->used_clusters[cluster_num] & USED_ANY) {
1762 fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
1763 return 0;
1765 s->used_clusters[cluster_num] = USED_DIRECTORY;
1767 DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
1768 subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
1769 s->sectors_per_cluster);
1770 if (subret) {
1771 fprintf(stderr, "Error fetching direntries\n");
1772 fail:
1773 g_free(cluster);
1774 return 0;
1777 for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
1778 int cluster_count = 0;
1780 DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i));
1781 if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
1782 is_free(direntries + i))
1783 continue;
1785 subret = parse_long_name(&lfn, direntries + i);
1786 if (subret < 0) {
1787 fprintf(stderr, "Error in long name\n");
1788 goto fail;
1790 if (subret == 0 || is_free(direntries + i))
1791 continue;
1793 if (fat_chksum(direntries+i) != lfn.checksum) {
1794 subret = parse_short_name(s, &lfn, direntries + i);
1795 if (subret < 0) {
1796 fprintf(stderr, "Error in short name (%d)\n", subret);
1797 goto fail;
1799 if (subret > 0 || !strcmp((char*)lfn.name, ".")
1800 || !strcmp((char*)lfn.name, ".."))
1801 continue;
1803 lfn.checksum = 0x100; /* cannot use long name twice */
1805 if (path_len + 1 + lfn.len >= PATH_MAX) {
1806 fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
1807 goto fail;
1809 pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
1810 (char*)lfn.name);
1812 if (is_directory(direntries + i)) {
1813 if (begin_of_direntry(direntries + i) == 0) {
1814 DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
1815 goto fail;
1817 cluster_count = check_directory_consistency(s,
1818 begin_of_direntry(direntries + i), path2);
1819 if (cluster_count == 0) {
1820 DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
1821 goto fail;
1823 } else if (is_file(direntries + i)) {
1824 /* check file size with FAT */
1825 cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
1826 if (cluster_count !=
1827 (le32_to_cpu(direntries[i].size) + s->cluster_size
1828 - 1) / s->cluster_size) {
1829 DLOG(fprintf(stderr, "Cluster count mismatch\n"));
1830 goto fail;
1832 } else
1833 abort(); /* cluster_count = 0; */
1835 ret += cluster_count;
1838 cluster_num = modified_fat_get(s, cluster_num);
1839 } while(!fat_eof(s, cluster_num));
1841 g_free(cluster);
1842 return ret;
1845 /* returns 1 on success */
1846 static int is_consistent(BDRVVVFATState* s)
1848 int i, check;
1849 int used_clusters_count = 0;
1851 DLOG(checkpoint());
1853 * - get modified FAT
1854 * - compare the two FATs (TODO)
1855 * - get buffer for marking used clusters
1856 * - recurse direntries from root (using bs->bdrv_read to make
1857 * sure to get the new data)
1858 * - check that the FAT agrees with the size
1859 * - count the number of clusters occupied by this directory and
1860 * its files
1861 * - check that the cumulative used cluster count agrees with the
1862 * FAT
1863 * - if all is fine, return number of used clusters
1865 if (s->fat2 == NULL) {
1866 int size = 0x200 * s->sectors_per_fat;
1867 s->fat2 = g_malloc(size);
1868 memcpy(s->fat2, s->fat.pointer, size);
1870 check = vvfat_read(s->bs,
1871 s->first_sectors_number, s->fat2, s->sectors_per_fat);
1872 if (check) {
1873 fprintf(stderr, "Could not copy fat\n");
1874 return 0;
1876 assert (s->used_clusters);
1877 for (i = 0; i < sector2cluster(s, s->sector_count); i++)
1878 s->used_clusters[i] &= ~USED_ANY;
1880 clear_commits(s);
1882 /* mark every mapped file/directory as deleted.
1883 * (check_directory_consistency() will unmark those still present). */
1884 if (s->qcow)
1885 for (i = 0; i < s->mapping.next; i++) {
1886 mapping_t* mapping = array_get(&(s->mapping), i);
1887 if (mapping->first_mapping_index < 0)
1888 mapping->mode |= MODE_DELETED;
1891 used_clusters_count = check_directory_consistency(s, 0, s->path);
1892 if (used_clusters_count <= 0) {
1893 DLOG(fprintf(stderr, "problem in directory\n"));
1894 return 0;
1897 check = s->last_cluster_of_root_directory;
1898 for (i = check; i < sector2cluster(s, s->sector_count); i++) {
1899 if (modified_fat_get(s, i)) {
1900 if(!s->used_clusters[i]) {
1901 DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
1902 return 0;
1904 check++;
1907 if (s->used_clusters[i] == USED_ALLOCATED) {
1908 /* allocated, but not used... */
1909 DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
1910 return 0;
1914 if (check != used_clusters_count)
1915 return 0;
1917 return used_clusters_count;
1920 static inline void adjust_mapping_indices(BDRVVVFATState* s,
1921 int offset, int adjust)
1923 int i;
1925 for (i = 0; i < s->mapping.next; i++) {
1926 mapping_t* mapping = array_get(&(s->mapping), i);
1928 #define ADJUST_MAPPING_INDEX(name) \
1929 if (mapping->name >= offset) \
1930 mapping->name += adjust
1932 ADJUST_MAPPING_INDEX(first_mapping_index);
1933 if (mapping->mode & MODE_DIRECTORY)
1934 ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
1938 /* insert or update mapping */
1939 static mapping_t* insert_mapping(BDRVVVFATState* s,
1940 uint32_t begin, uint32_t end)
1943 * - find mapping where mapping->begin >= begin,
1944 * - if mapping->begin > begin: insert
1945 * - adjust all references to mappings!
1946 * - else: adjust
1947 * - replace name
1949 int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
1950 mapping_t* mapping = NULL;
1951 mapping_t* first_mapping = array_get(&(s->mapping), 0);
1953 if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
1954 && mapping->begin < begin) {
1955 mapping->end = begin;
1956 index++;
1957 mapping = array_get(&(s->mapping), index);
1959 if (index >= s->mapping.next || mapping->begin > begin) {
1960 mapping = array_insert(&(s->mapping), index, 1);
1961 mapping->path = NULL;
1962 adjust_mapping_indices(s, index, +1);
1965 mapping->begin = begin;
1966 mapping->end = end;
1968 DLOG(mapping_t* next_mapping;
1969 assert(index + 1 >= s->mapping.next ||
1970 ((next_mapping = array_get(&(s->mapping), index + 1)) &&
1971 next_mapping->begin >= end)));
1973 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1974 s->current_mapping = array_get(&(s->mapping),
1975 s->current_mapping - first_mapping);
1977 return mapping;
1980 static int remove_mapping(BDRVVVFATState* s, int mapping_index)
1982 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
1983 mapping_t* first_mapping = array_get(&(s->mapping), 0);
1985 /* free mapping */
1986 if (mapping->first_mapping_index < 0) {
1987 g_free(mapping->path);
1990 /* remove from s->mapping */
1991 array_remove(&(s->mapping), mapping_index);
1993 /* adjust all references to mappings */
1994 adjust_mapping_indices(s, mapping_index, -1);
1996 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1997 s->current_mapping = array_get(&(s->mapping),
1998 s->current_mapping - first_mapping);
2000 return 0;
2003 static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
2005 int i;
2006 for (i = 0; i < s->mapping.next; i++) {
2007 mapping_t* mapping = array_get(&(s->mapping), i);
2008 if (mapping->dir_index >= offset)
2009 mapping->dir_index += adjust;
2010 if ((mapping->mode & MODE_DIRECTORY) &&
2011 mapping->info.dir.first_dir_index >= offset)
2012 mapping->info.dir.first_dir_index += adjust;
2016 static direntry_t* insert_direntries(BDRVVVFATState* s,
2017 int dir_index, int count)
2020 * make room in s->directory,
2021 * adjust_dirindices
2023 direntry_t* result = array_insert(&(s->directory), dir_index, count);
2024 if (result == NULL)
2025 return NULL;
2026 adjust_dirindices(s, dir_index, count);
2027 return result;
2030 static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
2032 int ret = array_remove_slice(&(s->directory), dir_index, count);
2033 if (ret)
2034 return ret;
2035 adjust_dirindices(s, dir_index, -count);
2036 return 0;
2040 * Adapt the mappings of the cluster chain starting at first cluster
2041 * (i.e. if a file starts at first_cluster, the chain is followed according
2042 * to the modified fat, and the corresponding entries in s->mapping are
2043 * adjusted)
2045 static int commit_mappings(BDRVVVFATState* s,
2046 uint32_t first_cluster, int dir_index)
2048 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2049 direntry_t* direntry = array_get(&(s->directory), dir_index);
2050 uint32_t cluster = first_cluster;
2052 vvfat_close_current_file(s);
2054 assert(mapping);
2055 assert(mapping->begin == first_cluster);
2056 mapping->first_mapping_index = -1;
2057 mapping->dir_index = dir_index;
2058 mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2059 MODE_DIRECTORY : MODE_NORMAL;
2061 while (!fat_eof(s, cluster)) {
2062 uint32_t c, c1;
2064 for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2065 c = c1, c1 = modified_fat_get(s, c1));
2067 c++;
2068 if (c > mapping->end) {
2069 int index = array_index(&(s->mapping), mapping);
2070 int i, max_i = s->mapping.next - index;
2071 for (i = 1; i < max_i && mapping[i].begin < c; i++);
2072 while (--i > 0)
2073 remove_mapping(s, index + 1);
2075 assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2076 || mapping[1].begin >= c);
2077 mapping->end = c;
2079 if (!fat_eof(s, c1)) {
2080 int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2081 mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2082 array_get(&(s->mapping), i);
2084 if (next_mapping == NULL || next_mapping->begin > c1) {
2085 int i1 = array_index(&(s->mapping), mapping);
2087 next_mapping = insert_mapping(s, c1, c1+1);
2089 if (c1 < c)
2090 i1++;
2091 mapping = array_get(&(s->mapping), i1);
2094 next_mapping->dir_index = mapping->dir_index;
2095 next_mapping->first_mapping_index =
2096 mapping->first_mapping_index < 0 ?
2097 array_index(&(s->mapping), mapping) :
2098 mapping->first_mapping_index;
2099 next_mapping->path = mapping->path;
2100 next_mapping->mode = mapping->mode;
2101 next_mapping->read_only = mapping->read_only;
2102 if (mapping->mode & MODE_DIRECTORY) {
2103 next_mapping->info.dir.parent_mapping_index =
2104 mapping->info.dir.parent_mapping_index;
2105 next_mapping->info.dir.first_dir_index =
2106 mapping->info.dir.first_dir_index +
2107 0x10 * s->sectors_per_cluster *
2108 (mapping->end - mapping->begin);
2109 } else
2110 next_mapping->info.file.offset = mapping->info.file.offset +
2111 mapping->end - mapping->begin;
2113 mapping = next_mapping;
2116 cluster = c1;
2119 return 0;
2122 static int commit_direntries(BDRVVVFATState* s,
2123 int dir_index, int parent_mapping_index)
2125 direntry_t* direntry = array_get(&(s->directory), dir_index);
2126 uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
2127 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2129 int factor = 0x10 * s->sectors_per_cluster;
2130 int old_cluster_count, new_cluster_count;
2131 int current_dir_index = mapping->info.dir.first_dir_index;
2132 int first_dir_index = current_dir_index;
2133 int ret, i;
2134 uint32_t c;
2136 DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
2138 assert(direntry);
2139 assert(mapping);
2140 assert(mapping->begin == first_cluster);
2141 assert(mapping->info.dir.first_dir_index < s->directory.next);
2142 assert(mapping->mode & MODE_DIRECTORY);
2143 assert(dir_index == 0 || is_directory(direntry));
2145 mapping->info.dir.parent_mapping_index = parent_mapping_index;
2147 if (first_cluster == 0) {
2148 old_cluster_count = new_cluster_count =
2149 s->last_cluster_of_root_directory;
2150 } else {
2151 for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2152 c = fat_get(s, c))
2153 old_cluster_count++;
2155 for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2156 c = modified_fat_get(s, c))
2157 new_cluster_count++;
2160 if (new_cluster_count > old_cluster_count) {
2161 if (insert_direntries(s,
2162 current_dir_index + factor * old_cluster_count,
2163 factor * (new_cluster_count - old_cluster_count)) == NULL)
2164 return -1;
2165 } else if (new_cluster_count < old_cluster_count)
2166 remove_direntries(s,
2167 current_dir_index + factor * new_cluster_count,
2168 factor * (old_cluster_count - new_cluster_count));
2170 for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
2171 void* direntry = array_get(&(s->directory), current_dir_index);
2172 int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2173 s->sectors_per_cluster);
2174 if (ret)
2175 return ret;
2176 assert(!strncmp(s->directory.pointer, "QEMU", 4));
2177 current_dir_index += factor;
2180 ret = commit_mappings(s, first_cluster, dir_index);
2181 if (ret)
2182 return ret;
2184 /* recurse */
2185 for (i = 0; i < factor * new_cluster_count; i++) {
2186 direntry = array_get(&(s->directory), first_dir_index + i);
2187 if (is_directory(direntry) && !is_dot(direntry)) {
2188 mapping = find_mapping_for_cluster(s, first_cluster);
2189 assert(mapping->mode & MODE_DIRECTORY);
2190 ret = commit_direntries(s, first_dir_index + i,
2191 array_index(&(s->mapping), mapping));
2192 if (ret)
2193 return ret;
2197 return 0;
2200 /* commit one file (adjust contents, adjust mapping),
2201 return first_mapping_index */
2202 static int commit_one_file(BDRVVVFATState* s,
2203 int dir_index, uint32_t offset)
2205 direntry_t* direntry = array_get(&(s->directory), dir_index);
2206 uint32_t c = begin_of_direntry(direntry);
2207 uint32_t first_cluster = c;
2208 mapping_t* mapping = find_mapping_for_cluster(s, c);
2209 uint32_t size = filesize_of_direntry(direntry);
2210 char* cluster = g_malloc(s->cluster_size);
2211 uint32_t i;
2212 int fd = 0;
2214 assert(offset < size);
2215 assert((offset % s->cluster_size) == 0);
2217 for (i = s->cluster_size; i < offset; i += s->cluster_size)
2218 c = modified_fat_get(s, c);
2220 fd = qemu_open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
2221 if (fd < 0) {
2222 fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2223 strerror(errno), errno);
2224 g_free(cluster);
2225 return fd;
2227 if (offset > 0) {
2228 if (lseek(fd, offset, SEEK_SET) != offset) {
2229 qemu_close(fd);
2230 g_free(cluster);
2231 return -3;
2235 while (offset < size) {
2236 uint32_t c1;
2237 int rest_size = (size - offset > s->cluster_size ?
2238 s->cluster_size : size - offset);
2239 int ret;
2241 c1 = modified_fat_get(s, c);
2243 assert((size - offset == 0 && fat_eof(s, c)) ||
2244 (size > offset && c >=2 && !fat_eof(s, c)));
2246 ret = vvfat_read(s->bs, cluster2sector(s, c),
2247 (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
2249 if (ret < 0) {
2250 qemu_close(fd);
2251 g_free(cluster);
2252 return ret;
2255 if (write(fd, cluster, rest_size) < 0) {
2256 qemu_close(fd);
2257 g_free(cluster);
2258 return -2;
2261 offset += rest_size;
2262 c = c1;
2265 if (ftruncate(fd, size)) {
2266 perror("ftruncate()");
2267 qemu_close(fd);
2268 g_free(cluster);
2269 return -4;
2271 qemu_close(fd);
2272 g_free(cluster);
2274 return commit_mappings(s, first_cluster, dir_index);
2277 #ifdef DEBUG
2278 /* test, if all mappings point to valid direntries */
2279 static void check1(BDRVVVFATState* s)
2281 int i;
2282 for (i = 0; i < s->mapping.next; i++) {
2283 mapping_t* mapping = array_get(&(s->mapping), i);
2284 if (mapping->mode & MODE_DELETED) {
2285 fprintf(stderr, "deleted\n");
2286 continue;
2288 assert(mapping->dir_index < s->directory.next);
2289 direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2290 assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2291 if (mapping->mode & MODE_DIRECTORY) {
2292 assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2293 assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2298 /* test, if all direntries have mappings */
2299 static void check2(BDRVVVFATState* s)
2301 int i;
2302 int first_mapping = -1;
2304 for (i = 0; i < s->directory.next; i++) {
2305 direntry_t* direntry = array_get(&(s->directory), i);
2307 if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2308 mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2309 assert(mapping);
2310 assert(mapping->dir_index == i || is_dot(direntry));
2311 assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2314 if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2315 /* cluster start */
2316 int j, count = 0;
2318 for (j = 0; j < s->mapping.next; j++) {
2319 mapping_t* mapping = array_get(&(s->mapping), j);
2320 if (mapping->mode & MODE_DELETED)
2321 continue;
2322 if (mapping->mode & MODE_DIRECTORY) {
2323 if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2324 assert(++count == 1);
2325 if (mapping->first_mapping_index == -1)
2326 first_mapping = array_index(&(s->mapping), mapping);
2327 else
2328 assert(first_mapping == mapping->first_mapping_index);
2329 if (mapping->info.dir.parent_mapping_index < 0)
2330 assert(j == 0);
2331 else {
2332 mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2333 assert(parent->mode & MODE_DIRECTORY);
2334 assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2339 if (count == 0)
2340 first_mapping = -1;
2344 #endif
2346 static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2348 int i;
2350 #ifdef DEBUG
2351 fprintf(stderr, "handle_renames\n");
2352 for (i = 0; i < s->commits.next; i++) {
2353 commit_t* commit = array_get(&(s->commits), i);
2354 fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
2356 #endif
2358 for (i = 0; i < s->commits.next;) {
2359 commit_t* commit = array_get(&(s->commits), i);
2360 if (commit->action == ACTION_RENAME) {
2361 mapping_t* mapping = find_mapping_for_cluster(s,
2362 commit->param.rename.cluster);
2363 char* old_path = mapping->path;
2365 assert(commit->path);
2366 mapping->path = commit->path;
2367 if (rename(old_path, mapping->path))
2368 return -2;
2370 if (mapping->mode & MODE_DIRECTORY) {
2371 int l1 = strlen(mapping->path);
2372 int l2 = strlen(old_path);
2373 int diff = l1 - l2;
2374 direntry_t* direntry = array_get(&(s->directory),
2375 mapping->info.dir.first_dir_index);
2376 uint32_t c = mapping->begin;
2377 int i = 0;
2379 /* recurse */
2380 while (!fat_eof(s, c)) {
2381 do {
2382 direntry_t* d = direntry + i;
2384 if (is_file(d) || (is_directory(d) && !is_dot(d))) {
2385 mapping_t* m = find_mapping_for_cluster(s,
2386 begin_of_direntry(d));
2387 int l = strlen(m->path);
2388 char* new_path = g_malloc(l + diff + 1);
2390 assert(!strncmp(m->path, mapping->path, l2));
2392 pstrcpy(new_path, l + diff + 1, mapping->path);
2393 pstrcpy(new_path + l1, l + diff + 1 - l1,
2394 m->path + l2);
2396 schedule_rename(s, m->begin, new_path);
2398 i++;
2399 } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2400 c = fat_get(s, c);
2404 g_free(old_path);
2405 array_remove(&(s->commits), i);
2406 continue;
2407 } else if (commit->action == ACTION_MKDIR) {
2408 mapping_t* mapping;
2409 int j, parent_path_len;
2411 #ifdef __MINGW32__
2412 if (mkdir(commit->path))
2413 return -5;
2414 #else
2415 if (mkdir(commit->path, 0755))
2416 return -5;
2417 #endif
2419 mapping = insert_mapping(s, commit->param.mkdir.cluster,
2420 commit->param.mkdir.cluster + 1);
2421 if (mapping == NULL)
2422 return -6;
2424 mapping->mode = MODE_DIRECTORY;
2425 mapping->read_only = 0;
2426 mapping->path = commit->path;
2427 j = s->directory.next;
2428 assert(j);
2429 insert_direntries(s, s->directory.next,
2430 0x10 * s->sectors_per_cluster);
2431 mapping->info.dir.first_dir_index = j;
2433 parent_path_len = strlen(commit->path)
2434 - strlen(get_basename(commit->path)) - 1;
2435 for (j = 0; j < s->mapping.next; j++) {
2436 mapping_t* m = array_get(&(s->mapping), j);
2437 if (m->first_mapping_index < 0 && m != mapping &&
2438 !strncmp(m->path, mapping->path, parent_path_len) &&
2439 strlen(m->path) == parent_path_len)
2440 break;
2442 assert(j < s->mapping.next);
2443 mapping->info.dir.parent_mapping_index = j;
2445 array_remove(&(s->commits), i);
2446 continue;
2449 i++;
2451 return 0;
2455 * TODO: make sure that the short name is not matching *another* file
2457 static int handle_commits(BDRVVVFATState* s)
2459 int i, fail = 0;
2461 vvfat_close_current_file(s);
2463 for (i = 0; !fail && i < s->commits.next; i++) {
2464 commit_t* commit = array_get(&(s->commits), i);
2465 switch(commit->action) {
2466 case ACTION_RENAME: case ACTION_MKDIR:
2467 abort();
2468 fail = -2;
2469 break;
2470 case ACTION_WRITEOUT: {
2471 #ifndef NDEBUG
2472 /* these variables are only used by assert() below */
2473 direntry_t* entry = array_get(&(s->directory),
2474 commit->param.writeout.dir_index);
2475 uint32_t begin = begin_of_direntry(entry);
2476 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2477 #endif
2479 assert(mapping);
2480 assert(mapping->begin == begin);
2481 assert(commit->path == NULL);
2483 if (commit_one_file(s, commit->param.writeout.dir_index,
2484 commit->param.writeout.modified_offset))
2485 fail = -3;
2487 break;
2489 case ACTION_NEW_FILE: {
2490 int begin = commit->param.new_file.first_cluster;
2491 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2492 direntry_t* entry;
2493 int i;
2495 /* find direntry */
2496 for (i = 0; i < s->directory.next; i++) {
2497 entry = array_get(&(s->directory), i);
2498 if (is_file(entry) && begin_of_direntry(entry) == begin)
2499 break;
2502 if (i >= s->directory.next) {
2503 fail = -6;
2504 continue;
2507 /* make sure there exists an initial mapping */
2508 if (mapping && mapping->begin != begin) {
2509 mapping->end = begin;
2510 mapping = NULL;
2512 if (mapping == NULL) {
2513 mapping = insert_mapping(s, begin, begin+1);
2515 /* most members will be fixed in commit_mappings() */
2516 assert(commit->path);
2517 mapping->path = commit->path;
2518 mapping->read_only = 0;
2519 mapping->mode = MODE_NORMAL;
2520 mapping->info.file.offset = 0;
2522 if (commit_one_file(s, i, 0))
2523 fail = -7;
2525 break;
2527 default:
2528 abort();
2531 if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2532 return -1;
2533 return fail;
2536 static int handle_deletes(BDRVVVFATState* s)
2538 int i, deferred = 1, deleted = 1;
2540 /* delete files corresponding to mappings marked as deleted */
2541 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2542 while (deferred && deleted) {
2543 deferred = 0;
2544 deleted = 0;
2546 for (i = 1; i < s->mapping.next; i++) {
2547 mapping_t* mapping = array_get(&(s->mapping), i);
2548 if (mapping->mode & MODE_DELETED) {
2549 direntry_t* entry = array_get(&(s->directory),
2550 mapping->dir_index);
2552 if (is_free(entry)) {
2553 /* remove file/directory */
2554 if (mapping->mode & MODE_DIRECTORY) {
2555 int j, next_dir_index = s->directory.next,
2556 first_dir_index = mapping->info.dir.first_dir_index;
2558 if (rmdir(mapping->path) < 0) {
2559 if (errno == ENOTEMPTY) {
2560 deferred++;
2561 continue;
2562 } else
2563 return -5;
2566 for (j = 1; j < s->mapping.next; j++) {
2567 mapping_t* m = array_get(&(s->mapping), j);
2568 if (m->mode & MODE_DIRECTORY &&
2569 m->info.dir.first_dir_index >
2570 first_dir_index &&
2571 m->info.dir.first_dir_index <
2572 next_dir_index)
2573 next_dir_index =
2574 m->info.dir.first_dir_index;
2576 remove_direntries(s, first_dir_index,
2577 next_dir_index - first_dir_index);
2579 deleted++;
2581 } else {
2582 if (unlink(mapping->path))
2583 return -4;
2584 deleted++;
2586 DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2587 remove_mapping(s, i);
2592 return 0;
2596 * synchronize mapping with new state:
2598 * - copy FAT (with bdrv_read)
2599 * - mark all filenames corresponding to mappings as deleted
2600 * - recurse direntries from root (using bs->bdrv_read)
2601 * - delete files corresponding to mappings marked as deleted
2603 static int do_commit(BDRVVVFATState* s)
2605 int ret = 0;
2607 /* the real meat are the commits. Nothing to do? Move along! */
2608 if (s->commits.next == 0)
2609 return 0;
2611 vvfat_close_current_file(s);
2613 ret = handle_renames_and_mkdirs(s);
2614 if (ret) {
2615 fprintf(stderr, "Error handling renames (%d)\n", ret);
2616 abort();
2617 return ret;
2620 /* copy FAT (with bdrv_read) */
2621 memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2623 /* recurse direntries from root (using bs->bdrv_read) */
2624 ret = commit_direntries(s, 0, -1);
2625 if (ret) {
2626 fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
2627 abort();
2628 return ret;
2631 ret = handle_commits(s);
2632 if (ret) {
2633 fprintf(stderr, "Error handling commits (%d)\n", ret);
2634 abort();
2635 return ret;
2638 ret = handle_deletes(s);
2639 if (ret) {
2640 fprintf(stderr, "Error deleting\n");
2641 abort();
2642 return ret;
2645 if (s->qcow->drv->bdrv_make_empty) {
2646 s->qcow->drv->bdrv_make_empty(s->qcow);
2649 memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2651 DLOG(checkpoint());
2652 return 0;
2655 static int try_commit(BDRVVVFATState* s)
2657 vvfat_close_current_file(s);
2658 DLOG(checkpoint());
2659 if(!is_consistent(s))
2660 return -1;
2661 return do_commit(s);
2664 static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
2665 const uint8_t *buf, int nb_sectors)
2667 BDRVVVFATState *s = bs->opaque;
2668 int i, ret;
2670 DLOG(checkpoint());
2672 /* Check if we're operating in read-only mode */
2673 if (s->qcow == NULL) {
2674 return -EACCES;
2677 vvfat_close_current_file(s);
2680 * Some sanity checks:
2681 * - do not allow writing to the boot sector
2682 * - do not allow to write non-ASCII filenames
2685 if (sector_num < s->first_sectors_number)
2686 return -1;
2688 for (i = sector2cluster(s, sector_num);
2689 i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
2690 mapping_t* mapping = find_mapping_for_cluster(s, i);
2691 if (mapping) {
2692 if (mapping->read_only) {
2693 fprintf(stderr, "Tried to write to write-protected file %s\n",
2694 mapping->path);
2695 return -1;
2698 if (mapping->mode & MODE_DIRECTORY) {
2699 int begin = cluster2sector(s, i);
2700 int end = begin + s->sectors_per_cluster, k;
2701 int dir_index;
2702 const direntry_t* direntries;
2703 long_file_name lfn;
2705 lfn_init(&lfn);
2707 if (begin < sector_num)
2708 begin = sector_num;
2709 if (end > sector_num + nb_sectors)
2710 end = sector_num + nb_sectors;
2711 dir_index = mapping->dir_index +
2712 0x10 * (begin - mapping->begin * s->sectors_per_cluster);
2713 direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
2715 for (k = 0; k < (end - begin) * 0x10; k++) {
2716 /* do not allow non-ASCII filenames */
2717 if (parse_long_name(&lfn, direntries + k) < 0) {
2718 fprintf(stderr, "Warning: non-ASCII filename\n");
2719 return -1;
2721 /* no access to the direntry of a read-only file */
2722 else if (is_short_name(direntries+k) &&
2723 (direntries[k].attributes & 1)) {
2724 if (memcmp(direntries + k,
2725 array_get(&(s->directory), dir_index + k),
2726 sizeof(direntry_t))) {
2727 fprintf(stderr, "Warning: tried to write to write-protected file\n");
2728 return -1;
2733 i = mapping->end;
2734 } else
2735 i++;
2739 * Use qcow backend. Commit later.
2741 DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
2742 ret = bdrv_write(s->qcow, sector_num, buf, nb_sectors);
2743 if (ret < 0) {
2744 fprintf(stderr, "Error writing to qcow backend\n");
2745 return ret;
2748 for (i = sector2cluster(s, sector_num);
2749 i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
2750 if (i >= 0)
2751 s->used_clusters[i] |= USED_ALLOCATED;
2753 DLOG(checkpoint());
2754 /* TODO: add timeout */
2755 try_commit(s);
2757 DLOG(checkpoint());
2758 return 0;
2761 static coroutine_fn int vvfat_co_write(BlockDriverState *bs, int64_t sector_num,
2762 const uint8_t *buf, int nb_sectors)
2764 int ret;
2765 BDRVVVFATState *s = bs->opaque;
2766 qemu_co_mutex_lock(&s->lock);
2767 ret = vvfat_write(bs, sector_num, buf, nb_sectors);
2768 qemu_co_mutex_unlock(&s->lock);
2769 return ret;
2772 static int coroutine_fn vvfat_co_is_allocated(BlockDriverState *bs,
2773 int64_t sector_num, int nb_sectors, int* n)
2775 BDRVVVFATState* s = bs->opaque;
2776 *n = s->sector_count - sector_num;
2777 if (*n > nb_sectors)
2778 *n = nb_sectors;
2779 else if (*n < 0)
2780 return 0;
2781 return 1;
2784 static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
2785 const uint8_t* buffer, int nb_sectors) {
2786 BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
2787 return try_commit(s);
2790 static void write_target_close(BlockDriverState *bs) {
2791 BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
2792 bdrv_delete(s->qcow);
2793 g_free(s->qcow_filename);
2796 static BlockDriver vvfat_write_target = {
2797 .format_name = "vvfat_write_target",
2798 .bdrv_write = write_target_commit,
2799 .bdrv_close = write_target_close,
2802 static int enable_write_target(BDRVVVFATState *s)
2804 BlockDriver *bdrv_qcow;
2805 QEMUOptionParameter *options;
2806 int ret;
2807 int size = sector2cluster(s, s->sector_count);
2808 s->used_clusters = calloc(size, 1);
2810 array_init(&(s->commits), sizeof(commit_t));
2812 s->qcow_filename = g_malloc(1024);
2813 ret = get_tmp_filename(s->qcow_filename, 1024);
2814 if (ret < 0) {
2815 g_free(s->qcow_filename);
2816 s->qcow_filename = NULL;
2817 return ret;
2820 bdrv_qcow = bdrv_find_format("qcow");
2821 options = parse_option_parameters("", bdrv_qcow->create_options, NULL);
2822 set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512);
2823 set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:");
2825 if (bdrv_create(bdrv_qcow, s->qcow_filename, options) < 0)
2826 return -1;
2828 s->qcow = bdrv_new("");
2829 if (s->qcow == NULL) {
2830 return -1;
2833 ret = bdrv_open(s->qcow, s->qcow_filename,
2834 BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, bdrv_qcow);
2835 if (ret < 0) {
2836 return ret;
2839 #ifndef _WIN32
2840 unlink(s->qcow_filename);
2841 #endif
2843 s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
2844 s->bs->backing_hd->drv = &vvfat_write_target;
2845 s->bs->backing_hd->opaque = g_malloc(sizeof(void*));
2846 *(void**)s->bs->backing_hd->opaque = s;
2848 return 0;
2851 static void vvfat_close(BlockDriverState *bs)
2853 BDRVVVFATState *s = bs->opaque;
2855 vvfat_close_current_file(s);
2856 array_free(&(s->fat));
2857 array_free(&(s->directory));
2858 array_free(&(s->mapping));
2859 g_free(s->cluster_buffer);
2861 if (s->qcow) {
2862 migrate_del_blocker(s->migration_blocker);
2863 error_free(s->migration_blocker);
2867 static BlockDriver bdrv_vvfat = {
2868 .format_name = "vvfat",
2869 .instance_size = sizeof(BDRVVVFATState),
2870 .bdrv_file_open = vvfat_open,
2871 .bdrv_rebind = vvfat_rebind,
2872 .bdrv_read = vvfat_co_read,
2873 .bdrv_write = vvfat_co_write,
2874 .bdrv_close = vvfat_close,
2875 .bdrv_co_is_allocated = vvfat_co_is_allocated,
2876 .protocol_name = "fat",
2879 static void bdrv_vvfat_init(void)
2881 bdrv_register(&bdrv_vvfat);
2884 block_init(bdrv_vvfat_init);
2886 #ifdef DEBUG
2887 static void checkpoint(void) {
2888 assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
2889 check1(vvv);
2890 check2(vvv);
2891 assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
2892 #if 0
2893 if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
2894 fprintf(stderr, "Nonono!\n");
2895 mapping_t* mapping;
2896 direntry_t* direntry;
2897 assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
2898 assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
2899 if (vvv->mapping.next<47)
2900 return;
2901 assert((mapping = array_get(&(vvv->mapping), 47)));
2902 assert(mapping->dir_index < vvv->directory.next);
2903 direntry = array_get(&(vvv->directory), mapping->dir_index);
2904 assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0);
2905 #endif
2907 #endif