1 /* vim:set shiftwidth=4 ts=8: */
3 * QEMU Block driver for virtual VFAT (shadows a local directory)
5 * Copyright (c) 2004,2005 Johannes E. Schindelin
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 #include "qemu-common.h"
28 #include "block_int.h"
38 /* TODO: add ":bootsector=blabla.img:" */
39 /* LATER TODO: add automatic boot sector generation from
40 BOOTEASY.ASM and Ranish Partition Manager
41 Note that DOS assumes the system files to be the first files in the
42 file system (test if the boot sector still relies on that fact)! */
43 /* MAYBE TODO: write block-visofs.c */
44 /* TODO: call try_commit() only after a timeout */
56 static void checkpoint(void);
59 void nonono(const char* file
, int line
, const char* msg
) {
60 fprintf(stderr
, "Nonono! %s:%d %s\n", file
, line
, msg
);
64 #define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
73 /* dynamic array functions */
74 typedef struct array_t
{
76 unsigned int size
,next
,item_size
;
79 static inline void array_init(array_t
* array
,unsigned int item_size
)
81 array
->pointer
= NULL
;
84 array
->item_size
=item_size
;
87 static inline void array_free(array_t
* array
)
89 g_free(array
->pointer
);
90 array
->size
=array
->next
=0;
93 /* does not automatically grow */
94 static inline void* array_get(array_t
* array
,unsigned int index
) {
95 assert(index
< array
->next
);
96 return array
->pointer
+ index
* array
->item_size
;
99 static inline int array_ensure_allocated(array_t
* array
, int index
)
101 if((index
+ 1) * array
->item_size
> array
->size
) {
102 int new_size
= (index
+ 32) * array
->item_size
;
103 array
->pointer
= g_realloc(array
->pointer
, new_size
);
106 array
->size
= new_size
;
107 array
->next
= index
+ 1;
113 static inline void* array_get_next(array_t
* array
) {
114 unsigned int next
= array
->next
;
117 if (array_ensure_allocated(array
, next
) < 0)
120 array
->next
= next
+ 1;
121 result
= array_get(array
, next
);
126 static inline void* array_insert(array_t
* array
,unsigned int index
,unsigned int count
) {
127 if((array
->next
+count
)*array
->item_size
>array
->size
) {
128 int increment
=count
*array
->item_size
;
129 array
->pointer
=g_realloc(array
->pointer
,array
->size
+increment
);
132 array
->size
+=increment
;
134 memmove(array
->pointer
+(index
+count
)*array
->item_size
,
135 array
->pointer
+index
*array
->item_size
,
136 (array
->next
-index
)*array
->item_size
);
138 return array
->pointer
+index
*array
->item_size
;
141 /* this performs a "roll", so that the element which was at index_from becomes
142 * index_to, but the order of all other elements is preserved. */
143 static inline int array_roll(array_t
* array
,int index_to
,int index_from
,int count
)
151 index_to
<0 || index_to
>=array
->next
||
152 index_from
<0 || index_from
>=array
->next
)
155 if(index_to
==index_from
)
159 from
=array
->pointer
+index_from
*is
;
160 to
=array
->pointer
+index_to
*is
;
161 buf
=g_malloc(is
*count
);
162 memcpy(buf
,from
,is
*count
);
164 if(index_to
<index_from
)
165 memmove(to
+is
*count
,to
,from
-to
);
167 memmove(from
,from
+is
*count
,to
-from
);
169 memcpy(to
,buf
,is
*count
);
176 static inline int array_remove_slice(array_t
* array
,int index
, int count
)
180 assert(index
+ count
<= array
->next
);
181 if(array_roll(array
,array
->next
-1,index
,count
))
183 array
->next
-= count
;
187 static int array_remove(array_t
* array
,int index
)
189 return array_remove_slice(array
, index
, 1);
192 /* return the index for a given member */
193 static int array_index(array_t
* array
, void* pointer
)
195 size_t offset
= (char*)pointer
- array
->pointer
;
196 assert((offset
% array
->item_size
) == 0);
197 assert(offset
/array
->item_size
< array
->next
);
198 return offset
/array
->item_size
;
201 /* These structures are used to fake a disk and the VFAT filesystem.
202 * For this reason we need to use QEMU_PACKED. */
204 typedef struct bootsector_t
{
207 uint16_t sector_size
;
208 uint8_t sectors_per_cluster
;
209 uint16_t reserved_sectors
;
210 uint8_t number_of_fats
;
211 uint16_t root_entries
;
212 uint16_t total_sectors16
;
214 uint16_t sectors_per_fat
;
215 uint16_t sectors_per_track
;
216 uint16_t number_of_heads
;
217 uint32_t hidden_sectors
;
218 uint32_t total_sectors
;
221 uint8_t drive_number
;
222 uint8_t current_head
;
225 uint8_t volume_label
[11];
228 uint32_t sectors_per_fat
;
231 uint32_t first_cluster_of_root_directory
;
232 uint16_t info_sector
;
233 uint16_t backup_boot_sector
;
238 uint8_t ignored
[0x1c0];
240 } QEMU_PACKED bootsector_t
;
248 typedef struct partition_t
{
249 uint8_t attributes
; /* 0x80 = bootable */
251 uint8_t fs_type
; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
253 uint32_t start_sector_long
;
254 uint32_t length_sector_long
;
255 } QEMU_PACKED partition_t
;
257 typedef struct mbr_t
{
258 uint8_t ignored
[0x1b8];
261 partition_t partition
[4];
265 typedef struct direntry_t
{
267 uint8_t extension
[3];
278 } QEMU_PACKED direntry_t
;
280 /* this structure are used to transparently access the files */
282 typedef struct mapping_t
{
283 /* begin is the first cluster, end is the last+1 */
285 /* as s->directory is growable, no pointer may be used here */
286 unsigned int dir_index
;
287 /* the clusters of a file may be in any order; this points to the first */
288 int first_mapping_index
;
291 * - the offset in the file (in clusters) for a file, or
292 * - the next cluster of the directory for a directory, and
293 * - the address of the buffer for a faked entry
299 int parent_mapping_index
;
303 /* path contains the full path, i.e. it always starts with s->path */
306 enum { MODE_UNDEFINED
= 0, MODE_NORMAL
= 1, MODE_MODIFIED
= 2,
307 MODE_DIRECTORY
= 4, MODE_FAKED
= 8,
308 MODE_DELETED
= 16, MODE_RENAMED
= 32 } mode
;
313 static void print_direntry(const struct direntry_t
*);
314 static void print_mapping(const struct mapping_t
* mapping
);
317 /* here begins the real VVFAT driver */
319 typedef struct BDRVVVFATState
{
320 BlockDriverState
* bs
; /* pointer to parent */
321 unsigned int first_sectors_number
; /* 1 for a single partition, 0x40 for a disk with partition table */
322 unsigned char first_sectors
[0x40*0x200];
324 int fat_type
; /* 16 or 32 */
325 array_t fat
,directory
,mapping
;
327 unsigned int cluster_size
;
328 unsigned int sectors_per_cluster
;
329 unsigned int sectors_per_fat
;
330 unsigned int sectors_of_root_directory
;
331 uint32_t last_cluster_of_root_directory
;
332 unsigned int faked_sectors
; /* how many sectors are faked before file data */
333 uint32_t sector_count
; /* total number of sectors of the partition */
334 uint32_t cluster_count
; /* total number of clusters of this partition */
335 uint32_t max_fat_value
;
338 mapping_t
* current_mapping
;
339 unsigned char* cluster
; /* points to current cluster */
340 unsigned char* cluster_buffer
; /* points to a buffer to hold temp data */
341 unsigned int current_cluster
;
344 BlockDriverState
* write_target
;
346 BlockDriverState
* qcow
;
351 int downcase_short_names
;
354 /* take the sector position spos and convert it to Cylinder/Head/Sector position
355 * if the position is outside the specified geometry, fill maximum value for CHS
356 * and return 1 to signal overflow.
358 static int sector2CHS(BlockDriverState
* bs
, mbr_chs_t
* chs
, int spos
){
360 sector
= spos
% (bs
->secs
); spos
/= bs
->secs
;
361 head
= spos
% (bs
->heads
); spos
/= bs
->heads
;
362 if(spos
>= bs
->cyls
){
364 it happens if 32bit sector positions are used, while CHS is only 24bit.
365 Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
368 chs
->cylinder
= 0xFF;
371 chs
->head
= (uint8_t)head
;
372 chs
->sector
= (uint8_t)( (sector
+1) | ((spos
>>8)<<6) );
373 chs
->cylinder
= (uint8_t)spos
;
377 static void init_mbr(BDRVVVFATState
* s
)
379 /* TODO: if the files mbr.img and bootsect.img exist, use them */
380 mbr_t
* real_mbr
=(mbr_t
*)s
->first_sectors
;
381 partition_t
* partition
= &(real_mbr
->partition
[0]);
384 memset(s
->first_sectors
,0,512);
386 /* Win NT Disk Signature */
387 real_mbr
->nt_id
= cpu_to_le32(0xbe1afdfa);
389 partition
->attributes
=0x80; /* bootable */
391 /* LBA is used when partition is outside the CHS geometry */
392 lba
= sector2CHS(s
->bs
, &partition
->start_CHS
, s
->first_sectors_number
-1);
393 lba
|= sector2CHS(s
->bs
, &partition
->end_CHS
, s
->sector_count
);
395 /*LBA partitions are identified only by start/length_sector_long not by CHS*/
396 partition
->start_sector_long
=cpu_to_le32(s
->first_sectors_number
-1);
397 partition
->length_sector_long
=cpu_to_le32(s
->sector_count
- s
->first_sectors_number
+1);
399 /* FAT12/FAT16/FAT32 */
400 /* DOS uses different types when partition is LBA,
401 probably to prevent older versions from using CHS on them */
402 partition
->fs_type
= s
->fat_type
==12 ? 0x1:
403 s
->fat_type
==16 ? (lba
?0xe:0x06):
404 /*fat_tyoe==32*/ (lba
?0xc:0x0b);
406 real_mbr
->magic
[0]=0x55; real_mbr
->magic
[1]=0xaa;
409 /* direntry functions */
411 /* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
412 static inline int short2long_name(char* dest
,const char* src
)
416 for(i
=0;i
<129 && src
[i
];i
++) {
421 dest
[2*i
]=dest
[2*i
+1]=0;
422 for(i
=2*i
+2;(i
%26);i
++)
427 static inline direntry_t
* create_long_filename(BDRVVVFATState
* s
,const char* filename
)
430 int length
=short2long_name(buffer
,filename
),
431 number_of_entries
=(length
+25)/26,i
;
434 for(i
=0;i
<number_of_entries
;i
++) {
435 entry
=array_get_next(&(s
->directory
));
436 entry
->attributes
=0xf;
437 entry
->reserved
[0]=0;
439 entry
->name
[0]=(number_of_entries
-i
)|(i
==0?0x40:0);
441 for(i
=0;i
<26*number_of_entries
;i
++) {
443 if(offset
<10) offset
=1+offset
;
444 else if(offset
<22) offset
=14+offset
-10;
445 else offset
=28+offset
-22;
446 entry
=array_get(&(s
->directory
),s
->directory
.next
-1-(i
/26));
447 entry
->name
[offset
]=buffer
[i
];
449 return array_get(&(s
->directory
),s
->directory
.next
-number_of_entries
);
452 static char is_free(const direntry_t
* direntry
)
454 return direntry
->name
[0]==0xe5 || direntry
->name
[0]==0x00;
457 static char is_volume_label(const direntry_t
* direntry
)
459 return direntry
->attributes
== 0x28;
462 static char is_long_name(const direntry_t
* direntry
)
464 return direntry
->attributes
== 0xf;
467 static char is_short_name(const direntry_t
* direntry
)
469 return !is_volume_label(direntry
) && !is_long_name(direntry
)
470 && !is_free(direntry
);
473 static char is_directory(const direntry_t
* direntry
)
475 return direntry
->attributes
& 0x10 && direntry
->name
[0] != 0xe5;
478 static inline char is_dot(const direntry_t
* direntry
)
480 return is_short_name(direntry
) && direntry
->name
[0] == '.';
483 static char is_file(const direntry_t
* direntry
)
485 return is_short_name(direntry
) && !is_directory(direntry
);
488 static inline uint32_t begin_of_direntry(const direntry_t
* direntry
)
490 return le16_to_cpu(direntry
->begin
)|(le16_to_cpu(direntry
->begin_hi
)<<16);
493 static inline uint32_t filesize_of_direntry(const direntry_t
* direntry
)
495 return le32_to_cpu(direntry
->size
);
498 static void set_begin_of_direntry(direntry_t
* direntry
, uint32_t begin
)
500 direntry
->begin
= cpu_to_le16(begin
& 0xffff);
501 direntry
->begin_hi
= cpu_to_le16((begin
>> 16) & 0xffff);
506 static inline uint8_t fat_chksum(const direntry_t
* entry
)
514 c
= (i
< 8) ? entry
->name
[i
] : entry
->extension
[i
-8];
515 chksum
=(((chksum
&0xfe)>>1)|((chksum
&0x01)?0x80:0)) + c
;
521 /* if return_time==0, this returns the fat_date, else the fat_time */
522 static uint16_t fat_datetime(time_t time
,int return_time
) {
525 t
=localtime(&time
); /* this is not thread safe */
529 localtime_r(&time
,t
);
532 return cpu_to_le16((t
->tm_sec
/2)|(t
->tm_min
<<5)|(t
->tm_hour
<<11));
533 return cpu_to_le16((t
->tm_mday
)|((t
->tm_mon
+1)<<5)|((t
->tm_year
-80)<<9));
536 static inline void fat_set(BDRVVVFATState
* s
,unsigned int cluster
,uint32_t value
)
538 if(s
->fat_type
==32) {
539 uint32_t* entry
=array_get(&(s
->fat
),cluster
);
540 *entry
=cpu_to_le32(value
);
541 } else if(s
->fat_type
==16) {
542 uint16_t* entry
=array_get(&(s
->fat
),cluster
);
543 *entry
=cpu_to_le16(value
&0xffff);
545 int offset
= (cluster
*3/2);
546 unsigned char* p
= array_get(&(s
->fat
), offset
);
550 p
[1] = (p
[1]&0xf0) | ((value
>>8)&0xf);
553 p
[0] = (p
[0]&0xf) | ((value
&0xf)<<4);
560 static inline uint32_t fat_get(BDRVVVFATState
* s
,unsigned int cluster
)
562 if(s
->fat_type
==32) {
563 uint32_t* entry
=array_get(&(s
->fat
),cluster
);
564 return le32_to_cpu(*entry
);
565 } else if(s
->fat_type
==16) {
566 uint16_t* entry
=array_get(&(s
->fat
),cluster
);
567 return le16_to_cpu(*entry
);
569 const uint8_t* x
=(uint8_t*)(s
->fat
.pointer
)+cluster
*3/2;
570 return ((x
[0]|(x
[1]<<8))>>(cluster
&1?4:0))&0x0fff;
574 static inline int fat_eof(BDRVVVFATState
* s
,uint32_t fat_entry
)
576 if(fat_entry
>s
->max_fat_value
-8)
581 static inline void init_fat(BDRVVVFATState
* s
)
583 if (s
->fat_type
== 12) {
584 array_init(&(s
->fat
),1);
585 array_ensure_allocated(&(s
->fat
),
586 s
->sectors_per_fat
* 0x200 * 3 / 2 - 1);
588 array_init(&(s
->fat
),(s
->fat_type
==32?4:2));
589 array_ensure_allocated(&(s
->fat
),
590 s
->sectors_per_fat
* 0x200 / s
->fat
.item_size
- 1);
592 memset(s
->fat
.pointer
,0,s
->fat
.size
);
594 switch(s
->fat_type
) {
595 case 12: s
->max_fat_value
=0xfff; break;
596 case 16: s
->max_fat_value
=0xffff; break;
597 case 32: s
->max_fat_value
=0x0fffffff; break;
598 default: s
->max_fat_value
=0; /* error... */
603 /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
604 /* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
605 static inline direntry_t
* create_short_and_long_name(BDRVVVFATState
* s
,
606 unsigned int directory_start
, const char* filename
, int is_dot
)
608 int i
,j
,long_index
=s
->directory
.next
;
609 direntry_t
* entry
= NULL
;
610 direntry_t
* entry_long
= NULL
;
613 entry
=array_get_next(&(s
->directory
));
614 memset(entry
->name
,0x20,11);
615 memcpy(entry
->name
,filename
,strlen(filename
));
619 entry_long
=create_long_filename(s
,filename
);
621 i
= strlen(filename
);
622 for(j
= i
- 1; j
>0 && filename
[j
]!='.';j
--);
628 entry
=array_get_next(&(s
->directory
));
629 memset(entry
->name
,0x20,11);
630 memcpy(entry
->name
, filename
, i
);
633 for (i
= 0; i
< 3 && filename
[j
+1+i
]; i
++)
634 entry
->extension
[i
] = filename
[j
+1+i
];
636 /* upcase & remove unwanted characters */
638 if(i
==10 || i
==7) for(;i
>0 && entry
->name
[i
]==' ';i
--);
639 if(entry
->name
[i
]<=' ' || entry
->name
[i
]>0x7f
640 || strchr(".*?<>|\":/\\[];,+='",entry
->name
[i
]))
642 else if(entry
->name
[i
]>='a' && entry
->name
[i
]<='z')
643 entry
->name
[i
]+='A'-'a';
646 /* mangle duplicates */
648 direntry_t
* entry1
=array_get(&(s
->directory
),directory_start
);
651 for(;entry1
<entry
;entry1
++)
652 if(!is_long_name(entry1
) && !memcmp(entry1
->name
,entry
->name
,11))
653 break; /* found dupe */
654 if(entry1
==entry
) /* no dupe found */
657 /* use all 8 characters of name */
658 if(entry
->name
[7]==' ') {
660 for(j
=6;j
>0 && entry
->name
[j
]==' ';j
--)
664 /* increment number */
665 for(j
=7;j
>0 && entry
->name
[j
]=='9';j
--)
668 if(entry
->name
[j
]<'0' || entry
->name
[j
]>'9')
675 /* calculate checksum; propagate to long name */
677 uint8_t chksum
=fat_chksum(entry
);
679 /* calculate anew, because realloc could have taken place */
680 entry_long
=array_get(&(s
->directory
),long_index
);
681 while(entry_long
<entry
&& is_long_name(entry_long
)) {
682 entry_long
->reserved
[1]=chksum
;
691 * Read a directory. (the index of the corresponding mapping must be passed).
693 static int read_directory(BDRVVVFATState
* s
, int mapping_index
)
695 mapping_t
* mapping
= array_get(&(s
->mapping
), mapping_index
);
696 direntry_t
* direntry
;
697 const char* dirname
= mapping
->path
;
698 int first_cluster
= mapping
->begin
;
699 int parent_index
= mapping
->info
.dir
.parent_mapping_index
;
700 mapping_t
* parent_mapping
= (mapping_t
*)
701 (parent_index
>= 0 ? array_get(&(s
->mapping
), parent_index
) : NULL
);
702 int first_cluster_of_parent
= parent_mapping
? parent_mapping
->begin
: -1;
704 DIR* dir
=opendir(dirname
);
705 struct dirent
* entry
;
708 assert(mapping
->mode
& MODE_DIRECTORY
);
711 mapping
->end
= mapping
->begin
;
715 i
= mapping
->info
.dir
.first_dir_index
=
716 first_cluster
== 0 ? 0 : s
->directory
.next
;
718 /* actually read the directory, and allocate the mappings */
719 while((entry
=readdir(dir
))) {
720 unsigned int length
=strlen(dirname
)+2+strlen(entry
->d_name
);
722 direntry_t
* direntry
;
724 int is_dot
=!strcmp(entry
->d_name
,".");
725 int is_dotdot
=!strcmp(entry
->d_name
,"..");
727 if(first_cluster
== 0 && (is_dotdot
|| is_dot
))
730 buffer
=(char*)g_malloc(length
);
731 snprintf(buffer
,length
,"%s/%s",dirname
,entry
->d_name
);
733 if(stat(buffer
,&st
)<0) {
738 /* create directory entry for this file */
739 direntry
=create_short_and_long_name(s
, i
, entry
->d_name
,
740 is_dot
|| is_dotdot
);
741 direntry
->attributes
=(S_ISDIR(st
.st_mode
)?0x10:0x20);
742 direntry
->reserved
[0]=direntry
->reserved
[1]=0;
743 direntry
->ctime
=fat_datetime(st
.st_ctime
,1);
744 direntry
->cdate
=fat_datetime(st
.st_ctime
,0);
745 direntry
->adate
=fat_datetime(st
.st_atime
,0);
746 direntry
->begin_hi
=0;
747 direntry
->mtime
=fat_datetime(st
.st_mtime
,1);
748 direntry
->mdate
=fat_datetime(st
.st_mtime
,0);
750 set_begin_of_direntry(direntry
, first_cluster_of_parent
);
752 set_begin_of_direntry(direntry
, first_cluster
);
754 direntry
->begin
=0; /* do that later */
755 if (st
.st_size
> 0x7fffffff) {
756 fprintf(stderr
, "File %s is larger than 2GB\n", buffer
);
761 direntry
->size
=cpu_to_le32(S_ISDIR(st
.st_mode
)?0:st
.st_size
);
763 /* create mapping for this file */
764 if(!is_dot
&& !is_dotdot
&& (S_ISDIR(st
.st_mode
) || st
.st_size
)) {
765 s
->current_mapping
=(mapping_t
*)array_get_next(&(s
->mapping
));
766 s
->current_mapping
->begin
=0;
767 s
->current_mapping
->end
=st
.st_size
;
769 * we get the direntry of the most recent direntry, which
770 * contains the short name and all the relevant information.
772 s
->current_mapping
->dir_index
=s
->directory
.next
-1;
773 s
->current_mapping
->first_mapping_index
= -1;
774 if (S_ISDIR(st
.st_mode
)) {
775 s
->current_mapping
->mode
= MODE_DIRECTORY
;
776 s
->current_mapping
->info
.dir
.parent_mapping_index
=
779 s
->current_mapping
->mode
= MODE_UNDEFINED
;
780 s
->current_mapping
->info
.file
.offset
= 0;
782 s
->current_mapping
->path
=buffer
;
783 s
->current_mapping
->read_only
=
784 (st
.st_mode
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) == 0;
789 /* fill with zeroes up to the end of the cluster */
790 while(s
->directory
.next
%(0x10*s
->sectors_per_cluster
)) {
791 direntry_t
* direntry
=array_get_next(&(s
->directory
));
792 memset(direntry
,0,sizeof(direntry_t
));
795 /* TODO: if there are more entries, bootsector has to be adjusted! */
796 #define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
797 if (mapping_index
== 0 && s
->directory
.next
< ROOT_ENTRIES
) {
799 int cur
= s
->directory
.next
;
800 array_ensure_allocated(&(s
->directory
), ROOT_ENTRIES
- 1);
801 memset(array_get(&(s
->directory
), cur
), 0,
802 (ROOT_ENTRIES
- cur
) * sizeof(direntry_t
));
805 /* reget the mapping, since s->mapping was possibly realloc()ed */
806 mapping
= (mapping_t
*)array_get(&(s
->mapping
), mapping_index
);
807 first_cluster
+= (s
->directory
.next
- mapping
->info
.dir
.first_dir_index
)
808 * 0x20 / s
->cluster_size
;
809 mapping
->end
= first_cluster
;
811 direntry
= (direntry_t
*)array_get(&(s
->directory
), mapping
->dir_index
);
812 set_begin_of_direntry(direntry
, mapping
->begin
);
817 static inline uint32_t sector2cluster(BDRVVVFATState
* s
,off_t sector_num
)
819 return (sector_num
-s
->faked_sectors
)/s
->sectors_per_cluster
;
822 static inline off_t
cluster2sector(BDRVVVFATState
* s
, uint32_t cluster_num
)
824 return s
->faked_sectors
+ s
->sectors_per_cluster
* cluster_num
;
827 static int init_directories(BDRVVVFATState
* s
,
830 bootsector_t
* bootsector
;
833 unsigned int cluster
;
835 memset(&(s
->first_sectors
[0]),0,0x40*0x200);
837 s
->cluster_size
=s
->sectors_per_cluster
*0x200;
838 s
->cluster_buffer
=g_malloc(s
->cluster_size
);
841 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
842 * where sc is sector_count,
843 * spf is sectors_per_fat,
844 * spc is sectors_per_clusters, and
845 * fat_type = 12, 16 or 32.
847 i
= 1+s
->sectors_per_cluster
*0x200*8/s
->fat_type
;
848 s
->sectors_per_fat
=(s
->sector_count
+i
)/i
; /* round up */
850 array_init(&(s
->mapping
),sizeof(mapping_t
));
851 array_init(&(s
->directory
),sizeof(direntry_t
));
853 /* add volume label */
855 direntry_t
* entry
=array_get_next(&(s
->directory
));
856 entry
->attributes
=0x28; /* archive | volume label */
857 memcpy(entry
->name
,"QEMU VVF",8);
858 memcpy(entry
->extension
,"AT ",3);
861 /* Now build FAT, and write back information into directory */
864 s
->faked_sectors
=s
->first_sectors_number
+s
->sectors_per_fat
*2;
865 s
->cluster_count
=sector2cluster(s
, s
->sector_count
);
867 mapping
= array_get_next(&(s
->mapping
));
869 mapping
->dir_index
= 0;
870 mapping
->info
.dir
.parent_mapping_index
= -1;
871 mapping
->first_mapping_index
= -1;
872 mapping
->path
= g_strdup(dirname
);
873 i
= strlen(mapping
->path
);
874 if (i
> 0 && mapping
->path
[i
- 1] == '/')
875 mapping
->path
[i
- 1] = '\0';
876 mapping
->mode
= MODE_DIRECTORY
;
877 mapping
->read_only
= 0;
878 s
->path
= mapping
->path
;
880 for (i
= 0, cluster
= 0; i
< s
->mapping
.next
; i
++) {
881 /* MS-DOS expects the FAT to be 0 for the root directory
882 * (except for the media byte). */
883 /* LATER TODO: still true for FAT32? */
884 int fix_fat
= (i
!= 0);
885 mapping
= array_get(&(s
->mapping
), i
);
887 if (mapping
->mode
& MODE_DIRECTORY
) {
888 mapping
->begin
= cluster
;
889 if(read_directory(s
, i
)) {
890 fprintf(stderr
, "Could not read directory %s\n",
894 mapping
= array_get(&(s
->mapping
), i
);
896 assert(mapping
->mode
== MODE_UNDEFINED
);
897 mapping
->mode
=MODE_NORMAL
;
898 mapping
->begin
= cluster
;
899 if (mapping
->end
> 0) {
900 direntry_t
* direntry
= array_get(&(s
->directory
),
903 mapping
->end
= cluster
+ 1 + (mapping
->end
-1)/s
->cluster_size
;
904 set_begin_of_direntry(direntry
, mapping
->begin
);
906 mapping
->end
= cluster
+ 1;
911 assert(mapping
->begin
< mapping
->end
);
913 /* next free cluster */
914 cluster
= mapping
->end
;
916 if(cluster
> s
->cluster_count
) {
917 fprintf(stderr
,"Directory does not fit in FAT%d (capacity %s)\n",
919 s
->fat_type
== 12 ? s
->sector_count
== 2880 ? "1.44 MB"
925 /* 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
);
934 mapping
= array_get(&(s
->mapping
), 0);
935 s
->sectors_of_root_directory
= mapping
->end
* s
->sectors_per_cluster
;
936 s
->last_cluster_of_root_directory
= mapping
->end
;
938 /* the FAT signature */
939 fat_set(s
,0,s
->max_fat_value
);
940 fat_set(s
,1,s
->max_fat_value
);
942 s
->current_mapping
= NULL
;
944 bootsector
=(bootsector_t
*)(s
->first_sectors
+(s
->first_sectors_number
-1)*0x200);
945 bootsector
->jump
[0]=0xeb;
946 bootsector
->jump
[1]=0x3e;
947 bootsector
->jump
[2]=0x90;
948 memcpy(bootsector
->name
,"QEMU ",8);
949 bootsector
->sector_size
=cpu_to_le16(0x200);
950 bootsector
->sectors_per_cluster
=s
->sectors_per_cluster
;
951 bootsector
->reserved_sectors
=cpu_to_le16(1);
952 bootsector
->number_of_fats
=0x2; /* number of FATs */
953 bootsector
->root_entries
=cpu_to_le16(s
->sectors_of_root_directory
*0x10);
954 bootsector
->total_sectors16
=s
->sector_count
>0xffff?0:cpu_to_le16(s
->sector_count
);
955 bootsector
->media_type
=(s
->fat_type
!=12?0xf8:s
->sector_count
==5760?0xf9:0xf8); /* media descriptor */
956 s
->fat
.pointer
[0] = bootsector
->media_type
;
957 bootsector
->sectors_per_fat
=cpu_to_le16(s
->sectors_per_fat
);
958 bootsector
->sectors_per_track
=cpu_to_le16(s
->bs
->secs
);
959 bootsector
->number_of_heads
=cpu_to_le16(s
->bs
->heads
);
960 bootsector
->hidden_sectors
=cpu_to_le32(s
->first_sectors_number
==1?0:0x3f);
961 bootsector
->total_sectors
=cpu_to_le32(s
->sector_count
>0xffff?s
->sector_count
:0);
963 /* LATER TODO: if FAT32, this is wrong */
964 bootsector
->u
.fat16
.drive_number
=s
->fat_type
==12?0:0x80; /* assume this is hda (TODO) */
965 bootsector
->u
.fat16
.current_head
=0;
966 bootsector
->u
.fat16
.signature
=0x29;
967 bootsector
->u
.fat16
.id
=cpu_to_le32(0xfabe1afd);
969 memcpy(bootsector
->u
.fat16
.volume_label
,"QEMU VVFAT ",11);
970 memcpy(bootsector
->fat_type
,(s
->fat_type
==12?"FAT12 ":s
->fat_type
==16?"FAT16 ":"FAT32 "),8);
971 bootsector
->magic
[0]=0x55; bootsector
->magic
[1]=0xaa;
977 static BDRVVVFATState
*vvv
= NULL
;
980 static int enable_write_target(BDRVVVFATState
*s
);
981 static int is_consistent(BDRVVVFATState
*s
);
983 static int vvfat_open(BlockDriverState
*bs
, const char* dirname
, int flags
)
985 BDRVVVFATState
*s
= bs
->opaque
;
993 DLOG(if (stderr
== NULL
) {
994 stderr
= fopen("vvfat.log", "a");
995 setbuf(stderr
, NULL
);
1001 /* LATER TODO: if FAT32, adjust */
1002 s
->sectors_per_cluster
=0x10;
1004 bs
->cyls
=1024; bs
->heads
=16; bs
->secs
=63;
1006 s
->current_cluster
=0xffffffff;
1008 s
->first_sectors_number
=0x40;
1009 /* read only is the default for safety */
1011 s
->qcow
= s
->write_target
= NULL
;
1012 s
->qcow_filename
= NULL
;
1014 s
->downcase_short_names
= 1;
1016 if (!strstart(dirname
, "fat:", NULL
))
1019 if (strstr(dirname
, ":floppy:")) {
1022 s
->first_sectors_number
= 1;
1023 s
->sectors_per_cluster
=2;
1024 bs
->cyls
= 80; bs
->heads
= 2; bs
->secs
= 36;
1027 s
->sector_count
=bs
->cyls
*bs
->heads
*bs
->secs
;
1029 if (strstr(dirname
, ":32:")) {
1030 fprintf(stderr
, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1032 } else if (strstr(dirname
, ":16:")) {
1034 } else if (strstr(dirname
, ":12:")) {
1036 s
->sector_count
=2880;
1039 if (strstr(dirname
, ":rw:")) {
1040 if (enable_write_target(s
))
1045 i
= strrchr(dirname
, ':') - dirname
;
1047 if (dirname
[i
-2] == ':' && qemu_isalpha(dirname
[i
-1]))
1048 /* workaround for DOS drive names */
1053 bs
->total_sectors
=bs
->cyls
*bs
->heads
*bs
->secs
;
1055 if(init_directories(s
, dirname
))
1058 s
->sector_count
= s
->faked_sectors
+ s
->sectors_per_cluster
*s
->cluster_count
;
1060 if(s
->first_sectors_number
==0x40)
1063 /* for some reason or other, MS-DOS does not like to know about CHS... */
1065 bs
->heads
= bs
->cyls
= bs
->secs
= 0;
1067 // assert(is_consistent(s));
1071 static inline void vvfat_close_current_file(BDRVVVFATState
*s
)
1073 if(s
->current_mapping
) {
1074 s
->current_mapping
= NULL
;
1075 if (s
->current_fd
) {
1076 close(s
->current_fd
);
1080 s
->current_cluster
= -1;
1083 /* mappings between index1 and index2-1 are supposed to be ordered
1084 * return value is the index of the last mapping for which end>cluster_num
1086 static inline int find_mapping_for_cluster_aux(BDRVVVFATState
* s
,int cluster_num
,int index1
,int index2
)
1091 index3
=(index1
+index2
)/2;
1092 mapping
=array_get(&(s
->mapping
),index3
);
1093 assert(mapping
->begin
< mapping
->end
);
1094 if(mapping
->begin
>=cluster_num
) {
1095 assert(index2
!=index3
|| index2
==0);
1101 return mapping
->end
<=cluster_num
? index2
: index1
;
1104 assert(index1
<=index2
);
1105 DLOG(mapping
=array_get(&(s
->mapping
),index1
);
1106 assert(mapping
->begin
<=cluster_num
);
1107 assert(index2
>= s
->mapping
.next
||
1108 ((mapping
= array_get(&(s
->mapping
),index2
)) &&
1109 mapping
->end
>cluster_num
)));
1113 static inline mapping_t
* find_mapping_for_cluster(BDRVVVFATState
* s
,int cluster_num
)
1115 int index
=find_mapping_for_cluster_aux(s
,cluster_num
,0,s
->mapping
.next
);
1117 if(index
>=s
->mapping
.next
)
1119 mapping
=array_get(&(s
->mapping
),index
);
1120 if(mapping
->begin
>cluster_num
)
1122 assert(mapping
->begin
<=cluster_num
&& mapping
->end
>cluster_num
);
1126 static int open_file(BDRVVVFATState
* s
,mapping_t
* mapping
)
1130 if(!s
->current_mapping
||
1131 strcmp(s
->current_mapping
->path
,mapping
->path
)) {
1133 int fd
= open(mapping
->path
, O_RDONLY
| O_BINARY
| O_LARGEFILE
);
1136 vvfat_close_current_file(s
);
1138 s
->current_mapping
= mapping
;
1143 static inline int read_cluster(BDRVVVFATState
*s
,int cluster_num
)
1145 if(s
->current_cluster
!= cluster_num
) {
1148 assert(!s
->current_mapping
|| s
->current_fd
|| (s
->current_mapping
->mode
& MODE_DIRECTORY
));
1149 if(!s
->current_mapping
1150 || s
->current_mapping
->begin
>cluster_num
1151 || s
->current_mapping
->end
<=cluster_num
) {
1152 /* binary search of mappings for file */
1153 mapping_t
* mapping
=find_mapping_for_cluster(s
,cluster_num
);
1155 assert(!mapping
|| (cluster_num
>=mapping
->begin
&& cluster_num
<mapping
->end
));
1157 if (mapping
&& mapping
->mode
& MODE_DIRECTORY
) {
1158 vvfat_close_current_file(s
);
1159 s
->current_mapping
= mapping
;
1160 read_cluster_directory
:
1161 offset
= s
->cluster_size
*(cluster_num
-s
->current_mapping
->begin
);
1162 s
->cluster
= (unsigned char*)s
->directory
.pointer
+offset
1163 + 0x20*s
->current_mapping
->info
.dir
.first_dir_index
;
1164 assert(((s
->cluster
-(unsigned char*)s
->directory
.pointer
)%s
->cluster_size
)==0);
1165 assert((char*)s
->cluster
+s
->cluster_size
<= s
->directory
.pointer
+s
->directory
.next
*s
->directory
.item_size
);
1166 s
->current_cluster
= cluster_num
;
1170 if(open_file(s
,mapping
))
1172 } else if (s
->current_mapping
->mode
& MODE_DIRECTORY
)
1173 goto read_cluster_directory
;
1175 assert(s
->current_fd
);
1177 offset
=s
->cluster_size
*(cluster_num
-s
->current_mapping
->begin
)+s
->current_mapping
->info
.file
.offset
;
1178 if(lseek(s
->current_fd
, offset
, SEEK_SET
)!=offset
)
1180 s
->cluster
=s
->cluster_buffer
;
1181 result
=read(s
->current_fd
,s
->cluster
,s
->cluster_size
);
1183 s
->current_cluster
= -1;
1186 s
->current_cluster
= cluster_num
;
1192 static void print_direntry(const direntry_t
* direntry
)
1197 fprintf(stderr
, "direntry %p: ", direntry
);
1200 if(is_long_name(direntry
)) {
1201 unsigned char* c
=(unsigned char*)direntry
;
1203 for(i
=1;i
<11 && c
[i
] && c
[i
]!=0xff;i
+=2)
1204 #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
1206 for(i
=14;i
<26 && c
[i
] && c
[i
]!=0xff;i
+=2)
1208 for(i
=28;i
<32 && c
[i
] && c
[i
]!=0xff;i
+=2)
1211 fprintf(stderr
, "%s\n", buffer
);
1215 ADD_CHAR(direntry
->name
[i
]);
1217 fprintf(stderr
,"%s attributes=0x%02x begin=%d size=%d\n",
1219 direntry
->attributes
,
1220 begin_of_direntry(direntry
),le32_to_cpu(direntry
->size
));
1224 static void print_mapping(const mapping_t
* mapping
)
1226 fprintf(stderr
, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1227 "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1228 mapping
, mapping
->begin
, mapping
->end
, mapping
->dir_index
,
1229 mapping
->first_mapping_index
, mapping
->path
, mapping
->mode
);
1231 if (mapping
->mode
& MODE_DIRECTORY
)
1232 fprintf(stderr
, "parent_mapping_index = %d, first_dir_index = %d\n", mapping
->info
.dir
.parent_mapping_index
, mapping
->info
.dir
.first_dir_index
);
1234 fprintf(stderr
, "offset = %d\n", mapping
->info
.file
.offset
);
1238 static int vvfat_read(BlockDriverState
*bs
, int64_t sector_num
,
1239 uint8_t *buf
, int nb_sectors
)
1241 BDRVVVFATState
*s
= bs
->opaque
;
1244 for(i
=0;i
<nb_sectors
;i
++,sector_num
++) {
1245 if (sector_num
>= s
->sector_count
)
1249 if (s
->qcow
->drv
->bdrv_is_allocated(s
->qcow
,
1250 sector_num
, nb_sectors
-i
, &n
)) {
1251 DLOG(fprintf(stderr
, "sectors %d+%d allocated\n", (int)sector_num
, n
));
1252 if (s
->qcow
->drv
->bdrv_read(s
->qcow
, sector_num
, buf
+i
*0x200, n
))
1255 sector_num
+= n
- 1;
1258 DLOG(fprintf(stderr
, "sector %d not allocated\n", (int)sector_num
));
1260 if(sector_num
<s
->faked_sectors
) {
1261 if(sector_num
<s
->first_sectors_number
)
1262 memcpy(buf
+i
*0x200,&(s
->first_sectors
[sector_num
*0x200]),0x200);
1263 else if(sector_num
-s
->first_sectors_number
<s
->sectors_per_fat
)
1264 memcpy(buf
+i
*0x200,&(s
->fat
.pointer
[(sector_num
-s
->first_sectors_number
)*0x200]),0x200);
1265 else if(sector_num
-s
->first_sectors_number
-s
->sectors_per_fat
<s
->sectors_per_fat
)
1266 memcpy(buf
+i
*0x200,&(s
->fat
.pointer
[(sector_num
-s
->first_sectors_number
-s
->sectors_per_fat
)*0x200]),0x200);
1268 uint32_t sector
=sector_num
-s
->faked_sectors
,
1269 sector_offset_in_cluster
=(sector
%s
->sectors_per_cluster
),
1270 cluster_num
=sector
/s
->sectors_per_cluster
;
1271 if(read_cluster(s
, cluster_num
) != 0) {
1272 /* LATER TODO: strict: return -1; */
1273 memset(buf
+i
*0x200,0,0x200);
1276 memcpy(buf
+i
*0x200,s
->cluster
+sector_offset_in_cluster
*0x200,0x200);
1282 /* LATER TODO: statify all functions */
1285 * Idea of the write support (use snapshot):
1287 * 1. check if all data is consistent, recording renames, modifications,
1288 * new files and directories (in s->commits).
1290 * 2. if the data is not consistent, stop committing
1292 * 3. handle renames, and create new files and directories (do not yet
1293 * write their contents)
1295 * 4. walk the directories, fixing the mapping and direntries, and marking
1296 * the handled mappings as not deleted
1298 * 5. commit the contents of the files
1300 * 6. handle deleted files and directories
1304 typedef struct commit_t
{
1307 struct { uint32_t cluster
; } rename
;
1308 struct { int dir_index
; uint32_t modified_offset
; } writeout
;
1309 struct { uint32_t first_cluster
; } new_file
;
1310 struct { uint32_t cluster
; } mkdir
;
1312 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1314 ACTION_RENAME
, ACTION_WRITEOUT
, ACTION_NEW_FILE
, ACTION_MKDIR
1318 static void clear_commits(BDRVVVFATState
* s
)
1321 DLOG(fprintf(stderr
, "clear_commits (%d commits)\n", s
->commits
.next
));
1322 for (i
= 0; i
< s
->commits
.next
; i
++) {
1323 commit_t
* commit
= array_get(&(s
->commits
), i
);
1324 assert(commit
->path
|| commit
->action
== ACTION_WRITEOUT
);
1325 if (commit
->action
!= ACTION_WRITEOUT
) {
1326 assert(commit
->path
);
1327 g_free(commit
->path
);
1329 assert(commit
->path
== NULL
);
1331 s
->commits
.next
= 0;
1334 static void schedule_rename(BDRVVVFATState
* s
,
1335 uint32_t cluster
, char* new_path
)
1337 commit_t
* commit
= array_get_next(&(s
->commits
));
1338 commit
->path
= new_path
;
1339 commit
->param
.rename
.cluster
= cluster
;
1340 commit
->action
= ACTION_RENAME
;
1343 static void schedule_writeout(BDRVVVFATState
* s
,
1344 int dir_index
, uint32_t modified_offset
)
1346 commit_t
* commit
= array_get_next(&(s
->commits
));
1347 commit
->path
= NULL
;
1348 commit
->param
.writeout
.dir_index
= dir_index
;
1349 commit
->param
.writeout
.modified_offset
= modified_offset
;
1350 commit
->action
= ACTION_WRITEOUT
;
1353 static void schedule_new_file(BDRVVVFATState
* s
,
1354 char* path
, uint32_t first_cluster
)
1356 commit_t
* commit
= array_get_next(&(s
->commits
));
1357 commit
->path
= path
;
1358 commit
->param
.new_file
.first_cluster
= first_cluster
;
1359 commit
->action
= ACTION_NEW_FILE
;
1362 static void schedule_mkdir(BDRVVVFATState
* s
, uint32_t cluster
, char* path
)
1364 commit_t
* commit
= array_get_next(&(s
->commits
));
1365 commit
->path
= path
;
1366 commit
->param
.mkdir
.cluster
= cluster
;
1367 commit
->action
= ACTION_MKDIR
;
1372 * Since the sequence number is at most 0x3f, and the filename
1373 * length is at most 13 times the sequence number, the maximal
1374 * filename length is 0x3f * 13 bytes.
1376 unsigned char name
[0x3f * 13 + 1];
1378 int sequence_number
;
1381 static void lfn_init(long_file_name
* lfn
)
1383 lfn
->sequence_number
= lfn
->len
= 0;
1384 lfn
->checksum
= 0x100;
1387 /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1388 static int parse_long_name(long_file_name
* lfn
,
1389 const direntry_t
* direntry
)
1392 const unsigned char* pointer
= (const unsigned char*)direntry
;
1394 if (!is_long_name(direntry
))
1397 if (pointer
[0] & 0x40) {
1398 lfn
->sequence_number
= pointer
[0] & 0x3f;
1399 lfn
->checksum
= pointer
[13];
1401 lfn
->name
[lfn
->sequence_number
* 13] = 0;
1402 } else if ((pointer
[0] & 0x3f) != --lfn
->sequence_number
)
1404 else if (pointer
[13] != lfn
->checksum
)
1406 else if (pointer
[12] || pointer
[26] || pointer
[27])
1409 offset
= 13 * (lfn
->sequence_number
- 1);
1410 for (i
= 0, j
= 1; i
< 13; i
++, j
+=2) {
1416 if (pointer
[j
+1] == 0)
1417 lfn
->name
[offset
+ i
] = pointer
[j
];
1418 else if (pointer
[j
+1] != 0xff || (pointer
[0] & 0x40) == 0)
1421 lfn
->name
[offset
+ i
] = 0;
1424 if (pointer
[0] & 0x40)
1425 lfn
->len
= offset
+ strlen((char*)lfn
->name
+ offset
);
1430 /* returns 0 if successful, >0 if no short_name, and <0 on error */
1431 static int parse_short_name(BDRVVVFATState
* s
,
1432 long_file_name
* lfn
, direntry_t
* direntry
)
1436 if (!is_short_name(direntry
))
1439 for (j
= 7; j
>= 0 && direntry
->name
[j
] == ' '; j
--);
1440 for (i
= 0; i
<= j
; i
++) {
1441 if (direntry
->name
[i
] <= ' ' || direntry
->name
[i
] > 0x7f)
1443 else if (s
->downcase_short_names
)
1444 lfn
->name
[i
] = qemu_tolower(direntry
->name
[i
]);
1446 lfn
->name
[i
] = direntry
->name
[i
];
1449 for (j
= 2; j
>= 0 && direntry
->extension
[j
] == ' '; j
--);
1451 lfn
->name
[i
++] = '.';
1452 lfn
->name
[i
+ j
+ 1] = '\0';
1453 for (;j
>= 0; j
--) {
1454 if (direntry
->extension
[j
] <= ' ' || direntry
->extension
[j
] > 0x7f)
1456 else if (s
->downcase_short_names
)
1457 lfn
->name
[i
+ j
] = qemu_tolower(direntry
->extension
[j
]);
1459 lfn
->name
[i
+ j
] = direntry
->extension
[j
];
1462 lfn
->name
[i
+ j
+ 1] = '\0';
1464 lfn
->len
= strlen((char*)lfn
->name
);
1469 static inline uint32_t modified_fat_get(BDRVVVFATState
* s
,
1470 unsigned int cluster
)
1472 if (cluster
< s
->last_cluster_of_root_directory
) {
1473 if (cluster
+ 1 == s
->last_cluster_of_root_directory
)
1474 return s
->max_fat_value
;
1479 if (s
->fat_type
==32) {
1480 uint32_t* entry
=((uint32_t*)s
->fat2
)+cluster
;
1481 return le32_to_cpu(*entry
);
1482 } else if (s
->fat_type
==16) {
1483 uint16_t* entry
=((uint16_t*)s
->fat2
)+cluster
;
1484 return le16_to_cpu(*entry
);
1486 const uint8_t* x
=s
->fat2
+cluster
*3/2;
1487 return ((x
[0]|(x
[1]<<8))>>(cluster
&1?4:0))&0x0fff;
1491 static inline int cluster_was_modified(BDRVVVFATState
* s
, uint32_t cluster_num
)
1493 int was_modified
= 0;
1496 if (s
->qcow
== NULL
)
1499 for (i
= 0; !was_modified
&& i
< s
->sectors_per_cluster
; i
++)
1500 was_modified
= s
->qcow
->drv
->bdrv_is_allocated(s
->qcow
,
1501 cluster2sector(s
, cluster_num
) + i
, 1, &dummy
);
1503 return was_modified
;
1506 static const char* get_basename(const char* path
)
1508 char* basename
= strrchr(path
, '/');
1509 if (basename
== NULL
)
1512 return basename
+ 1; /* strip '/' */
1516 * The array s->used_clusters holds the states of the clusters. If it is
1517 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1518 * was modified, bit 3 is set.
1519 * If any cluster is allocated, but not part of a file or directory, this
1520 * driver refuses to commit.
1523 USED_DIRECTORY
= 1, USED_FILE
= 2, USED_ANY
= 3, USED_ALLOCATED
= 4
1527 * get_cluster_count_for_direntry() not only determines how many clusters
1528 * are occupied by direntry, but also if it was renamed or modified.
1530 * A file is thought to be renamed *only* if there already was a file with
1531 * exactly the same first cluster, but a different name.
1533 * Further, the files/directories handled by this function are
1534 * assumed to be *not* deleted (and *only* those).
1536 static uint32_t get_cluster_count_for_direntry(BDRVVVFATState
* s
,
1537 direntry_t
* direntry
, const char* path
)
1540 * This is a little bit tricky:
1541 * IF the guest OS just inserts a cluster into the file chain,
1542 * and leaves the rest alone, (i.e. the original file had clusters
1543 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1545 * - do_commit will write the cluster into the file at the given
1548 * - the cluster which is overwritten should be moved to a later
1549 * position in the file.
1551 * I am not aware that any OS does something as braindead, but this
1552 * situation could happen anyway when not committing for a long time.
1553 * Just to be sure that this does not bite us, detect it, and copy the
1554 * contents of the clusters to-be-overwritten into the qcow.
1557 int was_modified
= 0;
1560 uint32_t cluster_num
= begin_of_direntry(direntry
);
1561 uint32_t offset
= 0;
1562 int first_mapping_index
= -1;
1563 mapping_t
* mapping
= NULL
;
1564 const char* basename2
= NULL
;
1566 vvfat_close_current_file(s
);
1568 /* the root directory */
1569 if (cluster_num
== 0)
1574 basename2
= get_basename(path
);
1576 mapping
= find_mapping_for_cluster(s
, cluster_num
);
1579 const char* basename
;
1581 assert(mapping
->mode
& MODE_DELETED
);
1582 mapping
->mode
&= ~MODE_DELETED
;
1584 basename
= get_basename(mapping
->path
);
1586 assert(mapping
->mode
& MODE_NORMAL
);
1589 if (strcmp(basename
, basename2
))
1590 schedule_rename(s
, cluster_num
, g_strdup(path
));
1591 } else if (is_file(direntry
))
1593 schedule_new_file(s
, g_strdup(path
), cluster_num
);
1602 if (!copy_it
&& cluster_was_modified(s
, cluster_num
)) {
1603 if (mapping
== NULL
||
1604 mapping
->begin
> cluster_num
||
1605 mapping
->end
<= cluster_num
)
1606 mapping
= find_mapping_for_cluster(s
, cluster_num
);
1610 (mapping
->mode
& MODE_DIRECTORY
) == 0) {
1612 /* was modified in qcow */
1613 if (offset
!= mapping
->info
.file
.offset
+ s
->cluster_size
1614 * (cluster_num
- mapping
->begin
)) {
1615 /* offset of this cluster in file chain has changed */
1618 } else if (offset
== 0) {
1619 const char* basename
= get_basename(mapping
->path
);
1621 if (strcmp(basename
, basename2
))
1623 first_mapping_index
= array_index(&(s
->mapping
), mapping
);
1626 if (mapping
->first_mapping_index
!= first_mapping_index
1627 && mapping
->info
.file
.offset
> 0) {
1632 /* need to write out? */
1633 if (!was_modified
&& is_file(direntry
)) {
1635 schedule_writeout(s
, mapping
->dir_index
, offset
);
1643 * This is horribly inefficient, but that is okay, since
1644 * it is rarely executed, if at all.
1646 int64_t offset
= cluster2sector(s
, cluster_num
);
1648 vvfat_close_current_file(s
);
1649 for (i
= 0; i
< s
->sectors_per_cluster
; i
++)
1650 if (!s
->qcow
->drv
->bdrv_is_allocated(s
->qcow
,
1651 offset
+ i
, 1, &dummy
)) {
1652 if (vvfat_read(s
->bs
,
1653 offset
, s
->cluster_buffer
, 1))
1655 if (s
->qcow
->drv
->bdrv_write(s
->qcow
,
1656 offset
, s
->cluster_buffer
, 1))
1663 if (s
->used_clusters
[cluster_num
] & USED_ANY
)
1665 s
->used_clusters
[cluster_num
] = USED_FILE
;
1667 cluster_num
= modified_fat_get(s
, cluster_num
);
1669 if (fat_eof(s
, cluster_num
))
1671 else if (cluster_num
< 2 || cluster_num
> s
->max_fat_value
- 16)
1674 offset
+= s
->cluster_size
;
1679 * This function looks at the modified data (qcow).
1680 * It returns 0 upon inconsistency or error, and the number of clusters
1681 * used by the directory, its subdirectories and their files.
1683 static int check_directory_consistency(BDRVVVFATState
*s
,
1684 int cluster_num
, const char* path
)
1687 unsigned char* cluster
= g_malloc(s
->cluster_size
);
1688 direntry_t
* direntries
= (direntry_t
*)cluster
;
1689 mapping_t
* mapping
= find_mapping_for_cluster(s
, cluster_num
);
1692 int path_len
= strlen(path
);
1693 char path2
[PATH_MAX
+ 1];
1695 assert(path_len
< PATH_MAX
); /* len was tested before! */
1696 pstrcpy(path2
, sizeof(path2
), path
);
1697 path2
[path_len
] = '/';
1698 path2
[path_len
+ 1] = '\0';
1701 const char* basename
= get_basename(mapping
->path
);
1702 const char* basename2
= get_basename(path
);
1704 assert(mapping
->mode
& MODE_DIRECTORY
);
1706 assert(mapping
->mode
& MODE_DELETED
);
1707 mapping
->mode
&= ~MODE_DELETED
;
1709 if (strcmp(basename
, basename2
))
1710 schedule_rename(s
, cluster_num
, g_strdup(path
));
1713 schedule_mkdir(s
, cluster_num
, g_strdup(path
));
1722 if (s
->used_clusters
[cluster_num
] & USED_ANY
) {
1723 fprintf(stderr
, "cluster %d used more than once\n", (int)cluster_num
);
1726 s
->used_clusters
[cluster_num
] = USED_DIRECTORY
;
1728 DLOG(fprintf(stderr
, "read cluster %d (sector %d)\n", (int)cluster_num
, (int)cluster2sector(s
, cluster_num
)));
1729 subret
= vvfat_read(s
->bs
, cluster2sector(s
, cluster_num
), cluster
,
1730 s
->sectors_per_cluster
);
1732 fprintf(stderr
, "Error fetching direntries\n");
1738 for (i
= 0; i
< 0x10 * s
->sectors_per_cluster
; i
++) {
1739 int cluster_count
= 0;
1741 DLOG(fprintf(stderr
, "check direntry %d:\n", i
); print_direntry(direntries
+ i
));
1742 if (is_volume_label(direntries
+ i
) || is_dot(direntries
+ i
) ||
1743 is_free(direntries
+ i
))
1746 subret
= parse_long_name(&lfn
, direntries
+ i
);
1748 fprintf(stderr
, "Error in long name\n");
1751 if (subret
== 0 || is_free(direntries
+ i
))
1754 if (fat_chksum(direntries
+i
) != lfn
.checksum
) {
1755 subret
= parse_short_name(s
, &lfn
, direntries
+ i
);
1757 fprintf(stderr
, "Error in short name (%d)\n", subret
);
1760 if (subret
> 0 || !strcmp((char*)lfn
.name
, ".")
1761 || !strcmp((char*)lfn
.name
, ".."))
1764 lfn
.checksum
= 0x100; /* cannot use long name twice */
1766 if (path_len
+ 1 + lfn
.len
>= PATH_MAX
) {
1767 fprintf(stderr
, "Name too long: %s/%s\n", path
, lfn
.name
);
1770 pstrcpy(path2
+ path_len
+ 1, sizeof(path2
) - path_len
- 1,
1773 if (is_directory(direntries
+ i
)) {
1774 if (begin_of_direntry(direntries
+ i
) == 0) {
1775 DLOG(fprintf(stderr
, "invalid begin for directory: %s\n", path2
); print_direntry(direntries
+ i
));
1778 cluster_count
= check_directory_consistency(s
,
1779 begin_of_direntry(direntries
+ i
), path2
);
1780 if (cluster_count
== 0) {
1781 DLOG(fprintf(stderr
, "problem in directory %s:\n", path2
); print_direntry(direntries
+ i
));
1784 } else if (is_file(direntries
+ i
)) {
1785 /* check file size with FAT */
1786 cluster_count
= get_cluster_count_for_direntry(s
, direntries
+ i
, path2
);
1787 if (cluster_count
!=
1788 (le32_to_cpu(direntries
[i
].size
) + s
->cluster_size
1789 - 1) / s
->cluster_size
) {
1790 DLOG(fprintf(stderr
, "Cluster count mismatch\n"));
1794 abort(); /* cluster_count = 0; */
1796 ret
+= cluster_count
;
1799 cluster_num
= modified_fat_get(s
, cluster_num
);
1800 } while(!fat_eof(s
, cluster_num
));
1806 /* returns 1 on success */
1807 static int is_consistent(BDRVVVFATState
* s
)
1810 int used_clusters_count
= 0;
1814 * - get modified FAT
1815 * - compare the two FATs (TODO)
1816 * - get buffer for marking used clusters
1817 * - recurse direntries from root (using bs->bdrv_read to make
1818 * sure to get the new data)
1819 * - check that the FAT agrees with the size
1820 * - count the number of clusters occupied by this directory and
1822 * - check that the cumulative used cluster count agrees with the
1824 * - if all is fine, return number of used clusters
1826 if (s
->fat2
== NULL
) {
1827 int size
= 0x200 * s
->sectors_per_fat
;
1828 s
->fat2
= g_malloc(size
);
1829 memcpy(s
->fat2
, s
->fat
.pointer
, size
);
1831 check
= vvfat_read(s
->bs
,
1832 s
->first_sectors_number
, s
->fat2
, s
->sectors_per_fat
);
1834 fprintf(stderr
, "Could not copy fat\n");
1837 assert (s
->used_clusters
);
1838 for (i
= 0; i
< sector2cluster(s
, s
->sector_count
); i
++)
1839 s
->used_clusters
[i
] &= ~USED_ANY
;
1843 /* mark every mapped file/directory as deleted.
1844 * (check_directory_consistency() will unmark those still present). */
1846 for (i
= 0; i
< s
->mapping
.next
; i
++) {
1847 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
1848 if (mapping
->first_mapping_index
< 0)
1849 mapping
->mode
|= MODE_DELETED
;
1852 used_clusters_count
= check_directory_consistency(s
, 0, s
->path
);
1853 if (used_clusters_count
<= 0) {
1854 DLOG(fprintf(stderr
, "problem in directory\n"));
1858 check
= s
->last_cluster_of_root_directory
;
1859 for (i
= check
; i
< sector2cluster(s
, s
->sector_count
); i
++) {
1860 if (modified_fat_get(s
, i
)) {
1861 if(!s
->used_clusters
[i
]) {
1862 DLOG(fprintf(stderr
, "FAT was modified (%d), but cluster is not used?\n", i
));
1868 if (s
->used_clusters
[i
] == USED_ALLOCATED
) {
1869 /* allocated, but not used... */
1870 DLOG(fprintf(stderr
, "unused, modified cluster: %d\n", i
));
1875 if (check
!= used_clusters_count
)
1878 return used_clusters_count
;
1881 static inline void adjust_mapping_indices(BDRVVVFATState
* s
,
1882 int offset
, int adjust
)
1886 for (i
= 0; i
< s
->mapping
.next
; i
++) {
1887 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
1889 #define ADJUST_MAPPING_INDEX(name) \
1890 if (mapping->name >= offset) \
1891 mapping->name += adjust
1893 ADJUST_MAPPING_INDEX(first_mapping_index
);
1894 if (mapping
->mode
& MODE_DIRECTORY
)
1895 ADJUST_MAPPING_INDEX(info
.dir
.parent_mapping_index
);
1899 /* insert or update mapping */
1900 static mapping_t
* insert_mapping(BDRVVVFATState
* s
,
1901 uint32_t begin
, uint32_t end
)
1904 * - find mapping where mapping->begin >= begin,
1905 * - if mapping->begin > begin: insert
1906 * - adjust all references to mappings!
1910 int index
= find_mapping_for_cluster_aux(s
, begin
, 0, s
->mapping
.next
);
1911 mapping_t
* mapping
= NULL
;
1912 mapping_t
* first_mapping
= array_get(&(s
->mapping
), 0);
1914 if (index
< s
->mapping
.next
&& (mapping
= array_get(&(s
->mapping
), index
))
1915 && mapping
->begin
< begin
) {
1916 mapping
->end
= begin
;
1918 mapping
= array_get(&(s
->mapping
), index
);
1920 if (index
>= s
->mapping
.next
|| mapping
->begin
> begin
) {
1921 mapping
= array_insert(&(s
->mapping
), index
, 1);
1922 mapping
->path
= NULL
;
1923 adjust_mapping_indices(s
, index
, +1);
1926 mapping
->begin
= begin
;
1929 DLOG(mapping_t
* next_mapping
;
1930 assert(index
+ 1 >= s
->mapping
.next
||
1931 ((next_mapping
= array_get(&(s
->mapping
), index
+ 1)) &&
1932 next_mapping
->begin
>= end
)));
1934 if (s
->current_mapping
&& first_mapping
!= (mapping_t
*)s
->mapping
.pointer
)
1935 s
->current_mapping
= array_get(&(s
->mapping
),
1936 s
->current_mapping
- first_mapping
);
1941 static int remove_mapping(BDRVVVFATState
* s
, int mapping_index
)
1943 mapping_t
* mapping
= array_get(&(s
->mapping
), mapping_index
);
1944 mapping_t
* first_mapping
= array_get(&(s
->mapping
), 0);
1947 if (mapping
->first_mapping_index
< 0) {
1948 g_free(mapping
->path
);
1951 /* remove from s->mapping */
1952 array_remove(&(s
->mapping
), mapping_index
);
1954 /* adjust all references to mappings */
1955 adjust_mapping_indices(s
, mapping_index
, -1);
1957 if (s
->current_mapping
&& first_mapping
!= (mapping_t
*)s
->mapping
.pointer
)
1958 s
->current_mapping
= array_get(&(s
->mapping
),
1959 s
->current_mapping
- first_mapping
);
1964 static void adjust_dirindices(BDRVVVFATState
* s
, int offset
, int adjust
)
1967 for (i
= 0; i
< s
->mapping
.next
; i
++) {
1968 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
1969 if (mapping
->dir_index
>= offset
)
1970 mapping
->dir_index
+= adjust
;
1971 if ((mapping
->mode
& MODE_DIRECTORY
) &&
1972 mapping
->info
.dir
.first_dir_index
>= offset
)
1973 mapping
->info
.dir
.first_dir_index
+= adjust
;
1977 static direntry_t
* insert_direntries(BDRVVVFATState
* s
,
1978 int dir_index
, int count
)
1981 * make room in s->directory,
1984 direntry_t
* result
= array_insert(&(s
->directory
), dir_index
, count
);
1987 adjust_dirindices(s
, dir_index
, count
);
1991 static int remove_direntries(BDRVVVFATState
* s
, int dir_index
, int count
)
1993 int ret
= array_remove_slice(&(s
->directory
), dir_index
, count
);
1996 adjust_dirindices(s
, dir_index
, -count
);
2001 * Adapt the mappings of the cluster chain starting at first cluster
2002 * (i.e. if a file starts at first_cluster, the chain is followed according
2003 * to the modified fat, and the corresponding entries in s->mapping are
2006 static int commit_mappings(BDRVVVFATState
* s
,
2007 uint32_t first_cluster
, int dir_index
)
2009 mapping_t
* mapping
= find_mapping_for_cluster(s
, first_cluster
);
2010 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2011 uint32_t cluster
= first_cluster
;
2013 vvfat_close_current_file(s
);
2016 assert(mapping
->begin
== first_cluster
);
2017 mapping
->first_mapping_index
= -1;
2018 mapping
->dir_index
= dir_index
;
2019 mapping
->mode
= (dir_index
<= 0 || is_directory(direntry
)) ?
2020 MODE_DIRECTORY
: MODE_NORMAL
;
2022 while (!fat_eof(s
, cluster
)) {
2025 for (c
= cluster
, c1
= modified_fat_get(s
, c
); c
+ 1 == c1
;
2026 c
= c1
, c1
= modified_fat_get(s
, c1
));
2029 if (c
> mapping
->end
) {
2030 int index
= array_index(&(s
->mapping
), mapping
);
2031 int i
, max_i
= s
->mapping
.next
- index
;
2032 for (i
= 1; i
< max_i
&& mapping
[i
].begin
< c
; i
++);
2034 remove_mapping(s
, index
+ 1);
2036 assert(mapping
== array_get(&(s
->mapping
), s
->mapping
.next
- 1)
2037 || mapping
[1].begin
>= c
);
2040 if (!fat_eof(s
, c1
)) {
2041 int i
= find_mapping_for_cluster_aux(s
, c1
, 0, s
->mapping
.next
);
2042 mapping_t
* next_mapping
= i
>= s
->mapping
.next
? NULL
:
2043 array_get(&(s
->mapping
), i
);
2045 if (next_mapping
== NULL
|| next_mapping
->begin
> c1
) {
2046 int i1
= array_index(&(s
->mapping
), mapping
);
2048 next_mapping
= insert_mapping(s
, c1
, c1
+1);
2052 mapping
= array_get(&(s
->mapping
), i1
);
2055 next_mapping
->dir_index
= mapping
->dir_index
;
2056 next_mapping
->first_mapping_index
=
2057 mapping
->first_mapping_index
< 0 ?
2058 array_index(&(s
->mapping
), mapping
) :
2059 mapping
->first_mapping_index
;
2060 next_mapping
->path
= mapping
->path
;
2061 next_mapping
->mode
= mapping
->mode
;
2062 next_mapping
->read_only
= mapping
->read_only
;
2063 if (mapping
->mode
& MODE_DIRECTORY
) {
2064 next_mapping
->info
.dir
.parent_mapping_index
=
2065 mapping
->info
.dir
.parent_mapping_index
;
2066 next_mapping
->info
.dir
.first_dir_index
=
2067 mapping
->info
.dir
.first_dir_index
+
2068 0x10 * s
->sectors_per_cluster
*
2069 (mapping
->end
- mapping
->begin
);
2071 next_mapping
->info
.file
.offset
= mapping
->info
.file
.offset
+
2072 mapping
->end
- mapping
->begin
;
2074 mapping
= next_mapping
;
2083 static int commit_direntries(BDRVVVFATState
* s
,
2084 int dir_index
, int parent_mapping_index
)
2086 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2087 uint32_t first_cluster
= dir_index
== 0 ? 0 : begin_of_direntry(direntry
);
2088 mapping_t
* mapping
= find_mapping_for_cluster(s
, first_cluster
);
2090 int factor
= 0x10 * s
->sectors_per_cluster
;
2091 int old_cluster_count
, new_cluster_count
;
2092 int current_dir_index
= mapping
->info
.dir
.first_dir_index
;
2093 int first_dir_index
= current_dir_index
;
2097 DLOG(fprintf(stderr
, "commit_direntries for %s, parent_mapping_index %d\n", mapping
->path
, parent_mapping_index
));
2101 assert(mapping
->begin
== first_cluster
);
2102 assert(mapping
->info
.dir
.first_dir_index
< s
->directory
.next
);
2103 assert(mapping
->mode
& MODE_DIRECTORY
);
2104 assert(dir_index
== 0 || is_directory(direntry
));
2106 mapping
->info
.dir
.parent_mapping_index
= parent_mapping_index
;
2108 if (first_cluster
== 0) {
2109 old_cluster_count
= new_cluster_count
=
2110 s
->last_cluster_of_root_directory
;
2112 for (old_cluster_count
= 0, c
= first_cluster
; !fat_eof(s
, c
);
2114 old_cluster_count
++;
2116 for (new_cluster_count
= 0, c
= first_cluster
; !fat_eof(s
, c
);
2117 c
= modified_fat_get(s
, c
))
2118 new_cluster_count
++;
2121 if (new_cluster_count
> old_cluster_count
) {
2122 if (insert_direntries(s
,
2123 current_dir_index
+ factor
* old_cluster_count
,
2124 factor
* (new_cluster_count
- old_cluster_count
)) == NULL
)
2126 } else if (new_cluster_count
< old_cluster_count
)
2127 remove_direntries(s
,
2128 current_dir_index
+ factor
* new_cluster_count
,
2129 factor
* (old_cluster_count
- new_cluster_count
));
2131 for (c
= first_cluster
; !fat_eof(s
, c
); c
= modified_fat_get(s
, c
)) {
2132 void* direntry
= array_get(&(s
->directory
), current_dir_index
);
2133 int ret
= vvfat_read(s
->bs
, cluster2sector(s
, c
), direntry
,
2134 s
->sectors_per_cluster
);
2137 assert(!strncmp(s
->directory
.pointer
, "QEMU", 4));
2138 current_dir_index
+= factor
;
2141 ret
= commit_mappings(s
, first_cluster
, dir_index
);
2146 for (i
= 0; i
< factor
* new_cluster_count
; i
++) {
2147 direntry
= array_get(&(s
->directory
), first_dir_index
+ i
);
2148 if (is_directory(direntry
) && !is_dot(direntry
)) {
2149 mapping
= find_mapping_for_cluster(s
, first_cluster
);
2150 assert(mapping
->mode
& MODE_DIRECTORY
);
2151 ret
= commit_direntries(s
, first_dir_index
+ i
,
2152 array_index(&(s
->mapping
), mapping
));
2161 /* commit one file (adjust contents, adjust mapping),
2162 return first_mapping_index */
2163 static int commit_one_file(BDRVVVFATState
* s
,
2164 int dir_index
, uint32_t offset
)
2166 direntry_t
* direntry
= array_get(&(s
->directory
), dir_index
);
2167 uint32_t c
= begin_of_direntry(direntry
);
2168 uint32_t first_cluster
= c
;
2169 mapping_t
* mapping
= find_mapping_for_cluster(s
, c
);
2170 uint32_t size
= filesize_of_direntry(direntry
);
2171 char* cluster
= g_malloc(s
->cluster_size
);
2175 assert(offset
< size
);
2176 assert((offset
% s
->cluster_size
) == 0);
2178 for (i
= s
->cluster_size
; i
< offset
; i
+= s
->cluster_size
)
2179 c
= modified_fat_get(s
, c
);
2181 fd
= open(mapping
->path
, O_RDWR
| O_CREAT
| O_BINARY
, 0666);
2183 fprintf(stderr
, "Could not open %s... (%s, %d)\n", mapping
->path
,
2184 strerror(errno
), errno
);
2189 if (lseek(fd
, offset
, SEEK_SET
) != offset
) {
2195 while (offset
< size
) {
2197 int rest_size
= (size
- offset
> s
->cluster_size
?
2198 s
->cluster_size
: size
- offset
);
2201 c1
= modified_fat_get(s
, c
);
2203 assert((size
- offset
== 0 && fat_eof(s
, c
)) ||
2204 (size
> offset
&& c
>=2 && !fat_eof(s
, c
)));
2206 ret
= vvfat_read(s
->bs
, cluster2sector(s
, c
),
2207 (uint8_t*)cluster
, (rest_size
+ 0x1ff) / 0x200);
2214 if (write(fd
, cluster
, rest_size
) < 0) {
2219 offset
+= rest_size
;
2223 if (ftruncate(fd
, size
)) {
2224 perror("ftruncate()");
2232 return commit_mappings(s
, first_cluster
, dir_index
);
2236 /* test, if all mappings point to valid direntries */
2237 static void check1(BDRVVVFATState
* s
)
2240 for (i
= 0; i
< s
->mapping
.next
; i
++) {
2241 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2242 if (mapping
->mode
& MODE_DELETED
) {
2243 fprintf(stderr
, "deleted\n");
2246 assert(mapping
->dir_index
< s
->directory
.next
);
2247 direntry_t
* direntry
= array_get(&(s
->directory
), mapping
->dir_index
);
2248 assert(mapping
->begin
== begin_of_direntry(direntry
) || mapping
->first_mapping_index
>= 0);
2249 if (mapping
->mode
& MODE_DIRECTORY
) {
2250 assert(mapping
->info
.dir
.first_dir_index
+ 0x10 * s
->sectors_per_cluster
* (mapping
->end
- mapping
->begin
) <= s
->directory
.next
);
2251 assert((mapping
->info
.dir
.first_dir_index
% (0x10 * s
->sectors_per_cluster
)) == 0);
2256 /* test, if all direntries have mappings */
2257 static void check2(BDRVVVFATState
* s
)
2260 int first_mapping
= -1;
2262 for (i
= 0; i
< s
->directory
.next
; i
++) {
2263 direntry_t
* direntry
= array_get(&(s
->directory
), i
);
2265 if (is_short_name(direntry
) && begin_of_direntry(direntry
)) {
2266 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin_of_direntry(direntry
));
2268 assert(mapping
->dir_index
== i
|| is_dot(direntry
));
2269 assert(mapping
->begin
== begin_of_direntry(direntry
) || is_dot(direntry
));
2272 if ((i
% (0x10 * s
->sectors_per_cluster
)) == 0) {
2276 for (j
= 0; j
< s
->mapping
.next
; j
++) {
2277 mapping_t
* mapping
= array_get(&(s
->mapping
), j
);
2278 if (mapping
->mode
& MODE_DELETED
)
2280 if (mapping
->mode
& MODE_DIRECTORY
) {
2281 if (mapping
->info
.dir
.first_dir_index
<= i
&& mapping
->info
.dir
.first_dir_index
+ 0x10 * s
->sectors_per_cluster
> i
) {
2282 assert(++count
== 1);
2283 if (mapping
->first_mapping_index
== -1)
2284 first_mapping
= array_index(&(s
->mapping
), mapping
);
2286 assert(first_mapping
== mapping
->first_mapping_index
);
2287 if (mapping
->info
.dir
.parent_mapping_index
< 0)
2290 mapping_t
* parent
= array_get(&(s
->mapping
), mapping
->info
.dir
.parent_mapping_index
);
2291 assert(parent
->mode
& MODE_DIRECTORY
);
2292 assert(parent
->info
.dir
.first_dir_index
< mapping
->info
.dir
.first_dir_index
);
2304 static int handle_renames_and_mkdirs(BDRVVVFATState
* s
)
2309 fprintf(stderr
, "handle_renames\n");
2310 for (i
= 0; i
< s
->commits
.next
; i
++) {
2311 commit_t
* commit
= array_get(&(s
->commits
), i
);
2312 fprintf(stderr
, "%d, %s (%d, %d)\n", i
, commit
->path
? commit
->path
: "(null)", commit
->param
.rename
.cluster
, commit
->action
);
2316 for (i
= 0; i
< s
->commits
.next
;) {
2317 commit_t
* commit
= array_get(&(s
->commits
), i
);
2318 if (commit
->action
== ACTION_RENAME
) {
2319 mapping_t
* mapping
= find_mapping_for_cluster(s
,
2320 commit
->param
.rename
.cluster
);
2321 char* old_path
= mapping
->path
;
2323 assert(commit
->path
);
2324 mapping
->path
= commit
->path
;
2325 if (rename(old_path
, mapping
->path
))
2328 if (mapping
->mode
& MODE_DIRECTORY
) {
2329 int l1
= strlen(mapping
->path
);
2330 int l2
= strlen(old_path
);
2332 direntry_t
* direntry
= array_get(&(s
->directory
),
2333 mapping
->info
.dir
.first_dir_index
);
2334 uint32_t c
= mapping
->begin
;
2338 while (!fat_eof(s
, c
)) {
2340 direntry_t
* d
= direntry
+ i
;
2342 if (is_file(d
) || (is_directory(d
) && !is_dot(d
))) {
2343 mapping_t
* m
= find_mapping_for_cluster(s
,
2344 begin_of_direntry(d
));
2345 int l
= strlen(m
->path
);
2346 char* new_path
= g_malloc(l
+ diff
+ 1);
2348 assert(!strncmp(m
->path
, mapping
->path
, l2
));
2350 pstrcpy(new_path
, l
+ diff
+ 1, mapping
->path
);
2351 pstrcpy(new_path
+ l1
, l
+ diff
+ 1 - l1
,
2354 schedule_rename(s
, m
->begin
, new_path
);
2357 } while((i
% (0x10 * s
->sectors_per_cluster
)) != 0);
2363 array_remove(&(s
->commits
), i
);
2365 } else if (commit
->action
== ACTION_MKDIR
) {
2367 int j
, parent_path_len
;
2370 if (mkdir(commit
->path
))
2373 if (mkdir(commit
->path
, 0755))
2377 mapping
= insert_mapping(s
, commit
->param
.mkdir
.cluster
,
2378 commit
->param
.mkdir
.cluster
+ 1);
2379 if (mapping
== NULL
)
2382 mapping
->mode
= MODE_DIRECTORY
;
2383 mapping
->read_only
= 0;
2384 mapping
->path
= commit
->path
;
2385 j
= s
->directory
.next
;
2387 insert_direntries(s
, s
->directory
.next
,
2388 0x10 * s
->sectors_per_cluster
);
2389 mapping
->info
.dir
.first_dir_index
= j
;
2391 parent_path_len
= strlen(commit
->path
)
2392 - strlen(get_basename(commit
->path
)) - 1;
2393 for (j
= 0; j
< s
->mapping
.next
; j
++) {
2394 mapping_t
* m
= array_get(&(s
->mapping
), j
);
2395 if (m
->first_mapping_index
< 0 && m
!= mapping
&&
2396 !strncmp(m
->path
, mapping
->path
, parent_path_len
) &&
2397 strlen(m
->path
) == parent_path_len
)
2400 assert(j
< s
->mapping
.next
);
2401 mapping
->info
.dir
.parent_mapping_index
= j
;
2403 array_remove(&(s
->commits
), i
);
2413 * TODO: make sure that the short name is not matching *another* file
2415 static int handle_commits(BDRVVVFATState
* s
)
2419 vvfat_close_current_file(s
);
2421 for (i
= 0; !fail
&& i
< s
->commits
.next
; i
++) {
2422 commit_t
* commit
= array_get(&(s
->commits
), i
);
2423 switch(commit
->action
) {
2424 case ACTION_RENAME
: case ACTION_MKDIR
:
2428 case ACTION_WRITEOUT
: {
2430 /* these variables are only used by assert() below */
2431 direntry_t
* entry
= array_get(&(s
->directory
),
2432 commit
->param
.writeout
.dir_index
);
2433 uint32_t begin
= begin_of_direntry(entry
);
2434 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin
);
2438 assert(mapping
->begin
== begin
);
2439 assert(commit
->path
== NULL
);
2441 if (commit_one_file(s
, commit
->param
.writeout
.dir_index
,
2442 commit
->param
.writeout
.modified_offset
))
2447 case ACTION_NEW_FILE
: {
2448 int begin
= commit
->param
.new_file
.first_cluster
;
2449 mapping_t
* mapping
= find_mapping_for_cluster(s
, begin
);
2454 for (i
= 0; i
< s
->directory
.next
; i
++) {
2455 entry
= array_get(&(s
->directory
), i
);
2456 if (is_file(entry
) && begin_of_direntry(entry
) == begin
)
2460 if (i
>= s
->directory
.next
) {
2465 /* make sure there exists an initial mapping */
2466 if (mapping
&& mapping
->begin
!= begin
) {
2467 mapping
->end
= begin
;
2470 if (mapping
== NULL
) {
2471 mapping
= insert_mapping(s
, begin
, begin
+1);
2473 /* most members will be fixed in commit_mappings() */
2474 assert(commit
->path
);
2475 mapping
->path
= commit
->path
;
2476 mapping
->read_only
= 0;
2477 mapping
->mode
= MODE_NORMAL
;
2478 mapping
->info
.file
.offset
= 0;
2480 if (commit_one_file(s
, i
, 0))
2489 if (i
> 0 && array_remove_slice(&(s
->commits
), 0, i
))
2494 static int handle_deletes(BDRVVVFATState
* s
)
2496 int i
, deferred
= 1, deleted
= 1;
2498 /* delete files corresponding to mappings marked as deleted */
2499 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2500 while (deferred
&& deleted
) {
2504 for (i
= 1; i
< s
->mapping
.next
; i
++) {
2505 mapping_t
* mapping
= array_get(&(s
->mapping
), i
);
2506 if (mapping
->mode
& MODE_DELETED
) {
2507 direntry_t
* entry
= array_get(&(s
->directory
),
2508 mapping
->dir_index
);
2510 if (is_free(entry
)) {
2511 /* remove file/directory */
2512 if (mapping
->mode
& MODE_DIRECTORY
) {
2513 int j
, next_dir_index
= s
->directory
.next
,
2514 first_dir_index
= mapping
->info
.dir
.first_dir_index
;
2516 if (rmdir(mapping
->path
) < 0) {
2517 if (errno
== ENOTEMPTY
) {
2524 for (j
= 1; j
< s
->mapping
.next
; j
++) {
2525 mapping_t
* m
= array_get(&(s
->mapping
), j
);
2526 if (m
->mode
& MODE_DIRECTORY
&&
2527 m
->info
.dir
.first_dir_index
>
2529 m
->info
.dir
.first_dir_index
<
2532 m
->info
.dir
.first_dir_index
;
2534 remove_direntries(s
, first_dir_index
,
2535 next_dir_index
- first_dir_index
);
2540 if (unlink(mapping
->path
))
2544 DLOG(fprintf(stderr
, "DELETE (%d)\n", i
); print_mapping(mapping
); print_direntry(entry
));
2545 remove_mapping(s
, i
);
2554 * synchronize mapping with new state:
2556 * - copy FAT (with bdrv_read)
2557 * - mark all filenames corresponding to mappings as deleted
2558 * - recurse direntries from root (using bs->bdrv_read)
2559 * - delete files corresponding to mappings marked as deleted
2561 static int do_commit(BDRVVVFATState
* s
)
2565 /* the real meat are the commits. Nothing to do? Move along! */
2566 if (s
->commits
.next
== 0)
2569 vvfat_close_current_file(s
);
2571 ret
= handle_renames_and_mkdirs(s
);
2573 fprintf(stderr
, "Error handling renames (%d)\n", ret
);
2578 /* copy FAT (with bdrv_read) */
2579 memcpy(s
->fat
.pointer
, s
->fat2
, 0x200 * s
->sectors_per_fat
);
2581 /* recurse direntries from root (using bs->bdrv_read) */
2582 ret
= commit_direntries(s
, 0, -1);
2584 fprintf(stderr
, "Fatal: error while committing (%d)\n", ret
);
2589 ret
= handle_commits(s
);
2591 fprintf(stderr
, "Error handling commits (%d)\n", ret
);
2596 ret
= handle_deletes(s
);
2598 fprintf(stderr
, "Error deleting\n");
2603 s
->qcow
->drv
->bdrv_make_empty(s
->qcow
);
2605 memset(s
->used_clusters
, 0, sector2cluster(s
, s
->sector_count
));
2611 static int try_commit(BDRVVVFATState
* s
)
2613 vvfat_close_current_file(s
);
2615 if(!is_consistent(s
))
2617 return do_commit(s
);
2620 static int vvfat_write(BlockDriverState
*bs
, int64_t sector_num
,
2621 const uint8_t *buf
, int nb_sectors
)
2623 BDRVVVFATState
*s
= bs
->opaque
;
2628 /* Check if we're operating in read-only mode */
2629 if (s
->qcow
== NULL
) {
2633 vvfat_close_current_file(s
);
2636 * Some sanity checks:
2637 * - do not allow writing to the boot sector
2638 * - do not allow to write non-ASCII filenames
2641 if (sector_num
< s
->first_sectors_number
)
2644 for (i
= sector2cluster(s
, sector_num
);
2645 i
<= sector2cluster(s
, sector_num
+ nb_sectors
- 1);) {
2646 mapping_t
* mapping
= find_mapping_for_cluster(s
, i
);
2648 if (mapping
->read_only
) {
2649 fprintf(stderr
, "Tried to write to write-protected file %s\n",
2654 if (mapping
->mode
& MODE_DIRECTORY
) {
2655 int begin
= cluster2sector(s
, i
);
2656 int end
= begin
+ s
->sectors_per_cluster
, k
;
2658 const direntry_t
* direntries
;
2663 if (begin
< sector_num
)
2665 if (end
> sector_num
+ nb_sectors
)
2666 end
= sector_num
+ nb_sectors
;
2667 dir_index
= mapping
->dir_index
+
2668 0x10 * (begin
- mapping
->begin
* s
->sectors_per_cluster
);
2669 direntries
= (direntry_t
*)(buf
+ 0x200 * (begin
- sector_num
));
2671 for (k
= 0; k
< (end
- begin
) * 0x10; k
++) {
2672 /* do not allow non-ASCII filenames */
2673 if (parse_long_name(&lfn
, direntries
+ k
) < 0) {
2674 fprintf(stderr
, "Warning: non-ASCII filename\n");
2677 /* no access to the direntry of a read-only file */
2678 else if (is_short_name(direntries
+k
) &&
2679 (direntries
[k
].attributes
& 1)) {
2680 if (memcmp(direntries
+ k
,
2681 array_get(&(s
->directory
), dir_index
+ k
),
2682 sizeof(direntry_t
))) {
2683 fprintf(stderr
, "Warning: tried to write to write-protected file\n");
2695 * Use qcow backend. Commit later.
2697 DLOG(fprintf(stderr
, "Write to qcow backend: %d + %d\n", (int)sector_num
, nb_sectors
));
2698 ret
= s
->qcow
->drv
->bdrv_write(s
->qcow
, sector_num
, buf
, nb_sectors
);
2700 fprintf(stderr
, "Error writing to qcow backend\n");
2704 for (i
= sector2cluster(s
, sector_num
);
2705 i
<= sector2cluster(s
, sector_num
+ nb_sectors
- 1); i
++)
2707 s
->used_clusters
[i
] |= USED_ALLOCATED
;
2710 /* TODO: add timeout */
2717 static int vvfat_is_allocated(BlockDriverState
*bs
,
2718 int64_t sector_num
, int nb_sectors
, int* n
)
2720 BDRVVVFATState
* s
= bs
->opaque
;
2721 *n
= s
->sector_count
- sector_num
;
2722 if (*n
> nb_sectors
)
2729 static int write_target_commit(BlockDriverState
*bs
, int64_t sector_num
,
2730 const uint8_t* buffer
, int nb_sectors
) {
2731 BDRVVVFATState
* s
= *((BDRVVVFATState
**) bs
->opaque
);
2732 return try_commit(s
);
2735 static void write_target_close(BlockDriverState
*bs
) {
2736 BDRVVVFATState
* s
= *((BDRVVVFATState
**) bs
->opaque
);
2737 bdrv_delete(s
->qcow
);
2738 g_free(s
->qcow_filename
);
2741 static BlockDriver vvfat_write_target
= {
2742 .format_name
= "vvfat_write_target",
2743 .bdrv_write
= write_target_commit
,
2744 .bdrv_close
= write_target_close
,
2747 static int enable_write_target(BDRVVVFATState
*s
)
2749 BlockDriver
*bdrv_qcow
;
2750 QEMUOptionParameter
*options
;
2752 int size
= sector2cluster(s
, s
->sector_count
);
2753 s
->used_clusters
= calloc(size
, 1);
2755 array_init(&(s
->commits
), sizeof(commit_t
));
2757 s
->qcow_filename
= g_malloc(1024);
2758 get_tmp_filename(s
->qcow_filename
, 1024);
2760 bdrv_qcow
= bdrv_find_format("qcow");
2761 options
= parse_option_parameters("", bdrv_qcow
->create_options
, NULL
);
2762 set_option_parameter_int(options
, BLOCK_OPT_SIZE
, s
->sector_count
* 512);
2763 set_option_parameter(options
, BLOCK_OPT_BACKING_FILE
, "fat:");
2765 if (bdrv_create(bdrv_qcow
, s
->qcow_filename
, options
) < 0)
2768 s
->qcow
= bdrv_new("");
2769 if (s
->qcow
== NULL
) {
2773 ret
= bdrv_open(s
->qcow
, s
->qcow_filename
,
2774 BDRV_O_RDWR
| BDRV_O_CACHE_WB
| BDRV_O_NO_FLUSH
, bdrv_qcow
);
2780 unlink(s
->qcow_filename
);
2783 s
->bs
->backing_hd
= calloc(sizeof(BlockDriverState
), 1);
2784 s
->bs
->backing_hd
->drv
= &vvfat_write_target
;
2785 s
->bs
->backing_hd
->opaque
= g_malloc(sizeof(void*));
2786 *(void**)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 g_free(s
->cluster_buffer
);
2802 static BlockDriver bdrv_vvfat
= {
2803 .format_name
= "vvfat",
2804 .instance_size
= sizeof(BDRVVVFATState
),
2805 .bdrv_file_open
= vvfat_open
,
2806 .bdrv_read
= vvfat_read
,
2807 .bdrv_write
= vvfat_write
,
2808 .bdrv_close
= vvfat_close
,
2809 .bdrv_is_allocated
= vvfat_is_allocated
,
2810 .protocol_name
= "fat",
2813 static void bdrv_vvfat_init(void)
2815 bdrv_register(&bdrv_vvfat
);
2818 block_init(bdrv_vvfat_init
);
2821 static void checkpoint(void) {
2822 assert(((mapping_t
*)array_get(&(vvv
->mapping
), 0))->end
== 2);
2825 assert(!vvv
->current_mapping
|| vvv
->current_fd
|| (vvv
->current_mapping
->mode
& MODE_DIRECTORY
));
2827 if (((direntry_t
*)vvv
->directory
.pointer
)[1].attributes
!= 0xf)
2828 fprintf(stderr
, "Nonono!\n");
2830 direntry_t
* direntry
;
2831 assert(vvv
->mapping
.size
>= vvv
->mapping
.item_size
* vvv
->mapping
.next
);
2832 assert(vvv
->directory
.size
>= vvv
->directory
.item_size
* vvv
->directory
.next
);
2833 if (vvv
->mapping
.next
<47)
2835 assert((mapping
= array_get(&(vvv
->mapping
), 47)));
2836 assert(mapping
->dir_index
< vvv
->directory
.next
);
2837 direntry
= array_get(&(vvv
->directory
), mapping
->dir_index
);
2838 assert(!memcmp(direntry
->name
, "USB H ", 11) || direntry
->name
[0]==0);