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
)
91 array
->size
=array
->next
=0;
94 /* does not automatically grow */
95 static inline void* array_get(array_t
* array
,unsigned int index
) {
96 assert(index
< array
->next
);
97 return array
->pointer
+ index
* array
->item_size
;
100 static inline int array_ensure_allocated(array_t
* array
, int index
)
102 if((index
+ 1) * array
->item_size
> array
->size
) {
103 int new_size
= (index
+ 32) * array
->item_size
;
104 array
->pointer
= qemu_realloc(array
->pointer
, new_size
);
107 array
->size
= new_size
;
108 array
->next
= index
+ 1;
114 static inline void* array_get_next(array_t
* array
) {
115 unsigned int next
= array
->next
;
118 if (array_ensure_allocated(array
, next
) < 0)
121 array
->next
= next
+ 1;
122 result
= array_get(array
, next
);
127 static inline void* array_insert(array_t
* array
,unsigned int index
,unsigned int count
) {
128 if((array
->next
+count
)*array
->item_size
>array
->size
) {
129 int increment
=count
*array
->item_size
;
130 array
->pointer
=qemu_realloc(array
->pointer
,array
->size
+increment
);
133 array
->size
+=increment
;
135 memmove(array
->pointer
+(index
+count
)*array
->item_size
,
136 array
->pointer
+index
*array
->item_size
,
137 (array
->next
-index
)*array
->item_size
);
139 return array
->pointer
+index
*array
->item_size
;
142 /* this performs a "roll", so that the element which was at index_from becomes
143 * index_to, but the order of all other elements is preserved. */
144 static inline int array_roll(array_t
* array
,int index_to
,int index_from
,int count
)
152 index_to
<0 || index_to
>=array
->next
||
153 index_from
<0 || index_from
>=array
->next
)
156 if(index_to
==index_from
)
160 from
=array
->pointer
+index_from
*is
;
161 to
=array
->pointer
+index_to
*is
;
162 buf
=qemu_malloc(is
*count
);
163 memcpy(buf
,from
,is
*count
);
165 if(index_to
<index_from
)
166 memmove(to
+is
*count
,to
,from
-to
);
168 memmove(from
,from
+is
*count
,to
-from
);
170 memcpy(to
,buf
,is
*count
);
177 static inline int array_remove_slice(array_t
* array
,int index
, int count
)
181 assert(index
+ count
<= array
->next
);
182 if(array_roll(array
,array
->next
-1,index
,count
))
184 array
->next
-= count
;
188 static int array_remove(array_t
* array
,int index
)
190 return array_remove_slice(array
, index
, 1);
193 /* return the index for a given member */
194 static int array_index(array_t
* array
, void* pointer
)
196 size_t offset
= (char*)pointer
- array
->pointer
;
197 assert((offset
% array
->item_size
) == 0);
198 assert(offset
/array
->item_size
< array
->next
);
199 return offset
/array
->item_size
;
202 /* These structures are used to fake a disk and the VFAT filesystem.
203 * For this reason we need to use __attribute__((packed)). */
205 typedef struct bootsector_t
{
208 uint16_t sector_size
;
209 uint8_t sectors_per_cluster
;
210 uint16_t reserved_sectors
;
211 uint8_t number_of_fats
;
212 uint16_t root_entries
;
213 uint16_t total_sectors16
;
215 uint16_t sectors_per_fat
;
216 uint16_t sectors_per_track
;
217 uint16_t number_of_heads
;
218 uint32_t hidden_sectors
;
219 uint32_t total_sectors
;
222 uint8_t drive_number
;
223 uint8_t current_head
;
226 uint8_t volume_label
[11];
227 } __attribute__((packed
)) fat16
;
229 uint32_t sectors_per_fat
;
232 uint32_t first_cluster_of_root_directory
;
233 uint16_t info_sector
;
234 uint16_t backup_boot_sector
;
236 } __attribute__((packed
)) fat32
;
239 uint8_t ignored
[0x1c0];
241 } __attribute__((packed
)) bootsector_t
;
249 typedef struct partition_t
{
250 uint8_t attributes
; /* 0x80 = bootable */
252 uint8_t fs_type
; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
254 uint32_t start_sector_long
;
255 uint32_t length_sector_long
;
256 } __attribute__((packed
)) partition_t
;
258 typedef struct mbr_t
{
259 uint8_t ignored
[0x1b8];
262 partition_t partition
[4];
264 } __attribute__((packed
)) mbr_t
;
266 typedef struct direntry_t
{
268 uint8_t extension
[3];
279 } __attribute__((packed
)) direntry_t
;
281 /* this structure are used to transparently access the files */
283 typedef struct mapping_t
{
284 /* begin is the first cluster, end is the last+1 */
286 /* as s->directory is growable, no pointer may be used here */
287 unsigned int dir_index
;
288 /* the clusters of a file may be in any order; this points to the first */
289 int first_mapping_index
;
292 * - the offset in the file (in clusters) for a file, or
293 * - the next cluster of the directory for a directory, and
294 * - the address of the buffer for a faked entry
300 int parent_mapping_index
;
304 /* path contains the full path, i.e. it always starts with s->path */
307 enum { MODE_UNDEFINED
= 0, MODE_NORMAL
= 1, MODE_MODIFIED
= 2,
308 MODE_DIRECTORY
= 4, MODE_FAKED
= 8,
309 MODE_DELETED
= 16, MODE_RENAMED
= 32 } mode
;
314 static void print_direntry(const struct direntry_t
*);
315 static void print_mapping(const struct mapping_t
* mapping
);
318 /* here begins the real VVFAT driver */
320 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*)qemu_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 inline uint32_t sector_offset_in_cluster(BDRVVVFATState
* s
,off_t sector_num
)
830 return (sector_num
-s
->first_sectors_number
-2*s
->sectors_per_fat
)%s
->sectors_per_cluster
;
834 static direntry_t
* get_direntry_for_mapping(BDRVVVFATState
* s
,mapping_t
* mapping
)
836 if(mapping
->mode
==MODE_UNDEFINED
)
838 return (direntry_t
*)(s
->directory
.pointer
+sizeof(direntry_t
)*mapping
->dir_index
);
842 static int init_directories(BDRVVVFATState
* s
,
845 bootsector_t
* bootsector
;
848 unsigned int cluster
;
850 memset(&(s
->first_sectors
[0]),0,0x40*0x200);
852 s
->cluster_size
=s
->sectors_per_cluster
*0x200;
853 s
->cluster_buffer
=qemu_malloc(s
->cluster_size
);
856 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
857 * where sc is sector_count,
858 * spf is sectors_per_fat,
859 * spc is sectors_per_clusters, and
860 * fat_type = 12, 16 or 32.
862 i
= 1+s
->sectors_per_cluster
*0x200*8/s
->fat_type
;
863 s
->sectors_per_fat
=(s
->sector_count
+i
)/i
; /* round up */
865 array_init(&(s
->mapping
),sizeof(mapping_t
));
866 array_init(&(s
->directory
),sizeof(direntry_t
));
868 /* add volume label */
870 direntry_t
* entry
=array_get_next(&(s
->directory
));
871 entry
->attributes
=0x28; /* archive | volume label */
872 memcpy(entry
->name
,"QEMU VVF",8);
873 memcpy(entry
->extension
,"AT ",3);
876 /* Now build FAT, and write back information into directory */
879 s
->faked_sectors
=s
->first_sectors_number
+s
->sectors_per_fat
*2;
880 s
->cluster_count
=sector2cluster(s
, s
->sector_count
);
882 mapping
= array_get_next(&(s
->mapping
));
884 mapping
->dir_index
= 0;
885 mapping
->info
.dir
.parent_mapping_index
= -1;
886 mapping
->first_mapping_index
= -1;
887 mapping
->path
= qemu_strdup(dirname
);
888 i
= strlen(mapping
->path
);
889 if (i
> 0 && mapping
->path
[i
- 1] == '/')
890 mapping
->path
[i
- 1] = '\0';
891 mapping
->mode
= MODE_DIRECTORY
;
892 mapping
->read_only
= 0;
893 s
->path
= mapping
->path
;
895 for (i
= 0, cluster
= 0; i
< s
->mapping
.next
; i
++) {
896 /* MS-DOS expects the FAT to be 0 for the root directory
897 * (except for the media byte). */
898 /* LATER TODO: still true for FAT32? */
899 int fix_fat
= (i
!= 0);
900 mapping
= array_get(&(s
->mapping
), i
);
902 if (mapping
->mode
& MODE_DIRECTORY
) {
903 mapping
->begin
= cluster
;
904 if(read_directory(s
, i
)) {
905 fprintf(stderr
, "Could not read directory %s\n",
909 mapping
= array_get(&(s
->mapping
), i
);
911 assert(mapping
->mode
== MODE_UNDEFINED
);
912 mapping
->mode
=MODE_NORMAL
;
913 mapping
->begin
= cluster
;
914 if (mapping
->end
> 0) {
915 direntry_t
* direntry
= array_get(&(s
->directory
),
918 mapping
->end
= cluster
+ 1 + (mapping
->end
-1)/s
->cluster_size
;
919 set_begin_of_direntry(direntry
, mapping
->begin
);
921 mapping
->end
= cluster
+ 1;
926 assert(mapping
->begin
< mapping
->end
);
928 /* next free cluster */
929 cluster
= mapping
->end
;
931 if(cluster
> s
->cluster_count
) {
932 fprintf(stderr
,"Directory does not fit in FAT%d (capacity %s)\n",
934 s
->fat_type
== 12 ? s
->sector_count
== 2880 ? "1.44 MB"
940 /* fix fat for entry */
943 for(j
= mapping
->begin
; j
< mapping
->end
- 1; j
++)
945 fat_set(s
, mapping
->end
- 1, s
->max_fat_value
);
949 mapping
= array_get(&(s
->mapping
), 0);
950 s
->sectors_of_root_directory
= mapping
->end
* s
->sectors_per_cluster
;
951 s
->last_cluster_of_root_directory
= mapping
->end
;
953 /* the FAT signature */
954 fat_set(s
,0,s
->max_fat_value
);
955 fat_set(s
,1,s
->max_fat_value
);
957 s
->current_mapping
= NULL
;
959 bootsector
=(bootsector_t
*)(s
->first_sectors
+(s
->first_sectors_number
-1)*0x200);
960 bootsector
->jump
[0]=0xeb;
961 bootsector
->jump
[1]=0x3e;
962 bootsector
->jump
[2]=0x90;
963 memcpy(bootsector
->name
,"QEMU ",8);
964 bootsector
->sector_size
=cpu_to_le16(0x200);
965 bootsector
->sectors_per_cluster
=s
->sectors_per_cluster
;
966 bootsector
->reserved_sectors
=cpu_to_le16(1);
967 bootsector
->number_of_fats
=0x2; /* number of FATs */
968 bootsector
->root_entries
=cpu_to_le16(s
->sectors_of_root_directory
*0x10);
969 bootsector
->total_sectors16
=s
->sector_count
>0xffff?0:cpu_to_le16(s
->sector_count
);
970 bootsector
->media_type
=(s
->fat_type
!=12?0xf8:s
->sector_count
==5760?0xf9:0xf8); /* media descriptor */
971 s
->fat
.pointer
[0] = bootsector
->media_type
;
972 bootsector
->sectors_per_fat
=cpu_to_le16(s
->sectors_per_fat
);
973 bootsector
->sectors_per_track
=cpu_to_le16(s
->bs
->secs
);
974 bootsector
->number_of_heads
=cpu_to_le16(s
->bs
->heads
);
975 bootsector
->hidden_sectors
=cpu_to_le32(s
->first_sectors_number
==1?0:0x3f);
976 bootsector
->total_sectors
=cpu_to_le32(s
->sector_count
>0xffff?s
->sector_count
:0);
978 /* LATER TODO: if FAT32, this is wrong */
979 bootsector
->u
.fat16
.drive_number
=s
->fat_type
==12?0:0x80; /* assume this is hda (TODO) */
980 bootsector
->u
.fat16
.current_head
=0;
981 bootsector
->u
.fat16
.signature
=0x29;
982 bootsector
->u
.fat16
.id
=cpu_to_le32(0xfabe1afd);
984 memcpy(bootsector
->u
.fat16
.volume_label
,"QEMU VVFAT ",11);
985 memcpy(bootsector
->fat_type
,(s
->fat_type
==12?"FAT12 ":s
->fat_type
==16?"FAT16 ":"FAT32 "),8);
986 bootsector
->magic
[0]=0x55; bootsector
->magic
[1]=0xaa;
992 static BDRVVVFATState
*vvv
= NULL
;
995 static int enable_write_target(BDRVVVFATState
*s
);
996 static int is_consistent(BDRVVVFATState
*s
);
998 static int vvfat_open(BlockDriverState
*bs
, const char* dirname
, int flags
)
1000 BDRVVVFATState
*s
= bs
->opaque
;
1008 DLOG(if (stderr
== NULL
) {
1009 stderr
= fopen("vvfat.log", "a");
1010 setbuf(stderr
, NULL
);
1016 /* LATER TODO: if FAT32, adjust */
1017 s
->sectors_per_cluster
=0x10;
1019 bs
->cyls
=1024; bs
->heads
=16; bs
->secs
=63;
1021 s
->current_cluster
=0xffffffff;
1023 s
->first_sectors_number
=0x40;
1024 /* read only is the default for safety */
1026 s
->qcow
= s
->write_target
= NULL
;
1027 s
->qcow_filename
= NULL
;
1029 s
->downcase_short_names
= 1;
1031 if (!strstart(dirname
, "fat:", NULL
))
1034 if (strstr(dirname
, ":floppy:")) {
1037 s
->first_sectors_number
= 1;
1038 s
->sectors_per_cluster
=2;
1039 bs
->cyls
= 80; bs
->heads
= 2; bs
->secs
= 36;
1042 s
->sector_count
=bs
->cyls
*bs
->heads
*bs
->secs
;
1044 if (strstr(dirname
, ":32:")) {
1045 fprintf(stderr
, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1047 } else if (strstr(dirname
, ":16:")) {
1049 } else if (strstr(dirname
, ":12:")) {
1051 s
->sector_count
=2880;
1054 if (strstr(dirname
, ":rw:")) {
1055 if (enable_write_target(s
))
1060 i
= strrchr(dirname
, ':') - dirname
;
1062 if (dirname
[i
-2] == ':' && qemu_isalpha(dirname
[i
-1]))
1063 /* workaround for DOS drive names */
1068 bs
->total_sectors
=bs
->cyls
*bs
->heads
*bs
->secs
;
1070 if(init_directories(s
, dirname
))
1073 s
->sector_count
= s
->faked_sectors
+ s
->sectors_per_cluster
*s
->cluster_count
;
1075 if(s
->first_sectors_number
==0x40)
1078 /* for some reason or other, MS-DOS does not like to know about CHS... */
1080 bs
->heads
= bs
->cyls
= bs
->secs
= 0;
1082 // assert(is_consistent(s));
1086 static inline void vvfat_close_current_file(BDRVVVFATState
*s
)
1088 if(s
->current_mapping
) {
1089 s
->current_mapping
= NULL
;
1090 if (s
->current_fd
) {
1091 close(s
->current_fd
);
1095 s
->current_cluster
= -1;
1098 /* mappings between index1 and index2-1 are supposed to be ordered
1099 * return value is the index of the last mapping for which end>cluster_num
1101 static inline int find_mapping_for_cluster_aux(BDRVVVFATState
* s
,int cluster_num
,int index1
,int index2
)
1106 index3
=(index1
+index2
)/2;
1107 mapping
=array_get(&(s
->mapping
),index3
);
1108 assert(mapping
->begin
< mapping
->end
);
1109 if(mapping
->begin
>=cluster_num
) {
1110 assert(index2
!=index3
|| index2
==0);
1116 return mapping
->end
<=cluster_num
? index2
: index1
;
1119 assert(index1
<=index2
);
1120 DLOG(mapping
=array_get(&(s
->mapping
),index1
);
1121 assert(mapping
->begin
<=cluster_num
);
1122 assert(index2
>= s
->mapping
.next
||
1123 ((mapping
= array_get(&(s
->mapping
),index2
)) &&
1124 mapping
->end
>cluster_num
)));
1128 static inline mapping_t
* find_mapping_for_cluster(BDRVVVFATState
* s
,int cluster_num
)
1130 int index
=find_mapping_for_cluster_aux(s
,cluster_num
,0,s
->mapping
.next
);
1132 if(index
>=s
->mapping
.next
)
1134 mapping
=array_get(&(s
->mapping
),index
);
1135 if(mapping
->begin
>cluster_num
)
1137 assert(mapping
->begin
<=cluster_num
&& mapping
->end
>cluster_num
);
1142 * This function simply compares path == mapping->path. Since the mappings
1143 * are sorted by cluster, this is expensive: O(n).
1145 static inline mapping_t
* find_mapping_for_path(BDRVVVFATState
* s
,
1150 for (i
= 0; i
< s
->mapping
.next
; i
++) {
1151 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
1152 if (mapping
->first_mapping_index
< 0 &&
1153 !strcmp(path
, mapping
->path
))
1160 static int open_file(BDRVVVFATState
* s
,mapping_t
* mapping
)
1164 if(!s
->current_mapping
||
1165 strcmp(s
->current_mapping
->path
,mapping
->path
)) {
1167 int fd
= open(mapping
->path
, O_RDONLY
| O_BINARY
| O_LARGEFILE
);
1170 vvfat_close_current_file(s
);
1172 s
->current_mapping
= mapping
;
1177 static inline int read_cluster(BDRVVVFATState
*s
,int cluster_num
)
1179 if(s
->current_cluster
!= cluster_num
) {
1182 assert(!s
->current_mapping
|| s
->current_fd
|| (s
->current_mapping
->mode
& MODE_DIRECTORY
));
1183 if(!s
->current_mapping
1184 || s
->current_mapping
->begin
>cluster_num
1185 || s
->current_mapping
->end
<=cluster_num
) {
1186 /* binary search of mappings for file */
1187 mapping_t
* mapping
=find_mapping_for_cluster(s
,cluster_num
);
1189 assert(!mapping
|| (cluster_num
>=mapping
->begin
&& cluster_num
<mapping
->end
));
1191 if (mapping
&& mapping
->mode
& MODE_DIRECTORY
) {
1192 vvfat_close_current_file(s
);
1193 s
->current_mapping
= mapping
;
1194 read_cluster_directory
:
1195 offset
= s
->cluster_size
*(cluster_num
-s
->current_mapping
->begin
);
1196 s
->cluster
= (unsigned char*)s
->directory
.pointer
+offset
1197 + 0x20*s
->current_mapping
->info
.dir
.first_dir_index
;
1198 assert(((s
->cluster
-(unsigned char*)s
->directory
.pointer
)%s
->cluster_size
)==0);
1199 assert((char*)s
->cluster
+s
->cluster_size
<= s
->directory
.pointer
+s
->directory
.next
*s
->directory
.item_size
);
1200 s
->current_cluster
= cluster_num
;
1204 if(open_file(s
,mapping
))
1206 } else if (s
->current_mapping
->mode
& MODE_DIRECTORY
)
1207 goto read_cluster_directory
;
1209 assert(s
->current_fd
);
1211 offset
=s
->cluster_size
*(cluster_num
-s
->current_mapping
->begin
)+s
->current_mapping
->info
.file
.offset
;
1212 if(lseek(s
->current_fd
, offset
, SEEK_SET
)!=offset
)
1214 s
->cluster
=s
->cluster_buffer
;
1215 result
=read(s
->current_fd
,s
->cluster
,s
->cluster_size
);
1217 s
->current_cluster
= -1;
1220 s
->current_cluster
= cluster_num
;
1226 static void hexdump(const void* address
, uint32_t len
)
1228 const unsigned char* p
= address
;
1231 for (i
= 0; i
< len
; i
+= 16) {
1232 for (j
= 0; j
< 16 && i
+ j
< len
; j
++)
1233 fprintf(stderr
, "%02x ", p
[i
+ j
]);
1235 fprintf(stderr
, " ");
1236 fprintf(stderr
, " ");
1237 for (j
= 0; j
< 16 && i
+ j
< len
; j
++)
1238 fprintf(stderr
, "%c", (p
[i
+ j
] < ' ' || p
[i
+ j
] > 0x7f) ? '.' : p
[i
+ j
]);
1239 fprintf(stderr
, "\n");
1243 static void print_direntry(const direntry_t
* direntry
)
1248 fprintf(stderr
, "direntry %p: ", direntry
);
1251 if(is_long_name(direntry
)) {
1252 unsigned char* c
=(unsigned char*)direntry
;
1254 for(i
=1;i
<11 && c
[i
] && c
[i
]!=0xff;i
+=2)
1255 #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
1257 for(i
=14;i
<26 && c
[i
] && c
[i
]!=0xff;i
+=2)
1259 for(i
=28;i
<32 && c
[i
] && c
[i
]!=0xff;i
+=2)
1262 fprintf(stderr
, "%s\n", buffer
);
1266 ADD_CHAR(direntry
->name
[i
]);
1268 fprintf(stderr
,"%s attributes=0x%02x begin=%d size=%d\n",
1270 direntry
->attributes
,
1271 begin_of_direntry(direntry
),le32_to_cpu(direntry
->size
));
1275 static void print_mapping(const mapping_t
* mapping
)
1277 fprintf(stderr
, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1278 "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1279 mapping
, mapping
->begin
, mapping
->end
, mapping
->dir_index
,
1280 mapping
->first_mapping_index
, mapping
->path
, mapping
->mode
);
1282 if (mapping
->mode
& MODE_DIRECTORY
)
1283 fprintf(stderr
, "parent_mapping_index = %d, first_dir_index = %d\n", mapping
->info
.dir
.parent_mapping_index
, mapping
->info
.dir
.first_dir_index
);
1285 fprintf(stderr
, "offset = %d\n", mapping
->info
.file
.offset
);
1289 static int vvfat_read(BlockDriverState
*bs
, int64_t sector_num
,
1290 uint8_t *buf
, int nb_sectors
)
1292 BDRVVVFATState
*s
= bs
->opaque
;
1295 for(i
=0;i
<nb_sectors
;i
++,sector_num
++) {
1296 if (sector_num
>= s
->sector_count
)
1300 if (s
->qcow
->drv
->bdrv_is_allocated(s
->qcow
,
1301 sector_num
, nb_sectors
-i
, &n
)) {
1302 DLOG(fprintf(stderr
, "sectors %d+%d allocated\n", (int)sector_num
, n
));
1303 if (s
->qcow
->drv
->bdrv_read(s
->qcow
, sector_num
, buf
+i
*0x200, n
))
1306 sector_num
+= n
- 1;
1309 DLOG(fprintf(stderr
, "sector %d not allocated\n", (int)sector_num
));
1311 if(sector_num
<s
->faked_sectors
) {
1312 if(sector_num
<s
->first_sectors_number
)
1313 memcpy(buf
+i
*0x200,&(s
->first_sectors
[sector_num
*0x200]),0x200);
1314 else if(sector_num
-s
->first_sectors_number
<s
->sectors_per_fat
)
1315 memcpy(buf
+i
*0x200,&(s
->fat
.pointer
[(sector_num
-s
->first_sectors_number
)*0x200]),0x200);
1316 else if(sector_num
-s
->first_sectors_number
-s
->sectors_per_fat
<s
->sectors_per_fat
)
1317 memcpy(buf
+i
*0x200,&(s
->fat
.pointer
[(sector_num
-s
->first_sectors_number
-s
->sectors_per_fat
)*0x200]),0x200);
1319 uint32_t sector
=sector_num
-s
->faked_sectors
,
1320 sector_offset_in_cluster
=(sector
%s
->sectors_per_cluster
),
1321 cluster_num
=sector
/s
->sectors_per_cluster
;
1322 if(read_cluster(s
, cluster_num
) != 0) {
1323 /* LATER TODO: strict: return -1; */
1324 memset(buf
+i
*0x200,0,0x200);
1327 memcpy(buf
+i
*0x200,s
->cluster
+sector_offset_in_cluster
*0x200,0x200);
1333 /* LATER TODO: statify all functions */
1336 * Idea of the write support (use snapshot):
1338 * 1. check if all data is consistent, recording renames, modifications,
1339 * new files and directories (in s->commits).
1341 * 2. if the data is not consistent, stop committing
1343 * 3. handle renames, and create new files and directories (do not yet
1344 * write their contents)
1346 * 4. walk the directories, fixing the mapping and direntries, and marking
1347 * the handled mappings as not deleted
1349 * 5. commit the contents of the files
1351 * 6. handle deleted files and directories
1355 typedef struct commit_t
{
1358 struct { uint32_t cluster
; } rename
;
1359 struct { int dir_index
; uint32_t modified_offset
; } writeout
;
1360 struct { uint32_t first_cluster
; } new_file
;
1361 struct { uint32_t cluster
; } mkdir
;
1363 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1365 ACTION_RENAME
, ACTION_WRITEOUT
, ACTION_NEW_FILE
, ACTION_MKDIR
1369 static void clear_commits(BDRVVVFATState
* s
)
1372 DLOG(fprintf(stderr
, "clear_commits (%d commits)\n", s
->commits
.next
));
1373 for (i
= 0; i
< s
->commits
.next
; i
++) {
1374 commit_t
* commit
= array_get(&(s
->commits
), i
);
1375 assert(commit
->path
|| commit
->action
== ACTION_WRITEOUT
);
1376 if (commit
->action
!= ACTION_WRITEOUT
) {
1377 assert(commit
->path
);
1380 assert(commit
->path
== NULL
);
1382 s
->commits
.next
= 0;
1385 static void schedule_rename(BDRVVVFATState
* s
,
1386 uint32_t cluster
, char* new_path
)
1388 commit_t
* commit
= array_get_next(&(s
->commits
));
1389 commit
->path
= new_path
;
1390 commit
->param
.rename
.cluster
= cluster
;
1391 commit
->action
= ACTION_RENAME
;
1394 static void schedule_writeout(BDRVVVFATState
* s
,
1395 int dir_index
, uint32_t modified_offset
)
1397 commit_t
* commit
= array_get_next(&(s
->commits
));
1398 commit
->path
= NULL
;
1399 commit
->param
.writeout
.dir_index
= dir_index
;
1400 commit
->param
.writeout
.modified_offset
= modified_offset
;
1401 commit
->action
= ACTION_WRITEOUT
;
1404 static void schedule_new_file(BDRVVVFATState
* s
,
1405 char* path
, uint32_t first_cluster
)
1407 commit_t
* commit
= array_get_next(&(s
->commits
));
1408 commit
->path
= path
;
1409 commit
->param
.new_file
.first_cluster
= first_cluster
;
1410 commit
->action
= ACTION_NEW_FILE
;
1413 static void schedule_mkdir(BDRVVVFATState
* s
, uint32_t cluster
, char* path
)
1415 commit_t
* commit
= array_get_next(&(s
->commits
));
1416 commit
->path
= path
;
1417 commit
->param
.mkdir
.cluster
= cluster
;
1418 commit
->action
= ACTION_MKDIR
;
1423 * Since the sequence number is at most 0x3f, and the filename
1424 * length is at most 13 times the sequence number, the maximal
1425 * filename length is 0x3f * 13 bytes.
1427 unsigned char name
[0x3f * 13 + 1];
1429 int sequence_number
;
1432 static void lfn_init(long_file_name
* lfn
)
1434 lfn
->sequence_number
= lfn
->len
= 0;
1435 lfn
->checksum
= 0x100;
1438 /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1439 static int parse_long_name(long_file_name
* lfn
,
1440 const direntry_t
* direntry
)
1443 const unsigned char* pointer
= (const unsigned char*)direntry
;
1445 if (!is_long_name(direntry
))
1448 if (pointer
[0] & 0x40) {
1449 lfn
->sequence_number
= pointer
[0] & 0x3f;
1450 lfn
->checksum
= pointer
[13];
1452 lfn
->name
[lfn
->sequence_number
* 13] = 0;
1453 } else if ((pointer
[0] & 0x3f) != --lfn
->sequence_number
)
1455 else if (pointer
[13] != lfn
->checksum
)
1457 else if (pointer
[12] || pointer
[26] || pointer
[27])
1460 offset
= 13 * (lfn
->sequence_number
- 1);
1461 for (i
= 0, j
= 1; i
< 13; i
++, j
+=2) {
1467 if (pointer
[j
+1] == 0)
1468 lfn
->name
[offset
+ i
] = pointer
[j
];
1469 else if (pointer
[j
+1] != 0xff || (pointer
[0] & 0x40) == 0)
1472 lfn
->name
[offset
+ i
] = 0;
1475 if (pointer
[0] & 0x40)
1476 lfn
->len
= offset
+ strlen((char*)lfn
->name
+ offset
);
1481 /* returns 0 if successful, >0 if no short_name, and <0 on error */
1482 static int parse_short_name(BDRVVVFATState
* s
,
1483 long_file_name
* lfn
, direntry_t
* direntry
)
1487 if (!is_short_name(direntry
))
1490 for (j
= 7; j
>= 0 && direntry
->name
[j
] == ' '; j
--);
1491 for (i
= 0; i
<= j
; i
++) {
1492 if (direntry
->name
[i
] <= ' ' || direntry
->name
[i
] > 0x7f)
1494 else if (s
->downcase_short_names
)
1495 lfn
->name
[i
] = qemu_tolower(direntry
->name
[i
]);
1497 lfn
->name
[i
] = direntry
->name
[i
];
1500 for (j
= 2; j
>= 0 && direntry
->extension
[j
] == ' '; j
--);
1502 lfn
->name
[i
++] = '.';
1503 lfn
->name
[i
+ j
+ 1] = '\0';
1504 for (;j
>= 0; j
--) {
1505 if (direntry
->extension
[j
] <= ' ' || direntry
->extension
[j
] > 0x7f)
1507 else if (s
->downcase_short_names
)
1508 lfn
->name
[i
+ j
] = qemu_tolower(direntry
->extension
[j
]);
1510 lfn
->name
[i
+ j
] = direntry
->extension
[j
];
1513 lfn
->name
[i
+ j
+ 1] = '\0';
1515 lfn
->len
= strlen((char*)lfn
->name
);
1520 static inline uint32_t modified_fat_get(BDRVVVFATState
* s
,
1521 unsigned int cluster
)
1523 if (cluster
< s
->last_cluster_of_root_directory
) {
1524 if (cluster
+ 1 == s
->last_cluster_of_root_directory
)
1525 return s
->max_fat_value
;
1530 if (s
->fat_type
==32) {
1531 uint32_t* entry
=((uint32_t*)s
->fat2
)+cluster
;
1532 return le32_to_cpu(*entry
);
1533 } else if (s
->fat_type
==16) {
1534 uint16_t* entry
=((uint16_t*)s
->fat2
)+cluster
;
1535 return le16_to_cpu(*entry
);
1537 const uint8_t* x
=s
->fat2
+cluster
*3/2;
1538 return ((x
[0]|(x
[1]<<8))>>(cluster
&1?4:0))&0x0fff;
1542 static inline int cluster_was_modified(BDRVVVFATState
* s
, uint32_t cluster_num
)
1544 int was_modified
= 0;
1547 if (s
->qcow
== NULL
)
1550 for (i
= 0; !was_modified
&& i
< s
->sectors_per_cluster
; i
++)
1551 was_modified
= s
->qcow
->drv
->bdrv_is_allocated(s
->qcow
,
1552 cluster2sector(s
, cluster_num
) + i
, 1, &dummy
);
1554 return was_modified
;
1557 static const char* get_basename(const char* path
)
1559 char* basename
= strrchr(path
, '/');
1560 if (basename
== NULL
)
1563 return basename
+ 1; /* strip '/' */
1567 * The array s->used_clusters holds the states of the clusters. If it is
1568 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1569 * was modified, bit 3 is set.
1570 * If any cluster is allocated, but not part of a file or directory, this
1571 * driver refuses to commit.
1574 USED_DIRECTORY
= 1, USED_FILE
= 2, USED_ANY
= 3, USED_ALLOCATED
= 4
1578 * get_cluster_count_for_direntry() not only determines how many clusters
1579 * are occupied by direntry, but also if it was renamed or modified.
1581 * A file is thought to be renamed *only* if there already was a file with
1582 * exactly the same first cluster, but a different name.
1584 * Further, the files/directories handled by this function are
1585 * assumed to be *not* deleted (and *only* those).
1587 static uint32_t get_cluster_count_for_direntry(BDRVVVFATState
* s
,
1588 direntry_t
* direntry
, const char* path
)
1591 * This is a little bit tricky:
1592 * IF the guest OS just inserts a cluster into the file chain,
1593 * and leaves the rest alone, (i.e. the original file had clusters
1594 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1596 * - do_commit will write the cluster into the file at the given
1599 * - the cluster which is overwritten should be moved to a later
1600 * position in the file.
1602 * I am not aware that any OS does something as braindead, but this
1603 * situation could happen anyway when not committing for a long time.
1604 * Just to be sure that this does not bite us, detect it, and copy the
1605 * contents of the clusters to-be-overwritten into the qcow.
1608 int was_modified
= 0;
1611 uint32_t cluster_num
= begin_of_direntry(direntry
);
1612 uint32_t offset
= 0;
1613 int first_mapping_index
= -1;
1614 mapping_t
* mapping
= NULL
;
1615 const char* basename2
= NULL
;
1617 vvfat_close_current_file(s
);
1619 /* the root directory */
1620 if (cluster_num
== 0)
1625 basename2
= get_basename(path
);
1627 mapping
= find_mapping_for_cluster(s
, cluster_num
);
1630 const char* basename
;
1632 assert(mapping
->mode
& MODE_DELETED
);
1633 mapping
->mode
&= ~MODE_DELETED
;
1635 basename
= get_basename(mapping
->path
);
1637 assert(mapping
->mode
& MODE_NORMAL
);
1640 if (strcmp(basename
, basename2
))
1641 schedule_rename(s
, cluster_num
, qemu_strdup(path
));
1642 } else if (is_file(direntry
))
1644 schedule_new_file(s
, qemu_strdup(path
), cluster_num
);
1653 if (!copy_it
&& cluster_was_modified(s
, cluster_num
)) {
1654 if (mapping
== NULL
||
1655 mapping
->begin
> cluster_num
||
1656 mapping
->end
<= cluster_num
)
1657 mapping
= find_mapping_for_cluster(s
, cluster_num
);
1661 (mapping
->mode
& MODE_DIRECTORY
) == 0) {
1663 /* was modified in qcow */
1664 if (offset
!= mapping
->info
.file
.offset
+ s
->cluster_size
1665 * (cluster_num
- mapping
->begin
)) {
1666 /* offset of this cluster in file chain has changed */
1669 } else if (offset
== 0) {
1670 const char* basename
= get_basename(mapping
->path
);
1672 if (strcmp(basename
, basename2
))
1674 first_mapping_index
= array_index(&(s
->mapping
), mapping
);
1677 if (mapping
->first_mapping_index
!= first_mapping_index
1678 && mapping
->info
.file
.offset
> 0) {
1683 /* need to write out? */
1684 if (!was_modified
&& is_file(direntry
)) {
1686 schedule_writeout(s
, mapping
->dir_index
, offset
);
1694 * This is horribly inefficient, but that is okay, since
1695 * it is rarely executed, if at all.
1697 int64_t offset
= cluster2sector(s
, cluster_num
);
1699 vvfat_close_current_file(s
);
1700 for (i
= 0; i
< s
->sectors_per_cluster
; i
++)
1701 if (!s
->qcow
->drv
->bdrv_is_allocated(s
->qcow
,
1702 offset
+ i
, 1, &dummy
)) {
1703 if (vvfat_read(s
->bs
,
1704 offset
, s
->cluster_buffer
, 1))
1706 if (s
->qcow
->drv
->bdrv_write(s
->qcow
,
1707 offset
, s
->cluster_buffer
, 1))
1714 if (s
->used_clusters
[cluster_num
] & USED_ANY
)
1716 s
->used_clusters
[cluster_num
] = USED_FILE
;
1718 cluster_num
= modified_fat_get(s
, cluster_num
);
1720 if (fat_eof(s
, cluster_num
))
1722 else if (cluster_num
< 2 || cluster_num
> s
->max_fat_value
- 16)
1725 offset
+= s
->cluster_size
;
1730 * This function looks at the modified data (qcow).
1731 * It returns 0 upon inconsistency or error, and the number of clusters
1732 * used by the directory, its subdirectories and their files.
1734 static int check_directory_consistency(BDRVVVFATState
*s
,
1735 int cluster_num
, const char* path
)
1738 unsigned char* cluster
= qemu_malloc(s
->cluster_size
);
1739 direntry_t
* direntries
= (direntry_t
*)cluster
;
1740 mapping_t
* mapping
= find_mapping_for_cluster(s
, cluster_num
);
1743 int path_len
= strlen(path
);
1744 char path2
[PATH_MAX
];
1746 assert(path_len
< PATH_MAX
); /* len was tested before! */
1747 pstrcpy(path2
, sizeof(path2
), path
);
1748 path2
[path_len
] = '/';
1749 path2
[path_len
+ 1] = '\0';
1752 const char* basename
= get_basename(mapping
->path
);
1753 const char* basename2
= get_basename(path
);
1755 assert(mapping
->mode
& MODE_DIRECTORY
);
1757 assert(mapping
->mode
& MODE_DELETED
);
1758 mapping
->mode
&= ~MODE_DELETED
;
1760 if (strcmp(basename
, basename2
))
1761 schedule_rename(s
, cluster_num
, qemu_strdup(path
));
1764 schedule_mkdir(s
, cluster_num
, qemu_strdup(path
));
1773 if (s
->used_clusters
[cluster_num
] & USED_ANY
) {
1774 fprintf(stderr
, "cluster %d used more than once\n", (int)cluster_num
);
1777 s
->used_clusters
[cluster_num
] = USED_DIRECTORY
;
1779 DLOG(fprintf(stderr
, "read cluster %d (sector %d)\n", (int)cluster_num
, (int)cluster2sector(s
, cluster_num
)));
1780 subret
= vvfat_read(s
->bs
, cluster2sector(s
, cluster_num
), cluster
,
1781 s
->sectors_per_cluster
);
1783 fprintf(stderr
, "Error fetching direntries\n");
1789 for (i
= 0; i
< 0x10 * s
->sectors_per_cluster
; i
++) {
1790 int cluster_count
= 0;
1792 DLOG(fprintf(stderr
, "check direntry %d: \n", i
); print_direntry(direntries
+ i
));
1793 if (is_volume_label(direntries
+ i
) || is_dot(direntries
+ i
) ||
1794 is_free(direntries
+ i
))
1797 subret
= parse_long_name(&lfn
, direntries
+ i
);
1799 fprintf(stderr
, "Error in long name\n");
1802 if (subret
== 0 || is_free(direntries
+ i
))
1805 if (fat_chksum(direntries
+i
) != lfn
.checksum
) {
1806 subret
= parse_short_name(s
, &lfn
, direntries
+ i
);
1808 fprintf(stderr
, "Error in short name (%d)\n", subret
);
1811 if (subret
> 0 || !strcmp((char*)lfn
.name
, ".")
1812 || !strcmp((char*)lfn
.name
, ".."))
1815 lfn
.checksum
= 0x100; /* cannot use long name twice */
1817 if (path_len
+ 1 + lfn
.len
>= PATH_MAX
) {
1818 fprintf(stderr
, "Name too long: %s/%s\n", path
, lfn
.name
);
1821 pstrcpy(path2
+ path_len
+ 1, sizeof(path2
) - path_len
- 1,
1824 if (is_directory(direntries
+ i
)) {
1825 if (begin_of_direntry(direntries
+ i
) == 0) {
1826 DLOG(fprintf(stderr
, "invalid begin for directory: %s\n", path2
); print_direntry(direntries
+ i
));
1829 cluster_count
= check_directory_consistency(s
,
1830 begin_of_direntry(direntries
+ i
), path2
);
1831 if (cluster_count
== 0) {
1832 DLOG(fprintf(stderr
, "problem in directory %s:\n", path2
); print_direntry(direntries
+ i
));
1835 } else if (is_file(direntries
+ i
)) {
1836 /* check file size with FAT */
1837 cluster_count
= get_cluster_count_for_direntry(s
, direntries
+ i
, path2
);
1838 if (cluster_count
!=
1839 (le32_to_cpu(direntries
[i
].size
) + s
->cluster_size
1840 - 1) / s
->cluster_size
) {
1841 DLOG(fprintf(stderr
, "Cluster count mismatch\n"));
1845 abort(); /* cluster_count = 0; */
1847 ret
+= cluster_count
;
1850 cluster_num
= modified_fat_get(s
, cluster_num
);
1851 } while(!fat_eof(s
, cluster_num
));
1857 /* returns 1 on success */
1858 static int is_consistent(BDRVVVFATState
* s
)
1861 int used_clusters_count
= 0;
1865 * - get modified FAT
1866 * - compare the two FATs (TODO)
1867 * - get buffer for marking used clusters
1868 * - recurse direntries from root (using bs->bdrv_read to make
1869 * sure to get the new data)
1870 * - check that the FAT agrees with the size
1871 * - count the number of clusters occupied by this directory and
1873 * - check that the cumulative used cluster count agrees with the
1875 * - if all is fine, return number of used clusters
1877 if (s
->fat2
== NULL
) {
1878 int size
= 0x200 * s
->sectors_per_fat
;
1879 s
->fat2
= qemu_malloc(size
);
1880 memcpy(s
->fat2
, s
->fat
.pointer
, size
);
1882 check
= vvfat_read(s
->bs
,
1883 s
->first_sectors_number
, s
->fat2
, s
->sectors_per_fat
);
1885 fprintf(stderr
, "Could not copy fat\n");
1888 assert (s
->used_clusters
);
1889 for (i
= 0; i
< sector2cluster(s
, s
->sector_count
); i
++)
1890 s
->used_clusters
[i
] &= ~USED_ANY
;
1894 /* mark every mapped file/directory as deleted.
1895 * (check_directory_consistency() will unmark those still present). */
1897 for (i
= 0; i
< s
->mapping
.next
; i
++) {
1898 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
1899 if (mapping
->first_mapping_index
< 0)
1900 mapping
->mode
|= MODE_DELETED
;
1903 used_clusters_count
= check_directory_consistency(s
, 0, s
->path
);
1904 if (used_clusters_count
<= 0) {
1905 DLOG(fprintf(stderr
, "problem in directory\n"));
1909 check
= s
->last_cluster_of_root_directory
;
1910 for (i
= check
; i
< sector2cluster(s
, s
->sector_count
); i
++) {
1911 if (modified_fat_get(s
, i
)) {
1912 if(!s
->used_clusters
[i
]) {
1913 DLOG(fprintf(stderr
, "FAT was modified (%d), but cluster is not used?\n", i
));
1919 if (s
->used_clusters
[i
] == USED_ALLOCATED
) {
1920 /* allocated, but not used... */
1921 DLOG(fprintf(stderr
, "unused, modified cluster: %d\n", i
));
1926 if (check
!= used_clusters_count
)
1929 return used_clusters_count
;
1932 static inline void adjust_mapping_indices(BDRVVVFATState
* s
,
1933 int offset
, int adjust
)
1937 for (i
= 0; i
< s
->mapping
.next
; i
++) {
1938 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
1940 #define ADJUST_MAPPING_INDEX(name) \
1941 if (mapping->name >= offset) \
1942 mapping->name += adjust
1944 ADJUST_MAPPING_INDEX(first_mapping_index
);
1945 if (mapping
->mode
& MODE_DIRECTORY
)
1946 ADJUST_MAPPING_INDEX(info
.dir
.parent_mapping_index
);
1950 /* insert or update mapping */
1951 static mapping_t
* insert_mapping(BDRVVVFATState
* s
,
1952 uint32_t begin
, uint32_t end
)
1955 * - find mapping where mapping->begin >= begin,
1956 * - if mapping->begin > begin: insert
1957 * - adjust all references to mappings!
1961 int index
= find_mapping_for_cluster_aux(s
, begin
, 0, s
->mapping
.next
);
1962 mapping_t
* mapping
= NULL
;
1963 mapping_t
* first_mapping
= array_get(&(s
->mapping
), 0);
1965 if (index
< s
->mapping
.next
&& (mapping
= array_get(&(s
->mapping
), index
))
1966 && mapping
->begin
< begin
) {
1967 mapping
->end
= begin
;
1969 mapping
= array_get(&(s
->mapping
), index
);
1971 if (index
>= s
->mapping
.next
|| mapping
->begin
> begin
) {
1972 mapping
= array_insert(&(s
->mapping
), index
, 1);
1973 mapping
->path
= NULL
;
1974 adjust_mapping_indices(s
, index
, +1);
1977 mapping
->begin
= begin
;
1980 DLOG(mapping_t
* next_mapping
;
1981 assert(index
+ 1 >= s
->mapping
.next
||
1982 ((next_mapping
= array_get(&(s
->mapping
), index
+ 1)) &&
1983 next_mapping
->begin
>= end
)));
1985 if (s
->current_mapping
&& first_mapping
!= (mapping_t
*)s
->mapping
.pointer
)
1986 s
->current_mapping
= array_get(&(s
->mapping
),
1987 s
->current_mapping
- first_mapping
);
1992 static int remove_mapping(BDRVVVFATState
* s
, int mapping_index
)
1994 mapping_t
* mapping
= array_get(&(s
->mapping
), mapping_index
);
1995 mapping_t
* first_mapping
= array_get(&(s
->mapping
), 0);
1998 if (mapping
->first_mapping_index
< 0)
1999 free(mapping
->path
);
2001 /* remove from s->mapping */
2002 array_remove(&(s
->mapping
), mapping_index
);
2004 /* adjust all references to mappings */
2005 adjust_mapping_indices(s
, mapping_index
, -1);
2007 if (s
->current_mapping
&& first_mapping
!= (mapping_t
*)s
->mapping
.pointer
)
2008 s
->current_mapping
= array_get(&(s
->mapping
),
2009 s
->current_mapping
- first_mapping
);
2014 static void adjust_dirindices(BDRVVVFATState
* s
, int offset
, int adjust
)
2017 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2018 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2019 if (mapping
->dir_index
>= offset
)
2020 mapping
->dir_index
+= adjust
;
2021 if ((mapping
->mode
& MODE_DIRECTORY
) &&
2022 mapping
->info
.dir
.first_dir_index
>= offset
)
2023 mapping
->info
.dir
.first_dir_index
+= adjust
;
2027 static direntry_t
* insert_direntries(BDRVVVFATState
* s
,
2028 int dir_index
, int count
)
2031 * make room in s->directory,
2034 direntry_t
* result
= array_insert(&(s
->directory
), dir_index
, count
);
2037 adjust_dirindices(s
, dir_index
, count
);
2041 static int remove_direntries(BDRVVVFATState
* s
, int dir_index
, int count
)
2043 int ret
= array_remove_slice(&(s
->directory
), dir_index
, count
);
2046 adjust_dirindices(s
, dir_index
, -count
);
2051 * Adapt the mappings of the cluster chain starting at first cluster
2052 * (i.e. if a file starts at first_cluster, the chain is followed according
2053 * to the modified fat, and the corresponding entries in s->mapping are
2056 static int commit_mappings(BDRVVVFATState
* s
,
2057 uint32_t first_cluster
, int dir_index
)
2059 mapping_t
* mapping
= find_mapping_for_cluster(s
, first_cluster
);
2060 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2061 uint32_t cluster
= first_cluster
;
2063 vvfat_close_current_file(s
);
2066 assert(mapping
->begin
== first_cluster
);
2067 mapping
->first_mapping_index
= -1;
2068 mapping
->dir_index
= dir_index
;
2069 mapping
->mode
= (dir_index
<= 0 || is_directory(direntry
)) ?
2070 MODE_DIRECTORY
: MODE_NORMAL
;
2072 while (!fat_eof(s
, cluster
)) {
2075 for (c
= cluster
, c1
= modified_fat_get(s
, c
); c
+ 1 == c1
;
2076 c
= c1
, c1
= modified_fat_get(s
, c1
));
2079 if (c
> mapping
->end
) {
2080 int index
= array_index(&(s
->mapping
), mapping
);
2081 int i
, max_i
= s
->mapping
.next
- index
;
2082 for (i
= 1; i
< max_i
&& mapping
[i
].begin
< c
; i
++);
2084 remove_mapping(s
, index
+ 1);
2086 assert(mapping
== array_get(&(s
->mapping
), s
->mapping
.next
- 1)
2087 || mapping
[1].begin
>= c
);
2090 if (!fat_eof(s
, c1
)) {
2091 int i
= find_mapping_for_cluster_aux(s
, c1
, 0, s
->mapping
.next
);
2092 mapping_t
* next_mapping
= i
>= s
->mapping
.next
? NULL
:
2093 array_get(&(s
->mapping
), i
);
2095 if (next_mapping
== NULL
|| next_mapping
->begin
> c1
) {
2096 int i1
= array_index(&(s
->mapping
), mapping
);
2098 next_mapping
= insert_mapping(s
, c1
, c1
+1);
2102 mapping
= array_get(&(s
->mapping
), i1
);
2105 next_mapping
->dir_index
= mapping
->dir_index
;
2106 next_mapping
->first_mapping_index
=
2107 mapping
->first_mapping_index
< 0 ?
2108 array_index(&(s
->mapping
), mapping
) :
2109 mapping
->first_mapping_index
;
2110 next_mapping
->path
= mapping
->path
;
2111 next_mapping
->mode
= mapping
->mode
;
2112 next_mapping
->read_only
= mapping
->read_only
;
2113 if (mapping
->mode
& MODE_DIRECTORY
) {
2114 next_mapping
->info
.dir
.parent_mapping_index
=
2115 mapping
->info
.dir
.parent_mapping_index
;
2116 next_mapping
->info
.dir
.first_dir_index
=
2117 mapping
->info
.dir
.first_dir_index
+
2118 0x10 * s
->sectors_per_cluster
*
2119 (mapping
->end
- mapping
->begin
);
2121 next_mapping
->info
.file
.offset
= mapping
->info
.file
.offset
+
2122 mapping
->end
- mapping
->begin
;
2124 mapping
= next_mapping
;
2133 static int commit_direntries(BDRVVVFATState
* s
,
2134 int dir_index
, int parent_mapping_index
)
2136 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2137 uint32_t first_cluster
= dir_index
== 0 ? 0 : begin_of_direntry(direntry
);
2138 mapping_t
* mapping
= find_mapping_for_cluster(s
, first_cluster
);
2140 int factor
= 0x10 * s
->sectors_per_cluster
;
2141 int old_cluster_count
, new_cluster_count
;
2142 int current_dir_index
= mapping
->info
.dir
.first_dir_index
;
2143 int first_dir_index
= current_dir_index
;
2147 DLOG(fprintf(stderr
, "commit_direntries for %s, parent_mapping_index %d\n", mapping
->path
, parent_mapping_index
));
2151 assert(mapping
->begin
== first_cluster
);
2152 assert(mapping
->info
.dir
.first_dir_index
< s
->directory
.next
);
2153 assert(mapping
->mode
& MODE_DIRECTORY
);
2154 assert(dir_index
== 0 || is_directory(direntry
));
2156 mapping
->info
.dir
.parent_mapping_index
= parent_mapping_index
;
2158 if (first_cluster
== 0) {
2159 old_cluster_count
= new_cluster_count
=
2160 s
->last_cluster_of_root_directory
;
2162 for (old_cluster_count
= 0, c
= first_cluster
; !fat_eof(s
, c
);
2164 old_cluster_count
++;
2166 for (new_cluster_count
= 0, c
= first_cluster
; !fat_eof(s
, c
);
2167 c
= modified_fat_get(s
, c
))
2168 new_cluster_count
++;
2171 if (new_cluster_count
> old_cluster_count
) {
2172 if (insert_direntries(s
,
2173 current_dir_index
+ factor
* old_cluster_count
,
2174 factor
* (new_cluster_count
- old_cluster_count
)) == NULL
)
2176 } else if (new_cluster_count
< old_cluster_count
)
2177 remove_direntries(s
,
2178 current_dir_index
+ factor
* new_cluster_count
,
2179 factor
* (old_cluster_count
- new_cluster_count
));
2181 for (c
= first_cluster
; !fat_eof(s
, c
); c
= modified_fat_get(s
, c
)) {
2182 void* direntry
= array_get(&(s
->directory
), current_dir_index
);
2183 int ret
= vvfat_read(s
->bs
, cluster2sector(s
, c
), direntry
,
2184 s
->sectors_per_cluster
);
2187 assert(!strncmp(s
->directory
.pointer
, "QEMU", 4));
2188 current_dir_index
+= factor
;
2191 ret
= commit_mappings(s
, first_cluster
, dir_index
);
2196 for (i
= 0; i
< factor
* new_cluster_count
; i
++) {
2197 direntry
= array_get(&(s
->directory
), first_dir_index
+ i
);
2198 if (is_directory(direntry
) && !is_dot(direntry
)) {
2199 mapping
= find_mapping_for_cluster(s
, first_cluster
);
2200 assert(mapping
->mode
& MODE_DIRECTORY
);
2201 ret
= commit_direntries(s
, first_dir_index
+ i
,
2202 array_index(&(s
->mapping
), mapping
));
2211 /* commit one file (adjust contents, adjust mapping),
2212 return first_mapping_index */
2213 static int commit_one_file(BDRVVVFATState
* s
,
2214 int dir_index
, uint32_t offset
)
2216 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2217 uint32_t c
= begin_of_direntry(direntry
);
2218 uint32_t first_cluster
= c
;
2219 mapping_t
* mapping
= find_mapping_for_cluster(s
, c
);
2220 uint32_t size
= filesize_of_direntry(direntry
);
2221 char* cluster
= qemu_malloc(s
->cluster_size
);
2225 assert(offset
< size
);
2226 assert((offset
% s
->cluster_size
) == 0);
2228 for (i
= s
->cluster_size
; i
< offset
; i
+= s
->cluster_size
)
2229 c
= modified_fat_get(s
, c
);
2231 fd
= open(mapping
->path
, O_RDWR
| O_CREAT
| O_BINARY
, 0666);
2233 fprintf(stderr
, "Could not open %s... (%s, %d)\n", mapping
->path
,
2234 strerror(errno
), errno
);
2238 if (lseek(fd
, offset
, SEEK_SET
) != offset
)
2241 while (offset
< size
) {
2243 int rest_size
= (size
- offset
> s
->cluster_size
?
2244 s
->cluster_size
: size
- offset
);
2247 c1
= modified_fat_get(s
, c
);
2249 assert((size
- offset
== 0 && fat_eof(s
, c
)) ||
2250 (size
> offset
&& c
>=2 && !fat_eof(s
, c
)));
2252 ret
= vvfat_read(s
->bs
, cluster2sector(s
, c
),
2253 (uint8_t*)cluster
, (rest_size
+ 0x1ff) / 0x200);
2258 if (write(fd
, cluster
, rest_size
) < 0)
2261 offset
+= rest_size
;
2265 if (ftruncate(fd
, size
)) {
2266 perror("ftruncate()");
2272 return commit_mappings(s
, first_cluster
, dir_index
);
2276 /* test, if all mappings point to valid direntries */
2277 static void check1(BDRVVVFATState
* s
)
2280 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2281 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2282 if (mapping
->mode
& MODE_DELETED
) {
2283 fprintf(stderr
, "deleted\n");
2286 assert(mapping
->dir_index
< s
->directory
.next
);
2287 direntry_t
* direntry
= array_get(&(s
->directory
), mapping
->dir_index
);
2288 assert(mapping
->begin
== begin_of_direntry(direntry
) || mapping
->first_mapping_index
>= 0);
2289 if (mapping
->mode
& MODE_DIRECTORY
) {
2290 assert(mapping
->info
.dir
.first_dir_index
+ 0x10 * s
->sectors_per_cluster
* (mapping
->end
- mapping
->begin
) <= s
->directory
.next
);
2291 assert((mapping
->info
.dir
.first_dir_index
% (0x10 * s
->sectors_per_cluster
)) == 0);
2296 /* test, if all direntries have mappings */
2297 static void check2(BDRVVVFATState
* s
)
2300 int first_mapping
= -1;
2302 for (i
= 0; i
< s
->directory
.next
; i
++) {
2303 direntry_t
* direntry
= array_get(&(s
->directory
), i
);
2305 if (is_short_name(direntry
) && begin_of_direntry(direntry
)) {
2306 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin_of_direntry(direntry
));
2308 assert(mapping
->dir_index
== i
|| is_dot(direntry
));
2309 assert(mapping
->begin
== begin_of_direntry(direntry
) || is_dot(direntry
));
2312 if ((i
% (0x10 * s
->sectors_per_cluster
)) == 0) {
2316 for (j
= 0; j
< s
->mapping
.next
; j
++) {
2317 mapping_t
* mapping
= array_get(&(s
->mapping
), j
);
2318 if (mapping
->mode
& MODE_DELETED
)
2320 if (mapping
->mode
& MODE_DIRECTORY
) {
2321 if (mapping
->info
.dir
.first_dir_index
<= i
&& mapping
->info
.dir
.first_dir_index
+ 0x10 * s
->sectors_per_cluster
> i
) {
2322 assert(++count
== 1);
2323 if (mapping
->first_mapping_index
== -1)
2324 first_mapping
= array_index(&(s
->mapping
), mapping
);
2326 assert(first_mapping
== mapping
->first_mapping_index
);
2327 if (mapping
->info
.dir
.parent_mapping_index
< 0)
2330 mapping_t
* parent
= array_get(&(s
->mapping
), mapping
->info
.dir
.parent_mapping_index
);
2331 assert(parent
->mode
& MODE_DIRECTORY
);
2332 assert(parent
->info
.dir
.first_dir_index
< mapping
->info
.dir
.first_dir_index
);
2344 static int handle_renames_and_mkdirs(BDRVVVFATState
* s
)
2349 fprintf(stderr
, "handle_renames\n");
2350 for (i
= 0; i
< s
->commits
.next
; i
++) {
2351 commit_t
* commit
= array_get(&(s
->commits
), i
);
2352 fprintf(stderr
, "%d, %s (%d, %d)\n", i
, commit
->path
? commit
->path
: "(null)", commit
->param
.rename
.cluster
, commit
->action
);
2356 for (i
= 0; i
< s
->commits
.next
;) {
2357 commit_t
* commit
= array_get(&(s
->commits
), i
);
2358 if (commit
->action
== ACTION_RENAME
) {
2359 mapping_t
* mapping
= find_mapping_for_cluster(s
,
2360 commit
->param
.rename
.cluster
);
2361 char* old_path
= mapping
->path
;
2363 assert(commit
->path
);
2364 mapping
->path
= commit
->path
;
2365 if (rename(old_path
, mapping
->path
))
2368 if (mapping
->mode
& MODE_DIRECTORY
) {
2369 int l1
= strlen(mapping
->path
);
2370 int l2
= strlen(old_path
);
2372 direntry_t
* direntry
= array_get(&(s
->directory
),
2373 mapping
->info
.dir
.first_dir_index
);
2374 uint32_t c
= mapping
->begin
;
2378 while (!fat_eof(s
, c
)) {
2380 direntry_t
* d
= direntry
+ i
;
2382 if (is_file(d
) || (is_directory(d
) && !is_dot(d
))) {
2383 mapping_t
* m
= find_mapping_for_cluster(s
,
2384 begin_of_direntry(d
));
2385 int l
= strlen(m
->path
);
2386 char* new_path
= qemu_malloc(l
+ diff
+ 1);
2388 assert(!strncmp(m
->path
, mapping
->path
, l2
));
2390 pstrcpy(new_path
, l
+ diff
+ 1, mapping
->path
);
2391 pstrcpy(new_path
+ l1
, l
+ diff
+ 1 - l1
,
2394 schedule_rename(s
, m
->begin
, new_path
);
2397 } while((i
% (0x10 * s
->sectors_per_cluster
)) != 0);
2403 array_remove(&(s
->commits
), i
);
2405 } else if (commit
->action
== ACTION_MKDIR
) {
2407 int j
, parent_path_len
;
2410 if (mkdir(commit
->path
))
2413 if (mkdir(commit
->path
, 0755))
2417 mapping
= insert_mapping(s
, commit
->param
.mkdir
.cluster
,
2418 commit
->param
.mkdir
.cluster
+ 1);
2419 if (mapping
== NULL
)
2422 mapping
->mode
= MODE_DIRECTORY
;
2423 mapping
->read_only
= 0;
2424 mapping
->path
= commit
->path
;
2425 j
= s
->directory
.next
;
2427 insert_direntries(s
, s
->directory
.next
,
2428 0x10 * s
->sectors_per_cluster
);
2429 mapping
->info
.dir
.first_dir_index
= j
;
2431 parent_path_len
= strlen(commit
->path
)
2432 - strlen(get_basename(commit
->path
)) - 1;
2433 for (j
= 0; j
< s
->mapping
.next
; j
++) {
2434 mapping_t
* m
= array_get(&(s
->mapping
), j
);
2435 if (m
->first_mapping_index
< 0 && m
!= mapping
&&
2436 !strncmp(m
->path
, mapping
->path
, parent_path_len
) &&
2437 strlen(m
->path
) == parent_path_len
)
2440 assert(j
< s
->mapping
.next
);
2441 mapping
->info
.dir
.parent_mapping_index
= j
;
2443 array_remove(&(s
->commits
), i
);
2453 * TODO: make sure that the short name is not matching *another* file
2455 static int handle_commits(BDRVVVFATState
* s
)
2459 vvfat_close_current_file(s
);
2461 for (i
= 0; !fail
&& i
< s
->commits
.next
; i
++) {
2462 commit_t
* commit
= array_get(&(s
->commits
), i
);
2463 switch(commit
->action
) {
2464 case ACTION_RENAME
: case ACTION_MKDIR
:
2468 case ACTION_WRITEOUT
: {
2470 /* these variables are only used by assert() below */
2471 direntry_t
* entry
= array_get(&(s
->directory
),
2472 commit
->param
.writeout
.dir_index
);
2473 uint32_t begin
= begin_of_direntry(entry
);
2474 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin
);
2478 assert(mapping
->begin
== begin
);
2479 assert(commit
->path
== NULL
);
2481 if (commit_one_file(s
, commit
->param
.writeout
.dir_index
,
2482 commit
->param
.writeout
.modified_offset
))
2487 case ACTION_NEW_FILE
: {
2488 int begin
= commit
->param
.new_file
.first_cluster
;
2489 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin
);
2494 for (i
= 0; i
< s
->directory
.next
; i
++) {
2495 entry
= array_get(&(s
->directory
), i
);
2496 if (is_file(entry
) && begin_of_direntry(entry
) == begin
)
2500 if (i
>= s
->directory
.next
) {
2505 /* make sure there exists an initial mapping */
2506 if (mapping
&& mapping
->begin
!= begin
) {
2507 mapping
->end
= begin
;
2510 if (mapping
== NULL
) {
2511 mapping
= insert_mapping(s
, begin
, begin
+1);
2513 /* most members will be fixed in commit_mappings() */
2514 assert(commit
->path
);
2515 mapping
->path
= commit
->path
;
2516 mapping
->read_only
= 0;
2517 mapping
->mode
= MODE_NORMAL
;
2518 mapping
->info
.file
.offset
= 0;
2520 if (commit_one_file(s
, i
, 0))
2529 if (i
> 0 && array_remove_slice(&(s
->commits
), 0, i
))
2534 static int handle_deletes(BDRVVVFATState
* s
)
2536 int i
, deferred
= 1, deleted
= 1;
2538 /* delete files corresponding to mappings marked as deleted */
2539 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2540 while (deferred
&& deleted
) {
2544 for (i
= 1; i
< s
->mapping
.next
; i
++) {
2545 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2546 if (mapping
->mode
& MODE_DELETED
) {
2547 direntry_t
* entry
= array_get(&(s
->directory
),
2548 mapping
->dir_index
);
2550 if (is_free(entry
)) {
2551 /* remove file/directory */
2552 if (mapping
->mode
& MODE_DIRECTORY
) {
2553 int j
, next_dir_index
= s
->directory
.next
,
2554 first_dir_index
= mapping
->info
.dir
.first_dir_index
;
2556 if (rmdir(mapping
->path
) < 0) {
2557 if (errno
== ENOTEMPTY
) {
2564 for (j
= 1; j
< s
->mapping
.next
; j
++) {
2565 mapping_t
* m
= array_get(&(s
->mapping
), j
);
2566 if (m
->mode
& MODE_DIRECTORY
&&
2567 m
->info
.dir
.first_dir_index
>
2569 m
->info
.dir
.first_dir_index
<
2572 m
->info
.dir
.first_dir_index
;
2574 remove_direntries(s
, first_dir_index
,
2575 next_dir_index
- first_dir_index
);
2580 if (unlink(mapping
->path
))
2584 DLOG(fprintf(stderr
, "DELETE (%d)\n", i
); print_mapping(mapping
); print_direntry(entry
));
2585 remove_mapping(s
, i
);
2594 * synchronize mapping with new state:
2596 * - copy FAT (with bdrv_read)
2597 * - mark all filenames corresponding to mappings as deleted
2598 * - recurse direntries from root (using bs->bdrv_read)
2599 * - delete files corresponding to mappings marked as deleted
2601 static int do_commit(BDRVVVFATState
* s
)
2605 /* the real meat are the commits. Nothing to do? Move along! */
2606 if (s
->commits
.next
== 0)
2609 vvfat_close_current_file(s
);
2611 ret
= handle_renames_and_mkdirs(s
);
2613 fprintf(stderr
, "Error handling renames (%d)\n", ret
);
2618 /* copy FAT (with bdrv_read) */
2619 memcpy(s
->fat
.pointer
, s
->fat2
, 0x200 * s
->sectors_per_fat
);
2621 /* recurse direntries from root (using bs->bdrv_read) */
2622 ret
= commit_direntries(s
, 0, -1);
2624 fprintf(stderr
, "Fatal: error while committing (%d)\n", ret
);
2629 ret
= handle_commits(s
);
2631 fprintf(stderr
, "Error handling commits (%d)\n", ret
);
2636 ret
= handle_deletes(s
);
2638 fprintf(stderr
, "Error deleting\n");
2643 s
->qcow
->drv
->bdrv_make_empty(s
->qcow
);
2645 memset(s
->used_clusters
, 0, sector2cluster(s
, s
->sector_count
));
2651 static int try_commit(BDRVVVFATState
* s
)
2653 vvfat_close_current_file(s
);
2655 if(!is_consistent(s
))
2657 return do_commit(s
);
2660 static int vvfat_write(BlockDriverState
*bs
, int64_t sector_num
,
2661 const uint8_t *buf
, int nb_sectors
)
2663 BDRVVVFATState
*s
= bs
->opaque
;
2668 /* Check if we're operating in read-only mode */
2669 if (s
->qcow
== NULL
) {
2673 vvfat_close_current_file(s
);
2676 * Some sanity checks:
2677 * - do not allow writing to the boot sector
2678 * - do not allow to write non-ASCII filenames
2681 if (sector_num
< s
->first_sectors_number
)
2684 for (i
= sector2cluster(s
, sector_num
);
2685 i
<= sector2cluster(s
, sector_num
+ nb_sectors
- 1);) {
2686 mapping_t
* mapping
= find_mapping_for_cluster(s
, i
);
2688 if (mapping
->read_only
) {
2689 fprintf(stderr
, "Tried to write to write-protected file %s\n",
2694 if (mapping
->mode
& MODE_DIRECTORY
) {
2695 int begin
= cluster2sector(s
, i
);
2696 int end
= begin
+ s
->sectors_per_cluster
, k
;
2698 const direntry_t
* direntries
;
2703 if (begin
< sector_num
)
2705 if (end
> sector_num
+ nb_sectors
)
2706 end
= sector_num
+ nb_sectors
;
2707 dir_index
= mapping
->dir_index
+
2708 0x10 * (begin
- mapping
->begin
* s
->sectors_per_cluster
);
2709 direntries
= (direntry_t
*)(buf
+ 0x200 * (begin
- sector_num
));
2711 for (k
= 0; k
< (end
- begin
) * 0x10; k
++) {
2712 /* do not allow non-ASCII filenames */
2713 if (parse_long_name(&lfn
, direntries
+ k
) < 0) {
2714 fprintf(stderr
, "Warning: non-ASCII filename\n");
2717 /* no access to the direntry of a read-only file */
2718 else if (is_short_name(direntries
+k
) &&
2719 (direntries
[k
].attributes
& 1)) {
2720 if (memcmp(direntries
+ k
,
2721 array_get(&(s
->directory
), dir_index
+ k
),
2722 sizeof(direntry_t
))) {
2723 fprintf(stderr
, "Warning: tried to write to write-protected file\n");
2735 * Use qcow backend. Commit later.
2737 DLOG(fprintf(stderr
, "Write to qcow backend: %d + %d\n", (int)sector_num
, nb_sectors
));
2738 ret
= s
->qcow
->drv
->bdrv_write(s
->qcow
, sector_num
, buf
, nb_sectors
);
2740 fprintf(stderr
, "Error writing to qcow backend\n");
2744 for (i
= sector2cluster(s
, sector_num
);
2745 i
<= sector2cluster(s
, sector_num
+ nb_sectors
- 1); i
++)
2747 s
->used_clusters
[i
] |= USED_ALLOCATED
;
2750 /* TODO: add timeout */
2757 static int vvfat_is_allocated(BlockDriverState
*bs
,
2758 int64_t sector_num
, int nb_sectors
, int* n
)
2760 BDRVVVFATState
* s
= bs
->opaque
;
2761 *n
= s
->sector_count
- sector_num
;
2762 if (*n
> nb_sectors
)
2769 static int write_target_commit(BlockDriverState
*bs
, int64_t sector_num
,
2770 const uint8_t* buffer
, int nb_sectors
) {
2771 BDRVVVFATState
* s
= *((BDRVVVFATState
**) bs
->opaque
);
2772 return try_commit(s
);
2775 static void write_target_close(BlockDriverState
*bs
) {
2776 BDRVVVFATState
* s
= *((BDRVVVFATState
**) bs
->opaque
);
2777 bdrv_delete(s
->qcow
);
2778 free(s
->qcow_filename
);
2781 static BlockDriver vvfat_write_target
= {
2782 .format_name
= "vvfat_write_target",
2783 .bdrv_write
= write_target_commit
,
2784 .bdrv_close
= write_target_close
,
2787 static int enable_write_target(BDRVVVFATState
*s
)
2789 BlockDriver
*bdrv_qcow
;
2790 QEMUOptionParameter
*options
;
2792 int size
= sector2cluster(s
, s
->sector_count
);
2793 s
->used_clusters
= calloc(size
, 1);
2795 array_init(&(s
->commits
), sizeof(commit_t
));
2797 s
->qcow_filename
= qemu_malloc(1024);
2798 get_tmp_filename(s
->qcow_filename
, 1024);
2800 bdrv_qcow
= bdrv_find_format("qcow");
2801 options
= parse_option_parameters("", bdrv_qcow
->create_options
, NULL
);
2802 set_option_parameter_int(options
, BLOCK_OPT_SIZE
, s
->sector_count
* 512);
2803 set_option_parameter(options
, BLOCK_OPT_BACKING_FILE
, "fat:");
2805 if (bdrv_create(bdrv_qcow
, s
->qcow_filename
, options
) < 0)
2808 s
->qcow
= bdrv_new("");
2809 if (s
->qcow
== NULL
) {
2813 ret
= bdrv_open(s
->qcow
, s
->qcow_filename
,
2814 BDRV_O_RDWR
| BDRV_O_CACHE_WB
| BDRV_O_NO_FLUSH
, bdrv_qcow
);
2820 unlink(s
->qcow_filename
);
2823 s
->bs
->backing_hd
= calloc(sizeof(BlockDriverState
), 1);
2824 s
->bs
->backing_hd
->drv
= &vvfat_write_target
;
2825 s
->bs
->backing_hd
->opaque
= qemu_malloc(sizeof(void*));
2826 *(void**)s
->bs
->backing_hd
->opaque
= s
;
2831 static void vvfat_close(BlockDriverState
*bs
)
2833 BDRVVVFATState
*s
= bs
->opaque
;
2835 vvfat_close_current_file(s
);
2836 array_free(&(s
->fat
));
2837 array_free(&(s
->directory
));
2838 array_free(&(s
->mapping
));
2839 if(s
->cluster_buffer
)
2840 free(s
->cluster_buffer
);
2843 static BlockDriver bdrv_vvfat
= {
2844 .format_name
= "vvfat",
2845 .instance_size
= sizeof(BDRVVVFATState
),
2846 .bdrv_file_open
= vvfat_open
,
2847 .bdrv_read
= vvfat_read
,
2848 .bdrv_write
= vvfat_write
,
2849 .bdrv_close
= vvfat_close
,
2850 .bdrv_is_allocated
= vvfat_is_allocated
,
2851 .protocol_name
= "fat",
2854 static void bdrv_vvfat_init(void)
2856 bdrv_register(&bdrv_vvfat
);
2859 block_init(bdrv_vvfat_init
);
2862 static void checkpoint(void) {
2863 assert(((mapping_t
*)array_get(&(vvv
->mapping
), 0))->end
== 2);
2866 assert(!vvv
->current_mapping
|| vvv
->current_fd
|| (vvv
->current_mapping
->mode
& MODE_DIRECTORY
));
2868 if (((direntry_t
*)vvv
->directory
.pointer
)[1].attributes
!= 0xf)
2869 fprintf(stderr
, "Nonono!\n");
2871 direntry_t
* direntry
;
2872 assert(vvv
->mapping
.size
>= vvv
->mapping
.item_size
* vvv
->mapping
.next
);
2873 assert(vvv
->directory
.size
>= vvv
->directory
.item_size
* vvv
->directory
.next
);
2874 if (vvv
->mapping
.next
<47)
2876 assert((mapping
= array_get(&(vvv
->mapping
), 47)));
2877 assert(mapping
->dir_index
< vvv
->directory
.next
);
2878 direntry
= array_get(&(vvv
->directory
), mapping
->dir_index
);
2879 assert(!memcmp(direntry
->name
, "USB H ", 11) || direntry
->name
[0]==0);
2882 /* avoid compiler warnings: */
2884 remove_mapping(vvv
, 0);
2885 print_mapping(NULL
);
2886 print_direntry(NULL
);