1 /* vim:set shiftwidth=4 ts=4: */
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
25 #include "qemu/osdep.h"
27 #include "qapi/error.h"
28 #include "block/block_int.h"
29 #include "qemu/module.h"
30 #include "qemu/bswap.h"
31 #include "migration/migration.h"
32 #include "qapi/qmp/qint.h"
33 #include "qapi/qmp/qbool.h"
34 #include "qapi/qmp/qstring.h"
35 #include "qemu/cutils.h"
44 /* TODO: add ":bootsector=blabla.img:" */
45 /* LATER TODO: add automatic boot sector generation from
46 BOOTEASY.ASM and Ranish Partition Manager
47 Note that DOS assumes the system files to be the first files in the
48 file system (test if the boot sector still relies on that fact)! */
49 /* MAYBE TODO: write block-visofs.c */
50 /* TODO: call try_commit() only after a timeout */
58 static void checkpoint(void);
61 void nonono(const char* file
, int line
, const char* msg
) {
62 fprintf(stderr
, "Nonono! %s:%d %s\n", file
, line
, msg
);
66 #define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
75 /* dynamic array functions */
76 typedef struct array_t
{
78 unsigned int size
,next
,item_size
;
81 static inline void array_init(array_t
* array
,unsigned int item_size
)
83 array
->pointer
= NULL
;
86 array
->item_size
=item_size
;
89 static inline void array_free(array_t
* array
)
91 g_free(array
->pointer
);
92 array
->size
=array
->next
=0;
95 /* does not automatically grow */
96 static inline void* array_get(array_t
* array
,unsigned int index
) {
97 assert(index
< array
->next
);
98 return array
->pointer
+ index
* array
->item_size
;
101 static inline int array_ensure_allocated(array_t
* array
, int index
)
103 if((index
+ 1) * array
->item_size
> array
->size
) {
104 int new_size
= (index
+ 32) * array
->item_size
;
105 array
->pointer
= g_realloc(array
->pointer
, new_size
);
108 array
->size
= new_size
;
109 array
->next
= index
+ 1;
115 static inline void* array_get_next(array_t
* array
) {
116 unsigned int next
= array
->next
;
118 if (array_ensure_allocated(array
, next
) < 0)
121 array
->next
= next
+ 1;
122 return array_get(array
, next
);
125 static inline void* array_insert(array_t
* array
,unsigned int index
,unsigned int count
) {
126 if((array
->next
+count
)*array
->item_size
>array
->size
) {
127 int increment
=count
*array
->item_size
;
128 array
->pointer
=g_realloc(array
->pointer
,array
->size
+increment
);
131 array
->size
+=increment
;
133 memmove(array
->pointer
+(index
+count
)*array
->item_size
,
134 array
->pointer
+index
*array
->item_size
,
135 (array
->next
-index
)*array
->item_size
);
137 return array
->pointer
+index
*array
->item_size
;
140 /* this performs a "roll", so that the element which was at index_from becomes
141 * index_to, but the order of all other elements is preserved. */
142 static inline int array_roll(array_t
* array
,int index_to
,int index_from
,int count
)
150 index_to
<0 || index_to
>=array
->next
||
151 index_from
<0 || index_from
>=array
->next
)
154 if(index_to
==index_from
)
158 from
=array
->pointer
+index_from
*is
;
159 to
=array
->pointer
+index_to
*is
;
160 buf
=g_malloc(is
*count
);
161 memcpy(buf
,from
,is
*count
);
163 if(index_to
<index_from
)
164 memmove(to
+is
*count
,to
,from
-to
);
166 memmove(from
,from
+is
*count
,to
-from
);
168 memcpy(to
,buf
,is
*count
);
175 static inline int array_remove_slice(array_t
* array
,int index
, int count
)
179 assert(index
+ count
<= array
->next
);
180 if(array_roll(array
,array
->next
-1,index
,count
))
182 array
->next
-= count
;
186 static int array_remove(array_t
* array
,int index
)
188 return array_remove_slice(array
, index
, 1);
191 /* return the index for a given member */
192 static int array_index(array_t
* array
, void* pointer
)
194 size_t offset
= (char*)pointer
- array
->pointer
;
195 assert((offset
% array
->item_size
) == 0);
196 assert(offset
/array
->item_size
< array
->next
);
197 return offset
/array
->item_size
;
200 /* These structures are used to fake a disk and the VFAT filesystem.
201 * For this reason we need to use QEMU_PACKED. */
203 typedef struct bootsector_t
{
206 uint16_t sector_size
;
207 uint8_t sectors_per_cluster
;
208 uint16_t reserved_sectors
;
209 uint8_t number_of_fats
;
210 uint16_t root_entries
;
211 uint16_t total_sectors16
;
213 uint16_t sectors_per_fat
;
214 uint16_t sectors_per_track
;
215 uint16_t number_of_heads
;
216 uint32_t hidden_sectors
;
217 uint32_t total_sectors
;
220 uint8_t drive_number
;
221 uint8_t current_head
;
224 uint8_t volume_label
[11];
227 uint32_t sectors_per_fat
;
230 uint32_t first_cluster_of_root_directory
;
231 uint16_t info_sector
;
232 uint16_t backup_boot_sector
;
237 uint8_t ignored
[0x1c0];
239 } QEMU_PACKED bootsector_t
;
247 typedef struct partition_t
{
248 uint8_t attributes
; /* 0x80 = bootable */
250 uint8_t fs_type
; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
252 uint32_t start_sector_long
;
253 uint32_t length_sector_long
;
254 } QEMU_PACKED partition_t
;
256 typedef struct mbr_t
{
257 uint8_t ignored
[0x1b8];
260 partition_t partition
[4];
264 typedef struct direntry_t
{
276 } QEMU_PACKED direntry_t
;
278 /* this structure are used to transparently access the files */
280 typedef struct mapping_t
{
281 /* begin is the first cluster, end is the last+1 */
283 /* as s->directory is growable, no pointer may be used here */
284 unsigned int dir_index
;
285 /* the clusters of a file may be in any order; this points to the first */
286 int first_mapping_index
;
289 * - the offset in the file (in clusters) for a file, or
290 * - the next cluster of the directory for a directory, and
291 * - the address of the buffer for a faked entry
297 int parent_mapping_index
;
301 /* path contains the full path, i.e. it always starts with s->path */
304 enum { MODE_UNDEFINED
= 0, MODE_NORMAL
= 1, MODE_MODIFIED
= 2,
305 MODE_DIRECTORY
= 4, MODE_FAKED
= 8,
306 MODE_DELETED
= 16, MODE_RENAMED
= 32 } mode
;
311 static void print_direntry(const struct direntry_t
*);
312 static void print_mapping(const struct mapping_t
* mapping
);
315 /* here begins the real VVFAT driver */
317 typedef struct BDRVVVFATState
{
319 BlockDriverState
* bs
; /* pointer to parent */
320 unsigned int first_sectors_number
; /* 1 for a single partition, 0x40 for a disk with partition table */
321 unsigned char first_sectors
[0x40*0x200];
323 int fat_type
; /* 16 or 32 */
324 array_t fat
,directory
,mapping
;
325 char volume_label
[11];
327 unsigned int cluster_size
;
328 unsigned int sectors_per_cluster
;
329 unsigned int sectors_per_fat
;
330 unsigned int sectors_of_root_directory
;
331 uint32_t last_cluster_of_root_directory
;
332 unsigned int faked_sectors
; /* how many sectors are faked before file data */
333 uint32_t sector_count
; /* total number of sectors of the partition */
334 uint32_t cluster_count
; /* total number of clusters of this partition */
335 uint32_t max_fat_value
;
338 mapping_t
* current_mapping
;
339 unsigned char* cluster
; /* points to current cluster */
340 unsigned char* cluster_buffer
; /* points to a buffer to hold temp data */
341 unsigned int current_cluster
;
344 BlockDriverState
* write_target
;
346 BlockDriverState
* qcow
;
351 int downcase_short_names
;
353 Error
*migration_blocker
;
356 /* take the sector position spos and convert it to Cylinder/Head/Sector position
357 * if the position is outside the specified geometry, fill maximum value for CHS
358 * and return 1 to signal overflow.
360 static int sector2CHS(mbr_chs_t
*chs
, int spos
, int cyls
, int heads
, int secs
)
363 sector
= spos
% secs
; spos
/= secs
;
364 head
= spos
% heads
; spos
/= heads
;
367 it happens if 32bit sector positions are used, while CHS is only 24bit.
368 Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
371 chs
->cylinder
= 0xFF;
374 chs
->head
= (uint8_t)head
;
375 chs
->sector
= (uint8_t)( (sector
+1) | ((spos
>>8)<<6) );
376 chs
->cylinder
= (uint8_t)spos
;
380 static void init_mbr(BDRVVVFATState
*s
, int cyls
, int heads
, int secs
)
382 /* TODO: if the files mbr.img and bootsect.img exist, use them */
383 mbr_t
* real_mbr
=(mbr_t
*)s
->first_sectors
;
384 partition_t
* partition
= &(real_mbr
->partition
[0]);
387 memset(s
->first_sectors
,0,512);
389 /* Win NT Disk Signature */
390 real_mbr
->nt_id
= cpu_to_le32(0xbe1afdfa);
392 partition
->attributes
=0x80; /* bootable */
394 /* LBA is used when partition is outside the CHS geometry */
395 lba
= sector2CHS(&partition
->start_CHS
, s
->first_sectors_number
- 1,
397 lba
|= sector2CHS(&partition
->end_CHS
, s
->bs
->total_sectors
- 1,
400 /*LBA partitions are identified only by start/length_sector_long not by CHS*/
401 partition
->start_sector_long
= cpu_to_le32(s
->first_sectors_number
- 1);
402 partition
->length_sector_long
= cpu_to_le32(s
->bs
->total_sectors
403 - s
->first_sectors_number
+ 1);
405 /* FAT12/FAT16/FAT32 */
406 /* DOS uses different types when partition is LBA,
407 probably to prevent older versions from using CHS on them */
408 partition
->fs_type
= s
->fat_type
==12 ? 0x1:
409 s
->fat_type
==16 ? (lba
?0xe:0x06):
410 /*fat_tyoe==32*/ (lba
?0xc:0x0b);
412 real_mbr
->magic
[0]=0x55; real_mbr
->magic
[1]=0xaa;
415 /* direntry functions */
417 /* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
418 static inline int short2long_name(char* dest
,const char* src
)
422 for(i
=0;i
<129 && src
[i
];i
++) {
427 dest
[2*i
]=dest
[2*i
+1]=0;
428 for(i
=2*i
+2;(i
%26);i
++)
433 static inline direntry_t
* create_long_filename(BDRVVVFATState
* s
,const char* filename
)
436 int length
=short2long_name(buffer
,filename
),
437 number_of_entries
=(length
+25)/26,i
;
440 for(i
=0;i
<number_of_entries
;i
++) {
441 entry
=array_get_next(&(s
->directory
));
442 entry
->attributes
=0xf;
443 entry
->reserved
[0]=0;
445 entry
->name
[0]=(number_of_entries
-i
)|(i
==0?0x40:0);
447 for(i
=0;i
<26*number_of_entries
;i
++) {
449 if(offset
<10) offset
=1+offset
;
450 else if(offset
<22) offset
=14+offset
-10;
451 else offset
=28+offset
-22;
452 entry
=array_get(&(s
->directory
),s
->directory
.next
-1-(i
/26));
453 entry
->name
[offset
]=buffer
[i
];
455 return array_get(&(s
->directory
),s
->directory
.next
-number_of_entries
);
458 static char is_free(const direntry_t
* direntry
)
460 return direntry
->name
[0]==0xe5 || direntry
->name
[0]==0x00;
463 static char is_volume_label(const direntry_t
* direntry
)
465 return direntry
->attributes
== 0x28;
468 static char is_long_name(const direntry_t
* direntry
)
470 return direntry
->attributes
== 0xf;
473 static char is_short_name(const direntry_t
* direntry
)
475 return !is_volume_label(direntry
) && !is_long_name(direntry
)
476 && !is_free(direntry
);
479 static char is_directory(const direntry_t
* direntry
)
481 return direntry
->attributes
& 0x10 && direntry
->name
[0] != 0xe5;
484 static inline char is_dot(const direntry_t
* direntry
)
486 return is_short_name(direntry
) && direntry
->name
[0] == '.';
489 static char is_file(const direntry_t
* direntry
)
491 return is_short_name(direntry
) && !is_directory(direntry
);
494 static inline uint32_t begin_of_direntry(const direntry_t
* direntry
)
496 return le16_to_cpu(direntry
->begin
)|(le16_to_cpu(direntry
->begin_hi
)<<16);
499 static inline uint32_t filesize_of_direntry(const direntry_t
* direntry
)
501 return le32_to_cpu(direntry
->size
);
504 static void set_begin_of_direntry(direntry_t
* direntry
, uint32_t begin
)
506 direntry
->begin
= cpu_to_le16(begin
& 0xffff);
507 direntry
->begin_hi
= cpu_to_le16((begin
>> 16) & 0xffff);
512 static inline uint8_t fat_chksum(const direntry_t
* entry
)
517 for (i
= 0; i
< ARRAY_SIZE(entry
->name
); i
++) {
518 chksum
= (((chksum
& 0xfe) >> 1) |
519 ((chksum
& 0x01) ? 0x80 : 0)) + entry
->name
[i
];
525 /* if return_time==0, this returns the fat_date, else the fat_time */
526 static uint16_t fat_datetime(time_t time
,int return_time
) {
530 localtime_r(&time
,t
);
532 return cpu_to_le16((t
->tm_sec
/2)|(t
->tm_min
<<5)|(t
->tm_hour
<<11));
533 return cpu_to_le16((t
->tm_mday
)|((t
->tm_mon
+1)<<5)|((t
->tm_year
-80)<<9));
536 static inline void fat_set(BDRVVVFATState
* s
,unsigned int cluster
,uint32_t value
)
538 if(s
->fat_type
==32) {
539 uint32_t* entry
=array_get(&(s
->fat
),cluster
);
540 *entry
=cpu_to_le32(value
);
541 } else if(s
->fat_type
==16) {
542 uint16_t* entry
=array_get(&(s
->fat
),cluster
);
543 *entry
=cpu_to_le16(value
&0xffff);
545 int offset
= (cluster
*3/2);
546 unsigned char* p
= array_get(&(s
->fat
), offset
);
550 p
[1] = (p
[1]&0xf0) | ((value
>>8)&0xf);
553 p
[0] = (p
[0]&0xf) | ((value
&0xf)<<4);
560 static inline uint32_t fat_get(BDRVVVFATState
* s
,unsigned int cluster
)
562 if(s
->fat_type
==32) {
563 uint32_t* entry
=array_get(&(s
->fat
),cluster
);
564 return le32_to_cpu(*entry
);
565 } else if(s
->fat_type
==16) {
566 uint16_t* entry
=array_get(&(s
->fat
),cluster
);
567 return le16_to_cpu(*entry
);
569 const uint8_t* x
=(uint8_t*)(s
->fat
.pointer
)+cluster
*3/2;
570 return ((x
[0]|(x
[1]<<8))>>(cluster
&1?4:0))&0x0fff;
574 static inline int fat_eof(BDRVVVFATState
* s
,uint32_t fat_entry
)
576 if(fat_entry
>s
->max_fat_value
-8)
581 static inline void init_fat(BDRVVVFATState
* s
)
583 if (s
->fat_type
== 12) {
584 array_init(&(s
->fat
),1);
585 array_ensure_allocated(&(s
->fat
),
586 s
->sectors_per_fat
* 0x200 * 3 / 2 - 1);
588 array_init(&(s
->fat
),(s
->fat_type
==32?4:2));
589 array_ensure_allocated(&(s
->fat
),
590 s
->sectors_per_fat
* 0x200 / s
->fat
.item_size
- 1);
592 memset(s
->fat
.pointer
,0,s
->fat
.size
);
594 switch(s
->fat_type
) {
595 case 12: s
->max_fat_value
=0xfff; break;
596 case 16: s
->max_fat_value
=0xffff; break;
597 case 32: s
->max_fat_value
=0x0fffffff; break;
598 default: s
->max_fat_value
=0; /* error... */
603 /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
604 /* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
605 static inline direntry_t
* create_short_and_long_name(BDRVVVFATState
* s
,
606 unsigned int directory_start
, const char* filename
, int is_dot
)
608 int i
,j
,long_index
=s
->directory
.next
;
609 direntry_t
* entry
= NULL
;
610 direntry_t
* entry_long
= NULL
;
613 entry
=array_get_next(&(s
->directory
));
614 memset(entry
->name
, 0x20, sizeof(entry
->name
));
615 memcpy(entry
->name
,filename
,strlen(filename
));
619 entry_long
=create_long_filename(s
,filename
);
621 i
= strlen(filename
);
622 for(j
= i
- 1; j
>0 && filename
[j
]!='.';j
--);
628 entry
=array_get_next(&(s
->directory
));
629 memset(entry
->name
, 0x20, sizeof(entry
->name
));
630 memcpy(entry
->name
, filename
, i
);
633 for (i
= 0; i
< 3 && filename
[j
+ 1 + i
]; i
++) {
634 entry
->name
[8 + i
] = filename
[j
+ 1 + i
];
638 /* upcase & remove unwanted characters */
640 if(i
==10 || i
==7) for(;i
>0 && entry
->name
[i
]==' ';i
--);
641 if(entry
->name
[i
]<=' ' || entry
->name
[i
]>0x7f
642 || strchr(".*?<>|\":/\\[];,+='",entry
->name
[i
]))
644 else if(entry
->name
[i
]>='a' && entry
->name
[i
]<='z')
645 entry
->name
[i
]+='A'-'a';
648 /* mangle duplicates */
650 direntry_t
* entry1
=array_get(&(s
->directory
),directory_start
);
653 for(;entry1
<entry
;entry1
++)
654 if(!is_long_name(entry1
) && !memcmp(entry1
->name
,entry
->name
,11))
655 break; /* found dupe */
656 if(entry1
==entry
) /* no dupe found */
659 /* use all 8 characters of name */
660 if(entry
->name
[7]==' ') {
662 for(j
=6;j
>0 && entry
->name
[j
]==' ';j
--)
666 /* increment number */
667 for(j
=7;j
>0 && entry
->name
[j
]=='9';j
--)
670 if(entry
->name
[j
]<'0' || entry
->name
[j
]>'9')
677 /* calculate checksum; propagate to long name */
679 uint8_t chksum
=fat_chksum(entry
);
681 /* calculate anew, because realloc could have taken place */
682 entry_long
=array_get(&(s
->directory
),long_index
);
683 while(entry_long
<entry
&& is_long_name(entry_long
)) {
684 entry_long
->reserved
[1]=chksum
;
693 * Read a directory. (the index of the corresponding mapping must be passed).
695 static int read_directory(BDRVVVFATState
* s
, int mapping_index
)
697 mapping_t
* mapping
= array_get(&(s
->mapping
), mapping_index
);
698 direntry_t
* direntry
;
699 const char* dirname
= mapping
->path
;
700 int first_cluster
= mapping
->begin
;
701 int parent_index
= mapping
->info
.dir
.parent_mapping_index
;
702 mapping_t
* parent_mapping
= (mapping_t
*)
703 (parent_index
>= 0 ? array_get(&(s
->mapping
), parent_index
) : NULL
);
704 int first_cluster_of_parent
= parent_mapping
? parent_mapping
->begin
: -1;
706 DIR* dir
=opendir(dirname
);
707 struct dirent
* entry
;
710 assert(mapping
->mode
& MODE_DIRECTORY
);
713 mapping
->end
= mapping
->begin
;
717 i
= mapping
->info
.dir
.first_dir_index
=
718 first_cluster
== 0 ? 0 : s
->directory
.next
;
720 /* actually read the directory, and allocate the mappings */
721 while((entry
=readdir(dir
))) {
722 unsigned int length
=strlen(dirname
)+2+strlen(entry
->d_name
);
724 direntry_t
* direntry
;
726 int is_dot
=!strcmp(entry
->d_name
,".");
727 int is_dotdot
=!strcmp(entry
->d_name
,"..");
729 if(first_cluster
== 0 && (is_dotdot
|| is_dot
))
732 buffer
= g_malloc(length
);
733 snprintf(buffer
,length
,"%s/%s",dirname
,entry
->d_name
);
735 if(stat(buffer
,&st
)<0) {
740 /* create directory entry for this file */
741 direntry
=create_short_and_long_name(s
, i
, entry
->d_name
,
742 is_dot
|| is_dotdot
);
743 direntry
->attributes
=(S_ISDIR(st
.st_mode
)?0x10:0x20);
744 direntry
->reserved
[0]=direntry
->reserved
[1]=0;
745 direntry
->ctime
=fat_datetime(st
.st_ctime
,1);
746 direntry
->cdate
=fat_datetime(st
.st_ctime
,0);
747 direntry
->adate
=fat_datetime(st
.st_atime
,0);
748 direntry
->begin_hi
=0;
749 direntry
->mtime
=fat_datetime(st
.st_mtime
,1);
750 direntry
->mdate
=fat_datetime(st
.st_mtime
,0);
752 set_begin_of_direntry(direntry
, first_cluster_of_parent
);
754 set_begin_of_direntry(direntry
, first_cluster
);
756 direntry
->begin
=0; /* do that later */
757 if (st
.st_size
> 0x7fffffff) {
758 fprintf(stderr
, "File %s is larger than 2GB\n", buffer
);
763 direntry
->size
=cpu_to_le32(S_ISDIR(st
.st_mode
)?0:st
.st_size
);
765 /* create mapping for this file */
766 if(!is_dot
&& !is_dotdot
&& (S_ISDIR(st
.st_mode
) || st
.st_size
)) {
767 s
->current_mapping
= array_get_next(&(s
->mapping
));
768 s
->current_mapping
->begin
=0;
769 s
->current_mapping
->end
=st
.st_size
;
771 * we get the direntry of the most recent direntry, which
772 * contains the short name and all the relevant information.
774 s
->current_mapping
->dir_index
=s
->directory
.next
-1;
775 s
->current_mapping
->first_mapping_index
= -1;
776 if (S_ISDIR(st
.st_mode
)) {
777 s
->current_mapping
->mode
= MODE_DIRECTORY
;
778 s
->current_mapping
->info
.dir
.parent_mapping_index
=
781 s
->current_mapping
->mode
= MODE_UNDEFINED
;
782 s
->current_mapping
->info
.file
.offset
= 0;
784 s
->current_mapping
->path
=buffer
;
785 s
->current_mapping
->read_only
=
786 (st
.st_mode
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) == 0;
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
) {
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
= 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
= array_get(&(s
->directory
), mapping
->dir_index
);
817 set_begin_of_direntry(direntry
, mapping
->begin
);
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
,
836 bootsector_t
* bootsector
;
839 unsigned int cluster
;
841 memset(&(s
->first_sectors
[0]),0,0x40*0x200);
843 s
->cluster_size
=s
->sectors_per_cluster
*0x200;
844 s
->cluster_buffer
=g_malloc(s
->cluster_size
);
847 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
848 * where sc is sector_count,
849 * spf is sectors_per_fat,
850 * spc is sectors_per_clusters, and
851 * fat_type = 12, 16 or 32.
853 i
= 1+s
->sectors_per_cluster
*0x200*8/s
->fat_type
;
854 s
->sectors_per_fat
=(s
->sector_count
+i
)/i
; /* round up */
856 array_init(&(s
->mapping
),sizeof(mapping_t
));
857 array_init(&(s
->directory
),sizeof(direntry_t
));
859 /* add volume label */
861 direntry_t
* entry
=array_get_next(&(s
->directory
));
862 entry
->attributes
=0x28; /* archive | volume label */
863 memcpy(entry
->name
, s
->volume_label
, sizeof(entry
->name
));
866 /* Now build FAT, and write back information into directory */
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
));
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 error_setg(errp
, "Could not read directory %s",
899 mapping
= array_get(&(s
->mapping
), i
);
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
),
908 mapping
->end
= cluster
+ 1 + (mapping
->end
-1)/s
->cluster_size
;
909 set_begin_of_direntry(direntry
, mapping
->begin
);
911 mapping
->end
= cluster
+ 1;
916 assert(mapping
->begin
< mapping
->end
);
918 /* next free cluster */
919 cluster
= mapping
->end
;
921 if(cluster
> s
->cluster_count
) {
923 "Directory does not fit in FAT%d (capacity %.2f MB)",
924 s
->fat_type
, s
->sector_count
/ 2000.0);
928 /* fix fat for entry */
931 for(j
= mapping
->begin
; j
< mapping
->end
- 1; j
++)
933 fat_set(s
, mapping
->end
- 1, s
->max_fat_value
);
937 mapping
= array_get(&(s
->mapping
), 0);
938 s
->sectors_of_root_directory
= mapping
->end
* s
->sectors_per_cluster
;
939 s
->last_cluster_of_root_directory
= mapping
->end
;
941 /* the FAT signature */
942 fat_set(s
,0,s
->max_fat_value
);
943 fat_set(s
,1,s
->max_fat_value
);
945 s
->current_mapping
= NULL
;
947 bootsector
=(bootsector_t
*)(s
->first_sectors
+(s
->first_sectors_number
-1)*0x200);
948 bootsector
->jump
[0]=0xeb;
949 bootsector
->jump
[1]=0x3e;
950 bootsector
->jump
[2]=0x90;
951 memcpy(bootsector
->name
,"QEMU ",8);
952 bootsector
->sector_size
=cpu_to_le16(0x200);
953 bootsector
->sectors_per_cluster
=s
->sectors_per_cluster
;
954 bootsector
->reserved_sectors
=cpu_to_le16(1);
955 bootsector
->number_of_fats
=0x2; /* number of FATs */
956 bootsector
->root_entries
=cpu_to_le16(s
->sectors_of_root_directory
*0x10);
957 bootsector
->total_sectors16
=s
->sector_count
>0xffff?0:cpu_to_le16(s
->sector_count
);
958 bootsector
->media_type
=(s
->first_sectors_number
>1?0xf8:0xf0); /* media descriptor (f8=hd, f0=3.5 fd)*/
959 s
->fat
.pointer
[0] = bootsector
->media_type
;
960 bootsector
->sectors_per_fat
=cpu_to_le16(s
->sectors_per_fat
);
961 bootsector
->sectors_per_track
= cpu_to_le16(secs
);
962 bootsector
->number_of_heads
= cpu_to_le16(heads
);
963 bootsector
->hidden_sectors
=cpu_to_le32(s
->first_sectors_number
==1?0:0x3f);
964 bootsector
->total_sectors
=cpu_to_le32(s
->sector_count
>0xffff?s
->sector_count
:0);
966 /* LATER TODO: if FAT32, this is wrong */
967 bootsector
->u
.fat16
.drive_number
=s
->first_sectors_number
==1?0:0x80; /* fda=0, hda=0x80 */
968 bootsector
->u
.fat16
.current_head
=0;
969 bootsector
->u
.fat16
.signature
=0x29;
970 bootsector
->u
.fat16
.id
=cpu_to_le32(0xfabe1afd);
972 memcpy(bootsector
->u
.fat16
.volume_label
, s
->volume_label
,
973 sizeof(bootsector
->u
.fat16
.volume_label
));
974 memcpy(bootsector
->fat_type
,(s
->fat_type
==12?"FAT12 ":s
->fat_type
==16?"FAT16 ":"FAT32 "),8);
975 bootsector
->magic
[0]=0x55; bootsector
->magic
[1]=0xaa;
981 static BDRVVVFATState
*vvv
= NULL
;
984 static int enable_write_target(BDRVVVFATState
*s
, Error
**errp
);
985 static int is_consistent(BDRVVVFATState
*s
);
987 static QemuOptsList runtime_opts
= {
989 .head
= QTAILQ_HEAD_INITIALIZER(runtime_opts
.head
),
993 .type
= QEMU_OPT_STRING
,
994 .help
= "Host directory to map to the vvfat device",
998 .type
= QEMU_OPT_NUMBER
,
999 .help
= "FAT type (12, 16 or 32)",
1003 .type
= QEMU_OPT_BOOL
,
1004 .help
= "Create a floppy rather than a hard disk image",
1008 .type
= QEMU_OPT_STRING
,
1009 .help
= "Use a volume label other than QEMU VVFAT",
1013 .type
= QEMU_OPT_BOOL
,
1014 .help
= "Make the image writable",
1016 { /* end of list */ }
1020 static void vvfat_parse_filename(const char *filename
, QDict
*options
,
1024 bool floppy
= false;
1028 if (!strstart(filename
, "fat:", NULL
)) {
1029 error_setg(errp
, "File name string must start with 'fat:'");
1034 if (strstr(filename
, ":32:")) {
1036 } else if (strstr(filename
, ":16:")) {
1038 } else if (strstr(filename
, ":12:")) {
1042 if (strstr(filename
, ":floppy:")) {
1046 if (strstr(filename
, ":rw:")) {
1050 /* Get the directory name without options */
1051 i
= strrchr(filename
, ':') - filename
;
1053 if (filename
[i
- 2] == ':' && qemu_isalpha(filename
[i
- 1])) {
1054 /* workaround for DOS drive names */
1060 /* Fill in the options QDict */
1061 qdict_put(options
, "dir", qstring_from_str(filename
));
1062 qdict_put(options
, "fat-type", qint_from_int(fat_type
));
1063 qdict_put(options
, "floppy", qbool_from_bool(floppy
));
1064 qdict_put(options
, "rw", qbool_from_bool(rw
));
1067 static int vvfat_open(BlockDriverState
*bs
, QDict
*options
, int flags
,
1070 BDRVVVFATState
*s
= bs
->opaque
;
1071 int cyls
, heads
, secs
;
1073 const char *dirname
, *label
;
1075 Error
*local_err
= NULL
;
1082 opts
= qemu_opts_create(&runtime_opts
, NULL
, 0, &error_abort
);
1083 qemu_opts_absorb_qdict(opts
, options
, &local_err
);
1085 error_propagate(errp
, local_err
);
1090 dirname
= qemu_opt_get(opts
, "dir");
1092 error_setg(errp
, "vvfat block driver requires a 'dir' option");
1097 s
->fat_type
= qemu_opt_get_number(opts
, "fat-type", 0);
1098 floppy
= qemu_opt_get_bool(opts
, "floppy", false);
1100 memset(s
->volume_label
, ' ', sizeof(s
->volume_label
));
1101 label
= qemu_opt_get(opts
, "label");
1103 size_t label_length
= strlen(label
);
1104 if (label_length
> 11) {
1105 error_setg(errp
, "vvfat label cannot be longer than 11 bytes");
1109 memcpy(s
->volume_label
, label
, label_length
);
1111 memcpy(s
->volume_label
, "QEMU VVFAT", 10);
1115 /* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */
1119 s
->sectors_per_cluster
= 2;
1121 secs
= s
->fat_type
== 12 ? 18 : 36;
1122 s
->sectors_per_cluster
= 1;
1124 s
->first_sectors_number
= 1;
1128 /* 32MB or 504MB disk*/
1132 s
->first_sectors_number
= 0x40;
1133 cyls
= s
->fat_type
== 12 ? 64 : 1024;
1138 switch (s
->fat_type
) {
1140 fprintf(stderr
, "Big fat greek warning: FAT32 has not been tested. "
1141 "You are welcome to do so!\n");
1147 error_setg(errp
, "Valid FAT types are only 12, 16 and 32");
1155 /* LATER TODO: if FAT32, adjust */
1156 s
->sectors_per_cluster
=0x10;
1158 s
->current_cluster
=0xffffffff;
1160 /* read only is the default for safety */
1162 s
->qcow
= s
->write_target
= NULL
;
1163 s
->qcow_filename
= NULL
;
1165 s
->downcase_short_names
= 1;
1167 fprintf(stderr
, "vvfat %s chs %d,%d,%d\n",
1168 dirname
, cyls
, heads
, secs
);
1170 s
->sector_count
= cyls
* heads
* secs
- (s
->first_sectors_number
- 1);
1172 if (qemu_opt_get_bool(opts
, "rw", false)) {
1173 ret
= enable_write_target(s
, errp
);
1180 bs
->request_alignment
= BDRV_SECTOR_SIZE
; /* No sub-sector I/O supported */
1181 bs
->total_sectors
= cyls
* heads
* secs
;
1183 if (init_directories(s
, dirname
, heads
, secs
, errp
)) {
1188 s
->sector_count
= s
->faked_sectors
+ s
->sectors_per_cluster
*s
->cluster_count
;
1190 if (s
->first_sectors_number
== 0x40) {
1191 init_mbr(s
, cyls
, heads
, secs
);
1194 // assert(is_consistent(s));
1195 qemu_co_mutex_init(&s
->lock
);
1197 /* Disable migration when vvfat is used rw */
1199 error_setg(&s
->migration_blocker
,
1200 "The vvfat (rw) format used by node '%s' "
1201 "does not support live migration",
1202 bdrv_get_device_or_node_name(bs
));
1203 migrate_add_blocker(s
->migration_blocker
);
1208 qemu_opts_del(opts
);
1212 static inline void vvfat_close_current_file(BDRVVVFATState
*s
)
1214 if(s
->current_mapping
) {
1215 s
->current_mapping
= NULL
;
1216 if (s
->current_fd
) {
1217 qemu_close(s
->current_fd
);
1221 s
->current_cluster
= -1;
1224 /* mappings between index1 and index2-1 are supposed to be ordered
1225 * return value is the index of the last mapping for which end>cluster_num
1227 static inline int find_mapping_for_cluster_aux(BDRVVVFATState
* s
,int cluster_num
,int index1
,int index2
)
1232 index3
=(index1
+index2
)/2;
1233 mapping
=array_get(&(s
->mapping
),index3
);
1234 assert(mapping
->begin
< mapping
->end
);
1235 if(mapping
->begin
>=cluster_num
) {
1236 assert(index2
!=index3
|| index2
==0);
1242 return mapping
->end
<=cluster_num
? index2
: index1
;
1245 assert(index1
<=index2
);
1246 DLOG(mapping
=array_get(&(s
->mapping
),index1
);
1247 assert(mapping
->begin
<=cluster_num
);
1248 assert(index2
>= s
->mapping
.next
||
1249 ((mapping
= array_get(&(s
->mapping
),index2
)) &&
1250 mapping
->end
>cluster_num
)));
1254 static inline mapping_t
* find_mapping_for_cluster(BDRVVVFATState
* s
,int cluster_num
)
1256 int index
=find_mapping_for_cluster_aux(s
,cluster_num
,0,s
->mapping
.next
);
1258 if(index
>=s
->mapping
.next
)
1260 mapping
=array_get(&(s
->mapping
),index
);
1261 if(mapping
->begin
>cluster_num
)
1263 assert(mapping
->begin
<=cluster_num
&& mapping
->end
>cluster_num
);
1267 static int open_file(BDRVVVFATState
* s
,mapping_t
* mapping
)
1271 if(!s
->current_mapping
||
1272 strcmp(s
->current_mapping
->path
,mapping
->path
)) {
1274 int fd
= qemu_open(mapping
->path
, O_RDONLY
| O_BINARY
| O_LARGEFILE
);
1277 vvfat_close_current_file(s
);
1279 s
->current_mapping
= mapping
;
1284 static inline int read_cluster(BDRVVVFATState
*s
,int cluster_num
)
1286 if(s
->current_cluster
!= cluster_num
) {
1289 assert(!s
->current_mapping
|| s
->current_fd
|| (s
->current_mapping
->mode
& MODE_DIRECTORY
));
1290 if(!s
->current_mapping
1291 || s
->current_mapping
->begin
>cluster_num
1292 || s
->current_mapping
->end
<=cluster_num
) {
1293 /* binary search of mappings for file */
1294 mapping_t
* mapping
=find_mapping_for_cluster(s
,cluster_num
);
1296 assert(!mapping
|| (cluster_num
>=mapping
->begin
&& cluster_num
<mapping
->end
));
1298 if (mapping
&& mapping
->mode
& MODE_DIRECTORY
) {
1299 vvfat_close_current_file(s
);
1300 s
->current_mapping
= mapping
;
1301 read_cluster_directory
:
1302 offset
= s
->cluster_size
*(cluster_num
-s
->current_mapping
->begin
);
1303 s
->cluster
= (unsigned char*)s
->directory
.pointer
+offset
1304 + 0x20*s
->current_mapping
->info
.dir
.first_dir_index
;
1305 assert(((s
->cluster
-(unsigned char*)s
->directory
.pointer
)%s
->cluster_size
)==0);
1306 assert((char*)s
->cluster
+s
->cluster_size
<= s
->directory
.pointer
+s
->directory
.next
*s
->directory
.item_size
);
1307 s
->current_cluster
= cluster_num
;
1311 if(open_file(s
,mapping
))
1313 } else if (s
->current_mapping
->mode
& MODE_DIRECTORY
)
1314 goto read_cluster_directory
;
1316 assert(s
->current_fd
);
1318 offset
=s
->cluster_size
*(cluster_num
-s
->current_mapping
->begin
)+s
->current_mapping
->info
.file
.offset
;
1319 if(lseek(s
->current_fd
, offset
, SEEK_SET
)!=offset
)
1321 s
->cluster
=s
->cluster_buffer
;
1322 result
=read(s
->current_fd
,s
->cluster
,s
->cluster_size
);
1324 s
->current_cluster
= -1;
1327 s
->current_cluster
= cluster_num
;
1333 static void print_direntry(const direntry_t
* direntry
)
1338 fprintf(stderr
, "direntry %p: ", direntry
);
1341 if(is_long_name(direntry
)) {
1342 unsigned char* c
=(unsigned char*)direntry
;
1344 for(i
=1;i
<11 && c
[i
] && c
[i
]!=0xff;i
+=2)
1345 #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
1347 for(i
=14;i
<26 && c
[i
] && c
[i
]!=0xff;i
+=2)
1349 for(i
=28;i
<32 && c
[i
] && c
[i
]!=0xff;i
+=2)
1352 fprintf(stderr
, "%s\n", buffer
);
1356 ADD_CHAR(direntry
->name
[i
]);
1358 fprintf(stderr
,"%s attributes=0x%02x begin=%d size=%d\n",
1360 direntry
->attributes
,
1361 begin_of_direntry(direntry
),le32_to_cpu(direntry
->size
));
1365 static void print_mapping(const mapping_t
* mapping
)
1367 fprintf(stderr
, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1368 "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1369 mapping
, mapping
->begin
, mapping
->end
, mapping
->dir_index
,
1370 mapping
->first_mapping_index
, mapping
->path
, mapping
->mode
);
1372 if (mapping
->mode
& MODE_DIRECTORY
)
1373 fprintf(stderr
, "parent_mapping_index = %d, first_dir_index = %d\n", mapping
->info
.dir
.parent_mapping_index
, mapping
->info
.dir
.first_dir_index
);
1375 fprintf(stderr
, "offset = %d\n", mapping
->info
.file
.offset
);
1379 static int vvfat_read(BlockDriverState
*bs
, int64_t sector_num
,
1380 uint8_t *buf
, int nb_sectors
)
1382 BDRVVVFATState
*s
= bs
->opaque
;
1385 for(i
=0;i
<nb_sectors
;i
++,sector_num
++) {
1386 if (sector_num
>= bs
->total_sectors
)
1390 if (bdrv_is_allocated(s
->qcow
, sector_num
, nb_sectors
-i
, &n
)) {
1391 DLOG(fprintf(stderr
, "sectors %d+%d allocated\n", (int)sector_num
, n
));
1392 if (bdrv_read(s
->qcow
, sector_num
, buf
+ i
*0x200, n
)) {
1396 sector_num
+= n
- 1;
1399 DLOG(fprintf(stderr
, "sector %d not allocated\n", (int)sector_num
));
1401 if(sector_num
<s
->faked_sectors
) {
1402 if(sector_num
<s
->first_sectors_number
)
1403 memcpy(buf
+i
*0x200,&(s
->first_sectors
[sector_num
*0x200]),0x200);
1404 else if(sector_num
-s
->first_sectors_number
<s
->sectors_per_fat
)
1405 memcpy(buf
+i
*0x200,&(s
->fat
.pointer
[(sector_num
-s
->first_sectors_number
)*0x200]),0x200);
1406 else if(sector_num
-s
->first_sectors_number
-s
->sectors_per_fat
<s
->sectors_per_fat
)
1407 memcpy(buf
+i
*0x200,&(s
->fat
.pointer
[(sector_num
-s
->first_sectors_number
-s
->sectors_per_fat
)*0x200]),0x200);
1409 uint32_t sector
=sector_num
-s
->faked_sectors
,
1410 sector_offset_in_cluster
=(sector
%s
->sectors_per_cluster
),
1411 cluster_num
=sector
/s
->sectors_per_cluster
;
1412 if(cluster_num
> s
->cluster_count
|| read_cluster(s
, cluster_num
) != 0) {
1413 /* LATER TODO: strict: return -1; */
1414 memset(buf
+i
*0x200,0,0x200);
1417 memcpy(buf
+i
*0x200,s
->cluster
+sector_offset_in_cluster
*0x200,0x200);
1423 static int coroutine_fn
1424 vvfat_co_preadv(BlockDriverState
*bs
, uint64_t offset
, uint64_t bytes
,
1425 QEMUIOVector
*qiov
, int flags
)
1428 BDRVVVFATState
*s
= bs
->opaque
;
1429 uint64_t sector_num
= offset
>> BDRV_SECTOR_BITS
;
1430 int nb_sectors
= bytes
>> BDRV_SECTOR_BITS
;
1433 assert((offset
& (BDRV_SECTOR_SIZE
- 1)) == 0);
1434 assert((bytes
& (BDRV_SECTOR_SIZE
- 1)) == 0);
1436 buf
= g_try_malloc(bytes
);
1437 if (bytes
&& buf
== NULL
) {
1441 qemu_co_mutex_lock(&s
->lock
);
1442 ret
= vvfat_read(bs
, sector_num
, buf
, nb_sectors
);
1443 qemu_co_mutex_unlock(&s
->lock
);
1445 qemu_iovec_from_buf(qiov
, 0, buf
, bytes
);
1451 /* LATER TODO: statify all functions */
1454 * Idea of the write support (use snapshot):
1456 * 1. check if all data is consistent, recording renames, modifications,
1457 * new files and directories (in s->commits).
1459 * 2. if the data is not consistent, stop committing
1461 * 3. handle renames, and create new files and directories (do not yet
1462 * write their contents)
1464 * 4. walk the directories, fixing the mapping and direntries, and marking
1465 * the handled mappings as not deleted
1467 * 5. commit the contents of the files
1469 * 6. handle deleted files and directories
1473 typedef struct commit_t
{
1476 struct { uint32_t cluster
; } rename
;
1477 struct { int dir_index
; uint32_t modified_offset
; } writeout
;
1478 struct { uint32_t first_cluster
; } new_file
;
1479 struct { uint32_t cluster
; } mkdir
;
1481 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1483 ACTION_RENAME
, ACTION_WRITEOUT
, ACTION_NEW_FILE
, ACTION_MKDIR
1487 static void clear_commits(BDRVVVFATState
* s
)
1490 DLOG(fprintf(stderr
, "clear_commits (%d commits)\n", s
->commits
.next
));
1491 for (i
= 0; i
< s
->commits
.next
; i
++) {
1492 commit_t
* commit
= array_get(&(s
->commits
), i
);
1493 assert(commit
->path
|| commit
->action
== ACTION_WRITEOUT
);
1494 if (commit
->action
!= ACTION_WRITEOUT
) {
1495 assert(commit
->path
);
1496 g_free(commit
->path
);
1498 assert(commit
->path
== NULL
);
1500 s
->commits
.next
= 0;
1503 static void schedule_rename(BDRVVVFATState
* s
,
1504 uint32_t cluster
, char* new_path
)
1506 commit_t
* commit
= array_get_next(&(s
->commits
));
1507 commit
->path
= new_path
;
1508 commit
->param
.rename
.cluster
= cluster
;
1509 commit
->action
= ACTION_RENAME
;
1512 static void schedule_writeout(BDRVVVFATState
* s
,
1513 int dir_index
, uint32_t modified_offset
)
1515 commit_t
* commit
= array_get_next(&(s
->commits
));
1516 commit
->path
= NULL
;
1517 commit
->param
.writeout
.dir_index
= dir_index
;
1518 commit
->param
.writeout
.modified_offset
= modified_offset
;
1519 commit
->action
= ACTION_WRITEOUT
;
1522 static void schedule_new_file(BDRVVVFATState
* s
,
1523 char* path
, uint32_t first_cluster
)
1525 commit_t
* commit
= array_get_next(&(s
->commits
));
1526 commit
->path
= path
;
1527 commit
->param
.new_file
.first_cluster
= first_cluster
;
1528 commit
->action
= ACTION_NEW_FILE
;
1531 static void schedule_mkdir(BDRVVVFATState
* s
, uint32_t cluster
, char* path
)
1533 commit_t
* commit
= array_get_next(&(s
->commits
));
1534 commit
->path
= path
;
1535 commit
->param
.mkdir
.cluster
= cluster
;
1536 commit
->action
= ACTION_MKDIR
;
1541 * Since the sequence number is at most 0x3f, and the filename
1542 * length is at most 13 times the sequence number, the maximal
1543 * filename length is 0x3f * 13 bytes.
1545 unsigned char name
[0x3f * 13 + 1];
1547 int sequence_number
;
1550 static void lfn_init(long_file_name
* lfn
)
1552 lfn
->sequence_number
= lfn
->len
= 0;
1553 lfn
->checksum
= 0x100;
1556 /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1557 static int parse_long_name(long_file_name
* lfn
,
1558 const direntry_t
* direntry
)
1561 const unsigned char* pointer
= (const unsigned char*)direntry
;
1563 if (!is_long_name(direntry
))
1566 if (pointer
[0] & 0x40) {
1567 lfn
->sequence_number
= pointer
[0] & 0x3f;
1568 lfn
->checksum
= pointer
[13];
1570 lfn
->name
[lfn
->sequence_number
* 13] = 0;
1571 } else if ((pointer
[0] & 0x3f) != --lfn
->sequence_number
)
1573 else if (pointer
[13] != lfn
->checksum
)
1575 else if (pointer
[12] || pointer
[26] || pointer
[27])
1578 offset
= 13 * (lfn
->sequence_number
- 1);
1579 for (i
= 0, j
= 1; i
< 13; i
++, j
+=2) {
1585 if (pointer
[j
+1] == 0)
1586 lfn
->name
[offset
+ i
] = pointer
[j
];
1587 else if (pointer
[j
+1] != 0xff || (pointer
[0] & 0x40) == 0)
1590 lfn
->name
[offset
+ i
] = 0;
1593 if (pointer
[0] & 0x40)
1594 lfn
->len
= offset
+ strlen((char*)lfn
->name
+ offset
);
1599 /* returns 0 if successful, >0 if no short_name, and <0 on error */
1600 static int parse_short_name(BDRVVVFATState
* s
,
1601 long_file_name
* lfn
, direntry_t
* direntry
)
1605 if (!is_short_name(direntry
))
1608 for (j
= 7; j
>= 0 && direntry
->name
[j
] == ' '; j
--);
1609 for (i
= 0; i
<= j
; i
++) {
1610 if (direntry
->name
[i
] <= ' ' || direntry
->name
[i
] > 0x7f)
1612 else if (s
->downcase_short_names
)
1613 lfn
->name
[i
] = qemu_tolower(direntry
->name
[i
]);
1615 lfn
->name
[i
] = direntry
->name
[i
];
1618 for (j
= 2; j
>= 0 && direntry
->name
[8 + j
] == ' '; j
--) {
1621 lfn
->name
[i
++] = '.';
1622 lfn
->name
[i
+ j
+ 1] = '\0';
1623 for (;j
>= 0; j
--) {
1624 uint8_t c
= direntry
->name
[8 + j
];
1625 if (c
<= ' ' || c
> 0x7f) {
1627 } else if (s
->downcase_short_names
) {
1628 lfn
->name
[i
+ j
] = qemu_tolower(c
);
1630 lfn
->name
[i
+ j
] = c
;
1634 lfn
->name
[i
+ j
+ 1] = '\0';
1636 lfn
->len
= strlen((char*)lfn
->name
);
1641 static inline uint32_t modified_fat_get(BDRVVVFATState
* s
,
1642 unsigned int cluster
)
1644 if (cluster
< s
->last_cluster_of_root_directory
) {
1645 if (cluster
+ 1 == s
->last_cluster_of_root_directory
)
1646 return s
->max_fat_value
;
1651 if (s
->fat_type
==32) {
1652 uint32_t* entry
=((uint32_t*)s
->fat2
)+cluster
;
1653 return le32_to_cpu(*entry
);
1654 } else if (s
->fat_type
==16) {
1655 uint16_t* entry
=((uint16_t*)s
->fat2
)+cluster
;
1656 return le16_to_cpu(*entry
);
1658 const uint8_t* x
=s
->fat2
+cluster
*3/2;
1659 return ((x
[0]|(x
[1]<<8))>>(cluster
&1?4:0))&0x0fff;
1663 static inline int cluster_was_modified(BDRVVVFATState
* s
, uint32_t cluster_num
)
1665 int was_modified
= 0;
1668 if (s
->qcow
== NULL
)
1671 for (i
= 0; !was_modified
&& i
< s
->sectors_per_cluster
; i
++)
1672 was_modified
= bdrv_is_allocated(s
->qcow
,
1673 cluster2sector(s
, cluster_num
) + i
, 1, &dummy
);
1675 return was_modified
;
1678 static const char* get_basename(const char* path
)
1680 char* basename
= strrchr(path
, '/');
1681 if (basename
== NULL
)
1684 return basename
+ 1; /* strip '/' */
1688 * The array s->used_clusters holds the states of the clusters. If it is
1689 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1690 * was modified, bit 3 is set.
1691 * If any cluster is allocated, but not part of a file or directory, this
1692 * driver refuses to commit.
1695 USED_DIRECTORY
= 1, USED_FILE
= 2, USED_ANY
= 3, USED_ALLOCATED
= 4
1699 * get_cluster_count_for_direntry() not only determines how many clusters
1700 * are occupied by direntry, but also if it was renamed or modified.
1702 * A file is thought to be renamed *only* if there already was a file with
1703 * exactly the same first cluster, but a different name.
1705 * Further, the files/directories handled by this function are
1706 * assumed to be *not* deleted (and *only* those).
1708 static uint32_t get_cluster_count_for_direntry(BDRVVVFATState
* s
,
1709 direntry_t
* direntry
, const char* path
)
1712 * This is a little bit tricky:
1713 * IF the guest OS just inserts a cluster into the file chain,
1714 * and leaves the rest alone, (i.e. the original file had clusters
1715 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1717 * - do_commit will write the cluster into the file at the given
1720 * - the cluster which is overwritten should be moved to a later
1721 * position in the file.
1723 * I am not aware that any OS does something as braindead, but this
1724 * situation could happen anyway when not committing for a long time.
1725 * Just to be sure that this does not bite us, detect it, and copy the
1726 * contents of the clusters to-be-overwritten into the qcow.
1729 int was_modified
= 0;
1732 uint32_t cluster_num
= begin_of_direntry(direntry
);
1733 uint32_t offset
= 0;
1734 int first_mapping_index
= -1;
1735 mapping_t
* mapping
= NULL
;
1736 const char* basename2
= NULL
;
1738 vvfat_close_current_file(s
);
1740 /* the root directory */
1741 if (cluster_num
== 0)
1746 basename2
= get_basename(path
);
1748 mapping
= find_mapping_for_cluster(s
, cluster_num
);
1751 const char* basename
;
1753 assert(mapping
->mode
& MODE_DELETED
);
1754 mapping
->mode
&= ~MODE_DELETED
;
1756 basename
= get_basename(mapping
->path
);
1758 assert(mapping
->mode
& MODE_NORMAL
);
1761 if (strcmp(basename
, basename2
))
1762 schedule_rename(s
, cluster_num
, g_strdup(path
));
1763 } else if (is_file(direntry
))
1765 schedule_new_file(s
, g_strdup(path
), cluster_num
);
1774 if (!copy_it
&& cluster_was_modified(s
, cluster_num
)) {
1775 if (mapping
== NULL
||
1776 mapping
->begin
> cluster_num
||
1777 mapping
->end
<= cluster_num
)
1778 mapping
= find_mapping_for_cluster(s
, cluster_num
);
1782 (mapping
->mode
& MODE_DIRECTORY
) == 0) {
1784 /* was modified in qcow */
1785 if (offset
!= mapping
->info
.file
.offset
+ s
->cluster_size
1786 * (cluster_num
- mapping
->begin
)) {
1787 /* offset of this cluster in file chain has changed */
1790 } else if (offset
== 0) {
1791 const char* basename
= get_basename(mapping
->path
);
1793 if (strcmp(basename
, basename2
))
1795 first_mapping_index
= array_index(&(s
->mapping
), mapping
);
1798 if (mapping
->first_mapping_index
!= first_mapping_index
1799 && mapping
->info
.file
.offset
> 0) {
1804 /* need to write out? */
1805 if (!was_modified
&& is_file(direntry
)) {
1807 schedule_writeout(s
, mapping
->dir_index
, offset
);
1815 * This is horribly inefficient, but that is okay, since
1816 * it is rarely executed, if at all.
1818 int64_t offset
= cluster2sector(s
, cluster_num
);
1820 vvfat_close_current_file(s
);
1821 for (i
= 0; i
< s
->sectors_per_cluster
; i
++) {
1822 if (!bdrv_is_allocated(s
->qcow
, offset
+ i
, 1, &dummy
)) {
1823 if (vvfat_read(s
->bs
, offset
, s
->cluster_buffer
, 1)) {
1826 if (bdrv_write(s
->qcow
, offset
, s
->cluster_buffer
, 1)) {
1835 if (s
->used_clusters
[cluster_num
] & USED_ANY
)
1837 s
->used_clusters
[cluster_num
] = USED_FILE
;
1839 cluster_num
= modified_fat_get(s
, cluster_num
);
1841 if (fat_eof(s
, cluster_num
))
1843 else if (cluster_num
< 2 || cluster_num
> s
->max_fat_value
- 16)
1846 offset
+= s
->cluster_size
;
1851 * This function looks at the modified data (qcow).
1852 * It returns 0 upon inconsistency or error, and the number of clusters
1853 * used by the directory, its subdirectories and their files.
1855 static int check_directory_consistency(BDRVVVFATState
*s
,
1856 int cluster_num
, const char* path
)
1859 unsigned char* cluster
= g_malloc(s
->cluster_size
);
1860 direntry_t
* direntries
= (direntry_t
*)cluster
;
1861 mapping_t
* mapping
= find_mapping_for_cluster(s
, cluster_num
);
1864 int path_len
= strlen(path
);
1865 char path2
[PATH_MAX
+ 1];
1867 assert(path_len
< PATH_MAX
); /* len was tested before! */
1868 pstrcpy(path2
, sizeof(path2
), path
);
1869 path2
[path_len
] = '/';
1870 path2
[path_len
+ 1] = '\0';
1873 const char* basename
= get_basename(mapping
->path
);
1874 const char* basename2
= get_basename(path
);
1876 assert(mapping
->mode
& MODE_DIRECTORY
);
1878 assert(mapping
->mode
& MODE_DELETED
);
1879 mapping
->mode
&= ~MODE_DELETED
;
1881 if (strcmp(basename
, basename2
))
1882 schedule_rename(s
, cluster_num
, g_strdup(path
));
1885 schedule_mkdir(s
, cluster_num
, g_strdup(path
));
1894 if (s
->used_clusters
[cluster_num
] & USED_ANY
) {
1895 fprintf(stderr
, "cluster %d used more than once\n", (int)cluster_num
);
1898 s
->used_clusters
[cluster_num
] = USED_DIRECTORY
;
1900 DLOG(fprintf(stderr
, "read cluster %d (sector %d)\n", (int)cluster_num
, (int)cluster2sector(s
, cluster_num
)));
1901 subret
= vvfat_read(s
->bs
, cluster2sector(s
, cluster_num
), cluster
,
1902 s
->sectors_per_cluster
);
1904 fprintf(stderr
, "Error fetching direntries\n");
1910 for (i
= 0; i
< 0x10 * s
->sectors_per_cluster
; i
++) {
1911 int cluster_count
= 0;
1913 DLOG(fprintf(stderr
, "check direntry %d:\n", i
); print_direntry(direntries
+ i
));
1914 if (is_volume_label(direntries
+ i
) || is_dot(direntries
+ i
) ||
1915 is_free(direntries
+ i
))
1918 subret
= parse_long_name(&lfn
, direntries
+ i
);
1920 fprintf(stderr
, "Error in long name\n");
1923 if (subret
== 0 || is_free(direntries
+ i
))
1926 if (fat_chksum(direntries
+i
) != lfn
.checksum
) {
1927 subret
= parse_short_name(s
, &lfn
, direntries
+ i
);
1929 fprintf(stderr
, "Error in short name (%d)\n", subret
);
1932 if (subret
> 0 || !strcmp((char*)lfn
.name
, ".")
1933 || !strcmp((char*)lfn
.name
, ".."))
1936 lfn
.checksum
= 0x100; /* cannot use long name twice */
1938 if (path_len
+ 1 + lfn
.len
>= PATH_MAX
) {
1939 fprintf(stderr
, "Name too long: %s/%s\n", path
, lfn
.name
);
1942 pstrcpy(path2
+ path_len
+ 1, sizeof(path2
) - path_len
- 1,
1945 if (is_directory(direntries
+ i
)) {
1946 if (begin_of_direntry(direntries
+ i
) == 0) {
1947 DLOG(fprintf(stderr
, "invalid begin for directory: %s\n", path2
); print_direntry(direntries
+ i
));
1950 cluster_count
= check_directory_consistency(s
,
1951 begin_of_direntry(direntries
+ i
), path2
);
1952 if (cluster_count
== 0) {
1953 DLOG(fprintf(stderr
, "problem in directory %s:\n", path2
); print_direntry(direntries
+ i
));
1956 } else if (is_file(direntries
+ i
)) {
1957 /* check file size with FAT */
1958 cluster_count
= get_cluster_count_for_direntry(s
, direntries
+ i
, path2
);
1959 if (cluster_count
!=
1960 DIV_ROUND_UP(le32_to_cpu(direntries
[i
].size
), s
->cluster_size
)) {
1961 DLOG(fprintf(stderr
, "Cluster count mismatch\n"));
1965 abort(); /* cluster_count = 0; */
1967 ret
+= cluster_count
;
1970 cluster_num
= modified_fat_get(s
, cluster_num
);
1971 } while(!fat_eof(s
, cluster_num
));
1977 /* returns 1 on success */
1978 static int is_consistent(BDRVVVFATState
* s
)
1981 int used_clusters_count
= 0;
1985 * - get modified FAT
1986 * - compare the two FATs (TODO)
1987 * - get buffer for marking used clusters
1988 * - recurse direntries from root (using bs->bdrv_read to make
1989 * sure to get the new data)
1990 * - check that the FAT agrees with the size
1991 * - count the number of clusters occupied by this directory and
1993 * - check that the cumulative used cluster count agrees with the
1995 * - if all is fine, return number of used clusters
1997 if (s
->fat2
== NULL
) {
1998 int size
= 0x200 * s
->sectors_per_fat
;
1999 s
->fat2
= g_malloc(size
);
2000 memcpy(s
->fat2
, s
->fat
.pointer
, size
);
2002 check
= vvfat_read(s
->bs
,
2003 s
->first_sectors_number
, s
->fat2
, s
->sectors_per_fat
);
2005 fprintf(stderr
, "Could not copy fat\n");
2008 assert (s
->used_clusters
);
2009 for (i
= 0; i
< sector2cluster(s
, s
->sector_count
); i
++)
2010 s
->used_clusters
[i
] &= ~USED_ANY
;
2014 /* mark every mapped file/directory as deleted.
2015 * (check_directory_consistency() will unmark those still present). */
2017 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2018 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2019 if (mapping
->first_mapping_index
< 0)
2020 mapping
->mode
|= MODE_DELETED
;
2023 used_clusters_count
= check_directory_consistency(s
, 0, s
->path
);
2024 if (used_clusters_count
<= 0) {
2025 DLOG(fprintf(stderr
, "problem in directory\n"));
2029 check
= s
->last_cluster_of_root_directory
;
2030 for (i
= check
; i
< sector2cluster(s
, s
->sector_count
); i
++) {
2031 if (modified_fat_get(s
, i
)) {
2032 if(!s
->used_clusters
[i
]) {
2033 DLOG(fprintf(stderr
, "FAT was modified (%d), but cluster is not used?\n", i
));
2039 if (s
->used_clusters
[i
] == USED_ALLOCATED
) {
2040 /* allocated, but not used... */
2041 DLOG(fprintf(stderr
, "unused, modified cluster: %d\n", i
));
2046 if (check
!= used_clusters_count
)
2049 return used_clusters_count
;
2052 static inline void adjust_mapping_indices(BDRVVVFATState
* s
,
2053 int offset
, int adjust
)
2057 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2058 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2060 #define ADJUST_MAPPING_INDEX(name) \
2061 if (mapping->name >= offset) \
2062 mapping->name += adjust
2064 ADJUST_MAPPING_INDEX(first_mapping_index
);
2065 if (mapping
->mode
& MODE_DIRECTORY
)
2066 ADJUST_MAPPING_INDEX(info
.dir
.parent_mapping_index
);
2070 /* insert or update mapping */
2071 static mapping_t
* insert_mapping(BDRVVVFATState
* s
,
2072 uint32_t begin
, uint32_t end
)
2075 * - find mapping where mapping->begin >= begin,
2076 * - if mapping->begin > begin: insert
2077 * - adjust all references to mappings!
2081 int index
= find_mapping_for_cluster_aux(s
, begin
, 0, s
->mapping
.next
);
2082 mapping_t
* mapping
= NULL
;
2083 mapping_t
* first_mapping
= array_get(&(s
->mapping
), 0);
2085 if (index
< s
->mapping
.next
&& (mapping
= array_get(&(s
->mapping
), index
))
2086 && mapping
->begin
< begin
) {
2087 mapping
->end
= begin
;
2089 mapping
= array_get(&(s
->mapping
), index
);
2091 if (index
>= s
->mapping
.next
|| mapping
->begin
> begin
) {
2092 mapping
= array_insert(&(s
->mapping
), index
, 1);
2093 mapping
->path
= NULL
;
2094 adjust_mapping_indices(s
, index
, +1);
2097 mapping
->begin
= begin
;
2100 DLOG(mapping_t
* next_mapping
;
2101 assert(index
+ 1 >= s
->mapping
.next
||
2102 ((next_mapping
= array_get(&(s
->mapping
), index
+ 1)) &&
2103 next_mapping
->begin
>= end
)));
2105 if (s
->current_mapping
&& first_mapping
!= (mapping_t
*)s
->mapping
.pointer
)
2106 s
->current_mapping
= array_get(&(s
->mapping
),
2107 s
->current_mapping
- first_mapping
);
2112 static int remove_mapping(BDRVVVFATState
* s
, int mapping_index
)
2114 mapping_t
* mapping
= array_get(&(s
->mapping
), mapping_index
);
2115 mapping_t
* first_mapping
= array_get(&(s
->mapping
), 0);
2118 if (mapping
->first_mapping_index
< 0) {
2119 g_free(mapping
->path
);
2122 /* remove from s->mapping */
2123 array_remove(&(s
->mapping
), mapping_index
);
2125 /* adjust all references to mappings */
2126 adjust_mapping_indices(s
, mapping_index
, -1);
2128 if (s
->current_mapping
&& first_mapping
!= (mapping_t
*)s
->mapping
.pointer
)
2129 s
->current_mapping
= array_get(&(s
->mapping
),
2130 s
->current_mapping
- first_mapping
);
2135 static void adjust_dirindices(BDRVVVFATState
* s
, int offset
, int adjust
)
2138 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2139 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2140 if (mapping
->dir_index
>= offset
)
2141 mapping
->dir_index
+= adjust
;
2142 if ((mapping
->mode
& MODE_DIRECTORY
) &&
2143 mapping
->info
.dir
.first_dir_index
>= offset
)
2144 mapping
->info
.dir
.first_dir_index
+= adjust
;
2148 static direntry_t
* insert_direntries(BDRVVVFATState
* s
,
2149 int dir_index
, int count
)
2152 * make room in s->directory,
2155 direntry_t
* result
= array_insert(&(s
->directory
), dir_index
, count
);
2158 adjust_dirindices(s
, dir_index
, count
);
2162 static int remove_direntries(BDRVVVFATState
* s
, int dir_index
, int count
)
2164 int ret
= array_remove_slice(&(s
->directory
), dir_index
, count
);
2167 adjust_dirindices(s
, dir_index
, -count
);
2172 * Adapt the mappings of the cluster chain starting at first cluster
2173 * (i.e. if a file starts at first_cluster, the chain is followed according
2174 * to the modified fat, and the corresponding entries in s->mapping are
2177 static int commit_mappings(BDRVVVFATState
* s
,
2178 uint32_t first_cluster
, int dir_index
)
2180 mapping_t
* mapping
= find_mapping_for_cluster(s
, first_cluster
);
2181 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2182 uint32_t cluster
= first_cluster
;
2184 vvfat_close_current_file(s
);
2187 assert(mapping
->begin
== first_cluster
);
2188 mapping
->first_mapping_index
= -1;
2189 mapping
->dir_index
= dir_index
;
2190 mapping
->mode
= (dir_index
<= 0 || is_directory(direntry
)) ?
2191 MODE_DIRECTORY
: MODE_NORMAL
;
2193 while (!fat_eof(s
, cluster
)) {
2196 for (c
= cluster
, c1
= modified_fat_get(s
, c
); c
+ 1 == c1
;
2197 c
= c1
, c1
= modified_fat_get(s
, c1
));
2200 if (c
> mapping
->end
) {
2201 int index
= array_index(&(s
->mapping
), mapping
);
2202 int i
, max_i
= s
->mapping
.next
- index
;
2203 for (i
= 1; i
< max_i
&& mapping
[i
].begin
< c
; i
++);
2205 remove_mapping(s
, index
+ 1);
2207 assert(mapping
== array_get(&(s
->mapping
), s
->mapping
.next
- 1)
2208 || mapping
[1].begin
>= c
);
2211 if (!fat_eof(s
, c1
)) {
2212 int i
= find_mapping_for_cluster_aux(s
, c1
, 0, s
->mapping
.next
);
2213 mapping_t
* next_mapping
= i
>= s
->mapping
.next
? NULL
:
2214 array_get(&(s
->mapping
), i
);
2216 if (next_mapping
== NULL
|| next_mapping
->begin
> c1
) {
2217 int i1
= array_index(&(s
->mapping
), mapping
);
2219 next_mapping
= insert_mapping(s
, c1
, c1
+1);
2223 mapping
= array_get(&(s
->mapping
), i1
);
2226 next_mapping
->dir_index
= mapping
->dir_index
;
2227 next_mapping
->first_mapping_index
=
2228 mapping
->first_mapping_index
< 0 ?
2229 array_index(&(s
->mapping
), mapping
) :
2230 mapping
->first_mapping_index
;
2231 next_mapping
->path
= mapping
->path
;
2232 next_mapping
->mode
= mapping
->mode
;
2233 next_mapping
->read_only
= mapping
->read_only
;
2234 if (mapping
->mode
& MODE_DIRECTORY
) {
2235 next_mapping
->info
.dir
.parent_mapping_index
=
2236 mapping
->info
.dir
.parent_mapping_index
;
2237 next_mapping
->info
.dir
.first_dir_index
=
2238 mapping
->info
.dir
.first_dir_index
+
2239 0x10 * s
->sectors_per_cluster
*
2240 (mapping
->end
- mapping
->begin
);
2242 next_mapping
->info
.file
.offset
= mapping
->info
.file
.offset
+
2243 mapping
->end
- mapping
->begin
;
2245 mapping
= next_mapping
;
2254 static int commit_direntries(BDRVVVFATState
* s
,
2255 int dir_index
, int parent_mapping_index
)
2257 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2258 uint32_t first_cluster
= dir_index
== 0 ? 0 : begin_of_direntry(direntry
);
2259 mapping_t
* mapping
= find_mapping_for_cluster(s
, first_cluster
);
2261 int factor
= 0x10 * s
->sectors_per_cluster
;
2262 int old_cluster_count
, new_cluster_count
;
2263 int current_dir_index
= mapping
->info
.dir
.first_dir_index
;
2264 int first_dir_index
= current_dir_index
;
2268 DLOG(fprintf(stderr
, "commit_direntries for %s, parent_mapping_index %d\n", mapping
->path
, parent_mapping_index
));
2272 assert(mapping
->begin
== first_cluster
);
2273 assert(mapping
->info
.dir
.first_dir_index
< s
->directory
.next
);
2274 assert(mapping
->mode
& MODE_DIRECTORY
);
2275 assert(dir_index
== 0 || is_directory(direntry
));
2277 mapping
->info
.dir
.parent_mapping_index
= parent_mapping_index
;
2279 if (first_cluster
== 0) {
2280 old_cluster_count
= new_cluster_count
=
2281 s
->last_cluster_of_root_directory
;
2283 for (old_cluster_count
= 0, c
= first_cluster
; !fat_eof(s
, c
);
2285 old_cluster_count
++;
2287 for (new_cluster_count
= 0, c
= first_cluster
; !fat_eof(s
, c
);
2288 c
= modified_fat_get(s
, c
))
2289 new_cluster_count
++;
2292 if (new_cluster_count
> old_cluster_count
) {
2293 if (insert_direntries(s
,
2294 current_dir_index
+ factor
* old_cluster_count
,
2295 factor
* (new_cluster_count
- old_cluster_count
)) == NULL
)
2297 } else if (new_cluster_count
< old_cluster_count
)
2298 remove_direntries(s
,
2299 current_dir_index
+ factor
* new_cluster_count
,
2300 factor
* (old_cluster_count
- new_cluster_count
));
2302 for (c
= first_cluster
; !fat_eof(s
, c
); c
= modified_fat_get(s
, c
)) {
2303 direntry_t
*first_direntry
;
2304 void* direntry
= array_get(&(s
->directory
), current_dir_index
);
2305 int ret
= vvfat_read(s
->bs
, cluster2sector(s
, c
), direntry
,
2306 s
->sectors_per_cluster
);
2310 /* The first directory entry on the filesystem is the volume name */
2311 first_direntry
= (direntry_t
*) s
->directory
.pointer
;
2312 assert(!memcmp(first_direntry
->name
, s
->volume_label
, 11));
2314 current_dir_index
+= factor
;
2317 ret
= commit_mappings(s
, first_cluster
, dir_index
);
2322 for (i
= 0; i
< factor
* new_cluster_count
; i
++) {
2323 direntry
= array_get(&(s
->directory
), first_dir_index
+ i
);
2324 if (is_directory(direntry
) && !is_dot(direntry
)) {
2325 mapping
= find_mapping_for_cluster(s
, first_cluster
);
2326 assert(mapping
->mode
& MODE_DIRECTORY
);
2327 ret
= commit_direntries(s
, first_dir_index
+ i
,
2328 array_index(&(s
->mapping
), mapping
));
2337 /* commit one file (adjust contents, adjust mapping),
2338 return first_mapping_index */
2339 static int commit_one_file(BDRVVVFATState
* s
,
2340 int dir_index
, uint32_t offset
)
2342 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2343 uint32_t c
= begin_of_direntry(direntry
);
2344 uint32_t first_cluster
= c
;
2345 mapping_t
* mapping
= find_mapping_for_cluster(s
, c
);
2346 uint32_t size
= filesize_of_direntry(direntry
);
2347 char* cluster
= g_malloc(s
->cluster_size
);
2351 assert(offset
< size
);
2352 assert((offset
% s
->cluster_size
) == 0);
2354 for (i
= s
->cluster_size
; i
< offset
; i
+= s
->cluster_size
)
2355 c
= modified_fat_get(s
, c
);
2357 fd
= qemu_open(mapping
->path
, O_RDWR
| O_CREAT
| O_BINARY
, 0666);
2359 fprintf(stderr
, "Could not open %s... (%s, %d)\n", mapping
->path
,
2360 strerror(errno
), errno
);
2365 if (lseek(fd
, offset
, SEEK_SET
) != offset
) {
2372 while (offset
< size
) {
2374 int rest_size
= (size
- offset
> s
->cluster_size
?
2375 s
->cluster_size
: size
- offset
);
2378 c1
= modified_fat_get(s
, c
);
2380 assert((size
- offset
== 0 && fat_eof(s
, c
)) ||
2381 (size
> offset
&& c
>=2 && !fat_eof(s
, c
)));
2383 ret
= vvfat_read(s
->bs
, cluster2sector(s
, c
),
2384 (uint8_t*)cluster
, (rest_size
+ 0x1ff) / 0x200);
2392 if (write(fd
, cluster
, rest_size
) < 0) {
2398 offset
+= rest_size
;
2402 if (ftruncate(fd
, size
)) {
2403 perror("ftruncate()");
2411 return commit_mappings(s
, first_cluster
, dir_index
);
2415 /* test, if all mappings point to valid direntries */
2416 static void check1(BDRVVVFATState
* s
)
2419 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2420 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2421 if (mapping
->mode
& MODE_DELETED
) {
2422 fprintf(stderr
, "deleted\n");
2425 assert(mapping
->dir_index
< s
->directory
.next
);
2426 direntry_t
* direntry
= array_get(&(s
->directory
), mapping
->dir_index
);
2427 assert(mapping
->begin
== begin_of_direntry(direntry
) || mapping
->first_mapping_index
>= 0);
2428 if (mapping
->mode
& MODE_DIRECTORY
) {
2429 assert(mapping
->info
.dir
.first_dir_index
+ 0x10 * s
->sectors_per_cluster
* (mapping
->end
- mapping
->begin
) <= s
->directory
.next
);
2430 assert((mapping
->info
.dir
.first_dir_index
% (0x10 * s
->sectors_per_cluster
)) == 0);
2435 /* test, if all direntries have mappings */
2436 static void check2(BDRVVVFATState
* s
)
2439 int first_mapping
= -1;
2441 for (i
= 0; i
< s
->directory
.next
; i
++) {
2442 direntry_t
* direntry
= array_get(&(s
->directory
), i
);
2444 if (is_short_name(direntry
) && begin_of_direntry(direntry
)) {
2445 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin_of_direntry(direntry
));
2447 assert(mapping
->dir_index
== i
|| is_dot(direntry
));
2448 assert(mapping
->begin
== begin_of_direntry(direntry
) || is_dot(direntry
));
2451 if ((i
% (0x10 * s
->sectors_per_cluster
)) == 0) {
2455 for (j
= 0; j
< s
->mapping
.next
; j
++) {
2456 mapping_t
* mapping
= array_get(&(s
->mapping
), j
);
2457 if (mapping
->mode
& MODE_DELETED
)
2459 if (mapping
->mode
& MODE_DIRECTORY
) {
2460 if (mapping
->info
.dir
.first_dir_index
<= i
&& mapping
->info
.dir
.first_dir_index
+ 0x10 * s
->sectors_per_cluster
> i
) {
2461 assert(++count
== 1);
2462 if (mapping
->first_mapping_index
== -1)
2463 first_mapping
= array_index(&(s
->mapping
), mapping
);
2465 assert(first_mapping
== mapping
->first_mapping_index
);
2466 if (mapping
->info
.dir
.parent_mapping_index
< 0)
2469 mapping_t
* parent
= array_get(&(s
->mapping
), mapping
->info
.dir
.parent_mapping_index
);
2470 assert(parent
->mode
& MODE_DIRECTORY
);
2471 assert(parent
->info
.dir
.first_dir_index
< mapping
->info
.dir
.first_dir_index
);
2483 static int handle_renames_and_mkdirs(BDRVVVFATState
* s
)
2488 fprintf(stderr
, "handle_renames\n");
2489 for (i
= 0; i
< s
->commits
.next
; i
++) {
2490 commit_t
* commit
= array_get(&(s
->commits
), i
);
2491 fprintf(stderr
, "%d, %s (%d, %d)\n", i
, commit
->path
? commit
->path
: "(null)", commit
->param
.rename
.cluster
, commit
->action
);
2495 for (i
= 0; i
< s
->commits
.next
;) {
2496 commit_t
* commit
= array_get(&(s
->commits
), i
);
2497 if (commit
->action
== ACTION_RENAME
) {
2498 mapping_t
* mapping
= find_mapping_for_cluster(s
,
2499 commit
->param
.rename
.cluster
);
2500 char* old_path
= mapping
->path
;
2502 assert(commit
->path
);
2503 mapping
->path
= commit
->path
;
2504 if (rename(old_path
, mapping
->path
))
2507 if (mapping
->mode
& MODE_DIRECTORY
) {
2508 int l1
= strlen(mapping
->path
);
2509 int l2
= strlen(old_path
);
2511 direntry_t
* direntry
= array_get(&(s
->directory
),
2512 mapping
->info
.dir
.first_dir_index
);
2513 uint32_t c
= mapping
->begin
;
2517 while (!fat_eof(s
, c
)) {
2519 direntry_t
* d
= direntry
+ i
;
2521 if (is_file(d
) || (is_directory(d
) && !is_dot(d
))) {
2522 mapping_t
* m
= find_mapping_for_cluster(s
,
2523 begin_of_direntry(d
));
2524 int l
= strlen(m
->path
);
2525 char* new_path
= g_malloc(l
+ diff
+ 1);
2527 assert(!strncmp(m
->path
, mapping
->path
, l2
));
2529 pstrcpy(new_path
, l
+ diff
+ 1, mapping
->path
);
2530 pstrcpy(new_path
+ l1
, l
+ diff
+ 1 - l1
,
2533 schedule_rename(s
, m
->begin
, new_path
);
2536 } while((i
% (0x10 * s
->sectors_per_cluster
)) != 0);
2542 array_remove(&(s
->commits
), i
);
2544 } else if (commit
->action
== ACTION_MKDIR
) {
2546 int j
, parent_path_len
;
2549 if (mkdir(commit
->path
))
2552 if (mkdir(commit
->path
, 0755))
2556 mapping
= insert_mapping(s
, commit
->param
.mkdir
.cluster
,
2557 commit
->param
.mkdir
.cluster
+ 1);
2558 if (mapping
== NULL
)
2561 mapping
->mode
= MODE_DIRECTORY
;
2562 mapping
->read_only
= 0;
2563 mapping
->path
= commit
->path
;
2564 j
= s
->directory
.next
;
2566 insert_direntries(s
, s
->directory
.next
,
2567 0x10 * s
->sectors_per_cluster
);
2568 mapping
->info
.dir
.first_dir_index
= j
;
2570 parent_path_len
= strlen(commit
->path
)
2571 - strlen(get_basename(commit
->path
)) - 1;
2572 for (j
= 0; j
< s
->mapping
.next
; j
++) {
2573 mapping_t
* m
= array_get(&(s
->mapping
), j
);
2574 if (m
->first_mapping_index
< 0 && m
!= mapping
&&
2575 !strncmp(m
->path
, mapping
->path
, parent_path_len
) &&
2576 strlen(m
->path
) == parent_path_len
)
2579 assert(j
< s
->mapping
.next
);
2580 mapping
->info
.dir
.parent_mapping_index
= j
;
2582 array_remove(&(s
->commits
), i
);
2592 * TODO: make sure that the short name is not matching *another* file
2594 static int handle_commits(BDRVVVFATState
* s
)
2598 vvfat_close_current_file(s
);
2600 for (i
= 0; !fail
&& i
< s
->commits
.next
; i
++) {
2601 commit_t
* commit
= array_get(&(s
->commits
), i
);
2602 switch(commit
->action
) {
2603 case ACTION_RENAME
: case ACTION_MKDIR
:
2607 case ACTION_WRITEOUT
: {
2609 /* these variables are only used by assert() below */
2610 direntry_t
* entry
= array_get(&(s
->directory
),
2611 commit
->param
.writeout
.dir_index
);
2612 uint32_t begin
= begin_of_direntry(entry
);
2613 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin
);
2617 assert(mapping
->begin
== begin
);
2618 assert(commit
->path
== NULL
);
2620 if (commit_one_file(s
, commit
->param
.writeout
.dir_index
,
2621 commit
->param
.writeout
.modified_offset
))
2626 case ACTION_NEW_FILE
: {
2627 int begin
= commit
->param
.new_file
.first_cluster
;
2628 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin
);
2633 for (i
= 0; i
< s
->directory
.next
; i
++) {
2634 entry
= array_get(&(s
->directory
), i
);
2635 if (is_file(entry
) && begin_of_direntry(entry
) == begin
)
2639 if (i
>= s
->directory
.next
) {
2644 /* make sure there exists an initial mapping */
2645 if (mapping
&& mapping
->begin
!= begin
) {
2646 mapping
->end
= begin
;
2649 if (mapping
== NULL
) {
2650 mapping
= insert_mapping(s
, begin
, begin
+1);
2652 /* most members will be fixed in commit_mappings() */
2653 assert(commit
->path
);
2654 mapping
->path
= commit
->path
;
2655 mapping
->read_only
= 0;
2656 mapping
->mode
= MODE_NORMAL
;
2657 mapping
->info
.file
.offset
= 0;
2659 if (commit_one_file(s
, i
, 0))
2668 if (i
> 0 && array_remove_slice(&(s
->commits
), 0, i
))
2673 static int handle_deletes(BDRVVVFATState
* s
)
2675 int i
, deferred
= 1, deleted
= 1;
2677 /* delete files corresponding to mappings marked as deleted */
2678 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2679 while (deferred
&& deleted
) {
2683 for (i
= 1; i
< s
->mapping
.next
; i
++) {
2684 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2685 if (mapping
->mode
& MODE_DELETED
) {
2686 direntry_t
* entry
= array_get(&(s
->directory
),
2687 mapping
->dir_index
);
2689 if (is_free(entry
)) {
2690 /* remove file/directory */
2691 if (mapping
->mode
& MODE_DIRECTORY
) {
2692 int j
, next_dir_index
= s
->directory
.next
,
2693 first_dir_index
= mapping
->info
.dir
.first_dir_index
;
2695 if (rmdir(mapping
->path
) < 0) {
2696 if (errno
== ENOTEMPTY
) {
2703 for (j
= 1; j
< s
->mapping
.next
; j
++) {
2704 mapping_t
* m
= array_get(&(s
->mapping
), j
);
2705 if (m
->mode
& MODE_DIRECTORY
&&
2706 m
->info
.dir
.first_dir_index
>
2708 m
->info
.dir
.first_dir_index
<
2711 m
->info
.dir
.first_dir_index
;
2713 remove_direntries(s
, first_dir_index
,
2714 next_dir_index
- first_dir_index
);
2719 if (unlink(mapping
->path
))
2723 DLOG(fprintf(stderr
, "DELETE (%d)\n", i
); print_mapping(mapping
); print_direntry(entry
));
2724 remove_mapping(s
, i
);
2733 * synchronize mapping with new state:
2735 * - copy FAT (with bdrv_read)
2736 * - mark all filenames corresponding to mappings as deleted
2737 * - recurse direntries from root (using bs->bdrv_read)
2738 * - delete files corresponding to mappings marked as deleted
2740 static int do_commit(BDRVVVFATState
* s
)
2744 /* the real meat are the commits. Nothing to do? Move along! */
2745 if (s
->commits
.next
== 0)
2748 vvfat_close_current_file(s
);
2750 ret
= handle_renames_and_mkdirs(s
);
2752 fprintf(stderr
, "Error handling renames (%d)\n", ret
);
2757 /* copy FAT (with bdrv_read) */
2758 memcpy(s
->fat
.pointer
, s
->fat2
, 0x200 * s
->sectors_per_fat
);
2760 /* recurse direntries from root (using bs->bdrv_read) */
2761 ret
= commit_direntries(s
, 0, -1);
2763 fprintf(stderr
, "Fatal: error while committing (%d)\n", ret
);
2768 ret
= handle_commits(s
);
2770 fprintf(stderr
, "Error handling commits (%d)\n", ret
);
2775 ret
= handle_deletes(s
);
2777 fprintf(stderr
, "Error deleting\n");
2782 if (s
->qcow
->drv
->bdrv_make_empty
) {
2783 s
->qcow
->drv
->bdrv_make_empty(s
->qcow
);
2786 memset(s
->used_clusters
, 0, sector2cluster(s
, s
->sector_count
));
2792 static int try_commit(BDRVVVFATState
* s
)
2794 vvfat_close_current_file(s
);
2796 if(!is_consistent(s
))
2798 return do_commit(s
);
2801 static int vvfat_write(BlockDriverState
*bs
, int64_t sector_num
,
2802 const uint8_t *buf
, int nb_sectors
)
2804 BDRVVVFATState
*s
= bs
->opaque
;
2809 /* Check if we're operating in read-only mode */
2810 if (s
->qcow
== NULL
) {
2814 vvfat_close_current_file(s
);
2817 * Some sanity checks:
2818 * - do not allow writing to the boot sector
2819 * - do not allow to write non-ASCII filenames
2822 if (sector_num
< s
->first_sectors_number
)
2825 for (i
= sector2cluster(s
, sector_num
);
2826 i
<= sector2cluster(s
, sector_num
+ nb_sectors
- 1);) {
2827 mapping_t
* mapping
= find_mapping_for_cluster(s
, i
);
2829 if (mapping
->read_only
) {
2830 fprintf(stderr
, "Tried to write to write-protected file %s\n",
2835 if (mapping
->mode
& MODE_DIRECTORY
) {
2836 int begin
= cluster2sector(s
, i
);
2837 int end
= begin
+ s
->sectors_per_cluster
, k
;
2839 const direntry_t
* direntries
;
2844 if (begin
< sector_num
)
2846 if (end
> sector_num
+ nb_sectors
)
2847 end
= sector_num
+ nb_sectors
;
2848 dir_index
= mapping
->dir_index
+
2849 0x10 * (begin
- mapping
->begin
* s
->sectors_per_cluster
);
2850 direntries
= (direntry_t
*)(buf
+ 0x200 * (begin
- sector_num
));
2852 for (k
= 0; k
< (end
- begin
) * 0x10; k
++) {
2853 /* do not allow non-ASCII filenames */
2854 if (parse_long_name(&lfn
, direntries
+ k
) < 0) {
2855 fprintf(stderr
, "Warning: non-ASCII filename\n");
2858 /* no access to the direntry of a read-only file */
2859 else if (is_short_name(direntries
+k
) &&
2860 (direntries
[k
].attributes
& 1)) {
2861 if (memcmp(direntries
+ k
,
2862 array_get(&(s
->directory
), dir_index
+ k
),
2863 sizeof(direntry_t
))) {
2864 fprintf(stderr
, "Warning: tried to write to write-protected file\n");
2876 * Use qcow backend. Commit later.
2878 DLOG(fprintf(stderr
, "Write to qcow backend: %d + %d\n", (int)sector_num
, nb_sectors
));
2879 ret
= bdrv_write(s
->qcow
, sector_num
, buf
, nb_sectors
);
2881 fprintf(stderr
, "Error writing to qcow backend\n");
2885 for (i
= sector2cluster(s
, sector_num
);
2886 i
<= sector2cluster(s
, sector_num
+ nb_sectors
- 1); i
++)
2888 s
->used_clusters
[i
] |= USED_ALLOCATED
;
2891 /* TODO: add timeout */
2898 static int coroutine_fn
2899 vvfat_co_pwritev(BlockDriverState
*bs
, uint64_t offset
, uint64_t bytes
,
2900 QEMUIOVector
*qiov
, int flags
)
2903 BDRVVVFATState
*s
= bs
->opaque
;
2904 uint64_t sector_num
= offset
>> BDRV_SECTOR_BITS
;
2905 int nb_sectors
= bytes
>> BDRV_SECTOR_BITS
;
2908 assert((offset
& (BDRV_SECTOR_SIZE
- 1)) == 0);
2909 assert((bytes
& (BDRV_SECTOR_SIZE
- 1)) == 0);
2911 buf
= g_try_malloc(bytes
);
2912 if (bytes
&& buf
== NULL
) {
2915 qemu_iovec_to_buf(qiov
, 0, buf
, bytes
);
2917 qemu_co_mutex_lock(&s
->lock
);
2918 ret
= vvfat_write(bs
, sector_num
, buf
, nb_sectors
);
2919 qemu_co_mutex_unlock(&s
->lock
);
2926 static int64_t coroutine_fn
vvfat_co_get_block_status(BlockDriverState
*bs
,
2927 int64_t sector_num
, int nb_sectors
, int *n
, BlockDriverState
**file
)
2929 BDRVVVFATState
* s
= bs
->opaque
;
2930 *n
= s
->sector_count
- sector_num
;
2931 if (*n
> nb_sectors
) {
2933 } else if (*n
< 0) {
2936 return BDRV_BLOCK_DATA
;
2939 static int coroutine_fn
2940 write_target_commit(BlockDriverState
*bs
, uint64_t offset
, uint64_t bytes
,
2941 QEMUIOVector
*qiov
, int flags
)
2943 BDRVVVFATState
* s
= *((BDRVVVFATState
**) bs
->opaque
);
2944 return try_commit(s
);
2947 static void write_target_close(BlockDriverState
*bs
) {
2948 BDRVVVFATState
* s
= *((BDRVVVFATState
**) bs
->opaque
);
2949 bdrv_unref(s
->qcow
);
2950 g_free(s
->qcow_filename
);
2953 static BlockDriver vvfat_write_target
= {
2954 .format_name
= "vvfat_write_target",
2955 .bdrv_co_pwritev
= write_target_commit
,
2956 .bdrv_close
= write_target_close
,
2959 static int enable_write_target(BDRVVVFATState
*s
, Error
**errp
)
2961 BlockDriver
*bdrv_qcow
= NULL
;
2962 BlockDriverState
*backing
;
2963 QemuOpts
*opts
= NULL
;
2965 int size
= sector2cluster(s
, s
->sector_count
);
2968 s
->used_clusters
= calloc(size
, 1);
2970 array_init(&(s
->commits
), sizeof(commit_t
));
2972 s
->qcow_filename
= g_malloc(PATH_MAX
);
2973 ret
= get_tmp_filename(s
->qcow_filename
, PATH_MAX
);
2975 error_setg_errno(errp
, -ret
, "can't create temporary file");
2979 bdrv_qcow
= bdrv_find_format("qcow");
2981 error_setg(errp
, "Failed to locate qcow driver");
2986 opts
= qemu_opts_create(bdrv_qcow
->create_opts
, NULL
, 0, &error_abort
);
2987 qemu_opt_set_number(opts
, BLOCK_OPT_SIZE
, s
->sector_count
* 512,
2989 qemu_opt_set(opts
, BLOCK_OPT_BACKING_FILE
, "fat:", &error_abort
);
2991 ret
= bdrv_create(bdrv_qcow
, s
->qcow_filename
, opts
, errp
);
2992 qemu_opts_del(opts
);
2997 options
= qdict_new();
2998 qdict_put(options
, "driver", qstring_from_str("qcow"));
2999 s
->qcow
= bdrv_open(s
->qcow_filename
, NULL
, options
,
3000 BDRV_O_RDWR
| BDRV_O_NO_FLUSH
, errp
);
3007 unlink(s
->qcow_filename
);
3010 backing
= bdrv_new();
3011 bdrv_set_backing_hd(s
->bs
, backing
);
3012 bdrv_unref(backing
);
3014 s
->bs
->backing
->bs
->drv
= &vvfat_write_target
;
3015 s
->bs
->backing
->bs
->opaque
= g_new(void *, 1);
3016 *(void**)s
->bs
->backing
->bs
->opaque
= s
;
3021 g_free(s
->qcow_filename
);
3022 s
->qcow_filename
= NULL
;
3026 static void vvfat_close(BlockDriverState
*bs
)
3028 BDRVVVFATState
*s
= bs
->opaque
;
3030 vvfat_close_current_file(s
);
3031 array_free(&(s
->fat
));
3032 array_free(&(s
->directory
));
3033 array_free(&(s
->mapping
));
3034 g_free(s
->cluster_buffer
);
3037 migrate_del_blocker(s
->migration_blocker
);
3038 error_free(s
->migration_blocker
);
3042 static BlockDriver bdrv_vvfat
= {
3043 .format_name
= "vvfat",
3044 .protocol_name
= "fat",
3045 .instance_size
= sizeof(BDRVVVFATState
),
3047 .bdrv_parse_filename
= vvfat_parse_filename
,
3048 .bdrv_file_open
= vvfat_open
,
3049 .bdrv_close
= vvfat_close
,
3051 .bdrv_co_preadv
= vvfat_co_preadv
,
3052 .bdrv_co_pwritev
= vvfat_co_pwritev
,
3053 .bdrv_co_get_block_status
= vvfat_co_get_block_status
,
3056 static void bdrv_vvfat_init(void)
3058 bdrv_register(&bdrv_vvfat
);
3061 block_init(bdrv_vvfat_init
);
3064 static void checkpoint(void) {
3065 assert(((mapping_t
*)array_get(&(vvv
->mapping
), 0))->end
== 2);
3068 assert(!vvv
->current_mapping
|| vvv
->current_fd
|| (vvv
->current_mapping
->mode
& MODE_DIRECTORY
));
3070 if (((direntry_t
*)vvv
->directory
.pointer
)[1].attributes
!= 0xf)
3071 fprintf(stderr
, "Nonono!\n");
3073 direntry_t
* direntry
;
3074 assert(vvv
->mapping
.size
>= vvv
->mapping
.item_size
* vvv
->mapping
.next
);
3075 assert(vvv
->directory
.size
>= vvv
->directory
.item_size
* vvv
->directory
.next
);
3076 if (vvv
->mapping
.next
<47)
3078 assert((mapping
= array_get(&(vvv
->mapping
), 47)));
3079 assert(mapping
->dir_index
< vvv
->directory
.next
);
3080 direntry
= array_get(&(vvv
->directory
), mapping
->dir_index
);
3081 assert(!memcmp(direntry
->name
, "USB H ", 11) || direntry
->name
[0]==0);