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 memset(array_get(&(s
->directory
), cur
), 0,
803 (ROOT_ENTRIES
- cur
) * sizeof(direntry_t
));
806 /* reget the mapping, since s->mapping was possibly realloc()ed */
807 mapping
= (mapping_t
*)array_get(&(s
->mapping
), mapping_index
);
808 first_cluster
+= (s
->directory
.next
- mapping
->info
.dir
.first_dir_index
)
809 * 0x20 / s
->cluster_size
;
810 mapping
->end
= first_cluster
;
812 direntry
= (direntry_t
*)array_get(&(s
->directory
), mapping
->dir_index
);
813 set_begin_of_direntry(direntry
, mapping
->begin
);
818 static inline uint32_t sector2cluster(BDRVVVFATState
* s
,off_t sector_num
)
820 return (sector_num
-s
->faked_sectors
)/s
->sectors_per_cluster
;
823 static inline off_t
cluster2sector(BDRVVVFATState
* s
, uint32_t cluster_num
)
825 return s
->faked_sectors
+ s
->sectors_per_cluster
* cluster_num
;
828 static int init_directories(BDRVVVFATState
* s
,
831 bootsector_t
* bootsector
;
834 unsigned int cluster
;
836 memset(&(s
->first_sectors
[0]),0,0x40*0x200);
838 s
->cluster_size
=s
->sectors_per_cluster
*0x200;
839 s
->cluster_buffer
=g_malloc(s
->cluster_size
);
842 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
843 * where sc is sector_count,
844 * spf is sectors_per_fat,
845 * spc is sectors_per_clusters, and
846 * fat_type = 12, 16 or 32.
848 i
= 1+s
->sectors_per_cluster
*0x200*8/s
->fat_type
;
849 s
->sectors_per_fat
=(s
->sector_count
+i
)/i
; /* round up */
851 array_init(&(s
->mapping
),sizeof(mapping_t
));
852 array_init(&(s
->directory
),sizeof(direntry_t
));
854 /* add volume label */
856 direntry_t
* entry
=array_get_next(&(s
->directory
));
857 entry
->attributes
=0x28; /* archive | volume label */
858 memcpy(entry
->name
,"QEMU VVF",8);
859 memcpy(entry
->extension
,"AT ",3);
862 /* Now build FAT, and write back information into directory */
865 s
->faked_sectors
=s
->first_sectors_number
+s
->sectors_per_fat
*2;
866 s
->cluster_count
=sector2cluster(s
, s
->sector_count
);
868 mapping
= array_get_next(&(s
->mapping
));
870 mapping
->dir_index
= 0;
871 mapping
->info
.dir
.parent_mapping_index
= -1;
872 mapping
->first_mapping_index
= -1;
873 mapping
->path
= g_strdup(dirname
);
874 i
= strlen(mapping
->path
);
875 if (i
> 0 && mapping
->path
[i
- 1] == '/')
876 mapping
->path
[i
- 1] = '\0';
877 mapping
->mode
= MODE_DIRECTORY
;
878 mapping
->read_only
= 0;
879 s
->path
= mapping
->path
;
881 for (i
= 0, cluster
= 0; i
< s
->mapping
.next
; i
++) {
882 /* MS-DOS expects the FAT to be 0 for the root directory
883 * (except for the media byte). */
884 /* LATER TODO: still true for FAT32? */
885 int fix_fat
= (i
!= 0);
886 mapping
= array_get(&(s
->mapping
), i
);
888 if (mapping
->mode
& MODE_DIRECTORY
) {
889 mapping
->begin
= cluster
;
890 if(read_directory(s
, i
)) {
891 fprintf(stderr
, "Could not read directory %s\n",
895 mapping
= array_get(&(s
->mapping
), i
);
897 assert(mapping
->mode
== MODE_UNDEFINED
);
898 mapping
->mode
=MODE_NORMAL
;
899 mapping
->begin
= cluster
;
900 if (mapping
->end
> 0) {
901 direntry_t
* direntry
= array_get(&(s
->directory
),
904 mapping
->end
= cluster
+ 1 + (mapping
->end
-1)/s
->cluster_size
;
905 set_begin_of_direntry(direntry
, mapping
->begin
);
907 mapping
->end
= cluster
+ 1;
912 assert(mapping
->begin
< mapping
->end
);
914 /* next free cluster */
915 cluster
= mapping
->end
;
917 if(cluster
> s
->cluster_count
) {
918 fprintf(stderr
,"Directory does not fit in FAT%d (capacity %s)\n",
920 s
->fat_type
== 12 ? s
->sector_count
== 2880 ? "1.44 MB"
926 /* fix fat for entry */
929 for(j
= mapping
->begin
; j
< mapping
->end
- 1; j
++)
931 fat_set(s
, mapping
->end
- 1, s
->max_fat_value
);
935 mapping
= array_get(&(s
->mapping
), 0);
936 s
->sectors_of_root_directory
= mapping
->end
* s
->sectors_per_cluster
;
937 s
->last_cluster_of_root_directory
= mapping
->end
;
939 /* the FAT signature */
940 fat_set(s
,0,s
->max_fat_value
);
941 fat_set(s
,1,s
->max_fat_value
);
943 s
->current_mapping
= NULL
;
945 bootsector
=(bootsector_t
*)(s
->first_sectors
+(s
->first_sectors_number
-1)*0x200);
946 bootsector
->jump
[0]=0xeb;
947 bootsector
->jump
[1]=0x3e;
948 bootsector
->jump
[2]=0x90;
949 memcpy(bootsector
->name
,"QEMU ",8);
950 bootsector
->sector_size
=cpu_to_le16(0x200);
951 bootsector
->sectors_per_cluster
=s
->sectors_per_cluster
;
952 bootsector
->reserved_sectors
=cpu_to_le16(1);
953 bootsector
->number_of_fats
=0x2; /* number of FATs */
954 bootsector
->root_entries
=cpu_to_le16(s
->sectors_of_root_directory
*0x10);
955 bootsector
->total_sectors16
=s
->sector_count
>0xffff?0:cpu_to_le16(s
->sector_count
);
956 bootsector
->media_type
=(s
->fat_type
!=12?0xf8:s
->sector_count
==5760?0xf9:0xf8); /* media descriptor */
957 s
->fat
.pointer
[0] = bootsector
->media_type
;
958 bootsector
->sectors_per_fat
=cpu_to_le16(s
->sectors_per_fat
);
959 bootsector
->sectors_per_track
=cpu_to_le16(s
->bs
->secs
);
960 bootsector
->number_of_heads
=cpu_to_le16(s
->bs
->heads
);
961 bootsector
->hidden_sectors
=cpu_to_le32(s
->first_sectors_number
==1?0:0x3f);
962 bootsector
->total_sectors
=cpu_to_le32(s
->sector_count
>0xffff?s
->sector_count
:0);
964 /* LATER TODO: if FAT32, this is wrong */
965 bootsector
->u
.fat16
.drive_number
=s
->fat_type
==12?0:0x80; /* assume this is hda (TODO) */
966 bootsector
->u
.fat16
.current_head
=0;
967 bootsector
->u
.fat16
.signature
=0x29;
968 bootsector
->u
.fat16
.id
=cpu_to_le32(0xfabe1afd);
970 memcpy(bootsector
->u
.fat16
.volume_label
,"QEMU VVFAT ",11);
971 memcpy(bootsector
->fat_type
,(s
->fat_type
==12?"FAT12 ":s
->fat_type
==16?"FAT16 ":"FAT32 "),8);
972 bootsector
->magic
[0]=0x55; bootsector
->magic
[1]=0xaa;
978 static BDRVVVFATState
*vvv
= NULL
;
981 static int enable_write_target(BDRVVVFATState
*s
);
982 static int is_consistent(BDRVVVFATState
*s
);
984 static int vvfat_open(BlockDriverState
*bs
, const char* dirname
, int flags
)
986 BDRVVVFATState
*s
= bs
->opaque
;
994 DLOG(if (stderr
== NULL
) {
995 stderr
= fopen("vvfat.log", "a");
996 setbuf(stderr
, NULL
);
1002 /* LATER TODO: if FAT32, adjust */
1003 s
->sectors_per_cluster
=0x10;
1005 bs
->cyls
=1024; bs
->heads
=16; bs
->secs
=63;
1007 s
->current_cluster
=0xffffffff;
1009 s
->first_sectors_number
=0x40;
1010 /* read only is the default for safety */
1012 s
->qcow
= s
->write_target
= NULL
;
1013 s
->qcow_filename
= NULL
;
1015 s
->downcase_short_names
= 1;
1017 if (!strstart(dirname
, "fat:", NULL
))
1020 if (strstr(dirname
, ":floppy:")) {
1023 s
->first_sectors_number
= 1;
1024 s
->sectors_per_cluster
=2;
1025 bs
->cyls
= 80; bs
->heads
= 2; bs
->secs
= 36;
1028 s
->sector_count
=bs
->cyls
*bs
->heads
*bs
->secs
;
1030 if (strstr(dirname
, ":32:")) {
1031 fprintf(stderr
, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1033 } else if (strstr(dirname
, ":16:")) {
1035 } else if (strstr(dirname
, ":12:")) {
1037 s
->sector_count
=2880;
1040 if (strstr(dirname
, ":rw:")) {
1041 if (enable_write_target(s
))
1046 i
= strrchr(dirname
, ':') - dirname
;
1048 if (dirname
[i
-2] == ':' && qemu_isalpha(dirname
[i
-1]))
1049 /* workaround for DOS drive names */
1054 bs
->total_sectors
=bs
->cyls
*bs
->heads
*bs
->secs
;
1056 if(init_directories(s
, dirname
))
1059 s
->sector_count
= s
->faked_sectors
+ s
->sectors_per_cluster
*s
->cluster_count
;
1061 if(s
->first_sectors_number
==0x40)
1064 /* for some reason or other, MS-DOS does not like to know about CHS... */
1066 bs
->heads
= bs
->cyls
= bs
->secs
= 0;
1068 // assert(is_consistent(s));
1069 qemu_co_mutex_init(&s
->lock
);
1073 static inline void vvfat_close_current_file(BDRVVVFATState
*s
)
1075 if(s
->current_mapping
) {
1076 s
->current_mapping
= NULL
;
1077 if (s
->current_fd
) {
1078 close(s
->current_fd
);
1082 s
->current_cluster
= -1;
1085 /* mappings between index1 and index2-1 are supposed to be ordered
1086 * return value is the index of the last mapping for which end>cluster_num
1088 static inline int find_mapping_for_cluster_aux(BDRVVVFATState
* s
,int cluster_num
,int index1
,int index2
)
1093 index3
=(index1
+index2
)/2;
1094 mapping
=array_get(&(s
->mapping
),index3
);
1095 assert(mapping
->begin
< mapping
->end
);
1096 if(mapping
->begin
>=cluster_num
) {
1097 assert(index2
!=index3
|| index2
==0);
1103 return mapping
->end
<=cluster_num
? index2
: index1
;
1106 assert(index1
<=index2
);
1107 DLOG(mapping
=array_get(&(s
->mapping
),index1
);
1108 assert(mapping
->begin
<=cluster_num
);
1109 assert(index2
>= s
->mapping
.next
||
1110 ((mapping
= array_get(&(s
->mapping
),index2
)) &&
1111 mapping
->end
>cluster_num
)));
1115 static inline mapping_t
* find_mapping_for_cluster(BDRVVVFATState
* s
,int cluster_num
)
1117 int index
=find_mapping_for_cluster_aux(s
,cluster_num
,0,s
->mapping
.next
);
1119 if(index
>=s
->mapping
.next
)
1121 mapping
=array_get(&(s
->mapping
),index
);
1122 if(mapping
->begin
>cluster_num
)
1124 assert(mapping
->begin
<=cluster_num
&& mapping
->end
>cluster_num
);
1128 static int open_file(BDRVVVFATState
* s
,mapping_t
* mapping
)
1132 if(!s
->current_mapping
||
1133 strcmp(s
->current_mapping
->path
,mapping
->path
)) {
1135 int fd
= open(mapping
->path
, O_RDONLY
| O_BINARY
| O_LARGEFILE
);
1138 vvfat_close_current_file(s
);
1140 s
->current_mapping
= mapping
;
1145 static inline int read_cluster(BDRVVVFATState
*s
,int cluster_num
)
1147 if(s
->current_cluster
!= cluster_num
) {
1150 assert(!s
->current_mapping
|| s
->current_fd
|| (s
->current_mapping
->mode
& MODE_DIRECTORY
));
1151 if(!s
->current_mapping
1152 || s
->current_mapping
->begin
>cluster_num
1153 || s
->current_mapping
->end
<=cluster_num
) {
1154 /* binary search of mappings for file */
1155 mapping_t
* mapping
=find_mapping_for_cluster(s
,cluster_num
);
1157 assert(!mapping
|| (cluster_num
>=mapping
->begin
&& cluster_num
<mapping
->end
));
1159 if (mapping
&& mapping
->mode
& MODE_DIRECTORY
) {
1160 vvfat_close_current_file(s
);
1161 s
->current_mapping
= mapping
;
1162 read_cluster_directory
:
1163 offset
= s
->cluster_size
*(cluster_num
-s
->current_mapping
->begin
);
1164 s
->cluster
= (unsigned char*)s
->directory
.pointer
+offset
1165 + 0x20*s
->current_mapping
->info
.dir
.first_dir_index
;
1166 assert(((s
->cluster
-(unsigned char*)s
->directory
.pointer
)%s
->cluster_size
)==0);
1167 assert((char*)s
->cluster
+s
->cluster_size
<= s
->directory
.pointer
+s
->directory
.next
*s
->directory
.item_size
);
1168 s
->current_cluster
= cluster_num
;
1172 if(open_file(s
,mapping
))
1174 } else if (s
->current_mapping
->mode
& MODE_DIRECTORY
)
1175 goto read_cluster_directory
;
1177 assert(s
->current_fd
);
1179 offset
=s
->cluster_size
*(cluster_num
-s
->current_mapping
->begin
)+s
->current_mapping
->info
.file
.offset
;
1180 if(lseek(s
->current_fd
, offset
, SEEK_SET
)!=offset
)
1182 s
->cluster
=s
->cluster_buffer
;
1183 result
=read(s
->current_fd
,s
->cluster
,s
->cluster_size
);
1185 s
->current_cluster
= -1;
1188 s
->current_cluster
= cluster_num
;
1194 static void print_direntry(const direntry_t
* direntry
)
1199 fprintf(stderr
, "direntry %p: ", direntry
);
1202 if(is_long_name(direntry
)) {
1203 unsigned char* c
=(unsigned char*)direntry
;
1205 for(i
=1;i
<11 && c
[i
] && c
[i
]!=0xff;i
+=2)
1206 #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
1208 for(i
=14;i
<26 && c
[i
] && c
[i
]!=0xff;i
+=2)
1210 for(i
=28;i
<32 && c
[i
] && c
[i
]!=0xff;i
+=2)
1213 fprintf(stderr
, "%s\n", buffer
);
1217 ADD_CHAR(direntry
->name
[i
]);
1219 fprintf(stderr
,"%s attributes=0x%02x begin=%d size=%d\n",
1221 direntry
->attributes
,
1222 begin_of_direntry(direntry
),le32_to_cpu(direntry
->size
));
1226 static void print_mapping(const mapping_t
* mapping
)
1228 fprintf(stderr
, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1229 "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1230 mapping
, mapping
->begin
, mapping
->end
, mapping
->dir_index
,
1231 mapping
->first_mapping_index
, mapping
->path
, mapping
->mode
);
1233 if (mapping
->mode
& MODE_DIRECTORY
)
1234 fprintf(stderr
, "parent_mapping_index = %d, first_dir_index = %d\n", mapping
->info
.dir
.parent_mapping_index
, mapping
->info
.dir
.first_dir_index
);
1236 fprintf(stderr
, "offset = %d\n", mapping
->info
.file
.offset
);
1240 static int vvfat_read(BlockDriverState
*bs
, int64_t sector_num
,
1241 uint8_t *buf
, int nb_sectors
)
1243 BDRVVVFATState
*s
= bs
->opaque
;
1246 for(i
=0;i
<nb_sectors
;i
++,sector_num
++) {
1247 if (sector_num
>= s
->sector_count
)
1251 if (s
->qcow
->drv
->bdrv_is_allocated(s
->qcow
,
1252 sector_num
, nb_sectors
-i
, &n
)) {
1253 DLOG(fprintf(stderr
, "sectors %d+%d allocated\n", (int)sector_num
, n
));
1254 if (s
->qcow
->drv
->bdrv_read(s
->qcow
, sector_num
, buf
+i
*0x200, n
))
1257 sector_num
+= n
- 1;
1260 DLOG(fprintf(stderr
, "sector %d not allocated\n", (int)sector_num
));
1262 if(sector_num
<s
->faked_sectors
) {
1263 if(sector_num
<s
->first_sectors_number
)
1264 memcpy(buf
+i
*0x200,&(s
->first_sectors
[sector_num
*0x200]),0x200);
1265 else if(sector_num
-s
->first_sectors_number
<s
->sectors_per_fat
)
1266 memcpy(buf
+i
*0x200,&(s
->fat
.pointer
[(sector_num
-s
->first_sectors_number
)*0x200]),0x200);
1267 else if(sector_num
-s
->first_sectors_number
-s
->sectors_per_fat
<s
->sectors_per_fat
)
1268 memcpy(buf
+i
*0x200,&(s
->fat
.pointer
[(sector_num
-s
->first_sectors_number
-s
->sectors_per_fat
)*0x200]),0x200);
1270 uint32_t sector
=sector_num
-s
->faked_sectors
,
1271 sector_offset_in_cluster
=(sector
%s
->sectors_per_cluster
),
1272 cluster_num
=sector
/s
->sectors_per_cluster
;
1273 if(read_cluster(s
, cluster_num
) != 0) {
1274 /* LATER TODO: strict: return -1; */
1275 memset(buf
+i
*0x200,0,0x200);
1278 memcpy(buf
+i
*0x200,s
->cluster
+sector_offset_in_cluster
*0x200,0x200);
1284 static coroutine_fn
int vvfat_co_read(BlockDriverState
*bs
, int64_t sector_num
,
1285 uint8_t *buf
, int nb_sectors
)
1288 BDRVVVFATState
*s
= bs
->opaque
;
1289 qemu_co_mutex_lock(&s
->lock
);
1290 ret
= vvfat_read(bs
, sector_num
, buf
, nb_sectors
);
1291 qemu_co_mutex_unlock(&s
->lock
);
1295 /* LATER TODO: statify all functions */
1298 * Idea of the write support (use snapshot):
1300 * 1. check if all data is consistent, recording renames, modifications,
1301 * new files and directories (in s->commits).
1303 * 2. if the data is not consistent, stop committing
1305 * 3. handle renames, and create new files and directories (do not yet
1306 * write their contents)
1308 * 4. walk the directories, fixing the mapping and direntries, and marking
1309 * the handled mappings as not deleted
1311 * 5. commit the contents of the files
1313 * 6. handle deleted files and directories
1317 typedef struct commit_t
{
1320 struct { uint32_t cluster
; } rename
;
1321 struct { int dir_index
; uint32_t modified_offset
; } writeout
;
1322 struct { uint32_t first_cluster
; } new_file
;
1323 struct { uint32_t cluster
; } mkdir
;
1325 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1327 ACTION_RENAME
, ACTION_WRITEOUT
, ACTION_NEW_FILE
, ACTION_MKDIR
1331 static void clear_commits(BDRVVVFATState
* s
)
1334 DLOG(fprintf(stderr
, "clear_commits (%d commits)\n", s
->commits
.next
));
1335 for (i
= 0; i
< s
->commits
.next
; i
++) {
1336 commit_t
* commit
= array_get(&(s
->commits
), i
);
1337 assert(commit
->path
|| commit
->action
== ACTION_WRITEOUT
);
1338 if (commit
->action
!= ACTION_WRITEOUT
) {
1339 assert(commit
->path
);
1340 g_free(commit
->path
);
1342 assert(commit
->path
== NULL
);
1344 s
->commits
.next
= 0;
1347 static void schedule_rename(BDRVVVFATState
* s
,
1348 uint32_t cluster
, char* new_path
)
1350 commit_t
* commit
= array_get_next(&(s
->commits
));
1351 commit
->path
= new_path
;
1352 commit
->param
.rename
.cluster
= cluster
;
1353 commit
->action
= ACTION_RENAME
;
1356 static void schedule_writeout(BDRVVVFATState
* s
,
1357 int dir_index
, uint32_t modified_offset
)
1359 commit_t
* commit
= array_get_next(&(s
->commits
));
1360 commit
->path
= NULL
;
1361 commit
->param
.writeout
.dir_index
= dir_index
;
1362 commit
->param
.writeout
.modified_offset
= modified_offset
;
1363 commit
->action
= ACTION_WRITEOUT
;
1366 static void schedule_new_file(BDRVVVFATState
* s
,
1367 char* path
, uint32_t first_cluster
)
1369 commit_t
* commit
= array_get_next(&(s
->commits
));
1370 commit
->path
= path
;
1371 commit
->param
.new_file
.first_cluster
= first_cluster
;
1372 commit
->action
= ACTION_NEW_FILE
;
1375 static void schedule_mkdir(BDRVVVFATState
* s
, uint32_t cluster
, char* path
)
1377 commit_t
* commit
= array_get_next(&(s
->commits
));
1378 commit
->path
= path
;
1379 commit
->param
.mkdir
.cluster
= cluster
;
1380 commit
->action
= ACTION_MKDIR
;
1385 * Since the sequence number is at most 0x3f, and the filename
1386 * length is at most 13 times the sequence number, the maximal
1387 * filename length is 0x3f * 13 bytes.
1389 unsigned char name
[0x3f * 13 + 1];
1391 int sequence_number
;
1394 static void lfn_init(long_file_name
* lfn
)
1396 lfn
->sequence_number
= lfn
->len
= 0;
1397 lfn
->checksum
= 0x100;
1400 /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1401 static int parse_long_name(long_file_name
* lfn
,
1402 const direntry_t
* direntry
)
1405 const unsigned char* pointer
= (const unsigned char*)direntry
;
1407 if (!is_long_name(direntry
))
1410 if (pointer
[0] & 0x40) {
1411 lfn
->sequence_number
= pointer
[0] & 0x3f;
1412 lfn
->checksum
= pointer
[13];
1414 lfn
->name
[lfn
->sequence_number
* 13] = 0;
1415 } else if ((pointer
[0] & 0x3f) != --lfn
->sequence_number
)
1417 else if (pointer
[13] != lfn
->checksum
)
1419 else if (pointer
[12] || pointer
[26] || pointer
[27])
1422 offset
= 13 * (lfn
->sequence_number
- 1);
1423 for (i
= 0, j
= 1; i
< 13; i
++, j
+=2) {
1429 if (pointer
[j
+1] == 0)
1430 lfn
->name
[offset
+ i
] = pointer
[j
];
1431 else if (pointer
[j
+1] != 0xff || (pointer
[0] & 0x40) == 0)
1434 lfn
->name
[offset
+ i
] = 0;
1437 if (pointer
[0] & 0x40)
1438 lfn
->len
= offset
+ strlen((char*)lfn
->name
+ offset
);
1443 /* returns 0 if successful, >0 if no short_name, and <0 on error */
1444 static int parse_short_name(BDRVVVFATState
* s
,
1445 long_file_name
* lfn
, direntry_t
* direntry
)
1449 if (!is_short_name(direntry
))
1452 for (j
= 7; j
>= 0 && direntry
->name
[j
] == ' '; j
--);
1453 for (i
= 0; i
<= j
; i
++) {
1454 if (direntry
->name
[i
] <= ' ' || direntry
->name
[i
] > 0x7f)
1456 else if (s
->downcase_short_names
)
1457 lfn
->name
[i
] = qemu_tolower(direntry
->name
[i
]);
1459 lfn
->name
[i
] = direntry
->name
[i
];
1462 for (j
= 2; j
>= 0 && direntry
->extension
[j
] == ' '; j
--);
1464 lfn
->name
[i
++] = '.';
1465 lfn
->name
[i
+ j
+ 1] = '\0';
1466 for (;j
>= 0; j
--) {
1467 if (direntry
->extension
[j
] <= ' ' || direntry
->extension
[j
] > 0x7f)
1469 else if (s
->downcase_short_names
)
1470 lfn
->name
[i
+ j
] = qemu_tolower(direntry
->extension
[j
]);
1472 lfn
->name
[i
+ j
] = direntry
->extension
[j
];
1475 lfn
->name
[i
+ j
+ 1] = '\0';
1477 lfn
->len
= strlen((char*)lfn
->name
);
1482 static inline uint32_t modified_fat_get(BDRVVVFATState
* s
,
1483 unsigned int cluster
)
1485 if (cluster
< s
->last_cluster_of_root_directory
) {
1486 if (cluster
+ 1 == s
->last_cluster_of_root_directory
)
1487 return s
->max_fat_value
;
1492 if (s
->fat_type
==32) {
1493 uint32_t* entry
=((uint32_t*)s
->fat2
)+cluster
;
1494 return le32_to_cpu(*entry
);
1495 } else if (s
->fat_type
==16) {
1496 uint16_t* entry
=((uint16_t*)s
->fat2
)+cluster
;
1497 return le16_to_cpu(*entry
);
1499 const uint8_t* x
=s
->fat2
+cluster
*3/2;
1500 return ((x
[0]|(x
[1]<<8))>>(cluster
&1?4:0))&0x0fff;
1504 static inline int cluster_was_modified(BDRVVVFATState
* s
, uint32_t cluster_num
)
1506 int was_modified
= 0;
1509 if (s
->qcow
== NULL
)
1512 for (i
= 0; !was_modified
&& i
< s
->sectors_per_cluster
; i
++)
1513 was_modified
= s
->qcow
->drv
->bdrv_is_allocated(s
->qcow
,
1514 cluster2sector(s
, cluster_num
) + i
, 1, &dummy
);
1516 return was_modified
;
1519 static const char* get_basename(const char* path
)
1521 char* basename
= strrchr(path
, '/');
1522 if (basename
== NULL
)
1525 return basename
+ 1; /* strip '/' */
1529 * The array s->used_clusters holds the states of the clusters. If it is
1530 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1531 * was modified, bit 3 is set.
1532 * If any cluster is allocated, but not part of a file or directory, this
1533 * driver refuses to commit.
1536 USED_DIRECTORY
= 1, USED_FILE
= 2, USED_ANY
= 3, USED_ALLOCATED
= 4
1540 * get_cluster_count_for_direntry() not only determines how many clusters
1541 * are occupied by direntry, but also if it was renamed or modified.
1543 * A file is thought to be renamed *only* if there already was a file with
1544 * exactly the same first cluster, but a different name.
1546 * Further, the files/directories handled by this function are
1547 * assumed to be *not* deleted (and *only* those).
1549 static uint32_t get_cluster_count_for_direntry(BDRVVVFATState
* s
,
1550 direntry_t
* direntry
, const char* path
)
1553 * This is a little bit tricky:
1554 * IF the guest OS just inserts a cluster into the file chain,
1555 * and leaves the rest alone, (i.e. the original file had clusters
1556 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1558 * - do_commit will write the cluster into the file at the given
1561 * - the cluster which is overwritten should be moved to a later
1562 * position in the file.
1564 * I am not aware that any OS does something as braindead, but this
1565 * situation could happen anyway when not committing for a long time.
1566 * Just to be sure that this does not bite us, detect it, and copy the
1567 * contents of the clusters to-be-overwritten into the qcow.
1570 int was_modified
= 0;
1573 uint32_t cluster_num
= begin_of_direntry(direntry
);
1574 uint32_t offset
= 0;
1575 int first_mapping_index
= -1;
1576 mapping_t
* mapping
= NULL
;
1577 const char* basename2
= NULL
;
1579 vvfat_close_current_file(s
);
1581 /* the root directory */
1582 if (cluster_num
== 0)
1587 basename2
= get_basename(path
);
1589 mapping
= find_mapping_for_cluster(s
, cluster_num
);
1592 const char* basename
;
1594 assert(mapping
->mode
& MODE_DELETED
);
1595 mapping
->mode
&= ~MODE_DELETED
;
1597 basename
= get_basename(mapping
->path
);
1599 assert(mapping
->mode
& MODE_NORMAL
);
1602 if (strcmp(basename
, basename2
))
1603 schedule_rename(s
, cluster_num
, g_strdup(path
));
1604 } else if (is_file(direntry
))
1606 schedule_new_file(s
, g_strdup(path
), cluster_num
);
1615 if (!copy_it
&& cluster_was_modified(s
, cluster_num
)) {
1616 if (mapping
== NULL
||
1617 mapping
->begin
> cluster_num
||
1618 mapping
->end
<= cluster_num
)
1619 mapping
= find_mapping_for_cluster(s
, cluster_num
);
1623 (mapping
->mode
& MODE_DIRECTORY
) == 0) {
1625 /* was modified in qcow */
1626 if (offset
!= mapping
->info
.file
.offset
+ s
->cluster_size
1627 * (cluster_num
- mapping
->begin
)) {
1628 /* offset of this cluster in file chain has changed */
1631 } else if (offset
== 0) {
1632 const char* basename
= get_basename(mapping
->path
);
1634 if (strcmp(basename
, basename2
))
1636 first_mapping_index
= array_index(&(s
->mapping
), mapping
);
1639 if (mapping
->first_mapping_index
!= first_mapping_index
1640 && mapping
->info
.file
.offset
> 0) {
1645 /* need to write out? */
1646 if (!was_modified
&& is_file(direntry
)) {
1648 schedule_writeout(s
, mapping
->dir_index
, offset
);
1656 * This is horribly inefficient, but that is okay, since
1657 * it is rarely executed, if at all.
1659 int64_t offset
= cluster2sector(s
, cluster_num
);
1661 vvfat_close_current_file(s
);
1662 for (i
= 0; i
< s
->sectors_per_cluster
; i
++)
1663 if (!s
->qcow
->drv
->bdrv_is_allocated(s
->qcow
,
1664 offset
+ i
, 1, &dummy
)) {
1665 if (vvfat_read(s
->bs
,
1666 offset
, s
->cluster_buffer
, 1))
1668 if (s
->qcow
->drv
->bdrv_write(s
->qcow
,
1669 offset
, s
->cluster_buffer
, 1))
1676 if (s
->used_clusters
[cluster_num
] & USED_ANY
)
1678 s
->used_clusters
[cluster_num
] = USED_FILE
;
1680 cluster_num
= modified_fat_get(s
, cluster_num
);
1682 if (fat_eof(s
, cluster_num
))
1684 else if (cluster_num
< 2 || cluster_num
> s
->max_fat_value
- 16)
1687 offset
+= s
->cluster_size
;
1692 * This function looks at the modified data (qcow).
1693 * It returns 0 upon inconsistency or error, and the number of clusters
1694 * used by the directory, its subdirectories and their files.
1696 static int check_directory_consistency(BDRVVVFATState
*s
,
1697 int cluster_num
, const char* path
)
1700 unsigned char* cluster
= g_malloc(s
->cluster_size
);
1701 direntry_t
* direntries
= (direntry_t
*)cluster
;
1702 mapping_t
* mapping
= find_mapping_for_cluster(s
, cluster_num
);
1705 int path_len
= strlen(path
);
1706 char path2
[PATH_MAX
+ 1];
1708 assert(path_len
< PATH_MAX
); /* len was tested before! */
1709 pstrcpy(path2
, sizeof(path2
), path
);
1710 path2
[path_len
] = '/';
1711 path2
[path_len
+ 1] = '\0';
1714 const char* basename
= get_basename(mapping
->path
);
1715 const char* basename2
= get_basename(path
);
1717 assert(mapping
->mode
& MODE_DIRECTORY
);
1719 assert(mapping
->mode
& MODE_DELETED
);
1720 mapping
->mode
&= ~MODE_DELETED
;
1722 if (strcmp(basename
, basename2
))
1723 schedule_rename(s
, cluster_num
, g_strdup(path
));
1726 schedule_mkdir(s
, cluster_num
, g_strdup(path
));
1735 if (s
->used_clusters
[cluster_num
] & USED_ANY
) {
1736 fprintf(stderr
, "cluster %d used more than once\n", (int)cluster_num
);
1739 s
->used_clusters
[cluster_num
] = USED_DIRECTORY
;
1741 DLOG(fprintf(stderr
, "read cluster %d (sector %d)\n", (int)cluster_num
, (int)cluster2sector(s
, cluster_num
)));
1742 subret
= vvfat_read(s
->bs
, cluster2sector(s
, cluster_num
), cluster
,
1743 s
->sectors_per_cluster
);
1745 fprintf(stderr
, "Error fetching direntries\n");
1751 for (i
= 0; i
< 0x10 * s
->sectors_per_cluster
; i
++) {
1752 int cluster_count
= 0;
1754 DLOG(fprintf(stderr
, "check direntry %d:\n", i
); print_direntry(direntries
+ i
));
1755 if (is_volume_label(direntries
+ i
) || is_dot(direntries
+ i
) ||
1756 is_free(direntries
+ i
))
1759 subret
= parse_long_name(&lfn
, direntries
+ i
);
1761 fprintf(stderr
, "Error in long name\n");
1764 if (subret
== 0 || is_free(direntries
+ i
))
1767 if (fat_chksum(direntries
+i
) != lfn
.checksum
) {
1768 subret
= parse_short_name(s
, &lfn
, direntries
+ i
);
1770 fprintf(stderr
, "Error in short name (%d)\n", subret
);
1773 if (subret
> 0 || !strcmp((char*)lfn
.name
, ".")
1774 || !strcmp((char*)lfn
.name
, ".."))
1777 lfn
.checksum
= 0x100; /* cannot use long name twice */
1779 if (path_len
+ 1 + lfn
.len
>= PATH_MAX
) {
1780 fprintf(stderr
, "Name too long: %s/%s\n", path
, lfn
.name
);
1783 pstrcpy(path2
+ path_len
+ 1, sizeof(path2
) - path_len
- 1,
1786 if (is_directory(direntries
+ i
)) {
1787 if (begin_of_direntry(direntries
+ i
) == 0) {
1788 DLOG(fprintf(stderr
, "invalid begin for directory: %s\n", path2
); print_direntry(direntries
+ i
));
1791 cluster_count
= check_directory_consistency(s
,
1792 begin_of_direntry(direntries
+ i
), path2
);
1793 if (cluster_count
== 0) {
1794 DLOG(fprintf(stderr
, "problem in directory %s:\n", path2
); print_direntry(direntries
+ i
));
1797 } else if (is_file(direntries
+ i
)) {
1798 /* check file size with FAT */
1799 cluster_count
= get_cluster_count_for_direntry(s
, direntries
+ i
, path2
);
1800 if (cluster_count
!=
1801 (le32_to_cpu(direntries
[i
].size
) + s
->cluster_size
1802 - 1) / s
->cluster_size
) {
1803 DLOG(fprintf(stderr
, "Cluster count mismatch\n"));
1807 abort(); /* cluster_count = 0; */
1809 ret
+= cluster_count
;
1812 cluster_num
= modified_fat_get(s
, cluster_num
);
1813 } while(!fat_eof(s
, cluster_num
));
1819 /* returns 1 on success */
1820 static int is_consistent(BDRVVVFATState
* s
)
1823 int used_clusters_count
= 0;
1827 * - get modified FAT
1828 * - compare the two FATs (TODO)
1829 * - get buffer for marking used clusters
1830 * - recurse direntries from root (using bs->bdrv_read to make
1831 * sure to get the new data)
1832 * - check that the FAT agrees with the size
1833 * - count the number of clusters occupied by this directory and
1835 * - check that the cumulative used cluster count agrees with the
1837 * - if all is fine, return number of used clusters
1839 if (s
->fat2
== NULL
) {
1840 int size
= 0x200 * s
->sectors_per_fat
;
1841 s
->fat2
= g_malloc(size
);
1842 memcpy(s
->fat2
, s
->fat
.pointer
, size
);
1844 check
= vvfat_read(s
->bs
,
1845 s
->first_sectors_number
, s
->fat2
, s
->sectors_per_fat
);
1847 fprintf(stderr
, "Could not copy fat\n");
1850 assert (s
->used_clusters
);
1851 for (i
= 0; i
< sector2cluster(s
, s
->sector_count
); i
++)
1852 s
->used_clusters
[i
] &= ~USED_ANY
;
1856 /* mark every mapped file/directory as deleted.
1857 * (check_directory_consistency() will unmark those still present). */
1859 for (i
= 0; i
< s
->mapping
.next
; i
++) {
1860 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
1861 if (mapping
->first_mapping_index
< 0)
1862 mapping
->mode
|= MODE_DELETED
;
1865 used_clusters_count
= check_directory_consistency(s
, 0, s
->path
);
1866 if (used_clusters_count
<= 0) {
1867 DLOG(fprintf(stderr
, "problem in directory\n"));
1871 check
= s
->last_cluster_of_root_directory
;
1872 for (i
= check
; i
< sector2cluster(s
, s
->sector_count
); i
++) {
1873 if (modified_fat_get(s
, i
)) {
1874 if(!s
->used_clusters
[i
]) {
1875 DLOG(fprintf(stderr
, "FAT was modified (%d), but cluster is not used?\n", i
));
1881 if (s
->used_clusters
[i
] == USED_ALLOCATED
) {
1882 /* allocated, but not used... */
1883 DLOG(fprintf(stderr
, "unused, modified cluster: %d\n", i
));
1888 if (check
!= used_clusters_count
)
1891 return used_clusters_count
;
1894 static inline void adjust_mapping_indices(BDRVVVFATState
* s
,
1895 int offset
, int adjust
)
1899 for (i
= 0; i
< s
->mapping
.next
; i
++) {
1900 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
1902 #define ADJUST_MAPPING_INDEX(name) \
1903 if (mapping->name >= offset) \
1904 mapping->name += adjust
1906 ADJUST_MAPPING_INDEX(first_mapping_index
);
1907 if (mapping
->mode
& MODE_DIRECTORY
)
1908 ADJUST_MAPPING_INDEX(info
.dir
.parent_mapping_index
);
1912 /* insert or update mapping */
1913 static mapping_t
* insert_mapping(BDRVVVFATState
* s
,
1914 uint32_t begin
, uint32_t end
)
1917 * - find mapping where mapping->begin >= begin,
1918 * - if mapping->begin > begin: insert
1919 * - adjust all references to mappings!
1923 int index
= find_mapping_for_cluster_aux(s
, begin
, 0, s
->mapping
.next
);
1924 mapping_t
* mapping
= NULL
;
1925 mapping_t
* first_mapping
= array_get(&(s
->mapping
), 0);
1927 if (index
< s
->mapping
.next
&& (mapping
= array_get(&(s
->mapping
), index
))
1928 && mapping
->begin
< begin
) {
1929 mapping
->end
= begin
;
1931 mapping
= array_get(&(s
->mapping
), index
);
1933 if (index
>= s
->mapping
.next
|| mapping
->begin
> begin
) {
1934 mapping
= array_insert(&(s
->mapping
), index
, 1);
1935 mapping
->path
= NULL
;
1936 adjust_mapping_indices(s
, index
, +1);
1939 mapping
->begin
= begin
;
1942 DLOG(mapping_t
* next_mapping
;
1943 assert(index
+ 1 >= s
->mapping
.next
||
1944 ((next_mapping
= array_get(&(s
->mapping
), index
+ 1)) &&
1945 next_mapping
->begin
>= end
)));
1947 if (s
->current_mapping
&& first_mapping
!= (mapping_t
*)s
->mapping
.pointer
)
1948 s
->current_mapping
= array_get(&(s
->mapping
),
1949 s
->current_mapping
- first_mapping
);
1954 static int remove_mapping(BDRVVVFATState
* s
, int mapping_index
)
1956 mapping_t
* mapping
= array_get(&(s
->mapping
), mapping_index
);
1957 mapping_t
* first_mapping
= array_get(&(s
->mapping
), 0);
1960 if (mapping
->first_mapping_index
< 0) {
1961 g_free(mapping
->path
);
1964 /* remove from s->mapping */
1965 array_remove(&(s
->mapping
), mapping_index
);
1967 /* adjust all references to mappings */
1968 adjust_mapping_indices(s
, mapping_index
, -1);
1970 if (s
->current_mapping
&& first_mapping
!= (mapping_t
*)s
->mapping
.pointer
)
1971 s
->current_mapping
= array_get(&(s
->mapping
),
1972 s
->current_mapping
- first_mapping
);
1977 static void adjust_dirindices(BDRVVVFATState
* s
, int offset
, int adjust
)
1980 for (i
= 0; i
< s
->mapping
.next
; i
++) {
1981 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
1982 if (mapping
->dir_index
>= offset
)
1983 mapping
->dir_index
+= adjust
;
1984 if ((mapping
->mode
& MODE_DIRECTORY
) &&
1985 mapping
->info
.dir
.first_dir_index
>= offset
)
1986 mapping
->info
.dir
.first_dir_index
+= adjust
;
1990 static direntry_t
* insert_direntries(BDRVVVFATState
* s
,
1991 int dir_index
, int count
)
1994 * make room in s->directory,
1997 direntry_t
* result
= array_insert(&(s
->directory
), dir_index
, count
);
2000 adjust_dirindices(s
, dir_index
, count
);
2004 static int remove_direntries(BDRVVVFATState
* s
, int dir_index
, int count
)
2006 int ret
= array_remove_slice(&(s
->directory
), dir_index
, count
);
2009 adjust_dirindices(s
, dir_index
, -count
);
2014 * Adapt the mappings of the cluster chain starting at first cluster
2015 * (i.e. if a file starts at first_cluster, the chain is followed according
2016 * to the modified fat, and the corresponding entries in s->mapping are
2019 static int commit_mappings(BDRVVVFATState
* s
,
2020 uint32_t first_cluster
, int dir_index
)
2022 mapping_t
* mapping
= find_mapping_for_cluster(s
, first_cluster
);
2023 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2024 uint32_t cluster
= first_cluster
;
2026 vvfat_close_current_file(s
);
2029 assert(mapping
->begin
== first_cluster
);
2030 mapping
->first_mapping_index
= -1;
2031 mapping
->dir_index
= dir_index
;
2032 mapping
->mode
= (dir_index
<= 0 || is_directory(direntry
)) ?
2033 MODE_DIRECTORY
: MODE_NORMAL
;
2035 while (!fat_eof(s
, cluster
)) {
2038 for (c
= cluster
, c1
= modified_fat_get(s
, c
); c
+ 1 == c1
;
2039 c
= c1
, c1
= modified_fat_get(s
, c1
));
2042 if (c
> mapping
->end
) {
2043 int index
= array_index(&(s
->mapping
), mapping
);
2044 int i
, max_i
= s
->mapping
.next
- index
;
2045 for (i
= 1; i
< max_i
&& mapping
[i
].begin
< c
; i
++);
2047 remove_mapping(s
, index
+ 1);
2049 assert(mapping
== array_get(&(s
->mapping
), s
->mapping
.next
- 1)
2050 || mapping
[1].begin
>= c
);
2053 if (!fat_eof(s
, c1
)) {
2054 int i
= find_mapping_for_cluster_aux(s
, c1
, 0, s
->mapping
.next
);
2055 mapping_t
* next_mapping
= i
>= s
->mapping
.next
? NULL
:
2056 array_get(&(s
->mapping
), i
);
2058 if (next_mapping
== NULL
|| next_mapping
->begin
> c1
) {
2059 int i1
= array_index(&(s
->mapping
), mapping
);
2061 next_mapping
= insert_mapping(s
, c1
, c1
+1);
2065 mapping
= array_get(&(s
->mapping
), i1
);
2068 next_mapping
->dir_index
= mapping
->dir_index
;
2069 next_mapping
->first_mapping_index
=
2070 mapping
->first_mapping_index
< 0 ?
2071 array_index(&(s
->mapping
), mapping
) :
2072 mapping
->first_mapping_index
;
2073 next_mapping
->path
= mapping
->path
;
2074 next_mapping
->mode
= mapping
->mode
;
2075 next_mapping
->read_only
= mapping
->read_only
;
2076 if (mapping
->mode
& MODE_DIRECTORY
) {
2077 next_mapping
->info
.dir
.parent_mapping_index
=
2078 mapping
->info
.dir
.parent_mapping_index
;
2079 next_mapping
->info
.dir
.first_dir_index
=
2080 mapping
->info
.dir
.first_dir_index
+
2081 0x10 * s
->sectors_per_cluster
*
2082 (mapping
->end
- mapping
->begin
);
2084 next_mapping
->info
.file
.offset
= mapping
->info
.file
.offset
+
2085 mapping
->end
- mapping
->begin
;
2087 mapping
= next_mapping
;
2096 static int commit_direntries(BDRVVVFATState
* s
,
2097 int dir_index
, int parent_mapping_index
)
2099 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2100 uint32_t first_cluster
= dir_index
== 0 ? 0 : begin_of_direntry(direntry
);
2101 mapping_t
* mapping
= find_mapping_for_cluster(s
, first_cluster
);
2103 int factor
= 0x10 * s
->sectors_per_cluster
;
2104 int old_cluster_count
, new_cluster_count
;
2105 int current_dir_index
= mapping
->info
.dir
.first_dir_index
;
2106 int first_dir_index
= current_dir_index
;
2110 DLOG(fprintf(stderr
, "commit_direntries for %s, parent_mapping_index %d\n", mapping
->path
, parent_mapping_index
));
2114 assert(mapping
->begin
== first_cluster
);
2115 assert(mapping
->info
.dir
.first_dir_index
< s
->directory
.next
);
2116 assert(mapping
->mode
& MODE_DIRECTORY
);
2117 assert(dir_index
== 0 || is_directory(direntry
));
2119 mapping
->info
.dir
.parent_mapping_index
= parent_mapping_index
;
2121 if (first_cluster
== 0) {
2122 old_cluster_count
= new_cluster_count
=
2123 s
->last_cluster_of_root_directory
;
2125 for (old_cluster_count
= 0, c
= first_cluster
; !fat_eof(s
, c
);
2127 old_cluster_count
++;
2129 for (new_cluster_count
= 0, c
= first_cluster
; !fat_eof(s
, c
);
2130 c
= modified_fat_get(s
, c
))
2131 new_cluster_count
++;
2134 if (new_cluster_count
> old_cluster_count
) {
2135 if (insert_direntries(s
,
2136 current_dir_index
+ factor
* old_cluster_count
,
2137 factor
* (new_cluster_count
- old_cluster_count
)) == NULL
)
2139 } else if (new_cluster_count
< old_cluster_count
)
2140 remove_direntries(s
,
2141 current_dir_index
+ factor
* new_cluster_count
,
2142 factor
* (old_cluster_count
- new_cluster_count
));
2144 for (c
= first_cluster
; !fat_eof(s
, c
); c
= modified_fat_get(s
, c
)) {
2145 void* direntry
= array_get(&(s
->directory
), current_dir_index
);
2146 int ret
= vvfat_read(s
->bs
, cluster2sector(s
, c
), direntry
,
2147 s
->sectors_per_cluster
);
2150 assert(!strncmp(s
->directory
.pointer
, "QEMU", 4));
2151 current_dir_index
+= factor
;
2154 ret
= commit_mappings(s
, first_cluster
, dir_index
);
2159 for (i
= 0; i
< factor
* new_cluster_count
; i
++) {
2160 direntry
= array_get(&(s
->directory
), first_dir_index
+ i
);
2161 if (is_directory(direntry
) && !is_dot(direntry
)) {
2162 mapping
= find_mapping_for_cluster(s
, first_cluster
);
2163 assert(mapping
->mode
& MODE_DIRECTORY
);
2164 ret
= commit_direntries(s
, first_dir_index
+ i
,
2165 array_index(&(s
->mapping
), mapping
));
2174 /* commit one file (adjust contents, adjust mapping),
2175 return first_mapping_index */
2176 static int commit_one_file(BDRVVVFATState
* s
,
2177 int dir_index
, uint32_t offset
)
2179 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2180 uint32_t c
= begin_of_direntry(direntry
);
2181 uint32_t first_cluster
= c
;
2182 mapping_t
* mapping
= find_mapping_for_cluster(s
, c
);
2183 uint32_t size
= filesize_of_direntry(direntry
);
2184 char* cluster
= g_malloc(s
->cluster_size
);
2188 assert(offset
< size
);
2189 assert((offset
% s
->cluster_size
) == 0);
2191 for (i
= s
->cluster_size
; i
< offset
; i
+= s
->cluster_size
)
2192 c
= modified_fat_get(s
, c
);
2194 fd
= open(mapping
->path
, O_RDWR
| O_CREAT
| O_BINARY
, 0666);
2196 fprintf(stderr
, "Could not open %s... (%s, %d)\n", mapping
->path
,
2197 strerror(errno
), errno
);
2202 if (lseek(fd
, offset
, SEEK_SET
) != offset
) {
2208 while (offset
< size
) {
2210 int rest_size
= (size
- offset
> s
->cluster_size
?
2211 s
->cluster_size
: size
- offset
);
2214 c1
= modified_fat_get(s
, c
);
2216 assert((size
- offset
== 0 && fat_eof(s
, c
)) ||
2217 (size
> offset
&& c
>=2 && !fat_eof(s
, c
)));
2219 ret
= vvfat_read(s
->bs
, cluster2sector(s
, c
),
2220 (uint8_t*)cluster
, (rest_size
+ 0x1ff) / 0x200);
2227 if (write(fd
, cluster
, rest_size
) < 0) {
2232 offset
+= rest_size
;
2236 if (ftruncate(fd
, size
)) {
2237 perror("ftruncate()");
2245 return commit_mappings(s
, first_cluster
, dir_index
);
2249 /* test, if all mappings point to valid direntries */
2250 static void check1(BDRVVVFATState
* s
)
2253 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2254 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2255 if (mapping
->mode
& MODE_DELETED
) {
2256 fprintf(stderr
, "deleted\n");
2259 assert(mapping
->dir_index
< s
->directory
.next
);
2260 direntry_t
* direntry
= array_get(&(s
->directory
), mapping
->dir_index
);
2261 assert(mapping
->begin
== begin_of_direntry(direntry
) || mapping
->first_mapping_index
>= 0);
2262 if (mapping
->mode
& MODE_DIRECTORY
) {
2263 assert(mapping
->info
.dir
.first_dir_index
+ 0x10 * s
->sectors_per_cluster
* (mapping
->end
- mapping
->begin
) <= s
->directory
.next
);
2264 assert((mapping
->info
.dir
.first_dir_index
% (0x10 * s
->sectors_per_cluster
)) == 0);
2269 /* test, if all direntries have mappings */
2270 static void check2(BDRVVVFATState
* s
)
2273 int first_mapping
= -1;
2275 for (i
= 0; i
< s
->directory
.next
; i
++) {
2276 direntry_t
* direntry
= array_get(&(s
->directory
), i
);
2278 if (is_short_name(direntry
) && begin_of_direntry(direntry
)) {
2279 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin_of_direntry(direntry
));
2281 assert(mapping
->dir_index
== i
|| is_dot(direntry
));
2282 assert(mapping
->begin
== begin_of_direntry(direntry
) || is_dot(direntry
));
2285 if ((i
% (0x10 * s
->sectors_per_cluster
)) == 0) {
2289 for (j
= 0; j
< s
->mapping
.next
; j
++) {
2290 mapping_t
* mapping
= array_get(&(s
->mapping
), j
);
2291 if (mapping
->mode
& MODE_DELETED
)
2293 if (mapping
->mode
& MODE_DIRECTORY
) {
2294 if (mapping
->info
.dir
.first_dir_index
<= i
&& mapping
->info
.dir
.first_dir_index
+ 0x10 * s
->sectors_per_cluster
> i
) {
2295 assert(++count
== 1);
2296 if (mapping
->first_mapping_index
== -1)
2297 first_mapping
= array_index(&(s
->mapping
), mapping
);
2299 assert(first_mapping
== mapping
->first_mapping_index
);
2300 if (mapping
->info
.dir
.parent_mapping_index
< 0)
2303 mapping_t
* parent
= array_get(&(s
->mapping
), mapping
->info
.dir
.parent_mapping_index
);
2304 assert(parent
->mode
& MODE_DIRECTORY
);
2305 assert(parent
->info
.dir
.first_dir_index
< mapping
->info
.dir
.first_dir_index
);
2317 static int handle_renames_and_mkdirs(BDRVVVFATState
* s
)
2322 fprintf(stderr
, "handle_renames\n");
2323 for (i
= 0; i
< s
->commits
.next
; i
++) {
2324 commit_t
* commit
= array_get(&(s
->commits
), i
);
2325 fprintf(stderr
, "%d, %s (%d, %d)\n", i
, commit
->path
? commit
->path
: "(null)", commit
->param
.rename
.cluster
, commit
->action
);
2329 for (i
= 0; i
< s
->commits
.next
;) {
2330 commit_t
* commit
= array_get(&(s
->commits
), i
);
2331 if (commit
->action
== ACTION_RENAME
) {
2332 mapping_t
* mapping
= find_mapping_for_cluster(s
,
2333 commit
->param
.rename
.cluster
);
2334 char* old_path
= mapping
->path
;
2336 assert(commit
->path
);
2337 mapping
->path
= commit
->path
;
2338 if (rename(old_path
, mapping
->path
))
2341 if (mapping
->mode
& MODE_DIRECTORY
) {
2342 int l1
= strlen(mapping
->path
);
2343 int l2
= strlen(old_path
);
2345 direntry_t
* direntry
= array_get(&(s
->directory
),
2346 mapping
->info
.dir
.first_dir_index
);
2347 uint32_t c
= mapping
->begin
;
2351 while (!fat_eof(s
, c
)) {
2353 direntry_t
* d
= direntry
+ i
;
2355 if (is_file(d
) || (is_directory(d
) && !is_dot(d
))) {
2356 mapping_t
* m
= find_mapping_for_cluster(s
,
2357 begin_of_direntry(d
));
2358 int l
= strlen(m
->path
);
2359 char* new_path
= g_malloc(l
+ diff
+ 1);
2361 assert(!strncmp(m
->path
, mapping
->path
, l2
));
2363 pstrcpy(new_path
, l
+ diff
+ 1, mapping
->path
);
2364 pstrcpy(new_path
+ l1
, l
+ diff
+ 1 - l1
,
2367 schedule_rename(s
, m
->begin
, new_path
);
2370 } while((i
% (0x10 * s
->sectors_per_cluster
)) != 0);
2376 array_remove(&(s
->commits
), i
);
2378 } else if (commit
->action
== ACTION_MKDIR
) {
2380 int j
, parent_path_len
;
2383 if (mkdir(commit
->path
))
2386 if (mkdir(commit
->path
, 0755))
2390 mapping
= insert_mapping(s
, commit
->param
.mkdir
.cluster
,
2391 commit
->param
.mkdir
.cluster
+ 1);
2392 if (mapping
== NULL
)
2395 mapping
->mode
= MODE_DIRECTORY
;
2396 mapping
->read_only
= 0;
2397 mapping
->path
= commit
->path
;
2398 j
= s
->directory
.next
;
2400 insert_direntries(s
, s
->directory
.next
,
2401 0x10 * s
->sectors_per_cluster
);
2402 mapping
->info
.dir
.first_dir_index
= j
;
2404 parent_path_len
= strlen(commit
->path
)
2405 - strlen(get_basename(commit
->path
)) - 1;
2406 for (j
= 0; j
< s
->mapping
.next
; j
++) {
2407 mapping_t
* m
= array_get(&(s
->mapping
), j
);
2408 if (m
->first_mapping_index
< 0 && m
!= mapping
&&
2409 !strncmp(m
->path
, mapping
->path
, parent_path_len
) &&
2410 strlen(m
->path
) == parent_path_len
)
2413 assert(j
< s
->mapping
.next
);
2414 mapping
->info
.dir
.parent_mapping_index
= j
;
2416 array_remove(&(s
->commits
), i
);
2426 * TODO: make sure that the short name is not matching *another* file
2428 static int handle_commits(BDRVVVFATState
* s
)
2432 vvfat_close_current_file(s
);
2434 for (i
= 0; !fail
&& i
< s
->commits
.next
; i
++) {
2435 commit_t
* commit
= array_get(&(s
->commits
), i
);
2436 switch(commit
->action
) {
2437 case ACTION_RENAME
: case ACTION_MKDIR
:
2441 case ACTION_WRITEOUT
: {
2443 /* these variables are only used by assert() below */
2444 direntry_t
* entry
= array_get(&(s
->directory
),
2445 commit
->param
.writeout
.dir_index
);
2446 uint32_t begin
= begin_of_direntry(entry
);
2447 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin
);
2451 assert(mapping
->begin
== begin
);
2452 assert(commit
->path
== NULL
);
2454 if (commit_one_file(s
, commit
->param
.writeout
.dir_index
,
2455 commit
->param
.writeout
.modified_offset
))
2460 case ACTION_NEW_FILE
: {
2461 int begin
= commit
->param
.new_file
.first_cluster
;
2462 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin
);
2467 for (i
= 0; i
< s
->directory
.next
; i
++) {
2468 entry
= array_get(&(s
->directory
), i
);
2469 if (is_file(entry
) && begin_of_direntry(entry
) == begin
)
2473 if (i
>= s
->directory
.next
) {
2478 /* make sure there exists an initial mapping */
2479 if (mapping
&& mapping
->begin
!= begin
) {
2480 mapping
->end
= begin
;
2483 if (mapping
== NULL
) {
2484 mapping
= insert_mapping(s
, begin
, begin
+1);
2486 /* most members will be fixed in commit_mappings() */
2487 assert(commit
->path
);
2488 mapping
->path
= commit
->path
;
2489 mapping
->read_only
= 0;
2490 mapping
->mode
= MODE_NORMAL
;
2491 mapping
->info
.file
.offset
= 0;
2493 if (commit_one_file(s
, i
, 0))
2502 if (i
> 0 && array_remove_slice(&(s
->commits
), 0, i
))
2507 static int handle_deletes(BDRVVVFATState
* s
)
2509 int i
, deferred
= 1, deleted
= 1;
2511 /* delete files corresponding to mappings marked as deleted */
2512 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2513 while (deferred
&& deleted
) {
2517 for (i
= 1; i
< s
->mapping
.next
; i
++) {
2518 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2519 if (mapping
->mode
& MODE_DELETED
) {
2520 direntry_t
* entry
= array_get(&(s
->directory
),
2521 mapping
->dir_index
);
2523 if (is_free(entry
)) {
2524 /* remove file/directory */
2525 if (mapping
->mode
& MODE_DIRECTORY
) {
2526 int j
, next_dir_index
= s
->directory
.next
,
2527 first_dir_index
= mapping
->info
.dir
.first_dir_index
;
2529 if (rmdir(mapping
->path
) < 0) {
2530 if (errno
== ENOTEMPTY
) {
2537 for (j
= 1; j
< s
->mapping
.next
; j
++) {
2538 mapping_t
* m
= array_get(&(s
->mapping
), j
);
2539 if (m
->mode
& MODE_DIRECTORY
&&
2540 m
->info
.dir
.first_dir_index
>
2542 m
->info
.dir
.first_dir_index
<
2545 m
->info
.dir
.first_dir_index
;
2547 remove_direntries(s
, first_dir_index
,
2548 next_dir_index
- first_dir_index
);
2553 if (unlink(mapping
->path
))
2557 DLOG(fprintf(stderr
, "DELETE (%d)\n", i
); print_mapping(mapping
); print_direntry(entry
));
2558 remove_mapping(s
, i
);
2567 * synchronize mapping with new state:
2569 * - copy FAT (with bdrv_read)
2570 * - mark all filenames corresponding to mappings as deleted
2571 * - recurse direntries from root (using bs->bdrv_read)
2572 * - delete files corresponding to mappings marked as deleted
2574 static int do_commit(BDRVVVFATState
* s
)
2578 /* the real meat are the commits. Nothing to do? Move along! */
2579 if (s
->commits
.next
== 0)
2582 vvfat_close_current_file(s
);
2584 ret
= handle_renames_and_mkdirs(s
);
2586 fprintf(stderr
, "Error handling renames (%d)\n", ret
);
2591 /* copy FAT (with bdrv_read) */
2592 memcpy(s
->fat
.pointer
, s
->fat2
, 0x200 * s
->sectors_per_fat
);
2594 /* recurse direntries from root (using bs->bdrv_read) */
2595 ret
= commit_direntries(s
, 0, -1);
2597 fprintf(stderr
, "Fatal: error while committing (%d)\n", ret
);
2602 ret
= handle_commits(s
);
2604 fprintf(stderr
, "Error handling commits (%d)\n", ret
);
2609 ret
= handle_deletes(s
);
2611 fprintf(stderr
, "Error deleting\n");
2616 s
->qcow
->drv
->bdrv_make_empty(s
->qcow
);
2618 memset(s
->used_clusters
, 0, sector2cluster(s
, s
->sector_count
));
2624 static int try_commit(BDRVVVFATState
* s
)
2626 vvfat_close_current_file(s
);
2628 if(!is_consistent(s
))
2630 return do_commit(s
);
2633 static int vvfat_write(BlockDriverState
*bs
, int64_t sector_num
,
2634 const uint8_t *buf
, int nb_sectors
)
2636 BDRVVVFATState
*s
= bs
->opaque
;
2641 /* Check if we're operating in read-only mode */
2642 if (s
->qcow
== NULL
) {
2646 vvfat_close_current_file(s
);
2649 * Some sanity checks:
2650 * - do not allow writing to the boot sector
2651 * - do not allow to write non-ASCII filenames
2654 if (sector_num
< s
->first_sectors_number
)
2657 for (i
= sector2cluster(s
, sector_num
);
2658 i
<= sector2cluster(s
, sector_num
+ nb_sectors
- 1);) {
2659 mapping_t
* mapping
= find_mapping_for_cluster(s
, i
);
2661 if (mapping
->read_only
) {
2662 fprintf(stderr
, "Tried to write to write-protected file %s\n",
2667 if (mapping
->mode
& MODE_DIRECTORY
) {
2668 int begin
= cluster2sector(s
, i
);
2669 int end
= begin
+ s
->sectors_per_cluster
, k
;
2671 const direntry_t
* direntries
;
2676 if (begin
< sector_num
)
2678 if (end
> sector_num
+ nb_sectors
)
2679 end
= sector_num
+ nb_sectors
;
2680 dir_index
= mapping
->dir_index
+
2681 0x10 * (begin
- mapping
->begin
* s
->sectors_per_cluster
);
2682 direntries
= (direntry_t
*)(buf
+ 0x200 * (begin
- sector_num
));
2684 for (k
= 0; k
< (end
- begin
) * 0x10; k
++) {
2685 /* do not allow non-ASCII filenames */
2686 if (parse_long_name(&lfn
, direntries
+ k
) < 0) {
2687 fprintf(stderr
, "Warning: non-ASCII filename\n");
2690 /* no access to the direntry of a read-only file */
2691 else if (is_short_name(direntries
+k
) &&
2692 (direntries
[k
].attributes
& 1)) {
2693 if (memcmp(direntries
+ k
,
2694 array_get(&(s
->directory
), dir_index
+ k
),
2695 sizeof(direntry_t
))) {
2696 fprintf(stderr
, "Warning: tried to write to write-protected file\n");
2708 * Use qcow backend. Commit later.
2710 DLOG(fprintf(stderr
, "Write to qcow backend: %d + %d\n", (int)sector_num
, nb_sectors
));
2711 ret
= s
->qcow
->drv
->bdrv_write(s
->qcow
, sector_num
, buf
, nb_sectors
);
2713 fprintf(stderr
, "Error writing to qcow backend\n");
2717 for (i
= sector2cluster(s
, sector_num
);
2718 i
<= sector2cluster(s
, sector_num
+ nb_sectors
- 1); i
++)
2720 s
->used_clusters
[i
] |= USED_ALLOCATED
;
2723 /* TODO: add timeout */
2730 static coroutine_fn
int vvfat_co_write(BlockDriverState
*bs
, int64_t sector_num
,
2731 const uint8_t *buf
, int nb_sectors
)
2734 BDRVVVFATState
*s
= bs
->opaque
;
2735 qemu_co_mutex_lock(&s
->lock
);
2736 ret
= vvfat_write(bs
, sector_num
, buf
, nb_sectors
);
2737 qemu_co_mutex_unlock(&s
->lock
);
2741 static int vvfat_is_allocated(BlockDriverState
*bs
,
2742 int64_t sector_num
, int nb_sectors
, int* n
)
2744 BDRVVVFATState
* s
= bs
->opaque
;
2745 *n
= s
->sector_count
- sector_num
;
2746 if (*n
> nb_sectors
)
2753 static int write_target_commit(BlockDriverState
*bs
, int64_t sector_num
,
2754 const uint8_t* buffer
, int nb_sectors
) {
2755 BDRVVVFATState
* s
= *((BDRVVVFATState
**) bs
->opaque
);
2756 return try_commit(s
);
2759 static void write_target_close(BlockDriverState
*bs
) {
2760 BDRVVVFATState
* s
= *((BDRVVVFATState
**) bs
->opaque
);
2761 bdrv_delete(s
->qcow
);
2762 g_free(s
->qcow_filename
);
2765 static BlockDriver vvfat_write_target
= {
2766 .format_name
= "vvfat_write_target",
2767 .bdrv_write
= write_target_commit
,
2768 .bdrv_close
= write_target_close
,
2771 static int enable_write_target(BDRVVVFATState
*s
)
2773 BlockDriver
*bdrv_qcow
;
2774 QEMUOptionParameter
*options
;
2776 int size
= sector2cluster(s
, s
->sector_count
);
2777 s
->used_clusters
= calloc(size
, 1);
2779 array_init(&(s
->commits
), sizeof(commit_t
));
2781 s
->qcow_filename
= g_malloc(1024);
2782 get_tmp_filename(s
->qcow_filename
, 1024);
2784 bdrv_qcow
= bdrv_find_format("qcow");
2785 options
= parse_option_parameters("", bdrv_qcow
->create_options
, NULL
);
2786 set_option_parameter_int(options
, BLOCK_OPT_SIZE
, s
->sector_count
* 512);
2787 set_option_parameter(options
, BLOCK_OPT_BACKING_FILE
, "fat:");
2789 if (bdrv_create(bdrv_qcow
, s
->qcow_filename
, options
) < 0)
2792 s
->qcow
= bdrv_new("");
2793 if (s
->qcow
== NULL
) {
2797 ret
= bdrv_open(s
->qcow
, s
->qcow_filename
,
2798 BDRV_O_RDWR
| BDRV_O_CACHE_WB
| BDRV_O_NO_FLUSH
, bdrv_qcow
);
2804 unlink(s
->qcow_filename
);
2807 s
->bs
->backing_hd
= calloc(sizeof(BlockDriverState
), 1);
2808 s
->bs
->backing_hd
->drv
= &vvfat_write_target
;
2809 s
->bs
->backing_hd
->opaque
= g_malloc(sizeof(void*));
2810 *(void**)s
->bs
->backing_hd
->opaque
= s
;
2815 static void vvfat_close(BlockDriverState
*bs
)
2817 BDRVVVFATState
*s
= bs
->opaque
;
2819 vvfat_close_current_file(s
);
2820 array_free(&(s
->fat
));
2821 array_free(&(s
->directory
));
2822 array_free(&(s
->mapping
));
2823 g_free(s
->cluster_buffer
);
2826 static BlockDriver bdrv_vvfat
= {
2827 .format_name
= "vvfat",
2828 .instance_size
= sizeof(BDRVVVFATState
),
2829 .bdrv_file_open
= vvfat_open
,
2830 .bdrv_read
= vvfat_co_read
,
2831 .bdrv_write
= vvfat_co_write
,
2832 .bdrv_close
= vvfat_close
,
2833 .bdrv_is_allocated
= vvfat_is_allocated
,
2834 .protocol_name
= "fat",
2837 static void bdrv_vvfat_init(void)
2839 bdrv_register(&bdrv_vvfat
);
2842 block_init(bdrv_vvfat_init
);
2845 static void checkpoint(void) {
2846 assert(((mapping_t
*)array_get(&(vvv
->mapping
), 0))->end
== 2);
2849 assert(!vvv
->current_mapping
|| vvv
->current_fd
|| (vvv
->current_mapping
->mode
& MODE_DIRECTORY
));
2851 if (((direntry_t
*)vvv
->directory
.pointer
)[1].attributes
!= 0xf)
2852 fprintf(stderr
, "Nonono!\n");
2854 direntry_t
* direntry
;
2855 assert(vvv
->mapping
.size
>= vvv
->mapping
.item_size
* vvv
->mapping
.next
);
2856 assert(vvv
->directory
.size
>= vvv
->directory
.item_size
* vvv
->directory
.next
);
2857 if (vvv
->mapping
.next
<47)
2859 assert((mapping
= array_get(&(vvv
->mapping
), 47)));
2860 assert(mapping
->dir_index
< vvv
->directory
.next
);
2861 direntry
= array_get(&(vvv
->directory
), mapping
->dir_index
);
2862 assert(!memcmp(direntry
->name
, "USB H ", 11) || direntry
->name
[0]==0);