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
28 #include "qemu-common.h"
29 #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
)
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
=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
)
513 chksum
=(((chksum
&0xfe)>>1)|((chksum
&0x01)?0x80:0))
514 +(unsigned char)entry
->name
[i
];
519 /* if return_time==0, this returns the fat_date, else the fat_time */
520 static uint16_t fat_datetime(time_t time
,int return_time
) {
523 t
=localtime(&time
); /* this is not thread safe */
527 localtime_r(&time
,t
);
530 return cpu_to_le16((t
->tm_sec
/2)|(t
->tm_min
<<5)|(t
->tm_hour
<<11));
531 return cpu_to_le16((t
->tm_mday
)|((t
->tm_mon
+1)<<5)|((t
->tm_year
-80)<<9));
534 static inline void fat_set(BDRVVVFATState
* s
,unsigned int cluster
,uint32_t value
)
536 if(s
->fat_type
==32) {
537 uint32_t* entry
=array_get(&(s
->fat
),cluster
);
538 *entry
=cpu_to_le32(value
);
539 } else if(s
->fat_type
==16) {
540 uint16_t* entry
=array_get(&(s
->fat
),cluster
);
541 *entry
=cpu_to_le16(value
&0xffff);
543 int offset
= (cluster
*3/2);
544 unsigned char* p
= array_get(&(s
->fat
), offset
);
548 p
[1] = (p
[1]&0xf0) | ((value
>>8)&0xf);
551 p
[0] = (p
[0]&0xf) | ((value
&0xf)<<4);
558 static inline uint32_t fat_get(BDRVVVFATState
* s
,unsigned int cluster
)
560 if(s
->fat_type
==32) {
561 uint32_t* entry
=array_get(&(s
->fat
),cluster
);
562 return le32_to_cpu(*entry
);
563 } else if(s
->fat_type
==16) {
564 uint16_t* entry
=array_get(&(s
->fat
),cluster
);
565 return le16_to_cpu(*entry
);
567 const uint8_t* x
=(uint8_t*)(s
->fat
.pointer
)+cluster
*3/2;
568 return ((x
[0]|(x
[1]<<8))>>(cluster
&1?4:0))&0x0fff;
572 static inline int fat_eof(BDRVVVFATState
* s
,uint32_t fat_entry
)
574 if(fat_entry
>s
->max_fat_value
-8)
579 static inline void init_fat(BDRVVVFATState
* s
)
581 if (s
->fat_type
== 12) {
582 array_init(&(s
->fat
),1);
583 array_ensure_allocated(&(s
->fat
),
584 s
->sectors_per_fat
* 0x200 * 3 / 2 - 1);
586 array_init(&(s
->fat
),(s
->fat_type
==32?4:2));
587 array_ensure_allocated(&(s
->fat
),
588 s
->sectors_per_fat
* 0x200 / s
->fat
.item_size
- 1);
590 memset(s
->fat
.pointer
,0,s
->fat
.size
);
592 switch(s
->fat_type
) {
593 case 12: s
->max_fat_value
=0xfff; break;
594 case 16: s
->max_fat_value
=0xffff; break;
595 case 32: s
->max_fat_value
=0x0fffffff; break;
596 default: s
->max_fat_value
=0; /* error... */
601 /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
602 /* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
603 static inline direntry_t
* create_short_and_long_name(BDRVVVFATState
* s
,
604 unsigned int directory_start
, const char* filename
, int is_dot
)
606 int i
,j
,long_index
=s
->directory
.next
;
608 direntry_t
* entry_long
=0;
611 entry
=array_get_next(&(s
->directory
));
612 memset(entry
->name
,0x20,11);
613 memcpy(entry
->name
,filename
,strlen(filename
));
617 entry_long
=create_long_filename(s
,filename
);
619 i
= strlen(filename
);
620 for(j
= i
- 1; j
>0 && filename
[j
]!='.';j
--);
626 entry
=array_get_next(&(s
->directory
));
627 memset(entry
->name
,0x20,11);
628 strncpy((char*)entry
->name
,filename
,i
);
631 for (i
= 0; i
< 3 && filename
[j
+1+i
]; i
++)
632 entry
->extension
[i
] = filename
[j
+1+i
];
634 /* upcase & remove unwanted characters */
636 if(i
==10 || i
==7) for(;i
>0 && entry
->name
[i
]==' ';i
--);
637 if(entry
->name
[i
]<=' ' || entry
->name
[i
]>0x7f
638 || strchr(".*?<>|\":/\\[];,+='",entry
->name
[i
]))
640 else if(entry
->name
[i
]>='a' && entry
->name
[i
]<='z')
641 entry
->name
[i
]+='A'-'a';
644 /* mangle duplicates */
646 direntry_t
* entry1
=array_get(&(s
->directory
),directory_start
);
649 for(;entry1
<entry
;entry1
++)
650 if(!is_long_name(entry1
) && !memcmp(entry1
->name
,entry
->name
,11))
651 break; /* found dupe */
652 if(entry1
==entry
) /* no dupe found */
655 /* use all 8 characters of name */
656 if(entry
->name
[7]==' ') {
658 for(j
=6;j
>0 && entry
->name
[j
]==' ';j
--)
662 /* increment number */
663 for(j
=7;j
>0 && entry
->name
[j
]=='9';j
--)
666 if(entry
->name
[j
]<'0' || entry
->name
[j
]>'9')
673 /* calculate checksum; propagate to long name */
675 uint8_t chksum
=fat_chksum(entry
);
677 /* calculate anew, because realloc could have taken place */
678 entry_long
=array_get(&(s
->directory
),long_index
);
679 while(entry_long
<entry
&& is_long_name(entry_long
)) {
680 entry_long
->reserved
[1]=chksum
;
689 * Read a directory. (the index of the corresponding mapping must be passed).
691 static int read_directory(BDRVVVFATState
* s
, int mapping_index
)
693 mapping_t
* mapping
= array_get(&(s
->mapping
), mapping_index
);
694 direntry_t
* direntry
;
695 const char* dirname
= mapping
->path
;
696 int first_cluster
= mapping
->begin
;
697 int parent_index
= mapping
->info
.dir
.parent_mapping_index
;
698 mapping_t
* parent_mapping
= (mapping_t
*)
699 (parent_index
>= 0 ? array_get(&(s
->mapping
), parent_index
) : 0);
700 int first_cluster_of_parent
= parent_mapping
? parent_mapping
->begin
: -1;
702 DIR* dir
=opendir(dirname
);
703 struct dirent
* entry
;
706 assert(mapping
->mode
& MODE_DIRECTORY
);
709 mapping
->end
= mapping
->begin
;
713 i
= mapping
->info
.dir
.first_dir_index
=
714 first_cluster
== 0 ? 0 : s
->directory
.next
;
716 /* actually read the directory, and allocate the mappings */
717 while((entry
=readdir(dir
))) {
718 unsigned int length
=strlen(dirname
)+2+strlen(entry
->d_name
);
720 direntry_t
* direntry
;
722 int is_dot
=!strcmp(entry
->d_name
,".");
723 int is_dotdot
=!strcmp(entry
->d_name
,"..");
725 if(first_cluster
== 0 && (is_dotdot
|| is_dot
))
728 buffer
=(char*)malloc(length
);
730 snprintf(buffer
,length
,"%s/%s",dirname
,entry
->d_name
);
732 if(stat(buffer
,&st
)<0) {
737 /* create directory entry for this file */
738 direntry
=create_short_and_long_name(s
, i
, entry
->d_name
,
739 is_dot
|| is_dotdot
);
740 direntry
->attributes
=(S_ISDIR(st
.st_mode
)?0x10:0x20);
741 direntry
->reserved
[0]=direntry
->reserved
[1]=0;
742 direntry
->ctime
=fat_datetime(st
.st_ctime
,1);
743 direntry
->cdate
=fat_datetime(st
.st_ctime
,0);
744 direntry
->adate
=fat_datetime(st
.st_atime
,0);
745 direntry
->begin_hi
=0;
746 direntry
->mtime
=fat_datetime(st
.st_mtime
,1);
747 direntry
->mdate
=fat_datetime(st
.st_mtime
,0);
749 set_begin_of_direntry(direntry
, first_cluster_of_parent
);
751 set_begin_of_direntry(direntry
, first_cluster
);
753 direntry
->begin
=0; /* do that later */
754 if (st
.st_size
> 0x7fffffff) {
755 fprintf(stderr
, "File %s is larger than 2GB\n", buffer
);
759 direntry
->size
=cpu_to_le32(S_ISDIR(st
.st_mode
)?0:st
.st_size
);
761 /* create mapping for this file */
762 if(!is_dot
&& !is_dotdot
&& (S_ISDIR(st
.st_mode
) || st
.st_size
)) {
763 s
->current_mapping
=(mapping_t
*)array_get_next(&(s
->mapping
));
764 s
->current_mapping
->begin
=0;
765 s
->current_mapping
->end
=st
.st_size
;
767 * we get the direntry of the most recent direntry, which
768 * contains the short name and all the relevant information.
770 s
->current_mapping
->dir_index
=s
->directory
.next
-1;
771 s
->current_mapping
->first_mapping_index
= -1;
772 if (S_ISDIR(st
.st_mode
)) {
773 s
->current_mapping
->mode
= MODE_DIRECTORY
;
774 s
->current_mapping
->info
.dir
.parent_mapping_index
=
777 s
->current_mapping
->mode
= MODE_UNDEFINED
;
778 s
->current_mapping
->info
.file
.offset
= 0;
780 s
->current_mapping
->path
=buffer
;
781 s
->current_mapping
->read_only
=
782 (st
.st_mode
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) == 0;
787 /* fill with zeroes up to the end of the cluster */
788 while(s
->directory
.next
%(0x10*s
->sectors_per_cluster
)) {
789 direntry_t
* direntry
=array_get_next(&(s
->directory
));
790 memset(direntry
,0,sizeof(direntry_t
));
793 /* TODO: if there are more entries, bootsector has to be adjusted! */
794 #define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
795 if (mapping_index
== 0 && s
->directory
.next
< ROOT_ENTRIES
) {
797 int cur
= s
->directory
.next
;
798 array_ensure_allocated(&(s
->directory
), ROOT_ENTRIES
- 1);
799 memset(array_get(&(s
->directory
), cur
), 0,
800 (ROOT_ENTRIES
- cur
) * sizeof(direntry_t
));
803 /* reget the mapping, since s->mapping was possibly realloc()ed */
804 mapping
= (mapping_t
*)array_get(&(s
->mapping
), mapping_index
);
805 first_cluster
+= (s
->directory
.next
- mapping
->info
.dir
.first_dir_index
)
806 * 0x20 / s
->cluster_size
;
807 mapping
->end
= first_cluster
;
809 direntry
= (direntry_t
*)array_get(&(s
->directory
), mapping
->dir_index
);
810 set_begin_of_direntry(direntry
, mapping
->begin
);
815 static inline uint32_t sector2cluster(BDRVVVFATState
* s
,off_t sector_num
)
817 return (sector_num
-s
->faked_sectors
)/s
->sectors_per_cluster
;
820 static inline off_t
cluster2sector(BDRVVVFATState
* s
, uint32_t cluster_num
)
822 return s
->faked_sectors
+ s
->sectors_per_cluster
* cluster_num
;
825 static inline uint32_t sector_offset_in_cluster(BDRVVVFATState
* s
,off_t sector_num
)
827 return (sector_num
-s
->first_sectors_number
-2*s
->sectors_per_fat
)%s
->sectors_per_cluster
;
831 static direntry_t
* get_direntry_for_mapping(BDRVVVFATState
* s
,mapping_t
* mapping
)
833 if(mapping
->mode
==MODE_UNDEFINED
)
835 return (direntry_t
*)(s
->directory
.pointer
+sizeof(direntry_t
)*mapping
->dir_index
);
839 static int init_directories(BDRVVVFATState
* s
,
842 bootsector_t
* bootsector
;
845 unsigned int cluster
;
847 memset(&(s
->first_sectors
[0]),0,0x40*0x200);
849 s
->cluster_size
=s
->sectors_per_cluster
*0x200;
850 s
->cluster_buffer
=malloc(s
->cluster_size
);
851 assert(s
->cluster_buffer
);
854 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
855 * where sc is sector_count,
856 * spf is sectors_per_fat,
857 * spc is sectors_per_clusters, and
858 * fat_type = 12, 16 or 32.
860 i
= 1+s
->sectors_per_cluster
*0x200*8/s
->fat_type
;
861 s
->sectors_per_fat
=(s
->sector_count
+i
)/i
; /* round up */
863 array_init(&(s
->mapping
),sizeof(mapping_t
));
864 array_init(&(s
->directory
),sizeof(direntry_t
));
866 /* add volume label */
868 direntry_t
* entry
=array_get_next(&(s
->directory
));
869 entry
->attributes
=0x28; /* archive | volume label */
870 snprintf((char*)entry
->name
,11,"QEMU VVFAT");
873 /* Now build FAT, and write back information into directory */
876 s
->faked_sectors
=s
->first_sectors_number
+s
->sectors_per_fat
*2;
877 s
->cluster_count
=sector2cluster(s
, s
->sector_count
);
879 mapping
= array_get_next(&(s
->mapping
));
881 mapping
->dir_index
= 0;
882 mapping
->info
.dir
.parent_mapping_index
= -1;
883 mapping
->first_mapping_index
= -1;
884 mapping
->path
= strdup(dirname
);
885 i
= strlen(mapping
->path
);
886 if (i
> 0 && mapping
->path
[i
- 1] == '/')
887 mapping
->path
[i
- 1] = '\0';
888 mapping
->mode
= MODE_DIRECTORY
;
889 mapping
->read_only
= 0;
890 s
->path
= mapping
->path
;
892 for (i
= 0, cluster
= 0; i
< s
->mapping
.next
; i
++) {
894 /* MS-DOS expects the FAT to be 0 for the root directory
895 * (except for the media byte). */
896 /* LATER TODO: still true for FAT32? */
897 int fix_fat
= (i
!= 0);
898 mapping
= array_get(&(s
->mapping
), i
);
900 if (mapping
->mode
& MODE_DIRECTORY
) {
901 mapping
->begin
= cluster
;
902 if(read_directory(s
, i
)) {
903 fprintf(stderr
, "Could not read directory %s\n",
907 mapping
= array_get(&(s
->mapping
), i
);
909 assert(mapping
->mode
== MODE_UNDEFINED
);
910 mapping
->mode
=MODE_NORMAL
;
911 mapping
->begin
= cluster
;
912 if (mapping
->end
> 0) {
913 direntry_t
* direntry
= array_get(&(s
->directory
),
916 mapping
->end
= cluster
+ 1 + (mapping
->end
-1)/s
->cluster_size
;
917 set_begin_of_direntry(direntry
, mapping
->begin
);
919 mapping
->end
= cluster
+ 1;
924 assert(mapping
->begin
< mapping
->end
);
926 /* fix fat for entry */
928 for(j
= mapping
->begin
; j
< mapping
->end
- 1; j
++)
930 fat_set(s
, mapping
->end
- 1, s
->max_fat_value
);
933 /* next free cluster */
934 cluster
= mapping
->end
;
936 if(cluster
> s
->cluster_count
) {
937 fprintf(stderr
,"Directory does not fit in FAT%d\n",s
->fat_type
);
942 mapping
= array_get(&(s
->mapping
), 0);
943 s
->sectors_of_root_directory
= mapping
->end
* s
->sectors_per_cluster
;
944 s
->last_cluster_of_root_directory
= mapping
->end
;
946 /* the FAT signature */
947 fat_set(s
,0,s
->max_fat_value
);
948 fat_set(s
,1,s
->max_fat_value
);
950 s
->current_mapping
= NULL
;
952 bootsector
=(bootsector_t
*)(s
->first_sectors
+(s
->first_sectors_number
-1)*0x200);
953 bootsector
->jump
[0]=0xeb;
954 bootsector
->jump
[1]=0x3e;
955 bootsector
->jump
[2]=0x90;
956 memcpy(bootsector
->name
,"QEMU ",8);
957 bootsector
->sector_size
=cpu_to_le16(0x200);
958 bootsector
->sectors_per_cluster
=s
->sectors_per_cluster
;
959 bootsector
->reserved_sectors
=cpu_to_le16(1);
960 bootsector
->number_of_fats
=0x2; /* number of FATs */
961 bootsector
->root_entries
=cpu_to_le16(s
->sectors_of_root_directory
*0x10);
962 bootsector
->total_sectors16
=s
->sector_count
>0xffff?0:cpu_to_le16(s
->sector_count
);
963 bootsector
->media_type
=(s
->fat_type
!=12?0xf8:s
->sector_count
==5760?0xf9:0xf8); /* media descriptor */
964 s
->fat
.pointer
[0] = bootsector
->media_type
;
965 bootsector
->sectors_per_fat
=cpu_to_le16(s
->sectors_per_fat
);
966 bootsector
->sectors_per_track
=cpu_to_le16(s
->bs
->secs
);
967 bootsector
->number_of_heads
=cpu_to_le16(s
->bs
->heads
);
968 bootsector
->hidden_sectors
=cpu_to_le32(s
->first_sectors_number
==1?0:0x3f);
969 bootsector
->total_sectors
=cpu_to_le32(s
->sector_count
>0xffff?s
->sector_count
:0);
971 /* LATER TODO: if FAT32, this is wrong */
972 bootsector
->u
.fat16
.drive_number
=s
->fat_type
==12?0:0x80; /* assume this is hda (TODO) */
973 bootsector
->u
.fat16
.current_head
=0;
974 bootsector
->u
.fat16
.signature
=0x29;
975 bootsector
->u
.fat16
.id
=cpu_to_le32(0xfabe1afd);
977 memcpy(bootsector
->u
.fat16
.volume_label
,"QEMU VVFAT ",11);
978 memcpy(bootsector
->fat_type
,(s
->fat_type
==12?"FAT12 ":s
->fat_type
==16?"FAT16 ":"FAT32 "),8);
979 bootsector
->magic
[0]=0x55; bootsector
->magic
[1]=0xaa;
985 static BDRVVVFATState
*vvv
= NULL
;
988 static int enable_write_target(BDRVVVFATState
*s
);
989 static int is_consistent(BDRVVVFATState
*s
);
991 static int vvfat_open(BlockDriverState
*bs
, const char* dirname
, int flags
)
993 BDRVVVFATState
*s
= bs
->opaque
;
1001 DLOG(if (stderr
== NULL
) {
1002 stderr
= fopen("vvfat.log", "a");
1003 setbuf(stderr
, NULL
);
1009 /* LATER TODO: if FAT32, adjust */
1010 s
->sectors_per_cluster
=0x10;
1012 bs
->cyls
=1024; bs
->heads
=16; bs
->secs
=63;
1014 s
->current_cluster
=0xffffffff;
1016 s
->first_sectors_number
=0x40;
1017 /* read only is the default for safety */
1019 s
->qcow
= s
->write_target
= NULL
;
1020 s
->qcow_filename
= NULL
;
1022 s
->downcase_short_names
= 1;
1024 if (!strstart(dirname
, "fat:", NULL
))
1027 if (strstr(dirname
, ":floppy:")) {
1030 s
->first_sectors_number
= 1;
1031 s
->sectors_per_cluster
=2;
1032 bs
->cyls
= 80; bs
->heads
= 2; bs
->secs
= 36;
1035 s
->sector_count
=bs
->cyls
*bs
->heads
*bs
->secs
;
1037 if (strstr(dirname
, ":32:")) {
1038 fprintf(stderr
, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1040 } else if (strstr(dirname
, ":16:")) {
1042 } else if (strstr(dirname
, ":12:")) {
1044 s
->sector_count
=2880;
1047 if (strstr(dirname
, ":rw:")) {
1048 if (enable_write_target(s
))
1053 i
= strrchr(dirname
, ':') - dirname
;
1055 if (dirname
[i
-2] == ':' && isalpha(dirname
[i
-1]))
1056 /* workaround for DOS drive names */
1061 bs
->total_sectors
=bs
->cyls
*bs
->heads
*bs
->secs
;
1063 if(init_directories(s
, dirname
))
1066 s
->sector_count
= s
->faked_sectors
+ s
->sectors_per_cluster
*s
->cluster_count
;
1068 if(s
->first_sectors_number
==0x40)
1071 /* for some reason or other, MS-DOS does not like to know about CHS... */
1073 bs
->heads
= bs
->cyls
= bs
->secs
= 0;
1075 // assert(is_consistent(s));
1079 static inline void vvfat_close_current_file(BDRVVVFATState
*s
)
1081 if(s
->current_mapping
) {
1082 s
->current_mapping
= NULL
;
1083 if (s
->current_fd
) {
1084 close(s
->current_fd
);
1088 s
->current_cluster
= -1;
1091 /* mappings between index1 and index2-1 are supposed to be ordered
1092 * return value is the index of the last mapping for which end>cluster_num
1094 static inline int find_mapping_for_cluster_aux(BDRVVVFATState
* s
,int cluster_num
,int index1
,int index2
)
1096 int index3
=index1
+1;
1099 index3
=(index1
+index2
)/2;
1100 mapping
=array_get(&(s
->mapping
),index3
);
1101 assert(mapping
->begin
< mapping
->end
);
1102 if(mapping
->begin
>=cluster_num
) {
1103 assert(index2
!=index3
|| index2
==0);
1109 return mapping
->end
<=cluster_num
? index2
: index1
;
1112 assert(index1
<=index2
);
1113 DLOG(mapping
=array_get(&(s
->mapping
),index1
);
1114 assert(mapping
->begin
<=cluster_num
);
1115 assert(index2
>= s
->mapping
.next
||
1116 ((mapping
= array_get(&(s
->mapping
),index2
)) &&
1117 mapping
->end
>cluster_num
)));
1121 static inline mapping_t
* find_mapping_for_cluster(BDRVVVFATState
* s
,int cluster_num
)
1123 int index
=find_mapping_for_cluster_aux(s
,cluster_num
,0,s
->mapping
.next
);
1125 if(index
>=s
->mapping
.next
)
1127 mapping
=array_get(&(s
->mapping
),index
);
1128 if(mapping
->begin
>cluster_num
)
1130 assert(mapping
->begin
<=cluster_num
&& mapping
->end
>cluster_num
);
1135 * This function simply compares path == mapping->path. Since the mappings
1136 * are sorted by cluster, this is expensive: O(n).
1138 static inline mapping_t
* find_mapping_for_path(BDRVVVFATState
* s
,
1143 for (i
= 0; i
< s
->mapping
.next
; i
++) {
1144 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
1145 if (mapping
->first_mapping_index
< 0 &&
1146 !strcmp(path
, mapping
->path
))
1153 static int open_file(BDRVVVFATState
* s
,mapping_t
* mapping
)
1157 if(!s
->current_mapping
||
1158 strcmp(s
->current_mapping
->path
,mapping
->path
)) {
1160 int fd
= open(mapping
->path
, O_RDONLY
| O_BINARY
| O_LARGEFILE
);
1163 vvfat_close_current_file(s
);
1165 s
->current_mapping
= mapping
;
1170 static inline int read_cluster(BDRVVVFATState
*s
,int cluster_num
)
1172 if(s
->current_cluster
!= cluster_num
) {
1175 assert(!s
->current_mapping
|| s
->current_fd
|| (s
->current_mapping
->mode
& MODE_DIRECTORY
));
1176 if(!s
->current_mapping
1177 || s
->current_mapping
->begin
>cluster_num
1178 || s
->current_mapping
->end
<=cluster_num
) {
1179 /* binary search of mappings for file */
1180 mapping_t
* mapping
=find_mapping_for_cluster(s
,cluster_num
);
1182 assert(!mapping
|| (cluster_num
>=mapping
->begin
&& cluster_num
<mapping
->end
));
1184 if (mapping
&& mapping
->mode
& MODE_DIRECTORY
) {
1185 vvfat_close_current_file(s
);
1186 s
->current_mapping
= mapping
;
1187 read_cluster_directory
:
1188 offset
= s
->cluster_size
*(cluster_num
-s
->current_mapping
->begin
);
1189 s
->cluster
= (unsigned char*)s
->directory
.pointer
+offset
1190 + 0x20*s
->current_mapping
->info
.dir
.first_dir_index
;
1191 assert(((s
->cluster
-(unsigned char*)s
->directory
.pointer
)%s
->cluster_size
)==0);
1192 assert((char*)s
->cluster
+s
->cluster_size
<= s
->directory
.pointer
+s
->directory
.next
*s
->directory
.item_size
);
1193 s
->current_cluster
= cluster_num
;
1197 if(open_file(s
,mapping
))
1199 } else if (s
->current_mapping
->mode
& MODE_DIRECTORY
)
1200 goto read_cluster_directory
;
1202 assert(s
->current_fd
);
1204 offset
=s
->cluster_size
*(cluster_num
-s
->current_mapping
->begin
)+s
->current_mapping
->info
.file
.offset
;
1205 if(lseek(s
->current_fd
, offset
, SEEK_SET
)!=offset
)
1207 s
->cluster
=s
->cluster_buffer
;
1208 result
=read(s
->current_fd
,s
->cluster
,s
->cluster_size
);
1210 s
->current_cluster
= -1;
1213 s
->current_cluster
= cluster_num
;
1219 static void hexdump(const void* address
, uint32_t len
)
1221 const unsigned char* p
= address
;
1224 for (i
= 0; i
< len
; i
+= 16) {
1225 for (j
= 0; j
< 16 && i
+ j
< len
; j
++)
1226 fprintf(stderr
, "%02x ", p
[i
+ j
]);
1228 fprintf(stderr
, " ");
1229 fprintf(stderr
, " ");
1230 for (j
= 0; j
< 16 && i
+ j
< len
; j
++)
1231 fprintf(stderr
, "%c", (p
[i
+ j
] < ' ' || p
[i
+ j
] > 0x7f) ? '.' : p
[i
+ j
]);
1232 fprintf(stderr
, "\n");
1236 static void print_direntry(const direntry_t
* direntry
)
1241 fprintf(stderr
, "direntry 0x%x: ", (int)direntry
);
1244 if(is_long_name(direntry
)) {
1245 unsigned char* c
=(unsigned char*)direntry
;
1247 for(i
=1;i
<11 && c
[i
] && c
[i
]!=0xff;i
+=2)
1248 #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = '°'; j++;}
1250 for(i
=14;i
<26 && c
[i
] && c
[i
]!=0xff;i
+=2)
1252 for(i
=28;i
<32 && c
[i
] && c
[i
]!=0xff;i
+=2)
1255 fprintf(stderr
, "%s\n", buffer
);
1259 ADD_CHAR(direntry
->name
[i
]);
1261 fprintf(stderr
,"%s attributes=0x%02x begin=%d size=%d\n",
1263 direntry
->attributes
,
1264 begin_of_direntry(direntry
),le32_to_cpu(direntry
->size
));
1268 static void print_mapping(const mapping_t
* mapping
)
1270 fprintf(stderr
, "mapping (0x%x): begin, end = %d, %d, dir_index = %d, first_mapping_index = %d, name = %s, mode = 0x%x, " , (int)mapping
, mapping
->begin
, mapping
->end
, mapping
->dir_index
, mapping
->first_mapping_index
, mapping
->path
, mapping
->mode
);
1271 if (mapping
->mode
& MODE_DIRECTORY
)
1272 fprintf(stderr
, "parent_mapping_index = %d, first_dir_index = %d\n", mapping
->info
.dir
.parent_mapping_index
, mapping
->info
.dir
.first_dir_index
);
1274 fprintf(stderr
, "offset = %d\n", mapping
->info
.file
.offset
);
1278 static int vvfat_read(BlockDriverState
*bs
, int64_t sector_num
,
1279 uint8_t *buf
, int nb_sectors
)
1281 BDRVVVFATState
*s
= bs
->opaque
;
1284 for(i
=0;i
<nb_sectors
;i
++,sector_num
++) {
1285 if (sector_num
>= s
->sector_count
)
1289 if (s
->qcow
->drv
->bdrv_is_allocated(s
->qcow
,
1290 sector_num
, nb_sectors
-i
, &n
)) {
1291 DLOG(fprintf(stderr
, "sectors %d+%d allocated\n", (int)sector_num
, n
));
1292 if (s
->qcow
->drv
->bdrv_read(s
->qcow
, sector_num
, buf
+i
*0x200, n
))
1295 sector_num
+= n
- 1;
1298 DLOG(fprintf(stderr
, "sector %d not allocated\n", (int)sector_num
));
1300 if(sector_num
<s
->faked_sectors
) {
1301 if(sector_num
<s
->first_sectors_number
)
1302 memcpy(buf
+i
*0x200,&(s
->first_sectors
[sector_num
*0x200]),0x200);
1303 else if(sector_num
-s
->first_sectors_number
<s
->sectors_per_fat
)
1304 memcpy(buf
+i
*0x200,&(s
->fat
.pointer
[(sector_num
-s
->first_sectors_number
)*0x200]),0x200);
1305 else if(sector_num
-s
->first_sectors_number
-s
->sectors_per_fat
<s
->sectors_per_fat
)
1306 memcpy(buf
+i
*0x200,&(s
->fat
.pointer
[(sector_num
-s
->first_sectors_number
-s
->sectors_per_fat
)*0x200]),0x200);
1308 uint32_t sector
=sector_num
-s
->faked_sectors
,
1309 sector_offset_in_cluster
=(sector
%s
->sectors_per_cluster
),
1310 cluster_num
=sector
/s
->sectors_per_cluster
;
1311 if(read_cluster(s
, cluster_num
) != 0) {
1312 /* LATER TODO: strict: return -1; */
1313 memset(buf
+i
*0x200,0,0x200);
1316 memcpy(buf
+i
*0x200,s
->cluster
+sector_offset_in_cluster
*0x200,0x200);
1322 /* LATER TODO: statify all functions */
1325 * Idea of the write support (use snapshot):
1327 * 1. check if all data is consistent, recording renames, modifications,
1328 * new files and directories (in s->commits).
1330 * 2. if the data is not consistent, stop committing
1332 * 3. handle renames, and create new files and directories (do not yet
1333 * write their contents)
1335 * 4. walk the directories, fixing the mapping and direntries, and marking
1336 * the handled mappings as not deleted
1338 * 5. commit the contents of the files
1340 * 6. handle deleted files and directories
1344 typedef struct commit_t
{
1347 struct { uint32_t cluster
; } rename
;
1348 struct { int dir_index
; uint32_t modified_offset
; } writeout
;
1349 struct { uint32_t first_cluster
; } new_file
;
1350 struct { uint32_t cluster
; } mkdir
;
1352 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1354 ACTION_RENAME
, ACTION_WRITEOUT
, ACTION_NEW_FILE
, ACTION_MKDIR
1358 static void clear_commits(BDRVVVFATState
* s
)
1361 DLOG(fprintf(stderr
, "clear_commits (%d commits)\n", s
->commits
.next
));
1362 for (i
= 0; i
< s
->commits
.next
; i
++) {
1363 commit_t
* commit
= array_get(&(s
->commits
), i
);
1364 assert(commit
->path
|| commit
->action
== ACTION_WRITEOUT
);
1365 if (commit
->action
!= ACTION_WRITEOUT
) {
1366 assert(commit
->path
);
1369 assert(commit
->path
== NULL
);
1371 s
->commits
.next
= 0;
1374 static void schedule_rename(BDRVVVFATState
* s
,
1375 uint32_t cluster
, char* new_path
)
1377 commit_t
* commit
= array_get_next(&(s
->commits
));
1378 commit
->path
= new_path
;
1379 commit
->param
.rename
.cluster
= cluster
;
1380 commit
->action
= ACTION_RENAME
;
1383 static void schedule_writeout(BDRVVVFATState
* s
,
1384 int dir_index
, uint32_t modified_offset
)
1386 commit_t
* commit
= array_get_next(&(s
->commits
));
1387 commit
->path
= NULL
;
1388 commit
->param
.writeout
.dir_index
= dir_index
;
1389 commit
->param
.writeout
.modified_offset
= modified_offset
;
1390 commit
->action
= ACTION_WRITEOUT
;
1393 static void schedule_new_file(BDRVVVFATState
* s
,
1394 char* path
, uint32_t first_cluster
)
1396 commit_t
* commit
= array_get_next(&(s
->commits
));
1397 commit
->path
= path
;
1398 commit
->param
.new_file
.first_cluster
= first_cluster
;
1399 commit
->action
= ACTION_NEW_FILE
;
1402 static void schedule_mkdir(BDRVVVFATState
* s
, uint32_t cluster
, char* path
)
1404 commit_t
* commit
= array_get_next(&(s
->commits
));
1405 commit
->path
= path
;
1406 commit
->param
.mkdir
.cluster
= cluster
;
1407 commit
->action
= ACTION_MKDIR
;
1412 * Since the sequence number is at most 0x3f, and the filename
1413 * length is at most 13 times the sequence number, the maximal
1414 * filename length is 0x3f * 13 bytes.
1416 unsigned char name
[0x3f * 13 + 1];
1418 int sequence_number
;
1421 static void lfn_init(long_file_name
* lfn
)
1423 lfn
->sequence_number
= lfn
->len
= 0;
1424 lfn
->checksum
= 0x100;
1427 /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1428 static int parse_long_name(long_file_name
* lfn
,
1429 const direntry_t
* direntry
)
1432 const unsigned char* pointer
= (const unsigned char*)direntry
;
1434 if (!is_long_name(direntry
))
1437 if (pointer
[0] & 0x40) {
1438 lfn
->sequence_number
= pointer
[0] & 0x3f;
1439 lfn
->checksum
= pointer
[13];
1441 lfn
->name
[lfn
->sequence_number
* 13] = 0;
1442 } else if ((pointer
[0] & 0x3f) != --lfn
->sequence_number
)
1444 else if (pointer
[13] != lfn
->checksum
)
1446 else if (pointer
[12] || pointer
[26] || pointer
[27])
1449 offset
= 13 * (lfn
->sequence_number
- 1);
1450 for (i
= 0, j
= 1; i
< 13; i
++, j
+=2) {
1456 if (pointer
[j
+1] == 0)
1457 lfn
->name
[offset
+ i
] = pointer
[j
];
1458 else if (pointer
[j
+1] != 0xff || (pointer
[0] & 0x40) == 0)
1461 lfn
->name
[offset
+ i
] = 0;
1464 if (pointer
[0] & 0x40)
1465 lfn
->len
= offset
+ strlen((char*)lfn
->name
+ offset
);
1470 /* returns 0 if successful, >0 if no short_name, and <0 on error */
1471 static int parse_short_name(BDRVVVFATState
* s
,
1472 long_file_name
* lfn
, direntry_t
* direntry
)
1476 if (!is_short_name(direntry
))
1479 for (j
= 7; j
>= 0 && direntry
->name
[j
] == ' '; j
--);
1480 for (i
= 0; i
<= j
; i
++) {
1481 if (direntry
->name
[i
] <= ' ' || direntry
->name
[i
] > 0x7f)
1483 else if (s
->downcase_short_names
)
1484 lfn
->name
[i
] = tolower(direntry
->name
[i
]);
1486 lfn
->name
[i
] = direntry
->name
[i
];
1489 for (j
= 2; j
>= 0 && direntry
->extension
[j
] == ' '; j
--);
1491 lfn
->name
[i
++] = '.';
1492 lfn
->name
[i
+ j
+ 1] = '\0';
1493 for (;j
>= 0; j
--) {
1494 if (direntry
->extension
[j
] <= ' ' || direntry
->extension
[j
] > 0x7f)
1496 else if (s
->downcase_short_names
)
1497 lfn
->name
[i
+ j
] = tolower(direntry
->extension
[j
]);
1499 lfn
->name
[i
+ j
] = direntry
->extension
[j
];
1502 lfn
->name
[i
+ j
+ 1] = '\0';
1504 lfn
->len
= strlen((char*)lfn
->name
);
1509 static inline uint32_t modified_fat_get(BDRVVVFATState
* s
,
1510 unsigned int cluster
)
1512 if (cluster
< s
->last_cluster_of_root_directory
) {
1513 if (cluster
+ 1 == s
->last_cluster_of_root_directory
)
1514 return s
->max_fat_value
;
1519 if (s
->fat_type
==32) {
1520 uint32_t* entry
=((uint32_t*)s
->fat2
)+cluster
;
1521 return le32_to_cpu(*entry
);
1522 } else if (s
->fat_type
==16) {
1523 uint16_t* entry
=((uint16_t*)s
->fat2
)+cluster
;
1524 return le16_to_cpu(*entry
);
1526 const uint8_t* x
=s
->fat2
+cluster
*3/2;
1527 return ((x
[0]|(x
[1]<<8))>>(cluster
&1?4:0))&0x0fff;
1531 static inline int cluster_was_modified(BDRVVVFATState
* s
, uint32_t cluster_num
)
1533 int was_modified
= 0;
1536 if (s
->qcow
== NULL
)
1539 for (i
= 0; !was_modified
&& i
< s
->sectors_per_cluster
; i
++)
1540 was_modified
= s
->qcow
->drv
->bdrv_is_allocated(s
->qcow
,
1541 cluster2sector(s
, cluster_num
) + i
, 1, &dummy
);
1543 return was_modified
;
1546 static const char* get_basename(const char* path
)
1548 char* basename
= strrchr(path
, '/');
1549 if (basename
== NULL
)
1552 return basename
+ 1; /* strip '/' */
1556 * The array s->used_clusters holds the states of the clusters. If it is
1557 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1558 * was modified, bit 3 is set.
1559 * If any cluster is allocated, but not part of a file or directory, this
1560 * driver refuses to commit.
1563 USED_DIRECTORY
= 1, USED_FILE
= 2, USED_ANY
= 3, USED_ALLOCATED
= 4
1567 * get_cluster_count_for_direntry() not only determines how many clusters
1568 * are occupied by direntry, but also if it was renamed or modified.
1570 * A file is thought to be renamed *only* if there already was a file with
1571 * exactly the same first cluster, but a different name.
1573 * Further, the files/directories handled by this function are
1574 * assumed to be *not* deleted (and *only* those).
1576 static uint32_t get_cluster_count_for_direntry(BDRVVVFATState
* s
,
1577 direntry_t
* direntry
, const char* path
)
1580 * This is a little bit tricky:
1581 * IF the guest OS just inserts a cluster into the file chain,
1582 * and leaves the rest alone, (i.e. the original file had clusters
1583 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1585 * - do_commit will write the cluster into the file at the given
1588 * - the cluster which is overwritten should be moved to a later
1589 * position in the file.
1591 * I am not aware that any OS does something as braindead, but this
1592 * situation could happen anyway when not committing for a long time.
1593 * Just to be sure that this does not bite us, detect it, and copy the
1594 * contents of the clusters to-be-overwritten into the qcow.
1597 int was_modified
= 0;
1600 uint32_t cluster_num
= begin_of_direntry(direntry
);
1601 uint32_t offset
= 0;
1602 int first_mapping_index
= -1;
1603 mapping_t
* mapping
= NULL
;
1604 const char* basename2
= NULL
;
1606 vvfat_close_current_file(s
);
1608 /* the root directory */
1609 if (cluster_num
== 0)
1614 basename2
= get_basename(path
);
1616 mapping
= find_mapping_for_cluster(s
, cluster_num
);
1619 const char* basename
;
1621 assert(mapping
->mode
& MODE_DELETED
);
1622 mapping
->mode
&= ~MODE_DELETED
;
1624 basename
= get_basename(mapping
->path
);
1626 assert(mapping
->mode
& MODE_NORMAL
);
1629 if (strcmp(basename
, basename2
))
1630 schedule_rename(s
, cluster_num
, strdup(path
));
1631 } else if (is_file(direntry
))
1633 schedule_new_file(s
, strdup(path
), cluster_num
);
1642 if (!copy_it
&& cluster_was_modified(s
, cluster_num
)) {
1643 if (mapping
== NULL
||
1644 mapping
->begin
> cluster_num
||
1645 mapping
->end
<= cluster_num
)
1646 mapping
= find_mapping_for_cluster(s
, cluster_num
);
1650 (mapping
->mode
& MODE_DIRECTORY
) == 0) {
1652 /* was modified in qcow */
1653 if (offset
!= mapping
->info
.file
.offset
+ s
->cluster_size
1654 * (cluster_num
- mapping
->begin
)) {
1655 /* offset of this cluster in file chain has changed */
1658 } else if (offset
== 0) {
1659 const char* basename
= get_basename(mapping
->path
);
1661 if (strcmp(basename
, basename2
))
1663 first_mapping_index
= array_index(&(s
->mapping
), mapping
);
1666 if (mapping
->first_mapping_index
!= first_mapping_index
1667 && mapping
->info
.file
.offset
> 0) {
1672 /* need to write out? */
1673 if (!was_modified
&& is_file(direntry
)) {
1675 schedule_writeout(s
, mapping
->dir_index
, offset
);
1683 * This is horribly inefficient, but that is okay, since
1684 * it is rarely executed, if at all.
1686 int64_t offset
= cluster2sector(s
, cluster_num
);
1688 vvfat_close_current_file(s
);
1689 for (i
= 0; i
< s
->sectors_per_cluster
; i
++)
1690 if (!s
->qcow
->drv
->bdrv_is_allocated(s
->qcow
,
1691 offset
+ i
, 1, &dummy
)) {
1692 if (vvfat_read(s
->bs
,
1693 offset
, s
->cluster_buffer
, 1))
1695 if (s
->qcow
->drv
->bdrv_write(s
->qcow
,
1696 offset
, s
->cluster_buffer
, 1))
1703 if (s
->used_clusters
[cluster_num
] & USED_ANY
)
1705 s
->used_clusters
[cluster_num
] = USED_FILE
;
1707 cluster_num
= modified_fat_get(s
, cluster_num
);
1709 if (fat_eof(s
, cluster_num
))
1711 else if (cluster_num
< 2 || cluster_num
> s
->max_fat_value
- 16)
1714 offset
+= s
->cluster_size
;
1719 * This function looks at the modified data (qcow).
1720 * It returns 0 upon inconsistency or error, and the number of clusters
1721 * used by the directory, its subdirectories and their files.
1723 static int check_directory_consistency(BDRVVVFATState
*s
,
1724 int cluster_num
, const char* path
)
1727 unsigned char* cluster
= malloc(s
->cluster_size
);
1728 direntry_t
* direntries
= (direntry_t
*)cluster
;
1729 mapping_t
* mapping
= find_mapping_for_cluster(s
, cluster_num
);
1732 int path_len
= strlen(path
);
1733 char path2
[PATH_MAX
];
1735 assert(path_len
< PATH_MAX
); /* len was tested before! */
1736 strcpy(path2
, path
);
1737 path2
[path_len
] = '/';
1738 path2
[path_len
+ 1] = '\0';
1741 const char* basename
= get_basename(mapping
->path
);
1742 const char* basename2
= get_basename(path
);
1744 assert(mapping
->mode
& MODE_DIRECTORY
);
1746 assert(mapping
->mode
& MODE_DELETED
);
1747 mapping
->mode
&= ~MODE_DELETED
;
1749 if (strcmp(basename
, basename2
))
1750 schedule_rename(s
, cluster_num
, strdup(path
));
1753 schedule_mkdir(s
, cluster_num
, strdup(path
));
1762 if (s
->used_clusters
[cluster_num
] & USED_ANY
) {
1763 fprintf(stderr
, "cluster %d used more than once\n", (int)cluster_num
);
1766 s
->used_clusters
[cluster_num
] = USED_DIRECTORY
;
1768 DLOG(fprintf(stderr
, "read cluster %d (sector %d)\n", (int)cluster_num
, (int)cluster2sector(s
, cluster_num
)));
1769 subret
= vvfat_read(s
->bs
, cluster2sector(s
, cluster_num
), cluster
,
1770 s
->sectors_per_cluster
);
1772 fprintf(stderr
, "Error fetching direntries\n");
1778 for (i
= 0; i
< 0x10 * s
->sectors_per_cluster
; i
++) {
1781 DLOG(fprintf(stderr
, "check direntry %d: \n", i
); print_direntry(direntries
+ i
));
1782 if (is_volume_label(direntries
+ i
) || is_dot(direntries
+ i
) ||
1783 is_free(direntries
+ i
))
1786 subret
= parse_long_name(&lfn
, direntries
+ i
);
1788 fprintf(stderr
, "Error in long name\n");
1791 if (subret
== 0 || is_free(direntries
+ i
))
1794 if (fat_chksum(direntries
+i
) != lfn
.checksum
) {
1795 subret
= parse_short_name(s
, &lfn
, direntries
+ i
);
1797 fprintf(stderr
, "Error in short name (%d)\n", subret
);
1800 if (subret
> 0 || !strcmp((char*)lfn
.name
, ".")
1801 || !strcmp((char*)lfn
.name
, ".."))
1804 lfn
.checksum
= 0x100; /* cannot use long name twice */
1806 if (path_len
+ 1 + lfn
.len
>= PATH_MAX
) {
1807 fprintf(stderr
, "Name too long: %s/%s\n", path
, lfn
.name
);
1810 strcpy(path2
+ path_len
+ 1, (char*)lfn
.name
);
1812 if (is_directory(direntries
+ i
)) {
1813 if (begin_of_direntry(direntries
+ i
) == 0) {
1814 DLOG(fprintf(stderr
, "invalid begin for directory: %s\n", path2
); print_direntry(direntries
+ i
));
1817 cluster_count
= check_directory_consistency(s
,
1818 begin_of_direntry(direntries
+ i
), path2
);
1819 if (cluster_count
== 0) {
1820 DLOG(fprintf(stderr
, "problem in directory %s:\n", path2
); print_direntry(direntries
+ i
));
1823 } else if (is_file(direntries
+ i
)) {
1824 /* check file size with FAT */
1825 cluster_count
= get_cluster_count_for_direntry(s
, direntries
+ i
, path2
);
1826 if (cluster_count
!=
1827 (le32_to_cpu(direntries
[i
].size
) + s
->cluster_size
1828 - 1) / s
->cluster_size
) {
1829 DLOG(fprintf(stderr
, "Cluster count mismatch\n"));
1833 assert(0); /* cluster_count = 0; */
1835 ret
+= cluster_count
;
1838 cluster_num
= modified_fat_get(s
, cluster_num
);
1839 } while(!fat_eof(s
, cluster_num
));
1845 /* returns 1 on success */
1846 static int is_consistent(BDRVVVFATState
* s
)
1849 int used_clusters_count
= 0;
1853 * - get modified FAT
1854 * - compare the two FATs (TODO)
1855 * - get buffer for marking used clusters
1856 * - recurse direntries from root (using bs->bdrv_read to make
1857 * sure to get the new data)
1858 * - check that the FAT agrees with the size
1859 * - count the number of clusters occupied by this directory and
1861 * - check that the cumulative used cluster count agrees with the
1863 * - if all is fine, return number of used clusters
1865 if (s
->fat2
== NULL
) {
1866 int size
= 0x200 * s
->sectors_per_fat
;
1867 s
->fat2
= malloc(size
);
1868 memcpy(s
->fat2
, s
->fat
.pointer
, size
);
1870 check
= vvfat_read(s
->bs
,
1871 s
->first_sectors_number
, s
->fat2
, s
->sectors_per_fat
);
1873 fprintf(stderr
, "Could not copy fat\n");
1876 assert (s
->used_clusters
);
1877 for (i
= 0; i
< sector2cluster(s
, s
->sector_count
); i
++)
1878 s
->used_clusters
[i
] &= ~USED_ANY
;
1882 /* mark every mapped file/directory as deleted.
1883 * (check_directory_consistency() will unmark those still present). */
1885 for (i
= 0; i
< s
->mapping
.next
; i
++) {
1886 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
1887 if (mapping
->first_mapping_index
< 0)
1888 mapping
->mode
|= MODE_DELETED
;
1891 used_clusters_count
= check_directory_consistency(s
, 0, s
->path
);
1892 if (used_clusters_count
<= 0) {
1893 DLOG(fprintf(stderr
, "problem in directory\n"));
1897 check
= s
->last_cluster_of_root_directory
;
1898 for (i
= check
; i
< sector2cluster(s
, s
->sector_count
); i
++) {
1899 if (modified_fat_get(s
, i
)) {
1900 if(!s
->used_clusters
[i
]) {
1901 DLOG(fprintf(stderr
, "FAT was modified (%d), but cluster is not used?\n", i
));
1907 if (s
->used_clusters
[i
] == USED_ALLOCATED
) {
1908 /* allocated, but not used... */
1909 DLOG(fprintf(stderr
, "unused, modified cluster: %d\n", i
));
1914 if (check
!= used_clusters_count
)
1917 return used_clusters_count
;
1920 static inline void adjust_mapping_indices(BDRVVVFATState
* s
,
1921 int offset
, int adjust
)
1925 for (i
= 0; i
< s
->mapping
.next
; i
++) {
1926 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
1928 #define ADJUST_MAPPING_INDEX(name) \
1929 if (mapping->name >= offset) \
1930 mapping->name += adjust
1932 ADJUST_MAPPING_INDEX(first_mapping_index
);
1933 if (mapping
->mode
& MODE_DIRECTORY
)
1934 ADJUST_MAPPING_INDEX(info
.dir
.parent_mapping_index
);
1938 /* insert or update mapping */
1939 static mapping_t
* insert_mapping(BDRVVVFATState
* s
,
1940 uint32_t begin
, uint32_t end
)
1943 * - find mapping where mapping->begin >= begin,
1944 * - if mapping->begin > begin: insert
1945 * - adjust all references to mappings!
1949 int index
= find_mapping_for_cluster_aux(s
, begin
, 0, s
->mapping
.next
);
1950 mapping_t
* mapping
= NULL
;
1951 mapping_t
* first_mapping
= array_get(&(s
->mapping
), 0);
1953 if (index
< s
->mapping
.next
&& (mapping
= array_get(&(s
->mapping
), index
))
1954 && mapping
->begin
< begin
) {
1955 mapping
->end
= begin
;
1957 mapping
= array_get(&(s
->mapping
), index
);
1959 if (index
>= s
->mapping
.next
|| mapping
->begin
> begin
) {
1960 mapping
= array_insert(&(s
->mapping
), index
, 1);
1961 mapping
->path
= NULL
;
1962 adjust_mapping_indices(s
, index
, +1);
1965 mapping
->begin
= begin
;
1968 DLOG(mapping_t
* next_mapping
;
1969 assert(index
+ 1 >= s
->mapping
.next
||
1970 ((next_mapping
= array_get(&(s
->mapping
), index
+ 1)) &&
1971 next_mapping
->begin
>= end
)));
1973 if (s
->current_mapping
&& first_mapping
!= (mapping_t
*)s
->mapping
.pointer
)
1974 s
->current_mapping
= array_get(&(s
->mapping
),
1975 s
->current_mapping
- first_mapping
);
1980 static int remove_mapping(BDRVVVFATState
* s
, int mapping_index
)
1982 mapping_t
* mapping
= array_get(&(s
->mapping
), mapping_index
);
1983 mapping_t
* first_mapping
= array_get(&(s
->mapping
), 0);
1986 if (mapping
->first_mapping_index
< 0)
1987 free(mapping
->path
);
1989 /* remove from s->mapping */
1990 array_remove(&(s
->mapping
), mapping_index
);
1992 /* adjust all references to mappings */
1993 adjust_mapping_indices(s
, mapping_index
, -1);
1995 if (s
->current_mapping
&& first_mapping
!= (mapping_t
*)s
->mapping
.pointer
)
1996 s
->current_mapping
= array_get(&(s
->mapping
),
1997 s
->current_mapping
- first_mapping
);
2002 static void adjust_dirindices(BDRVVVFATState
* s
, int offset
, int adjust
)
2005 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2006 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2007 if (mapping
->dir_index
>= offset
)
2008 mapping
->dir_index
+= adjust
;
2009 if ((mapping
->mode
& MODE_DIRECTORY
) &&
2010 mapping
->info
.dir
.first_dir_index
>= offset
)
2011 mapping
->info
.dir
.first_dir_index
+= adjust
;
2015 static direntry_t
* insert_direntries(BDRVVVFATState
* s
,
2016 int dir_index
, int count
)
2019 * make room in s->directory,
2022 direntry_t
* result
= array_insert(&(s
->directory
), dir_index
, count
);
2025 adjust_dirindices(s
, dir_index
, count
);
2029 static int remove_direntries(BDRVVVFATState
* s
, int dir_index
, int count
)
2031 int ret
= array_remove_slice(&(s
->directory
), dir_index
, count
);
2034 adjust_dirindices(s
, dir_index
, -count
);
2039 * Adapt the mappings of the cluster chain starting at first cluster
2040 * (i.e. if a file starts at first_cluster, the chain is followed according
2041 * to the modified fat, and the corresponding entries in s->mapping are
2044 static int commit_mappings(BDRVVVFATState
* s
,
2045 uint32_t first_cluster
, int dir_index
)
2047 mapping_t
* mapping
= find_mapping_for_cluster(s
, first_cluster
);
2048 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2049 uint32_t cluster
= first_cluster
;
2051 vvfat_close_current_file(s
);
2054 assert(mapping
->begin
== first_cluster
);
2055 mapping
->first_mapping_index
= -1;
2056 mapping
->dir_index
= dir_index
;
2057 mapping
->mode
= (dir_index
<= 0 || is_directory(direntry
)) ?
2058 MODE_DIRECTORY
: MODE_NORMAL
;
2060 while (!fat_eof(s
, cluster
)) {
2063 for (c
= cluster
, c1
= modified_fat_get(s
, c
); c
+ 1 == c1
;
2064 c
= c1
, c1
= modified_fat_get(s
, c1
));
2067 if (c
> mapping
->end
) {
2068 int index
= array_index(&(s
->mapping
), mapping
);
2069 int i
, max_i
= s
->mapping
.next
- index
;
2070 for (i
= 1; i
< max_i
&& mapping
[i
].begin
< c
; i
++);
2072 remove_mapping(s
, index
+ 1);
2074 assert(mapping
== array_get(&(s
->mapping
), s
->mapping
.next
- 1)
2075 || mapping
[1].begin
>= c
);
2078 if (!fat_eof(s
, c1
)) {
2079 int i
= find_mapping_for_cluster_aux(s
, c1
, 0, s
->mapping
.next
);
2080 mapping_t
* next_mapping
= i
>= s
->mapping
.next
? NULL
:
2081 array_get(&(s
->mapping
), i
);
2083 if (next_mapping
== NULL
|| next_mapping
->begin
> c1
) {
2084 int i1
= array_index(&(s
->mapping
), mapping
);
2086 next_mapping
= insert_mapping(s
, c1
, c1
+1);
2090 mapping
= array_get(&(s
->mapping
), i1
);
2093 next_mapping
->dir_index
= mapping
->dir_index
;
2094 next_mapping
->first_mapping_index
=
2095 mapping
->first_mapping_index
< 0 ?
2096 array_index(&(s
->mapping
), mapping
) :
2097 mapping
->first_mapping_index
;
2098 next_mapping
->path
= mapping
->path
;
2099 next_mapping
->mode
= mapping
->mode
;
2100 next_mapping
->read_only
= mapping
->read_only
;
2101 if (mapping
->mode
& MODE_DIRECTORY
) {
2102 next_mapping
->info
.dir
.parent_mapping_index
=
2103 mapping
->info
.dir
.parent_mapping_index
;
2104 next_mapping
->info
.dir
.first_dir_index
=
2105 mapping
->info
.dir
.first_dir_index
+
2106 0x10 * s
->sectors_per_cluster
*
2107 (mapping
->end
- mapping
->begin
);
2109 next_mapping
->info
.file
.offset
= mapping
->info
.file
.offset
+
2110 mapping
->end
- mapping
->begin
;
2112 mapping
= next_mapping
;
2121 static int commit_direntries(BDRVVVFATState
* s
,
2122 int dir_index
, int parent_mapping_index
)
2124 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2125 uint32_t first_cluster
= dir_index
== 0 ? 0 : begin_of_direntry(direntry
);
2126 mapping_t
* mapping
= find_mapping_for_cluster(s
, first_cluster
);
2128 int factor
= 0x10 * s
->sectors_per_cluster
;
2129 int old_cluster_count
, new_cluster_count
;
2130 int current_dir_index
= mapping
->info
.dir
.first_dir_index
;
2131 int first_dir_index
= current_dir_index
;
2135 DLOG(fprintf(stderr
, "commit_direntries for %s, parent_mapping_index %d\n", mapping
->path
, parent_mapping_index
));
2139 assert(mapping
->begin
== first_cluster
);
2140 assert(mapping
->info
.dir
.first_dir_index
< s
->directory
.next
);
2141 assert(mapping
->mode
& MODE_DIRECTORY
);
2142 assert(dir_index
== 0 || is_directory(direntry
));
2144 mapping
->info
.dir
.parent_mapping_index
= parent_mapping_index
;
2146 if (first_cluster
== 0) {
2147 old_cluster_count
= new_cluster_count
=
2148 s
->last_cluster_of_root_directory
;
2150 for (old_cluster_count
= 0, c
= first_cluster
; !fat_eof(s
, c
);
2152 old_cluster_count
++;
2154 for (new_cluster_count
= 0, c
= first_cluster
; !fat_eof(s
, c
);
2155 c
= modified_fat_get(s
, c
))
2156 new_cluster_count
++;
2159 if (new_cluster_count
> old_cluster_count
) {
2160 if (insert_direntries(s
,
2161 current_dir_index
+ factor
* old_cluster_count
,
2162 factor
* (new_cluster_count
- old_cluster_count
)) == NULL
)
2164 } else if (new_cluster_count
< old_cluster_count
)
2165 remove_direntries(s
,
2166 current_dir_index
+ factor
* new_cluster_count
,
2167 factor
* (old_cluster_count
- new_cluster_count
));
2169 for (c
= first_cluster
; !fat_eof(s
, c
); c
= modified_fat_get(s
, c
)) {
2170 void* direntry
= array_get(&(s
->directory
), current_dir_index
);
2171 int ret
= vvfat_read(s
->bs
, cluster2sector(s
, c
), direntry
,
2172 s
->sectors_per_cluster
);
2175 assert(!strncmp(s
->directory
.pointer
, "QEMU", 4));
2176 current_dir_index
+= factor
;
2179 ret
= commit_mappings(s
, first_cluster
, dir_index
);
2184 for (i
= 0; i
< factor
* new_cluster_count
; i
++) {
2185 direntry
= array_get(&(s
->directory
), first_dir_index
+ i
);
2186 if (is_directory(direntry
) && !is_dot(direntry
)) {
2187 mapping
= find_mapping_for_cluster(s
, first_cluster
);
2188 assert(mapping
->mode
& MODE_DIRECTORY
);
2189 ret
= commit_direntries(s
, first_dir_index
+ i
,
2190 array_index(&(s
->mapping
), mapping
));
2199 /* commit one file (adjust contents, adjust mapping),
2200 return first_mapping_index */
2201 static int commit_one_file(BDRVVVFATState
* s
,
2202 int dir_index
, uint32_t offset
)
2204 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2205 uint32_t c
= begin_of_direntry(direntry
);
2206 uint32_t first_cluster
= c
;
2207 mapping_t
* mapping
= find_mapping_for_cluster(s
, c
);
2208 uint32_t size
= filesize_of_direntry(direntry
);
2209 char* cluster
= malloc(s
->cluster_size
);
2213 assert(offset
< size
);
2214 assert((offset
% s
->cluster_size
) == 0);
2216 for (i
= s
->cluster_size
; i
< offset
; i
+= s
->cluster_size
)
2217 c
= modified_fat_get(s
, c
);
2219 fd
= open(mapping
->path
, O_RDWR
| O_CREAT
| O_BINARY
, 0666);
2221 fprintf(stderr
, "Could not open %s... (%s, %d)\n", mapping
->path
,
2222 strerror(errno
), errno
);
2226 if (lseek(fd
, offset
, SEEK_SET
) != offset
)
2229 while (offset
< size
) {
2231 int rest_size
= (size
- offset
> s
->cluster_size
?
2232 s
->cluster_size
: size
- offset
);
2235 c1
= modified_fat_get(s
, c
);
2237 assert((size
- offset
== 0 && fat_eof(s
, c
)) ||
2238 (size
> offset
&& c
>=2 && !fat_eof(s
, c
)));
2240 ret
= vvfat_read(s
->bs
, cluster2sector(s
, c
),
2241 (uint8_t*)cluster
, (rest_size
+ 0x1ff) / 0x200);
2246 if (write(fd
, cluster
, rest_size
) < 0)
2249 offset
+= rest_size
;
2253 ftruncate(fd
, size
);
2256 return commit_mappings(s
, first_cluster
, dir_index
);
2260 /* test, if all mappings point to valid direntries */
2261 static void check1(BDRVVVFATState
* s
)
2264 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2265 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2266 if (mapping
->mode
& MODE_DELETED
) {
2267 fprintf(stderr
, "deleted\n");
2270 assert(mapping
->dir_index
>= 0);
2271 assert(mapping
->dir_index
< s
->directory
.next
);
2272 direntry_t
* direntry
= array_get(&(s
->directory
), mapping
->dir_index
);
2273 assert(mapping
->begin
== begin_of_direntry(direntry
) || mapping
->first_mapping_index
>= 0);
2274 if (mapping
->mode
& MODE_DIRECTORY
) {
2275 assert(mapping
->info
.dir
.first_dir_index
+ 0x10 * s
->sectors_per_cluster
* (mapping
->end
- mapping
->begin
) <= s
->directory
.next
);
2276 assert((mapping
->info
.dir
.first_dir_index
% (0x10 * s
->sectors_per_cluster
)) == 0);
2281 /* test, if all direntries have mappings */
2282 static void check2(BDRVVVFATState
* s
)
2285 int first_mapping
= -1;
2287 for (i
= 0; i
< s
->directory
.next
; i
++) {
2288 direntry_t
* direntry
= array_get(&(s
->directory
), i
);
2290 if (is_short_name(direntry
) && begin_of_direntry(direntry
)) {
2291 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin_of_direntry(direntry
));
2293 assert(mapping
->dir_index
== i
|| is_dot(direntry
));
2294 assert(mapping
->begin
== begin_of_direntry(direntry
) || is_dot(direntry
));
2297 if ((i
% (0x10 * s
->sectors_per_cluster
)) == 0) {
2301 for (j
= 0; j
< s
->mapping
.next
; j
++) {
2302 mapping_t
* mapping
= array_get(&(s
->mapping
), j
);
2303 if (mapping
->mode
& MODE_DELETED
)
2305 if (mapping
->mode
& MODE_DIRECTORY
) {
2306 if (mapping
->info
.dir
.first_dir_index
<= i
&& mapping
->info
.dir
.first_dir_index
+ 0x10 * s
->sectors_per_cluster
> i
) {
2307 assert(++count
== 1);
2308 if (mapping
->first_mapping_index
== -1)
2309 first_mapping
= array_index(&(s
->mapping
), mapping
);
2311 assert(first_mapping
== mapping
->first_mapping_index
);
2312 if (mapping
->info
.dir
.parent_mapping_index
< 0)
2315 mapping_t
* parent
= array_get(&(s
->mapping
), mapping
->info
.dir
.parent_mapping_index
);
2316 assert(parent
->mode
& MODE_DIRECTORY
);
2317 assert(parent
->info
.dir
.first_dir_index
< mapping
->info
.dir
.first_dir_index
);
2329 static int handle_renames_and_mkdirs(BDRVVVFATState
* s
)
2334 fprintf(stderr
, "handle_renames\n");
2335 for (i
= 0; i
< s
->commits
.next
; i
++) {
2336 commit_t
* commit
= array_get(&(s
->commits
), i
);
2337 fprintf(stderr
, "%d, %s (%d, %d)\n", i
, commit
->path
? commit
->path
: "(null)", commit
->param
.rename
.cluster
, commit
->action
);
2341 for (i
= 0; i
< s
->commits
.next
;) {
2342 commit_t
* commit
= array_get(&(s
->commits
), i
);
2343 if (commit
->action
== ACTION_RENAME
) {
2344 mapping_t
* mapping
= find_mapping_for_cluster(s
,
2345 commit
->param
.rename
.cluster
);
2346 char* old_path
= mapping
->path
;
2348 assert(commit
->path
);
2349 mapping
->path
= commit
->path
;
2350 if (rename(old_path
, mapping
->path
))
2353 if (mapping
->mode
& MODE_DIRECTORY
) {
2354 int l1
= strlen(mapping
->path
);
2355 int l2
= strlen(old_path
);
2357 direntry_t
* direntry
= array_get(&(s
->directory
),
2358 mapping
->info
.dir
.first_dir_index
);
2359 uint32_t c
= mapping
->begin
;
2363 while (!fat_eof(s
, c
)) {
2365 direntry_t
* d
= direntry
+ i
;
2367 if (is_file(d
) || (is_directory(d
) && !is_dot(d
))) {
2368 mapping_t
* m
= find_mapping_for_cluster(s
,
2369 begin_of_direntry(d
));
2370 int l
= strlen(m
->path
);
2371 char* new_path
= malloc(l
+ diff
+ 1);
2373 assert(!strncmp(m
->path
, mapping
->path
, l2
));
2375 strcpy(new_path
, mapping
->path
);
2376 strcpy(new_path
+ l1
, m
->path
+ l2
);
2378 schedule_rename(s
, m
->begin
, new_path
);
2381 } while((i
% (0x10 * s
->sectors_per_cluster
)) != 0);
2387 array_remove(&(s
->commits
), i
);
2389 } else if (commit
->action
== ACTION_MKDIR
) {
2391 int j
, parent_path_len
;
2394 if (mkdir(commit
->path
))
2397 if (mkdir(commit
->path
, 0755))
2401 mapping
= insert_mapping(s
, commit
->param
.mkdir
.cluster
,
2402 commit
->param
.mkdir
.cluster
+ 1);
2403 if (mapping
== NULL
)
2406 mapping
->mode
= MODE_DIRECTORY
;
2407 mapping
->read_only
= 0;
2408 mapping
->path
= commit
->path
;
2409 j
= s
->directory
.next
;
2411 insert_direntries(s
, s
->directory
.next
,
2412 0x10 * s
->sectors_per_cluster
);
2413 mapping
->info
.dir
.first_dir_index
= j
;
2415 parent_path_len
= strlen(commit
->path
)
2416 - strlen(get_basename(commit
->path
)) - 1;
2417 for (j
= 0; j
< s
->mapping
.next
; j
++) {
2418 mapping_t
* m
= array_get(&(s
->mapping
), j
);
2419 if (m
->first_mapping_index
< 0 && m
!= mapping
&&
2420 !strncmp(m
->path
, mapping
->path
, parent_path_len
) &&
2421 strlen(m
->path
) == parent_path_len
)
2424 assert(j
< s
->mapping
.next
);
2425 mapping
->info
.dir
.parent_mapping_index
= j
;
2427 array_remove(&(s
->commits
), i
);
2437 * TODO: make sure that the short name is not matching *another* file
2439 static int handle_commits(BDRVVVFATState
* s
)
2443 vvfat_close_current_file(s
);
2445 for (i
= 0; !fail
&& i
< s
->commits
.next
; i
++) {
2446 commit_t
* commit
= array_get(&(s
->commits
), i
);
2447 switch(commit
->action
) {
2448 case ACTION_RENAME
: case ACTION_MKDIR
:
2452 case ACTION_WRITEOUT
: {
2453 direntry_t
* entry
= array_get(&(s
->directory
),
2454 commit
->param
.writeout
.dir_index
);
2455 uint32_t begin
= begin_of_direntry(entry
);
2456 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin
);
2459 assert(mapping
->begin
== begin
);
2460 assert(commit
->path
== NULL
);
2462 if (commit_one_file(s
, commit
->param
.writeout
.dir_index
,
2463 commit
->param
.writeout
.modified_offset
))
2468 case ACTION_NEW_FILE
: {
2469 int begin
= commit
->param
.new_file
.first_cluster
;
2470 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin
);
2475 for (i
= 0; i
< s
->directory
.next
; i
++) {
2476 entry
= array_get(&(s
->directory
), i
);
2477 if (is_file(entry
) && begin_of_direntry(entry
) == begin
)
2481 if (i
>= s
->directory
.next
) {
2486 /* make sure there exists an initial mapping */
2487 if (mapping
&& mapping
->begin
!= begin
) {
2488 mapping
->end
= begin
;
2491 if (mapping
== NULL
) {
2492 mapping
= insert_mapping(s
, begin
, begin
+1);
2494 /* most members will be fixed in commit_mappings() */
2495 assert(commit
->path
);
2496 mapping
->path
= commit
->path
;
2497 mapping
->read_only
= 0;
2498 mapping
->mode
= MODE_NORMAL
;
2499 mapping
->info
.file
.offset
= 0;
2501 if (commit_one_file(s
, i
, 0))
2510 if (i
> 0 && array_remove_slice(&(s
->commits
), 0, i
))
2515 static int handle_deletes(BDRVVVFATState
* s
)
2517 int i
, deferred
= 1, deleted
= 1;
2519 /* delete files corresponding to mappings marked as deleted */
2520 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2521 while (deferred
&& deleted
) {
2525 for (i
= 1; i
< s
->mapping
.next
; i
++) {
2526 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2527 if (mapping
->mode
& MODE_DELETED
) {
2528 direntry_t
* entry
= array_get(&(s
->directory
),
2529 mapping
->dir_index
);
2531 if (is_free(entry
)) {
2532 /* remove file/directory */
2533 if (mapping
->mode
& MODE_DIRECTORY
) {
2534 int j
, next_dir_index
= s
->directory
.next
,
2535 first_dir_index
= mapping
->info
.dir
.first_dir_index
;
2537 if (rmdir(mapping
->path
) < 0) {
2538 if (errno
== ENOTEMPTY
) {
2545 for (j
= 1; j
< s
->mapping
.next
; j
++) {
2546 mapping_t
* m
= array_get(&(s
->mapping
), j
);
2547 if (m
->mode
& MODE_DIRECTORY
&&
2548 m
->info
.dir
.first_dir_index
>
2550 m
->info
.dir
.first_dir_index
<
2553 m
->info
.dir
.first_dir_index
;
2555 remove_direntries(s
, first_dir_index
,
2556 next_dir_index
- first_dir_index
);
2561 if (unlink(mapping
->path
))
2565 DLOG(fprintf(stderr
, "DELETE (%d)\n", i
); print_mapping(mapping
); print_direntry(entry
));
2566 remove_mapping(s
, i
);
2575 * synchronize mapping with new state:
2577 * - copy FAT (with bdrv_read)
2578 * - mark all filenames corresponding to mappings as deleted
2579 * - recurse direntries from root (using bs->bdrv_read)
2580 * - delete files corresponding to mappings marked as deleted
2582 static int do_commit(BDRVVVFATState
* s
)
2586 /* the real meat are the commits. Nothing to do? Move along! */
2587 if (s
->commits
.next
== 0)
2590 vvfat_close_current_file(s
);
2592 ret
= handle_renames_and_mkdirs(s
);
2594 fprintf(stderr
, "Error handling renames (%d)\n", ret
);
2599 /* copy FAT (with bdrv_read) */
2600 memcpy(s
->fat
.pointer
, s
->fat2
, 0x200 * s
->sectors_per_fat
);
2602 /* recurse direntries from root (using bs->bdrv_read) */
2603 ret
= commit_direntries(s
, 0, -1);
2605 fprintf(stderr
, "Fatal: error while committing (%d)\n", ret
);
2610 ret
= handle_commits(s
);
2612 fprintf(stderr
, "Error handling commits (%d)\n", ret
);
2617 ret
= handle_deletes(s
);
2619 fprintf(stderr
, "Error deleting\n");
2624 s
->qcow
->drv
->bdrv_make_empty(s
->qcow
);
2626 memset(s
->used_clusters
, 0, sector2cluster(s
, s
->sector_count
));
2632 static int try_commit(BDRVVVFATState
* s
)
2634 vvfat_close_current_file(s
);
2636 if(!is_consistent(s
))
2638 return do_commit(s
);
2641 static int vvfat_write(BlockDriverState
*bs
, int64_t sector_num
,
2642 const uint8_t *buf
, int nb_sectors
)
2644 BDRVVVFATState
*s
= bs
->opaque
;
2649 vvfat_close_current_file(s
);
2652 * Some sanity checks:
2653 * - do not allow writing to the boot sector
2654 * - do not allow to write non-ASCII filenames
2657 if (sector_num
< s
->first_sectors_number
)
2660 for (i
= sector2cluster(s
, sector_num
);
2661 i
<= sector2cluster(s
, sector_num
+ nb_sectors
- 1);) {
2662 mapping_t
* mapping
= find_mapping_for_cluster(s
, i
);
2664 if (mapping
->read_only
) {
2665 fprintf(stderr
, "Tried to write to write-protected file %s\n",
2670 if (mapping
->mode
& MODE_DIRECTORY
) {
2671 int begin
= cluster2sector(s
, i
);
2672 int end
= begin
+ s
->sectors_per_cluster
, k
;
2674 const direntry_t
* direntries
;
2679 if (begin
< sector_num
)
2681 if (end
> sector_num
+ nb_sectors
)
2682 end
= sector_num
+ nb_sectors
;
2683 dir_index
= mapping
->dir_index
+
2684 0x10 * (begin
- mapping
->begin
* s
->sectors_per_cluster
);
2685 direntries
= (direntry_t
*)(buf
+ 0x200 * (begin
- sector_num
));
2687 for (k
= 0; k
< (end
- begin
) * 0x10; k
++) {
2688 /* do not allow non-ASCII filenames */
2689 if (parse_long_name(&lfn
, direntries
+ k
) < 0) {
2690 fprintf(stderr
, "Warning: non-ASCII filename\n");
2693 /* no access to the direntry of a read-only file */
2694 else if (is_short_name(direntries
+k
) &&
2695 (direntries
[k
].attributes
& 1)) {
2696 if (memcmp(direntries
+ k
,
2697 array_get(&(s
->directory
), dir_index
+ k
),
2698 sizeof(direntry_t
))) {
2699 fprintf(stderr
, "Warning: tried to write to write-protected file\n");
2711 * Use qcow backend. Commit later.
2713 DLOG(fprintf(stderr
, "Write to qcow backend: %d + %d\n", (int)sector_num
, nb_sectors
));
2714 ret
= s
->qcow
->drv
->bdrv_write(s
->qcow
, sector_num
, buf
, nb_sectors
);
2716 fprintf(stderr
, "Error writing to qcow backend\n");
2720 for (i
= sector2cluster(s
, sector_num
);
2721 i
<= sector2cluster(s
, sector_num
+ nb_sectors
- 1); i
++)
2723 s
->used_clusters
[i
] |= USED_ALLOCATED
;
2726 /* TODO: add timeout */
2733 static int vvfat_is_allocated(BlockDriverState
*bs
,
2734 int64_t sector_num
, int nb_sectors
, int* n
)
2736 BDRVVVFATState
* s
= bs
->opaque
;
2737 *n
= s
->sector_count
- sector_num
;
2738 if (*n
> nb_sectors
)
2745 static int write_target_commit(BlockDriverState
*bs
, int64_t sector_num
,
2746 const uint8_t* buffer
, int nb_sectors
) {
2747 BDRVVVFATState
* s
= bs
->opaque
;
2748 return try_commit(s
);
2751 static void write_target_close(BlockDriverState
*bs
) {
2752 BDRVVVFATState
* s
= bs
->opaque
;
2753 bdrv_delete(s
->qcow
);
2754 free(s
->qcow_filename
);
2757 static BlockDriver vvfat_write_target
= {
2758 "vvfat_write_target", 0, NULL
, NULL
, NULL
,
2759 write_target_commit
,
2764 static int enable_write_target(BDRVVVFATState
*s
)
2766 int size
= sector2cluster(s
, s
->sector_count
);
2767 s
->used_clusters
= calloc(size
, 1);
2769 array_init(&(s
->commits
), sizeof(commit_t
));
2771 s
->qcow_filename
= malloc(1024);
2772 get_tmp_filename(s
->qcow_filename
, 1024);
2773 if (bdrv_create(&bdrv_qcow
,
2774 s
->qcow_filename
, s
->sector_count
, "fat:", 0) < 0)
2776 s
->qcow
= bdrv_new("");
2777 if (s
->qcow
== NULL
|| bdrv_open(s
->qcow
, s
->qcow_filename
, 0) < 0)
2781 unlink(s
->qcow_filename
);
2784 s
->bs
->backing_hd
= calloc(sizeof(BlockDriverState
), 1);
2785 s
->bs
->backing_hd
->drv
= &vvfat_write_target
;
2786 s
->bs
->backing_hd
->opaque
= s
;
2791 static void vvfat_close(BlockDriverState
*bs
)
2793 BDRVVVFATState
*s
= bs
->opaque
;
2795 vvfat_close_current_file(s
);
2796 array_free(&(s
->fat
));
2797 array_free(&(s
->directory
));
2798 array_free(&(s
->mapping
));
2799 if(s
->cluster_buffer
)
2800 free(s
->cluster_buffer
);
2803 BlockDriver bdrv_vvfat
= {
2805 sizeof(BDRVVVFATState
),
2806 NULL
, /* no probe for protocols */
2811 NULL
, /* ??? Not sure if we can do any meaningful flushing. */
2814 .protocol_name
= "fat",
2818 static void checkpoint(void) {
2819 assert(((mapping_t
*)array_get(&(vvv
->mapping
), 0))->end
== 2);
2822 assert(!vvv
->current_mapping
|| vvv
->current_fd
|| (vvv
->current_mapping
->mode
& MODE_DIRECTORY
));
2824 if (((direntry_t
*)vvv
->directory
.pointer
)[1].attributes
!= 0xf)
2825 fprintf(stderr
, "Nonono!\n");
2827 direntry_t
* direntry
;
2828 assert(vvv
->mapping
.size
>= vvv
->mapping
.item_size
* vvv
->mapping
.next
);
2829 assert(vvv
->directory
.size
>= vvv
->directory
.item_size
* vvv
->directory
.next
);
2830 if (vvv
->mapping
.next
<47)
2832 assert((mapping
= array_get(&(vvv
->mapping
), 47)));
2833 assert(mapping
->dir_index
< vvv
->directory
.next
);
2834 direntry
= array_get(&(vvv
->directory
), mapping
->dir_index
);
2835 assert(!memcmp(direntry
->name
, "USB H ", 11) || direntry
->name
[0]==0);
2838 /* avoid compiler warnings: */
2840 remove_mapping(vvv
, NULL
);
2841 print_mapping(NULL
);
2842 print_direntry(NULL
);