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 qemu_co_mutex_init(&s
->lock
);
1194 /* Disable migration when vvfat is used rw */
1196 error_setg(&s
->migration_blocker
,
1197 "The vvfat (rw) format used by node '%s' "
1198 "does not support live migration",
1199 bdrv_get_device_or_node_name(bs
));
1200 migrate_add_blocker(s
->migration_blocker
);
1205 qemu_opts_del(opts
);
1209 static void vvfat_refresh_limits(BlockDriverState
*bs
, Error
**errp
)
1211 bs
->bl
.request_alignment
= BDRV_SECTOR_SIZE
; /* No sub-sector I/O */
1214 static inline void vvfat_close_current_file(BDRVVVFATState
*s
)
1216 if(s
->current_mapping
) {
1217 s
->current_mapping
= NULL
;
1218 if (s
->current_fd
) {
1219 qemu_close(s
->current_fd
);
1223 s
->current_cluster
= -1;
1226 /* mappings between index1 and index2-1 are supposed to be ordered
1227 * return value is the index of the last mapping for which end>cluster_num
1229 static inline int find_mapping_for_cluster_aux(BDRVVVFATState
* s
,int cluster_num
,int index1
,int index2
)
1234 index3
=(index1
+index2
)/2;
1235 mapping
=array_get(&(s
->mapping
),index3
);
1236 assert(mapping
->begin
< mapping
->end
);
1237 if(mapping
->begin
>=cluster_num
) {
1238 assert(index2
!=index3
|| index2
==0);
1244 return mapping
->end
<=cluster_num
? index2
: index1
;
1247 assert(index1
<=index2
);
1248 DLOG(mapping
=array_get(&(s
->mapping
),index1
);
1249 assert(mapping
->begin
<=cluster_num
);
1250 assert(index2
>= s
->mapping
.next
||
1251 ((mapping
= array_get(&(s
->mapping
),index2
)) &&
1252 mapping
->end
>cluster_num
)));
1256 static inline mapping_t
* find_mapping_for_cluster(BDRVVVFATState
* s
,int cluster_num
)
1258 int index
=find_mapping_for_cluster_aux(s
,cluster_num
,0,s
->mapping
.next
);
1260 if(index
>=s
->mapping
.next
)
1262 mapping
=array_get(&(s
->mapping
),index
);
1263 if(mapping
->begin
>cluster_num
)
1265 assert(mapping
->begin
<=cluster_num
&& mapping
->end
>cluster_num
);
1269 static int open_file(BDRVVVFATState
* s
,mapping_t
* mapping
)
1273 if(!s
->current_mapping
||
1274 strcmp(s
->current_mapping
->path
,mapping
->path
)) {
1276 int fd
= qemu_open(mapping
->path
, O_RDONLY
| O_BINARY
| O_LARGEFILE
);
1279 vvfat_close_current_file(s
);
1281 s
->current_mapping
= mapping
;
1286 static inline int read_cluster(BDRVVVFATState
*s
,int cluster_num
)
1288 if(s
->current_cluster
!= cluster_num
) {
1291 assert(!s
->current_mapping
|| s
->current_fd
|| (s
->current_mapping
->mode
& MODE_DIRECTORY
));
1292 if(!s
->current_mapping
1293 || s
->current_mapping
->begin
>cluster_num
1294 || s
->current_mapping
->end
<=cluster_num
) {
1295 /* binary search of mappings for file */
1296 mapping_t
* mapping
=find_mapping_for_cluster(s
,cluster_num
);
1298 assert(!mapping
|| (cluster_num
>=mapping
->begin
&& cluster_num
<mapping
->end
));
1300 if (mapping
&& mapping
->mode
& MODE_DIRECTORY
) {
1301 vvfat_close_current_file(s
);
1302 s
->current_mapping
= mapping
;
1303 read_cluster_directory
:
1304 offset
= s
->cluster_size
*(cluster_num
-s
->current_mapping
->begin
);
1305 s
->cluster
= (unsigned char*)s
->directory
.pointer
+offset
1306 + 0x20*s
->current_mapping
->info
.dir
.first_dir_index
;
1307 assert(((s
->cluster
-(unsigned char*)s
->directory
.pointer
)%s
->cluster_size
)==0);
1308 assert((char*)s
->cluster
+s
->cluster_size
<= s
->directory
.pointer
+s
->directory
.next
*s
->directory
.item_size
);
1309 s
->current_cluster
= cluster_num
;
1313 if(open_file(s
,mapping
))
1315 } else if (s
->current_mapping
->mode
& MODE_DIRECTORY
)
1316 goto read_cluster_directory
;
1318 assert(s
->current_fd
);
1320 offset
=s
->cluster_size
*(cluster_num
-s
->current_mapping
->begin
)+s
->current_mapping
->info
.file
.offset
;
1321 if(lseek(s
->current_fd
, offset
, SEEK_SET
)!=offset
)
1323 s
->cluster
=s
->cluster_buffer
;
1324 result
=read(s
->current_fd
,s
->cluster
,s
->cluster_size
);
1326 s
->current_cluster
= -1;
1329 s
->current_cluster
= cluster_num
;
1335 static void print_direntry(const direntry_t
* direntry
)
1340 fprintf(stderr
, "direntry %p: ", direntry
);
1343 if(is_long_name(direntry
)) {
1344 unsigned char* c
=(unsigned char*)direntry
;
1346 for(i
=1;i
<11 && c
[i
] && c
[i
]!=0xff;i
+=2)
1347 #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
1349 for(i
=14;i
<26 && c
[i
] && c
[i
]!=0xff;i
+=2)
1351 for(i
=28;i
<32 && c
[i
] && c
[i
]!=0xff;i
+=2)
1354 fprintf(stderr
, "%s\n", buffer
);
1358 ADD_CHAR(direntry
->name
[i
]);
1360 fprintf(stderr
,"%s attributes=0x%02x begin=%d size=%d\n",
1362 direntry
->attributes
,
1363 begin_of_direntry(direntry
),le32_to_cpu(direntry
->size
));
1367 static void print_mapping(const mapping_t
* mapping
)
1369 fprintf(stderr
, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1370 "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1371 mapping
, mapping
->begin
, mapping
->end
, mapping
->dir_index
,
1372 mapping
->first_mapping_index
, mapping
->path
, mapping
->mode
);
1374 if (mapping
->mode
& MODE_DIRECTORY
)
1375 fprintf(stderr
, "parent_mapping_index = %d, first_dir_index = %d\n", mapping
->info
.dir
.parent_mapping_index
, mapping
->info
.dir
.first_dir_index
);
1377 fprintf(stderr
, "offset = %d\n", mapping
->info
.file
.offset
);
1381 static int vvfat_read(BlockDriverState
*bs
, int64_t sector_num
,
1382 uint8_t *buf
, int nb_sectors
)
1384 BDRVVVFATState
*s
= bs
->opaque
;
1387 for(i
=0;i
<nb_sectors
;i
++,sector_num
++) {
1388 if (sector_num
>= bs
->total_sectors
)
1392 if (bdrv_is_allocated(s
->qcow
->bs
, sector_num
, nb_sectors
-i
, &n
)) {
1393 DLOG(fprintf(stderr
, "sectors %d+%d allocated\n",
1394 (int)sector_num
, n
));
1395 if (bdrv_read(s
->qcow
, sector_num
, buf
+ i
* 0x200, n
)) {
1399 sector_num
+= n
- 1;
1402 DLOG(fprintf(stderr
, "sector %d not allocated\n", (int)sector_num
));
1404 if(sector_num
<s
->faked_sectors
) {
1405 if(sector_num
<s
->first_sectors_number
)
1406 memcpy(buf
+i
*0x200,&(s
->first_sectors
[sector_num
*0x200]),0x200);
1407 else if(sector_num
-s
->first_sectors_number
<s
->sectors_per_fat
)
1408 memcpy(buf
+i
*0x200,&(s
->fat
.pointer
[(sector_num
-s
->first_sectors_number
)*0x200]),0x200);
1409 else if(sector_num
-s
->first_sectors_number
-s
->sectors_per_fat
<s
->sectors_per_fat
)
1410 memcpy(buf
+i
*0x200,&(s
->fat
.pointer
[(sector_num
-s
->first_sectors_number
-s
->sectors_per_fat
)*0x200]),0x200);
1412 uint32_t sector
=sector_num
-s
->faked_sectors
,
1413 sector_offset_in_cluster
=(sector
%s
->sectors_per_cluster
),
1414 cluster_num
=sector
/s
->sectors_per_cluster
;
1415 if(cluster_num
> s
->cluster_count
|| read_cluster(s
, cluster_num
) != 0) {
1416 /* LATER TODO: strict: return -1; */
1417 memset(buf
+i
*0x200,0,0x200);
1420 memcpy(buf
+i
*0x200,s
->cluster
+sector_offset_in_cluster
*0x200,0x200);
1426 static int coroutine_fn
1427 vvfat_co_preadv(BlockDriverState
*bs
, uint64_t offset
, uint64_t bytes
,
1428 QEMUIOVector
*qiov
, int flags
)
1431 BDRVVVFATState
*s
= bs
->opaque
;
1432 uint64_t sector_num
= offset
>> BDRV_SECTOR_BITS
;
1433 int nb_sectors
= bytes
>> BDRV_SECTOR_BITS
;
1436 assert((offset
& (BDRV_SECTOR_SIZE
- 1)) == 0);
1437 assert((bytes
& (BDRV_SECTOR_SIZE
- 1)) == 0);
1439 buf
= g_try_malloc(bytes
);
1440 if (bytes
&& buf
== NULL
) {
1444 qemu_co_mutex_lock(&s
->lock
);
1445 ret
= vvfat_read(bs
, sector_num
, buf
, nb_sectors
);
1446 qemu_co_mutex_unlock(&s
->lock
);
1448 qemu_iovec_from_buf(qiov
, 0, buf
, bytes
);
1454 /* LATER TODO: statify all functions */
1457 * Idea of the write support (use snapshot):
1459 * 1. check if all data is consistent, recording renames, modifications,
1460 * new files and directories (in s->commits).
1462 * 2. if the data is not consistent, stop committing
1464 * 3. handle renames, and create new files and directories (do not yet
1465 * write their contents)
1467 * 4. walk the directories, fixing the mapping and direntries, and marking
1468 * the handled mappings as not deleted
1470 * 5. commit the contents of the files
1472 * 6. handle deleted files and directories
1476 typedef struct commit_t
{
1479 struct { uint32_t cluster
; } rename
;
1480 struct { int dir_index
; uint32_t modified_offset
; } writeout
;
1481 struct { uint32_t first_cluster
; } new_file
;
1482 struct { uint32_t cluster
; } mkdir
;
1484 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1486 ACTION_RENAME
, ACTION_WRITEOUT
, ACTION_NEW_FILE
, ACTION_MKDIR
1490 static void clear_commits(BDRVVVFATState
* s
)
1493 DLOG(fprintf(stderr
, "clear_commits (%d commits)\n", s
->commits
.next
));
1494 for (i
= 0; i
< s
->commits
.next
; i
++) {
1495 commit_t
* commit
= array_get(&(s
->commits
), i
);
1496 assert(commit
->path
|| commit
->action
== ACTION_WRITEOUT
);
1497 if (commit
->action
!= ACTION_WRITEOUT
) {
1498 assert(commit
->path
);
1499 g_free(commit
->path
);
1501 assert(commit
->path
== NULL
);
1503 s
->commits
.next
= 0;
1506 static void schedule_rename(BDRVVVFATState
* s
,
1507 uint32_t cluster
, char* new_path
)
1509 commit_t
* commit
= array_get_next(&(s
->commits
));
1510 commit
->path
= new_path
;
1511 commit
->param
.rename
.cluster
= cluster
;
1512 commit
->action
= ACTION_RENAME
;
1515 static void schedule_writeout(BDRVVVFATState
* s
,
1516 int dir_index
, uint32_t modified_offset
)
1518 commit_t
* commit
= array_get_next(&(s
->commits
));
1519 commit
->path
= NULL
;
1520 commit
->param
.writeout
.dir_index
= dir_index
;
1521 commit
->param
.writeout
.modified_offset
= modified_offset
;
1522 commit
->action
= ACTION_WRITEOUT
;
1525 static void schedule_new_file(BDRVVVFATState
* s
,
1526 char* path
, uint32_t first_cluster
)
1528 commit_t
* commit
= array_get_next(&(s
->commits
));
1529 commit
->path
= path
;
1530 commit
->param
.new_file
.first_cluster
= first_cluster
;
1531 commit
->action
= ACTION_NEW_FILE
;
1534 static void schedule_mkdir(BDRVVVFATState
* s
, uint32_t cluster
, char* path
)
1536 commit_t
* commit
= array_get_next(&(s
->commits
));
1537 commit
->path
= path
;
1538 commit
->param
.mkdir
.cluster
= cluster
;
1539 commit
->action
= ACTION_MKDIR
;
1544 * Since the sequence number is at most 0x3f, and the filename
1545 * length is at most 13 times the sequence number, the maximal
1546 * filename length is 0x3f * 13 bytes.
1548 unsigned char name
[0x3f * 13 + 1];
1550 int sequence_number
;
1553 static void lfn_init(long_file_name
* lfn
)
1555 lfn
->sequence_number
= lfn
->len
= 0;
1556 lfn
->checksum
= 0x100;
1559 /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1560 static int parse_long_name(long_file_name
* lfn
,
1561 const direntry_t
* direntry
)
1564 const unsigned char* pointer
= (const unsigned char*)direntry
;
1566 if (!is_long_name(direntry
))
1569 if (pointer
[0] & 0x40) {
1570 lfn
->sequence_number
= pointer
[0] & 0x3f;
1571 lfn
->checksum
= pointer
[13];
1573 lfn
->name
[lfn
->sequence_number
* 13] = 0;
1574 } else if ((pointer
[0] & 0x3f) != --lfn
->sequence_number
)
1576 else if (pointer
[13] != lfn
->checksum
)
1578 else if (pointer
[12] || pointer
[26] || pointer
[27])
1581 offset
= 13 * (lfn
->sequence_number
- 1);
1582 for (i
= 0, j
= 1; i
< 13; i
++, j
+=2) {
1588 if (pointer
[j
+1] == 0)
1589 lfn
->name
[offset
+ i
] = pointer
[j
];
1590 else if (pointer
[j
+1] != 0xff || (pointer
[0] & 0x40) == 0)
1593 lfn
->name
[offset
+ i
] = 0;
1596 if (pointer
[0] & 0x40)
1597 lfn
->len
= offset
+ strlen((char*)lfn
->name
+ offset
);
1602 /* returns 0 if successful, >0 if no short_name, and <0 on error */
1603 static int parse_short_name(BDRVVVFATState
* s
,
1604 long_file_name
* lfn
, direntry_t
* direntry
)
1608 if (!is_short_name(direntry
))
1611 for (j
= 7; j
>= 0 && direntry
->name
[j
] == ' '; j
--);
1612 for (i
= 0; i
<= j
; i
++) {
1613 if (direntry
->name
[i
] <= ' ' || direntry
->name
[i
] > 0x7f)
1615 else if (s
->downcase_short_names
)
1616 lfn
->name
[i
] = qemu_tolower(direntry
->name
[i
]);
1618 lfn
->name
[i
] = direntry
->name
[i
];
1621 for (j
= 2; j
>= 0 && direntry
->name
[8 + j
] == ' '; j
--) {
1624 lfn
->name
[i
++] = '.';
1625 lfn
->name
[i
+ j
+ 1] = '\0';
1626 for (;j
>= 0; j
--) {
1627 uint8_t c
= direntry
->name
[8 + j
];
1628 if (c
<= ' ' || c
> 0x7f) {
1630 } else if (s
->downcase_short_names
) {
1631 lfn
->name
[i
+ j
] = qemu_tolower(c
);
1633 lfn
->name
[i
+ j
] = c
;
1637 lfn
->name
[i
+ j
+ 1] = '\0';
1639 lfn
->len
= strlen((char*)lfn
->name
);
1644 static inline uint32_t modified_fat_get(BDRVVVFATState
* s
,
1645 unsigned int cluster
)
1647 if (cluster
< s
->last_cluster_of_root_directory
) {
1648 if (cluster
+ 1 == s
->last_cluster_of_root_directory
)
1649 return s
->max_fat_value
;
1654 if (s
->fat_type
==32) {
1655 uint32_t* entry
=((uint32_t*)s
->fat2
)+cluster
;
1656 return le32_to_cpu(*entry
);
1657 } else if (s
->fat_type
==16) {
1658 uint16_t* entry
=((uint16_t*)s
->fat2
)+cluster
;
1659 return le16_to_cpu(*entry
);
1661 const uint8_t* x
=s
->fat2
+cluster
*3/2;
1662 return ((x
[0]|(x
[1]<<8))>>(cluster
&1?4:0))&0x0fff;
1666 static inline int cluster_was_modified(BDRVVVFATState
* s
, uint32_t cluster_num
)
1668 int was_modified
= 0;
1671 if (s
->qcow
== NULL
) {
1675 for (i
= 0; !was_modified
&& i
< s
->sectors_per_cluster
; i
++) {
1676 was_modified
= bdrv_is_allocated(s
->qcow
->bs
,
1677 cluster2sector(s
, cluster_num
) + i
,
1681 return was_modified
;
1684 static const char* get_basename(const char* path
)
1686 char* basename
= strrchr(path
, '/');
1687 if (basename
== NULL
)
1690 return basename
+ 1; /* strip '/' */
1694 * The array s->used_clusters holds the states of the clusters. If it is
1695 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1696 * was modified, bit 3 is set.
1697 * If any cluster is allocated, but not part of a file or directory, this
1698 * driver refuses to commit.
1701 USED_DIRECTORY
= 1, USED_FILE
= 2, USED_ANY
= 3, USED_ALLOCATED
= 4
1705 * get_cluster_count_for_direntry() not only determines how many clusters
1706 * are occupied by direntry, but also if it was renamed or modified.
1708 * A file is thought to be renamed *only* if there already was a file with
1709 * exactly the same first cluster, but a different name.
1711 * Further, the files/directories handled by this function are
1712 * assumed to be *not* deleted (and *only* those).
1714 static uint32_t get_cluster_count_for_direntry(BDRVVVFATState
* s
,
1715 direntry_t
* direntry
, const char* path
)
1718 * This is a little bit tricky:
1719 * IF the guest OS just inserts a cluster into the file chain,
1720 * and leaves the rest alone, (i.e. the original file had clusters
1721 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1723 * - do_commit will write the cluster into the file at the given
1726 * - the cluster which is overwritten should be moved to a later
1727 * position in the file.
1729 * I am not aware that any OS does something as braindead, but this
1730 * situation could happen anyway when not committing for a long time.
1731 * Just to be sure that this does not bite us, detect it, and copy the
1732 * contents of the clusters to-be-overwritten into the qcow.
1735 int was_modified
= 0;
1738 uint32_t cluster_num
= begin_of_direntry(direntry
);
1739 uint32_t offset
= 0;
1740 int first_mapping_index
= -1;
1741 mapping_t
* mapping
= NULL
;
1742 const char* basename2
= NULL
;
1744 vvfat_close_current_file(s
);
1746 /* the root directory */
1747 if (cluster_num
== 0)
1752 basename2
= get_basename(path
);
1754 mapping
= find_mapping_for_cluster(s
, cluster_num
);
1757 const char* basename
;
1759 assert(mapping
->mode
& MODE_DELETED
);
1760 mapping
->mode
&= ~MODE_DELETED
;
1762 basename
= get_basename(mapping
->path
);
1764 assert(mapping
->mode
& MODE_NORMAL
);
1767 if (strcmp(basename
, basename2
))
1768 schedule_rename(s
, cluster_num
, g_strdup(path
));
1769 } else if (is_file(direntry
))
1771 schedule_new_file(s
, g_strdup(path
), cluster_num
);
1780 if (!copy_it
&& cluster_was_modified(s
, cluster_num
)) {
1781 if (mapping
== NULL
||
1782 mapping
->begin
> cluster_num
||
1783 mapping
->end
<= cluster_num
)
1784 mapping
= find_mapping_for_cluster(s
, cluster_num
);
1788 (mapping
->mode
& MODE_DIRECTORY
) == 0) {
1790 /* was modified in qcow */
1791 if (offset
!= mapping
->info
.file
.offset
+ s
->cluster_size
1792 * (cluster_num
- mapping
->begin
)) {
1793 /* offset of this cluster in file chain has changed */
1796 } else if (offset
== 0) {
1797 const char* basename
= get_basename(mapping
->path
);
1799 if (strcmp(basename
, basename2
))
1801 first_mapping_index
= array_index(&(s
->mapping
), mapping
);
1804 if (mapping
->first_mapping_index
!= first_mapping_index
1805 && mapping
->info
.file
.offset
> 0) {
1810 /* need to write out? */
1811 if (!was_modified
&& is_file(direntry
)) {
1813 schedule_writeout(s
, mapping
->dir_index
, offset
);
1821 * This is horribly inefficient, but that is okay, since
1822 * it is rarely executed, if at all.
1824 int64_t offset
= cluster2sector(s
, cluster_num
);
1826 vvfat_close_current_file(s
);
1827 for (i
= 0; i
< s
->sectors_per_cluster
; i
++) {
1830 res
= bdrv_is_allocated(s
->qcow
->bs
, offset
+ i
, 1, &dummy
);
1832 res
= vvfat_read(s
->bs
, offset
, s
->cluster_buffer
, 1);
1836 res
= bdrv_write(s
->qcow
, offset
, s
->cluster_buffer
, 1);
1846 if (s
->used_clusters
[cluster_num
] & USED_ANY
)
1848 s
->used_clusters
[cluster_num
] = USED_FILE
;
1850 cluster_num
= modified_fat_get(s
, cluster_num
);
1852 if (fat_eof(s
, cluster_num
))
1854 else if (cluster_num
< 2 || cluster_num
> s
->max_fat_value
- 16)
1857 offset
+= s
->cluster_size
;
1862 * This function looks at the modified data (qcow).
1863 * It returns 0 upon inconsistency or error, and the number of clusters
1864 * used by the directory, its subdirectories and their files.
1866 static int check_directory_consistency(BDRVVVFATState
*s
,
1867 int cluster_num
, const char* path
)
1870 unsigned char* cluster
= g_malloc(s
->cluster_size
);
1871 direntry_t
* direntries
= (direntry_t
*)cluster
;
1872 mapping_t
* mapping
= find_mapping_for_cluster(s
, cluster_num
);
1875 int path_len
= strlen(path
);
1876 char path2
[PATH_MAX
+ 1];
1878 assert(path_len
< PATH_MAX
); /* len was tested before! */
1879 pstrcpy(path2
, sizeof(path2
), path
);
1880 path2
[path_len
] = '/';
1881 path2
[path_len
+ 1] = '\0';
1884 const char* basename
= get_basename(mapping
->path
);
1885 const char* basename2
= get_basename(path
);
1887 assert(mapping
->mode
& MODE_DIRECTORY
);
1889 assert(mapping
->mode
& MODE_DELETED
);
1890 mapping
->mode
&= ~MODE_DELETED
;
1892 if (strcmp(basename
, basename2
))
1893 schedule_rename(s
, cluster_num
, g_strdup(path
));
1896 schedule_mkdir(s
, cluster_num
, g_strdup(path
));
1905 if (s
->used_clusters
[cluster_num
] & USED_ANY
) {
1906 fprintf(stderr
, "cluster %d used more than once\n", (int)cluster_num
);
1909 s
->used_clusters
[cluster_num
] = USED_DIRECTORY
;
1911 DLOG(fprintf(stderr
, "read cluster %d (sector %d)\n", (int)cluster_num
, (int)cluster2sector(s
, cluster_num
)));
1912 subret
= vvfat_read(s
->bs
, cluster2sector(s
, cluster_num
), cluster
,
1913 s
->sectors_per_cluster
);
1915 fprintf(stderr
, "Error fetching direntries\n");
1921 for (i
= 0; i
< 0x10 * s
->sectors_per_cluster
; i
++) {
1922 int cluster_count
= 0;
1924 DLOG(fprintf(stderr
, "check direntry %d:\n", i
); print_direntry(direntries
+ i
));
1925 if (is_volume_label(direntries
+ i
) || is_dot(direntries
+ i
) ||
1926 is_free(direntries
+ i
))
1929 subret
= parse_long_name(&lfn
, direntries
+ i
);
1931 fprintf(stderr
, "Error in long name\n");
1934 if (subret
== 0 || is_free(direntries
+ i
))
1937 if (fat_chksum(direntries
+i
) != lfn
.checksum
) {
1938 subret
= parse_short_name(s
, &lfn
, direntries
+ i
);
1940 fprintf(stderr
, "Error in short name (%d)\n", subret
);
1943 if (subret
> 0 || !strcmp((char*)lfn
.name
, ".")
1944 || !strcmp((char*)lfn
.name
, ".."))
1947 lfn
.checksum
= 0x100; /* cannot use long name twice */
1949 if (path_len
+ 1 + lfn
.len
>= PATH_MAX
) {
1950 fprintf(stderr
, "Name too long: %s/%s\n", path
, lfn
.name
);
1953 pstrcpy(path2
+ path_len
+ 1, sizeof(path2
) - path_len
- 1,
1956 if (is_directory(direntries
+ i
)) {
1957 if (begin_of_direntry(direntries
+ i
) == 0) {
1958 DLOG(fprintf(stderr
, "invalid begin for directory: %s\n", path2
); print_direntry(direntries
+ i
));
1961 cluster_count
= check_directory_consistency(s
,
1962 begin_of_direntry(direntries
+ i
), path2
);
1963 if (cluster_count
== 0) {
1964 DLOG(fprintf(stderr
, "problem in directory %s:\n", path2
); print_direntry(direntries
+ i
));
1967 } else if (is_file(direntries
+ i
)) {
1968 /* check file size with FAT */
1969 cluster_count
= get_cluster_count_for_direntry(s
, direntries
+ i
, path2
);
1970 if (cluster_count
!=
1971 DIV_ROUND_UP(le32_to_cpu(direntries
[i
].size
), s
->cluster_size
)) {
1972 DLOG(fprintf(stderr
, "Cluster count mismatch\n"));
1976 abort(); /* cluster_count = 0; */
1978 ret
+= cluster_count
;
1981 cluster_num
= modified_fat_get(s
, cluster_num
);
1982 } while(!fat_eof(s
, cluster_num
));
1988 /* returns 1 on success */
1989 static int is_consistent(BDRVVVFATState
* s
)
1992 int used_clusters_count
= 0;
1996 * - get modified FAT
1997 * - compare the two FATs (TODO)
1998 * - get buffer for marking used clusters
1999 * - recurse direntries from root (using bs->bdrv_read to make
2000 * sure to get the new data)
2001 * - check that the FAT agrees with the size
2002 * - count the number of clusters occupied by this directory and
2004 * - check that the cumulative used cluster count agrees with the
2006 * - if all is fine, return number of used clusters
2008 if (s
->fat2
== NULL
) {
2009 int size
= 0x200 * s
->sectors_per_fat
;
2010 s
->fat2
= g_malloc(size
);
2011 memcpy(s
->fat2
, s
->fat
.pointer
, size
);
2013 check
= vvfat_read(s
->bs
,
2014 s
->first_sectors_number
, s
->fat2
, s
->sectors_per_fat
);
2016 fprintf(stderr
, "Could not copy fat\n");
2019 assert (s
->used_clusters
);
2020 for (i
= 0; i
< sector2cluster(s
, s
->sector_count
); i
++)
2021 s
->used_clusters
[i
] &= ~USED_ANY
;
2025 /* mark every mapped file/directory as deleted.
2026 * (check_directory_consistency() will unmark those still present). */
2028 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2029 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2030 if (mapping
->first_mapping_index
< 0)
2031 mapping
->mode
|= MODE_DELETED
;
2034 used_clusters_count
= check_directory_consistency(s
, 0, s
->path
);
2035 if (used_clusters_count
<= 0) {
2036 DLOG(fprintf(stderr
, "problem in directory\n"));
2040 check
= s
->last_cluster_of_root_directory
;
2041 for (i
= check
; i
< sector2cluster(s
, s
->sector_count
); i
++) {
2042 if (modified_fat_get(s
, i
)) {
2043 if(!s
->used_clusters
[i
]) {
2044 DLOG(fprintf(stderr
, "FAT was modified (%d), but cluster is not used?\n", i
));
2050 if (s
->used_clusters
[i
] == USED_ALLOCATED
) {
2051 /* allocated, but not used... */
2052 DLOG(fprintf(stderr
, "unused, modified cluster: %d\n", i
));
2057 if (check
!= used_clusters_count
)
2060 return used_clusters_count
;
2063 static inline void adjust_mapping_indices(BDRVVVFATState
* s
,
2064 int offset
, int adjust
)
2068 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2069 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2071 #define ADJUST_MAPPING_INDEX(name) \
2072 if (mapping->name >= offset) \
2073 mapping->name += adjust
2075 ADJUST_MAPPING_INDEX(first_mapping_index
);
2076 if (mapping
->mode
& MODE_DIRECTORY
)
2077 ADJUST_MAPPING_INDEX(info
.dir
.parent_mapping_index
);
2081 /* insert or update mapping */
2082 static mapping_t
* insert_mapping(BDRVVVFATState
* s
,
2083 uint32_t begin
, uint32_t end
)
2086 * - find mapping where mapping->begin >= begin,
2087 * - if mapping->begin > begin: insert
2088 * - adjust all references to mappings!
2092 int index
= find_mapping_for_cluster_aux(s
, begin
, 0, s
->mapping
.next
);
2093 mapping_t
* mapping
= NULL
;
2094 mapping_t
* first_mapping
= array_get(&(s
->mapping
), 0);
2096 if (index
< s
->mapping
.next
&& (mapping
= array_get(&(s
->mapping
), index
))
2097 && mapping
->begin
< begin
) {
2098 mapping
->end
= begin
;
2100 mapping
= array_get(&(s
->mapping
), index
);
2102 if (index
>= s
->mapping
.next
|| mapping
->begin
> begin
) {
2103 mapping
= array_insert(&(s
->mapping
), index
, 1);
2104 mapping
->path
= NULL
;
2105 adjust_mapping_indices(s
, index
, +1);
2108 mapping
->begin
= begin
;
2111 DLOG(mapping_t
* next_mapping
;
2112 assert(index
+ 1 >= s
->mapping
.next
||
2113 ((next_mapping
= array_get(&(s
->mapping
), index
+ 1)) &&
2114 next_mapping
->begin
>= end
)));
2116 if (s
->current_mapping
&& first_mapping
!= (mapping_t
*)s
->mapping
.pointer
)
2117 s
->current_mapping
= array_get(&(s
->mapping
),
2118 s
->current_mapping
- first_mapping
);
2123 static int remove_mapping(BDRVVVFATState
* s
, int mapping_index
)
2125 mapping_t
* mapping
= array_get(&(s
->mapping
), mapping_index
);
2126 mapping_t
* first_mapping
= array_get(&(s
->mapping
), 0);
2129 if (mapping
->first_mapping_index
< 0) {
2130 g_free(mapping
->path
);
2133 /* remove from s->mapping */
2134 array_remove(&(s
->mapping
), mapping_index
);
2136 /* adjust all references to mappings */
2137 adjust_mapping_indices(s
, mapping_index
, -1);
2139 if (s
->current_mapping
&& first_mapping
!= (mapping_t
*)s
->mapping
.pointer
)
2140 s
->current_mapping
= array_get(&(s
->mapping
),
2141 s
->current_mapping
- first_mapping
);
2146 static void adjust_dirindices(BDRVVVFATState
* s
, int offset
, int adjust
)
2149 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2150 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2151 if (mapping
->dir_index
>= offset
)
2152 mapping
->dir_index
+= adjust
;
2153 if ((mapping
->mode
& MODE_DIRECTORY
) &&
2154 mapping
->info
.dir
.first_dir_index
>= offset
)
2155 mapping
->info
.dir
.first_dir_index
+= adjust
;
2159 static direntry_t
* insert_direntries(BDRVVVFATState
* s
,
2160 int dir_index
, int count
)
2163 * make room in s->directory,
2166 direntry_t
* result
= array_insert(&(s
->directory
), dir_index
, count
);
2169 adjust_dirindices(s
, dir_index
, count
);
2173 static int remove_direntries(BDRVVVFATState
* s
, int dir_index
, int count
)
2175 int ret
= array_remove_slice(&(s
->directory
), dir_index
, count
);
2178 adjust_dirindices(s
, dir_index
, -count
);
2183 * Adapt the mappings of the cluster chain starting at first cluster
2184 * (i.e. if a file starts at first_cluster, the chain is followed according
2185 * to the modified fat, and the corresponding entries in s->mapping are
2188 static int commit_mappings(BDRVVVFATState
* s
,
2189 uint32_t first_cluster
, int dir_index
)
2191 mapping_t
* mapping
= find_mapping_for_cluster(s
, first_cluster
);
2192 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2193 uint32_t cluster
= first_cluster
;
2195 vvfat_close_current_file(s
);
2198 assert(mapping
->begin
== first_cluster
);
2199 mapping
->first_mapping_index
= -1;
2200 mapping
->dir_index
= dir_index
;
2201 mapping
->mode
= (dir_index
<= 0 || is_directory(direntry
)) ?
2202 MODE_DIRECTORY
: MODE_NORMAL
;
2204 while (!fat_eof(s
, cluster
)) {
2207 for (c
= cluster
, c1
= modified_fat_get(s
, c
); c
+ 1 == c1
;
2208 c
= c1
, c1
= modified_fat_get(s
, c1
));
2211 if (c
> mapping
->end
) {
2212 int index
= array_index(&(s
->mapping
), mapping
);
2213 int i
, max_i
= s
->mapping
.next
- index
;
2214 for (i
= 1; i
< max_i
&& mapping
[i
].begin
< c
; i
++);
2216 remove_mapping(s
, index
+ 1);
2218 assert(mapping
== array_get(&(s
->mapping
), s
->mapping
.next
- 1)
2219 || mapping
[1].begin
>= c
);
2222 if (!fat_eof(s
, c1
)) {
2223 int i
= find_mapping_for_cluster_aux(s
, c1
, 0, s
->mapping
.next
);
2224 mapping_t
* next_mapping
= i
>= s
->mapping
.next
? NULL
:
2225 array_get(&(s
->mapping
), i
);
2227 if (next_mapping
== NULL
|| next_mapping
->begin
> c1
) {
2228 int i1
= array_index(&(s
->mapping
), mapping
);
2230 next_mapping
= insert_mapping(s
, c1
, c1
+1);
2234 mapping
= array_get(&(s
->mapping
), i1
);
2237 next_mapping
->dir_index
= mapping
->dir_index
;
2238 next_mapping
->first_mapping_index
=
2239 mapping
->first_mapping_index
< 0 ?
2240 array_index(&(s
->mapping
), mapping
) :
2241 mapping
->first_mapping_index
;
2242 next_mapping
->path
= mapping
->path
;
2243 next_mapping
->mode
= mapping
->mode
;
2244 next_mapping
->read_only
= mapping
->read_only
;
2245 if (mapping
->mode
& MODE_DIRECTORY
) {
2246 next_mapping
->info
.dir
.parent_mapping_index
=
2247 mapping
->info
.dir
.parent_mapping_index
;
2248 next_mapping
->info
.dir
.first_dir_index
=
2249 mapping
->info
.dir
.first_dir_index
+
2250 0x10 * s
->sectors_per_cluster
*
2251 (mapping
->end
- mapping
->begin
);
2253 next_mapping
->info
.file
.offset
= mapping
->info
.file
.offset
+
2254 mapping
->end
- mapping
->begin
;
2256 mapping
= next_mapping
;
2265 static int commit_direntries(BDRVVVFATState
* s
,
2266 int dir_index
, int parent_mapping_index
)
2268 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2269 uint32_t first_cluster
= dir_index
== 0 ? 0 : begin_of_direntry(direntry
);
2270 mapping_t
* mapping
= find_mapping_for_cluster(s
, first_cluster
);
2272 int factor
= 0x10 * s
->sectors_per_cluster
;
2273 int old_cluster_count
, new_cluster_count
;
2274 int current_dir_index
= mapping
->info
.dir
.first_dir_index
;
2275 int first_dir_index
= current_dir_index
;
2279 DLOG(fprintf(stderr
, "commit_direntries for %s, parent_mapping_index %d\n", mapping
->path
, parent_mapping_index
));
2283 assert(mapping
->begin
== first_cluster
);
2284 assert(mapping
->info
.dir
.first_dir_index
< s
->directory
.next
);
2285 assert(mapping
->mode
& MODE_DIRECTORY
);
2286 assert(dir_index
== 0 || is_directory(direntry
));
2288 mapping
->info
.dir
.parent_mapping_index
= parent_mapping_index
;
2290 if (first_cluster
== 0) {
2291 old_cluster_count
= new_cluster_count
=
2292 s
->last_cluster_of_root_directory
;
2294 for (old_cluster_count
= 0, c
= first_cluster
; !fat_eof(s
, c
);
2296 old_cluster_count
++;
2298 for (new_cluster_count
= 0, c
= first_cluster
; !fat_eof(s
, c
);
2299 c
= modified_fat_get(s
, c
))
2300 new_cluster_count
++;
2303 if (new_cluster_count
> old_cluster_count
) {
2304 if (insert_direntries(s
,
2305 current_dir_index
+ factor
* old_cluster_count
,
2306 factor
* (new_cluster_count
- old_cluster_count
)) == NULL
)
2308 } else if (new_cluster_count
< old_cluster_count
)
2309 remove_direntries(s
,
2310 current_dir_index
+ factor
* new_cluster_count
,
2311 factor
* (old_cluster_count
- new_cluster_count
));
2313 for (c
= first_cluster
; !fat_eof(s
, c
); c
= modified_fat_get(s
, c
)) {
2314 direntry_t
*first_direntry
;
2315 void* direntry
= array_get(&(s
->directory
), current_dir_index
);
2316 int ret
= vvfat_read(s
->bs
, cluster2sector(s
, c
), direntry
,
2317 s
->sectors_per_cluster
);
2321 /* The first directory entry on the filesystem is the volume name */
2322 first_direntry
= (direntry_t
*) s
->directory
.pointer
;
2323 assert(!memcmp(first_direntry
->name
, s
->volume_label
, 11));
2325 current_dir_index
+= factor
;
2328 ret
= commit_mappings(s
, first_cluster
, dir_index
);
2333 for (i
= 0; i
< factor
* new_cluster_count
; i
++) {
2334 direntry
= array_get(&(s
->directory
), first_dir_index
+ i
);
2335 if (is_directory(direntry
) && !is_dot(direntry
)) {
2336 mapping
= find_mapping_for_cluster(s
, first_cluster
);
2337 assert(mapping
->mode
& MODE_DIRECTORY
);
2338 ret
= commit_direntries(s
, first_dir_index
+ i
,
2339 array_index(&(s
->mapping
), mapping
));
2348 /* commit one file (adjust contents, adjust mapping),
2349 return first_mapping_index */
2350 static int commit_one_file(BDRVVVFATState
* s
,
2351 int dir_index
, uint32_t offset
)
2353 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2354 uint32_t c
= begin_of_direntry(direntry
);
2355 uint32_t first_cluster
= c
;
2356 mapping_t
* mapping
= find_mapping_for_cluster(s
, c
);
2357 uint32_t size
= filesize_of_direntry(direntry
);
2358 char* cluster
= g_malloc(s
->cluster_size
);
2362 assert(offset
< size
);
2363 assert((offset
% s
->cluster_size
) == 0);
2365 for (i
= s
->cluster_size
; i
< offset
; i
+= s
->cluster_size
)
2366 c
= modified_fat_get(s
, c
);
2368 fd
= qemu_open(mapping
->path
, O_RDWR
| O_CREAT
| O_BINARY
, 0666);
2370 fprintf(stderr
, "Could not open %s... (%s, %d)\n", mapping
->path
,
2371 strerror(errno
), errno
);
2376 if (lseek(fd
, offset
, SEEK_SET
) != offset
) {
2383 while (offset
< size
) {
2385 int rest_size
= (size
- offset
> s
->cluster_size
?
2386 s
->cluster_size
: size
- offset
);
2389 c1
= modified_fat_get(s
, c
);
2391 assert((size
- offset
== 0 && fat_eof(s
, c
)) ||
2392 (size
> offset
&& c
>=2 && !fat_eof(s
, c
)));
2394 ret
= vvfat_read(s
->bs
, cluster2sector(s
, c
),
2395 (uint8_t*)cluster
, (rest_size
+ 0x1ff) / 0x200);
2403 if (write(fd
, cluster
, rest_size
) < 0) {
2409 offset
+= rest_size
;
2413 if (ftruncate(fd
, size
)) {
2414 perror("ftruncate()");
2422 return commit_mappings(s
, first_cluster
, dir_index
);
2426 /* test, if all mappings point to valid direntries */
2427 static void check1(BDRVVVFATState
* s
)
2430 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2431 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2432 if (mapping
->mode
& MODE_DELETED
) {
2433 fprintf(stderr
, "deleted\n");
2436 assert(mapping
->dir_index
< s
->directory
.next
);
2437 direntry_t
* direntry
= array_get(&(s
->directory
), mapping
->dir_index
);
2438 assert(mapping
->begin
== begin_of_direntry(direntry
) || mapping
->first_mapping_index
>= 0);
2439 if (mapping
->mode
& MODE_DIRECTORY
) {
2440 assert(mapping
->info
.dir
.first_dir_index
+ 0x10 * s
->sectors_per_cluster
* (mapping
->end
- mapping
->begin
) <= s
->directory
.next
);
2441 assert((mapping
->info
.dir
.first_dir_index
% (0x10 * s
->sectors_per_cluster
)) == 0);
2446 /* test, if all direntries have mappings */
2447 static void check2(BDRVVVFATState
* s
)
2450 int first_mapping
= -1;
2452 for (i
= 0; i
< s
->directory
.next
; i
++) {
2453 direntry_t
* direntry
= array_get(&(s
->directory
), i
);
2455 if (is_short_name(direntry
) && begin_of_direntry(direntry
)) {
2456 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin_of_direntry(direntry
));
2458 assert(mapping
->dir_index
== i
|| is_dot(direntry
));
2459 assert(mapping
->begin
== begin_of_direntry(direntry
) || is_dot(direntry
));
2462 if ((i
% (0x10 * s
->sectors_per_cluster
)) == 0) {
2466 for (j
= 0; j
< s
->mapping
.next
; j
++) {
2467 mapping_t
* mapping
= array_get(&(s
->mapping
), j
);
2468 if (mapping
->mode
& MODE_DELETED
)
2470 if (mapping
->mode
& MODE_DIRECTORY
) {
2471 if (mapping
->info
.dir
.first_dir_index
<= i
&& mapping
->info
.dir
.first_dir_index
+ 0x10 * s
->sectors_per_cluster
> i
) {
2472 assert(++count
== 1);
2473 if (mapping
->first_mapping_index
== -1)
2474 first_mapping
= array_index(&(s
->mapping
), mapping
);
2476 assert(first_mapping
== mapping
->first_mapping_index
);
2477 if (mapping
->info
.dir
.parent_mapping_index
< 0)
2480 mapping_t
* parent
= array_get(&(s
->mapping
), mapping
->info
.dir
.parent_mapping_index
);
2481 assert(parent
->mode
& MODE_DIRECTORY
);
2482 assert(parent
->info
.dir
.first_dir_index
< mapping
->info
.dir
.first_dir_index
);
2494 static int handle_renames_and_mkdirs(BDRVVVFATState
* s
)
2499 fprintf(stderr
, "handle_renames\n");
2500 for (i
= 0; i
< s
->commits
.next
; i
++) {
2501 commit_t
* commit
= array_get(&(s
->commits
), i
);
2502 fprintf(stderr
, "%d, %s (%d, %d)\n", i
, commit
->path
? commit
->path
: "(null)", commit
->param
.rename
.cluster
, commit
->action
);
2506 for (i
= 0; i
< s
->commits
.next
;) {
2507 commit_t
* commit
= array_get(&(s
->commits
), i
);
2508 if (commit
->action
== ACTION_RENAME
) {
2509 mapping_t
* mapping
= find_mapping_for_cluster(s
,
2510 commit
->param
.rename
.cluster
);
2511 char* old_path
= mapping
->path
;
2513 assert(commit
->path
);
2514 mapping
->path
= commit
->path
;
2515 if (rename(old_path
, mapping
->path
))
2518 if (mapping
->mode
& MODE_DIRECTORY
) {
2519 int l1
= strlen(mapping
->path
);
2520 int l2
= strlen(old_path
);
2522 direntry_t
* direntry
= array_get(&(s
->directory
),
2523 mapping
->info
.dir
.first_dir_index
);
2524 uint32_t c
= mapping
->begin
;
2528 while (!fat_eof(s
, c
)) {
2530 direntry_t
* d
= direntry
+ i
;
2532 if (is_file(d
) || (is_directory(d
) && !is_dot(d
))) {
2533 mapping_t
* m
= find_mapping_for_cluster(s
,
2534 begin_of_direntry(d
));
2535 int l
= strlen(m
->path
);
2536 char* new_path
= g_malloc(l
+ diff
+ 1);
2538 assert(!strncmp(m
->path
, mapping
->path
, l2
));
2540 pstrcpy(new_path
, l
+ diff
+ 1, mapping
->path
);
2541 pstrcpy(new_path
+ l1
, l
+ diff
+ 1 - l1
,
2544 schedule_rename(s
, m
->begin
, new_path
);
2547 } while((i
% (0x10 * s
->sectors_per_cluster
)) != 0);
2553 array_remove(&(s
->commits
), i
);
2555 } else if (commit
->action
== ACTION_MKDIR
) {
2557 int j
, parent_path_len
;
2560 if (mkdir(commit
->path
))
2563 if (mkdir(commit
->path
, 0755))
2567 mapping
= insert_mapping(s
, commit
->param
.mkdir
.cluster
,
2568 commit
->param
.mkdir
.cluster
+ 1);
2569 if (mapping
== NULL
)
2572 mapping
->mode
= MODE_DIRECTORY
;
2573 mapping
->read_only
= 0;
2574 mapping
->path
= commit
->path
;
2575 j
= s
->directory
.next
;
2577 insert_direntries(s
, s
->directory
.next
,
2578 0x10 * s
->sectors_per_cluster
);
2579 mapping
->info
.dir
.first_dir_index
= j
;
2581 parent_path_len
= strlen(commit
->path
)
2582 - strlen(get_basename(commit
->path
)) - 1;
2583 for (j
= 0; j
< s
->mapping
.next
; j
++) {
2584 mapping_t
* m
= array_get(&(s
->mapping
), j
);
2585 if (m
->first_mapping_index
< 0 && m
!= mapping
&&
2586 !strncmp(m
->path
, mapping
->path
, parent_path_len
) &&
2587 strlen(m
->path
) == parent_path_len
)
2590 assert(j
< s
->mapping
.next
);
2591 mapping
->info
.dir
.parent_mapping_index
= j
;
2593 array_remove(&(s
->commits
), i
);
2603 * TODO: make sure that the short name is not matching *another* file
2605 static int handle_commits(BDRVVVFATState
* s
)
2609 vvfat_close_current_file(s
);
2611 for (i
= 0; !fail
&& i
< s
->commits
.next
; i
++) {
2612 commit_t
* commit
= array_get(&(s
->commits
), i
);
2613 switch(commit
->action
) {
2614 case ACTION_RENAME
: case ACTION_MKDIR
:
2618 case ACTION_WRITEOUT
: {
2620 /* these variables are only used by assert() below */
2621 direntry_t
* entry
= array_get(&(s
->directory
),
2622 commit
->param
.writeout
.dir_index
);
2623 uint32_t begin
= begin_of_direntry(entry
);
2624 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin
);
2628 assert(mapping
->begin
== begin
);
2629 assert(commit
->path
== NULL
);
2631 if (commit_one_file(s
, commit
->param
.writeout
.dir_index
,
2632 commit
->param
.writeout
.modified_offset
))
2637 case ACTION_NEW_FILE
: {
2638 int begin
= commit
->param
.new_file
.first_cluster
;
2639 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin
);
2644 for (i
= 0; i
< s
->directory
.next
; i
++) {
2645 entry
= array_get(&(s
->directory
), i
);
2646 if (is_file(entry
) && begin_of_direntry(entry
) == begin
)
2650 if (i
>= s
->directory
.next
) {
2655 /* make sure there exists an initial mapping */
2656 if (mapping
&& mapping
->begin
!= begin
) {
2657 mapping
->end
= begin
;
2660 if (mapping
== NULL
) {
2661 mapping
= insert_mapping(s
, begin
, begin
+1);
2663 /* most members will be fixed in commit_mappings() */
2664 assert(commit
->path
);
2665 mapping
->path
= commit
->path
;
2666 mapping
->read_only
= 0;
2667 mapping
->mode
= MODE_NORMAL
;
2668 mapping
->info
.file
.offset
= 0;
2670 if (commit_one_file(s
, i
, 0))
2679 if (i
> 0 && array_remove_slice(&(s
->commits
), 0, i
))
2684 static int handle_deletes(BDRVVVFATState
* s
)
2686 int i
, deferred
= 1, deleted
= 1;
2688 /* delete files corresponding to mappings marked as deleted */
2689 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2690 while (deferred
&& deleted
) {
2694 for (i
= 1; i
< s
->mapping
.next
; i
++) {
2695 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2696 if (mapping
->mode
& MODE_DELETED
) {
2697 direntry_t
* entry
= array_get(&(s
->directory
),
2698 mapping
->dir_index
);
2700 if (is_free(entry
)) {
2701 /* remove file/directory */
2702 if (mapping
->mode
& MODE_DIRECTORY
) {
2703 int j
, next_dir_index
= s
->directory
.next
,
2704 first_dir_index
= mapping
->info
.dir
.first_dir_index
;
2706 if (rmdir(mapping
->path
) < 0) {
2707 if (errno
== ENOTEMPTY
) {
2714 for (j
= 1; j
< s
->mapping
.next
; j
++) {
2715 mapping_t
* m
= array_get(&(s
->mapping
), j
);
2716 if (m
->mode
& MODE_DIRECTORY
&&
2717 m
->info
.dir
.first_dir_index
>
2719 m
->info
.dir
.first_dir_index
<
2722 m
->info
.dir
.first_dir_index
;
2724 remove_direntries(s
, first_dir_index
,
2725 next_dir_index
- first_dir_index
);
2730 if (unlink(mapping
->path
))
2734 DLOG(fprintf(stderr
, "DELETE (%d)\n", i
); print_mapping(mapping
); print_direntry(entry
));
2735 remove_mapping(s
, i
);
2744 * synchronize mapping with new state:
2746 * - copy FAT (with bdrv_read)
2747 * - mark all filenames corresponding to mappings as deleted
2748 * - recurse direntries from root (using bs->bdrv_read)
2749 * - delete files corresponding to mappings marked as deleted
2751 static int do_commit(BDRVVVFATState
* s
)
2755 /* the real meat are the commits. Nothing to do? Move along! */
2756 if (s
->commits
.next
== 0)
2759 vvfat_close_current_file(s
);
2761 ret
= handle_renames_and_mkdirs(s
);
2763 fprintf(stderr
, "Error handling renames (%d)\n", ret
);
2768 /* copy FAT (with bdrv_read) */
2769 memcpy(s
->fat
.pointer
, s
->fat2
, 0x200 * s
->sectors_per_fat
);
2771 /* recurse direntries from root (using bs->bdrv_read) */
2772 ret
= commit_direntries(s
, 0, -1);
2774 fprintf(stderr
, "Fatal: error while committing (%d)\n", ret
);
2779 ret
= handle_commits(s
);
2781 fprintf(stderr
, "Error handling commits (%d)\n", ret
);
2786 ret
= handle_deletes(s
);
2788 fprintf(stderr
, "Error deleting\n");
2793 if (s
->qcow
->bs
->drv
->bdrv_make_empty
) {
2794 s
->qcow
->bs
->drv
->bdrv_make_empty(s
->qcow
->bs
);
2797 memset(s
->used_clusters
, 0, sector2cluster(s
, s
->sector_count
));
2803 static int try_commit(BDRVVVFATState
* s
)
2805 vvfat_close_current_file(s
);
2807 if(!is_consistent(s
))
2809 return do_commit(s
);
2812 static int vvfat_write(BlockDriverState
*bs
, int64_t sector_num
,
2813 const uint8_t *buf
, int nb_sectors
)
2815 BDRVVVFATState
*s
= bs
->opaque
;
2820 /* Check if we're operating in read-only mode */
2821 if (s
->qcow
== NULL
) {
2825 vvfat_close_current_file(s
);
2828 * Some sanity checks:
2829 * - do not allow writing to the boot sector
2830 * - do not allow to write non-ASCII filenames
2833 if (sector_num
< s
->first_sectors_number
)
2836 for (i
= sector2cluster(s
, sector_num
);
2837 i
<= sector2cluster(s
, sector_num
+ nb_sectors
- 1);) {
2838 mapping_t
* mapping
= find_mapping_for_cluster(s
, i
);
2840 if (mapping
->read_only
) {
2841 fprintf(stderr
, "Tried to write to write-protected file %s\n",
2846 if (mapping
->mode
& MODE_DIRECTORY
) {
2847 int begin
= cluster2sector(s
, i
);
2848 int end
= begin
+ s
->sectors_per_cluster
, k
;
2850 const direntry_t
* direntries
;
2855 if (begin
< sector_num
)
2857 if (end
> sector_num
+ nb_sectors
)
2858 end
= sector_num
+ nb_sectors
;
2859 dir_index
= mapping
->dir_index
+
2860 0x10 * (begin
- mapping
->begin
* s
->sectors_per_cluster
);
2861 direntries
= (direntry_t
*)(buf
+ 0x200 * (begin
- sector_num
));
2863 for (k
= 0; k
< (end
- begin
) * 0x10; k
++) {
2864 /* do not allow non-ASCII filenames */
2865 if (parse_long_name(&lfn
, direntries
+ k
) < 0) {
2866 fprintf(stderr
, "Warning: non-ASCII filename\n");
2869 /* no access to the direntry of a read-only file */
2870 else if (is_short_name(direntries
+k
) &&
2871 (direntries
[k
].attributes
& 1)) {
2872 if (memcmp(direntries
+ k
,
2873 array_get(&(s
->directory
), dir_index
+ k
),
2874 sizeof(direntry_t
))) {
2875 fprintf(stderr
, "Warning: tried to write to write-protected file\n");
2887 * Use qcow backend. Commit later.
2889 DLOG(fprintf(stderr
, "Write to qcow backend: %d + %d\n", (int)sector_num
, nb_sectors
));
2890 ret
= bdrv_write(s
->qcow
, sector_num
, buf
, nb_sectors
);
2892 fprintf(stderr
, "Error writing to qcow backend\n");
2896 for (i
= sector2cluster(s
, sector_num
);
2897 i
<= sector2cluster(s
, sector_num
+ nb_sectors
- 1); i
++)
2899 s
->used_clusters
[i
] |= USED_ALLOCATED
;
2902 /* TODO: add timeout */
2909 static int coroutine_fn
2910 vvfat_co_pwritev(BlockDriverState
*bs
, uint64_t offset
, uint64_t bytes
,
2911 QEMUIOVector
*qiov
, int flags
)
2914 BDRVVVFATState
*s
= bs
->opaque
;
2915 uint64_t sector_num
= offset
>> BDRV_SECTOR_BITS
;
2916 int nb_sectors
= bytes
>> BDRV_SECTOR_BITS
;
2919 assert((offset
& (BDRV_SECTOR_SIZE
- 1)) == 0);
2920 assert((bytes
& (BDRV_SECTOR_SIZE
- 1)) == 0);
2922 buf
= g_try_malloc(bytes
);
2923 if (bytes
&& buf
== NULL
) {
2926 qemu_iovec_to_buf(qiov
, 0, buf
, bytes
);
2928 qemu_co_mutex_lock(&s
->lock
);
2929 ret
= vvfat_write(bs
, sector_num
, buf
, nb_sectors
);
2930 qemu_co_mutex_unlock(&s
->lock
);
2937 static int64_t coroutine_fn
vvfat_co_get_block_status(BlockDriverState
*bs
,
2938 int64_t sector_num
, int nb_sectors
, int *n
, BlockDriverState
**file
)
2940 BDRVVVFATState
* s
= bs
->opaque
;
2941 *n
= s
->sector_count
- sector_num
;
2942 if (*n
> nb_sectors
) {
2944 } else if (*n
< 0) {
2947 return BDRV_BLOCK_DATA
;
2950 static int coroutine_fn
2951 write_target_commit(BlockDriverState
*bs
, uint64_t offset
, uint64_t bytes
,
2952 QEMUIOVector
*qiov
, int flags
)
2954 BDRVVVFATState
* s
= *((BDRVVVFATState
**) bs
->opaque
);
2955 return try_commit(s
);
2958 static void write_target_close(BlockDriverState
*bs
) {
2959 BDRVVVFATState
* s
= *((BDRVVVFATState
**) bs
->opaque
);
2960 bdrv_unref_child(s
->bs
, s
->qcow
);
2961 g_free(s
->qcow_filename
);
2964 static BlockDriver vvfat_write_target
= {
2965 .format_name
= "vvfat_write_target",
2966 .bdrv_co_pwritev
= write_target_commit
,
2967 .bdrv_close
= write_target_close
,
2970 static void vvfat_qcow_options(int *child_flags
, QDict
*child_options
,
2971 int parent_flags
, QDict
*parent_options
)
2973 qdict_set_default_str(child_options
, BDRV_OPT_READ_ONLY
, "off");
2974 *child_flags
= 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
, "write-target.driver", qstring_from_str("qcow"));
3022 s
->qcow
= bdrv_open_child(s
->qcow_filename
, options
, "write-target", bs
,
3023 &child_vvfat_qcow
, false, errp
);
3031 unlink(s
->qcow_filename
);
3034 backing
= bdrv_new();
3035 bdrv_set_backing_hd(s
->bs
, backing
);
3036 bdrv_unref(backing
);
3038 s
->bs
->backing
->bs
->drv
= &vvfat_write_target
;
3039 s
->bs
->backing
->bs
->opaque
= g_new(void *, 1);
3040 *(void**)s
->bs
->backing
->bs
->opaque
= s
;
3045 g_free(s
->qcow_filename
);
3046 s
->qcow_filename
= NULL
;
3050 static void vvfat_close(BlockDriverState
*bs
)
3052 BDRVVVFATState
*s
= bs
->opaque
;
3054 vvfat_close_current_file(s
);
3055 array_free(&(s
->fat
));
3056 array_free(&(s
->directory
));
3057 array_free(&(s
->mapping
));
3058 g_free(s
->cluster_buffer
);
3061 migrate_del_blocker(s
->migration_blocker
);
3062 error_free(s
->migration_blocker
);
3066 static BlockDriver bdrv_vvfat
= {
3067 .format_name
= "vvfat",
3068 .protocol_name
= "fat",
3069 .instance_size
= sizeof(BDRVVVFATState
),
3071 .bdrv_parse_filename
= vvfat_parse_filename
,
3072 .bdrv_file_open
= vvfat_open
,
3073 .bdrv_refresh_limits
= vvfat_refresh_limits
,
3074 .bdrv_close
= vvfat_close
,
3076 .bdrv_co_preadv
= vvfat_co_preadv
,
3077 .bdrv_co_pwritev
= vvfat_co_pwritev
,
3078 .bdrv_co_get_block_status
= vvfat_co_get_block_status
,
3081 static void bdrv_vvfat_init(void)
3083 bdrv_register(&bdrv_vvfat
);
3086 block_init(bdrv_vvfat_init
);
3089 static void checkpoint(void) {
3090 assert(((mapping_t
*)array_get(&(vvv
->mapping
), 0))->end
== 2);
3093 assert(!vvv
->current_mapping
|| vvv
->current_fd
|| (vvv
->current_mapping
->mode
& MODE_DIRECTORY
));
3095 if (((direntry_t
*)vvv
->directory
.pointer
)[1].attributes
!= 0xf)
3096 fprintf(stderr
, "Nonono!\n");
3098 direntry_t
* direntry
;
3099 assert(vvv
->mapping
.size
>= vvv
->mapping
.item_size
* vvv
->mapping
.next
);
3100 assert(vvv
->directory
.size
>= vvv
->directory
.item_size
* vvv
->directory
.next
);
3101 if (vvv
->mapping
.next
<47)
3103 assert((mapping
= array_get(&(vvv
->mapping
), 47)));
3104 assert(mapping
->dir_index
< vvv
->directory
.next
);
3105 direntry
= array_get(&(vvv
->directory
), mapping
->dir_index
);
3106 assert(!memcmp(direntry
->name
, "USB H ", 11) || direntry
->name
[0]==0);