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
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();
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) if (!(a)) nonono(__FILE__, __LINE__, #a)
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
) {
97 assert(index
< array
->next
);
98 return array
->pointer
+ index
* array
->item_size
;
101 static inline int array_ensure_allocated(array_t
* array
, int index
)
103 if((index
+ 1) * array
->item_size
> array
->size
) {
104 int new_size
= (index
+ 32) * array
->item_size
;
105 array
->pointer
= realloc(array
->pointer
, new_size
);
108 array
->size
= new_size
;
109 array
->next
= index
+ 1;
115 static inline void* array_get_next(array_t
* array
) {
116 unsigned int next
= array
->next
;
119 if (array_ensure_allocated(array
, next
) < 0)
122 array
->next
= next
+ 1;
123 result
= array_get(array
, next
);
128 static inline void* array_insert(array_t
* array
,unsigned int index
,unsigned int count
) {
129 if((array
->next
+count
)*array
->item_size
>array
->size
) {
130 int increment
=count
*array
->item_size
;
131 array
->pointer
=realloc(array
->pointer
,array
->size
+increment
);
134 array
->size
+=increment
;
136 memmove(array
->pointer
+(index
+count
)*array
->item_size
,
137 array
->pointer
+index
*array
->item_size
,
138 (array
->next
-index
)*array
->item_size
);
140 return array
->pointer
+index
*array
->item_size
;
143 /* this performs a "roll", so that the element which was at index_from becomes
144 * index_to, but the order of all other elements is preserved. */
145 static inline int array_roll(array_t
* array
,int index_to
,int index_from
,int count
)
153 index_to
<0 || index_to
>=array
->next
||
154 index_from
<0 || index_from
>=array
->next
)
157 if(index_to
==index_from
)
161 from
=array
->pointer
+index_from
*is
;
162 to
=array
->pointer
+index_to
*is
;
163 buf
=malloc(is
*count
);
164 memcpy(buf
,from
,is
*count
);
166 if(index_to
<index_from
)
167 memmove(to
+is
*count
,to
,from
-to
);
169 memmove(from
,from
+is
*count
,to
-from
);
171 memcpy(to
,buf
,is
*count
);
178 inline int array_remove_slice(array_t
* array
,int index
, int count
)
182 assert(index
+ count
<= array
->next
);
183 if(array_roll(array
,array
->next
-1,index
,count
))
185 array
->next
-= count
;
189 int array_remove(array_t
* array
,int index
)
191 return array_remove_slice(array
, index
, 1);
194 /* return the index for a given member */
195 int array_index(array_t
* array
, void* pointer
)
197 size_t offset
= (char*)pointer
- array
->pointer
;
199 assert((offset
% array
->item_size
) == 0);
200 assert(offset
/array
->item_size
< array
->next
);
201 return offset
/array
->item_size
;
204 /* These structures are used to fake a disk and the VFAT filesystem.
205 * For this reason we need to use __attribute__((packed)). */
207 typedef struct bootsector_t
{
210 uint16_t sector_size
;
211 uint8_t sectors_per_cluster
;
212 uint16_t reserved_sectors
;
213 uint8_t number_of_fats
;
214 uint16_t root_entries
;
215 uint16_t total_sectors16
;
217 uint16_t sectors_per_fat
;
218 uint16_t sectors_per_track
;
219 uint16_t number_of_heads
;
220 uint32_t hidden_sectors
;
221 uint32_t total_sectors
;
224 uint8_t drive_number
;
225 uint8_t current_head
;
228 uint8_t volume_label
[11];
229 } __attribute__((packed
)) fat16
;
231 uint32_t sectors_per_fat
;
234 uint32_t first_cluster_of_root_directory
;
235 uint16_t info_sector
;
236 uint16_t backup_boot_sector
;
238 } __attribute__((packed
)) fat32
;
241 uint8_t ignored
[0x1c0];
243 } __attribute__((packed
)) bootsector_t
;
245 typedef struct partition_t
{
246 uint8_t attributes
; /* 0x80 = bootable */
248 uint8_t start_sector
;
249 uint8_t start_cylinder
;
250 uint8_t fs_type
; /* 0x1 = FAT12, 0x6 = FAT16, 0xb = FAT32 */
253 uint8_t end_cylinder
;
254 uint32_t start_sector_long
;
255 uint32_t end_sector_long
;
256 } __attribute__((packed
)) partition_t
;
258 typedef struct mbr_t
{
259 uint8_t ignored
[0x1be];
260 partition_t partition
[4];
262 } __attribute__((packed
)) mbr_t
;
264 typedef struct direntry_t
{
266 uint8_t extension
[3];
277 } __attribute__((packed
)) direntry_t
;
279 /* this structure are used to transparently access the files */
281 typedef struct mapping_t
{
282 /* begin is the first cluster, end is the last+1 */
284 /* as s->directory is growable, no pointer may be used here */
285 unsigned int dir_index
;
286 /* the clusters of a file may be in any order; this points to the first */
287 int first_mapping_index
;
290 * - the offset in the file (in clusters) for a file, or
291 * - the next cluster of the directory for a directory, and
292 * - the address of the buffer for a faked entry
298 int parent_mapping_index
;
302 /* path contains the full path, i.e. it always starts with s->path */
305 enum { MODE_UNDEFINED
= 0, MODE_NORMAL
= 1, MODE_MODIFIED
= 2,
306 MODE_DIRECTORY
= 4, MODE_FAKED
= 8,
307 MODE_DELETED
= 16, MODE_RENAMED
= 32 } mode
;
312 static void print_direntry(const struct direntry_t
*);
313 static void print_mapping(const struct mapping_t
* mapping
);
316 /* here begins the real VVFAT driver */
318 typedef struct BDRVVVFATState
{
319 BlockDriverState
* bs
; /* pointer to parent */
320 unsigned int first_sectors_number
; /* 1 for a single partition, 0x40 for a disk with partition table */
321 unsigned char first_sectors
[0x40*0x200];
323 int fat_type
; /* 16 or 32 */
324 array_t fat
,directory
,mapping
;
326 unsigned int cluster_size
;
327 unsigned int sectors_per_cluster
;
328 unsigned int sectors_per_fat
;
329 unsigned int sectors_of_root_directory
;
330 uint32_t last_cluster_of_root_directory
;
331 unsigned int faked_sectors
; /* how many sectors are faked before file data */
332 uint32_t sector_count
; /* total number of sectors of the partition */
333 uint32_t cluster_count
; /* total number of clusters of this partition */
334 uint32_t max_fat_value
;
337 mapping_t
* current_mapping
;
338 unsigned char* cluster
; /* points to current cluster */
339 unsigned char* cluster_buffer
; /* points to a buffer to hold temp data */
340 unsigned int current_cluster
;
343 BlockDriverState
* write_target
;
345 BlockDriverState
* qcow
;
350 int downcase_short_names
;
354 static void init_mbr(BDRVVVFATState
* s
)
356 /* TODO: if the files mbr.img and bootsect.img exist, use them */
357 mbr_t
* real_mbr
=(mbr_t
*)s
->first_sectors
;
358 partition_t
* partition
=&(real_mbr
->partition
[0]);
360 memset(s
->first_sectors
,0,512);
362 partition
->attributes
=0x80; /* bootable */
363 partition
->start_head
=1;
364 partition
->start_sector
=1;
365 partition
->start_cylinder
=0;
366 /* FAT12/FAT16/FAT32 */
367 partition
->fs_type
=(s
->fat_type
==12?0x1:s
->fat_type
==16?0x6:0xb);
368 partition
->end_head
=s
->bs
->heads
-1;
369 partition
->end_sector
=0xff; /* end sector & upper 2 bits of cylinder */;
370 partition
->end_cylinder
=0xff; /* lower 8 bits of end cylinder */;
371 partition
->start_sector_long
=cpu_to_le32(s
->bs
->secs
);
372 partition
->end_sector_long
=cpu_to_le32(s
->sector_count
);
374 real_mbr
->magic
[0]=0x55; real_mbr
->magic
[1]=0xaa;
377 /* direntry functions */
379 /* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
380 static inline int short2long_name(unsigned char* dest
,const char* src
)
383 for(i
=0;i
<129 && src
[i
];i
++) {
387 dest
[2*i
]=dest
[2*i
+1]=0;
388 for(i
=2*i
+2;(i
%26);i
++)
393 static inline direntry_t
* create_long_filename(BDRVVVFATState
* s
,const char* filename
)
396 int length
=short2long_name(buffer
,filename
),
397 number_of_entries
=(length
+25)/26,i
;
400 for(i
=0;i
<number_of_entries
;i
++) {
401 entry
=array_get_next(&(s
->directory
));
402 entry
->attributes
=0xf;
403 entry
->reserved
[0]=0;
405 entry
->name
[0]=(number_of_entries
-i
)|(i
==0?0x40:0);
407 for(i
=0;i
<length
;i
++) {
409 if(offset
<10) offset
=1+offset
;
410 else if(offset
<22) offset
=14+offset
-10;
411 else offset
=28+offset
-22;
412 entry
=array_get(&(s
->directory
),s
->directory
.next
-1-(i
/26));
413 entry
->name
[offset
]=buffer
[i
];
415 return array_get(&(s
->directory
),s
->directory
.next
-number_of_entries
);
418 static char is_free(const direntry_t
* direntry
)
420 /* return direntry->name[0]==0 ; */
421 return direntry
->attributes
== 0 || direntry
->name
[0]==0xe5;
424 static char is_volume_label(const direntry_t
* direntry
)
426 return direntry
->attributes
== 0x28;
429 static char is_long_name(const direntry_t
* direntry
)
431 return direntry
->attributes
== 0xf;
434 static char is_short_name(const direntry_t
* direntry
)
436 return !is_volume_label(direntry
) && !is_long_name(direntry
)
437 && !is_free(direntry
);
440 static char is_directory(const direntry_t
* direntry
)
442 return direntry
->attributes
& 0x10 && direntry
->name
[0] != 0xe5;
445 static inline char is_dot(const direntry_t
* direntry
)
447 return is_short_name(direntry
) && direntry
->name
[0] == '.';
450 static char is_file(const direntry_t
* direntry
)
452 return is_short_name(direntry
) && !is_directory(direntry
);
455 static inline uint32_t begin_of_direntry(const direntry_t
* direntry
)
457 return le16_to_cpu(direntry
->begin
)|(le16_to_cpu(direntry
->begin_hi
)<<16);
460 static inline uint32_t filesize_of_direntry(const direntry_t
* direntry
)
462 return le32_to_cpu(direntry
->size
);
465 static void set_begin_of_direntry(direntry_t
* direntry
, uint32_t begin
)
467 direntry
->begin
= cpu_to_le16(begin
& 0xffff);
468 direntry
->begin_hi
= cpu_to_le16((begin
>> 16) & 0xffff);
473 static inline uint8_t fat_chksum(const direntry_t
* entry
)
479 chksum
=(((chksum
&0xfe)>>1)|((chksum
&0x01)?0x80:0))
480 +(unsigned char)entry
->name
[i
];
485 /* if return_time==0, this returns the fat_date, else the fat_time */
486 static uint16_t fat_datetime(time_t time
,int return_time
) {
489 t
=localtime(&time
); /* this is not thread safe */
493 localtime_r(&time
,t
);
496 return cpu_to_le16((t
->tm_sec
/2)|(t
->tm_min
<<5)|(t
->tm_hour
<<11));
497 return cpu_to_le16((t
->tm_mday
)|((t
->tm_mon
+1)<<5)|((t
->tm_year
-80)<<9));
500 static inline void fat_set(BDRVVVFATState
* s
,unsigned int cluster
,uint32_t value
)
502 if(s
->fat_type
==32) {
503 uint32_t* entry
=array_get(&(s
->fat
),cluster
);
504 *entry
=cpu_to_le32(value
);
505 } else if(s
->fat_type
==16) {
506 uint16_t* entry
=array_get(&(s
->fat
),cluster
);
507 *entry
=cpu_to_le16(value
&0xffff);
509 int offset
= (cluster
*3/2);
510 unsigned char* p
= array_get(&(s
->fat
), offset
);
514 p
[1] = (p
[1]&0xf0) | ((value
>>8)&0xf);
517 p
[0] = (p
[0]&0xf) | ((value
&0xf)<<4);
524 static inline uint32_t fat_get(BDRVVVFATState
* s
,unsigned int cluster
)
526 if(s
->fat_type
==32) {
527 uint32_t* entry
=array_get(&(s
->fat
),cluster
);
528 return le32_to_cpu(*entry
);
529 } else if(s
->fat_type
==16) {
530 uint16_t* entry
=array_get(&(s
->fat
),cluster
);
531 return le16_to_cpu(*entry
);
533 const uint8_t* x
=s
->fat
.pointer
+cluster
*3/2;
534 return ((x
[0]|(x
[1]<<8))>>(cluster
&1?4:0))&0x0fff;
538 static inline int fat_eof(BDRVVVFATState
* s
,uint32_t fat_entry
)
540 if(fat_entry
>s
->max_fat_value
-8)
545 static inline void init_fat(BDRVVVFATState
* s
)
547 if (s
->fat_type
== 12) {
548 array_init(&(s
->fat
),1);
549 array_ensure_allocated(&(s
->fat
),
550 s
->sectors_per_fat
* 0x200 * 3 / 2 - 1);
552 array_init(&(s
->fat
),(s
->fat_type
==32?4:2));
553 array_ensure_allocated(&(s
->fat
),
554 s
->sectors_per_fat
* 0x200 / s
->fat
.item_size
- 1);
556 memset(s
->fat
.pointer
,0,s
->fat
.size
);
558 switch(s
->fat_type
) {
559 case 12: s
->max_fat_value
=0xfff; break;
560 case 16: s
->max_fat_value
=0xffff; break;
561 case 32: s
->max_fat_value
=0x0fffffff; break;
562 default: s
->max_fat_value
=0; /* error... */
567 /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
568 /* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
569 static inline direntry_t
* create_short_and_long_name(BDRVVVFATState
* s
,
570 unsigned int directory_start
, const char* filename
, int is_dot
)
572 int i
,j
,long_index
=s
->directory
.next
;
574 direntry_t
* entry_long
=0;
577 entry
=array_get_next(&(s
->directory
));
578 memset(entry
->name
,0x20,11);
579 memcpy(entry
->name
,filename
,strlen(filename
));
583 entry_long
=create_long_filename(s
,filename
);
585 i
= strlen(filename
);
586 for(j
= i
- 1; j
>0 && filename
[j
]!='.';j
--);
592 entry
=array_get_next(&(s
->directory
));
593 memset(entry
->name
,0x20,11);
594 strncpy(entry
->name
,filename
,i
);
597 for (i
= 0; i
< 3 && filename
[j
+1+i
]; i
++)
598 entry
->extension
[i
] = filename
[j
+1+i
];
600 /* upcase & remove unwanted characters */
602 if(i
==10 || i
==7) for(;i
>0 && entry
->name
[i
]==' ';i
--);
603 if(entry
->name
[i
]<=' ' || entry
->name
[i
]>0x7f
604 || strchr(".*?<>|\":/\\[];,+='",entry
->name
[i
]))
606 else if(entry
->name
[i
]>='a' && entry
->name
[i
]<='z')
607 entry
->name
[i
]+='A'-'a';
610 /* mangle duplicates */
612 direntry_t
* entry1
=array_get(&(s
->directory
),directory_start
);
615 for(;entry1
<entry
;entry1
++)
616 if(!is_long_name(entry1
) && !memcmp(entry1
->name
,entry
->name
,11))
617 break; /* found dupe */
618 if(entry1
==entry
) /* no dupe found */
621 /* use all 8 characters of name */
622 if(entry
->name
[7]==' ') {
624 for(j
=6;j
>0 && entry
->name
[j
]==' ';j
--)
628 /* increment number */
629 for(j
=7;j
>0 && entry
->name
[j
]=='9';j
--)
632 if(entry
->name
[j
]<'0' || entry
->name
[j
]>'9')
639 /* calculate checksum; propagate to long name */
641 uint8_t chksum
=fat_chksum(entry
);
643 /* calculate anew, because realloc could have taken place */
644 entry_long
=array_get(&(s
->directory
),long_index
);
645 while(entry_long
<entry
&& is_long_name(entry_long
)) {
646 entry_long
->reserved
[1]=chksum
;
655 * Read a directory. (the index of the corresponding mapping must be passed).
657 static int read_directory(BDRVVVFATState
* s
, int mapping_index
)
659 mapping_t
* mapping
= array_get(&(s
->mapping
), mapping_index
);
660 direntry_t
* direntry
;
661 const char* dirname
= mapping
->path
;
662 int first_cluster
= mapping
->begin
;
663 int parent_index
= mapping
->info
.dir
.parent_mapping_index
;
664 mapping_t
* parent_mapping
= (mapping_t
*)
665 (parent_index
>= 0 ? array_get(&(s
->mapping
), parent_index
) : 0);
666 int first_cluster_of_parent
= parent_mapping
? parent_mapping
->begin
: -1;
668 DIR* dir
=opendir(dirname
);
669 struct dirent
* entry
;
672 assert(mapping
->mode
& MODE_DIRECTORY
);
675 mapping
->end
= mapping
->begin
;
679 i
= mapping
->info
.dir
.first_dir_index
=
680 first_cluster
== 0 ? 0 : s
->directory
.next
;
682 /* actually read the directory, and allocate the mappings */
683 while((entry
=readdir(dir
))) {
684 unsigned int length
=strlen(dirname
)+2+strlen(entry
->d_name
);
686 direntry_t
* direntry
;
688 int is_dot
=!strcmp(entry
->d_name
,".");
689 int is_dotdot
=!strcmp(entry
->d_name
,"..");
691 if(first_cluster
== 0 && (is_dotdot
|| is_dot
))
694 buffer
=(char*)malloc(length
);
696 snprintf(buffer
,length
,"%s/%s",dirname
,entry
->d_name
);
698 if(stat(buffer
,&st
)<0) {
703 /* create directory entry for this file */
704 direntry
=create_short_and_long_name(s
, i
, entry
->d_name
,
705 is_dot
|| is_dotdot
);
706 direntry
->attributes
=(S_ISDIR(st
.st_mode
)?0x10:0x20);
707 direntry
->reserved
[0]=direntry
->reserved
[1]=0;
708 direntry
->ctime
=fat_datetime(st
.st_ctime
,1);
709 direntry
->cdate
=fat_datetime(st
.st_ctime
,0);
710 direntry
->adate
=fat_datetime(st
.st_atime
,0);
711 direntry
->begin_hi
=0;
712 direntry
->mtime
=fat_datetime(st
.st_mtime
,1);
713 direntry
->mdate
=fat_datetime(st
.st_mtime
,0);
715 set_begin_of_direntry(direntry
, first_cluster_of_parent
);
717 set_begin_of_direntry(direntry
, first_cluster
);
719 direntry
->begin
=0; /* do that later */
720 if (st
.st_size
> 0x7fffffff) {
721 fprintf(stderr
, "File %s is larger than 2GB\n", buffer
);
725 direntry
->size
=cpu_to_le32(S_ISDIR(st
.st_mode
)?0:st
.st_size
);
727 /* create mapping for this file */
728 if(!is_dot
&& !is_dotdot
&& (S_ISDIR(st
.st_mode
) || st
.st_size
)) {
729 s
->current_mapping
=(mapping_t
*)array_get_next(&(s
->mapping
));
730 s
->current_mapping
->begin
=0;
731 s
->current_mapping
->end
=st
.st_size
;
733 * we get the direntry of the most recent direntry, which
734 * contains the short name and all the relevant information.
736 s
->current_mapping
->dir_index
=s
->directory
.next
-1;
737 s
->current_mapping
->first_mapping_index
= -1;
738 if (S_ISDIR(st
.st_mode
)) {
739 s
->current_mapping
->mode
= MODE_DIRECTORY
;
740 s
->current_mapping
->info
.dir
.parent_mapping_index
=
743 s
->current_mapping
->mode
= MODE_UNDEFINED
;
744 s
->current_mapping
->info
.file
.offset
= 0;
746 s
->current_mapping
->path
=buffer
;
747 s
->current_mapping
->read_only
=
748 (st
.st_mode
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) == 0;
753 /* fill with zeroes up to the end of the cluster */
754 while(s
->directory
.next
%(0x10*s
->sectors_per_cluster
)) {
755 direntry_t
* direntry
=array_get_next(&(s
->directory
));
756 memset(direntry
,0,sizeof(direntry_t
));
759 /* TODO: if there are more entries, bootsector has to be adjusted! */
760 #define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
761 if (mapping_index
== 0 && s
->directory
.next
< ROOT_ENTRIES
) {
763 int cur
= s
->directory
.next
;
764 array_ensure_allocated(&(s
->directory
), ROOT_ENTRIES
- 1);
765 memset(array_get(&(s
->directory
), cur
), 0,
766 (ROOT_ENTRIES
- cur
) * sizeof(direntry_t
));
769 /* reget the mapping, since s->mapping was possibly realloc()ed */
770 mapping
= (mapping_t
*)array_get(&(s
->mapping
), mapping_index
);
771 first_cluster
+= (s
->directory
.next
- mapping
->info
.dir
.first_dir_index
)
772 * 0x20 / s
->cluster_size
;
773 mapping
->end
= first_cluster
;
775 direntry
= (direntry_t
*)array_get(&(s
->directory
), mapping
->dir_index
);
776 set_begin_of_direntry(direntry
, mapping
->begin
);
781 static inline uint32_t sector2cluster(BDRVVVFATState
* s
,off_t sector_num
)
783 return (sector_num
-s
->faked_sectors
)/s
->sectors_per_cluster
;
786 static inline off_t
cluster2sector(BDRVVVFATState
* s
, uint32_t cluster_num
)
788 return s
->faked_sectors
+ s
->sectors_per_cluster
* cluster_num
;
791 static inline uint32_t sector_offset_in_cluster(BDRVVVFATState
* s
,off_t sector_num
)
793 return (sector_num
-s
->first_sectors_number
-2*s
->sectors_per_fat
)%s
->sectors_per_cluster
;
797 static direntry_t
* get_direntry_for_mapping(BDRVVVFATState
* s
,mapping_t
* mapping
)
799 if(mapping
->mode
==MODE_UNDEFINED
)
801 return (direntry_t
*)(s
->directory
.pointer
+sizeof(direntry_t
)*mapping
->dir_index
);
805 static int init_directories(BDRVVVFATState
* s
,
808 bootsector_t
* bootsector
;
811 unsigned int cluster
;
813 memset(&(s
->first_sectors
[0]),0,0x40*0x200);
815 s
->cluster_size
=s
->sectors_per_cluster
*0x200;
816 s
->cluster_buffer
=malloc(s
->cluster_size
);
817 assert(s
->cluster_buffer
);
820 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
821 * where sc is sector_count,
822 * spf is sectors_per_fat,
823 * spc is sectors_per_clusters, and
824 * fat_type = 12, 16 or 32.
826 i
= 1+s
->sectors_per_cluster
*0x200*8/s
->fat_type
;
827 s
->sectors_per_fat
=(s
->sector_count
+i
)/i
; /* round up */
829 array_init(&(s
->mapping
),sizeof(mapping_t
));
830 array_init(&(s
->directory
),sizeof(direntry_t
));
832 /* add volume label */
834 direntry_t
* entry
=array_get_next(&(s
->directory
));
835 entry
->attributes
=0x28; /* archive | volume label */
836 snprintf(entry
->name
,11,"QEMU VVFAT");
839 /* Now build FAT, and write back information into directory */
842 s
->faked_sectors
=s
->first_sectors_number
+s
->sectors_per_fat
*2;
843 s
->cluster_count
=sector2cluster(s
, s
->sector_count
);
845 mapping
= array_get_next(&(s
->mapping
));
847 mapping
->dir_index
= 0;
848 mapping
->info
.dir
.parent_mapping_index
= -1;
849 mapping
->first_mapping_index
= -1;
850 mapping
->path
= strdup(dirname
);
851 i
= strlen(mapping
->path
);
852 if (i
> 0 && mapping
->path
[i
- 1] == '/')
853 mapping
->path
[i
- 1] = '\0';
854 mapping
->mode
= MODE_DIRECTORY
;
855 mapping
->read_only
= 0;
856 s
->path
= mapping
->path
;
858 for (i
= 0, cluster
= 0; i
< s
->mapping
.next
; i
++) {
860 /* MS-DOS expects the FAT to be 0 for the root directory
861 * (except for the media byte). */
862 /* LATER TODO: still true for FAT32? */
863 int fix_fat
= (i
!= 0);
864 mapping
= array_get(&(s
->mapping
), i
);
866 if (mapping
->mode
& MODE_DIRECTORY
) {
867 mapping
->begin
= cluster
;
868 if(read_directory(s
, i
)) {
869 fprintf(stderr
, "Could not read directory %s\n",
873 mapping
= array_get(&(s
->mapping
), i
);
875 assert(mapping
->mode
== MODE_UNDEFINED
);
876 mapping
->mode
=MODE_NORMAL
;
877 mapping
->begin
= cluster
;
878 if (mapping
->end
> 0) {
879 direntry_t
* direntry
= array_get(&(s
->directory
),
882 mapping
->end
= cluster
+ 1 + (mapping
->end
-1)/s
->cluster_size
;
883 set_begin_of_direntry(direntry
, mapping
->begin
);
885 mapping
->end
= cluster
+ 1;
890 assert(mapping
->begin
< mapping
->end
);
892 /* fix fat for entry */
894 for(j
= mapping
->begin
; j
< mapping
->end
- 1; j
++)
896 fat_set(s
, mapping
->end
- 1, s
->max_fat_value
);
899 /* next free cluster */
900 cluster
= mapping
->end
;
902 if(cluster
> s
->cluster_count
) {
903 fprintf(stderr
,"Directory does not fit in FAT%d\n",s
->fat_type
);
908 mapping
= array_get(&(s
->mapping
), 0);
909 s
->sectors_of_root_directory
= mapping
->end
* s
->sectors_per_cluster
;
910 s
->last_cluster_of_root_directory
= mapping
->end
;
912 /* the FAT signature */
913 fat_set(s
,0,s
->max_fat_value
);
914 fat_set(s
,1,s
->max_fat_value
);
916 s
->current_mapping
= NULL
;
918 bootsector
=(bootsector_t
*)(s
->first_sectors
+(s
->first_sectors_number
-1)*0x200);
919 bootsector
->jump
[0]=0xeb;
920 bootsector
->jump
[1]=0x3e;
921 bootsector
->jump
[2]=0x90;
922 memcpy(bootsector
->name
,"QEMU ",8);
923 bootsector
->sector_size
=cpu_to_le16(0x200);
924 bootsector
->sectors_per_cluster
=s
->sectors_per_cluster
;
925 bootsector
->reserved_sectors
=cpu_to_le16(1);
926 bootsector
->number_of_fats
=0x2; /* number of FATs */
927 bootsector
->root_entries
=cpu_to_le16(s
->sectors_of_root_directory
*0x10);
928 bootsector
->total_sectors16
=s
->sector_count
>0xffff?0:cpu_to_le16(s
->sector_count
);
929 bootsector
->media_type
=(s
->fat_type
!=12?0xf8:s
->sector_count
==5760?0xf9:0xf8); /* media descriptor */
930 s
->fat
.pointer
[0] = bootsector
->media_type
;
931 bootsector
->sectors_per_fat
=cpu_to_le16(s
->sectors_per_fat
);
932 bootsector
->sectors_per_track
=cpu_to_le16(s
->bs
->secs
);
933 bootsector
->number_of_heads
=cpu_to_le16(s
->bs
->heads
);
934 bootsector
->hidden_sectors
=cpu_to_le32(s
->first_sectors_number
==1?0:0x3f);
935 bootsector
->total_sectors
=cpu_to_le32(s
->sector_count
>0xffff?s
->sector_count
:0);
937 /* LATER TODO: if FAT32, this is wrong */
938 bootsector
->u
.fat16
.drive_number
=s
->fat_type
==12?0:0x80; /* assume this is hda (TODO) */
939 bootsector
->u
.fat16
.current_head
=0;
940 bootsector
->u
.fat16
.signature
=0x29;
941 bootsector
->u
.fat16
.id
=cpu_to_le32(0xfabe1afd);
943 memcpy(bootsector
->u
.fat16
.volume_label
,"QEMU VVFAT ",11);
944 memcpy(bootsector
->fat_type
,(s
->fat_type
==12?"FAT12 ":s
->fat_type
==16?"FAT16 ":"FAT32 "),8);
945 bootsector
->magic
[0]=0x55; bootsector
->magic
[1]=0xaa;
951 static BDRVVVFATState
*vvv
= NULL
;
954 static int enable_write_target(BDRVVVFATState
*s
);
955 static int is_consistent(BDRVVVFATState
*s
);
957 static int vvfat_open(BlockDriverState
*bs
, const char* dirname
, int flags
)
959 BDRVVVFATState
*s
= bs
->opaque
;
967 DLOG(if (stderr
== NULL
) {
968 stderr
= fopen("vvfat.log", "a");
969 setbuf(stderr
, NULL
);
975 /* LATER TODO: if FAT32, adjust */
976 s
->sector_count
=0xec04f;
977 s
->sectors_per_cluster
=0x10;
978 /* LATER TODO: this could be wrong for FAT32 */
979 bs
->cyls
=1023; bs
->heads
=15; bs
->secs
=63;
981 s
->current_cluster
=0xffffffff;
983 s
->first_sectors_number
=0x40;
984 /* read only is the default for safety */
986 s
->qcow
= s
->write_target
= NULL
;
987 s
->qcow_filename
= NULL
;
989 s
->downcase_short_names
= 1;
991 if (!strstart(dirname
, "fat:", NULL
))
994 if (strstr(dirname
, ":rw:")) {
995 if (enable_write_target(s
))
1000 if (strstr(dirname
, ":floppy:")) {
1003 s
->first_sectors_number
= 1;
1004 s
->sectors_per_cluster
=2;
1005 bs
->cyls
= 80; bs
->heads
= 2; bs
->secs
= 36;
1008 if (strstr(dirname
, ":32:")) {
1009 fprintf(stderr
, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1011 } else if (strstr(dirname
, ":16:")) {
1013 } else if (strstr(dirname
, ":12:")) {
1015 s
->sector_count
=2880;
1018 i
= strrchr(dirname
, ':') - dirname
;
1020 if (dirname
[i
-2] == ':' && isalpha(dirname
[i
-1]))
1021 /* workaround for DOS drive names */
1026 bs
->total_sectors
=bs
->cyls
*bs
->heads
*bs
->secs
;
1027 if (s
->sector_count
> bs
->total_sectors
)
1028 s
->sector_count
= bs
->total_sectors
;
1029 if(init_directories(s
, dirname
))
1032 if(s
->first_sectors_number
==0x40)
1035 /* for some reason or other, MS-DOS does not like to know about CHS... */
1037 bs
->heads
= bs
->cyls
= bs
->secs
= 0;
1039 // assert(is_consistent(s));
1043 static inline void vvfat_close_current_file(BDRVVVFATState
*s
)
1045 if(s
->current_mapping
) {
1046 s
->current_mapping
= NULL
;
1047 if (s
->current_fd
) {
1048 close(s
->current_fd
);
1052 s
->current_cluster
= -1;
1055 /* mappings between index1 and index2-1 are supposed to be ordered
1056 * return value is the index of the last mapping for which end>cluster_num
1058 static inline int find_mapping_for_cluster_aux(BDRVVVFATState
* s
,int cluster_num
,int index1
,int index2
)
1060 int index3
=index1
+1;
1063 index3
=(index1
+index2
)/2;
1064 mapping
=array_get(&(s
->mapping
),index3
);
1065 assert(mapping
->begin
< mapping
->end
);
1066 if(mapping
->begin
>=cluster_num
) {
1067 assert(index2
!=index3
|| index2
==0);
1073 return mapping
->end
<=cluster_num
? index2
: index1
;
1076 assert(index1
<=index2
);
1077 DLOG(mapping
=array_get(&(s
->mapping
),index1
);
1078 assert(mapping
->begin
<=cluster_num
);
1079 assert(index2
>= s
->mapping
.next
||
1080 ((mapping
= array_get(&(s
->mapping
),index2
)) &&
1081 mapping
->end
>cluster_num
)));
1085 static inline mapping_t
* find_mapping_for_cluster(BDRVVVFATState
* s
,int cluster_num
)
1087 int index
=find_mapping_for_cluster_aux(s
,cluster_num
,0,s
->mapping
.next
);
1089 if(index
>=s
->mapping
.next
)
1091 mapping
=array_get(&(s
->mapping
),index
);
1092 if(mapping
->begin
>cluster_num
)
1094 assert(mapping
->begin
<=cluster_num
&& mapping
->end
>cluster_num
);
1099 * This function simply compares path == mapping->path. Since the mappings
1100 * are sorted by cluster, this is expensive: O(n).
1102 static inline mapping_t
* find_mapping_for_path(BDRVVVFATState
* s
,
1107 for (i
= 0; i
< s
->mapping
.next
; i
++) {
1108 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
1109 if (mapping
->first_mapping_index
< 0 &&
1110 !strcmp(path
, mapping
->path
))
1117 static int open_file(BDRVVVFATState
* s
,mapping_t
* mapping
)
1121 if(!s
->current_mapping
||
1122 strcmp(s
->current_mapping
->path
,mapping
->path
)) {
1124 int fd
= open(mapping
->path
, O_RDONLY
| O_BINARY
| O_LARGEFILE
);
1127 vvfat_close_current_file(s
);
1129 s
->current_mapping
= mapping
;
1134 static inline int read_cluster(BDRVVVFATState
*s
,int cluster_num
)
1136 if(s
->current_cluster
!= cluster_num
) {
1139 assert(!s
->current_mapping
|| s
->current_fd
|| (s
->current_mapping
->mode
& MODE_DIRECTORY
));
1140 if(!s
->current_mapping
1141 || s
->current_mapping
->begin
>cluster_num
1142 || s
->current_mapping
->end
<=cluster_num
) {
1143 /* binary search of mappings for file */
1144 mapping_t
* mapping
=find_mapping_for_cluster(s
,cluster_num
);
1146 assert(!mapping
|| (cluster_num
>=mapping
->begin
&& cluster_num
<mapping
->end
));
1148 if (mapping
&& mapping
->mode
& MODE_DIRECTORY
) {
1149 vvfat_close_current_file(s
);
1150 s
->current_mapping
= mapping
;
1151 read_cluster_directory
:
1152 offset
= s
->cluster_size
*(cluster_num
-s
->current_mapping
->begin
);
1153 s
->cluster
= s
->directory
.pointer
+offset
1154 + 0x20*s
->current_mapping
->info
.dir
.first_dir_index
;
1155 assert(((s
->cluster
-(unsigned char*)s
->directory
.pointer
)%s
->cluster_size
)==0);
1156 assert((char*)s
->cluster
+s
->cluster_size
<= s
->directory
.pointer
+s
->directory
.next
*s
->directory
.item_size
);
1157 s
->current_cluster
= cluster_num
;
1161 if(open_file(s
,mapping
))
1163 } else if (s
->current_mapping
->mode
& MODE_DIRECTORY
)
1164 goto read_cluster_directory
;
1166 assert(s
->current_fd
);
1168 offset
=s
->cluster_size
*(cluster_num
-s
->current_mapping
->begin
)+s
->current_mapping
->info
.file
.offset
;
1169 if(lseek(s
->current_fd
, offset
, SEEK_SET
)!=offset
)
1171 s
->cluster
=s
->cluster_buffer
;
1172 result
=read(s
->current_fd
,s
->cluster
,s
->cluster_size
);
1174 s
->current_cluster
= -1;
1177 s
->current_cluster
= cluster_num
;
1183 static void hexdump(const void* address
, uint32_t len
)
1185 const unsigned char* p
= address
;
1188 for (i
= 0; i
< len
; i
+= 16) {
1189 for (j
= 0; j
< 16 && i
+ j
< len
; j
++)
1190 fprintf(stderr
, "%02x ", p
[i
+ j
]);
1192 fprintf(stderr
, " ");
1193 fprintf(stderr
, " ");
1194 for (j
= 0; j
< 16 && i
+ j
< len
; j
++)
1195 fprintf(stderr
, "%c", (p
[i
+ j
] < ' ' || p
[i
+ j
] > 0x7f) ? '.' : p
[i
+ j
]);
1196 fprintf(stderr
, "\n");
1200 static void print_direntry(const direntry_t
* direntry
)
1205 fprintf(stderr
, "direntry 0x%x: ", (int)direntry
);
1208 if(is_long_name(direntry
)) {
1209 unsigned char* c
=(unsigned char*)direntry
;
1211 for(i
=1;i
<11 && c
[i
] && c
[i
]!=0xff;i
+=2)
1212 #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = '°'; j++;}
1214 for(i
=14;i
<26 && c
[i
] && c
[i
]!=0xff;i
+=2)
1216 for(i
=28;i
<32 && c
[i
] && c
[i
]!=0xff;i
+=2)
1219 fprintf(stderr
, "%s\n", buffer
);
1223 ADD_CHAR(direntry
->name
[i
]);
1225 fprintf(stderr
,"%s attributes=0x%02x begin=%d size=%d\n",
1227 direntry
->attributes
,
1228 begin_of_direntry(direntry
),le32_to_cpu(direntry
->size
));
1232 static void print_mapping(const mapping_t
* mapping
)
1234 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
);
1235 if (mapping
->mode
& MODE_DIRECTORY
)
1236 fprintf(stderr
, "parent_mapping_index = %d, first_dir_index = %d\n", mapping
->info
.dir
.parent_mapping_index
, mapping
->info
.dir
.first_dir_index
);
1238 fprintf(stderr
, "offset = %d\n", mapping
->info
.file
.offset
);
1242 static int vvfat_read(BlockDriverState
*bs
, int64_t sector_num
,
1243 uint8_t *buf
, int nb_sectors
)
1245 BDRVVVFATState
*s
= bs
->opaque
;
1248 for(i
=0;i
<nb_sectors
;i
++,sector_num
++) {
1249 if (sector_num
>= s
->sector_count
)
1253 if (s
->qcow
->drv
->bdrv_is_allocated(s
->qcow
,
1254 sector_num
, nb_sectors
-i
, &n
)) {
1255 DLOG(fprintf(stderr
, "sectors %d+%d allocated\n", (int)sector_num
, n
));
1256 if (s
->qcow
->drv
->bdrv_read(s
->qcow
, sector_num
, buf
+i
*0x200, n
))
1259 sector_num
+= n
- 1;
1262 DLOG(fprintf(stderr
, "sector %d not allocated\n", (int)sector_num
));
1264 if(sector_num
<s
->faked_sectors
) {
1265 if(sector_num
<s
->first_sectors_number
)
1266 memcpy(buf
+i
*0x200,&(s
->first_sectors
[sector_num
*0x200]),0x200);
1267 else if(sector_num
-s
->first_sectors_number
<s
->sectors_per_fat
)
1268 memcpy(buf
+i
*0x200,&(s
->fat
.pointer
[(sector_num
-s
->first_sectors_number
)*0x200]),0x200);
1269 else if(sector_num
-s
->first_sectors_number
-s
->sectors_per_fat
<s
->sectors_per_fat
)
1270 memcpy(buf
+i
*0x200,&(s
->fat
.pointer
[(sector_num
-s
->first_sectors_number
-s
->sectors_per_fat
)*0x200]),0x200);
1272 uint32_t sector
=sector_num
-s
->faked_sectors
,
1273 sector_offset_in_cluster
=(sector
%s
->sectors_per_cluster
),
1274 cluster_num
=sector
/s
->sectors_per_cluster
;
1275 if(read_cluster(s
, cluster_num
) != 0) {
1276 /* LATER TODO: strict: return -1; */
1277 memset(buf
+i
*0x200,0,0x200);
1280 memcpy(buf
+i
*0x200,s
->cluster
+sector_offset_in_cluster
*0x200,0x200);
1286 /* LATER TODO: statify all functions */
1289 * Idea of the write support (use snapshot):
1291 * 1. check if all data is consistent, recording renames, modifications,
1292 * new files and directories (in s->commits).
1294 * 2. if the data is not consistent, stop committing
1296 * 3. handle renames, and create new files and directories (do not yet
1297 * write their contents)
1299 * 4. walk the directories, fixing the mapping and direntries, and marking
1300 * the handled mappings as not deleted
1302 * 5. commit the contents of the files
1304 * 6. handle deleted files and directories
1308 typedef struct commit_t
{
1311 struct { uint32_t cluster
; } rename
;
1312 struct { int dir_index
; uint32_t modified_offset
; } writeout
;
1313 struct { uint32_t first_cluster
; } new_file
;
1314 struct { uint32_t cluster
; } mkdir
;
1316 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1318 ACTION_RENAME
, ACTION_WRITEOUT
, ACTION_NEW_FILE
, ACTION_MKDIR
1322 static void clear_commits(BDRVVVFATState
* s
)
1325 DLOG(fprintf(stderr
, "clear_commits (%d commits)\n", s
->commits
.next
));
1326 for (i
= 0; i
< s
->commits
.next
; i
++) {
1327 commit_t
* commit
= array_get(&(s
->commits
), i
);
1328 assert(commit
->path
|| commit
->action
== ACTION_WRITEOUT
);
1329 if (commit
->action
!= ACTION_WRITEOUT
) {
1330 assert(commit
->path
);
1333 assert(commit
->path
== NULL
);
1335 s
->commits
.next
= 0;
1338 static void schedule_rename(BDRVVVFATState
* s
,
1339 uint32_t cluster
, char* new_path
)
1341 commit_t
* commit
= array_get_next(&(s
->commits
));
1342 commit
->path
= new_path
;
1343 commit
->param
.rename
.cluster
= cluster
;
1344 commit
->action
= ACTION_RENAME
;
1347 static void schedule_writeout(BDRVVVFATState
* s
,
1348 int dir_index
, uint32_t modified_offset
)
1350 commit_t
* commit
= array_get_next(&(s
->commits
));
1351 commit
->path
= NULL
;
1352 commit
->param
.writeout
.dir_index
= dir_index
;
1353 commit
->param
.writeout
.modified_offset
= modified_offset
;
1354 commit
->action
= ACTION_WRITEOUT
;
1357 static void schedule_new_file(BDRVVVFATState
* s
,
1358 char* path
, uint32_t first_cluster
)
1360 commit_t
* commit
= array_get_next(&(s
->commits
));
1361 commit
->path
= path
;
1362 commit
->param
.new_file
.first_cluster
= first_cluster
;
1363 commit
->action
= ACTION_NEW_FILE
;
1366 static void schedule_mkdir(BDRVVVFATState
* s
, uint32_t cluster
, char* path
)
1368 commit_t
* commit
= array_get_next(&(s
->commits
));
1369 commit
->path
= path
;
1370 commit
->param
.mkdir
.cluster
= cluster
;
1371 commit
->action
= ACTION_MKDIR
;
1375 unsigned char name
[1024];
1377 int sequence_number
;
1380 static void lfn_init(long_file_name
* lfn
)
1382 lfn
->sequence_number
= lfn
->len
= 0;
1383 lfn
->checksum
= 0x100;
1386 /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1387 static int parse_long_name(long_file_name
* lfn
,
1388 const direntry_t
* direntry
)
1391 const unsigned char* pointer
= (const unsigned char*)direntry
;
1393 if (!is_long_name(direntry
))
1396 if (pointer
[0] & 0x40) {
1397 lfn
->sequence_number
= pointer
[0] & 0x3f;
1398 lfn
->checksum
= pointer
[13];
1400 } else if ((pointer
[0] & 0x3f) != --lfn
->sequence_number
)
1402 else if (pointer
[13] != lfn
->checksum
)
1404 else if (pointer
[12] || pointer
[26] || pointer
[27])
1407 offset
= 13 * (lfn
->sequence_number
- 1);
1408 for (i
= 0, j
= 1; i
< 13; i
++, j
+=2) {
1414 if (pointer
[j
+1] == 0)
1415 lfn
->name
[offset
+ i
] = pointer
[j
];
1416 else if (pointer
[j
+1] != 0xff || (pointer
[0] & 0x40) == 0)
1419 lfn
->name
[offset
+ i
] = 0;
1422 if (pointer
[0] & 0x40)
1423 lfn
->len
= offset
+ strlen(lfn
->name
+ offset
);
1428 /* returns 0 if successful, >0 if no short_name, and <0 on error */
1429 static int parse_short_name(BDRVVVFATState
* s
,
1430 long_file_name
* lfn
, direntry_t
* direntry
)
1434 if (!is_short_name(direntry
))
1437 for (j
= 7; j
>= 0 && direntry
->name
[j
] == ' '; j
--);
1438 for (i
= 0; i
<= j
; i
++) {
1439 if (direntry
->name
[i
] <= ' ' || direntry
->name
[i
] > 0x7f)
1441 else if (s
->downcase_short_names
)
1442 lfn
->name
[i
] = tolower(direntry
->name
[i
]);
1444 lfn
->name
[i
] = direntry
->name
[i
];
1447 for (j
= 2; j
>= 0 && direntry
->extension
[j
] == ' '; j
--);
1449 lfn
->name
[i
++] = '.';
1450 lfn
->name
[i
+ j
+ 1] = '\0';
1451 for (;j
>= 0; j
--) {
1452 if (direntry
->extension
[j
] <= ' ' || direntry
->extension
[j
] > 0x7f)
1454 else if (s
->downcase_short_names
)
1455 lfn
->name
[i
+ j
] = tolower(direntry
->extension
[j
]);
1457 lfn
->name
[i
+ j
] = direntry
->extension
[j
];
1460 lfn
->name
[i
+ j
+ 1] = '\0';
1462 lfn
->len
= strlen(lfn
->name
);
1467 static inline uint32_t modified_fat_get(BDRVVVFATState
* s
,
1468 unsigned int cluster
)
1470 if (cluster
< s
->last_cluster_of_root_directory
) {
1471 if (cluster
+ 1 == s
->last_cluster_of_root_directory
)
1472 return s
->max_fat_value
;
1477 if (s
->fat_type
==32) {
1478 uint32_t* entry
=((uint32_t*)s
->fat2
)+cluster
;
1479 return le32_to_cpu(*entry
);
1480 } else if (s
->fat_type
==16) {
1481 uint16_t* entry
=((uint16_t*)s
->fat2
)+cluster
;
1482 return le16_to_cpu(*entry
);
1484 const uint8_t* x
=s
->fat2
+cluster
*3/2;
1485 return ((x
[0]|(x
[1]<<8))>>(cluster
&1?4:0))&0x0fff;
1489 static inline int cluster_was_modified(BDRVVVFATState
* s
, uint32_t cluster_num
)
1491 int was_modified
= 0;
1494 if (s
->qcow
== NULL
)
1497 for (i
= 0; !was_modified
&& i
< s
->sectors_per_cluster
; i
++)
1498 was_modified
= s
->qcow
->drv
->bdrv_is_allocated(s
->qcow
,
1499 cluster2sector(s
, cluster_num
) + i
, 1, &dummy
);
1501 return was_modified
;
1504 static const char* get_basename(const char* path
)
1506 char* basename
= strrchr(path
, '/');
1507 if (basename
== NULL
)
1510 return basename
+ 1; /* strip '/' */
1514 * The array s->used_clusters holds the states of the clusters. If it is
1515 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1516 * was modified, bit 3 is set.
1517 * If any cluster is allocated, but not part of a file or directory, this
1518 * driver refuses to commit.
1521 USED_DIRECTORY
= 1, USED_FILE
= 2, USED_ANY
= 3, USED_ALLOCATED
= 4
1525 * get_cluster_count_for_direntry() not only determines how many clusters
1526 * are occupied by direntry, but also if it was renamed or modified.
1528 * A file is thought to be renamed *only* if there already was a file with
1529 * exactly the same first cluster, but a different name.
1531 * Further, the files/directories handled by this function are
1532 * assumed to be *not* deleted (and *only* those).
1534 static uint32_t get_cluster_count_for_direntry(BDRVVVFATState
* s
,
1535 direntry_t
* direntry
, const char* path
)
1538 * This is a little bit tricky:
1539 * IF the guest OS just inserts a cluster into the file chain,
1540 * and leaves the rest alone, (i.e. the original file had clusters
1541 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1543 * - do_commit will write the cluster into the file at the given
1546 * - the cluster which is overwritten should be moved to a later
1547 * position in the file.
1549 * I am not aware that any OS does something as braindead, but this
1550 * situation could happen anyway when not committing for a long time.
1551 * Just to be sure that this does not bite us, detect it, and copy the
1552 * contents of the clusters to-be-overwritten into the qcow.
1555 int was_modified
= 0;
1558 uint32_t cluster_num
= begin_of_direntry(direntry
);
1559 uint32_t offset
= 0;
1560 int first_mapping_index
= -1;
1561 mapping_t
* mapping
= NULL
;
1562 const char* basename2
= NULL
;
1564 vvfat_close_current_file(s
);
1566 /* the root directory */
1567 if (cluster_num
== 0)
1572 basename2
= get_basename(path
);
1574 mapping
= find_mapping_for_cluster(s
, cluster_num
);
1577 const char* basename
;
1579 assert(mapping
->mode
& MODE_DELETED
);
1580 mapping
->mode
&= ~MODE_DELETED
;
1582 basename
= get_basename(mapping
->path
);
1584 assert(mapping
->mode
& MODE_NORMAL
);
1587 if (strcmp(basename
, basename2
))
1588 schedule_rename(s
, cluster_num
, strdup(path
));
1589 } else if (is_file(direntry
))
1591 schedule_new_file(s
, strdup(path
), cluster_num
);
1600 if (!copy_it
&& cluster_was_modified(s
, cluster_num
)) {
1601 if (mapping
== NULL
||
1602 mapping
->begin
> cluster_num
||
1603 mapping
->end
<= cluster_num
)
1604 mapping
= find_mapping_for_cluster(s
, cluster_num
);
1608 (mapping
->mode
& MODE_DIRECTORY
) == 0) {
1610 /* was modified in qcow */
1611 if (offset
!= mapping
->info
.file
.offset
+ s
->cluster_size
1612 * (cluster_num
- mapping
->begin
)) {
1613 /* offset of this cluster in file chain has changed */
1616 } else if (offset
== 0) {
1617 const char* basename
= get_basename(mapping
->path
);
1619 if (strcmp(basename
, basename2
))
1621 first_mapping_index
= array_index(&(s
->mapping
), mapping
);
1624 if (mapping
->first_mapping_index
!= first_mapping_index
1625 && mapping
->info
.file
.offset
> 0) {
1630 /* need to write out? */
1631 if (!was_modified
&& is_file(direntry
)) {
1633 schedule_writeout(s
, mapping
->dir_index
, offset
);
1641 * This is horribly inefficient, but that is okay, since
1642 * it is rarely executed, if at all.
1644 int64_t offset
= cluster2sector(s
, cluster_num
);
1646 vvfat_close_current_file(s
);
1647 for (i
= 0; i
< s
->sectors_per_cluster
; i
++)
1648 if (!s
->qcow
->drv
->bdrv_is_allocated(s
->qcow
,
1649 offset
+ i
, 1, &dummy
)) {
1650 if (vvfat_read(s
->bs
,
1651 offset
, s
->cluster_buffer
, 1))
1653 if (s
->qcow
->drv
->bdrv_write(s
->qcow
,
1654 offset
, s
->cluster_buffer
, 1))
1661 if (s
->used_clusters
[cluster_num
] & USED_ANY
)
1663 s
->used_clusters
[cluster_num
] = USED_FILE
;
1665 cluster_num
= modified_fat_get(s
, cluster_num
);
1667 if (fat_eof(s
, cluster_num
))
1669 else if (cluster_num
< 2 || cluster_num
> s
->max_fat_value
- 16)
1672 offset
+= s
->cluster_size
;
1677 * This function looks at the modified data (qcow).
1678 * It returns 0 upon inconsistency or error, and the number of clusters
1679 * used by the directory, its subdirectories and their files.
1681 static int check_directory_consistency(BDRVVVFATState
*s
,
1682 int cluster_num
, const char* path
)
1685 unsigned char* cluster
= malloc(s
->cluster_size
);
1686 direntry_t
* direntries
= (direntry_t
*)cluster
;
1687 mapping_t
* mapping
= find_mapping_for_cluster(s
, cluster_num
);
1690 int path_len
= strlen(path
);
1691 char path2
[PATH_MAX
];
1693 assert(path_len
< PATH_MAX
); /* len was tested before! */
1694 strcpy(path2
, path
);
1695 path2
[path_len
] = '/';
1696 path2
[path_len
+ 1] = '\0';
1699 const char* basename
= get_basename(mapping
->path
);
1700 const char* basename2
= get_basename(path
);
1702 assert(mapping
->mode
& MODE_DIRECTORY
);
1704 assert(mapping
->mode
& MODE_DELETED
);
1705 mapping
->mode
&= ~MODE_DELETED
;
1707 if (strcmp(basename
, basename2
))
1708 schedule_rename(s
, cluster_num
, strdup(path
));
1711 schedule_mkdir(s
, cluster_num
, strdup(path
));
1720 if (s
->used_clusters
[cluster_num
] & USED_ANY
) {
1721 fprintf(stderr
, "cluster %d used more than once\n", (int)cluster_num
);
1724 s
->used_clusters
[cluster_num
] = USED_DIRECTORY
;
1726 DLOG(fprintf(stderr
, "read cluster %d (sector %d)\n", (int)cluster_num
, (int)cluster2sector(s
, cluster_num
)));
1727 subret
= vvfat_read(s
->bs
, cluster2sector(s
, cluster_num
), cluster
,
1728 s
->sectors_per_cluster
);
1730 fprintf(stderr
, "Error fetching direntries\n");
1736 for (i
= 0; i
< 0x10 * s
->sectors_per_cluster
; i
++) {
1739 DLOG(fprintf(stderr
, "check direntry %d: \n", i
); print_direntry(direntries
+ i
));
1740 if (is_volume_label(direntries
+ i
) || is_dot(direntries
+ i
) ||
1741 is_free(direntries
+ i
))
1744 subret
= parse_long_name(&lfn
, direntries
+ i
);
1746 fprintf(stderr
, "Error in long name\n");
1749 if (subret
== 0 || is_free(direntries
+ i
))
1752 if (fat_chksum(direntries
+i
) != lfn
.checksum
) {
1753 subret
= parse_short_name(s
, &lfn
, direntries
+ i
);
1755 fprintf(stderr
, "Error in short name (%d)\n", subret
);
1758 if (subret
> 0 || !strcmp(lfn
.name
, ".")
1759 || !strcmp(lfn
.name
, ".."))
1762 lfn
.checksum
= 0x100; /* cannot use long name twice */
1764 if (path_len
+ 1 + lfn
.len
>= PATH_MAX
) {
1765 fprintf(stderr
, "Name too long: %s/%s\n", path
, lfn
.name
);
1768 strcpy(path2
+ path_len
+ 1, lfn
.name
);
1770 if (is_directory(direntries
+ i
)) {
1771 if (begin_of_direntry(direntries
+ i
) == 0) {
1772 DLOG(fprintf(stderr
, "invalid begin for directory: %s\n", path2
); print_direntry(direntries
+ i
));
1775 cluster_count
= check_directory_consistency(s
,
1776 begin_of_direntry(direntries
+ i
), path2
);
1777 if (cluster_count
== 0) {
1778 DLOG(fprintf(stderr
, "problem in directory %s:\n", path2
); print_direntry(direntries
+ i
));
1781 } else if (is_file(direntries
+ i
)) {
1782 /* check file size with FAT */
1783 cluster_count
= get_cluster_count_for_direntry(s
, direntries
+ i
, path2
);
1784 if (cluster_count
!=
1785 (le32_to_cpu(direntries
[i
].size
) + s
->cluster_size
1786 - 1) / s
->cluster_size
) {
1787 DLOG(fprintf(stderr
, "Cluster count mismatch\n"));
1791 assert(0); /* cluster_count = 0; */
1793 ret
+= cluster_count
;
1796 cluster_num
= modified_fat_get(s
, cluster_num
);
1797 } while(!fat_eof(s
, cluster_num
));
1803 /* returns 1 on success */
1804 static int is_consistent(BDRVVVFATState
* s
)
1807 int used_clusters_count
= 0;
1811 * - get modified FAT
1812 * - compare the two FATs (TODO)
1813 * - get buffer for marking used clusters
1814 * - recurse direntries from root (using bs->bdrv_read to make
1815 * sure to get the new data)
1816 * - check that the FAT agrees with the size
1817 * - count the number of clusters occupied by this directory and
1819 * - check that the cumulative used cluster count agrees with the
1821 * - if all is fine, return number of used clusters
1823 if (s
->fat2
== NULL
) {
1824 int size
= 0x200 * s
->sectors_per_fat
;
1825 s
->fat2
= malloc(size
);
1826 memcpy(s
->fat2
, s
->fat
.pointer
, size
);
1828 check
= vvfat_read(s
->bs
,
1829 s
->first_sectors_number
, s
->fat2
, s
->sectors_per_fat
);
1831 fprintf(stderr
, "Could not copy fat\n");
1834 assert (s
->used_clusters
);
1835 for (i
= 0; i
< sector2cluster(s
, s
->sector_count
); i
++)
1836 s
->used_clusters
[i
] &= ~USED_ANY
;
1840 /* mark every mapped file/directory as deleted.
1841 * (check_directory_consistency() will unmark those still present). */
1843 for (i
= 0; i
< s
->mapping
.next
; i
++) {
1844 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
1845 if (mapping
->first_mapping_index
< 0)
1846 mapping
->mode
|= MODE_DELETED
;
1849 used_clusters_count
= check_directory_consistency(s
, 0, s
->path
);
1850 if (used_clusters_count
<= 0) {
1851 DLOG(fprintf(stderr
, "problem in directory\n"));
1855 check
= s
->last_cluster_of_root_directory
;
1856 for (i
= check
; i
< sector2cluster(s
, s
->sector_count
); i
++) {
1857 if (modified_fat_get(s
, i
)) {
1858 if(!s
->used_clusters
[i
]) {
1859 DLOG(fprintf(stderr
, "FAT was modified (%d), but cluster is not used?\n", i
));
1865 if (s
->used_clusters
[i
] == USED_ALLOCATED
) {
1866 /* allocated, but not used... */
1867 DLOG(fprintf(stderr
, "unused, modified cluster: %d\n", i
));
1872 if (check
!= used_clusters_count
)
1875 return used_clusters_count
;
1878 static inline void adjust_mapping_indices(BDRVVVFATState
* s
,
1879 int offset
, int adjust
)
1883 for (i
= 0; i
< s
->mapping
.next
; i
++) {
1884 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
1886 #define ADJUST_MAPPING_INDEX(name) \
1887 if (mapping->name >= offset) \
1888 mapping->name += adjust
1890 ADJUST_MAPPING_INDEX(first_mapping_index
);
1891 if (mapping
->mode
& MODE_DIRECTORY
)
1892 ADJUST_MAPPING_INDEX(info
.dir
.parent_mapping_index
);
1896 /* insert or update mapping */
1897 static mapping_t
* insert_mapping(BDRVVVFATState
* s
,
1898 uint32_t begin
, uint32_t end
)
1901 * - find mapping where mapping->begin >= begin,
1902 * - if mapping->begin > begin: insert
1903 * - adjust all references to mappings!
1907 int index
= find_mapping_for_cluster_aux(s
, begin
, 0, s
->mapping
.next
);
1908 mapping_t
* mapping
= NULL
;
1909 mapping_t
* first_mapping
= array_get(&(s
->mapping
), 0);
1911 if (index
< s
->mapping
.next
&& (mapping
= array_get(&(s
->mapping
), index
))
1912 && mapping
->begin
< begin
) {
1913 mapping
->end
= begin
;
1915 mapping
= array_get(&(s
->mapping
), index
);
1917 if (index
>= s
->mapping
.next
|| mapping
->begin
> begin
) {
1918 mapping
= array_insert(&(s
->mapping
), index
, 1);
1919 mapping
->path
= NULL
;
1920 adjust_mapping_indices(s
, index
, +1);
1923 mapping
->begin
= begin
;
1926 DLOG(mapping_t
* next_mapping
;
1927 assert(index
+ 1 >= s
->mapping
.next
||
1928 ((next_mapping
= array_get(&(s
->mapping
), index
+ 1)) &&
1929 next_mapping
->begin
>= end
)));
1931 if (s
->current_mapping
&& first_mapping
!= (mapping_t
*)s
->mapping
.pointer
)
1932 s
->current_mapping
= array_get(&(s
->mapping
),
1933 s
->current_mapping
- first_mapping
);
1938 static int remove_mapping(BDRVVVFATState
* s
, int mapping_index
)
1940 mapping_t
* mapping
= array_get(&(s
->mapping
), mapping_index
);
1941 mapping_t
* first_mapping
= array_get(&(s
->mapping
), 0);
1944 if (mapping
->first_mapping_index
< 0)
1945 free(mapping
->path
);
1947 /* remove from s->mapping */
1948 array_remove(&(s
->mapping
), mapping_index
);
1950 /* adjust all references to mappings */
1951 adjust_mapping_indices(s
, mapping_index
, -1);
1953 if (s
->current_mapping
&& first_mapping
!= (mapping_t
*)s
->mapping
.pointer
)
1954 s
->current_mapping
= array_get(&(s
->mapping
),
1955 s
->current_mapping
- first_mapping
);
1960 static void adjust_dirindices(BDRVVVFATState
* s
, int offset
, int adjust
)
1963 for (i
= 0; i
< s
->mapping
.next
; i
++) {
1964 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
1965 if (mapping
->dir_index
>= offset
)
1966 mapping
->dir_index
+= adjust
;
1967 if ((mapping
->mode
& MODE_DIRECTORY
) &&
1968 mapping
->info
.dir
.first_dir_index
>= offset
)
1969 mapping
->info
.dir
.first_dir_index
+= adjust
;
1973 static direntry_t
* insert_direntries(BDRVVVFATState
* s
,
1974 int dir_index
, int count
)
1977 * make room in s->directory,
1980 direntry_t
* result
= array_insert(&(s
->directory
), dir_index
, count
);
1983 adjust_dirindices(s
, dir_index
, count
);
1987 static int remove_direntries(BDRVVVFATState
* s
, int dir_index
, int count
)
1989 int ret
= array_remove_slice(&(s
->directory
), dir_index
, count
);
1992 adjust_dirindices(s
, dir_index
, -count
);
1997 * Adapt the mappings of the cluster chain starting at first cluster
1998 * (i.e. if a file starts at first_cluster, the chain is followed according
1999 * to the modified fat, and the corresponding entries in s->mapping are
2002 static int commit_mappings(BDRVVVFATState
* s
,
2003 uint32_t first_cluster
, int dir_index
)
2005 mapping_t
* mapping
= find_mapping_for_cluster(s
, first_cluster
);
2006 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2007 uint32_t cluster
= first_cluster
;
2009 vvfat_close_current_file(s
);
2012 assert(mapping
->begin
== first_cluster
);
2013 mapping
->first_mapping_index
= -1;
2014 mapping
->dir_index
= dir_index
;
2015 mapping
->mode
= (dir_index
<= 0 || is_directory(direntry
)) ?
2016 MODE_DIRECTORY
: MODE_NORMAL
;
2018 while (!fat_eof(s
, cluster
)) {
2021 for (c
= cluster
, c1
= modified_fat_get(s
, c
); c
+ 1 == c1
;
2022 c
= c1
, c1
= modified_fat_get(s
, c1
));
2025 if (c
> mapping
->end
) {
2026 int index
= array_index(&(s
->mapping
), mapping
);
2027 int i
, max_i
= s
->mapping
.next
- index
;
2028 for (i
= 1; i
< max_i
&& mapping
[i
].begin
< c
; i
++);
2030 remove_mapping(s
, index
+ 1);
2032 assert(mapping
== array_get(&(s
->mapping
), s
->mapping
.next
- 1)
2033 || mapping
[1].begin
>= c
);
2036 if (!fat_eof(s
, c1
)) {
2037 int i
= find_mapping_for_cluster_aux(s
, c1
, 0, s
->mapping
.next
);
2038 mapping_t
* next_mapping
= i
>= s
->mapping
.next
? NULL
:
2039 array_get(&(s
->mapping
), i
);
2041 if (next_mapping
== NULL
|| next_mapping
->begin
> c1
) {
2042 int i1
= array_index(&(s
->mapping
), mapping
);
2044 next_mapping
= insert_mapping(s
, c1
, c1
+1);
2048 mapping
= array_get(&(s
->mapping
), i1
);
2051 next_mapping
->dir_index
= mapping
->dir_index
;
2052 next_mapping
->first_mapping_index
=
2053 mapping
->first_mapping_index
< 0 ?
2054 array_index(&(s
->mapping
), mapping
) :
2055 mapping
->first_mapping_index
;
2056 next_mapping
->path
= mapping
->path
;
2057 next_mapping
->mode
= mapping
->mode
;
2058 next_mapping
->read_only
= mapping
->read_only
;
2059 if (mapping
->mode
& MODE_DIRECTORY
) {
2060 next_mapping
->info
.dir
.parent_mapping_index
=
2061 mapping
->info
.dir
.parent_mapping_index
;
2062 next_mapping
->info
.dir
.first_dir_index
=
2063 mapping
->info
.dir
.first_dir_index
+
2064 0x10 * s
->sectors_per_cluster
*
2065 (mapping
->end
- mapping
->begin
);
2067 next_mapping
->info
.file
.offset
= mapping
->info
.file
.offset
+
2068 mapping
->end
- mapping
->begin
;
2070 mapping
= next_mapping
;
2079 static int commit_direntries(BDRVVVFATState
* s
,
2080 int dir_index
, int parent_mapping_index
)
2082 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2083 uint32_t first_cluster
= dir_index
== 0 ? 0 : begin_of_direntry(direntry
);
2084 mapping_t
* mapping
= find_mapping_for_cluster(s
, first_cluster
);
2086 int factor
= 0x10 * s
->sectors_per_cluster
;
2087 int old_cluster_count
, new_cluster_count
;
2088 int current_dir_index
= mapping
->info
.dir
.first_dir_index
;
2089 int first_dir_index
= current_dir_index
;
2093 DLOG(fprintf(stderr
, "commit_direntries for %s, parent_mapping_index %d\n", mapping
->path
, parent_mapping_index
));
2097 assert(mapping
->begin
== first_cluster
);
2098 assert(mapping
->info
.dir
.first_dir_index
< s
->directory
.next
);
2099 assert(mapping
->mode
& MODE_DIRECTORY
);
2100 assert(dir_index
== 0 || is_directory(direntry
));
2102 mapping
->info
.dir
.parent_mapping_index
= parent_mapping_index
;
2104 if (first_cluster
== 0) {
2105 old_cluster_count
= new_cluster_count
=
2106 s
->last_cluster_of_root_directory
;
2108 for (old_cluster_count
= 0, c
= first_cluster
; !fat_eof(s
, c
);
2110 old_cluster_count
++;
2112 for (new_cluster_count
= 0, c
= first_cluster
; !fat_eof(s
, c
);
2113 c
= modified_fat_get(s
, c
))
2114 new_cluster_count
++;
2117 if (new_cluster_count
> old_cluster_count
) {
2118 if (insert_direntries(s
,
2119 current_dir_index
+ factor
* old_cluster_count
,
2120 factor
* (new_cluster_count
- old_cluster_count
)) == NULL
)
2122 } else if (new_cluster_count
< old_cluster_count
)
2123 remove_direntries(s
,
2124 current_dir_index
+ factor
* new_cluster_count
,
2125 factor
* (old_cluster_count
- new_cluster_count
));
2127 for (c
= first_cluster
; !fat_eof(s
, c
); c
= modified_fat_get(s
, c
)) {
2128 void* direntry
= array_get(&(s
->directory
), current_dir_index
);
2129 int ret
= vvfat_read(s
->bs
, cluster2sector(s
, c
), direntry
,
2130 s
->sectors_per_cluster
);
2133 assert(!strncmp(s
->directory
.pointer
, "QEMU", 4));
2134 current_dir_index
+= factor
;
2137 ret
= commit_mappings(s
, first_cluster
, dir_index
);
2142 for (i
= 0; i
< factor
* new_cluster_count
; i
++) {
2143 direntry
= array_get(&(s
->directory
), first_dir_index
+ i
);
2144 if (is_directory(direntry
) && !is_dot(direntry
)) {
2145 mapping
= find_mapping_for_cluster(s
, first_cluster
);
2146 assert(mapping
->mode
& MODE_DIRECTORY
);
2147 ret
= commit_direntries(s
, first_dir_index
+ i
,
2148 array_index(&(s
->mapping
), mapping
));
2157 /* commit one file (adjust contents, adjust mapping),
2158 return first_mapping_index */
2159 static int commit_one_file(BDRVVVFATState
* s
,
2160 int dir_index
, uint32_t offset
)
2162 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2163 uint32_t c
= begin_of_direntry(direntry
);
2164 uint32_t first_cluster
= c
;
2165 mapping_t
* mapping
= find_mapping_for_cluster(s
, c
);
2166 uint32_t size
= filesize_of_direntry(direntry
);
2167 char* cluster
= malloc(s
->cluster_size
);
2171 assert(offset
< size
);
2172 assert((offset
% s
->cluster_size
) == 0);
2174 for (i
= s
->cluster_size
; i
< offset
; i
+= s
->cluster_size
)
2175 c
= modified_fat_get(s
, c
);
2177 fd
= open(mapping
->path
, O_RDWR
| O_CREAT
, 0666);
2179 fprintf(stderr
, "Could not open %s... (%s, %d)\n", mapping
->path
,
2180 strerror(errno
), errno
);
2184 if (lseek(fd
, offset
, SEEK_SET
) != offset
)
2187 while (offset
< size
) {
2189 int rest_size
= (size
- offset
> s
->cluster_size
?
2190 s
->cluster_size
: size
- offset
);
2193 c1
= modified_fat_get(s
, c
);
2195 assert((size
- offset
== 0 && fat_eof(s
, c
)) ||
2196 (size
> offset
&& c
>=2 && !fat_eof(s
, c
)));
2199 ret
= vvfat_read(s
->bs
, cluster2sector(s
, c
),
2200 cluster
, (rest_size
+ 0x1ff) / 0x200);
2205 if (write(fd
, cluster
, rest_size
) < 0)
2208 offset
+= rest_size
;
2212 ftruncate(fd
, size
);
2215 return commit_mappings(s
, first_cluster
, dir_index
);
2219 /* test, if all mappings point to valid direntries */
2220 static void check1(BDRVVVFATState
* s
)
2223 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2224 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2225 if (mapping
->mode
& MODE_DELETED
) {
2226 fprintf(stderr
, "deleted\n");
2229 assert(mapping
->dir_index
>= 0);
2230 assert(mapping
->dir_index
< s
->directory
.next
);
2231 direntry_t
* direntry
= array_get(&(s
->directory
), mapping
->dir_index
);
2232 assert(mapping
->begin
== begin_of_direntry(direntry
) || mapping
->first_mapping_index
>= 0);
2233 if (mapping
->mode
& MODE_DIRECTORY
) {
2234 assert(mapping
->info
.dir
.first_dir_index
+ 0x10 * s
->sectors_per_cluster
* (mapping
->end
- mapping
->begin
) <= s
->directory
.next
);
2235 assert((mapping
->info
.dir
.first_dir_index
% (0x10 * s
->sectors_per_cluster
)) == 0);
2240 /* test, if all direntries have mappings */
2241 static void check2(BDRVVVFATState
* s
)
2244 int first_mapping
= -1;
2246 for (i
= 0; i
< s
->directory
.next
; i
++) {
2247 direntry_t
* direntry
= array_get(&(s
->directory
), i
);
2249 if (is_short_name(direntry
) && begin_of_direntry(direntry
)) {
2250 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin_of_direntry(direntry
));
2252 assert(mapping
->dir_index
== i
|| is_dot(direntry
));
2253 assert(mapping
->begin
== begin_of_direntry(direntry
) || is_dot(direntry
));
2256 if ((i
% (0x10 * s
->sectors_per_cluster
)) == 0) {
2260 for (j
= 0; j
< s
->mapping
.next
; j
++) {
2261 mapping_t
* mapping
= array_get(&(s
->mapping
), j
);
2262 if (mapping
->mode
& MODE_DELETED
)
2264 if (mapping
->mode
& MODE_DIRECTORY
) {
2265 if (mapping
->info
.dir
.first_dir_index
<= i
&& mapping
->info
.dir
.first_dir_index
+ 0x10 * s
->sectors_per_cluster
> i
) {
2266 assert(++count
== 1);
2267 if (mapping
->first_mapping_index
== -1)
2268 first_mapping
= array_index(&(s
->mapping
), mapping
);
2270 assert(first_mapping
== mapping
->first_mapping_index
);
2271 if (mapping
->info
.dir
.parent_mapping_index
< 0)
2274 mapping_t
* parent
= array_get(&(s
->mapping
), mapping
->info
.dir
.parent_mapping_index
);
2275 assert(parent
->mode
& MODE_DIRECTORY
);
2276 assert(parent
->info
.dir
.first_dir_index
< mapping
->info
.dir
.first_dir_index
);
2288 static int handle_renames_and_mkdirs(BDRVVVFATState
* s
)
2293 fprintf(stderr
, "handle_renames\n");
2294 for (i
= 0; i
< s
->commits
.next
; i
++) {
2295 commit_t
* commit
= array_get(&(s
->commits
), i
);
2296 fprintf(stderr
, "%d, %s (%d, %d)\n", i
, commit
->path
? commit
->path
: "(null)", commit
->param
.rename
.cluster
, commit
->action
);
2300 for (i
= 0; i
< s
->commits
.next
;) {
2301 commit_t
* commit
= array_get(&(s
->commits
), i
);
2302 if (commit
->action
== ACTION_RENAME
) {
2303 mapping_t
* mapping
= find_mapping_for_cluster(s
,
2304 commit
->param
.rename
.cluster
);
2305 char* old_path
= mapping
->path
;
2307 assert(commit
->path
);
2308 mapping
->path
= commit
->path
;
2309 if (rename(old_path
, mapping
->path
))
2312 if (mapping
->mode
& MODE_DIRECTORY
) {
2313 int l1
= strlen(mapping
->path
);
2314 int l2
= strlen(old_path
);
2316 direntry_t
* direntry
= array_get(&(s
->directory
),
2317 mapping
->info
.dir
.first_dir_index
);
2318 uint32_t c
= mapping
->begin
;
2322 while (!fat_eof(s
, c
)) {
2324 direntry_t
* d
= direntry
+ i
;
2326 if (is_file(d
) || (is_directory(d
) && !is_dot(d
))) {
2327 mapping_t
* m
= find_mapping_for_cluster(s
,
2328 begin_of_direntry(d
));
2329 int l
= strlen(m
->path
);
2330 char* new_path
= malloc(l
+ diff
+ 1);
2332 assert(!strncmp(m
->path
, mapping
->path
, l2
));
2334 strcpy(new_path
, mapping
->path
);
2335 strcpy(new_path
+ l1
, m
->path
+ l2
);
2337 schedule_rename(s
, m
->begin
, new_path
);
2340 } while((i
% (0x10 * s
->sectors_per_cluster
)) != 0);
2346 array_remove(&(s
->commits
), i
);
2348 } else if (commit
->action
== ACTION_MKDIR
) {
2350 int j
, parent_path_len
;
2353 if (mkdir(commit
->path
))
2356 if (mkdir(commit
->path
, 0755))
2360 mapping
= insert_mapping(s
, commit
->param
.mkdir
.cluster
,
2361 commit
->param
.mkdir
.cluster
+ 1);
2362 if (mapping
== NULL
)
2365 mapping
->mode
= MODE_DIRECTORY
;
2366 mapping
->read_only
= 0;
2367 mapping
->path
= commit
->path
;
2368 j
= s
->directory
.next
;
2370 insert_direntries(s
, s
->directory
.next
,
2371 0x10 * s
->sectors_per_cluster
);
2372 mapping
->info
.dir
.first_dir_index
= j
;
2374 parent_path_len
= strlen(commit
->path
)
2375 - strlen(get_basename(commit
->path
)) - 1;
2376 for (j
= 0; j
< s
->mapping
.next
; j
++) {
2377 mapping_t
* m
= array_get(&(s
->mapping
), j
);
2378 if (m
->first_mapping_index
< 0 && m
!= mapping
&&
2379 !strncmp(m
->path
, mapping
->path
, parent_path_len
) &&
2380 strlen(m
->path
) == parent_path_len
)
2383 assert(j
< s
->mapping
.next
);
2384 mapping
->info
.dir
.parent_mapping_index
= j
;
2386 array_remove(&(s
->commits
), i
);
2396 * TODO: make sure that the short name is not matching *another* file
2398 static int handle_commits(BDRVVVFATState
* s
)
2402 vvfat_close_current_file(s
);
2404 for (i
= 0; !fail
&& i
< s
->commits
.next
; i
++) {
2405 commit_t
* commit
= array_get(&(s
->commits
), i
);
2406 switch(commit
->action
) {
2407 case ACTION_RENAME
: case ACTION_MKDIR
:
2411 case ACTION_WRITEOUT
: {
2412 direntry_t
* entry
= array_get(&(s
->directory
),
2413 commit
->param
.writeout
.dir_index
);
2414 uint32_t begin
= begin_of_direntry(entry
);
2415 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin
);
2418 assert(mapping
->begin
== begin
);
2419 assert(commit
->path
== NULL
);
2421 if (commit_one_file(s
, commit
->param
.writeout
.dir_index
,
2422 commit
->param
.writeout
.modified_offset
))
2427 case ACTION_NEW_FILE
: {
2428 int begin
= commit
->param
.new_file
.first_cluster
;
2429 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin
);
2434 for (i
= 0; i
< s
->directory
.next
; i
++) {
2435 entry
= array_get(&(s
->directory
), i
);
2436 if (is_file(entry
) && begin_of_direntry(entry
) == begin
)
2440 if (i
>= s
->directory
.next
) {
2445 /* make sure there exists an initial mapping */
2446 if (mapping
&& mapping
->begin
!= begin
) {
2447 mapping
->end
= begin
;
2450 if (mapping
== NULL
) {
2451 mapping
= insert_mapping(s
, begin
, begin
+1);
2453 /* most members will be fixed in commit_mappings() */
2454 assert(commit
->path
);
2455 mapping
->path
= commit
->path
;
2456 mapping
->read_only
= 0;
2457 mapping
->mode
= MODE_NORMAL
;
2458 mapping
->info
.file
.offset
= 0;
2460 if (commit_one_file(s
, i
, 0))
2469 if (i
> 0 && array_remove_slice(&(s
->commits
), 0, i
))
2474 static int handle_deletes(BDRVVVFATState
* s
)
2476 int i
, deferred
= 1, deleted
= 1;
2478 /* delete files corresponding to mappings marked as deleted */
2479 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2480 while (deferred
&& deleted
) {
2484 for (i
= 1; i
< s
->mapping
.next
; i
++) {
2485 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2486 if (mapping
->mode
& MODE_DELETED
) {
2487 direntry_t
* entry
= array_get(&(s
->directory
),
2488 mapping
->dir_index
);
2490 if (is_free(entry
)) {
2491 /* remove file/directory */
2492 if (mapping
->mode
& MODE_DIRECTORY
) {
2493 int j
, next_dir_index
= s
->directory
.next
,
2494 first_dir_index
= mapping
->info
.dir
.first_dir_index
;
2496 if (rmdir(mapping
->path
) < 0) {
2497 if (errno
== ENOTEMPTY
) {
2504 for (j
= 1; j
< s
->mapping
.next
; j
++) {
2505 mapping_t
* m
= array_get(&(s
->mapping
), j
);
2506 if (m
->mode
& MODE_DIRECTORY
&&
2507 m
->info
.dir
.first_dir_index
>
2509 m
->info
.dir
.first_dir_index
<
2512 m
->info
.dir
.first_dir_index
;
2514 remove_direntries(s
, first_dir_index
,
2515 next_dir_index
- first_dir_index
);
2520 if (unlink(mapping
->path
))
2524 DLOG(fprintf(stderr
, "DELETE (%d)\n", i
); print_mapping(mapping
); print_direntry(entry
));
2525 remove_mapping(s
, i
);
2534 * synchronize mapping with new state:
2536 * - copy FAT (with bdrv_read)
2537 * - mark all filenames corresponding to mappings as deleted
2538 * - recurse direntries from root (using bs->bdrv_read)
2539 * - delete files corresponding to mappings marked as deleted
2541 static int do_commit(BDRVVVFATState
* s
)
2545 /* the real meat are the commits. Nothing to do? Move along! */
2546 if (s
->commits
.next
== 0)
2549 vvfat_close_current_file(s
);
2551 ret
= handle_renames_and_mkdirs(s
);
2553 fprintf(stderr
, "Error handling renames (%d)\n", ret
);
2558 /* copy FAT (with bdrv_read) */
2559 memcpy(s
->fat
.pointer
, s
->fat2
, 0x200 * s
->sectors_per_fat
);
2561 /* recurse direntries from root (using bs->bdrv_read) */
2562 ret
= commit_direntries(s
, 0, -1);
2564 fprintf(stderr
, "Fatal: error while committing (%d)\n", ret
);
2569 ret
= handle_commits(s
);
2571 fprintf(stderr
, "Error handling commits (%d)\n", ret
);
2576 ret
= handle_deletes(s
);
2578 fprintf(stderr
, "Error deleting\n");
2583 s
->qcow
->drv
->bdrv_make_empty(s
->qcow
);
2585 memset(s
->used_clusters
, 0, sector2cluster(s
, s
->sector_count
));
2591 static int try_commit(BDRVVVFATState
* s
)
2593 vvfat_close_current_file(s
);
2595 if(!is_consistent(s
))
2597 return do_commit(s
);
2600 static int vvfat_write(BlockDriverState
*bs
, int64_t sector_num
,
2601 const uint8_t *buf
, int nb_sectors
)
2603 BDRVVVFATState
*s
= bs
->opaque
;
2608 vvfat_close_current_file(s
);
2611 * Some sanity checks:
2612 * - do not allow writing to the boot sector
2613 * - do not allow to write non-ASCII filenames
2616 if (sector_num
< s
->first_sectors_number
)
2619 for (i
= sector2cluster(s
, sector_num
);
2620 i
<= sector2cluster(s
, sector_num
+ nb_sectors
- 1);) {
2621 mapping_t
* mapping
= find_mapping_for_cluster(s
, i
);
2623 if (mapping
->read_only
) {
2624 fprintf(stderr
, "Tried to write to write-protected file %s\n",
2629 if (mapping
->mode
& MODE_DIRECTORY
) {
2630 int begin
= cluster2sector(s
, i
);
2631 int end
= begin
+ s
->sectors_per_cluster
, k
;
2633 const direntry_t
* direntries
;
2638 if (begin
< sector_num
)
2640 if (end
> sector_num
+ nb_sectors
)
2641 end
= sector_num
+ nb_sectors
;
2642 dir_index
= mapping
->dir_index
+
2643 0x10 * (begin
- mapping
->begin
* s
->sectors_per_cluster
);
2644 direntries
= (direntry_t
*)(buf
+ 0x200 * (begin
- sector_num
));
2646 for (k
= 0; k
< (end
- begin
) * 0x10; k
++) {
2647 /* do not allow non-ASCII filenames */
2648 if (parse_long_name(&lfn
, direntries
+ k
) < 0) {
2649 fprintf(stderr
, "Warning: non-ASCII filename\n");
2652 /* no access to the direntry of a read-only file */
2653 else if (is_short_name(direntries
+k
) &&
2654 (direntries
[k
].attributes
& 1)) {
2655 if (memcmp(direntries
+ k
,
2656 array_get(&(s
->directory
), dir_index
+ k
),
2657 sizeof(direntry_t
))) {
2658 fprintf(stderr
, "Warning: tried to write to write-protected file\n");
2670 * Use qcow backend. Commit later.
2672 DLOG(fprintf(stderr
, "Write to qcow backend: %d + %d\n", (int)sector_num
, nb_sectors
));
2673 ret
= s
->qcow
->drv
->bdrv_write(s
->qcow
, sector_num
, buf
, nb_sectors
);
2675 fprintf(stderr
, "Error writing to qcow backend\n");
2679 for (i
= sector2cluster(s
, sector_num
);
2680 i
<= sector2cluster(s
, sector_num
+ nb_sectors
- 1); i
++)
2682 s
->used_clusters
[i
] |= USED_ALLOCATED
;
2685 /* TODO: add timeout */
2692 static int vvfat_is_allocated(BlockDriverState
*bs
,
2693 int64_t sector_num
, int nb_sectors
, int* n
)
2695 BDRVVVFATState
* s
= bs
->opaque
;
2696 *n
= s
->sector_count
- sector_num
;
2697 if (*n
> nb_sectors
)
2704 static int write_target_commit(BlockDriverState
*bs
, int64_t sector_num
,
2705 const uint8_t* buffer
, int nb_sectors
) {
2706 BDRVVVFATState
* s
= bs
->opaque
;
2707 return try_commit(s
);
2710 static void write_target_close(BlockDriverState
*bs
) {
2711 BDRVVVFATState
* s
= bs
->opaque
;
2712 bdrv_delete(s
->qcow
);
2713 free(s
->qcow_filename
);
2716 static BlockDriver vvfat_write_target
= {
2717 "vvfat_write_target", 0, NULL
, NULL
, NULL
,
2718 write_target_commit
,
2723 static int enable_write_target(BDRVVVFATState
*s
)
2725 int size
= sector2cluster(s
, s
->sector_count
);
2726 s
->used_clusters
= calloc(size
, 1);
2728 array_init(&(s
->commits
), sizeof(commit_t
));
2730 s
->qcow_filename
= malloc(1024);
2731 get_tmp_filename(s
->qcow_filename
, 1024);
2732 if (bdrv_create(&bdrv_qcow
,
2733 s
->qcow_filename
, s
->sector_count
, "fat:", 0) < 0)
2735 s
->qcow
= bdrv_new("");
2736 if (s
->qcow
== NULL
|| bdrv_open(s
->qcow
, s
->qcow_filename
, 0) < 0)
2740 unlink(s
->qcow_filename
);
2743 s
->bs
->backing_hd
= calloc(sizeof(BlockDriverState
), 1);
2744 s
->bs
->backing_hd
->drv
= &vvfat_write_target
;
2745 s
->bs
->backing_hd
->opaque
= s
;
2750 static void vvfat_close(BlockDriverState
*bs
)
2752 BDRVVVFATState
*s
= bs
->opaque
;
2754 vvfat_close_current_file(s
);
2755 array_free(&(s
->fat
));
2756 array_free(&(s
->directory
));
2757 array_free(&(s
->mapping
));
2758 if(s
->cluster_buffer
)
2759 free(s
->cluster_buffer
);
2762 BlockDriver bdrv_vvfat
= {
2764 sizeof(BDRVVVFATState
),
2765 NULL
, /* no probe for protocols */
2770 NULL
, /* ??? Not sure if we can do any meaningful flushing. */
2773 .protocol_name
= "fat",
2777 static void checkpoint() {
2778 assert(((mapping_t
*)array_get(&(vvv
->mapping
), 0))->end
== 2);
2781 assert(!vvv
->current_mapping
|| vvv
->current_fd
|| (vvv
->current_mapping
->mode
& MODE_DIRECTORY
));
2783 if (((direntry_t
*)vvv
->directory
.pointer
)[1].attributes
!= 0xf)
2784 fprintf(stderr
, "Nonono!\n");
2786 direntry_t
* direntry
;
2787 assert(vvv
->mapping
.size
>= vvv
->mapping
.item_size
* vvv
->mapping
.next
);
2788 assert(vvv
->directory
.size
>= vvv
->directory
.item_size
* vvv
->directory
.next
);
2789 if (vvv
->mapping
.next
<47)
2791 assert((mapping
= array_get(&(vvv
->mapping
), 47)));
2792 assert(mapping
->dir_index
< vvv
->directory
.next
);
2793 direntry
= array_get(&(vvv
->directory
), mapping
->dir_index
);
2794 assert(!memcmp(direntry
->name
, "USB H ", 11) || direntry
->name
[0]==0);
2797 /* avoid compiler warnings: */
2799 remove_mapping(vvv
, NULL
);
2800 print_mapping(NULL
);
2801 print_direntry(NULL
);