1 /* vim:set shiftwidth=4 ts=8: */
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
27 #include "qemu-common.h"
28 #include "block_int.h"
38 /* TODO: add ":bootsector=blabla.img:" */
39 /* LATER TODO: add automatic boot sector generation from
40 BOOTEASY.ASM and Ranish Partition Manager
41 Note that DOS assumes the system files to be the first files in the
42 file system (test if the boot sector still relies on that fact)! */
43 /* MAYBE TODO: write block-visofs.c */
44 /* TODO: call try_commit() only after a timeout */
56 static void checkpoint(void);
59 void nonono(const char* file
, int line
, const char* msg
) {
60 fprintf(stderr
, "Nonono! %s:%d %s\n", file
, line
, msg
);
64 #define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
73 /* dynamic array functions */
74 typedef struct array_t
{
76 unsigned int size
,next
,item_size
;
79 static inline void array_init(array_t
* array
,unsigned int item_size
)
81 array
->pointer
= NULL
;
84 array
->item_size
=item_size
;
87 static inline void array_free(array_t
* array
)
89 g_free(array
->pointer
);
90 array
->size
=array
->next
=0;
93 /* does not automatically grow */
94 static inline void* array_get(array_t
* array
,unsigned int index
) {
95 assert(index
< array
->next
);
96 return array
->pointer
+ index
* array
->item_size
;
99 static inline int array_ensure_allocated(array_t
* array
, int index
)
101 if((index
+ 1) * array
->item_size
> array
->size
) {
102 int new_size
= (index
+ 32) * array
->item_size
;
103 array
->pointer
= g_realloc(array
->pointer
, new_size
);
106 array
->size
= new_size
;
107 array
->next
= index
+ 1;
113 static inline void* array_get_next(array_t
* array
) {
114 unsigned int next
= array
->next
;
117 if (array_ensure_allocated(array
, next
) < 0)
120 array
->next
= next
+ 1;
121 result
= array_get(array
, next
);
126 static inline void* array_insert(array_t
* array
,unsigned int index
,unsigned int count
) {
127 if((array
->next
+count
)*array
->item_size
>array
->size
) {
128 int increment
=count
*array
->item_size
;
129 array
->pointer
=g_realloc(array
->pointer
,array
->size
+increment
);
132 array
->size
+=increment
;
134 memmove(array
->pointer
+(index
+count
)*array
->item_size
,
135 array
->pointer
+index
*array
->item_size
,
136 (array
->next
-index
)*array
->item_size
);
138 return array
->pointer
+index
*array
->item_size
;
141 /* this performs a "roll", so that the element which was at index_from becomes
142 * index_to, but the order of all other elements is preserved. */
143 static inline int array_roll(array_t
* array
,int index_to
,int index_from
,int count
)
151 index_to
<0 || index_to
>=array
->next
||
152 index_from
<0 || index_from
>=array
->next
)
155 if(index_to
==index_from
)
159 from
=array
->pointer
+index_from
*is
;
160 to
=array
->pointer
+index_to
*is
;
161 buf
=g_malloc(is
*count
);
162 memcpy(buf
,from
,is
*count
);
164 if(index_to
<index_from
)
165 memmove(to
+is
*count
,to
,from
-to
);
167 memmove(from
,from
+is
*count
,to
-from
);
169 memcpy(to
,buf
,is
*count
);
176 static inline int array_remove_slice(array_t
* array
,int index
, int count
)
180 assert(index
+ count
<= array
->next
);
181 if(array_roll(array
,array
->next
-1,index
,count
))
183 array
->next
-= count
;
187 static int array_remove(array_t
* array
,int index
)
189 return array_remove_slice(array
, index
, 1);
192 /* return the index for a given member */
193 static int array_index(array_t
* array
, void* pointer
)
195 size_t offset
= (char*)pointer
- array
->pointer
;
196 assert((offset
% array
->item_size
) == 0);
197 assert(offset
/array
->item_size
< array
->next
);
198 return offset
/array
->item_size
;
201 /* These structures are used to fake a disk and the VFAT filesystem.
202 * For this reason we need to use QEMU_PACKED. */
204 typedef struct bootsector_t
{
207 uint16_t sector_size
;
208 uint8_t sectors_per_cluster
;
209 uint16_t reserved_sectors
;
210 uint8_t number_of_fats
;
211 uint16_t root_entries
;
212 uint16_t total_sectors16
;
214 uint16_t sectors_per_fat
;
215 uint16_t sectors_per_track
;
216 uint16_t number_of_heads
;
217 uint32_t hidden_sectors
;
218 uint32_t total_sectors
;
221 uint8_t drive_number
;
222 uint8_t current_head
;
225 uint8_t volume_label
[11];
228 uint32_t sectors_per_fat
;
231 uint32_t first_cluster_of_root_directory
;
232 uint16_t info_sector
;
233 uint16_t backup_boot_sector
;
238 uint8_t ignored
[0x1c0];
240 } QEMU_PACKED bootsector_t
;
248 typedef struct partition_t
{
249 uint8_t attributes
; /* 0x80 = bootable */
251 uint8_t fs_type
; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
253 uint32_t start_sector_long
;
254 uint32_t length_sector_long
;
255 } QEMU_PACKED partition_t
;
257 typedef struct mbr_t
{
258 uint8_t ignored
[0x1b8];
261 partition_t partition
[4];
265 typedef struct direntry_t
{
267 uint8_t extension
[3];
278 } QEMU_PACKED direntry_t
;
280 /* this structure are used to transparently access the files */
282 typedef struct mapping_t
{
283 /* begin is the first cluster, end is the last+1 */
285 /* as s->directory is growable, no pointer may be used here */
286 unsigned int dir_index
;
287 /* the clusters of a file may be in any order; this points to the first */
288 int first_mapping_index
;
291 * - the offset in the file (in clusters) for a file, or
292 * - the next cluster of the directory for a directory, and
293 * - the address of the buffer for a faked entry
299 int parent_mapping_index
;
303 /* path contains the full path, i.e. it always starts with s->path */
306 enum { MODE_UNDEFINED
= 0, MODE_NORMAL
= 1, MODE_MODIFIED
= 2,
307 MODE_DIRECTORY
= 4, MODE_FAKED
= 8,
308 MODE_DELETED
= 16, MODE_RENAMED
= 32 } mode
;
313 static void print_direntry(const struct direntry_t
*);
314 static void print_mapping(const struct mapping_t
* mapping
);
317 /* here begins the real VVFAT driver */
319 typedef struct BDRVVVFATState
{
321 BlockDriverState
* bs
; /* pointer to parent */
322 unsigned int first_sectors_number
; /* 1 for a single partition, 0x40 for a disk with partition table */
323 unsigned char first_sectors
[0x40*0x200];
325 int fat_type
; /* 16 or 32 */
326 array_t fat
,directory
,mapping
;
328 unsigned int cluster_size
;
329 unsigned int sectors_per_cluster
;
330 unsigned int sectors_per_fat
;
331 unsigned int sectors_of_root_directory
;
332 uint32_t last_cluster_of_root_directory
;
333 unsigned int faked_sectors
; /* how many sectors are faked before file data */
334 uint32_t sector_count
; /* total number of sectors of the partition */
335 uint32_t cluster_count
; /* total number of clusters of this partition */
336 uint32_t max_fat_value
;
339 mapping_t
* current_mapping
;
340 unsigned char* cluster
; /* points to current cluster */
341 unsigned char* cluster_buffer
; /* points to a buffer to hold temp data */
342 unsigned int current_cluster
;
345 BlockDriverState
* write_target
;
347 BlockDriverState
* qcow
;
352 int downcase_short_names
;
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(BlockDriverState
* bs
, mbr_chs_t
* chs
, int spos
){
361 sector
= spos
% (bs
->secs
); spos
/= bs
->secs
;
362 head
= spos
% (bs
->heads
); spos
/= bs
->heads
;
363 if(spos
>= bs
->cyls
){
365 it happens if 32bit sector positions are used, while CHS is only 24bit.
366 Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
369 chs
->cylinder
= 0xFF;
372 chs
->head
= (uint8_t)head
;
373 chs
->sector
= (uint8_t)( (sector
+1) | ((spos
>>8)<<6) );
374 chs
->cylinder
= (uint8_t)spos
;
378 static void init_mbr(BDRVVVFATState
* s
)
380 /* TODO: if the files mbr.img and bootsect.img exist, use them */
381 mbr_t
* real_mbr
=(mbr_t
*)s
->first_sectors
;
382 partition_t
* partition
= &(real_mbr
->partition
[0]);
385 memset(s
->first_sectors
,0,512);
387 /* Win NT Disk Signature */
388 real_mbr
->nt_id
= cpu_to_le32(0xbe1afdfa);
390 partition
->attributes
=0x80; /* bootable */
392 /* LBA is used when partition is outside the CHS geometry */
393 lba
= sector2CHS(s
->bs
, &partition
->start_CHS
, s
->first_sectors_number
-1);
394 lba
|= sector2CHS(s
->bs
, &partition
->end_CHS
, s
->sector_count
);
396 /*LBA partitions are identified only by start/length_sector_long not by CHS*/
397 partition
->start_sector_long
=cpu_to_le32(s
->first_sectors_number
-1);
398 partition
->length_sector_long
=cpu_to_le32(s
->sector_count
- s
->first_sectors_number
+1);
400 /* FAT12/FAT16/FAT32 */
401 /* DOS uses different types when partition is LBA,
402 probably to prevent older versions from using CHS on them */
403 partition
->fs_type
= s
->fat_type
==12 ? 0x1:
404 s
->fat_type
==16 ? (lba
?0xe:0x06):
405 /*fat_tyoe==32*/ (lba
?0xc:0x0b);
407 real_mbr
->magic
[0]=0x55; real_mbr
->magic
[1]=0xaa;
410 /* direntry functions */
412 /* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
413 static inline int short2long_name(char* dest
,const char* src
)
417 for(i
=0;i
<129 && src
[i
];i
++) {
422 dest
[2*i
]=dest
[2*i
+1]=0;
423 for(i
=2*i
+2;(i
%26);i
++)
428 static inline direntry_t
* create_long_filename(BDRVVVFATState
* s
,const char* filename
)
431 int length
=short2long_name(buffer
,filename
),
432 number_of_entries
=(length
+25)/26,i
;
435 for(i
=0;i
<number_of_entries
;i
++) {
436 entry
=array_get_next(&(s
->directory
));
437 entry
->attributes
=0xf;
438 entry
->reserved
[0]=0;
440 entry
->name
[0]=(number_of_entries
-i
)|(i
==0?0x40:0);
442 for(i
=0;i
<26*number_of_entries
;i
++) {
444 if(offset
<10) offset
=1+offset
;
445 else if(offset
<22) offset
=14+offset
-10;
446 else offset
=28+offset
-22;
447 entry
=array_get(&(s
->directory
),s
->directory
.next
-1-(i
/26));
448 entry
->name
[offset
]=buffer
[i
];
450 return array_get(&(s
->directory
),s
->directory
.next
-number_of_entries
);
453 static char is_free(const direntry_t
* direntry
)
455 return direntry
->name
[0]==0xe5 || direntry
->name
[0]==0x00;
458 static char is_volume_label(const direntry_t
* direntry
)
460 return direntry
->attributes
== 0x28;
463 static char is_long_name(const direntry_t
* direntry
)
465 return direntry
->attributes
== 0xf;
468 static char is_short_name(const direntry_t
* direntry
)
470 return !is_volume_label(direntry
) && !is_long_name(direntry
)
471 && !is_free(direntry
);
474 static char is_directory(const direntry_t
* direntry
)
476 return direntry
->attributes
& 0x10 && direntry
->name
[0] != 0xe5;
479 static inline char is_dot(const direntry_t
* direntry
)
481 return is_short_name(direntry
) && direntry
->name
[0] == '.';
484 static char is_file(const direntry_t
* direntry
)
486 return is_short_name(direntry
) && !is_directory(direntry
);
489 static inline uint32_t begin_of_direntry(const direntry_t
* direntry
)
491 return le16_to_cpu(direntry
->begin
)|(le16_to_cpu(direntry
->begin_hi
)<<16);
494 static inline uint32_t filesize_of_direntry(const direntry_t
* direntry
)
496 return le32_to_cpu(direntry
->size
);
499 static void set_begin_of_direntry(direntry_t
* direntry
, uint32_t begin
)
501 direntry
->begin
= cpu_to_le16(begin
& 0xffff);
502 direntry
->begin_hi
= cpu_to_le16((begin
>> 16) & 0xffff);
507 static inline uint8_t fat_chksum(const direntry_t
* entry
)
515 c
= (i
< 8) ? entry
->name
[i
] : entry
->extension
[i
-8];
516 chksum
=(((chksum
&0xfe)>>1)|((chksum
&0x01)?0x80:0)) + c
;
522 /* if return_time==0, this returns the fat_date, else the fat_time */
523 static uint16_t fat_datetime(time_t time
,int return_time
) {
526 t
=localtime(&time
); /* this is not thread safe */
530 localtime_r(&time
,t
);
533 return cpu_to_le16((t
->tm_sec
/2)|(t
->tm_min
<<5)|(t
->tm_hour
<<11));
534 return cpu_to_le16((t
->tm_mday
)|((t
->tm_mon
+1)<<5)|((t
->tm_year
-80)<<9));
537 static inline void fat_set(BDRVVVFATState
* s
,unsigned int cluster
,uint32_t value
)
539 if(s
->fat_type
==32) {
540 uint32_t* entry
=array_get(&(s
->fat
),cluster
);
541 *entry
=cpu_to_le32(value
);
542 } else if(s
->fat_type
==16) {
543 uint16_t* entry
=array_get(&(s
->fat
),cluster
);
544 *entry
=cpu_to_le16(value
&0xffff);
546 int offset
= (cluster
*3/2);
547 unsigned char* p
= array_get(&(s
->fat
), offset
);
551 p
[1] = (p
[1]&0xf0) | ((value
>>8)&0xf);
554 p
[0] = (p
[0]&0xf) | ((value
&0xf)<<4);
561 static inline uint32_t fat_get(BDRVVVFATState
* s
,unsigned int cluster
)
563 if(s
->fat_type
==32) {
564 uint32_t* entry
=array_get(&(s
->fat
),cluster
);
565 return le32_to_cpu(*entry
);
566 } else if(s
->fat_type
==16) {
567 uint16_t* entry
=array_get(&(s
->fat
),cluster
);
568 return le16_to_cpu(*entry
);
570 const uint8_t* x
=(uint8_t*)(s
->fat
.pointer
)+cluster
*3/2;
571 return ((x
[0]|(x
[1]<<8))>>(cluster
&1?4:0))&0x0fff;
575 static inline int fat_eof(BDRVVVFATState
* s
,uint32_t fat_entry
)
577 if(fat_entry
>s
->max_fat_value
-8)
582 static inline void init_fat(BDRVVVFATState
* s
)
584 if (s
->fat_type
== 12) {
585 array_init(&(s
->fat
),1);
586 array_ensure_allocated(&(s
->fat
),
587 s
->sectors_per_fat
* 0x200 * 3 / 2 - 1);
589 array_init(&(s
->fat
),(s
->fat_type
==32?4:2));
590 array_ensure_allocated(&(s
->fat
),
591 s
->sectors_per_fat
* 0x200 / s
->fat
.item_size
- 1);
593 memset(s
->fat
.pointer
,0,s
->fat
.size
);
595 switch(s
->fat_type
) {
596 case 12: s
->max_fat_value
=0xfff; break;
597 case 16: s
->max_fat_value
=0xffff; break;
598 case 32: s
->max_fat_value
=0x0fffffff; break;
599 default: s
->max_fat_value
=0; /* error... */
604 /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
605 /* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
606 static inline direntry_t
* create_short_and_long_name(BDRVVVFATState
* s
,
607 unsigned int directory_start
, const char* filename
, int is_dot
)
609 int i
,j
,long_index
=s
->directory
.next
;
610 direntry_t
* entry
= NULL
;
611 direntry_t
* entry_long
= NULL
;
614 entry
=array_get_next(&(s
->directory
));
615 memset(entry
->name
,0x20,11);
616 memcpy(entry
->name
,filename
,strlen(filename
));
620 entry_long
=create_long_filename(s
,filename
);
622 i
= strlen(filename
);
623 for(j
= i
- 1; j
>0 && filename
[j
]!='.';j
--);
629 entry
=array_get_next(&(s
->directory
));
630 memset(entry
->name
,0x20,11);
631 memcpy(entry
->name
, filename
, i
);
634 for (i
= 0; i
< 3 && filename
[j
+1+i
]; i
++)
635 entry
->extension
[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
=(char*)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
=(mapping_t
*)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;
790 /* fill with zeroes up to the end of the cluster */
791 while(s
->directory
.next
%(0x10*s
->sectors_per_cluster
)) {
792 direntry_t
* direntry
=array_get_next(&(s
->directory
));
793 memset(direntry
,0,sizeof(direntry_t
));
796 /* TODO: if there are more entries, bootsector has to be adjusted! */
797 #define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
798 if (mapping_index
== 0 && s
->directory
.next
< ROOT_ENTRIES
) {
800 int cur
= s
->directory
.next
;
801 array_ensure_allocated(&(s
->directory
), ROOT_ENTRIES
- 1);
802 s
->directory
.next
= ROOT_ENTRIES
;
803 memset(array_get(&(s
->directory
), cur
), 0,
804 (ROOT_ENTRIES
- cur
) * sizeof(direntry_t
));
807 /* reget the mapping, since s->mapping was possibly realloc()ed */
808 mapping
= (mapping_t
*)array_get(&(s
->mapping
), mapping_index
);
809 first_cluster
+= (s
->directory
.next
- mapping
->info
.dir
.first_dir_index
)
810 * 0x20 / s
->cluster_size
;
811 mapping
->end
= first_cluster
;
813 direntry
= (direntry_t
*)array_get(&(s
->directory
), mapping
->dir_index
);
814 set_begin_of_direntry(direntry
, mapping
->begin
);
819 static inline uint32_t sector2cluster(BDRVVVFATState
* s
,off_t sector_num
)
821 return (sector_num
-s
->faked_sectors
)/s
->sectors_per_cluster
;
824 static inline off_t
cluster2sector(BDRVVVFATState
* s
, uint32_t cluster_num
)
826 return s
->faked_sectors
+ s
->sectors_per_cluster
* cluster_num
;
829 static int init_directories(BDRVVVFATState
* s
,
832 bootsector_t
* bootsector
;
835 unsigned int cluster
;
837 memset(&(s
->first_sectors
[0]),0,0x40*0x200);
839 s
->cluster_size
=s
->sectors_per_cluster
*0x200;
840 s
->cluster_buffer
=g_malloc(s
->cluster_size
);
843 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
844 * where sc is sector_count,
845 * spf is sectors_per_fat,
846 * spc is sectors_per_clusters, and
847 * fat_type = 12, 16 or 32.
849 i
= 1+s
->sectors_per_cluster
*0x200*8/s
->fat_type
;
850 s
->sectors_per_fat
=(s
->sector_count
+i
)/i
; /* round up */
852 array_init(&(s
->mapping
),sizeof(mapping_t
));
853 array_init(&(s
->directory
),sizeof(direntry_t
));
855 /* add volume label */
857 direntry_t
* entry
=array_get_next(&(s
->directory
));
858 entry
->attributes
=0x28; /* archive | volume label */
859 memcpy(entry
->name
,"QEMU VVF",8);
860 memcpy(entry
->extension
,"AT ",3);
863 /* Now build FAT, and write back information into directory */
866 s
->faked_sectors
=s
->first_sectors_number
+s
->sectors_per_fat
*2;
867 s
->cluster_count
=sector2cluster(s
, s
->sector_count
);
869 mapping
= array_get_next(&(s
->mapping
));
871 mapping
->dir_index
= 0;
872 mapping
->info
.dir
.parent_mapping_index
= -1;
873 mapping
->first_mapping_index
= -1;
874 mapping
->path
= g_strdup(dirname
);
875 i
= strlen(mapping
->path
);
876 if (i
> 0 && mapping
->path
[i
- 1] == '/')
877 mapping
->path
[i
- 1] = '\0';
878 mapping
->mode
= MODE_DIRECTORY
;
879 mapping
->read_only
= 0;
880 s
->path
= mapping
->path
;
882 for (i
= 0, cluster
= 0; i
< s
->mapping
.next
; i
++) {
883 /* MS-DOS expects the FAT to be 0 for the root directory
884 * (except for the media byte). */
885 /* LATER TODO: still true for FAT32? */
886 int fix_fat
= (i
!= 0);
887 mapping
= array_get(&(s
->mapping
), i
);
889 if (mapping
->mode
& MODE_DIRECTORY
) {
890 mapping
->begin
= cluster
;
891 if(read_directory(s
, i
)) {
892 fprintf(stderr
, "Could not read directory %s\n",
896 mapping
= array_get(&(s
->mapping
), i
);
898 assert(mapping
->mode
== MODE_UNDEFINED
);
899 mapping
->mode
=MODE_NORMAL
;
900 mapping
->begin
= cluster
;
901 if (mapping
->end
> 0) {
902 direntry_t
* direntry
= array_get(&(s
->directory
),
905 mapping
->end
= cluster
+ 1 + (mapping
->end
-1)/s
->cluster_size
;
906 set_begin_of_direntry(direntry
, mapping
->begin
);
908 mapping
->end
= cluster
+ 1;
913 assert(mapping
->begin
< mapping
->end
);
915 /* next free cluster */
916 cluster
= mapping
->end
;
918 if(cluster
> s
->cluster_count
) {
919 fprintf(stderr
,"Directory does not fit in FAT%d (capacity %s)\n",
921 s
->fat_type
== 12 ? s
->sector_count
== 2880 ? "1.44 MB"
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
->fat_type
!=12?0xf8:s
->sector_count
==5760?0xf9:0xf8); /* media descriptor */
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(s
->bs
->secs
);
961 bootsector
->number_of_heads
=cpu_to_le16(s
->bs
->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
->fat_type
==12?0:0x80; /* assume this is hda (TODO) */
967 bootsector
->u
.fat16
.current_head
=0;
968 bootsector
->u
.fat16
.signature
=0x29;
969 bootsector
->u
.fat16
.id
=cpu_to_le32(0xfabe1afd);
971 memcpy(bootsector
->u
.fat16
.volume_label
,"QEMU VVFAT ",11);
972 memcpy(bootsector
->fat_type
,(s
->fat_type
==12?"FAT12 ":s
->fat_type
==16?"FAT16 ":"FAT32 "),8);
973 bootsector
->magic
[0]=0x55; bootsector
->magic
[1]=0xaa;
979 static BDRVVVFATState
*vvv
= NULL
;
982 static int enable_write_target(BDRVVVFATState
*s
);
983 static int is_consistent(BDRVVVFATState
*s
);
985 static int vvfat_open(BlockDriverState
*bs
, const char* dirname
, int flags
)
987 BDRVVVFATState
*s
= bs
->opaque
;
995 DLOG(if (stderr
== NULL
) {
996 stderr
= fopen("vvfat.log", "a");
997 setbuf(stderr
, NULL
);
1003 /* LATER TODO: if FAT32, adjust */
1004 s
->sectors_per_cluster
=0x10;
1006 bs
->cyls
=1024; bs
->heads
=16; bs
->secs
=63;
1008 s
->current_cluster
=0xffffffff;
1010 s
->first_sectors_number
=0x40;
1011 /* read only is the default for safety */
1013 s
->qcow
= s
->write_target
= NULL
;
1014 s
->qcow_filename
= NULL
;
1016 s
->downcase_short_names
= 1;
1018 if (!strstart(dirname
, "fat:", NULL
))
1021 if (strstr(dirname
, ":floppy:")) {
1024 s
->first_sectors_number
= 1;
1025 s
->sectors_per_cluster
=2;
1026 bs
->cyls
= 80; bs
->heads
= 2; bs
->secs
= 36;
1029 s
->sector_count
=bs
->cyls
*bs
->heads
*bs
->secs
;
1031 if (strstr(dirname
, ":32:")) {
1032 fprintf(stderr
, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1034 } else if (strstr(dirname
, ":16:")) {
1036 } else if (strstr(dirname
, ":12:")) {
1038 s
->sector_count
=2880;
1041 if (strstr(dirname
, ":rw:")) {
1042 if (enable_write_target(s
))
1047 i
= strrchr(dirname
, ':') - dirname
;
1049 if (dirname
[i
-2] == ':' && qemu_isalpha(dirname
[i
-1]))
1050 /* workaround for DOS drive names */
1055 bs
->total_sectors
=bs
->cyls
*bs
->heads
*bs
->secs
;
1057 if(init_directories(s
, dirname
))
1060 s
->sector_count
= s
->faked_sectors
+ s
->sectors_per_cluster
*s
->cluster_count
;
1062 if(s
->first_sectors_number
==0x40)
1065 /* for some reason or other, MS-DOS does not like to know about CHS... */
1067 bs
->heads
= bs
->cyls
= bs
->secs
= 0;
1069 // assert(is_consistent(s));
1070 qemu_co_mutex_init(&s
->lock
);
1074 static inline void vvfat_close_current_file(BDRVVVFATState
*s
)
1076 if(s
->current_mapping
) {
1077 s
->current_mapping
= NULL
;
1078 if (s
->current_fd
) {
1079 close(s
->current_fd
);
1083 s
->current_cluster
= -1;
1086 /* mappings between index1 and index2-1 are supposed to be ordered
1087 * return value is the index of the last mapping for which end>cluster_num
1089 static inline int find_mapping_for_cluster_aux(BDRVVVFATState
* s
,int cluster_num
,int index1
,int index2
)
1094 index3
=(index1
+index2
)/2;
1095 mapping
=array_get(&(s
->mapping
),index3
);
1096 assert(mapping
->begin
< mapping
->end
);
1097 if(mapping
->begin
>=cluster_num
) {
1098 assert(index2
!=index3
|| index2
==0);
1104 return mapping
->end
<=cluster_num
? index2
: index1
;
1107 assert(index1
<=index2
);
1108 DLOG(mapping
=array_get(&(s
->mapping
),index1
);
1109 assert(mapping
->begin
<=cluster_num
);
1110 assert(index2
>= s
->mapping
.next
||
1111 ((mapping
= array_get(&(s
->mapping
),index2
)) &&
1112 mapping
->end
>cluster_num
)));
1116 static inline mapping_t
* find_mapping_for_cluster(BDRVVVFATState
* s
,int cluster_num
)
1118 int index
=find_mapping_for_cluster_aux(s
,cluster_num
,0,s
->mapping
.next
);
1120 if(index
>=s
->mapping
.next
)
1122 mapping
=array_get(&(s
->mapping
),index
);
1123 if(mapping
->begin
>cluster_num
)
1125 assert(mapping
->begin
<=cluster_num
&& mapping
->end
>cluster_num
);
1129 static int open_file(BDRVVVFATState
* s
,mapping_t
* mapping
)
1133 if(!s
->current_mapping
||
1134 strcmp(s
->current_mapping
->path
,mapping
->path
)) {
1136 int fd
= open(mapping
->path
, O_RDONLY
| O_BINARY
| O_LARGEFILE
);
1139 vvfat_close_current_file(s
);
1141 s
->current_mapping
= mapping
;
1146 static inline int read_cluster(BDRVVVFATState
*s
,int cluster_num
)
1148 if(s
->current_cluster
!= cluster_num
) {
1151 assert(!s
->current_mapping
|| s
->current_fd
|| (s
->current_mapping
->mode
& MODE_DIRECTORY
));
1152 if(!s
->current_mapping
1153 || s
->current_mapping
->begin
>cluster_num
1154 || s
->current_mapping
->end
<=cluster_num
) {
1155 /* binary search of mappings for file */
1156 mapping_t
* mapping
=find_mapping_for_cluster(s
,cluster_num
);
1158 assert(!mapping
|| (cluster_num
>=mapping
->begin
&& cluster_num
<mapping
->end
));
1160 if (mapping
&& mapping
->mode
& MODE_DIRECTORY
) {
1161 vvfat_close_current_file(s
);
1162 s
->current_mapping
= mapping
;
1163 read_cluster_directory
:
1164 offset
= s
->cluster_size
*(cluster_num
-s
->current_mapping
->begin
);
1165 s
->cluster
= (unsigned char*)s
->directory
.pointer
+offset
1166 + 0x20*s
->current_mapping
->info
.dir
.first_dir_index
;
1167 assert(((s
->cluster
-(unsigned char*)s
->directory
.pointer
)%s
->cluster_size
)==0);
1168 assert((char*)s
->cluster
+s
->cluster_size
<= s
->directory
.pointer
+s
->directory
.next
*s
->directory
.item_size
);
1169 s
->current_cluster
= cluster_num
;
1173 if(open_file(s
,mapping
))
1175 } else if (s
->current_mapping
->mode
& MODE_DIRECTORY
)
1176 goto read_cluster_directory
;
1178 assert(s
->current_fd
);
1180 offset
=s
->cluster_size
*(cluster_num
-s
->current_mapping
->begin
)+s
->current_mapping
->info
.file
.offset
;
1181 if(lseek(s
->current_fd
, offset
, SEEK_SET
)!=offset
)
1183 s
->cluster
=s
->cluster_buffer
;
1184 result
=read(s
->current_fd
,s
->cluster
,s
->cluster_size
);
1186 s
->current_cluster
= -1;
1189 s
->current_cluster
= cluster_num
;
1195 static void print_direntry(const direntry_t
* direntry
)
1200 fprintf(stderr
, "direntry %p: ", direntry
);
1203 if(is_long_name(direntry
)) {
1204 unsigned char* c
=(unsigned char*)direntry
;
1206 for(i
=1;i
<11 && c
[i
] && c
[i
]!=0xff;i
+=2)
1207 #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
1209 for(i
=14;i
<26 && c
[i
] && c
[i
]!=0xff;i
+=2)
1211 for(i
=28;i
<32 && c
[i
] && c
[i
]!=0xff;i
+=2)
1214 fprintf(stderr
, "%s\n", buffer
);
1218 ADD_CHAR(direntry
->name
[i
]);
1220 fprintf(stderr
,"%s attributes=0x%02x begin=%d size=%d\n",
1222 direntry
->attributes
,
1223 begin_of_direntry(direntry
),le32_to_cpu(direntry
->size
));
1227 static void print_mapping(const mapping_t
* mapping
)
1229 fprintf(stderr
, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1230 "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1231 mapping
, mapping
->begin
, mapping
->end
, mapping
->dir_index
,
1232 mapping
->first_mapping_index
, mapping
->path
, mapping
->mode
);
1234 if (mapping
->mode
& MODE_DIRECTORY
)
1235 fprintf(stderr
, "parent_mapping_index = %d, first_dir_index = %d\n", mapping
->info
.dir
.parent_mapping_index
, mapping
->info
.dir
.first_dir_index
);
1237 fprintf(stderr
, "offset = %d\n", mapping
->info
.file
.offset
);
1241 static int vvfat_read(BlockDriverState
*bs
, int64_t sector_num
,
1242 uint8_t *buf
, int nb_sectors
)
1244 BDRVVVFATState
*s
= bs
->opaque
;
1247 for(i
=0;i
<nb_sectors
;i
++,sector_num
++) {
1248 if (sector_num
>= s
->sector_count
)
1252 if (s
->qcow
->drv
->bdrv_is_allocated(s
->qcow
,
1253 sector_num
, nb_sectors
-i
, &n
)) {
1254 DLOG(fprintf(stderr
, "sectors %d+%d allocated\n", (int)sector_num
, n
));
1255 if (s
->qcow
->drv
->bdrv_read(s
->qcow
, sector_num
, buf
+i
*0x200, n
))
1258 sector_num
+= n
- 1;
1261 DLOG(fprintf(stderr
, "sector %d not allocated\n", (int)sector_num
));
1263 if(sector_num
<s
->faked_sectors
) {
1264 if(sector_num
<s
->first_sectors_number
)
1265 memcpy(buf
+i
*0x200,&(s
->first_sectors
[sector_num
*0x200]),0x200);
1266 else if(sector_num
-s
->first_sectors_number
<s
->sectors_per_fat
)
1267 memcpy(buf
+i
*0x200,&(s
->fat
.pointer
[(sector_num
-s
->first_sectors_number
)*0x200]),0x200);
1268 else if(sector_num
-s
->first_sectors_number
-s
->sectors_per_fat
<s
->sectors_per_fat
)
1269 memcpy(buf
+i
*0x200,&(s
->fat
.pointer
[(sector_num
-s
->first_sectors_number
-s
->sectors_per_fat
)*0x200]),0x200);
1271 uint32_t sector
=sector_num
-s
->faked_sectors
,
1272 sector_offset_in_cluster
=(sector
%s
->sectors_per_cluster
),
1273 cluster_num
=sector
/s
->sectors_per_cluster
;
1274 if(read_cluster(s
, cluster_num
) != 0) {
1275 /* LATER TODO: strict: return -1; */
1276 memset(buf
+i
*0x200,0,0x200);
1279 memcpy(buf
+i
*0x200,s
->cluster
+sector_offset_in_cluster
*0x200,0x200);
1285 static coroutine_fn
int vvfat_co_read(BlockDriverState
*bs
, int64_t sector_num
,
1286 uint8_t *buf
, int nb_sectors
)
1289 BDRVVVFATState
*s
= bs
->opaque
;
1290 qemu_co_mutex_lock(&s
->lock
);
1291 ret
= vvfat_read(bs
, sector_num
, buf
, nb_sectors
);
1292 qemu_co_mutex_unlock(&s
->lock
);
1296 /* LATER TODO: statify all functions */
1299 * Idea of the write support (use snapshot):
1301 * 1. check if all data is consistent, recording renames, modifications,
1302 * new files and directories (in s->commits).
1304 * 2. if the data is not consistent, stop committing
1306 * 3. handle renames, and create new files and directories (do not yet
1307 * write their contents)
1309 * 4. walk the directories, fixing the mapping and direntries, and marking
1310 * the handled mappings as not deleted
1312 * 5. commit the contents of the files
1314 * 6. handle deleted files and directories
1318 typedef struct commit_t
{
1321 struct { uint32_t cluster
; } rename
;
1322 struct { int dir_index
; uint32_t modified_offset
; } writeout
;
1323 struct { uint32_t first_cluster
; } new_file
;
1324 struct { uint32_t cluster
; } mkdir
;
1326 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1328 ACTION_RENAME
, ACTION_WRITEOUT
, ACTION_NEW_FILE
, ACTION_MKDIR
1332 static void clear_commits(BDRVVVFATState
* s
)
1335 DLOG(fprintf(stderr
, "clear_commits (%d commits)\n", s
->commits
.next
));
1336 for (i
= 0; i
< s
->commits
.next
; i
++) {
1337 commit_t
* commit
= array_get(&(s
->commits
), i
);
1338 assert(commit
->path
|| commit
->action
== ACTION_WRITEOUT
);
1339 if (commit
->action
!= ACTION_WRITEOUT
) {
1340 assert(commit
->path
);
1341 g_free(commit
->path
);
1343 assert(commit
->path
== NULL
);
1345 s
->commits
.next
= 0;
1348 static void schedule_rename(BDRVVVFATState
* s
,
1349 uint32_t cluster
, char* new_path
)
1351 commit_t
* commit
= array_get_next(&(s
->commits
));
1352 commit
->path
= new_path
;
1353 commit
->param
.rename
.cluster
= cluster
;
1354 commit
->action
= ACTION_RENAME
;
1357 static void schedule_writeout(BDRVVVFATState
* s
,
1358 int dir_index
, uint32_t modified_offset
)
1360 commit_t
* commit
= array_get_next(&(s
->commits
));
1361 commit
->path
= NULL
;
1362 commit
->param
.writeout
.dir_index
= dir_index
;
1363 commit
->param
.writeout
.modified_offset
= modified_offset
;
1364 commit
->action
= ACTION_WRITEOUT
;
1367 static void schedule_new_file(BDRVVVFATState
* s
,
1368 char* path
, uint32_t first_cluster
)
1370 commit_t
* commit
= array_get_next(&(s
->commits
));
1371 commit
->path
= path
;
1372 commit
->param
.new_file
.first_cluster
= first_cluster
;
1373 commit
->action
= ACTION_NEW_FILE
;
1376 static void schedule_mkdir(BDRVVVFATState
* s
, uint32_t cluster
, char* path
)
1378 commit_t
* commit
= array_get_next(&(s
->commits
));
1379 commit
->path
= path
;
1380 commit
->param
.mkdir
.cluster
= cluster
;
1381 commit
->action
= ACTION_MKDIR
;
1386 * Since the sequence number is at most 0x3f, and the filename
1387 * length is at most 13 times the sequence number, the maximal
1388 * filename length is 0x3f * 13 bytes.
1390 unsigned char name
[0x3f * 13 + 1];
1392 int sequence_number
;
1395 static void lfn_init(long_file_name
* lfn
)
1397 lfn
->sequence_number
= lfn
->len
= 0;
1398 lfn
->checksum
= 0x100;
1401 /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1402 static int parse_long_name(long_file_name
* lfn
,
1403 const direntry_t
* direntry
)
1406 const unsigned char* pointer
= (const unsigned char*)direntry
;
1408 if (!is_long_name(direntry
))
1411 if (pointer
[0] & 0x40) {
1412 lfn
->sequence_number
= pointer
[0] & 0x3f;
1413 lfn
->checksum
= pointer
[13];
1415 lfn
->name
[lfn
->sequence_number
* 13] = 0;
1416 } else if ((pointer
[0] & 0x3f) != --lfn
->sequence_number
)
1418 else if (pointer
[13] != lfn
->checksum
)
1420 else if (pointer
[12] || pointer
[26] || pointer
[27])
1423 offset
= 13 * (lfn
->sequence_number
- 1);
1424 for (i
= 0, j
= 1; i
< 13; i
++, j
+=2) {
1430 if (pointer
[j
+1] == 0)
1431 lfn
->name
[offset
+ i
] = pointer
[j
];
1432 else if (pointer
[j
+1] != 0xff || (pointer
[0] & 0x40) == 0)
1435 lfn
->name
[offset
+ i
] = 0;
1438 if (pointer
[0] & 0x40)
1439 lfn
->len
= offset
+ strlen((char*)lfn
->name
+ offset
);
1444 /* returns 0 if successful, >0 if no short_name, and <0 on error */
1445 static int parse_short_name(BDRVVVFATState
* s
,
1446 long_file_name
* lfn
, direntry_t
* direntry
)
1450 if (!is_short_name(direntry
))
1453 for (j
= 7; j
>= 0 && direntry
->name
[j
] == ' '; j
--);
1454 for (i
= 0; i
<= j
; i
++) {
1455 if (direntry
->name
[i
] <= ' ' || direntry
->name
[i
] > 0x7f)
1457 else if (s
->downcase_short_names
)
1458 lfn
->name
[i
] = qemu_tolower(direntry
->name
[i
]);
1460 lfn
->name
[i
] = direntry
->name
[i
];
1463 for (j
= 2; j
>= 0 && direntry
->extension
[j
] == ' '; j
--);
1465 lfn
->name
[i
++] = '.';
1466 lfn
->name
[i
+ j
+ 1] = '\0';
1467 for (;j
>= 0; j
--) {
1468 if (direntry
->extension
[j
] <= ' ' || direntry
->extension
[j
] > 0x7f)
1470 else if (s
->downcase_short_names
)
1471 lfn
->name
[i
+ j
] = qemu_tolower(direntry
->extension
[j
]);
1473 lfn
->name
[i
+ j
] = direntry
->extension
[j
];
1476 lfn
->name
[i
+ j
+ 1] = '\0';
1478 lfn
->len
= strlen((char*)lfn
->name
);
1483 static inline uint32_t modified_fat_get(BDRVVVFATState
* s
,
1484 unsigned int cluster
)
1486 if (cluster
< s
->last_cluster_of_root_directory
) {
1487 if (cluster
+ 1 == s
->last_cluster_of_root_directory
)
1488 return s
->max_fat_value
;
1493 if (s
->fat_type
==32) {
1494 uint32_t* entry
=((uint32_t*)s
->fat2
)+cluster
;
1495 return le32_to_cpu(*entry
);
1496 } else if (s
->fat_type
==16) {
1497 uint16_t* entry
=((uint16_t*)s
->fat2
)+cluster
;
1498 return le16_to_cpu(*entry
);
1500 const uint8_t* x
=s
->fat2
+cluster
*3/2;
1501 return ((x
[0]|(x
[1]<<8))>>(cluster
&1?4:0))&0x0fff;
1505 static inline int cluster_was_modified(BDRVVVFATState
* s
, uint32_t cluster_num
)
1507 int was_modified
= 0;
1510 if (s
->qcow
== NULL
)
1513 for (i
= 0; !was_modified
&& i
< s
->sectors_per_cluster
; i
++)
1514 was_modified
= s
->qcow
->drv
->bdrv_is_allocated(s
->qcow
,
1515 cluster2sector(s
, cluster_num
) + i
, 1, &dummy
);
1517 return was_modified
;
1520 static const char* get_basename(const char* path
)
1522 char* basename
= strrchr(path
, '/');
1523 if (basename
== NULL
)
1526 return basename
+ 1; /* strip '/' */
1530 * The array s->used_clusters holds the states of the clusters. If it is
1531 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1532 * was modified, bit 3 is set.
1533 * If any cluster is allocated, but not part of a file or directory, this
1534 * driver refuses to commit.
1537 USED_DIRECTORY
= 1, USED_FILE
= 2, USED_ANY
= 3, USED_ALLOCATED
= 4
1541 * get_cluster_count_for_direntry() not only determines how many clusters
1542 * are occupied by direntry, but also if it was renamed or modified.
1544 * A file is thought to be renamed *only* if there already was a file with
1545 * exactly the same first cluster, but a different name.
1547 * Further, the files/directories handled by this function are
1548 * assumed to be *not* deleted (and *only* those).
1550 static uint32_t get_cluster_count_for_direntry(BDRVVVFATState
* s
,
1551 direntry_t
* direntry
, const char* path
)
1554 * This is a little bit tricky:
1555 * IF the guest OS just inserts a cluster into the file chain,
1556 * and leaves the rest alone, (i.e. the original file had clusters
1557 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1559 * - do_commit will write the cluster into the file at the given
1562 * - the cluster which is overwritten should be moved to a later
1563 * position in the file.
1565 * I am not aware that any OS does something as braindead, but this
1566 * situation could happen anyway when not committing for a long time.
1567 * Just to be sure that this does not bite us, detect it, and copy the
1568 * contents of the clusters to-be-overwritten into the qcow.
1571 int was_modified
= 0;
1574 uint32_t cluster_num
= begin_of_direntry(direntry
);
1575 uint32_t offset
= 0;
1576 int first_mapping_index
= -1;
1577 mapping_t
* mapping
= NULL
;
1578 const char* basename2
= NULL
;
1580 vvfat_close_current_file(s
);
1582 /* the root directory */
1583 if (cluster_num
== 0)
1588 basename2
= get_basename(path
);
1590 mapping
= find_mapping_for_cluster(s
, cluster_num
);
1593 const char* basename
;
1595 assert(mapping
->mode
& MODE_DELETED
);
1596 mapping
->mode
&= ~MODE_DELETED
;
1598 basename
= get_basename(mapping
->path
);
1600 assert(mapping
->mode
& MODE_NORMAL
);
1603 if (strcmp(basename
, basename2
))
1604 schedule_rename(s
, cluster_num
, g_strdup(path
));
1605 } else if (is_file(direntry
))
1607 schedule_new_file(s
, g_strdup(path
), cluster_num
);
1616 if (!copy_it
&& cluster_was_modified(s
, cluster_num
)) {
1617 if (mapping
== NULL
||
1618 mapping
->begin
> cluster_num
||
1619 mapping
->end
<= cluster_num
)
1620 mapping
= find_mapping_for_cluster(s
, cluster_num
);
1624 (mapping
->mode
& MODE_DIRECTORY
) == 0) {
1626 /* was modified in qcow */
1627 if (offset
!= mapping
->info
.file
.offset
+ s
->cluster_size
1628 * (cluster_num
- mapping
->begin
)) {
1629 /* offset of this cluster in file chain has changed */
1632 } else if (offset
== 0) {
1633 const char* basename
= get_basename(mapping
->path
);
1635 if (strcmp(basename
, basename2
))
1637 first_mapping_index
= array_index(&(s
->mapping
), mapping
);
1640 if (mapping
->first_mapping_index
!= first_mapping_index
1641 && mapping
->info
.file
.offset
> 0) {
1646 /* need to write out? */
1647 if (!was_modified
&& is_file(direntry
)) {
1649 schedule_writeout(s
, mapping
->dir_index
, offset
);
1657 * This is horribly inefficient, but that is okay, since
1658 * it is rarely executed, if at all.
1660 int64_t offset
= cluster2sector(s
, cluster_num
);
1662 vvfat_close_current_file(s
);
1663 for (i
= 0; i
< s
->sectors_per_cluster
; i
++)
1664 if (!s
->qcow
->drv
->bdrv_is_allocated(s
->qcow
,
1665 offset
+ i
, 1, &dummy
)) {
1666 if (vvfat_read(s
->bs
,
1667 offset
, s
->cluster_buffer
, 1))
1669 if (s
->qcow
->drv
->bdrv_write(s
->qcow
,
1670 offset
, s
->cluster_buffer
, 1))
1677 if (s
->used_clusters
[cluster_num
] & USED_ANY
)
1679 s
->used_clusters
[cluster_num
] = USED_FILE
;
1681 cluster_num
= modified_fat_get(s
, cluster_num
);
1683 if (fat_eof(s
, cluster_num
))
1685 else if (cluster_num
< 2 || cluster_num
> s
->max_fat_value
- 16)
1688 offset
+= s
->cluster_size
;
1693 * This function looks at the modified data (qcow).
1694 * It returns 0 upon inconsistency or error, and the number of clusters
1695 * used by the directory, its subdirectories and their files.
1697 static int check_directory_consistency(BDRVVVFATState
*s
,
1698 int cluster_num
, const char* path
)
1701 unsigned char* cluster
= g_malloc(s
->cluster_size
);
1702 direntry_t
* direntries
= (direntry_t
*)cluster
;
1703 mapping_t
* mapping
= find_mapping_for_cluster(s
, cluster_num
);
1706 int path_len
= strlen(path
);
1707 char path2
[PATH_MAX
+ 1];
1709 assert(path_len
< PATH_MAX
); /* len was tested before! */
1710 pstrcpy(path2
, sizeof(path2
), path
);
1711 path2
[path_len
] = '/';
1712 path2
[path_len
+ 1] = '\0';
1715 const char* basename
= get_basename(mapping
->path
);
1716 const char* basename2
= get_basename(path
);
1718 assert(mapping
->mode
& MODE_DIRECTORY
);
1720 assert(mapping
->mode
& MODE_DELETED
);
1721 mapping
->mode
&= ~MODE_DELETED
;
1723 if (strcmp(basename
, basename2
))
1724 schedule_rename(s
, cluster_num
, g_strdup(path
));
1727 schedule_mkdir(s
, cluster_num
, g_strdup(path
));
1736 if (s
->used_clusters
[cluster_num
] & USED_ANY
) {
1737 fprintf(stderr
, "cluster %d used more than once\n", (int)cluster_num
);
1740 s
->used_clusters
[cluster_num
] = USED_DIRECTORY
;
1742 DLOG(fprintf(stderr
, "read cluster %d (sector %d)\n", (int)cluster_num
, (int)cluster2sector(s
, cluster_num
)));
1743 subret
= vvfat_read(s
->bs
, cluster2sector(s
, cluster_num
), cluster
,
1744 s
->sectors_per_cluster
);
1746 fprintf(stderr
, "Error fetching direntries\n");
1752 for (i
= 0; i
< 0x10 * s
->sectors_per_cluster
; i
++) {
1753 int cluster_count
= 0;
1755 DLOG(fprintf(stderr
, "check direntry %d:\n", i
); print_direntry(direntries
+ i
));
1756 if (is_volume_label(direntries
+ i
) || is_dot(direntries
+ i
) ||
1757 is_free(direntries
+ i
))
1760 subret
= parse_long_name(&lfn
, direntries
+ i
);
1762 fprintf(stderr
, "Error in long name\n");
1765 if (subret
== 0 || is_free(direntries
+ i
))
1768 if (fat_chksum(direntries
+i
) != lfn
.checksum
) {
1769 subret
= parse_short_name(s
, &lfn
, direntries
+ i
);
1771 fprintf(stderr
, "Error in short name (%d)\n", subret
);
1774 if (subret
> 0 || !strcmp((char*)lfn
.name
, ".")
1775 || !strcmp((char*)lfn
.name
, ".."))
1778 lfn
.checksum
= 0x100; /* cannot use long name twice */
1780 if (path_len
+ 1 + lfn
.len
>= PATH_MAX
) {
1781 fprintf(stderr
, "Name too long: %s/%s\n", path
, lfn
.name
);
1784 pstrcpy(path2
+ path_len
+ 1, sizeof(path2
) - path_len
- 1,
1787 if (is_directory(direntries
+ i
)) {
1788 if (begin_of_direntry(direntries
+ i
) == 0) {
1789 DLOG(fprintf(stderr
, "invalid begin for directory: %s\n", path2
); print_direntry(direntries
+ i
));
1792 cluster_count
= check_directory_consistency(s
,
1793 begin_of_direntry(direntries
+ i
), path2
);
1794 if (cluster_count
== 0) {
1795 DLOG(fprintf(stderr
, "problem in directory %s:\n", path2
); print_direntry(direntries
+ i
));
1798 } else if (is_file(direntries
+ i
)) {
1799 /* check file size with FAT */
1800 cluster_count
= get_cluster_count_for_direntry(s
, direntries
+ i
, path2
);
1801 if (cluster_count
!=
1802 (le32_to_cpu(direntries
[i
].size
) + s
->cluster_size
1803 - 1) / s
->cluster_size
) {
1804 DLOG(fprintf(stderr
, "Cluster count mismatch\n"));
1808 abort(); /* cluster_count = 0; */
1810 ret
+= cluster_count
;
1813 cluster_num
= modified_fat_get(s
, cluster_num
);
1814 } while(!fat_eof(s
, cluster_num
));
1820 /* returns 1 on success */
1821 static int is_consistent(BDRVVVFATState
* s
)
1824 int used_clusters_count
= 0;
1828 * - get modified FAT
1829 * - compare the two FATs (TODO)
1830 * - get buffer for marking used clusters
1831 * - recurse direntries from root (using bs->bdrv_read to make
1832 * sure to get the new data)
1833 * - check that the FAT agrees with the size
1834 * - count the number of clusters occupied by this directory and
1836 * - check that the cumulative used cluster count agrees with the
1838 * - if all is fine, return number of used clusters
1840 if (s
->fat2
== NULL
) {
1841 int size
= 0x200 * s
->sectors_per_fat
;
1842 s
->fat2
= g_malloc(size
);
1843 memcpy(s
->fat2
, s
->fat
.pointer
, size
);
1845 check
= vvfat_read(s
->bs
,
1846 s
->first_sectors_number
, s
->fat2
, s
->sectors_per_fat
);
1848 fprintf(stderr
, "Could not copy fat\n");
1851 assert (s
->used_clusters
);
1852 for (i
= 0; i
< sector2cluster(s
, s
->sector_count
); i
++)
1853 s
->used_clusters
[i
] &= ~USED_ANY
;
1857 /* mark every mapped file/directory as deleted.
1858 * (check_directory_consistency() will unmark those still present). */
1860 for (i
= 0; i
< s
->mapping
.next
; i
++) {
1861 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
1862 if (mapping
->first_mapping_index
< 0)
1863 mapping
->mode
|= MODE_DELETED
;
1866 used_clusters_count
= check_directory_consistency(s
, 0, s
->path
);
1867 if (used_clusters_count
<= 0) {
1868 DLOG(fprintf(stderr
, "problem in directory\n"));
1872 check
= s
->last_cluster_of_root_directory
;
1873 for (i
= check
; i
< sector2cluster(s
, s
->sector_count
); i
++) {
1874 if (modified_fat_get(s
, i
)) {
1875 if(!s
->used_clusters
[i
]) {
1876 DLOG(fprintf(stderr
, "FAT was modified (%d), but cluster is not used?\n", i
));
1882 if (s
->used_clusters
[i
] == USED_ALLOCATED
) {
1883 /* allocated, but not used... */
1884 DLOG(fprintf(stderr
, "unused, modified cluster: %d\n", i
));
1889 if (check
!= used_clusters_count
)
1892 return used_clusters_count
;
1895 static inline void adjust_mapping_indices(BDRVVVFATState
* s
,
1896 int offset
, int adjust
)
1900 for (i
= 0; i
< s
->mapping
.next
; i
++) {
1901 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
1903 #define ADJUST_MAPPING_INDEX(name) \
1904 if (mapping->name >= offset) \
1905 mapping->name += adjust
1907 ADJUST_MAPPING_INDEX(first_mapping_index
);
1908 if (mapping
->mode
& MODE_DIRECTORY
)
1909 ADJUST_MAPPING_INDEX(info
.dir
.parent_mapping_index
);
1913 /* insert or update mapping */
1914 static mapping_t
* insert_mapping(BDRVVVFATState
* s
,
1915 uint32_t begin
, uint32_t end
)
1918 * - find mapping where mapping->begin >= begin,
1919 * - if mapping->begin > begin: insert
1920 * - adjust all references to mappings!
1924 int index
= find_mapping_for_cluster_aux(s
, begin
, 0, s
->mapping
.next
);
1925 mapping_t
* mapping
= NULL
;
1926 mapping_t
* first_mapping
= array_get(&(s
->mapping
), 0);
1928 if (index
< s
->mapping
.next
&& (mapping
= array_get(&(s
->mapping
), index
))
1929 && mapping
->begin
< begin
) {
1930 mapping
->end
= begin
;
1932 mapping
= array_get(&(s
->mapping
), index
);
1934 if (index
>= s
->mapping
.next
|| mapping
->begin
> begin
) {
1935 mapping
= array_insert(&(s
->mapping
), index
, 1);
1936 mapping
->path
= NULL
;
1937 adjust_mapping_indices(s
, index
, +1);
1940 mapping
->begin
= begin
;
1943 DLOG(mapping_t
* next_mapping
;
1944 assert(index
+ 1 >= s
->mapping
.next
||
1945 ((next_mapping
= array_get(&(s
->mapping
), index
+ 1)) &&
1946 next_mapping
->begin
>= end
)));
1948 if (s
->current_mapping
&& first_mapping
!= (mapping_t
*)s
->mapping
.pointer
)
1949 s
->current_mapping
= array_get(&(s
->mapping
),
1950 s
->current_mapping
- first_mapping
);
1955 static int remove_mapping(BDRVVVFATState
* s
, int mapping_index
)
1957 mapping_t
* mapping
= array_get(&(s
->mapping
), mapping_index
);
1958 mapping_t
* first_mapping
= array_get(&(s
->mapping
), 0);
1961 if (mapping
->first_mapping_index
< 0) {
1962 g_free(mapping
->path
);
1965 /* remove from s->mapping */
1966 array_remove(&(s
->mapping
), mapping_index
);
1968 /* adjust all references to mappings */
1969 adjust_mapping_indices(s
, mapping_index
, -1);
1971 if (s
->current_mapping
&& first_mapping
!= (mapping_t
*)s
->mapping
.pointer
)
1972 s
->current_mapping
= array_get(&(s
->mapping
),
1973 s
->current_mapping
- first_mapping
);
1978 static void adjust_dirindices(BDRVVVFATState
* s
, int offset
, int adjust
)
1981 for (i
= 0; i
< s
->mapping
.next
; i
++) {
1982 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
1983 if (mapping
->dir_index
>= offset
)
1984 mapping
->dir_index
+= adjust
;
1985 if ((mapping
->mode
& MODE_DIRECTORY
) &&
1986 mapping
->info
.dir
.first_dir_index
>= offset
)
1987 mapping
->info
.dir
.first_dir_index
+= adjust
;
1991 static direntry_t
* insert_direntries(BDRVVVFATState
* s
,
1992 int dir_index
, int count
)
1995 * make room in s->directory,
1998 direntry_t
* result
= array_insert(&(s
->directory
), dir_index
, count
);
2001 adjust_dirindices(s
, dir_index
, count
);
2005 static int remove_direntries(BDRVVVFATState
* s
, int dir_index
, int count
)
2007 int ret
= array_remove_slice(&(s
->directory
), dir_index
, count
);
2010 adjust_dirindices(s
, dir_index
, -count
);
2015 * Adapt the mappings of the cluster chain starting at first cluster
2016 * (i.e. if a file starts at first_cluster, the chain is followed according
2017 * to the modified fat, and the corresponding entries in s->mapping are
2020 static int commit_mappings(BDRVVVFATState
* s
,
2021 uint32_t first_cluster
, int dir_index
)
2023 mapping_t
* mapping
= find_mapping_for_cluster(s
, first_cluster
);
2024 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2025 uint32_t cluster
= first_cluster
;
2027 vvfat_close_current_file(s
);
2030 assert(mapping
->begin
== first_cluster
);
2031 mapping
->first_mapping_index
= -1;
2032 mapping
->dir_index
= dir_index
;
2033 mapping
->mode
= (dir_index
<= 0 || is_directory(direntry
)) ?
2034 MODE_DIRECTORY
: MODE_NORMAL
;
2036 while (!fat_eof(s
, cluster
)) {
2039 for (c
= cluster
, c1
= modified_fat_get(s
, c
); c
+ 1 == c1
;
2040 c
= c1
, c1
= modified_fat_get(s
, c1
));
2043 if (c
> mapping
->end
) {
2044 int index
= array_index(&(s
->mapping
), mapping
);
2045 int i
, max_i
= s
->mapping
.next
- index
;
2046 for (i
= 1; i
< max_i
&& mapping
[i
].begin
< c
; i
++);
2048 remove_mapping(s
, index
+ 1);
2050 assert(mapping
== array_get(&(s
->mapping
), s
->mapping
.next
- 1)
2051 || mapping
[1].begin
>= c
);
2054 if (!fat_eof(s
, c1
)) {
2055 int i
= find_mapping_for_cluster_aux(s
, c1
, 0, s
->mapping
.next
);
2056 mapping_t
* next_mapping
= i
>= s
->mapping
.next
? NULL
:
2057 array_get(&(s
->mapping
), i
);
2059 if (next_mapping
== NULL
|| next_mapping
->begin
> c1
) {
2060 int i1
= array_index(&(s
->mapping
), mapping
);
2062 next_mapping
= insert_mapping(s
, c1
, c1
+1);
2066 mapping
= array_get(&(s
->mapping
), i1
);
2069 next_mapping
->dir_index
= mapping
->dir_index
;
2070 next_mapping
->first_mapping_index
=
2071 mapping
->first_mapping_index
< 0 ?
2072 array_index(&(s
->mapping
), mapping
) :
2073 mapping
->first_mapping_index
;
2074 next_mapping
->path
= mapping
->path
;
2075 next_mapping
->mode
= mapping
->mode
;
2076 next_mapping
->read_only
= mapping
->read_only
;
2077 if (mapping
->mode
& MODE_DIRECTORY
) {
2078 next_mapping
->info
.dir
.parent_mapping_index
=
2079 mapping
->info
.dir
.parent_mapping_index
;
2080 next_mapping
->info
.dir
.first_dir_index
=
2081 mapping
->info
.dir
.first_dir_index
+
2082 0x10 * s
->sectors_per_cluster
*
2083 (mapping
->end
- mapping
->begin
);
2085 next_mapping
->info
.file
.offset
= mapping
->info
.file
.offset
+
2086 mapping
->end
- mapping
->begin
;
2088 mapping
= next_mapping
;
2097 static int commit_direntries(BDRVVVFATState
* s
,
2098 int dir_index
, int parent_mapping_index
)
2100 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2101 uint32_t first_cluster
= dir_index
== 0 ? 0 : begin_of_direntry(direntry
);
2102 mapping_t
* mapping
= find_mapping_for_cluster(s
, first_cluster
);
2104 int factor
= 0x10 * s
->sectors_per_cluster
;
2105 int old_cluster_count
, new_cluster_count
;
2106 int current_dir_index
= mapping
->info
.dir
.first_dir_index
;
2107 int first_dir_index
= current_dir_index
;
2111 DLOG(fprintf(stderr
, "commit_direntries for %s, parent_mapping_index %d\n", mapping
->path
, parent_mapping_index
));
2115 assert(mapping
->begin
== first_cluster
);
2116 assert(mapping
->info
.dir
.first_dir_index
< s
->directory
.next
);
2117 assert(mapping
->mode
& MODE_DIRECTORY
);
2118 assert(dir_index
== 0 || is_directory(direntry
));
2120 mapping
->info
.dir
.parent_mapping_index
= parent_mapping_index
;
2122 if (first_cluster
== 0) {
2123 old_cluster_count
= new_cluster_count
=
2124 s
->last_cluster_of_root_directory
;
2126 for (old_cluster_count
= 0, c
= first_cluster
; !fat_eof(s
, c
);
2128 old_cluster_count
++;
2130 for (new_cluster_count
= 0, c
= first_cluster
; !fat_eof(s
, c
);
2131 c
= modified_fat_get(s
, c
))
2132 new_cluster_count
++;
2135 if (new_cluster_count
> old_cluster_count
) {
2136 if (insert_direntries(s
,
2137 current_dir_index
+ factor
* old_cluster_count
,
2138 factor
* (new_cluster_count
- old_cluster_count
)) == NULL
)
2140 } else if (new_cluster_count
< old_cluster_count
)
2141 remove_direntries(s
,
2142 current_dir_index
+ factor
* new_cluster_count
,
2143 factor
* (old_cluster_count
- new_cluster_count
));
2145 for (c
= first_cluster
; !fat_eof(s
, c
); c
= modified_fat_get(s
, c
)) {
2146 void* direntry
= array_get(&(s
->directory
), current_dir_index
);
2147 int ret
= vvfat_read(s
->bs
, cluster2sector(s
, c
), direntry
,
2148 s
->sectors_per_cluster
);
2151 assert(!strncmp(s
->directory
.pointer
, "QEMU", 4));
2152 current_dir_index
+= factor
;
2155 ret
= commit_mappings(s
, first_cluster
, dir_index
);
2160 for (i
= 0; i
< factor
* new_cluster_count
; i
++) {
2161 direntry
= array_get(&(s
->directory
), first_dir_index
+ i
);
2162 if (is_directory(direntry
) && !is_dot(direntry
)) {
2163 mapping
= find_mapping_for_cluster(s
, first_cluster
);
2164 assert(mapping
->mode
& MODE_DIRECTORY
);
2165 ret
= commit_direntries(s
, first_dir_index
+ i
,
2166 array_index(&(s
->mapping
), mapping
));
2175 /* commit one file (adjust contents, adjust mapping),
2176 return first_mapping_index */
2177 static int commit_one_file(BDRVVVFATState
* s
,
2178 int dir_index
, uint32_t offset
)
2180 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2181 uint32_t c
= begin_of_direntry(direntry
);
2182 uint32_t first_cluster
= c
;
2183 mapping_t
* mapping
= find_mapping_for_cluster(s
, c
);
2184 uint32_t size
= filesize_of_direntry(direntry
);
2185 char* cluster
= g_malloc(s
->cluster_size
);
2189 assert(offset
< size
);
2190 assert((offset
% s
->cluster_size
) == 0);
2192 for (i
= s
->cluster_size
; i
< offset
; i
+= s
->cluster_size
)
2193 c
= modified_fat_get(s
, c
);
2195 fd
= open(mapping
->path
, O_RDWR
| O_CREAT
| O_BINARY
, 0666);
2197 fprintf(stderr
, "Could not open %s... (%s, %d)\n", mapping
->path
,
2198 strerror(errno
), errno
);
2203 if (lseek(fd
, offset
, SEEK_SET
) != offset
) {
2209 while (offset
< size
) {
2211 int rest_size
= (size
- offset
> s
->cluster_size
?
2212 s
->cluster_size
: size
- offset
);
2215 c1
= modified_fat_get(s
, c
);
2217 assert((size
- offset
== 0 && fat_eof(s
, c
)) ||
2218 (size
> offset
&& c
>=2 && !fat_eof(s
, c
)));
2220 ret
= vvfat_read(s
->bs
, cluster2sector(s
, c
),
2221 (uint8_t*)cluster
, (rest_size
+ 0x1ff) / 0x200);
2228 if (write(fd
, cluster
, rest_size
) < 0) {
2233 offset
+= rest_size
;
2237 if (ftruncate(fd
, size
)) {
2238 perror("ftruncate()");
2246 return commit_mappings(s
, first_cluster
, dir_index
);
2250 /* test, if all mappings point to valid direntries */
2251 static void check1(BDRVVVFATState
* s
)
2254 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2255 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2256 if (mapping
->mode
& MODE_DELETED
) {
2257 fprintf(stderr
, "deleted\n");
2260 assert(mapping
->dir_index
< s
->directory
.next
);
2261 direntry_t
* direntry
= array_get(&(s
->directory
), mapping
->dir_index
);
2262 assert(mapping
->begin
== begin_of_direntry(direntry
) || mapping
->first_mapping_index
>= 0);
2263 if (mapping
->mode
& MODE_DIRECTORY
) {
2264 assert(mapping
->info
.dir
.first_dir_index
+ 0x10 * s
->sectors_per_cluster
* (mapping
->end
- mapping
->begin
) <= s
->directory
.next
);
2265 assert((mapping
->info
.dir
.first_dir_index
% (0x10 * s
->sectors_per_cluster
)) == 0);
2270 /* test, if all direntries have mappings */
2271 static void check2(BDRVVVFATState
* s
)
2274 int first_mapping
= -1;
2276 for (i
= 0; i
< s
->directory
.next
; i
++) {
2277 direntry_t
* direntry
= array_get(&(s
->directory
), i
);
2279 if (is_short_name(direntry
) && begin_of_direntry(direntry
)) {
2280 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin_of_direntry(direntry
));
2282 assert(mapping
->dir_index
== i
|| is_dot(direntry
));
2283 assert(mapping
->begin
== begin_of_direntry(direntry
) || is_dot(direntry
));
2286 if ((i
% (0x10 * s
->sectors_per_cluster
)) == 0) {
2290 for (j
= 0; j
< s
->mapping
.next
; j
++) {
2291 mapping_t
* mapping
= array_get(&(s
->mapping
), j
);
2292 if (mapping
->mode
& MODE_DELETED
)
2294 if (mapping
->mode
& MODE_DIRECTORY
) {
2295 if (mapping
->info
.dir
.first_dir_index
<= i
&& mapping
->info
.dir
.first_dir_index
+ 0x10 * s
->sectors_per_cluster
> i
) {
2296 assert(++count
== 1);
2297 if (mapping
->first_mapping_index
== -1)
2298 first_mapping
= array_index(&(s
->mapping
), mapping
);
2300 assert(first_mapping
== mapping
->first_mapping_index
);
2301 if (mapping
->info
.dir
.parent_mapping_index
< 0)
2304 mapping_t
* parent
= array_get(&(s
->mapping
), mapping
->info
.dir
.parent_mapping_index
);
2305 assert(parent
->mode
& MODE_DIRECTORY
);
2306 assert(parent
->info
.dir
.first_dir_index
< mapping
->info
.dir
.first_dir_index
);
2318 static int handle_renames_and_mkdirs(BDRVVVFATState
* s
)
2323 fprintf(stderr
, "handle_renames\n");
2324 for (i
= 0; i
< s
->commits
.next
; i
++) {
2325 commit_t
* commit
= array_get(&(s
->commits
), i
);
2326 fprintf(stderr
, "%d, %s (%d, %d)\n", i
, commit
->path
? commit
->path
: "(null)", commit
->param
.rename
.cluster
, commit
->action
);
2330 for (i
= 0; i
< s
->commits
.next
;) {
2331 commit_t
* commit
= array_get(&(s
->commits
), i
);
2332 if (commit
->action
== ACTION_RENAME
) {
2333 mapping_t
* mapping
= find_mapping_for_cluster(s
,
2334 commit
->param
.rename
.cluster
);
2335 char* old_path
= mapping
->path
;
2337 assert(commit
->path
);
2338 mapping
->path
= commit
->path
;
2339 if (rename(old_path
, mapping
->path
))
2342 if (mapping
->mode
& MODE_DIRECTORY
) {
2343 int l1
= strlen(mapping
->path
);
2344 int l2
= strlen(old_path
);
2346 direntry_t
* direntry
= array_get(&(s
->directory
),
2347 mapping
->info
.dir
.first_dir_index
);
2348 uint32_t c
= mapping
->begin
;
2352 while (!fat_eof(s
, c
)) {
2354 direntry_t
* d
= direntry
+ i
;
2356 if (is_file(d
) || (is_directory(d
) && !is_dot(d
))) {
2357 mapping_t
* m
= find_mapping_for_cluster(s
,
2358 begin_of_direntry(d
));
2359 int l
= strlen(m
->path
);
2360 char* new_path
= g_malloc(l
+ diff
+ 1);
2362 assert(!strncmp(m
->path
, mapping
->path
, l2
));
2364 pstrcpy(new_path
, l
+ diff
+ 1, mapping
->path
);
2365 pstrcpy(new_path
+ l1
, l
+ diff
+ 1 - l1
,
2368 schedule_rename(s
, m
->begin
, new_path
);
2371 } while((i
% (0x10 * s
->sectors_per_cluster
)) != 0);
2377 array_remove(&(s
->commits
), i
);
2379 } else if (commit
->action
== ACTION_MKDIR
) {
2381 int j
, parent_path_len
;
2384 if (mkdir(commit
->path
))
2387 if (mkdir(commit
->path
, 0755))
2391 mapping
= insert_mapping(s
, commit
->param
.mkdir
.cluster
,
2392 commit
->param
.mkdir
.cluster
+ 1);
2393 if (mapping
== NULL
)
2396 mapping
->mode
= MODE_DIRECTORY
;
2397 mapping
->read_only
= 0;
2398 mapping
->path
= commit
->path
;
2399 j
= s
->directory
.next
;
2401 insert_direntries(s
, s
->directory
.next
,
2402 0x10 * s
->sectors_per_cluster
);
2403 mapping
->info
.dir
.first_dir_index
= j
;
2405 parent_path_len
= strlen(commit
->path
)
2406 - strlen(get_basename(commit
->path
)) - 1;
2407 for (j
= 0; j
< s
->mapping
.next
; j
++) {
2408 mapping_t
* m
= array_get(&(s
->mapping
), j
);
2409 if (m
->first_mapping_index
< 0 && m
!= mapping
&&
2410 !strncmp(m
->path
, mapping
->path
, parent_path_len
) &&
2411 strlen(m
->path
) == parent_path_len
)
2414 assert(j
< s
->mapping
.next
);
2415 mapping
->info
.dir
.parent_mapping_index
= j
;
2417 array_remove(&(s
->commits
), i
);
2427 * TODO: make sure that the short name is not matching *another* file
2429 static int handle_commits(BDRVVVFATState
* s
)
2433 vvfat_close_current_file(s
);
2435 for (i
= 0; !fail
&& i
< s
->commits
.next
; i
++) {
2436 commit_t
* commit
= array_get(&(s
->commits
), i
);
2437 switch(commit
->action
) {
2438 case ACTION_RENAME
: case ACTION_MKDIR
:
2442 case ACTION_WRITEOUT
: {
2444 /* these variables are only used by assert() below */
2445 direntry_t
* entry
= array_get(&(s
->directory
),
2446 commit
->param
.writeout
.dir_index
);
2447 uint32_t begin
= begin_of_direntry(entry
);
2448 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin
);
2452 assert(mapping
->begin
== begin
);
2453 assert(commit
->path
== NULL
);
2455 if (commit_one_file(s
, commit
->param
.writeout
.dir_index
,
2456 commit
->param
.writeout
.modified_offset
))
2461 case ACTION_NEW_FILE
: {
2462 int begin
= commit
->param
.new_file
.first_cluster
;
2463 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin
);
2468 for (i
= 0; i
< s
->directory
.next
; i
++) {
2469 entry
= array_get(&(s
->directory
), i
);
2470 if (is_file(entry
) && begin_of_direntry(entry
) == begin
)
2474 if (i
>= s
->directory
.next
) {
2479 /* make sure there exists an initial mapping */
2480 if (mapping
&& mapping
->begin
!= begin
) {
2481 mapping
->end
= begin
;
2484 if (mapping
== NULL
) {
2485 mapping
= insert_mapping(s
, begin
, begin
+1);
2487 /* most members will be fixed in commit_mappings() */
2488 assert(commit
->path
);
2489 mapping
->path
= commit
->path
;
2490 mapping
->read_only
= 0;
2491 mapping
->mode
= MODE_NORMAL
;
2492 mapping
->info
.file
.offset
= 0;
2494 if (commit_one_file(s
, i
, 0))
2503 if (i
> 0 && array_remove_slice(&(s
->commits
), 0, i
))
2508 static int handle_deletes(BDRVVVFATState
* s
)
2510 int i
, deferred
= 1, deleted
= 1;
2512 /* delete files corresponding to mappings marked as deleted */
2513 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2514 while (deferred
&& deleted
) {
2518 for (i
= 1; i
< s
->mapping
.next
; i
++) {
2519 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2520 if (mapping
->mode
& MODE_DELETED
) {
2521 direntry_t
* entry
= array_get(&(s
->directory
),
2522 mapping
->dir_index
);
2524 if (is_free(entry
)) {
2525 /* remove file/directory */
2526 if (mapping
->mode
& MODE_DIRECTORY
) {
2527 int j
, next_dir_index
= s
->directory
.next
,
2528 first_dir_index
= mapping
->info
.dir
.first_dir_index
;
2530 if (rmdir(mapping
->path
) < 0) {
2531 if (errno
== ENOTEMPTY
) {
2538 for (j
= 1; j
< s
->mapping
.next
; j
++) {
2539 mapping_t
* m
= array_get(&(s
->mapping
), j
);
2540 if (m
->mode
& MODE_DIRECTORY
&&
2541 m
->info
.dir
.first_dir_index
>
2543 m
->info
.dir
.first_dir_index
<
2546 m
->info
.dir
.first_dir_index
;
2548 remove_direntries(s
, first_dir_index
,
2549 next_dir_index
- first_dir_index
);
2554 if (unlink(mapping
->path
))
2558 DLOG(fprintf(stderr
, "DELETE (%d)\n", i
); print_mapping(mapping
); print_direntry(entry
));
2559 remove_mapping(s
, i
);
2568 * synchronize mapping with new state:
2570 * - copy FAT (with bdrv_read)
2571 * - mark all filenames corresponding to mappings as deleted
2572 * - recurse direntries from root (using bs->bdrv_read)
2573 * - delete files corresponding to mappings marked as deleted
2575 static int do_commit(BDRVVVFATState
* s
)
2579 /* the real meat are the commits. Nothing to do? Move along! */
2580 if (s
->commits
.next
== 0)
2583 vvfat_close_current_file(s
);
2585 ret
= handle_renames_and_mkdirs(s
);
2587 fprintf(stderr
, "Error handling renames (%d)\n", ret
);
2592 /* copy FAT (with bdrv_read) */
2593 memcpy(s
->fat
.pointer
, s
->fat2
, 0x200 * s
->sectors_per_fat
);
2595 /* recurse direntries from root (using bs->bdrv_read) */
2596 ret
= commit_direntries(s
, 0, -1);
2598 fprintf(stderr
, "Fatal: error while committing (%d)\n", ret
);
2603 ret
= handle_commits(s
);
2605 fprintf(stderr
, "Error handling commits (%d)\n", ret
);
2610 ret
= handle_deletes(s
);
2612 fprintf(stderr
, "Error deleting\n");
2617 s
->qcow
->drv
->bdrv_make_empty(s
->qcow
);
2619 memset(s
->used_clusters
, 0, sector2cluster(s
, s
->sector_count
));
2625 static int try_commit(BDRVVVFATState
* s
)
2627 vvfat_close_current_file(s
);
2629 if(!is_consistent(s
))
2631 return do_commit(s
);
2634 static int vvfat_write(BlockDriverState
*bs
, int64_t sector_num
,
2635 const uint8_t *buf
, int nb_sectors
)
2637 BDRVVVFATState
*s
= bs
->opaque
;
2642 /* Check if we're operating in read-only mode */
2643 if (s
->qcow
== NULL
) {
2647 vvfat_close_current_file(s
);
2650 * Some sanity checks:
2651 * - do not allow writing to the boot sector
2652 * - do not allow to write non-ASCII filenames
2655 if (sector_num
< s
->first_sectors_number
)
2658 for (i
= sector2cluster(s
, sector_num
);
2659 i
<= sector2cluster(s
, sector_num
+ nb_sectors
- 1);) {
2660 mapping_t
* mapping
= find_mapping_for_cluster(s
, i
);
2662 if (mapping
->read_only
) {
2663 fprintf(stderr
, "Tried to write to write-protected file %s\n",
2668 if (mapping
->mode
& MODE_DIRECTORY
) {
2669 int begin
= cluster2sector(s
, i
);
2670 int end
= begin
+ s
->sectors_per_cluster
, k
;
2672 const direntry_t
* direntries
;
2677 if (begin
< sector_num
)
2679 if (end
> sector_num
+ nb_sectors
)
2680 end
= sector_num
+ nb_sectors
;
2681 dir_index
= mapping
->dir_index
+
2682 0x10 * (begin
- mapping
->begin
* s
->sectors_per_cluster
);
2683 direntries
= (direntry_t
*)(buf
+ 0x200 * (begin
- sector_num
));
2685 for (k
= 0; k
< (end
- begin
) * 0x10; k
++) {
2686 /* do not allow non-ASCII filenames */
2687 if (parse_long_name(&lfn
, direntries
+ k
) < 0) {
2688 fprintf(stderr
, "Warning: non-ASCII filename\n");
2691 /* no access to the direntry of a read-only file */
2692 else if (is_short_name(direntries
+k
) &&
2693 (direntries
[k
].attributes
& 1)) {
2694 if (memcmp(direntries
+ k
,
2695 array_get(&(s
->directory
), dir_index
+ k
),
2696 sizeof(direntry_t
))) {
2697 fprintf(stderr
, "Warning: tried to write to write-protected file\n");
2709 * Use qcow backend. Commit later.
2711 DLOG(fprintf(stderr
, "Write to qcow backend: %d + %d\n", (int)sector_num
, nb_sectors
));
2712 ret
= s
->qcow
->drv
->bdrv_write(s
->qcow
, sector_num
, buf
, nb_sectors
);
2714 fprintf(stderr
, "Error writing to qcow backend\n");
2718 for (i
= sector2cluster(s
, sector_num
);
2719 i
<= sector2cluster(s
, sector_num
+ nb_sectors
- 1); i
++)
2721 s
->used_clusters
[i
] |= USED_ALLOCATED
;
2724 /* TODO: add timeout */
2731 static coroutine_fn
int vvfat_co_write(BlockDriverState
*bs
, int64_t sector_num
,
2732 const uint8_t *buf
, int nb_sectors
)
2735 BDRVVVFATState
*s
= bs
->opaque
;
2736 qemu_co_mutex_lock(&s
->lock
);
2737 ret
= vvfat_write(bs
, sector_num
, buf
, nb_sectors
);
2738 qemu_co_mutex_unlock(&s
->lock
);
2742 static int vvfat_is_allocated(BlockDriverState
*bs
,
2743 int64_t sector_num
, int nb_sectors
, int* n
)
2745 BDRVVVFATState
* s
= bs
->opaque
;
2746 *n
= s
->sector_count
- sector_num
;
2747 if (*n
> nb_sectors
)
2754 static int write_target_commit(BlockDriverState
*bs
, int64_t sector_num
,
2755 const uint8_t* buffer
, int nb_sectors
) {
2756 BDRVVVFATState
* s
= *((BDRVVVFATState
**) bs
->opaque
);
2757 return try_commit(s
);
2760 static void write_target_close(BlockDriverState
*bs
) {
2761 BDRVVVFATState
* s
= *((BDRVVVFATState
**) bs
->opaque
);
2762 bdrv_delete(s
->qcow
);
2763 g_free(s
->qcow_filename
);
2766 static BlockDriver vvfat_write_target
= {
2767 .format_name
= "vvfat_write_target",
2768 .bdrv_write
= write_target_commit
,
2769 .bdrv_close
= write_target_close
,
2772 static int enable_write_target(BDRVVVFATState
*s
)
2774 BlockDriver
*bdrv_qcow
;
2775 QEMUOptionParameter
*options
;
2777 int size
= sector2cluster(s
, s
->sector_count
);
2778 s
->used_clusters
= calloc(size
, 1);
2780 array_init(&(s
->commits
), sizeof(commit_t
));
2782 s
->qcow_filename
= g_malloc(1024);
2783 get_tmp_filename(s
->qcow_filename
, 1024);
2785 bdrv_qcow
= bdrv_find_format("qcow");
2786 options
= parse_option_parameters("", bdrv_qcow
->create_options
, NULL
);
2787 set_option_parameter_int(options
, BLOCK_OPT_SIZE
, s
->sector_count
* 512);
2788 set_option_parameter(options
, BLOCK_OPT_BACKING_FILE
, "fat:");
2790 if (bdrv_create(bdrv_qcow
, s
->qcow_filename
, options
) < 0)
2793 s
->qcow
= bdrv_new("");
2794 if (s
->qcow
== NULL
) {
2798 ret
= bdrv_open(s
->qcow
, s
->qcow_filename
,
2799 BDRV_O_RDWR
| BDRV_O_CACHE_WB
| BDRV_O_NO_FLUSH
, bdrv_qcow
);
2805 unlink(s
->qcow_filename
);
2808 s
->bs
->backing_hd
= calloc(sizeof(BlockDriverState
), 1);
2809 s
->bs
->backing_hd
->drv
= &vvfat_write_target
;
2810 s
->bs
->backing_hd
->opaque
= g_malloc(sizeof(void*));
2811 *(void**)s
->bs
->backing_hd
->opaque
= s
;
2816 static void vvfat_close(BlockDriverState
*bs
)
2818 BDRVVVFATState
*s
= bs
->opaque
;
2820 vvfat_close_current_file(s
);
2821 array_free(&(s
->fat
));
2822 array_free(&(s
->directory
));
2823 array_free(&(s
->mapping
));
2824 g_free(s
->cluster_buffer
);
2827 static BlockDriver bdrv_vvfat
= {
2828 .format_name
= "vvfat",
2829 .instance_size
= sizeof(BDRVVVFATState
),
2830 .bdrv_file_open
= vvfat_open
,
2831 .bdrv_read
= vvfat_co_read
,
2832 .bdrv_write
= vvfat_co_write
,
2833 .bdrv_close
= vvfat_close
,
2834 .bdrv_is_allocated
= vvfat_is_allocated
,
2835 .protocol_name
= "fat",
2838 static void bdrv_vvfat_init(void)
2840 bdrv_register(&bdrv_vvfat
);
2843 block_init(bdrv_vvfat_init
);
2846 static void checkpoint(void) {
2847 assert(((mapping_t
*)array_get(&(vvv
->mapping
), 0))->end
== 2);
2850 assert(!vvv
->current_mapping
|| vvv
->current_fd
|| (vvv
->current_mapping
->mode
& MODE_DIRECTORY
));
2852 if (((direntry_t
*)vvv
->directory
.pointer
)[1].attributes
!= 0xf)
2853 fprintf(stderr
, "Nonono!\n");
2855 direntry_t
* direntry
;
2856 assert(vvv
->mapping
.size
>= vvv
->mapping
.item_size
* vvv
->mapping
.next
);
2857 assert(vvv
->directory
.size
>= vvv
->directory
.item_size
* vvv
->directory
.next
);
2858 if (vvv
->mapping
.next
<47)
2860 assert((mapping
= array_get(&(vvv
->mapping
), 47)));
2861 assert(mapping
->dir_index
< vvv
->directory
.next
);
2862 direntry
= array_get(&(vvv
->directory
), mapping
->dir_index
);
2863 assert(!memcmp(direntry
->name
, "USB H ", 11) || direntry
->name
[0]==0);