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
;
350 int downcase_short_names
;
352 Error
*migration_blocker
;
355 /* take the sector position spos and convert it to Cylinder/Head/Sector position
356 * if the position is outside the specified geometry, fill maximum value for CHS
357 * and return 1 to signal overflow.
359 static int sector2CHS(mbr_chs_t
*chs
, int spos
, int cyls
, int heads
, int secs
)
362 sector
= spos
% secs
; spos
/= secs
;
363 head
= spos
% heads
; spos
/= heads
;
366 it happens if 32bit sector positions are used, while CHS is only 24bit.
367 Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
370 chs
->cylinder
= 0xFF;
373 chs
->head
= (uint8_t)head
;
374 chs
->sector
= (uint8_t)( (sector
+1) | ((spos
>>8)<<6) );
375 chs
->cylinder
= (uint8_t)spos
;
379 static void init_mbr(BDRVVVFATState
*s
, int cyls
, int heads
, int secs
)
381 /* TODO: if the files mbr.img and bootsect.img exist, use them */
382 mbr_t
* real_mbr
=(mbr_t
*)s
->first_sectors
;
383 partition_t
* partition
= &(real_mbr
->partition
[0]);
386 memset(s
->first_sectors
,0,512);
388 /* Win NT Disk Signature */
389 real_mbr
->nt_id
= cpu_to_le32(0xbe1afdfa);
391 partition
->attributes
=0x80; /* bootable */
393 /* LBA is used when partition is outside the CHS geometry */
394 lba
= sector2CHS(&partition
->start_CHS
, s
->first_sectors_number
- 1,
396 lba
|= sector2CHS(&partition
->end_CHS
, s
->bs
->total_sectors
- 1,
399 /*LBA partitions are identified only by start/length_sector_long not by CHS*/
400 partition
->start_sector_long
= cpu_to_le32(s
->first_sectors_number
- 1);
401 partition
->length_sector_long
= cpu_to_le32(s
->bs
->total_sectors
402 - s
->first_sectors_number
+ 1);
404 /* FAT12/FAT16/FAT32 */
405 /* DOS uses different types when partition is LBA,
406 probably to prevent older versions from using CHS on them */
407 partition
->fs_type
= s
->fat_type
==12 ? 0x1:
408 s
->fat_type
==16 ? (lba
?0xe:0x06):
409 /*fat_tyoe==32*/ (lba
?0xc:0x0b);
411 real_mbr
->magic
[0]=0x55; real_mbr
->magic
[1]=0xaa;
414 /* direntry functions */
416 /* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
417 static inline int short2long_name(char* dest
,const char* src
)
421 for(i
=0;i
<129 && src
[i
];i
++) {
426 dest
[2*i
]=dest
[2*i
+1]=0;
427 for(i
=2*i
+2;(i
%26);i
++)
432 static inline direntry_t
* create_long_filename(BDRVVVFATState
* s
,const char* filename
)
435 int length
=short2long_name(buffer
,filename
),
436 number_of_entries
=(length
+25)/26,i
;
439 for(i
=0;i
<number_of_entries
;i
++) {
440 entry
=array_get_next(&(s
->directory
));
441 entry
->attributes
=0xf;
442 entry
->reserved
[0]=0;
444 entry
->name
[0]=(number_of_entries
-i
)|(i
==0?0x40:0);
446 for(i
=0;i
<26*number_of_entries
;i
++) {
448 if(offset
<10) offset
=1+offset
;
449 else if(offset
<22) offset
=14+offset
-10;
450 else offset
=28+offset
-22;
451 entry
=array_get(&(s
->directory
),s
->directory
.next
-1-(i
/26));
452 entry
->name
[offset
]=buffer
[i
];
454 return array_get(&(s
->directory
),s
->directory
.next
-number_of_entries
);
457 static char is_free(const direntry_t
* direntry
)
459 return direntry
->name
[0]==0xe5 || direntry
->name
[0]==0x00;
462 static char is_volume_label(const direntry_t
* direntry
)
464 return direntry
->attributes
== 0x28;
467 static char is_long_name(const direntry_t
* direntry
)
469 return direntry
->attributes
== 0xf;
472 static char is_short_name(const direntry_t
* direntry
)
474 return !is_volume_label(direntry
) && !is_long_name(direntry
)
475 && !is_free(direntry
);
478 static char is_directory(const direntry_t
* direntry
)
480 return direntry
->attributes
& 0x10 && direntry
->name
[0] != 0xe5;
483 static inline char is_dot(const direntry_t
* direntry
)
485 return is_short_name(direntry
) && direntry
->name
[0] == '.';
488 static char is_file(const direntry_t
* direntry
)
490 return is_short_name(direntry
) && !is_directory(direntry
);
493 static inline uint32_t begin_of_direntry(const direntry_t
* direntry
)
495 return le16_to_cpu(direntry
->begin
)|(le16_to_cpu(direntry
->begin_hi
)<<16);
498 static inline uint32_t filesize_of_direntry(const direntry_t
* direntry
)
500 return le32_to_cpu(direntry
->size
);
503 static void set_begin_of_direntry(direntry_t
* direntry
, uint32_t begin
)
505 direntry
->begin
= cpu_to_le16(begin
& 0xffff);
506 direntry
->begin_hi
= cpu_to_le16((begin
>> 16) & 0xffff);
511 static inline uint8_t fat_chksum(const direntry_t
* entry
)
516 for (i
= 0; i
< ARRAY_SIZE(entry
->name
); i
++) {
517 chksum
= (((chksum
& 0xfe) >> 1) |
518 ((chksum
& 0x01) ? 0x80 : 0)) + entry
->name
[i
];
524 /* if return_time==0, this returns the fat_date, else the fat_time */
525 static uint16_t fat_datetime(time_t time
,int return_time
) {
529 localtime_r(&time
,t
);
531 return cpu_to_le16((t
->tm_sec
/2)|(t
->tm_min
<<5)|(t
->tm_hour
<<11));
532 return cpu_to_le16((t
->tm_mday
)|((t
->tm_mon
+1)<<5)|((t
->tm_year
-80)<<9));
535 static inline void fat_set(BDRVVVFATState
* s
,unsigned int cluster
,uint32_t value
)
537 if(s
->fat_type
==32) {
538 uint32_t* entry
=array_get(&(s
->fat
),cluster
);
539 *entry
=cpu_to_le32(value
);
540 } else if(s
->fat_type
==16) {
541 uint16_t* entry
=array_get(&(s
->fat
),cluster
);
542 *entry
=cpu_to_le16(value
&0xffff);
544 int offset
= (cluster
*3/2);
545 unsigned char* p
= array_get(&(s
->fat
), offset
);
549 p
[1] = (p
[1]&0xf0) | ((value
>>8)&0xf);
552 p
[0] = (p
[0]&0xf) | ((value
&0xf)<<4);
559 static inline uint32_t fat_get(BDRVVVFATState
* s
,unsigned int cluster
)
561 if(s
->fat_type
==32) {
562 uint32_t* entry
=array_get(&(s
->fat
),cluster
);
563 return le32_to_cpu(*entry
);
564 } else if(s
->fat_type
==16) {
565 uint16_t* entry
=array_get(&(s
->fat
),cluster
);
566 return le16_to_cpu(*entry
);
568 const uint8_t* x
=(uint8_t*)(s
->fat
.pointer
)+cluster
*3/2;
569 return ((x
[0]|(x
[1]<<8))>>(cluster
&1?4:0))&0x0fff;
573 static inline int fat_eof(BDRVVVFATState
* s
,uint32_t fat_entry
)
575 if(fat_entry
>s
->max_fat_value
-8)
580 static inline void init_fat(BDRVVVFATState
* s
)
582 if (s
->fat_type
== 12) {
583 array_init(&(s
->fat
),1);
584 array_ensure_allocated(&(s
->fat
),
585 s
->sectors_per_fat
* 0x200 * 3 / 2 - 1);
587 array_init(&(s
->fat
),(s
->fat_type
==32?4:2));
588 array_ensure_allocated(&(s
->fat
),
589 s
->sectors_per_fat
* 0x200 / s
->fat
.item_size
- 1);
591 memset(s
->fat
.pointer
,0,s
->fat
.size
);
593 switch(s
->fat_type
) {
594 case 12: s
->max_fat_value
=0xfff; break;
595 case 16: s
->max_fat_value
=0xffff; break;
596 case 32: s
->max_fat_value
=0x0fffffff; break;
597 default: s
->max_fat_value
=0; /* error... */
602 /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
603 /* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
604 static inline direntry_t
* create_short_and_long_name(BDRVVVFATState
* s
,
605 unsigned int directory_start
, const char* filename
, int is_dot
)
607 int i
,j
,long_index
=s
->directory
.next
;
608 direntry_t
* entry
= NULL
;
609 direntry_t
* entry_long
= NULL
;
612 entry
=array_get_next(&(s
->directory
));
613 memset(entry
->name
, 0x20, sizeof(entry
->name
));
614 memcpy(entry
->name
,filename
,strlen(filename
));
618 entry_long
=create_long_filename(s
,filename
);
620 i
= strlen(filename
);
621 for(j
= i
- 1; j
>0 && filename
[j
]!='.';j
--);
627 entry
=array_get_next(&(s
->directory
));
628 memset(entry
->name
, 0x20, sizeof(entry
->name
));
629 memcpy(entry
->name
, filename
, i
);
632 for (i
= 0; i
< 3 && filename
[j
+ 1 + i
]; i
++) {
633 entry
->name
[8 + i
] = filename
[j
+ 1 + i
];
637 /* upcase & remove unwanted characters */
639 if(i
==10 || i
==7) for(;i
>0 && entry
->name
[i
]==' ';i
--);
640 if(entry
->name
[i
]<=' ' || entry
->name
[i
]>0x7f
641 || strchr(".*?<>|\":/\\[];,+='",entry
->name
[i
]))
643 else if(entry
->name
[i
]>='a' && entry
->name
[i
]<='z')
644 entry
->name
[i
]+='A'-'a';
647 /* mangle duplicates */
649 direntry_t
* entry1
=array_get(&(s
->directory
),directory_start
);
652 for(;entry1
<entry
;entry1
++)
653 if(!is_long_name(entry1
) && !memcmp(entry1
->name
,entry
->name
,11))
654 break; /* found dupe */
655 if(entry1
==entry
) /* no dupe found */
658 /* use all 8 characters of name */
659 if(entry
->name
[7]==' ') {
661 for(j
=6;j
>0 && entry
->name
[j
]==' ';j
--)
665 /* increment number */
666 for(j
=7;j
>0 && entry
->name
[j
]=='9';j
--)
669 if(entry
->name
[j
]<'0' || entry
->name
[j
]>'9')
676 /* calculate checksum; propagate to long name */
678 uint8_t chksum
=fat_chksum(entry
);
680 /* calculate anew, because realloc could have taken place */
681 entry_long
=array_get(&(s
->directory
),long_index
);
682 while(entry_long
<entry
&& is_long_name(entry_long
)) {
683 entry_long
->reserved
[1]=chksum
;
692 * Read a directory. (the index of the corresponding mapping must be passed).
694 static int read_directory(BDRVVVFATState
* s
, int mapping_index
)
696 mapping_t
* mapping
= array_get(&(s
->mapping
), mapping_index
);
697 direntry_t
* direntry
;
698 const char* dirname
= mapping
->path
;
699 int first_cluster
= mapping
->begin
;
700 int parent_index
= mapping
->info
.dir
.parent_mapping_index
;
701 mapping_t
* parent_mapping
= (mapping_t
*)
702 (parent_index
>= 0 ? array_get(&(s
->mapping
), parent_index
) : NULL
);
703 int first_cluster_of_parent
= parent_mapping
? parent_mapping
->begin
: -1;
705 DIR* dir
=opendir(dirname
);
706 struct dirent
* entry
;
709 assert(mapping
->mode
& MODE_DIRECTORY
);
712 mapping
->end
= mapping
->begin
;
716 i
= mapping
->info
.dir
.first_dir_index
=
717 first_cluster
== 0 ? 0 : s
->directory
.next
;
719 /* actually read the directory, and allocate the mappings */
720 while((entry
=readdir(dir
))) {
721 unsigned int length
=strlen(dirname
)+2+strlen(entry
->d_name
);
723 direntry_t
* direntry
;
725 int is_dot
=!strcmp(entry
->d_name
,".");
726 int is_dotdot
=!strcmp(entry
->d_name
,"..");
728 if(first_cluster
== 0 && (is_dotdot
|| is_dot
))
731 buffer
= g_malloc(length
);
732 snprintf(buffer
,length
,"%s/%s",dirname
,entry
->d_name
);
734 if(stat(buffer
,&st
)<0) {
739 /* create directory entry for this file */
740 direntry
=create_short_and_long_name(s
, i
, entry
->d_name
,
741 is_dot
|| is_dotdot
);
742 direntry
->attributes
=(S_ISDIR(st
.st_mode
)?0x10:0x20);
743 direntry
->reserved
[0]=direntry
->reserved
[1]=0;
744 direntry
->ctime
=fat_datetime(st
.st_ctime
,1);
745 direntry
->cdate
=fat_datetime(st
.st_ctime
,0);
746 direntry
->adate
=fat_datetime(st
.st_atime
,0);
747 direntry
->begin_hi
=0;
748 direntry
->mtime
=fat_datetime(st
.st_mtime
,1);
749 direntry
->mdate
=fat_datetime(st
.st_mtime
,0);
751 set_begin_of_direntry(direntry
, first_cluster_of_parent
);
753 set_begin_of_direntry(direntry
, first_cluster
);
755 direntry
->begin
=0; /* do that later */
756 if (st
.st_size
> 0x7fffffff) {
757 fprintf(stderr
, "File %s is larger than 2GB\n", buffer
);
762 direntry
->size
=cpu_to_le32(S_ISDIR(st
.st_mode
)?0:st
.st_size
);
764 /* create mapping for this file */
765 if(!is_dot
&& !is_dotdot
&& (S_ISDIR(st
.st_mode
) || st
.st_size
)) {
766 s
->current_mapping
= array_get_next(&(s
->mapping
));
767 s
->current_mapping
->begin
=0;
768 s
->current_mapping
->end
=st
.st_size
;
770 * we get the direntry of the most recent direntry, which
771 * contains the short name and all the relevant information.
773 s
->current_mapping
->dir_index
=s
->directory
.next
-1;
774 s
->current_mapping
->first_mapping_index
= -1;
775 if (S_ISDIR(st
.st_mode
)) {
776 s
->current_mapping
->mode
= MODE_DIRECTORY
;
777 s
->current_mapping
->info
.dir
.parent_mapping_index
=
780 s
->current_mapping
->mode
= MODE_UNDEFINED
;
781 s
->current_mapping
->info
.file
.offset
= 0;
783 s
->current_mapping
->path
=buffer
;
784 s
->current_mapping
->read_only
=
785 (st
.st_mode
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) == 0;
792 /* fill with zeroes up to the end of the cluster */
793 while(s
->directory
.next
%(0x10*s
->sectors_per_cluster
)) {
794 direntry_t
* direntry
=array_get_next(&(s
->directory
));
795 memset(direntry
,0,sizeof(direntry_t
));
798 /* TODO: if there are more entries, bootsector has to be adjusted! */
799 #define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
800 if (mapping_index
== 0 && s
->directory
.next
< ROOT_ENTRIES
) {
802 int cur
= s
->directory
.next
;
803 array_ensure_allocated(&(s
->directory
), ROOT_ENTRIES
- 1);
804 s
->directory
.next
= ROOT_ENTRIES
;
805 memset(array_get(&(s
->directory
), cur
), 0,
806 (ROOT_ENTRIES
- cur
) * sizeof(direntry_t
));
809 /* reget the mapping, since s->mapping was possibly realloc()ed */
810 mapping
= array_get(&(s
->mapping
), mapping_index
);
811 first_cluster
+= (s
->directory
.next
- mapping
->info
.dir
.first_dir_index
)
812 * 0x20 / s
->cluster_size
;
813 mapping
->end
= first_cluster
;
815 direntry
= array_get(&(s
->directory
), mapping
->dir_index
);
816 set_begin_of_direntry(direntry
, mapping
->begin
);
821 static inline uint32_t sector2cluster(BDRVVVFATState
* s
,off_t sector_num
)
823 return (sector_num
-s
->faked_sectors
)/s
->sectors_per_cluster
;
826 static inline off_t
cluster2sector(BDRVVVFATState
* s
, uint32_t cluster_num
)
828 return s
->faked_sectors
+ s
->sectors_per_cluster
* cluster_num
;
831 static int init_directories(BDRVVVFATState
* s
,
832 const char *dirname
, int heads
, int secs
,
835 bootsector_t
* bootsector
;
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
, s
->volume_label
, sizeof(entry
->name
));
865 /* Now build FAT, and write back information into directory */
868 s
->faked_sectors
=s
->first_sectors_number
+s
->sectors_per_fat
*2;
869 s
->cluster_count
=sector2cluster(s
, s
->sector_count
);
871 mapping
= array_get_next(&(s
->mapping
));
873 mapping
->dir_index
= 0;
874 mapping
->info
.dir
.parent_mapping_index
= -1;
875 mapping
->first_mapping_index
= -1;
876 mapping
->path
= g_strdup(dirname
);
877 i
= strlen(mapping
->path
);
878 if (i
> 0 && mapping
->path
[i
- 1] == '/')
879 mapping
->path
[i
- 1] = '\0';
880 mapping
->mode
= MODE_DIRECTORY
;
881 mapping
->read_only
= 0;
882 s
->path
= mapping
->path
;
884 for (i
= 0, cluster
= 0; i
< s
->mapping
.next
; i
++) {
885 /* MS-DOS expects the FAT to be 0 for the root directory
886 * (except for the media byte). */
887 /* LATER TODO: still true for FAT32? */
888 int fix_fat
= (i
!= 0);
889 mapping
= array_get(&(s
->mapping
), i
);
891 if (mapping
->mode
& MODE_DIRECTORY
) {
892 mapping
->begin
= cluster
;
893 if(read_directory(s
, i
)) {
894 error_setg(errp
, "Could not read directory %s",
898 mapping
= array_get(&(s
->mapping
), i
);
900 assert(mapping
->mode
== MODE_UNDEFINED
);
901 mapping
->mode
=MODE_NORMAL
;
902 mapping
->begin
= cluster
;
903 if (mapping
->end
> 0) {
904 direntry_t
* direntry
= array_get(&(s
->directory
),
907 mapping
->end
= cluster
+ 1 + (mapping
->end
-1)/s
->cluster_size
;
908 set_begin_of_direntry(direntry
, mapping
->begin
);
910 mapping
->end
= cluster
+ 1;
915 assert(mapping
->begin
< mapping
->end
);
917 /* next free cluster */
918 cluster
= mapping
->end
;
920 if(cluster
> s
->cluster_count
) {
922 "Directory does not fit in FAT%d (capacity %.2f MB)",
923 s
->fat_type
, s
->sector_count
/ 2000.0);
927 /* fix fat for entry */
930 for(j
= mapping
->begin
; j
< mapping
->end
- 1; j
++)
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
, s
->volume_label
,
972 sizeof(bootsector
->u
.fat16
.volume_label
));
973 memcpy(bootsector
->fat_type
,(s
->fat_type
==12?"FAT12 ":s
->fat_type
==16?"FAT16 ":"FAT32 "),8);
974 bootsector
->magic
[0]=0x55; bootsector
->magic
[1]=0xaa;
980 static BDRVVVFATState
*vvv
= NULL
;
983 static int enable_write_target(BlockDriverState
*bs
, Error
**errp
);
984 static int is_consistent(BDRVVVFATState
*s
);
986 static QemuOptsList runtime_opts
= {
988 .head
= QTAILQ_HEAD_INITIALIZER(runtime_opts
.head
),
992 .type
= QEMU_OPT_STRING
,
993 .help
= "Host directory to map to the vvfat device",
997 .type
= QEMU_OPT_NUMBER
,
998 .help
= "FAT type (12, 16 or 32)",
1002 .type
= QEMU_OPT_BOOL
,
1003 .help
= "Create a floppy rather than a hard disk image",
1007 .type
= QEMU_OPT_STRING
,
1008 .help
= "Use a volume label other than QEMU VVFAT",
1012 .type
= QEMU_OPT_BOOL
,
1013 .help
= "Make the image writable",
1015 { /* end of list */ }
1019 static void vvfat_parse_filename(const char *filename
, QDict
*options
,
1023 bool floppy
= false;
1027 if (!strstart(filename
, "fat:", NULL
)) {
1028 error_setg(errp
, "File name string must start with 'fat:'");
1033 if (strstr(filename
, ":32:")) {
1035 } else if (strstr(filename
, ":16:")) {
1037 } else if (strstr(filename
, ":12:")) {
1041 if (strstr(filename
, ":floppy:")) {
1045 if (strstr(filename
, ":rw:")) {
1049 /* Get the directory name without options */
1050 i
= strrchr(filename
, ':') - filename
;
1052 if (filename
[i
- 2] == ':' && qemu_isalpha(filename
[i
- 1])) {
1053 /* workaround for DOS drive names */
1059 /* Fill in the options QDict */
1060 qdict_put(options
, "dir", qstring_from_str(filename
));
1061 qdict_put(options
, "fat-type", qint_from_int(fat_type
));
1062 qdict_put(options
, "floppy", qbool_from_bool(floppy
));
1063 qdict_put(options
, "rw", qbool_from_bool(rw
));
1066 static int vvfat_open(BlockDriverState
*bs
, QDict
*options
, int flags
,
1069 BDRVVVFATState
*s
= bs
->opaque
;
1070 int cyls
, heads
, secs
;
1072 const char *dirname
, *label
;
1074 Error
*local_err
= NULL
;
1081 opts
= qemu_opts_create(&runtime_opts
, NULL
, 0, &error_abort
);
1082 qemu_opts_absorb_qdict(opts
, options
, &local_err
);
1084 error_propagate(errp
, local_err
);
1089 dirname
= qemu_opt_get(opts
, "dir");
1091 error_setg(errp
, "vvfat block driver requires a 'dir' option");
1096 s
->fat_type
= qemu_opt_get_number(opts
, "fat-type", 0);
1097 floppy
= qemu_opt_get_bool(opts
, "floppy", false);
1099 memset(s
->volume_label
, ' ', sizeof(s
->volume_label
));
1100 label
= qemu_opt_get(opts
, "label");
1102 size_t label_length
= strlen(label
);
1103 if (label_length
> 11) {
1104 error_setg(errp
, "vvfat label cannot be longer than 11 bytes");
1108 memcpy(s
->volume_label
, label
, label_length
);
1110 memcpy(s
->volume_label
, "QEMU VVFAT", 10);
1114 /* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */
1118 s
->sectors_per_cluster
= 2;
1120 secs
= s
->fat_type
== 12 ? 18 : 36;
1121 s
->sectors_per_cluster
= 1;
1123 s
->first_sectors_number
= 1;
1127 /* 32MB or 504MB disk*/
1131 s
->first_sectors_number
= 0x40;
1132 cyls
= s
->fat_type
== 12 ? 64 : 1024;
1137 switch (s
->fat_type
) {
1139 fprintf(stderr
, "Big fat greek warning: FAT32 has not been tested. "
1140 "You are welcome to do so!\n");
1146 error_setg(errp
, "Valid FAT types are only 12, 16 and 32");
1154 /* LATER TODO: if FAT32, adjust */
1155 s
->sectors_per_cluster
=0x10;
1157 s
->current_cluster
=0xffffffff;
1159 /* read only is the default for safety */
1160 bs
->read_only
= true;
1162 s
->qcow_filename
= NULL
;
1164 s
->downcase_short_names
= 1;
1166 fprintf(stderr
, "vvfat %s chs %d,%d,%d\n",
1167 dirname
, cyls
, heads
, secs
);
1169 s
->sector_count
= cyls
* heads
* secs
- (s
->first_sectors_number
- 1);
1171 if (qemu_opt_get_bool(opts
, "rw", false)) {
1172 ret
= enable_write_target(bs
, errp
);
1176 bs
->read_only
= false;
1179 bs
->total_sectors
= cyls
* heads
* secs
;
1181 if (init_directories(s
, dirname
, heads
, secs
, errp
)) {
1186 s
->sector_count
= s
->faked_sectors
+ s
->sectors_per_cluster
*s
->cluster_count
;
1188 if (s
->first_sectors_number
== 0x40) {
1189 init_mbr(s
, cyls
, heads
, secs
);
1192 // assert(is_consistent(s));
1193 qemu_co_mutex_init(&s
->lock
);
1195 /* Disable migration when vvfat is used rw */
1197 error_setg(&s
->migration_blocker
,
1198 "The vvfat (rw) format used by node '%s' "
1199 "does not support live migration",
1200 bdrv_get_device_or_node_name(bs
));
1201 migrate_add_blocker(s
->migration_blocker
);
1206 qemu_opts_del(opts
);
1210 static void vvfat_refresh_limits(BlockDriverState
*bs
, Error
**errp
)
1212 bs
->bl
.request_alignment
= BDRV_SECTOR_SIZE
; /* No sub-sector I/O */
1215 static inline void vvfat_close_current_file(BDRVVVFATState
*s
)
1217 if(s
->current_mapping
) {
1218 s
->current_mapping
= NULL
;
1219 if (s
->current_fd
) {
1220 qemu_close(s
->current_fd
);
1224 s
->current_cluster
= -1;
1227 /* mappings between index1 and index2-1 are supposed to be ordered
1228 * return value is the index of the last mapping for which end>cluster_num
1230 static inline int find_mapping_for_cluster_aux(BDRVVVFATState
* s
,int cluster_num
,int index1
,int index2
)
1235 index3
=(index1
+index2
)/2;
1236 mapping
=array_get(&(s
->mapping
),index3
);
1237 assert(mapping
->begin
< mapping
->end
);
1238 if(mapping
->begin
>=cluster_num
) {
1239 assert(index2
!=index3
|| index2
==0);
1245 return mapping
->end
<=cluster_num
? index2
: index1
;
1248 assert(index1
<=index2
);
1249 DLOG(mapping
=array_get(&(s
->mapping
),index1
);
1250 assert(mapping
->begin
<=cluster_num
);
1251 assert(index2
>= s
->mapping
.next
||
1252 ((mapping
= array_get(&(s
->mapping
),index2
)) &&
1253 mapping
->end
>cluster_num
)));
1257 static inline mapping_t
* find_mapping_for_cluster(BDRVVVFATState
* s
,int cluster_num
)
1259 int index
=find_mapping_for_cluster_aux(s
,cluster_num
,0,s
->mapping
.next
);
1261 if(index
>=s
->mapping
.next
)
1263 mapping
=array_get(&(s
->mapping
),index
);
1264 if(mapping
->begin
>cluster_num
)
1266 assert(mapping
->begin
<=cluster_num
&& mapping
->end
>cluster_num
);
1270 static int open_file(BDRVVVFATState
* s
,mapping_t
* mapping
)
1274 if(!s
->current_mapping
||
1275 strcmp(s
->current_mapping
->path
,mapping
->path
)) {
1277 int fd
= qemu_open(mapping
->path
, O_RDONLY
| O_BINARY
| O_LARGEFILE
);
1280 vvfat_close_current_file(s
);
1282 s
->current_mapping
= mapping
;
1287 static inline int read_cluster(BDRVVVFATState
*s
,int cluster_num
)
1289 if(s
->current_cluster
!= cluster_num
) {
1292 assert(!s
->current_mapping
|| s
->current_fd
|| (s
->current_mapping
->mode
& MODE_DIRECTORY
));
1293 if(!s
->current_mapping
1294 || s
->current_mapping
->begin
>cluster_num
1295 || s
->current_mapping
->end
<=cluster_num
) {
1296 /* binary search of mappings for file */
1297 mapping_t
* mapping
=find_mapping_for_cluster(s
,cluster_num
);
1299 assert(!mapping
|| (cluster_num
>=mapping
->begin
&& cluster_num
<mapping
->end
));
1301 if (mapping
&& mapping
->mode
& MODE_DIRECTORY
) {
1302 vvfat_close_current_file(s
);
1303 s
->current_mapping
= mapping
;
1304 read_cluster_directory
:
1305 offset
= s
->cluster_size
*(cluster_num
-s
->current_mapping
->begin
);
1306 s
->cluster
= (unsigned char*)s
->directory
.pointer
+offset
1307 + 0x20*s
->current_mapping
->info
.dir
.first_dir_index
;
1308 assert(((s
->cluster
-(unsigned char*)s
->directory
.pointer
)%s
->cluster_size
)==0);
1309 assert((char*)s
->cluster
+s
->cluster_size
<= s
->directory
.pointer
+s
->directory
.next
*s
->directory
.item_size
);
1310 s
->current_cluster
= cluster_num
;
1314 if(open_file(s
,mapping
))
1316 } else if (s
->current_mapping
->mode
& MODE_DIRECTORY
)
1317 goto read_cluster_directory
;
1319 assert(s
->current_fd
);
1321 offset
=s
->cluster_size
*(cluster_num
-s
->current_mapping
->begin
)+s
->current_mapping
->info
.file
.offset
;
1322 if(lseek(s
->current_fd
, offset
, SEEK_SET
)!=offset
)
1324 s
->cluster
=s
->cluster_buffer
;
1325 result
=read(s
->current_fd
,s
->cluster
,s
->cluster_size
);
1327 s
->current_cluster
= -1;
1330 s
->current_cluster
= cluster_num
;
1336 static void print_direntry(const direntry_t
* direntry
)
1341 fprintf(stderr
, "direntry %p: ", direntry
);
1344 if(is_long_name(direntry
)) {
1345 unsigned char* c
=(unsigned char*)direntry
;
1347 for(i
=1;i
<11 && c
[i
] && c
[i
]!=0xff;i
+=2)
1348 #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
1350 for(i
=14;i
<26 && c
[i
] && c
[i
]!=0xff;i
+=2)
1352 for(i
=28;i
<32 && c
[i
] && c
[i
]!=0xff;i
+=2)
1355 fprintf(stderr
, "%s\n", buffer
);
1359 ADD_CHAR(direntry
->name
[i
]);
1361 fprintf(stderr
,"%s attributes=0x%02x begin=%d size=%d\n",
1363 direntry
->attributes
,
1364 begin_of_direntry(direntry
),le32_to_cpu(direntry
->size
));
1368 static void print_mapping(const mapping_t
* mapping
)
1370 fprintf(stderr
, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1371 "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1372 mapping
, mapping
->begin
, mapping
->end
, mapping
->dir_index
,
1373 mapping
->first_mapping_index
, mapping
->path
, mapping
->mode
);
1375 if (mapping
->mode
& MODE_DIRECTORY
)
1376 fprintf(stderr
, "parent_mapping_index = %d, first_dir_index = %d\n", mapping
->info
.dir
.parent_mapping_index
, mapping
->info
.dir
.first_dir_index
);
1378 fprintf(stderr
, "offset = %d\n", mapping
->info
.file
.offset
);
1382 static int vvfat_read(BlockDriverState
*bs
, int64_t sector_num
,
1383 uint8_t *buf
, int nb_sectors
)
1385 BDRVVVFATState
*s
= bs
->opaque
;
1388 for(i
=0;i
<nb_sectors
;i
++,sector_num
++) {
1389 if (sector_num
>= bs
->total_sectors
)
1393 if (bdrv_is_allocated(s
->qcow
->bs
, sector_num
, nb_sectors
-i
, &n
)) {
1394 DLOG(fprintf(stderr
, "sectors %d+%d allocated\n",
1395 (int)sector_num
, n
));
1396 if (bdrv_read(s
->qcow
, sector_num
, buf
+ i
* 0x200, n
)) {
1400 sector_num
+= n
- 1;
1403 DLOG(fprintf(stderr
, "sector %d not allocated\n", (int)sector_num
));
1405 if(sector_num
<s
->faked_sectors
) {
1406 if(sector_num
<s
->first_sectors_number
)
1407 memcpy(buf
+i
*0x200,&(s
->first_sectors
[sector_num
*0x200]),0x200);
1408 else if(sector_num
-s
->first_sectors_number
<s
->sectors_per_fat
)
1409 memcpy(buf
+i
*0x200,&(s
->fat
.pointer
[(sector_num
-s
->first_sectors_number
)*0x200]),0x200);
1410 else if(sector_num
-s
->first_sectors_number
-s
->sectors_per_fat
<s
->sectors_per_fat
)
1411 memcpy(buf
+i
*0x200,&(s
->fat
.pointer
[(sector_num
-s
->first_sectors_number
-s
->sectors_per_fat
)*0x200]),0x200);
1413 uint32_t sector
=sector_num
-s
->faked_sectors
,
1414 sector_offset_in_cluster
=(sector
%s
->sectors_per_cluster
),
1415 cluster_num
=sector
/s
->sectors_per_cluster
;
1416 if(cluster_num
> s
->cluster_count
|| read_cluster(s
, cluster_num
) != 0) {
1417 /* LATER TODO: strict: return -1; */
1418 memset(buf
+i
*0x200,0,0x200);
1421 memcpy(buf
+i
*0x200,s
->cluster
+sector_offset_in_cluster
*0x200,0x200);
1427 static int coroutine_fn
1428 vvfat_co_preadv(BlockDriverState
*bs
, uint64_t offset
, uint64_t bytes
,
1429 QEMUIOVector
*qiov
, int flags
)
1432 BDRVVVFATState
*s
= bs
->opaque
;
1433 uint64_t sector_num
= offset
>> BDRV_SECTOR_BITS
;
1434 int nb_sectors
= bytes
>> BDRV_SECTOR_BITS
;
1437 assert((offset
& (BDRV_SECTOR_SIZE
- 1)) == 0);
1438 assert((bytes
& (BDRV_SECTOR_SIZE
- 1)) == 0);
1440 buf
= g_try_malloc(bytes
);
1441 if (bytes
&& buf
== NULL
) {
1445 qemu_co_mutex_lock(&s
->lock
);
1446 ret
= vvfat_read(bs
, sector_num
, buf
, nb_sectors
);
1447 qemu_co_mutex_unlock(&s
->lock
);
1449 qemu_iovec_from_buf(qiov
, 0, buf
, bytes
);
1455 /* LATER TODO: statify all functions */
1458 * Idea of the write support (use snapshot):
1460 * 1. check if all data is consistent, recording renames, modifications,
1461 * new files and directories (in s->commits).
1463 * 2. if the data is not consistent, stop committing
1465 * 3. handle renames, and create new files and directories (do not yet
1466 * write their contents)
1468 * 4. walk the directories, fixing the mapping and direntries, and marking
1469 * the handled mappings as not deleted
1471 * 5. commit the contents of the files
1473 * 6. handle deleted files and directories
1477 typedef struct commit_t
{
1480 struct { uint32_t cluster
; } rename
;
1481 struct { int dir_index
; uint32_t modified_offset
; } writeout
;
1482 struct { uint32_t first_cluster
; } new_file
;
1483 struct { uint32_t cluster
; } mkdir
;
1485 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1487 ACTION_RENAME
, ACTION_WRITEOUT
, ACTION_NEW_FILE
, ACTION_MKDIR
1491 static void clear_commits(BDRVVVFATState
* s
)
1494 DLOG(fprintf(stderr
, "clear_commits (%d commits)\n", s
->commits
.next
));
1495 for (i
= 0; i
< s
->commits
.next
; i
++) {
1496 commit_t
* commit
= array_get(&(s
->commits
), i
);
1497 assert(commit
->path
|| commit
->action
== ACTION_WRITEOUT
);
1498 if (commit
->action
!= ACTION_WRITEOUT
) {
1499 assert(commit
->path
);
1500 g_free(commit
->path
);
1502 assert(commit
->path
== NULL
);
1504 s
->commits
.next
= 0;
1507 static void schedule_rename(BDRVVVFATState
* s
,
1508 uint32_t cluster
, char* new_path
)
1510 commit_t
* commit
= array_get_next(&(s
->commits
));
1511 commit
->path
= new_path
;
1512 commit
->param
.rename
.cluster
= cluster
;
1513 commit
->action
= ACTION_RENAME
;
1516 static void schedule_writeout(BDRVVVFATState
* s
,
1517 int dir_index
, uint32_t modified_offset
)
1519 commit_t
* commit
= array_get_next(&(s
->commits
));
1520 commit
->path
= NULL
;
1521 commit
->param
.writeout
.dir_index
= dir_index
;
1522 commit
->param
.writeout
.modified_offset
= modified_offset
;
1523 commit
->action
= ACTION_WRITEOUT
;
1526 static void schedule_new_file(BDRVVVFATState
* s
,
1527 char* path
, uint32_t first_cluster
)
1529 commit_t
* commit
= array_get_next(&(s
->commits
));
1530 commit
->path
= path
;
1531 commit
->param
.new_file
.first_cluster
= first_cluster
;
1532 commit
->action
= ACTION_NEW_FILE
;
1535 static void schedule_mkdir(BDRVVVFATState
* s
, uint32_t cluster
, char* path
)
1537 commit_t
* commit
= array_get_next(&(s
->commits
));
1538 commit
->path
= path
;
1539 commit
->param
.mkdir
.cluster
= cluster
;
1540 commit
->action
= ACTION_MKDIR
;
1545 * Since the sequence number is at most 0x3f, and the filename
1546 * length is at most 13 times the sequence number, the maximal
1547 * filename length is 0x3f * 13 bytes.
1549 unsigned char name
[0x3f * 13 + 1];
1551 int sequence_number
;
1554 static void lfn_init(long_file_name
* lfn
)
1556 lfn
->sequence_number
= lfn
->len
= 0;
1557 lfn
->checksum
= 0x100;
1560 /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1561 static int parse_long_name(long_file_name
* lfn
,
1562 const direntry_t
* direntry
)
1565 const unsigned char* pointer
= (const unsigned char*)direntry
;
1567 if (!is_long_name(direntry
))
1570 if (pointer
[0] & 0x40) {
1571 lfn
->sequence_number
= pointer
[0] & 0x3f;
1572 lfn
->checksum
= pointer
[13];
1574 lfn
->name
[lfn
->sequence_number
* 13] = 0;
1575 } else if ((pointer
[0] & 0x3f) != --lfn
->sequence_number
)
1577 else if (pointer
[13] != lfn
->checksum
)
1579 else if (pointer
[12] || pointer
[26] || pointer
[27])
1582 offset
= 13 * (lfn
->sequence_number
- 1);
1583 for (i
= 0, j
= 1; i
< 13; i
++, j
+=2) {
1589 if (pointer
[j
+1] == 0)
1590 lfn
->name
[offset
+ i
] = pointer
[j
];
1591 else if (pointer
[j
+1] != 0xff || (pointer
[0] & 0x40) == 0)
1594 lfn
->name
[offset
+ i
] = 0;
1597 if (pointer
[0] & 0x40)
1598 lfn
->len
= offset
+ strlen((char*)lfn
->name
+ offset
);
1603 /* returns 0 if successful, >0 if no short_name, and <0 on error */
1604 static int parse_short_name(BDRVVVFATState
* s
,
1605 long_file_name
* lfn
, direntry_t
* direntry
)
1609 if (!is_short_name(direntry
))
1612 for (j
= 7; j
>= 0 && direntry
->name
[j
] == ' '; j
--);
1613 for (i
= 0; i
<= j
; i
++) {
1614 if (direntry
->name
[i
] <= ' ' || direntry
->name
[i
] > 0x7f)
1616 else if (s
->downcase_short_names
)
1617 lfn
->name
[i
] = qemu_tolower(direntry
->name
[i
]);
1619 lfn
->name
[i
] = direntry
->name
[i
];
1622 for (j
= 2; j
>= 0 && direntry
->name
[8 + j
] == ' '; j
--) {
1625 lfn
->name
[i
++] = '.';
1626 lfn
->name
[i
+ j
+ 1] = '\0';
1627 for (;j
>= 0; j
--) {
1628 uint8_t c
= direntry
->name
[8 + j
];
1629 if (c
<= ' ' || c
> 0x7f) {
1631 } else if (s
->downcase_short_names
) {
1632 lfn
->name
[i
+ j
] = qemu_tolower(c
);
1634 lfn
->name
[i
+ j
] = c
;
1638 lfn
->name
[i
+ j
+ 1] = '\0';
1640 lfn
->len
= strlen((char*)lfn
->name
);
1645 static inline uint32_t modified_fat_get(BDRVVVFATState
* s
,
1646 unsigned int cluster
)
1648 if (cluster
< s
->last_cluster_of_root_directory
) {
1649 if (cluster
+ 1 == s
->last_cluster_of_root_directory
)
1650 return s
->max_fat_value
;
1655 if (s
->fat_type
==32) {
1656 uint32_t* entry
=((uint32_t*)s
->fat2
)+cluster
;
1657 return le32_to_cpu(*entry
);
1658 } else if (s
->fat_type
==16) {
1659 uint16_t* entry
=((uint16_t*)s
->fat2
)+cluster
;
1660 return le16_to_cpu(*entry
);
1662 const uint8_t* x
=s
->fat2
+cluster
*3/2;
1663 return ((x
[0]|(x
[1]<<8))>>(cluster
&1?4:0))&0x0fff;
1667 static inline int cluster_was_modified(BDRVVVFATState
* s
, uint32_t cluster_num
)
1669 int was_modified
= 0;
1672 if (s
->qcow
== NULL
) {
1676 for (i
= 0; !was_modified
&& i
< s
->sectors_per_cluster
; i
++) {
1677 was_modified
= bdrv_is_allocated(s
->qcow
->bs
,
1678 cluster2sector(s
, cluster_num
) + i
,
1682 return was_modified
;
1685 static const char* get_basename(const char* path
)
1687 char* basename
= strrchr(path
, '/');
1688 if (basename
== NULL
)
1691 return basename
+ 1; /* strip '/' */
1695 * The array s->used_clusters holds the states of the clusters. If it is
1696 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1697 * was modified, bit 3 is set.
1698 * If any cluster is allocated, but not part of a file or directory, this
1699 * driver refuses to commit.
1702 USED_DIRECTORY
= 1, USED_FILE
= 2, USED_ANY
= 3, USED_ALLOCATED
= 4
1706 * get_cluster_count_for_direntry() not only determines how many clusters
1707 * are occupied by direntry, but also if it was renamed or modified.
1709 * A file is thought to be renamed *only* if there already was a file with
1710 * exactly the same first cluster, but a different name.
1712 * Further, the files/directories handled by this function are
1713 * assumed to be *not* deleted (and *only* those).
1715 static uint32_t get_cluster_count_for_direntry(BDRVVVFATState
* s
,
1716 direntry_t
* direntry
, const char* path
)
1719 * This is a little bit tricky:
1720 * IF the guest OS just inserts a cluster into the file chain,
1721 * and leaves the rest alone, (i.e. the original file had clusters
1722 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1724 * - do_commit will write the cluster into the file at the given
1727 * - the cluster which is overwritten should be moved to a later
1728 * position in the file.
1730 * I am not aware that any OS does something as braindead, but this
1731 * situation could happen anyway when not committing for a long time.
1732 * Just to be sure that this does not bite us, detect it, and copy the
1733 * contents of the clusters to-be-overwritten into the qcow.
1736 int was_modified
= 0;
1739 uint32_t cluster_num
= begin_of_direntry(direntry
);
1740 uint32_t offset
= 0;
1741 int first_mapping_index
= -1;
1742 mapping_t
* mapping
= NULL
;
1743 const char* basename2
= NULL
;
1745 vvfat_close_current_file(s
);
1747 /* the root directory */
1748 if (cluster_num
== 0)
1753 basename2
= get_basename(path
);
1755 mapping
= find_mapping_for_cluster(s
, cluster_num
);
1758 const char* basename
;
1760 assert(mapping
->mode
& MODE_DELETED
);
1761 mapping
->mode
&= ~MODE_DELETED
;
1763 basename
= get_basename(mapping
->path
);
1765 assert(mapping
->mode
& MODE_NORMAL
);
1768 if (strcmp(basename
, basename2
))
1769 schedule_rename(s
, cluster_num
, g_strdup(path
));
1770 } else if (is_file(direntry
))
1772 schedule_new_file(s
, g_strdup(path
), cluster_num
);
1781 if (!copy_it
&& cluster_was_modified(s
, cluster_num
)) {
1782 if (mapping
== NULL
||
1783 mapping
->begin
> cluster_num
||
1784 mapping
->end
<= cluster_num
)
1785 mapping
= find_mapping_for_cluster(s
, cluster_num
);
1789 (mapping
->mode
& MODE_DIRECTORY
) == 0) {
1791 /* was modified in qcow */
1792 if (offset
!= mapping
->info
.file
.offset
+ s
->cluster_size
1793 * (cluster_num
- mapping
->begin
)) {
1794 /* offset of this cluster in file chain has changed */
1797 } else if (offset
== 0) {
1798 const char* basename
= get_basename(mapping
->path
);
1800 if (strcmp(basename
, basename2
))
1802 first_mapping_index
= array_index(&(s
->mapping
), mapping
);
1805 if (mapping
->first_mapping_index
!= first_mapping_index
1806 && mapping
->info
.file
.offset
> 0) {
1811 /* need to write out? */
1812 if (!was_modified
&& is_file(direntry
)) {
1814 schedule_writeout(s
, mapping
->dir_index
, offset
);
1822 * This is horribly inefficient, but that is okay, since
1823 * it is rarely executed, if at all.
1825 int64_t offset
= cluster2sector(s
, cluster_num
);
1827 vvfat_close_current_file(s
);
1828 for (i
= 0; i
< s
->sectors_per_cluster
; i
++) {
1831 res
= bdrv_is_allocated(s
->qcow
->bs
, offset
+ i
, 1, &dummy
);
1833 res
= vvfat_read(s
->bs
, offset
, s
->cluster_buffer
, 1);
1837 res
= bdrv_write(s
->qcow
, offset
, s
->cluster_buffer
, 1);
1847 if (s
->used_clusters
[cluster_num
] & USED_ANY
)
1849 s
->used_clusters
[cluster_num
] = USED_FILE
;
1851 cluster_num
= modified_fat_get(s
, cluster_num
);
1853 if (fat_eof(s
, cluster_num
))
1855 else if (cluster_num
< 2 || cluster_num
> s
->max_fat_value
- 16)
1858 offset
+= s
->cluster_size
;
1863 * This function looks at the modified data (qcow).
1864 * It returns 0 upon inconsistency or error, and the number of clusters
1865 * used by the directory, its subdirectories and their files.
1867 static int check_directory_consistency(BDRVVVFATState
*s
,
1868 int cluster_num
, const char* path
)
1871 unsigned char* cluster
= g_malloc(s
->cluster_size
);
1872 direntry_t
* direntries
= (direntry_t
*)cluster
;
1873 mapping_t
* mapping
= find_mapping_for_cluster(s
, cluster_num
);
1876 int path_len
= strlen(path
);
1877 char path2
[PATH_MAX
+ 1];
1879 assert(path_len
< PATH_MAX
); /* len was tested before! */
1880 pstrcpy(path2
, sizeof(path2
), path
);
1881 path2
[path_len
] = '/';
1882 path2
[path_len
+ 1] = '\0';
1885 const char* basename
= get_basename(mapping
->path
);
1886 const char* basename2
= get_basename(path
);
1888 assert(mapping
->mode
& MODE_DIRECTORY
);
1890 assert(mapping
->mode
& MODE_DELETED
);
1891 mapping
->mode
&= ~MODE_DELETED
;
1893 if (strcmp(basename
, basename2
))
1894 schedule_rename(s
, cluster_num
, g_strdup(path
));
1897 schedule_mkdir(s
, cluster_num
, g_strdup(path
));
1906 if (s
->used_clusters
[cluster_num
] & USED_ANY
) {
1907 fprintf(stderr
, "cluster %d used more than once\n", (int)cluster_num
);
1910 s
->used_clusters
[cluster_num
] = USED_DIRECTORY
;
1912 DLOG(fprintf(stderr
, "read cluster %d (sector %d)\n", (int)cluster_num
, (int)cluster2sector(s
, cluster_num
)));
1913 subret
= vvfat_read(s
->bs
, cluster2sector(s
, cluster_num
), cluster
,
1914 s
->sectors_per_cluster
);
1916 fprintf(stderr
, "Error fetching direntries\n");
1922 for (i
= 0; i
< 0x10 * s
->sectors_per_cluster
; i
++) {
1923 int cluster_count
= 0;
1925 DLOG(fprintf(stderr
, "check direntry %d:\n", i
); print_direntry(direntries
+ i
));
1926 if (is_volume_label(direntries
+ i
) || is_dot(direntries
+ i
) ||
1927 is_free(direntries
+ i
))
1930 subret
= parse_long_name(&lfn
, direntries
+ i
);
1932 fprintf(stderr
, "Error in long name\n");
1935 if (subret
== 0 || is_free(direntries
+ i
))
1938 if (fat_chksum(direntries
+i
) != lfn
.checksum
) {
1939 subret
= parse_short_name(s
, &lfn
, direntries
+ i
);
1941 fprintf(stderr
, "Error in short name (%d)\n", subret
);
1944 if (subret
> 0 || !strcmp((char*)lfn
.name
, ".")
1945 || !strcmp((char*)lfn
.name
, ".."))
1948 lfn
.checksum
= 0x100; /* cannot use long name twice */
1950 if (path_len
+ 1 + lfn
.len
>= PATH_MAX
) {
1951 fprintf(stderr
, "Name too long: %s/%s\n", path
, lfn
.name
);
1954 pstrcpy(path2
+ path_len
+ 1, sizeof(path2
) - path_len
- 1,
1957 if (is_directory(direntries
+ i
)) {
1958 if (begin_of_direntry(direntries
+ i
) == 0) {
1959 DLOG(fprintf(stderr
, "invalid begin for directory: %s\n", path2
); print_direntry(direntries
+ i
));
1962 cluster_count
= check_directory_consistency(s
,
1963 begin_of_direntry(direntries
+ i
), path2
);
1964 if (cluster_count
== 0) {
1965 DLOG(fprintf(stderr
, "problem in directory %s:\n", path2
); print_direntry(direntries
+ i
));
1968 } else if (is_file(direntries
+ i
)) {
1969 /* check file size with FAT */
1970 cluster_count
= get_cluster_count_for_direntry(s
, direntries
+ i
, path2
);
1971 if (cluster_count
!=
1972 DIV_ROUND_UP(le32_to_cpu(direntries
[i
].size
), s
->cluster_size
)) {
1973 DLOG(fprintf(stderr
, "Cluster count mismatch\n"));
1977 abort(); /* cluster_count = 0; */
1979 ret
+= cluster_count
;
1982 cluster_num
= modified_fat_get(s
, cluster_num
);
1983 } while(!fat_eof(s
, cluster_num
));
1989 /* returns 1 on success */
1990 static int is_consistent(BDRVVVFATState
* s
)
1993 int used_clusters_count
= 0;
1997 * - get modified FAT
1998 * - compare the two FATs (TODO)
1999 * - get buffer for marking used clusters
2000 * - recurse direntries from root (using bs->bdrv_read to make
2001 * sure to get the new data)
2002 * - check that the FAT agrees with the size
2003 * - count the number of clusters occupied by this directory and
2005 * - check that the cumulative used cluster count agrees with the
2007 * - if all is fine, return number of used clusters
2009 if (s
->fat2
== NULL
) {
2010 int size
= 0x200 * s
->sectors_per_fat
;
2011 s
->fat2
= g_malloc(size
);
2012 memcpy(s
->fat2
, s
->fat
.pointer
, size
);
2014 check
= vvfat_read(s
->bs
,
2015 s
->first_sectors_number
, s
->fat2
, s
->sectors_per_fat
);
2017 fprintf(stderr
, "Could not copy fat\n");
2020 assert (s
->used_clusters
);
2021 for (i
= 0; i
< sector2cluster(s
, s
->sector_count
); i
++)
2022 s
->used_clusters
[i
] &= ~USED_ANY
;
2026 /* mark every mapped file/directory as deleted.
2027 * (check_directory_consistency() will unmark those still present). */
2029 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2030 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2031 if (mapping
->first_mapping_index
< 0)
2032 mapping
->mode
|= MODE_DELETED
;
2035 used_clusters_count
= check_directory_consistency(s
, 0, s
->path
);
2036 if (used_clusters_count
<= 0) {
2037 DLOG(fprintf(stderr
, "problem in directory\n"));
2041 check
= s
->last_cluster_of_root_directory
;
2042 for (i
= check
; i
< sector2cluster(s
, s
->sector_count
); i
++) {
2043 if (modified_fat_get(s
, i
)) {
2044 if(!s
->used_clusters
[i
]) {
2045 DLOG(fprintf(stderr
, "FAT was modified (%d), but cluster is not used?\n", i
));
2051 if (s
->used_clusters
[i
] == USED_ALLOCATED
) {
2052 /* allocated, but not used... */
2053 DLOG(fprintf(stderr
, "unused, modified cluster: %d\n", i
));
2058 if (check
!= used_clusters_count
)
2061 return used_clusters_count
;
2064 static inline void adjust_mapping_indices(BDRVVVFATState
* s
,
2065 int offset
, int adjust
)
2069 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2070 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2072 #define ADJUST_MAPPING_INDEX(name) \
2073 if (mapping->name >= offset) \
2074 mapping->name += adjust
2076 ADJUST_MAPPING_INDEX(first_mapping_index
);
2077 if (mapping
->mode
& MODE_DIRECTORY
)
2078 ADJUST_MAPPING_INDEX(info
.dir
.parent_mapping_index
);
2082 /* insert or update mapping */
2083 static mapping_t
* insert_mapping(BDRVVVFATState
* s
,
2084 uint32_t begin
, uint32_t end
)
2087 * - find mapping where mapping->begin >= begin,
2088 * - if mapping->begin > begin: insert
2089 * - adjust all references to mappings!
2093 int index
= find_mapping_for_cluster_aux(s
, begin
, 0, s
->mapping
.next
);
2094 mapping_t
* mapping
= NULL
;
2095 mapping_t
* first_mapping
= array_get(&(s
->mapping
), 0);
2097 if (index
< s
->mapping
.next
&& (mapping
= array_get(&(s
->mapping
), index
))
2098 && mapping
->begin
< begin
) {
2099 mapping
->end
= begin
;
2101 mapping
= array_get(&(s
->mapping
), index
);
2103 if (index
>= s
->mapping
.next
|| mapping
->begin
> begin
) {
2104 mapping
= array_insert(&(s
->mapping
), index
, 1);
2105 mapping
->path
= NULL
;
2106 adjust_mapping_indices(s
, index
, +1);
2109 mapping
->begin
= begin
;
2112 DLOG(mapping_t
* next_mapping
;
2113 assert(index
+ 1 >= s
->mapping
.next
||
2114 ((next_mapping
= array_get(&(s
->mapping
), index
+ 1)) &&
2115 next_mapping
->begin
>= end
)));
2117 if (s
->current_mapping
&& first_mapping
!= (mapping_t
*)s
->mapping
.pointer
)
2118 s
->current_mapping
= array_get(&(s
->mapping
),
2119 s
->current_mapping
- first_mapping
);
2124 static int remove_mapping(BDRVVVFATState
* s
, int mapping_index
)
2126 mapping_t
* mapping
= array_get(&(s
->mapping
), mapping_index
);
2127 mapping_t
* first_mapping
= array_get(&(s
->mapping
), 0);
2130 if (mapping
->first_mapping_index
< 0) {
2131 g_free(mapping
->path
);
2134 /* remove from s->mapping */
2135 array_remove(&(s
->mapping
), mapping_index
);
2137 /* adjust all references to mappings */
2138 adjust_mapping_indices(s
, mapping_index
, -1);
2140 if (s
->current_mapping
&& first_mapping
!= (mapping_t
*)s
->mapping
.pointer
)
2141 s
->current_mapping
= array_get(&(s
->mapping
),
2142 s
->current_mapping
- first_mapping
);
2147 static void adjust_dirindices(BDRVVVFATState
* s
, int offset
, int adjust
)
2150 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2151 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2152 if (mapping
->dir_index
>= offset
)
2153 mapping
->dir_index
+= adjust
;
2154 if ((mapping
->mode
& MODE_DIRECTORY
) &&
2155 mapping
->info
.dir
.first_dir_index
>= offset
)
2156 mapping
->info
.dir
.first_dir_index
+= adjust
;
2160 static direntry_t
* insert_direntries(BDRVVVFATState
* s
,
2161 int dir_index
, int count
)
2164 * make room in s->directory,
2167 direntry_t
* result
= array_insert(&(s
->directory
), dir_index
, count
);
2170 adjust_dirindices(s
, dir_index
, count
);
2174 static int remove_direntries(BDRVVVFATState
* s
, int dir_index
, int count
)
2176 int ret
= array_remove_slice(&(s
->directory
), dir_index
, count
);
2179 adjust_dirindices(s
, dir_index
, -count
);
2184 * Adapt the mappings of the cluster chain starting at first cluster
2185 * (i.e. if a file starts at first_cluster, the chain is followed according
2186 * to the modified fat, and the corresponding entries in s->mapping are
2189 static int commit_mappings(BDRVVVFATState
* s
,
2190 uint32_t first_cluster
, int dir_index
)
2192 mapping_t
* mapping
= find_mapping_for_cluster(s
, first_cluster
);
2193 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2194 uint32_t cluster
= first_cluster
;
2196 vvfat_close_current_file(s
);
2199 assert(mapping
->begin
== first_cluster
);
2200 mapping
->first_mapping_index
= -1;
2201 mapping
->dir_index
= dir_index
;
2202 mapping
->mode
= (dir_index
<= 0 || is_directory(direntry
)) ?
2203 MODE_DIRECTORY
: MODE_NORMAL
;
2205 while (!fat_eof(s
, cluster
)) {
2208 for (c
= cluster
, c1
= modified_fat_get(s
, c
); c
+ 1 == c1
;
2209 c
= c1
, c1
= modified_fat_get(s
, c1
));
2212 if (c
> mapping
->end
) {
2213 int index
= array_index(&(s
->mapping
), mapping
);
2214 int i
, max_i
= s
->mapping
.next
- index
;
2215 for (i
= 1; i
< max_i
&& mapping
[i
].begin
< c
; i
++);
2217 remove_mapping(s
, index
+ 1);
2219 assert(mapping
== array_get(&(s
->mapping
), s
->mapping
.next
- 1)
2220 || mapping
[1].begin
>= c
);
2223 if (!fat_eof(s
, c1
)) {
2224 int i
= find_mapping_for_cluster_aux(s
, c1
, 0, s
->mapping
.next
);
2225 mapping_t
* next_mapping
= i
>= s
->mapping
.next
? NULL
:
2226 array_get(&(s
->mapping
), i
);
2228 if (next_mapping
== NULL
|| next_mapping
->begin
> c1
) {
2229 int i1
= array_index(&(s
->mapping
), mapping
);
2231 next_mapping
= insert_mapping(s
, c1
, c1
+1);
2235 mapping
= array_get(&(s
->mapping
), i1
);
2238 next_mapping
->dir_index
= mapping
->dir_index
;
2239 next_mapping
->first_mapping_index
=
2240 mapping
->first_mapping_index
< 0 ?
2241 array_index(&(s
->mapping
), mapping
) :
2242 mapping
->first_mapping_index
;
2243 next_mapping
->path
= mapping
->path
;
2244 next_mapping
->mode
= mapping
->mode
;
2245 next_mapping
->read_only
= mapping
->read_only
;
2246 if (mapping
->mode
& MODE_DIRECTORY
) {
2247 next_mapping
->info
.dir
.parent_mapping_index
=
2248 mapping
->info
.dir
.parent_mapping_index
;
2249 next_mapping
->info
.dir
.first_dir_index
=
2250 mapping
->info
.dir
.first_dir_index
+
2251 0x10 * s
->sectors_per_cluster
*
2252 (mapping
->end
- mapping
->begin
);
2254 next_mapping
->info
.file
.offset
= mapping
->info
.file
.offset
+
2255 mapping
->end
- mapping
->begin
;
2257 mapping
= next_mapping
;
2266 static int commit_direntries(BDRVVVFATState
* s
,
2267 int dir_index
, int parent_mapping_index
)
2269 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2270 uint32_t first_cluster
= dir_index
== 0 ? 0 : begin_of_direntry(direntry
);
2271 mapping_t
* mapping
= find_mapping_for_cluster(s
, first_cluster
);
2273 int factor
= 0x10 * s
->sectors_per_cluster
;
2274 int old_cluster_count
, new_cluster_count
;
2275 int current_dir_index
= mapping
->info
.dir
.first_dir_index
;
2276 int first_dir_index
= current_dir_index
;
2280 DLOG(fprintf(stderr
, "commit_direntries for %s, parent_mapping_index %d\n", mapping
->path
, parent_mapping_index
));
2284 assert(mapping
->begin
== first_cluster
);
2285 assert(mapping
->info
.dir
.first_dir_index
< s
->directory
.next
);
2286 assert(mapping
->mode
& MODE_DIRECTORY
);
2287 assert(dir_index
== 0 || is_directory(direntry
));
2289 mapping
->info
.dir
.parent_mapping_index
= parent_mapping_index
;
2291 if (first_cluster
== 0) {
2292 old_cluster_count
= new_cluster_count
=
2293 s
->last_cluster_of_root_directory
;
2295 for (old_cluster_count
= 0, c
= first_cluster
; !fat_eof(s
, c
);
2297 old_cluster_count
++;
2299 for (new_cluster_count
= 0, c
= first_cluster
; !fat_eof(s
, c
);
2300 c
= modified_fat_get(s
, c
))
2301 new_cluster_count
++;
2304 if (new_cluster_count
> old_cluster_count
) {
2305 if (insert_direntries(s
,
2306 current_dir_index
+ factor
* old_cluster_count
,
2307 factor
* (new_cluster_count
- old_cluster_count
)) == NULL
)
2309 } else if (new_cluster_count
< old_cluster_count
)
2310 remove_direntries(s
,
2311 current_dir_index
+ factor
* new_cluster_count
,
2312 factor
* (old_cluster_count
- new_cluster_count
));
2314 for (c
= first_cluster
; !fat_eof(s
, c
); c
= modified_fat_get(s
, c
)) {
2315 direntry_t
*first_direntry
;
2316 void* direntry
= array_get(&(s
->directory
), current_dir_index
);
2317 int ret
= vvfat_read(s
->bs
, cluster2sector(s
, c
), direntry
,
2318 s
->sectors_per_cluster
);
2322 /* The first directory entry on the filesystem is the volume name */
2323 first_direntry
= (direntry_t
*) s
->directory
.pointer
;
2324 assert(!memcmp(first_direntry
->name
, s
->volume_label
, 11));
2326 current_dir_index
+= factor
;
2329 ret
= commit_mappings(s
, first_cluster
, dir_index
);
2334 for (i
= 0; i
< factor
* new_cluster_count
; i
++) {
2335 direntry
= array_get(&(s
->directory
), first_dir_index
+ i
);
2336 if (is_directory(direntry
) && !is_dot(direntry
)) {
2337 mapping
= find_mapping_for_cluster(s
, first_cluster
);
2338 assert(mapping
->mode
& MODE_DIRECTORY
);
2339 ret
= commit_direntries(s
, first_dir_index
+ i
,
2340 array_index(&(s
->mapping
), mapping
));
2349 /* commit one file (adjust contents, adjust mapping),
2350 return first_mapping_index */
2351 static int commit_one_file(BDRVVVFATState
* s
,
2352 int dir_index
, uint32_t offset
)
2354 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2355 uint32_t c
= begin_of_direntry(direntry
);
2356 uint32_t first_cluster
= c
;
2357 mapping_t
* mapping
= find_mapping_for_cluster(s
, c
);
2358 uint32_t size
= filesize_of_direntry(direntry
);
2359 char* cluster
= g_malloc(s
->cluster_size
);
2363 assert(offset
< size
);
2364 assert((offset
% s
->cluster_size
) == 0);
2366 for (i
= s
->cluster_size
; i
< offset
; i
+= s
->cluster_size
)
2367 c
= modified_fat_get(s
, c
);
2369 fd
= qemu_open(mapping
->path
, O_RDWR
| O_CREAT
| O_BINARY
, 0666);
2371 fprintf(stderr
, "Could not open %s... (%s, %d)\n", mapping
->path
,
2372 strerror(errno
), errno
);
2377 if (lseek(fd
, offset
, SEEK_SET
) != offset
) {
2384 while (offset
< size
) {
2386 int rest_size
= (size
- offset
> s
->cluster_size
?
2387 s
->cluster_size
: size
- offset
);
2390 c1
= modified_fat_get(s
, c
);
2392 assert((size
- offset
== 0 && fat_eof(s
, c
)) ||
2393 (size
> offset
&& c
>=2 && !fat_eof(s
, c
)));
2395 ret
= vvfat_read(s
->bs
, cluster2sector(s
, c
),
2396 (uint8_t*)cluster
, (rest_size
+ 0x1ff) / 0x200);
2404 if (write(fd
, cluster
, rest_size
) < 0) {
2410 offset
+= rest_size
;
2414 if (ftruncate(fd
, size
)) {
2415 perror("ftruncate()");
2423 return commit_mappings(s
, first_cluster
, dir_index
);
2427 /* test, if all mappings point to valid direntries */
2428 static void check1(BDRVVVFATState
* s
)
2431 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2432 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2433 if (mapping
->mode
& MODE_DELETED
) {
2434 fprintf(stderr
, "deleted\n");
2437 assert(mapping
->dir_index
< s
->directory
.next
);
2438 direntry_t
* direntry
= array_get(&(s
->directory
), mapping
->dir_index
);
2439 assert(mapping
->begin
== begin_of_direntry(direntry
) || mapping
->first_mapping_index
>= 0);
2440 if (mapping
->mode
& MODE_DIRECTORY
) {
2441 assert(mapping
->info
.dir
.first_dir_index
+ 0x10 * s
->sectors_per_cluster
* (mapping
->end
- mapping
->begin
) <= s
->directory
.next
);
2442 assert((mapping
->info
.dir
.first_dir_index
% (0x10 * s
->sectors_per_cluster
)) == 0);
2447 /* test, if all direntries have mappings */
2448 static void check2(BDRVVVFATState
* s
)
2451 int first_mapping
= -1;
2453 for (i
= 0; i
< s
->directory
.next
; i
++) {
2454 direntry_t
* direntry
= array_get(&(s
->directory
), i
);
2456 if (is_short_name(direntry
) && begin_of_direntry(direntry
)) {
2457 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin_of_direntry(direntry
));
2459 assert(mapping
->dir_index
== i
|| is_dot(direntry
));
2460 assert(mapping
->begin
== begin_of_direntry(direntry
) || is_dot(direntry
));
2463 if ((i
% (0x10 * s
->sectors_per_cluster
)) == 0) {
2467 for (j
= 0; j
< s
->mapping
.next
; j
++) {
2468 mapping_t
* mapping
= array_get(&(s
->mapping
), j
);
2469 if (mapping
->mode
& MODE_DELETED
)
2471 if (mapping
->mode
& MODE_DIRECTORY
) {
2472 if (mapping
->info
.dir
.first_dir_index
<= i
&& mapping
->info
.dir
.first_dir_index
+ 0x10 * s
->sectors_per_cluster
> i
) {
2473 assert(++count
== 1);
2474 if (mapping
->first_mapping_index
== -1)
2475 first_mapping
= array_index(&(s
->mapping
), mapping
);
2477 assert(first_mapping
== mapping
->first_mapping_index
);
2478 if (mapping
->info
.dir
.parent_mapping_index
< 0)
2481 mapping_t
* parent
= array_get(&(s
->mapping
), mapping
->info
.dir
.parent_mapping_index
);
2482 assert(parent
->mode
& MODE_DIRECTORY
);
2483 assert(parent
->info
.dir
.first_dir_index
< mapping
->info
.dir
.first_dir_index
);
2495 static int handle_renames_and_mkdirs(BDRVVVFATState
* s
)
2500 fprintf(stderr
, "handle_renames\n");
2501 for (i
= 0; i
< s
->commits
.next
; i
++) {
2502 commit_t
* commit
= array_get(&(s
->commits
), i
);
2503 fprintf(stderr
, "%d, %s (%d, %d)\n", i
, commit
->path
? commit
->path
: "(null)", commit
->param
.rename
.cluster
, commit
->action
);
2507 for (i
= 0; i
< s
->commits
.next
;) {
2508 commit_t
* commit
= array_get(&(s
->commits
), i
);
2509 if (commit
->action
== ACTION_RENAME
) {
2510 mapping_t
* mapping
= find_mapping_for_cluster(s
,
2511 commit
->param
.rename
.cluster
);
2512 char* old_path
= mapping
->path
;
2514 assert(commit
->path
);
2515 mapping
->path
= commit
->path
;
2516 if (rename(old_path
, mapping
->path
))
2519 if (mapping
->mode
& MODE_DIRECTORY
) {
2520 int l1
= strlen(mapping
->path
);
2521 int l2
= strlen(old_path
);
2523 direntry_t
* direntry
= array_get(&(s
->directory
),
2524 mapping
->info
.dir
.first_dir_index
);
2525 uint32_t c
= mapping
->begin
;
2529 while (!fat_eof(s
, c
)) {
2531 direntry_t
* d
= direntry
+ i
;
2533 if (is_file(d
) || (is_directory(d
) && !is_dot(d
))) {
2534 mapping_t
* m
= find_mapping_for_cluster(s
,
2535 begin_of_direntry(d
));
2536 int l
= strlen(m
->path
);
2537 char* new_path
= g_malloc(l
+ diff
+ 1);
2539 assert(!strncmp(m
->path
, mapping
->path
, l2
));
2541 pstrcpy(new_path
, l
+ diff
+ 1, mapping
->path
);
2542 pstrcpy(new_path
+ l1
, l
+ diff
+ 1 - l1
,
2545 schedule_rename(s
, m
->begin
, new_path
);
2548 } while((i
% (0x10 * s
->sectors_per_cluster
)) != 0);
2554 array_remove(&(s
->commits
), i
);
2556 } else if (commit
->action
== ACTION_MKDIR
) {
2558 int j
, parent_path_len
;
2561 if (mkdir(commit
->path
))
2564 if (mkdir(commit
->path
, 0755))
2568 mapping
= insert_mapping(s
, commit
->param
.mkdir
.cluster
,
2569 commit
->param
.mkdir
.cluster
+ 1);
2570 if (mapping
== NULL
)
2573 mapping
->mode
= MODE_DIRECTORY
;
2574 mapping
->read_only
= 0;
2575 mapping
->path
= commit
->path
;
2576 j
= s
->directory
.next
;
2578 insert_direntries(s
, s
->directory
.next
,
2579 0x10 * s
->sectors_per_cluster
);
2580 mapping
->info
.dir
.first_dir_index
= j
;
2582 parent_path_len
= strlen(commit
->path
)
2583 - strlen(get_basename(commit
->path
)) - 1;
2584 for (j
= 0; j
< s
->mapping
.next
; j
++) {
2585 mapping_t
* m
= array_get(&(s
->mapping
), j
);
2586 if (m
->first_mapping_index
< 0 && m
!= mapping
&&
2587 !strncmp(m
->path
, mapping
->path
, parent_path_len
) &&
2588 strlen(m
->path
) == parent_path_len
)
2591 assert(j
< s
->mapping
.next
);
2592 mapping
->info
.dir
.parent_mapping_index
= j
;
2594 array_remove(&(s
->commits
), i
);
2604 * TODO: make sure that the short name is not matching *another* file
2606 static int handle_commits(BDRVVVFATState
* s
)
2610 vvfat_close_current_file(s
);
2612 for (i
= 0; !fail
&& i
< s
->commits
.next
; i
++) {
2613 commit_t
* commit
= array_get(&(s
->commits
), i
);
2614 switch(commit
->action
) {
2615 case ACTION_RENAME
: case ACTION_MKDIR
:
2619 case ACTION_WRITEOUT
: {
2621 /* these variables are only used by assert() below */
2622 direntry_t
* entry
= array_get(&(s
->directory
),
2623 commit
->param
.writeout
.dir_index
);
2624 uint32_t begin
= begin_of_direntry(entry
);
2625 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin
);
2629 assert(mapping
->begin
== begin
);
2630 assert(commit
->path
== NULL
);
2632 if (commit_one_file(s
, commit
->param
.writeout
.dir_index
,
2633 commit
->param
.writeout
.modified_offset
))
2638 case ACTION_NEW_FILE
: {
2639 int begin
= commit
->param
.new_file
.first_cluster
;
2640 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin
);
2645 for (i
= 0; i
< s
->directory
.next
; i
++) {
2646 entry
= array_get(&(s
->directory
), i
);
2647 if (is_file(entry
) && begin_of_direntry(entry
) == begin
)
2651 if (i
>= s
->directory
.next
) {
2656 /* make sure there exists an initial mapping */
2657 if (mapping
&& mapping
->begin
!= begin
) {
2658 mapping
->end
= begin
;
2661 if (mapping
== NULL
) {
2662 mapping
= insert_mapping(s
, begin
, begin
+1);
2664 /* most members will be fixed in commit_mappings() */
2665 assert(commit
->path
);
2666 mapping
->path
= commit
->path
;
2667 mapping
->read_only
= 0;
2668 mapping
->mode
= MODE_NORMAL
;
2669 mapping
->info
.file
.offset
= 0;
2671 if (commit_one_file(s
, i
, 0))
2680 if (i
> 0 && array_remove_slice(&(s
->commits
), 0, i
))
2685 static int handle_deletes(BDRVVVFATState
* s
)
2687 int i
, deferred
= 1, deleted
= 1;
2689 /* delete files corresponding to mappings marked as deleted */
2690 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2691 while (deferred
&& deleted
) {
2695 for (i
= 1; i
< s
->mapping
.next
; i
++) {
2696 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2697 if (mapping
->mode
& MODE_DELETED
) {
2698 direntry_t
* entry
= array_get(&(s
->directory
),
2699 mapping
->dir_index
);
2701 if (is_free(entry
)) {
2702 /* remove file/directory */
2703 if (mapping
->mode
& MODE_DIRECTORY
) {
2704 int j
, next_dir_index
= s
->directory
.next
,
2705 first_dir_index
= mapping
->info
.dir
.first_dir_index
;
2707 if (rmdir(mapping
->path
) < 0) {
2708 if (errno
== ENOTEMPTY
) {
2715 for (j
= 1; j
< s
->mapping
.next
; j
++) {
2716 mapping_t
* m
= array_get(&(s
->mapping
), j
);
2717 if (m
->mode
& MODE_DIRECTORY
&&
2718 m
->info
.dir
.first_dir_index
>
2720 m
->info
.dir
.first_dir_index
<
2723 m
->info
.dir
.first_dir_index
;
2725 remove_direntries(s
, first_dir_index
,
2726 next_dir_index
- first_dir_index
);
2731 if (unlink(mapping
->path
))
2735 DLOG(fprintf(stderr
, "DELETE (%d)\n", i
); print_mapping(mapping
); print_direntry(entry
));
2736 remove_mapping(s
, i
);
2745 * synchronize mapping with new state:
2747 * - copy FAT (with bdrv_read)
2748 * - mark all filenames corresponding to mappings as deleted
2749 * - recurse direntries from root (using bs->bdrv_read)
2750 * - delete files corresponding to mappings marked as deleted
2752 static int do_commit(BDRVVVFATState
* s
)
2756 /* the real meat are the commits. Nothing to do? Move along! */
2757 if (s
->commits
.next
== 0)
2760 vvfat_close_current_file(s
);
2762 ret
= handle_renames_and_mkdirs(s
);
2764 fprintf(stderr
, "Error handling renames (%d)\n", ret
);
2769 /* copy FAT (with bdrv_read) */
2770 memcpy(s
->fat
.pointer
, s
->fat2
, 0x200 * s
->sectors_per_fat
);
2772 /* recurse direntries from root (using bs->bdrv_read) */
2773 ret
= commit_direntries(s
, 0, -1);
2775 fprintf(stderr
, "Fatal: error while committing (%d)\n", ret
);
2780 ret
= handle_commits(s
);
2782 fprintf(stderr
, "Error handling commits (%d)\n", ret
);
2787 ret
= handle_deletes(s
);
2789 fprintf(stderr
, "Error deleting\n");
2794 if (s
->qcow
->bs
->drv
->bdrv_make_empty
) {
2795 s
->qcow
->bs
->drv
->bdrv_make_empty(s
->qcow
->bs
);
2798 memset(s
->used_clusters
, 0, sector2cluster(s
, s
->sector_count
));
2804 static int try_commit(BDRVVVFATState
* s
)
2806 vvfat_close_current_file(s
);
2808 if(!is_consistent(s
))
2810 return do_commit(s
);
2813 static int vvfat_write(BlockDriverState
*bs
, int64_t sector_num
,
2814 const uint8_t *buf
, int nb_sectors
)
2816 BDRVVVFATState
*s
= bs
->opaque
;
2821 /* Check if we're operating in read-only mode */
2822 if (s
->qcow
== NULL
) {
2826 vvfat_close_current_file(s
);
2829 * Some sanity checks:
2830 * - do not allow writing to the boot sector
2831 * - do not allow to write non-ASCII filenames
2834 if (sector_num
< s
->first_sectors_number
)
2837 for (i
= sector2cluster(s
, sector_num
);
2838 i
<= sector2cluster(s
, sector_num
+ nb_sectors
- 1);) {
2839 mapping_t
* mapping
= find_mapping_for_cluster(s
, i
);
2841 if (mapping
->read_only
) {
2842 fprintf(stderr
, "Tried to write to write-protected file %s\n",
2847 if (mapping
->mode
& MODE_DIRECTORY
) {
2848 int begin
= cluster2sector(s
, i
);
2849 int end
= begin
+ s
->sectors_per_cluster
, k
;
2851 const direntry_t
* direntries
;
2856 if (begin
< sector_num
)
2858 if (end
> sector_num
+ nb_sectors
)
2859 end
= sector_num
+ nb_sectors
;
2860 dir_index
= mapping
->dir_index
+
2861 0x10 * (begin
- mapping
->begin
* s
->sectors_per_cluster
);
2862 direntries
= (direntry_t
*)(buf
+ 0x200 * (begin
- sector_num
));
2864 for (k
= 0; k
< (end
- begin
) * 0x10; k
++) {
2865 /* do not allow non-ASCII filenames */
2866 if (parse_long_name(&lfn
, direntries
+ k
) < 0) {
2867 fprintf(stderr
, "Warning: non-ASCII filename\n");
2870 /* no access to the direntry of a read-only file */
2871 else if (is_short_name(direntries
+k
) &&
2872 (direntries
[k
].attributes
& 1)) {
2873 if (memcmp(direntries
+ k
,
2874 array_get(&(s
->directory
), dir_index
+ k
),
2875 sizeof(direntry_t
))) {
2876 fprintf(stderr
, "Warning: tried to write to write-protected file\n");
2888 * Use qcow backend. Commit later.
2890 DLOG(fprintf(stderr
, "Write to qcow backend: %d + %d\n", (int)sector_num
, nb_sectors
));
2891 ret
= bdrv_write(s
->qcow
, sector_num
, buf
, nb_sectors
);
2893 fprintf(stderr
, "Error writing to qcow backend\n");
2897 for (i
= sector2cluster(s
, sector_num
);
2898 i
<= sector2cluster(s
, sector_num
+ nb_sectors
- 1); i
++)
2900 s
->used_clusters
[i
] |= USED_ALLOCATED
;
2903 /* TODO: add timeout */
2910 static int coroutine_fn
2911 vvfat_co_pwritev(BlockDriverState
*bs
, uint64_t offset
, uint64_t bytes
,
2912 QEMUIOVector
*qiov
, int flags
)
2915 BDRVVVFATState
*s
= bs
->opaque
;
2916 uint64_t sector_num
= offset
>> BDRV_SECTOR_BITS
;
2917 int nb_sectors
= bytes
>> BDRV_SECTOR_BITS
;
2920 assert((offset
& (BDRV_SECTOR_SIZE
- 1)) == 0);
2921 assert((bytes
& (BDRV_SECTOR_SIZE
- 1)) == 0);
2923 buf
= g_try_malloc(bytes
);
2924 if (bytes
&& buf
== NULL
) {
2927 qemu_iovec_to_buf(qiov
, 0, buf
, bytes
);
2929 qemu_co_mutex_lock(&s
->lock
);
2930 ret
= vvfat_write(bs
, sector_num
, buf
, nb_sectors
);
2931 qemu_co_mutex_unlock(&s
->lock
);
2938 static int64_t coroutine_fn
vvfat_co_get_block_status(BlockDriverState
*bs
,
2939 int64_t sector_num
, int nb_sectors
, int *n
, BlockDriverState
**file
)
2941 BDRVVVFATState
* s
= bs
->opaque
;
2942 *n
= s
->sector_count
- sector_num
;
2943 if (*n
> nb_sectors
) {
2945 } else if (*n
< 0) {
2948 return BDRV_BLOCK_DATA
;
2951 static int coroutine_fn
2952 write_target_commit(BlockDriverState
*bs
, uint64_t offset
, uint64_t bytes
,
2953 QEMUIOVector
*qiov
, int flags
)
2955 BDRVVVFATState
* s
= *((BDRVVVFATState
**) bs
->opaque
);
2956 return try_commit(s
);
2959 static void write_target_close(BlockDriverState
*bs
) {
2960 BDRVVVFATState
* s
= *((BDRVVVFATState
**) bs
->opaque
);
2961 bdrv_unref_child(s
->bs
, s
->qcow
);
2962 g_free(s
->qcow_filename
);
2965 static BlockDriver vvfat_write_target
= {
2966 .format_name
= "vvfat_write_target",
2967 .bdrv_co_pwritev
= write_target_commit
,
2968 .bdrv_close
= write_target_close
,
2971 static void vvfat_qcow_options(int *child_flags
, QDict
*child_options
,
2972 int parent_flags
, QDict
*parent_options
)
2974 *child_flags
= BDRV_O_RDWR
| BDRV_O_NO_FLUSH
;
2977 static const BdrvChildRole child_vvfat_qcow
= {
2978 .inherit_options
= vvfat_qcow_options
,
2981 static int enable_write_target(BlockDriverState
*bs
, Error
**errp
)
2983 BDRVVVFATState
*s
= bs
->opaque
;
2984 BlockDriver
*bdrv_qcow
= NULL
;
2985 BlockDriverState
*backing
;
2986 QemuOpts
*opts
= NULL
;
2988 int size
= sector2cluster(s
, s
->sector_count
);
2991 s
->used_clusters
= calloc(size
, 1);
2993 array_init(&(s
->commits
), sizeof(commit_t
));
2995 s
->qcow_filename
= g_malloc(PATH_MAX
);
2996 ret
= get_tmp_filename(s
->qcow_filename
, PATH_MAX
);
2998 error_setg_errno(errp
, -ret
, "can't create temporary file");
3002 bdrv_qcow
= bdrv_find_format("qcow");
3004 error_setg(errp
, "Failed to locate qcow driver");
3009 opts
= qemu_opts_create(bdrv_qcow
->create_opts
, NULL
, 0, &error_abort
);
3010 qemu_opt_set_number(opts
, BLOCK_OPT_SIZE
, s
->sector_count
* 512,
3012 qemu_opt_set(opts
, BLOCK_OPT_BACKING_FILE
, "fat:", &error_abort
);
3014 ret
= bdrv_create(bdrv_qcow
, s
->qcow_filename
, opts
, errp
);
3015 qemu_opts_del(opts
);
3020 options
= qdict_new();
3021 qdict_put(options
, "driver", qstring_from_str("qcow"));
3022 s
->qcow
= bdrv_open_child(s
->qcow_filename
, options
, "write-target", bs
,
3023 &child_vvfat_qcow
, false, errp
);
3030 unlink(s
->qcow_filename
);
3033 backing
= bdrv_new();
3034 bdrv_set_backing_hd(s
->bs
, backing
);
3035 bdrv_unref(backing
);
3037 s
->bs
->backing
->bs
->drv
= &vvfat_write_target
;
3038 s
->bs
->backing
->bs
->opaque
= g_new(void *, 1);
3039 *(void**)s
->bs
->backing
->bs
->opaque
= s
;
3044 g_free(s
->qcow_filename
);
3045 s
->qcow_filename
= NULL
;
3049 static void vvfat_close(BlockDriverState
*bs
)
3051 BDRVVVFATState
*s
= bs
->opaque
;
3053 vvfat_close_current_file(s
);
3054 array_free(&(s
->fat
));
3055 array_free(&(s
->directory
));
3056 array_free(&(s
->mapping
));
3057 g_free(s
->cluster_buffer
);
3060 migrate_del_blocker(s
->migration_blocker
);
3061 error_free(s
->migration_blocker
);
3065 static BlockDriver bdrv_vvfat
= {
3066 .format_name
= "vvfat",
3067 .protocol_name
= "fat",
3068 .instance_size
= sizeof(BDRVVVFATState
),
3070 .bdrv_parse_filename
= vvfat_parse_filename
,
3071 .bdrv_file_open
= vvfat_open
,
3072 .bdrv_refresh_limits
= vvfat_refresh_limits
,
3073 .bdrv_close
= vvfat_close
,
3075 .bdrv_co_preadv
= vvfat_co_preadv
,
3076 .bdrv_co_pwritev
= vvfat_co_pwritev
,
3077 .bdrv_co_get_block_status
= vvfat_co_get_block_status
,
3080 static void bdrv_vvfat_init(void)
3082 bdrv_register(&bdrv_vvfat
);
3085 block_init(bdrv_vvfat_init
);
3088 static void checkpoint(void) {
3089 assert(((mapping_t
*)array_get(&(vvv
->mapping
), 0))->end
== 2);
3092 assert(!vvv
->current_mapping
|| vvv
->current_fd
|| (vvv
->current_mapping
->mode
& MODE_DIRECTORY
));
3094 if (((direntry_t
*)vvv
->directory
.pointer
)[1].attributes
!= 0xf)
3095 fprintf(stderr
, "Nonono!\n");
3097 direntry_t
* direntry
;
3098 assert(vvv
->mapping
.size
>= vvv
->mapping
.item_size
* vvv
->mapping
.next
);
3099 assert(vvv
->directory
.size
>= vvv
->directory
.item_size
* vvv
->directory
.next
);
3100 if (vvv
->mapping
.next
<47)
3102 assert((mapping
= array_get(&(vvv
->mapping
), 47)));
3103 assert(mapping
->dir_index
< vvv
->directory
.next
);
3104 direntry
= array_get(&(vvv
->directory
), mapping
->dir_index
);
3105 assert(!memcmp(direntry
->name
, "USB H ", 11) || direntry
->name
[0]==0);