Model more parts of the ETRAX mmu (still alot missing).
[qemu/malc.git] / block-vvfat.c
bloba93fde9702bebcb99357c0ba05ef57360d380dd7
1 /* vim:set shiftwidth=4 ts=8: */
2 /*
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
23 * THE SOFTWARE.
25 #include <sys/stat.h>
26 #include <dirent.h>
27 #include <assert.h>
28 #include "qemu-common.h"
29 #include "block_int.h"
31 #ifndef S_IWGRP
32 #define S_IWGRP 0
33 #endif
34 #ifndef S_IWOTH
35 #define S_IWOTH 0
36 #endif
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 */
46 /* #define DEBUG */
48 #ifdef DEBUG
50 #define DLOG(a) a
52 #undef stderr
53 #define stderr STDERR
54 FILE* stderr = NULL;
56 static void checkpoint(void);
58 #ifdef __MINGW32__
59 void nonono(const char* file, int line, const char* msg) {
60 fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg);
61 exit(-5);
63 #undef assert
64 #define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
65 #endif
67 #else
69 #define DLOG(a)
71 #endif
73 /* dynamic array functions */
74 typedef struct array_t {
75 char* pointer;
76 unsigned int size,next,item_size;
77 } array_t;
79 static inline void array_init(array_t* array,unsigned int item_size)
81 array->pointer=0;
82 array->size=0;
83 array->next=0;
84 array->item_size=item_size;
87 static inline void array_free(array_t* array)
89 if(array->pointer)
90 free(array->pointer);
91 array->size=array->next=0;
94 /* does not automatically grow */
95 static inline void* array_get(array_t* array,unsigned int index) {
96 assert(index >= 0);
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);
106 if (!array->pointer)
107 return -1;
108 array->size = new_size;
109 array->next = index + 1;
112 return 0;
115 static inline void* array_get_next(array_t* array) {
116 unsigned int next = array->next;
117 void* result;
119 if (array_ensure_allocated(array, next) < 0)
120 return NULL;
122 array->next = next + 1;
123 result = array_get(array, next);
125 return result;
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);
132 if(!array->pointer)
133 return 0;
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);
139 array->next+=count;
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)
147 char* buf;
148 char* from;
149 char* to;
150 int is;
152 if(!array ||
153 index_to<0 || index_to>=array->next ||
154 index_from<0 || index_from>=array->next)
155 return -1;
157 if(index_to==index_from)
158 return 0;
160 is=array->item_size;
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);
168 else
169 memmove(from,from+is*count,to-from);
171 memcpy(to,buf,is*count);
173 free(buf);
175 return 0;
178 static inline int array_remove_slice(array_t* array,int index, int count)
180 assert(index >=0);
181 assert(count > 0);
182 assert(index + count <= array->next);
183 if(array_roll(array,array->next-1,index,count))
184 return -1;
185 array->next -= count;
186 return 0;
189 static 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 static int array_index(array_t* array, void* pointer)
197 size_t offset = (char*)pointer - array->pointer;
198 assert(offset >= 0);
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 {
208 uint8_t jump[3];
209 uint8_t name[8];
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;
216 uint8_t media_type;
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;
222 union {
223 struct {
224 uint8_t drive_number;
225 uint8_t current_head;
226 uint8_t signature;
227 uint32_t id;
228 uint8_t volume_label[11];
229 } __attribute__((packed)) fat16;
230 struct {
231 uint32_t sectors_per_fat;
232 uint16_t flags;
233 uint8_t major,minor;
234 uint32_t first_cluster_of_root_directory;
235 uint16_t info_sector;
236 uint16_t backup_boot_sector;
237 uint16_t ignored;
238 } __attribute__((packed)) fat32;
239 } u;
240 uint8_t fat_type[8];
241 uint8_t ignored[0x1c0];
242 uint8_t magic[2];
243 } __attribute__((packed)) bootsector_t;
245 typedef struct {
246 uint8_t head;
247 uint8_t sector;
248 uint8_t cylinder;
249 } mbr_chs_t;
251 typedef struct partition_t {
252 uint8_t attributes; /* 0x80 = bootable */
253 mbr_chs_t start_CHS;
254 uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
255 mbr_chs_t end_CHS;
256 uint32_t start_sector_long;
257 uint32_t length_sector_long;
258 } __attribute__((packed)) partition_t;
260 typedef struct mbr_t {
261 uint8_t ignored[0x1b8];
262 uint32_t nt_id;
263 uint8_t ignored2[2];
264 partition_t partition[4];
265 uint8_t magic[2];
266 } __attribute__((packed)) mbr_t;
268 typedef struct direntry_t {
269 uint8_t name[8];
270 uint8_t extension[3];
271 uint8_t attributes;
272 uint8_t reserved[2];
273 uint16_t ctime;
274 uint16_t cdate;
275 uint16_t adate;
276 uint16_t begin_hi;
277 uint16_t mtime;
278 uint16_t mdate;
279 uint16_t begin;
280 uint32_t size;
281 } __attribute__((packed)) direntry_t;
283 /* this structure are used to transparently access the files */
285 typedef struct mapping_t {
286 /* begin is the first cluster, end is the last+1 */
287 uint32_t begin,end;
288 /* as s->directory is growable, no pointer may be used here */
289 unsigned int dir_index;
290 /* the clusters of a file may be in any order; this points to the first */
291 int first_mapping_index;
292 union {
293 /* offset is
294 * - the offset in the file (in clusters) for a file, or
295 * - the next cluster of the directory for a directory, and
296 * - the address of the buffer for a faked entry
298 struct {
299 uint32_t offset;
300 } file;
301 struct {
302 int parent_mapping_index;
303 int first_dir_index;
304 } dir;
305 } info;
306 /* path contains the full path, i.e. it always starts with s->path */
307 char* path;
309 enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2,
310 MODE_DIRECTORY = 4, MODE_FAKED = 8,
311 MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
312 int read_only;
313 } mapping_t;
315 #ifdef DEBUG
316 static void print_direntry(const struct direntry_t*);
317 static void print_mapping(const struct mapping_t* mapping);
318 #endif
320 /* here begins the real VVFAT driver */
322 typedef struct BDRVVVFATState {
323 BlockDriverState* bs; /* pointer to parent */
324 unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
325 unsigned char first_sectors[0x40*0x200];
327 int fat_type; /* 16 or 32 */
328 array_t fat,directory,mapping;
330 unsigned int cluster_size;
331 unsigned int sectors_per_cluster;
332 unsigned int sectors_per_fat;
333 unsigned int sectors_of_root_directory;
334 uint32_t last_cluster_of_root_directory;
335 unsigned int faked_sectors; /* how many sectors are faked before file data */
336 uint32_t sector_count; /* total number of sectors of the partition */
337 uint32_t cluster_count; /* total number of clusters of this partition */
338 uint32_t max_fat_value;
340 int current_fd;
341 mapping_t* current_mapping;
342 unsigned char* cluster; /* points to current cluster */
343 unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
344 unsigned int current_cluster;
346 /* write support */
347 BlockDriverState* write_target;
348 char* qcow_filename;
349 BlockDriverState* qcow;
350 void* fat2;
351 char* used_clusters;
352 array_t commits;
353 const char* path;
354 int downcase_short_names;
355 } BDRVVVFATState;
357 /* take the sector position spos and convert it to Cylinder/Head/Sector position
358 * if the position is outside the specified geometry, fill maximum value for CHS
359 * and return 1 to signal overflow.
361 static int sector2CHS(BlockDriverState* bs, mbr_chs_t * chs, int spos){
362 int head,sector;
363 sector = spos % (bs->secs); spos/= bs->secs;
364 head = spos % (bs->heads); spos/= bs->heads;
365 if(spos >= bs->cyls){
366 /* Overflow,
367 it happens if 32bit sector positions are used, while CHS is only 24bit.
368 Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
369 chs->head = 0xFF;
370 chs->sector = 0xFF;
371 chs->cylinder = 0xFF;
372 return 1;
374 chs->head = (uint8_t)head;
375 chs->sector = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
376 chs->cylinder = (uint8_t)spos;
377 return 0;
380 static void init_mbr(BDRVVVFATState* s)
382 /* TODO: if the files mbr.img and bootsect.img exist, use them */
383 mbr_t* real_mbr=(mbr_t*)s->first_sectors;
384 partition_t* partition=&(real_mbr->partition[0]);
385 int lba;
387 memset(s->first_sectors,0,512);
389 /* Win NT Disk Signature */
390 real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
392 partition->attributes=0x80; /* bootable */
394 /* LBA is used when partition is outside the CHS geometry */
395 lba = sector2CHS(s->bs, &partition->start_CHS, s->first_sectors_number-1);
396 lba|= sector2CHS(s->bs, &partition->end_CHS, s->sector_count);
398 /*LBA partitions are identified only by start/length_sector_long not by CHS*/
399 partition->start_sector_long =cpu_to_le32(s->first_sectors_number-1);
400 partition->length_sector_long=cpu_to_le32(s->sector_count - s->first_sectors_number+1);
402 /* FAT12/FAT16/FAT32 */
403 /* DOS uses different types when partition is LBA,
404 probably to prevent older versions from using CHS on them */
405 partition->fs_type= s->fat_type==12 ? 0x1:
406 s->fat_type==16 ? (lba?0xe:0x06):
407 /*fat_tyoe==32*/ (lba?0xc:0x0b);
409 real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
412 /* direntry functions */
414 /* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
415 static inline int short2long_name(char* dest,const char* src)
417 int i;
418 int len;
419 for(i=0;i<129 && src[i];i++) {
420 dest[2*i]=src[i];
421 dest[2*i+1]=0;
423 len=2*i;
424 dest[2*i]=dest[2*i+1]=0;
425 for(i=2*i+2;(i%26);i++)
426 dest[i]=0xff;
427 return len;
430 static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
432 char buffer[258];
433 int length=short2long_name(buffer,filename),
434 number_of_entries=(length+25)/26,i;
435 direntry_t* entry;
437 for(i=0;i<number_of_entries;i++) {
438 entry=array_get_next(&(s->directory));
439 entry->attributes=0xf;
440 entry->reserved[0]=0;
441 entry->begin=0;
442 entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
444 for(i=0;i<26*number_of_entries;i++) {
445 int offset=(i%26);
446 if(offset<10) offset=1+offset;
447 else if(offset<22) offset=14+offset-10;
448 else offset=28+offset-22;
449 entry=array_get(&(s->directory),s->directory.next-1-(i/26));
450 entry->name[offset]=buffer[i];
452 return array_get(&(s->directory),s->directory.next-number_of_entries);
455 static char is_free(const direntry_t* direntry)
457 /* return direntry->name[0]==0 ; */
458 return direntry->attributes == 0 || direntry->name[0]==0xe5;
461 static char is_volume_label(const direntry_t* direntry)
463 return direntry->attributes == 0x28;
466 static char is_long_name(const direntry_t* direntry)
468 return direntry->attributes == 0xf;
471 static char is_short_name(const direntry_t* direntry)
473 return !is_volume_label(direntry) && !is_long_name(direntry)
474 && !is_free(direntry);
477 static char is_directory(const direntry_t* direntry)
479 return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
482 static inline char is_dot(const direntry_t* direntry)
484 return is_short_name(direntry) && direntry->name[0] == '.';
487 static char is_file(const direntry_t* direntry)
489 return is_short_name(direntry) && !is_directory(direntry);
492 static inline uint32_t begin_of_direntry(const direntry_t* direntry)
494 return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
497 static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
499 return le32_to_cpu(direntry->size);
502 static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
504 direntry->begin = cpu_to_le16(begin & 0xffff);
505 direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
508 /* fat functions */
510 static inline uint8_t fat_chksum(const direntry_t* entry)
512 uint8_t chksum=0;
513 int i;
515 for(i=0;i<11;i++)
516 chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0))
517 +(unsigned char)entry->name[i];
519 return chksum;
522 /* if return_time==0, this returns the fat_date, else the fat_time */
523 static uint16_t fat_datetime(time_t time,int return_time) {
524 struct tm* t;
525 #ifdef _WIN32
526 t=localtime(&time); /* this is not thread safe */
527 #else
528 struct tm t1;
529 t=&t1;
530 localtime_r(&time,t);
531 #endif
532 if(return_time)
533 return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
534 return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
537 static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
539 if(s->fat_type==32) {
540 uint32_t* entry=array_get(&(s->fat),cluster);
541 *entry=cpu_to_le32(value);
542 } else if(s->fat_type==16) {
543 uint16_t* entry=array_get(&(s->fat),cluster);
544 *entry=cpu_to_le16(value&0xffff);
545 } else {
546 int offset = (cluster*3/2);
547 unsigned char* p = array_get(&(s->fat), offset);
548 switch (cluster&1) {
549 case 0:
550 p[0] = value&0xff;
551 p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
552 break;
553 case 1:
554 p[0] = (p[0]&0xf) | ((value&0xf)<<4);
555 p[1] = (value>>4);
556 break;
561 static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
563 if(s->fat_type==32) {
564 uint32_t* entry=array_get(&(s->fat),cluster);
565 return le32_to_cpu(*entry);
566 } else if(s->fat_type==16) {
567 uint16_t* entry=array_get(&(s->fat),cluster);
568 return le16_to_cpu(*entry);
569 } else {
570 const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
571 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
575 static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
577 if(fat_entry>s->max_fat_value-8)
578 return -1;
579 return 0;
582 static inline void init_fat(BDRVVVFATState* s)
584 if (s->fat_type == 12) {
585 array_init(&(s->fat),1);
586 array_ensure_allocated(&(s->fat),
587 s->sectors_per_fat * 0x200 * 3 / 2 - 1);
588 } else {
589 array_init(&(s->fat),(s->fat_type==32?4:2));
590 array_ensure_allocated(&(s->fat),
591 s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
593 memset(s->fat.pointer,0,s->fat.size);
595 switch(s->fat_type) {
596 case 12: s->max_fat_value=0xfff; break;
597 case 16: s->max_fat_value=0xffff; break;
598 case 32: s->max_fat_value=0x0fffffff; break;
599 default: s->max_fat_value=0; /* error... */
604 /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
605 /* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
606 static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
607 unsigned int directory_start, const char* filename, int is_dot)
609 int i,j,long_index=s->directory.next;
610 direntry_t* entry=0;
611 direntry_t* entry_long=0;
613 if(is_dot) {
614 entry=array_get_next(&(s->directory));
615 memset(entry->name,0x20,11);
616 memcpy(entry->name,filename,strlen(filename));
617 return entry;
620 entry_long=create_long_filename(s,filename);
622 i = strlen(filename);
623 for(j = i - 1; j>0 && filename[j]!='.';j--);
624 if (j > 0)
625 i = (j > 8 ? 8 : j);
626 else if (i > 8)
627 i = 8;
629 entry=array_get_next(&(s->directory));
630 memset(entry->name,0x20,11);
631 strncpy((char*)entry->name,filename,i);
633 if(j > 0)
634 for (i = 0; i < 3 && filename[j+1+i]; i++)
635 entry->extension[i] = filename[j+1+i];
637 /* upcase & remove unwanted characters */
638 for(i=10;i>=0;i--) {
639 if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
640 if(entry->name[i]<=' ' || entry->name[i]>0x7f
641 || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
642 entry->name[i]='_';
643 else if(entry->name[i]>='a' && entry->name[i]<='z')
644 entry->name[i]+='A'-'a';
647 /* mangle duplicates */
648 while(1) {
649 direntry_t* entry1=array_get(&(s->directory),directory_start);
650 int j;
652 for(;entry1<entry;entry1++)
653 if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
654 break; /* found dupe */
655 if(entry1==entry) /* no dupe found */
656 break;
658 /* use all 8 characters of name */
659 if(entry->name[7]==' ') {
660 int j;
661 for(j=6;j>0 && entry->name[j]==' ';j--)
662 entry->name[j]='~';
665 /* increment number */
666 for(j=7;j>0 && entry->name[j]=='9';j--)
667 entry->name[j]='0';
668 if(j>0) {
669 if(entry->name[j]<'0' || entry->name[j]>'9')
670 entry->name[j]='0';
671 else
672 entry->name[j]++;
676 /* calculate checksum; propagate to long name */
677 if(entry_long) {
678 uint8_t chksum=fat_chksum(entry);
680 /* calculate anew, because realloc could have taken place */
681 entry_long=array_get(&(s->directory),long_index);
682 while(entry_long<entry && is_long_name(entry_long)) {
683 entry_long->reserved[1]=chksum;
684 entry_long++;
688 return entry;
692 * Read a directory. (the index of the corresponding mapping must be passed).
694 static int read_directory(BDRVVVFATState* s, int mapping_index)
696 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
697 direntry_t* direntry;
698 const char* dirname = mapping->path;
699 int first_cluster = mapping->begin;
700 int parent_index = mapping->info.dir.parent_mapping_index;
701 mapping_t* parent_mapping = (mapping_t*)
702 (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : 0);
703 int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
705 DIR* dir=opendir(dirname);
706 struct dirent* entry;
707 int i;
709 assert(mapping->mode & MODE_DIRECTORY);
711 if(!dir) {
712 mapping->end = mapping->begin;
713 return -1;
716 i = mapping->info.dir.first_dir_index =
717 first_cluster == 0 ? 0 : s->directory.next;
719 /* actually read the directory, and allocate the mappings */
720 while((entry=readdir(dir))) {
721 unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
722 char* buffer;
723 direntry_t* direntry;
724 struct stat st;
725 int is_dot=!strcmp(entry->d_name,".");
726 int is_dotdot=!strcmp(entry->d_name,"..");
728 if(first_cluster == 0 && (is_dotdot || is_dot))
729 continue;
731 buffer=(char*)malloc(length);
732 assert(buffer);
733 snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
735 if(stat(buffer,&st)<0) {
736 free(buffer);
737 continue;
740 /* create directory entry for this file */
741 direntry=create_short_and_long_name(s, i, entry->d_name,
742 is_dot || is_dotdot);
743 direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
744 direntry->reserved[0]=direntry->reserved[1]=0;
745 direntry->ctime=fat_datetime(st.st_ctime,1);
746 direntry->cdate=fat_datetime(st.st_ctime,0);
747 direntry->adate=fat_datetime(st.st_atime,0);
748 direntry->begin_hi=0;
749 direntry->mtime=fat_datetime(st.st_mtime,1);
750 direntry->mdate=fat_datetime(st.st_mtime,0);
751 if(is_dotdot)
752 set_begin_of_direntry(direntry, first_cluster_of_parent);
753 else if(is_dot)
754 set_begin_of_direntry(direntry, first_cluster);
755 else
756 direntry->begin=0; /* do that later */
757 if (st.st_size > 0x7fffffff) {
758 fprintf(stderr, "File %s is larger than 2GB\n", buffer);
759 free(buffer);
760 return -2;
762 direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
764 /* create mapping for this file */
765 if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
766 s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
767 s->current_mapping->begin=0;
768 s->current_mapping->end=st.st_size;
770 * we get the direntry of the most recent direntry, which
771 * contains the short name and all the relevant information.
773 s->current_mapping->dir_index=s->directory.next-1;
774 s->current_mapping->first_mapping_index = -1;
775 if (S_ISDIR(st.st_mode)) {
776 s->current_mapping->mode = MODE_DIRECTORY;
777 s->current_mapping->info.dir.parent_mapping_index =
778 mapping_index;
779 } else {
780 s->current_mapping->mode = MODE_UNDEFINED;
781 s->current_mapping->info.file.offset = 0;
783 s->current_mapping->path=buffer;
784 s->current_mapping->read_only =
785 (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
788 closedir(dir);
790 /* fill with zeroes up to the end of the cluster */
791 while(s->directory.next%(0x10*s->sectors_per_cluster)) {
792 direntry_t* direntry=array_get_next(&(s->directory));
793 memset(direntry,0,sizeof(direntry_t));
796 /* TODO: if there are more entries, bootsector has to be adjusted! */
797 #define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
798 if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
799 /* root directory */
800 int cur = s->directory.next;
801 array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
802 memset(array_get(&(s->directory), cur), 0,
803 (ROOT_ENTRIES - cur) * sizeof(direntry_t));
806 /* reget the mapping, since s->mapping was possibly realloc()ed */
807 mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
808 first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
809 * 0x20 / s->cluster_size;
810 mapping->end = first_cluster;
812 direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
813 set_begin_of_direntry(direntry, mapping->begin);
815 return 0;
818 static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
820 return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
823 static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
825 return s->faked_sectors + s->sectors_per_cluster * cluster_num;
828 static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
830 return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
833 #ifdef DBG
834 static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
836 if(mapping->mode==MODE_UNDEFINED)
837 return 0;
838 return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
840 #endif
842 static int init_directories(BDRVVVFATState* s,
843 const char* dirname)
845 bootsector_t* bootsector;
846 mapping_t* mapping;
847 unsigned int i;
848 unsigned int cluster;
850 memset(&(s->first_sectors[0]),0,0x40*0x200);
852 s->cluster_size=s->sectors_per_cluster*0x200;
853 s->cluster_buffer=malloc(s->cluster_size);
854 assert(s->cluster_buffer);
857 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
858 * where sc is sector_count,
859 * spf is sectors_per_fat,
860 * spc is sectors_per_clusters, and
861 * fat_type = 12, 16 or 32.
863 i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
864 s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
866 array_init(&(s->mapping),sizeof(mapping_t));
867 array_init(&(s->directory),sizeof(direntry_t));
869 /* add volume label */
871 direntry_t* entry=array_get_next(&(s->directory));
872 entry->attributes=0x28; /* archive | volume label */
873 snprintf((char*)entry->name,11,"QEMU VVFAT");
876 /* Now build FAT, and write back information into directory */
877 init_fat(s);
879 s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
880 s->cluster_count=sector2cluster(s, s->sector_count);
882 mapping = array_get_next(&(s->mapping));
883 mapping->begin = 0;
884 mapping->dir_index = 0;
885 mapping->info.dir.parent_mapping_index = -1;
886 mapping->first_mapping_index = -1;
887 mapping->path = strdup(dirname);
888 i = strlen(mapping->path);
889 if (i > 0 && mapping->path[i - 1] == '/')
890 mapping->path[i - 1] = '\0';
891 mapping->mode = MODE_DIRECTORY;
892 mapping->read_only = 0;
893 s->path = mapping->path;
895 for (i = 0, cluster = 0; i < s->mapping.next; i++) {
896 int j;
897 /* MS-DOS expects the FAT to be 0 for the root directory
898 * (except for the media byte). */
899 /* LATER TODO: still true for FAT32? */
900 int fix_fat = (i != 0);
901 mapping = array_get(&(s->mapping), i);
903 if (mapping->mode & MODE_DIRECTORY) {
904 mapping->begin = cluster;
905 if(read_directory(s, i)) {
906 fprintf(stderr, "Could not read directory %s\n",
907 mapping->path);
908 return -1;
910 mapping = array_get(&(s->mapping), i);
911 } else {
912 assert(mapping->mode == MODE_UNDEFINED);
913 mapping->mode=MODE_NORMAL;
914 mapping->begin = cluster;
915 if (mapping->end > 0) {
916 direntry_t* direntry = array_get(&(s->directory),
917 mapping->dir_index);
919 mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
920 set_begin_of_direntry(direntry, mapping->begin);
921 } else {
922 mapping->end = cluster + 1;
923 fix_fat = 0;
927 assert(mapping->begin < mapping->end);
929 /* fix fat for entry */
930 if (fix_fat) {
931 for(j = mapping->begin; j < mapping->end - 1; j++)
932 fat_set(s, j, j+1);
933 fat_set(s, mapping->end - 1, s->max_fat_value);
936 /* next free cluster */
937 cluster = mapping->end;
939 if(cluster > s->cluster_count) {
940 fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type);
941 return -1;
945 mapping = array_get(&(s->mapping), 0);
946 s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
947 s->last_cluster_of_root_directory = mapping->end;
949 /* the FAT signature */
950 fat_set(s,0,s->max_fat_value);
951 fat_set(s,1,s->max_fat_value);
953 s->current_mapping = NULL;
955 bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
956 bootsector->jump[0]=0xeb;
957 bootsector->jump[1]=0x3e;
958 bootsector->jump[2]=0x90;
959 memcpy(bootsector->name,"QEMU ",8);
960 bootsector->sector_size=cpu_to_le16(0x200);
961 bootsector->sectors_per_cluster=s->sectors_per_cluster;
962 bootsector->reserved_sectors=cpu_to_le16(1);
963 bootsector->number_of_fats=0x2; /* number of FATs */
964 bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
965 bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
966 bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
967 s->fat.pointer[0] = bootsector->media_type;
968 bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
969 bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
970 bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
971 bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
972 bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
974 /* LATER TODO: if FAT32, this is wrong */
975 bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
976 bootsector->u.fat16.current_head=0;
977 bootsector->u.fat16.signature=0x29;
978 bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
980 memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
981 memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12 ":s->fat_type==16?"FAT16 ":"FAT32 "),8);
982 bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
984 return 0;
987 #ifdef DEBUG
988 static BDRVVVFATState *vvv = NULL;
989 #endif
991 static int enable_write_target(BDRVVVFATState *s);
992 static int is_consistent(BDRVVVFATState *s);
994 static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
996 BDRVVVFATState *s = bs->opaque;
997 int floppy = 0;
998 int i;
1000 #ifdef DEBUG
1001 vvv = s;
1002 #endif
1004 DLOG(if (stderr == NULL) {
1005 stderr = fopen("vvfat.log", "a");
1006 setbuf(stderr, NULL);
1009 s->bs = bs;
1011 s->fat_type=16;
1012 /* LATER TODO: if FAT32, adjust */
1013 s->sectors_per_cluster=0x10;
1014 /* 504MB disk*/
1015 bs->cyls=1024; bs->heads=16; bs->secs=63;
1017 s->current_cluster=0xffffffff;
1019 s->first_sectors_number=0x40;
1020 /* read only is the default for safety */
1021 bs->read_only = 1;
1022 s->qcow = s->write_target = NULL;
1023 s->qcow_filename = NULL;
1024 s->fat2 = NULL;
1025 s->downcase_short_names = 1;
1027 if (!strstart(dirname, "fat:", NULL))
1028 return -1;
1030 if (strstr(dirname, ":floppy:")) {
1031 floppy = 1;
1032 s->fat_type = 12;
1033 s->first_sectors_number = 1;
1034 s->sectors_per_cluster=2;
1035 bs->cyls = 80; bs->heads = 2; bs->secs = 36;
1038 s->sector_count=bs->cyls*bs->heads*bs->secs;
1040 if (strstr(dirname, ":32:")) {
1041 fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1042 s->fat_type = 32;
1043 } else if (strstr(dirname, ":16:")) {
1044 s->fat_type = 16;
1045 } else if (strstr(dirname, ":12:")) {
1046 s->fat_type = 12;
1047 s->sector_count=2880;
1050 if (strstr(dirname, ":rw:")) {
1051 if (enable_write_target(s))
1052 return -1;
1053 bs->read_only = 0;
1056 i = strrchr(dirname, ':') - dirname;
1057 assert(i >= 3);
1058 if (dirname[i-2] == ':' && isalpha(dirname[i-1]))
1059 /* workaround for DOS drive names */
1060 dirname += i-1;
1061 else
1062 dirname += i+1;
1064 bs->total_sectors=bs->cyls*bs->heads*bs->secs;
1066 if(init_directories(s, dirname))
1067 return -1;
1069 s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
1071 if(s->first_sectors_number==0x40)
1072 init_mbr(s);
1074 /* for some reason or other, MS-DOS does not like to know about CHS... */
1075 if (floppy)
1076 bs->heads = bs->cyls = bs->secs = 0;
1078 // assert(is_consistent(s));
1079 return 0;
1082 static inline void vvfat_close_current_file(BDRVVVFATState *s)
1084 if(s->current_mapping) {
1085 s->current_mapping = NULL;
1086 if (s->current_fd) {
1087 close(s->current_fd);
1088 s->current_fd = 0;
1091 s->current_cluster = -1;
1094 /* mappings between index1 and index2-1 are supposed to be ordered
1095 * return value is the index of the last mapping for which end>cluster_num
1097 static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1099 int index3=index1+1;
1100 while(1) {
1101 mapping_t* mapping;
1102 index3=(index1+index2)/2;
1103 mapping=array_get(&(s->mapping),index3);
1104 assert(mapping->begin < mapping->end);
1105 if(mapping->begin>=cluster_num) {
1106 assert(index2!=index3 || index2==0);
1107 if(index2==index3)
1108 return index1;
1109 index2=index3;
1110 } else {
1111 if(index1==index3)
1112 return mapping->end<=cluster_num ? index2 : index1;
1113 index1=index3;
1115 assert(index1<=index2);
1116 DLOG(mapping=array_get(&(s->mapping),index1);
1117 assert(mapping->begin<=cluster_num);
1118 assert(index2 >= s->mapping.next ||
1119 ((mapping = array_get(&(s->mapping),index2)) &&
1120 mapping->end>cluster_num)));
1124 static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
1126 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
1127 mapping_t* mapping;
1128 if(index>=s->mapping.next)
1129 return 0;
1130 mapping=array_get(&(s->mapping),index);
1131 if(mapping->begin>cluster_num)
1132 return 0;
1133 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
1134 return mapping;
1138 * This function simply compares path == mapping->path. Since the mappings
1139 * are sorted by cluster, this is expensive: O(n).
1141 static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
1142 const char* path)
1144 int i;
1146 for (i = 0; i < s->mapping.next; i++) {
1147 mapping_t* mapping = array_get(&(s->mapping), i);
1148 if (mapping->first_mapping_index < 0 &&
1149 !strcmp(path, mapping->path))
1150 return mapping;
1153 return NULL;
1156 static int open_file(BDRVVVFATState* s,mapping_t* mapping)
1158 if(!mapping)
1159 return -1;
1160 if(!s->current_mapping ||
1161 strcmp(s->current_mapping->path,mapping->path)) {
1162 /* open file */
1163 int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
1164 if(fd<0)
1165 return -1;
1166 vvfat_close_current_file(s);
1167 s->current_fd = fd;
1168 s->current_mapping = mapping;
1170 return 0;
1173 static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1175 if(s->current_cluster != cluster_num) {
1176 int result=0;
1177 off_t offset;
1178 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
1179 if(!s->current_mapping
1180 || s->current_mapping->begin>cluster_num
1181 || s->current_mapping->end<=cluster_num) {
1182 /* binary search of mappings for file */
1183 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
1185 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1187 if (mapping && mapping->mode & MODE_DIRECTORY) {
1188 vvfat_close_current_file(s);
1189 s->current_mapping = mapping;
1190 read_cluster_directory:
1191 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
1192 s->cluster = (unsigned char*)s->directory.pointer+offset
1193 + 0x20*s->current_mapping->info.dir.first_dir_index;
1194 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1195 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1196 s->current_cluster = cluster_num;
1197 return 0;
1200 if(open_file(s,mapping))
1201 return -2;
1202 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1203 goto read_cluster_directory;
1205 assert(s->current_fd);
1207 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
1208 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1209 return -3;
1210 s->cluster=s->cluster_buffer;
1211 result=read(s->current_fd,s->cluster,s->cluster_size);
1212 if(result<0) {
1213 s->current_cluster = -1;
1214 return -1;
1216 s->current_cluster = cluster_num;
1218 return 0;
1221 #ifdef DEBUG
1222 static void hexdump(const void* address, uint32_t len)
1224 const unsigned char* p = address;
1225 int i, j;
1227 for (i = 0; i < len; i += 16) {
1228 for (j = 0; j < 16 && i + j < len; j++)
1229 fprintf(stderr, "%02x ", p[i + j]);
1230 for (; j < 16; j++)
1231 fprintf(stderr, " ");
1232 fprintf(stderr, " ");
1233 for (j = 0; j < 16 && i + j < len; j++)
1234 fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
1235 fprintf(stderr, "\n");
1239 static void print_direntry(const direntry_t* direntry)
1241 int j = 0;
1242 char buffer[1024];
1244 fprintf(stderr, "direntry 0x%x: ", (int)direntry);
1245 if(!direntry)
1246 return;
1247 if(is_long_name(direntry)) {
1248 unsigned char* c=(unsigned char*)direntry;
1249 int i;
1250 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
1251 #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = '°'; j++;}
1252 ADD_CHAR(c[i]);
1253 for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
1254 ADD_CHAR(c[i]);
1255 for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
1256 ADD_CHAR(c[i]);
1257 buffer[j] = 0;
1258 fprintf(stderr, "%s\n", buffer);
1259 } else {
1260 int i;
1261 for(i=0;i<11;i++)
1262 ADD_CHAR(direntry->name[i]);
1263 buffer[j] = 0;
1264 fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1265 buffer,
1266 direntry->attributes,
1267 begin_of_direntry(direntry),le32_to_cpu(direntry->size));
1271 static void print_mapping(const mapping_t* mapping)
1273 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);
1274 if (mapping->mode & MODE_DIRECTORY)
1275 fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1276 else
1277 fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
1279 #endif
1281 static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
1282 uint8_t *buf, int nb_sectors)
1284 BDRVVVFATState *s = bs->opaque;
1285 int i;
1287 for(i=0;i<nb_sectors;i++,sector_num++) {
1288 if (sector_num >= s->sector_count)
1289 return -1;
1290 if (s->qcow) {
1291 int n;
1292 if (s->qcow->drv->bdrv_is_allocated(s->qcow,
1293 sector_num, nb_sectors-i, &n)) {
1294 DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
1295 if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
1296 return -1;
1297 i += n - 1;
1298 sector_num += n - 1;
1299 continue;
1301 DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
1303 if(sector_num<s->faked_sectors) {
1304 if(sector_num<s->first_sectors_number)
1305 memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
1306 else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
1307 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
1308 else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
1309 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
1310 } else {
1311 uint32_t sector=sector_num-s->faked_sectors,
1312 sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1313 cluster_num=sector/s->sectors_per_cluster;
1314 if(read_cluster(s, cluster_num) != 0) {
1315 /* LATER TODO: strict: return -1; */
1316 memset(buf+i*0x200,0,0x200);
1317 continue;
1319 memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
1322 return 0;
1325 /* LATER TODO: statify all functions */
1328 * Idea of the write support (use snapshot):
1330 * 1. check if all data is consistent, recording renames, modifications,
1331 * new files and directories (in s->commits).
1333 * 2. if the data is not consistent, stop committing
1335 * 3. handle renames, and create new files and directories (do not yet
1336 * write their contents)
1338 * 4. walk the directories, fixing the mapping and direntries, and marking
1339 * the handled mappings as not deleted
1341 * 5. commit the contents of the files
1343 * 6. handle deleted files and directories
1347 typedef struct commit_t {
1348 char* path;
1349 union {
1350 struct { uint32_t cluster; } rename;
1351 struct { int dir_index; uint32_t modified_offset; } writeout;
1352 struct { uint32_t first_cluster; } new_file;
1353 struct { uint32_t cluster; } mkdir;
1354 } param;
1355 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1356 enum {
1357 ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1358 } action;
1359 } commit_t;
1361 static void clear_commits(BDRVVVFATState* s)
1363 int i;
1364 DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1365 for (i = 0; i < s->commits.next; i++) {
1366 commit_t* commit = array_get(&(s->commits), i);
1367 assert(commit->path || commit->action == ACTION_WRITEOUT);
1368 if (commit->action != ACTION_WRITEOUT) {
1369 assert(commit->path);
1370 free(commit->path);
1371 } else
1372 assert(commit->path == NULL);
1374 s->commits.next = 0;
1377 static void schedule_rename(BDRVVVFATState* s,
1378 uint32_t cluster, char* new_path)
1380 commit_t* commit = array_get_next(&(s->commits));
1381 commit->path = new_path;
1382 commit->param.rename.cluster = cluster;
1383 commit->action = ACTION_RENAME;
1386 static void schedule_writeout(BDRVVVFATState* s,
1387 int dir_index, uint32_t modified_offset)
1389 commit_t* commit = array_get_next(&(s->commits));
1390 commit->path = NULL;
1391 commit->param.writeout.dir_index = dir_index;
1392 commit->param.writeout.modified_offset = modified_offset;
1393 commit->action = ACTION_WRITEOUT;
1396 static void schedule_new_file(BDRVVVFATState* s,
1397 char* path, uint32_t first_cluster)
1399 commit_t* commit = array_get_next(&(s->commits));
1400 commit->path = path;
1401 commit->param.new_file.first_cluster = first_cluster;
1402 commit->action = ACTION_NEW_FILE;
1405 static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1407 commit_t* commit = array_get_next(&(s->commits));
1408 commit->path = path;
1409 commit->param.mkdir.cluster = cluster;
1410 commit->action = ACTION_MKDIR;
1413 typedef struct {
1414 unsigned char name[1024];
1415 int checksum, len;
1416 int sequence_number;
1417 } long_file_name;
1419 static void lfn_init(long_file_name* lfn)
1421 lfn->sequence_number = lfn->len = 0;
1422 lfn->checksum = 0x100;
1425 /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1426 static int parse_long_name(long_file_name* lfn,
1427 const direntry_t* direntry)
1429 int i, j, offset;
1430 const unsigned char* pointer = (const unsigned char*)direntry;
1432 if (!is_long_name(direntry))
1433 return 1;
1435 if (pointer[0] & 0x40) {
1436 lfn->sequence_number = pointer[0] & 0x3f;
1437 lfn->checksum = pointer[13];
1438 lfn->name[0] = 0;
1439 } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
1440 return -1;
1441 else if (pointer[13] != lfn->checksum)
1442 return -2;
1443 else if (pointer[12] || pointer[26] || pointer[27])
1444 return -3;
1446 offset = 13 * (lfn->sequence_number - 1);
1447 for (i = 0, j = 1; i < 13; i++, j+=2) {
1448 if (j == 11)
1449 j = 14;
1450 else if (j == 26)
1451 j = 28;
1453 if (pointer[j+1] == 0)
1454 lfn->name[offset + i] = pointer[j];
1455 else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1456 return -4;
1457 else
1458 lfn->name[offset + i] = 0;
1461 if (pointer[0] & 0x40)
1462 lfn->len = offset + strlen((char*)lfn->name + offset);
1464 return 0;
1467 /* returns 0 if successful, >0 if no short_name, and <0 on error */
1468 static int parse_short_name(BDRVVVFATState* s,
1469 long_file_name* lfn, direntry_t* direntry)
1471 int i, j;
1473 if (!is_short_name(direntry))
1474 return 1;
1476 for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1477 for (i = 0; i <= j; i++) {
1478 if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
1479 return -1;
1480 else if (s->downcase_short_names)
1481 lfn->name[i] = tolower(direntry->name[i]);
1482 else
1483 lfn->name[i] = direntry->name[i];
1486 for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
1487 if (j >= 0) {
1488 lfn->name[i++] = '.';
1489 lfn->name[i + j + 1] = '\0';
1490 for (;j >= 0; j--) {
1491 if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
1492 return -2;
1493 else if (s->downcase_short_names)
1494 lfn->name[i + j] = tolower(direntry->extension[j]);
1495 else
1496 lfn->name[i + j] = direntry->extension[j];
1498 } else
1499 lfn->name[i + j + 1] = '\0';
1501 lfn->len = strlen((char*)lfn->name);
1503 return 0;
1506 static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1507 unsigned int cluster)
1509 if (cluster < s->last_cluster_of_root_directory) {
1510 if (cluster + 1 == s->last_cluster_of_root_directory)
1511 return s->max_fat_value;
1512 else
1513 return cluster + 1;
1516 if (s->fat_type==32) {
1517 uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1518 return le32_to_cpu(*entry);
1519 } else if (s->fat_type==16) {
1520 uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1521 return le16_to_cpu(*entry);
1522 } else {
1523 const uint8_t* x=s->fat2+cluster*3/2;
1524 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1528 static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1530 int was_modified = 0;
1531 int i, dummy;
1533 if (s->qcow == NULL)
1534 return 0;
1536 for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
1537 was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
1538 cluster2sector(s, cluster_num) + i, 1, &dummy);
1540 return was_modified;
1543 static const char* get_basename(const char* path)
1545 char* basename = strrchr(path, '/');
1546 if (basename == NULL)
1547 return path;
1548 else
1549 return basename + 1; /* strip '/' */
1553 * The array s->used_clusters holds the states of the clusters. If it is
1554 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1555 * was modified, bit 3 is set.
1556 * If any cluster is allocated, but not part of a file or directory, this
1557 * driver refuses to commit.
1559 typedef enum {
1560 USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
1561 } used_t;
1564 * get_cluster_count_for_direntry() not only determines how many clusters
1565 * are occupied by direntry, but also if it was renamed or modified.
1567 * A file is thought to be renamed *only* if there already was a file with
1568 * exactly the same first cluster, but a different name.
1570 * Further, the files/directories handled by this function are
1571 * assumed to be *not* deleted (and *only* those).
1573 static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
1574 direntry_t* direntry, const char* path)
1577 * This is a little bit tricky:
1578 * IF the guest OS just inserts a cluster into the file chain,
1579 * and leaves the rest alone, (i.e. the original file had clusters
1580 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1582 * - do_commit will write the cluster into the file at the given
1583 * offset, but
1585 * - the cluster which is overwritten should be moved to a later
1586 * position in the file.
1588 * I am not aware that any OS does something as braindead, but this
1589 * situation could happen anyway when not committing for a long time.
1590 * Just to be sure that this does not bite us, detect it, and copy the
1591 * contents of the clusters to-be-overwritten into the qcow.
1593 int copy_it = 0;
1594 int was_modified = 0;
1595 int32_t ret = 0;
1597 uint32_t cluster_num = begin_of_direntry(direntry);
1598 uint32_t offset = 0;
1599 int first_mapping_index = -1;
1600 mapping_t* mapping = NULL;
1601 const char* basename2 = NULL;
1603 vvfat_close_current_file(s);
1605 /* the root directory */
1606 if (cluster_num == 0)
1607 return 0;
1609 /* write support */
1610 if (s->qcow) {
1611 basename2 = get_basename(path);
1613 mapping = find_mapping_for_cluster(s, cluster_num);
1615 if (mapping) {
1616 const char* basename;
1618 assert(mapping->mode & MODE_DELETED);
1619 mapping->mode &= ~MODE_DELETED;
1621 basename = get_basename(mapping->path);
1623 assert(mapping->mode & MODE_NORMAL);
1625 /* rename */
1626 if (strcmp(basename, basename2))
1627 schedule_rename(s, cluster_num, strdup(path));
1628 } else if (is_file(direntry))
1629 /* new file */
1630 schedule_new_file(s, strdup(path), cluster_num);
1631 else {
1632 assert(0);
1633 return 0;
1637 while(1) {
1638 if (s->qcow) {
1639 if (!copy_it && cluster_was_modified(s, cluster_num)) {
1640 if (mapping == NULL ||
1641 mapping->begin > cluster_num ||
1642 mapping->end <= cluster_num)
1643 mapping = find_mapping_for_cluster(s, cluster_num);
1646 if (mapping &&
1647 (mapping->mode & MODE_DIRECTORY) == 0) {
1649 /* was modified in qcow */
1650 if (offset != mapping->info.file.offset + s->cluster_size
1651 * (cluster_num - mapping->begin)) {
1652 /* offset of this cluster in file chain has changed */
1653 assert(0);
1654 copy_it = 1;
1655 } else if (offset == 0) {
1656 const char* basename = get_basename(mapping->path);
1658 if (strcmp(basename, basename2))
1659 copy_it = 1;
1660 first_mapping_index = array_index(&(s->mapping), mapping);
1663 if (mapping->first_mapping_index != first_mapping_index
1664 && mapping->info.file.offset > 0) {
1665 assert(0);
1666 copy_it = 1;
1669 /* need to write out? */
1670 if (!was_modified && is_file(direntry)) {
1671 was_modified = 1;
1672 schedule_writeout(s, mapping->dir_index, offset);
1677 if (copy_it) {
1678 int i, dummy;
1680 * This is horribly inefficient, but that is okay, since
1681 * it is rarely executed, if at all.
1683 int64_t offset = cluster2sector(s, cluster_num);
1685 vvfat_close_current_file(s);
1686 for (i = 0; i < s->sectors_per_cluster; i++)
1687 if (!s->qcow->drv->bdrv_is_allocated(s->qcow,
1688 offset + i, 1, &dummy)) {
1689 if (vvfat_read(s->bs,
1690 offset, s->cluster_buffer, 1))
1691 return -1;
1692 if (s->qcow->drv->bdrv_write(s->qcow,
1693 offset, s->cluster_buffer, 1))
1694 return -2;
1699 ret++;
1700 if (s->used_clusters[cluster_num] & USED_ANY)
1701 return 0;
1702 s->used_clusters[cluster_num] = USED_FILE;
1704 cluster_num = modified_fat_get(s, cluster_num);
1706 if (fat_eof(s, cluster_num))
1707 return ret;
1708 else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
1709 return -1;
1711 offset += s->cluster_size;
1716 * This function looks at the modified data (qcow).
1717 * It returns 0 upon inconsistency or error, and the number of clusters
1718 * used by the directory, its subdirectories and their files.
1720 static int check_directory_consistency(BDRVVVFATState *s,
1721 int cluster_num, const char* path)
1723 int ret = 0;
1724 unsigned char* cluster = malloc(s->cluster_size);
1725 direntry_t* direntries = (direntry_t*)cluster;
1726 mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
1728 long_file_name lfn;
1729 int path_len = strlen(path);
1730 char path2[PATH_MAX];
1732 assert(path_len < PATH_MAX); /* len was tested before! */
1733 strcpy(path2, path);
1734 path2[path_len] = '/';
1735 path2[path_len + 1] = '\0';
1737 if (mapping) {
1738 const char* basename = get_basename(mapping->path);
1739 const char* basename2 = get_basename(path);
1741 assert(mapping->mode & MODE_DIRECTORY);
1743 assert(mapping->mode & MODE_DELETED);
1744 mapping->mode &= ~MODE_DELETED;
1746 if (strcmp(basename, basename2))
1747 schedule_rename(s, cluster_num, strdup(path));
1748 } else
1749 /* new directory */
1750 schedule_mkdir(s, cluster_num, strdup(path));
1752 lfn_init(&lfn);
1753 do {
1754 int i;
1755 int subret = 0;
1757 ret++;
1759 if (s->used_clusters[cluster_num] & USED_ANY) {
1760 fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
1761 return 0;
1763 s->used_clusters[cluster_num] = USED_DIRECTORY;
1765 DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
1766 subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
1767 s->sectors_per_cluster);
1768 if (subret) {
1769 fprintf(stderr, "Error fetching direntries\n");
1770 fail:
1771 free(cluster);
1772 return 0;
1775 for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
1776 int cluster_count;
1778 DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
1779 if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
1780 is_free(direntries + i))
1781 continue;
1783 subret = parse_long_name(&lfn, direntries + i);
1784 if (subret < 0) {
1785 fprintf(stderr, "Error in long name\n");
1786 goto fail;
1788 if (subret == 0 || is_free(direntries + i))
1789 continue;
1791 if (fat_chksum(direntries+i) != lfn.checksum) {
1792 subret = parse_short_name(s, &lfn, direntries + i);
1793 if (subret < 0) {
1794 fprintf(stderr, "Error in short name (%d)\n", subret);
1795 goto fail;
1797 if (subret > 0 || !strcmp((char*)lfn.name, ".")
1798 || !strcmp((char*)lfn.name, ".."))
1799 continue;
1801 lfn.checksum = 0x100; /* cannot use long name twice */
1803 if (path_len + 1 + lfn.len >= PATH_MAX) {
1804 fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
1805 goto fail;
1807 strcpy(path2 + path_len + 1, (char*)lfn.name);
1809 if (is_directory(direntries + i)) {
1810 if (begin_of_direntry(direntries + i) == 0) {
1811 DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
1812 goto fail;
1814 cluster_count = check_directory_consistency(s,
1815 begin_of_direntry(direntries + i), path2);
1816 if (cluster_count == 0) {
1817 DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
1818 goto fail;
1820 } else if (is_file(direntries + i)) {
1821 /* check file size with FAT */
1822 cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
1823 if (cluster_count !=
1824 (le32_to_cpu(direntries[i].size) + s->cluster_size
1825 - 1) / s->cluster_size) {
1826 DLOG(fprintf(stderr, "Cluster count mismatch\n"));
1827 goto fail;
1829 } else
1830 assert(0); /* cluster_count = 0; */
1832 ret += cluster_count;
1835 cluster_num = modified_fat_get(s, cluster_num);
1836 } while(!fat_eof(s, cluster_num));
1838 free(cluster);
1839 return ret;
1842 /* returns 1 on success */
1843 static int is_consistent(BDRVVVFATState* s)
1845 int i, check;
1846 int used_clusters_count = 0;
1848 DLOG(checkpoint());
1850 * - get modified FAT
1851 * - compare the two FATs (TODO)
1852 * - get buffer for marking used clusters
1853 * - recurse direntries from root (using bs->bdrv_read to make
1854 * sure to get the new data)
1855 * - check that the FAT agrees with the size
1856 * - count the number of clusters occupied by this directory and
1857 * its files
1858 * - check that the cumulative used cluster count agrees with the
1859 * FAT
1860 * - if all is fine, return number of used clusters
1862 if (s->fat2 == NULL) {
1863 int size = 0x200 * s->sectors_per_fat;
1864 s->fat2 = malloc(size);
1865 memcpy(s->fat2, s->fat.pointer, size);
1867 check = vvfat_read(s->bs,
1868 s->first_sectors_number, s->fat2, s->sectors_per_fat);
1869 if (check) {
1870 fprintf(stderr, "Could not copy fat\n");
1871 return 0;
1873 assert (s->used_clusters);
1874 for (i = 0; i < sector2cluster(s, s->sector_count); i++)
1875 s->used_clusters[i] &= ~USED_ANY;
1877 clear_commits(s);
1879 /* mark every mapped file/directory as deleted.
1880 * (check_directory_consistency() will unmark those still present). */
1881 if (s->qcow)
1882 for (i = 0; i < s->mapping.next; i++) {
1883 mapping_t* mapping = array_get(&(s->mapping), i);
1884 if (mapping->first_mapping_index < 0)
1885 mapping->mode |= MODE_DELETED;
1888 used_clusters_count = check_directory_consistency(s, 0, s->path);
1889 if (used_clusters_count <= 0) {
1890 DLOG(fprintf(stderr, "problem in directory\n"));
1891 return 0;
1894 check = s->last_cluster_of_root_directory;
1895 for (i = check; i < sector2cluster(s, s->sector_count); i++) {
1896 if (modified_fat_get(s, i)) {
1897 if(!s->used_clusters[i]) {
1898 DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
1899 return 0;
1901 check++;
1904 if (s->used_clusters[i] == USED_ALLOCATED) {
1905 /* allocated, but not used... */
1906 DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
1907 return 0;
1911 if (check != used_clusters_count)
1912 return 0;
1914 return used_clusters_count;
1917 static inline void adjust_mapping_indices(BDRVVVFATState* s,
1918 int offset, int adjust)
1920 int i;
1922 for (i = 0; i < s->mapping.next; i++) {
1923 mapping_t* mapping = array_get(&(s->mapping), i);
1925 #define ADJUST_MAPPING_INDEX(name) \
1926 if (mapping->name >= offset) \
1927 mapping->name += adjust
1929 ADJUST_MAPPING_INDEX(first_mapping_index);
1930 if (mapping->mode & MODE_DIRECTORY)
1931 ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
1935 /* insert or update mapping */
1936 static mapping_t* insert_mapping(BDRVVVFATState* s,
1937 uint32_t begin, uint32_t end)
1940 * - find mapping where mapping->begin >= begin,
1941 * - if mapping->begin > begin: insert
1942 * - adjust all references to mappings!
1943 * - else: adjust
1944 * - replace name
1946 int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
1947 mapping_t* mapping = NULL;
1948 mapping_t* first_mapping = array_get(&(s->mapping), 0);
1950 if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
1951 && mapping->begin < begin) {
1952 mapping->end = begin;
1953 index++;
1954 mapping = array_get(&(s->mapping), index);
1956 if (index >= s->mapping.next || mapping->begin > begin) {
1957 mapping = array_insert(&(s->mapping), index, 1);
1958 mapping->path = NULL;
1959 adjust_mapping_indices(s, index, +1);
1962 mapping->begin = begin;
1963 mapping->end = end;
1965 DLOG(mapping_t* next_mapping;
1966 assert(index + 1 >= s->mapping.next ||
1967 ((next_mapping = array_get(&(s->mapping), index + 1)) &&
1968 next_mapping->begin >= end)));
1970 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1971 s->current_mapping = array_get(&(s->mapping),
1972 s->current_mapping - first_mapping);
1974 return mapping;
1977 static int remove_mapping(BDRVVVFATState* s, int mapping_index)
1979 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
1980 mapping_t* first_mapping = array_get(&(s->mapping), 0);
1982 /* free mapping */
1983 if (mapping->first_mapping_index < 0)
1984 free(mapping->path);
1986 /* remove from s->mapping */
1987 array_remove(&(s->mapping), mapping_index);
1989 /* adjust all references to mappings */
1990 adjust_mapping_indices(s, mapping_index, -1);
1992 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1993 s->current_mapping = array_get(&(s->mapping),
1994 s->current_mapping - first_mapping);
1996 return 0;
1999 static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
2001 int i;
2002 for (i = 0; i < s->mapping.next; i++) {
2003 mapping_t* mapping = array_get(&(s->mapping), i);
2004 if (mapping->dir_index >= offset)
2005 mapping->dir_index += adjust;
2006 if ((mapping->mode & MODE_DIRECTORY) &&
2007 mapping->info.dir.first_dir_index >= offset)
2008 mapping->info.dir.first_dir_index += adjust;
2012 static direntry_t* insert_direntries(BDRVVVFATState* s,
2013 int dir_index, int count)
2016 * make room in s->directory,
2017 * adjust_dirindices
2019 direntry_t* result = array_insert(&(s->directory), dir_index, count);
2020 if (result == NULL)
2021 return NULL;
2022 adjust_dirindices(s, dir_index, count);
2023 return result;
2026 static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
2028 int ret = array_remove_slice(&(s->directory), dir_index, count);
2029 if (ret)
2030 return ret;
2031 adjust_dirindices(s, dir_index, -count);
2032 return 0;
2036 * Adapt the mappings of the cluster chain starting at first cluster
2037 * (i.e. if a file starts at first_cluster, the chain is followed according
2038 * to the modified fat, and the corresponding entries in s->mapping are
2039 * adjusted)
2041 static int commit_mappings(BDRVVVFATState* s,
2042 uint32_t first_cluster, int dir_index)
2044 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2045 direntry_t* direntry = array_get(&(s->directory), dir_index);
2046 uint32_t cluster = first_cluster;
2048 vvfat_close_current_file(s);
2050 assert(mapping);
2051 assert(mapping->begin == first_cluster);
2052 mapping->first_mapping_index = -1;
2053 mapping->dir_index = dir_index;
2054 mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2055 MODE_DIRECTORY : MODE_NORMAL;
2057 while (!fat_eof(s, cluster)) {
2058 uint32_t c, c1;
2060 for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2061 c = c1, c1 = modified_fat_get(s, c1));
2063 c++;
2064 if (c > mapping->end) {
2065 int index = array_index(&(s->mapping), mapping);
2066 int i, max_i = s->mapping.next - index;
2067 for (i = 1; i < max_i && mapping[i].begin < c; i++);
2068 while (--i > 0)
2069 remove_mapping(s, index + 1);
2071 assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2072 || mapping[1].begin >= c);
2073 mapping->end = c;
2075 if (!fat_eof(s, c1)) {
2076 int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2077 mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2078 array_get(&(s->mapping), i);
2080 if (next_mapping == NULL || next_mapping->begin > c1) {
2081 int i1 = array_index(&(s->mapping), mapping);
2083 next_mapping = insert_mapping(s, c1, c1+1);
2085 if (c1 < c)
2086 i1++;
2087 mapping = array_get(&(s->mapping), i1);
2090 next_mapping->dir_index = mapping->dir_index;
2091 next_mapping->first_mapping_index =
2092 mapping->first_mapping_index < 0 ?
2093 array_index(&(s->mapping), mapping) :
2094 mapping->first_mapping_index;
2095 next_mapping->path = mapping->path;
2096 next_mapping->mode = mapping->mode;
2097 next_mapping->read_only = mapping->read_only;
2098 if (mapping->mode & MODE_DIRECTORY) {
2099 next_mapping->info.dir.parent_mapping_index =
2100 mapping->info.dir.parent_mapping_index;
2101 next_mapping->info.dir.first_dir_index =
2102 mapping->info.dir.first_dir_index +
2103 0x10 * s->sectors_per_cluster *
2104 (mapping->end - mapping->begin);
2105 } else
2106 next_mapping->info.file.offset = mapping->info.file.offset +
2107 mapping->end - mapping->begin;
2109 mapping = next_mapping;
2112 cluster = c1;
2115 return 0;
2118 static int commit_direntries(BDRVVVFATState* s,
2119 int dir_index, int parent_mapping_index)
2121 direntry_t* direntry = array_get(&(s->directory), dir_index);
2122 uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
2123 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2125 int factor = 0x10 * s->sectors_per_cluster;
2126 int old_cluster_count, new_cluster_count;
2127 int current_dir_index = mapping->info.dir.first_dir_index;
2128 int first_dir_index = current_dir_index;
2129 int ret, i;
2130 uint32_t c;
2132 DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
2134 assert(direntry);
2135 assert(mapping);
2136 assert(mapping->begin == first_cluster);
2137 assert(mapping->info.dir.first_dir_index < s->directory.next);
2138 assert(mapping->mode & MODE_DIRECTORY);
2139 assert(dir_index == 0 || is_directory(direntry));
2141 mapping->info.dir.parent_mapping_index = parent_mapping_index;
2143 if (first_cluster == 0) {
2144 old_cluster_count = new_cluster_count =
2145 s->last_cluster_of_root_directory;
2146 } else {
2147 for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2148 c = fat_get(s, c))
2149 old_cluster_count++;
2151 for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2152 c = modified_fat_get(s, c))
2153 new_cluster_count++;
2156 if (new_cluster_count > old_cluster_count) {
2157 if (insert_direntries(s,
2158 current_dir_index + factor * old_cluster_count,
2159 factor * (new_cluster_count - old_cluster_count)) == NULL)
2160 return -1;
2161 } else if (new_cluster_count < old_cluster_count)
2162 remove_direntries(s,
2163 current_dir_index + factor * new_cluster_count,
2164 factor * (old_cluster_count - new_cluster_count));
2166 for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
2167 void* direntry = array_get(&(s->directory), current_dir_index);
2168 int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2169 s->sectors_per_cluster);
2170 if (ret)
2171 return ret;
2172 assert(!strncmp(s->directory.pointer, "QEMU", 4));
2173 current_dir_index += factor;
2176 ret = commit_mappings(s, first_cluster, dir_index);
2177 if (ret)
2178 return ret;
2180 /* recurse */
2181 for (i = 0; i < factor * new_cluster_count; i++) {
2182 direntry = array_get(&(s->directory), first_dir_index + i);
2183 if (is_directory(direntry) && !is_dot(direntry)) {
2184 mapping = find_mapping_for_cluster(s, first_cluster);
2185 assert(mapping->mode & MODE_DIRECTORY);
2186 ret = commit_direntries(s, first_dir_index + i,
2187 array_index(&(s->mapping), mapping));
2188 if (ret)
2189 return ret;
2193 return 0;
2196 /* commit one file (adjust contents, adjust mapping),
2197 return first_mapping_index */
2198 static int commit_one_file(BDRVVVFATState* s,
2199 int dir_index, uint32_t offset)
2201 direntry_t* direntry = array_get(&(s->directory), dir_index);
2202 uint32_t c = begin_of_direntry(direntry);
2203 uint32_t first_cluster = c;
2204 mapping_t* mapping = find_mapping_for_cluster(s, c);
2205 uint32_t size = filesize_of_direntry(direntry);
2206 char* cluster = malloc(s->cluster_size);
2207 uint32_t i;
2208 int fd = 0;
2210 assert(offset < size);
2211 assert((offset % s->cluster_size) == 0);
2213 for (i = s->cluster_size; i < offset; i += s->cluster_size)
2214 c = modified_fat_get(s, c);
2216 fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
2217 if (fd < 0) {
2218 fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2219 strerror(errno), errno);
2220 return fd;
2222 if (offset > 0)
2223 if (lseek(fd, offset, SEEK_SET) != offset)
2224 return -3;
2226 while (offset < size) {
2227 uint32_t c1;
2228 int rest_size = (size - offset > s->cluster_size ?
2229 s->cluster_size : size - offset);
2230 int ret;
2232 c1 = modified_fat_get(s, c);
2234 assert((size - offset == 0 && fat_eof(s, c)) ||
2235 (size > offset && c >=2 && !fat_eof(s, c)));
2236 assert(size >= 0);
2238 ret = vvfat_read(s->bs, cluster2sector(s, c),
2239 (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
2241 if (ret < 0)
2242 return ret;
2244 if (write(fd, cluster, rest_size) < 0)
2245 return -2;
2247 offset += rest_size;
2248 c = c1;
2251 ftruncate(fd, size);
2252 close(fd);
2254 return commit_mappings(s, first_cluster, dir_index);
2257 #ifdef DEBUG
2258 /* test, if all mappings point to valid direntries */
2259 static void check1(BDRVVVFATState* s)
2261 int i;
2262 for (i = 0; i < s->mapping.next; i++) {
2263 mapping_t* mapping = array_get(&(s->mapping), i);
2264 if (mapping->mode & MODE_DELETED) {
2265 fprintf(stderr, "deleted\n");
2266 continue;
2268 assert(mapping->dir_index >= 0);
2269 assert(mapping->dir_index < s->directory.next);
2270 direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2271 assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2272 if (mapping->mode & MODE_DIRECTORY) {
2273 assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2274 assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2279 /* test, if all direntries have mappings */
2280 static void check2(BDRVVVFATState* s)
2282 int i;
2283 int first_mapping = -1;
2285 for (i = 0; i < s->directory.next; i++) {
2286 direntry_t* direntry = array_get(&(s->directory), i);
2288 if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2289 mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2290 assert(mapping);
2291 assert(mapping->dir_index == i || is_dot(direntry));
2292 assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2295 if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2296 /* cluster start */
2297 int j, count = 0;
2299 for (j = 0; j < s->mapping.next; j++) {
2300 mapping_t* mapping = array_get(&(s->mapping), j);
2301 if (mapping->mode & MODE_DELETED)
2302 continue;
2303 if (mapping->mode & MODE_DIRECTORY) {
2304 if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2305 assert(++count == 1);
2306 if (mapping->first_mapping_index == -1)
2307 first_mapping = array_index(&(s->mapping), mapping);
2308 else
2309 assert(first_mapping == mapping->first_mapping_index);
2310 if (mapping->info.dir.parent_mapping_index < 0)
2311 assert(j == 0);
2312 else {
2313 mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2314 assert(parent->mode & MODE_DIRECTORY);
2315 assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2320 if (count == 0)
2321 first_mapping = -1;
2325 #endif
2327 static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2329 int i;
2331 #ifdef DEBUG
2332 fprintf(stderr, "handle_renames\n");
2333 for (i = 0; i < s->commits.next; i++) {
2334 commit_t* commit = array_get(&(s->commits), i);
2335 fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
2337 #endif
2339 for (i = 0; i < s->commits.next;) {
2340 commit_t* commit = array_get(&(s->commits), i);
2341 if (commit->action == ACTION_RENAME) {
2342 mapping_t* mapping = find_mapping_for_cluster(s,
2343 commit->param.rename.cluster);
2344 char* old_path = mapping->path;
2346 assert(commit->path);
2347 mapping->path = commit->path;
2348 if (rename(old_path, mapping->path))
2349 return -2;
2351 if (mapping->mode & MODE_DIRECTORY) {
2352 int l1 = strlen(mapping->path);
2353 int l2 = strlen(old_path);
2354 int diff = l1 - l2;
2355 direntry_t* direntry = array_get(&(s->directory),
2356 mapping->info.dir.first_dir_index);
2357 uint32_t c = mapping->begin;
2358 int i = 0;
2360 /* recurse */
2361 while (!fat_eof(s, c)) {
2362 do {
2363 direntry_t* d = direntry + i;
2365 if (is_file(d) || (is_directory(d) && !is_dot(d))) {
2366 mapping_t* m = find_mapping_for_cluster(s,
2367 begin_of_direntry(d));
2368 int l = strlen(m->path);
2369 char* new_path = malloc(l + diff + 1);
2371 assert(!strncmp(m->path, mapping->path, l2));
2373 strcpy(new_path, mapping->path);
2374 strcpy(new_path + l1, m->path + l2);
2376 schedule_rename(s, m->begin, new_path);
2378 i++;
2379 } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2380 c = fat_get(s, c);
2384 free(old_path);
2385 array_remove(&(s->commits), i);
2386 continue;
2387 } else if (commit->action == ACTION_MKDIR) {
2388 mapping_t* mapping;
2389 int j, parent_path_len;
2391 #ifdef __MINGW32__
2392 if (mkdir(commit->path))
2393 return -5;
2394 #else
2395 if (mkdir(commit->path, 0755))
2396 return -5;
2397 #endif
2399 mapping = insert_mapping(s, commit->param.mkdir.cluster,
2400 commit->param.mkdir.cluster + 1);
2401 if (mapping == NULL)
2402 return -6;
2404 mapping->mode = MODE_DIRECTORY;
2405 mapping->read_only = 0;
2406 mapping->path = commit->path;
2407 j = s->directory.next;
2408 assert(j);
2409 insert_direntries(s, s->directory.next,
2410 0x10 * s->sectors_per_cluster);
2411 mapping->info.dir.first_dir_index = j;
2413 parent_path_len = strlen(commit->path)
2414 - strlen(get_basename(commit->path)) - 1;
2415 for (j = 0; j < s->mapping.next; j++) {
2416 mapping_t* m = array_get(&(s->mapping), j);
2417 if (m->first_mapping_index < 0 && m != mapping &&
2418 !strncmp(m->path, mapping->path, parent_path_len) &&
2419 strlen(m->path) == parent_path_len)
2420 break;
2422 assert(j < s->mapping.next);
2423 mapping->info.dir.parent_mapping_index = j;
2425 array_remove(&(s->commits), i);
2426 continue;
2429 i++;
2431 return 0;
2435 * TODO: make sure that the short name is not matching *another* file
2437 static int handle_commits(BDRVVVFATState* s)
2439 int i, fail = 0;
2441 vvfat_close_current_file(s);
2443 for (i = 0; !fail && i < s->commits.next; i++) {
2444 commit_t* commit = array_get(&(s->commits), i);
2445 switch(commit->action) {
2446 case ACTION_RENAME: case ACTION_MKDIR:
2447 assert(0);
2448 fail = -2;
2449 break;
2450 case ACTION_WRITEOUT: {
2451 direntry_t* entry = array_get(&(s->directory),
2452 commit->param.writeout.dir_index);
2453 uint32_t begin = begin_of_direntry(entry);
2454 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2456 assert(mapping);
2457 assert(mapping->begin == begin);
2458 assert(commit->path == NULL);
2460 if (commit_one_file(s, commit->param.writeout.dir_index,
2461 commit->param.writeout.modified_offset))
2462 fail = -3;
2464 break;
2466 case ACTION_NEW_FILE: {
2467 int begin = commit->param.new_file.first_cluster;
2468 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2469 direntry_t* entry;
2470 int i;
2472 /* find direntry */
2473 for (i = 0; i < s->directory.next; i++) {
2474 entry = array_get(&(s->directory), i);
2475 if (is_file(entry) && begin_of_direntry(entry) == begin)
2476 break;
2479 if (i >= s->directory.next) {
2480 fail = -6;
2481 continue;
2484 /* make sure there exists an initial mapping */
2485 if (mapping && mapping->begin != begin) {
2486 mapping->end = begin;
2487 mapping = NULL;
2489 if (mapping == NULL) {
2490 mapping = insert_mapping(s, begin, begin+1);
2492 /* most members will be fixed in commit_mappings() */
2493 assert(commit->path);
2494 mapping->path = commit->path;
2495 mapping->read_only = 0;
2496 mapping->mode = MODE_NORMAL;
2497 mapping->info.file.offset = 0;
2499 if (commit_one_file(s, i, 0))
2500 fail = -7;
2502 break;
2504 default:
2505 assert(0);
2508 if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2509 return -1;
2510 return fail;
2513 static int handle_deletes(BDRVVVFATState* s)
2515 int i, deferred = 1, deleted = 1;
2517 /* delete files corresponding to mappings marked as deleted */
2518 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2519 while (deferred && deleted) {
2520 deferred = 0;
2521 deleted = 0;
2523 for (i = 1; i < s->mapping.next; i++) {
2524 mapping_t* mapping = array_get(&(s->mapping), i);
2525 if (mapping->mode & MODE_DELETED) {
2526 direntry_t* entry = array_get(&(s->directory),
2527 mapping->dir_index);
2529 if (is_free(entry)) {
2530 /* remove file/directory */
2531 if (mapping->mode & MODE_DIRECTORY) {
2532 int j, next_dir_index = s->directory.next,
2533 first_dir_index = mapping->info.dir.first_dir_index;
2535 if (rmdir(mapping->path) < 0) {
2536 if (errno == ENOTEMPTY) {
2537 deferred++;
2538 continue;
2539 } else
2540 return -5;
2543 for (j = 1; j < s->mapping.next; j++) {
2544 mapping_t* m = array_get(&(s->mapping), j);
2545 if (m->mode & MODE_DIRECTORY &&
2546 m->info.dir.first_dir_index >
2547 first_dir_index &&
2548 m->info.dir.first_dir_index <
2549 next_dir_index)
2550 next_dir_index =
2551 m->info.dir.first_dir_index;
2553 remove_direntries(s, first_dir_index,
2554 next_dir_index - first_dir_index);
2556 deleted++;
2558 } else {
2559 if (unlink(mapping->path))
2560 return -4;
2561 deleted++;
2563 DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2564 remove_mapping(s, i);
2569 return 0;
2573 * synchronize mapping with new state:
2575 * - copy FAT (with bdrv_read)
2576 * - mark all filenames corresponding to mappings as deleted
2577 * - recurse direntries from root (using bs->bdrv_read)
2578 * - delete files corresponding to mappings marked as deleted
2580 static int do_commit(BDRVVVFATState* s)
2582 int ret = 0;
2584 /* the real meat are the commits. Nothing to do? Move along! */
2585 if (s->commits.next == 0)
2586 return 0;
2588 vvfat_close_current_file(s);
2590 ret = handle_renames_and_mkdirs(s);
2591 if (ret) {
2592 fprintf(stderr, "Error handling renames (%d)\n", ret);
2593 assert(0);
2594 return ret;
2597 /* copy FAT (with bdrv_read) */
2598 memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2600 /* recurse direntries from root (using bs->bdrv_read) */
2601 ret = commit_direntries(s, 0, -1);
2602 if (ret) {
2603 fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
2604 assert(0);
2605 return ret;
2608 ret = handle_commits(s);
2609 if (ret) {
2610 fprintf(stderr, "Error handling commits (%d)\n", ret);
2611 assert(0);
2612 return ret;
2615 ret = handle_deletes(s);
2616 if (ret) {
2617 fprintf(stderr, "Error deleting\n");
2618 assert(0);
2619 return ret;
2622 s->qcow->drv->bdrv_make_empty(s->qcow);
2624 memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2626 DLOG(checkpoint());
2627 return 0;
2630 static int try_commit(BDRVVVFATState* s)
2632 vvfat_close_current_file(s);
2633 DLOG(checkpoint());
2634 if(!is_consistent(s))
2635 return -1;
2636 return do_commit(s);
2639 static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
2640 const uint8_t *buf, int nb_sectors)
2642 BDRVVVFATState *s = bs->opaque;
2643 int i, ret;
2645 DLOG(checkpoint());
2647 vvfat_close_current_file(s);
2650 * Some sanity checks:
2651 * - do not allow writing to the boot sector
2652 * - do not allow to write non-ASCII filenames
2655 if (sector_num < s->first_sectors_number)
2656 return -1;
2658 for (i = sector2cluster(s, sector_num);
2659 i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
2660 mapping_t* mapping = find_mapping_for_cluster(s, i);
2661 if (mapping) {
2662 if (mapping->read_only) {
2663 fprintf(stderr, "Tried to write to write-protected file %s\n",
2664 mapping->path);
2665 return -1;
2668 if (mapping->mode & MODE_DIRECTORY) {
2669 int begin = cluster2sector(s, i);
2670 int end = begin + s->sectors_per_cluster, k;
2671 int dir_index;
2672 const direntry_t* direntries;
2673 long_file_name lfn;
2675 lfn_init(&lfn);
2677 if (begin < sector_num)
2678 begin = sector_num;
2679 if (end > sector_num + nb_sectors)
2680 end = sector_num + nb_sectors;
2681 dir_index = mapping->dir_index +
2682 0x10 * (begin - mapping->begin * s->sectors_per_cluster);
2683 direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
2685 for (k = 0; k < (end - begin) * 0x10; k++) {
2686 /* do not allow non-ASCII filenames */
2687 if (parse_long_name(&lfn, direntries + k) < 0) {
2688 fprintf(stderr, "Warning: non-ASCII filename\n");
2689 return -1;
2691 /* no access to the direntry of a read-only file */
2692 else if (is_short_name(direntries+k) &&
2693 (direntries[k].attributes & 1)) {
2694 if (memcmp(direntries + k,
2695 array_get(&(s->directory), dir_index + k),
2696 sizeof(direntry_t))) {
2697 fprintf(stderr, "Warning: tried to write to write-protected file\n");
2698 return -1;
2703 i = mapping->end;
2704 } else
2705 i++;
2709 * Use qcow backend. Commit later.
2711 DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
2712 ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
2713 if (ret < 0) {
2714 fprintf(stderr, "Error writing to qcow backend\n");
2715 return ret;
2718 for (i = sector2cluster(s, sector_num);
2719 i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
2720 if (i >= 0)
2721 s->used_clusters[i] |= USED_ALLOCATED;
2723 DLOG(checkpoint());
2724 /* TODO: add timeout */
2725 try_commit(s);
2727 DLOG(checkpoint());
2728 return 0;
2731 static int vvfat_is_allocated(BlockDriverState *bs,
2732 int64_t sector_num, int nb_sectors, int* n)
2734 BDRVVVFATState* s = bs->opaque;
2735 *n = s->sector_count - sector_num;
2736 if (*n > nb_sectors)
2737 *n = nb_sectors;
2738 else if (*n < 0)
2739 return 0;
2740 return 1;
2743 static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
2744 const uint8_t* buffer, int nb_sectors) {
2745 BDRVVVFATState* s = bs->opaque;
2746 return try_commit(s);
2749 static void write_target_close(BlockDriverState *bs) {
2750 BDRVVVFATState* s = bs->opaque;
2751 bdrv_delete(s->qcow);
2752 free(s->qcow_filename);
2755 static BlockDriver vvfat_write_target = {
2756 "vvfat_write_target", 0, NULL, NULL, NULL,
2757 write_target_commit,
2758 write_target_close,
2759 NULL, NULL, NULL
2762 static int enable_write_target(BDRVVVFATState *s)
2764 int size = sector2cluster(s, s->sector_count);
2765 s->used_clusters = calloc(size, 1);
2767 array_init(&(s->commits), sizeof(commit_t));
2769 s->qcow_filename = malloc(1024);
2770 get_tmp_filename(s->qcow_filename, 1024);
2771 if (bdrv_create(&bdrv_qcow,
2772 s->qcow_filename, s->sector_count, "fat:", 0) < 0)
2773 return -1;
2774 s->qcow = bdrv_new("");
2775 if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
2776 return -1;
2778 #ifndef _WIN32
2779 unlink(s->qcow_filename);
2780 #endif
2782 s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
2783 s->bs->backing_hd->drv = &vvfat_write_target;
2784 s->bs->backing_hd->opaque = s;
2786 return 0;
2789 static void vvfat_close(BlockDriverState *bs)
2791 BDRVVVFATState *s = bs->opaque;
2793 vvfat_close_current_file(s);
2794 array_free(&(s->fat));
2795 array_free(&(s->directory));
2796 array_free(&(s->mapping));
2797 if(s->cluster_buffer)
2798 free(s->cluster_buffer);
2801 BlockDriver bdrv_vvfat = {
2802 "vvfat",
2803 sizeof(BDRVVVFATState),
2804 NULL, /* no probe for protocols */
2805 vvfat_open,
2806 vvfat_read,
2807 vvfat_write,
2808 vvfat_close,
2809 NULL, /* ??? Not sure if we can do any meaningful flushing. */
2810 NULL,
2811 vvfat_is_allocated,
2812 .protocol_name = "fat",
2815 #ifdef DEBUG
2816 static void checkpoint(void) {
2817 assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
2818 check1(vvv);
2819 check2(vvv);
2820 assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
2821 #if 0
2822 if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
2823 fprintf(stderr, "Nonono!\n");
2824 mapping_t* mapping;
2825 direntry_t* direntry;
2826 assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
2827 assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
2828 if (vvv->mapping.next<47)
2829 return;
2830 assert((mapping = array_get(&(vvv->mapping), 47)));
2831 assert(mapping->dir_index < vvv->directory.next);
2832 direntry = array_get(&(vvv->directory), mapping->dir_index);
2833 assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0);
2834 #endif
2835 return;
2836 /* avoid compiler warnings: */
2837 hexdump(NULL, 100);
2838 remove_mapping(vvv, NULL);
2839 print_mapping(NULL);
2840 print_direntry(NULL);
2842 #endif