Arm display emulation.
[qemu/mini2440.git] / block-vvfat.c
blob36f97134d3a661d9ff017838d7e4bbe710a616a7
1 /* vim:set shiftwidth=4 ts=8: */
2 /*
3 * QEMU Block driver for virtual VFAT (shadows a local directory)
4 *
5 * Copyright (c) 2004,2005 Johannes E. Schindelin
6 *
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 "vl.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();
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) if (!(a)) nonono(__FILE__, __LINE__, #a)
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 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 int array_remove(array_t* array,int index)
191 return array_remove_slice(array, index, 1);
194 /* return the index for a given member */
195 int array_index(array_t* array, void* pointer)
197 size_t offset = (char*)pointer - array->pointer;
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 partition_t {
246 uint8_t attributes; /* 0x80 = bootable */
247 uint8_t start_head;
248 uint8_t start_sector;
249 uint8_t start_cylinder;
250 uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xb = FAT32 */
251 uint8_t end_head;
252 uint8_t end_sector;
253 uint8_t end_cylinder;
254 uint32_t start_sector_long;
255 uint32_t end_sector_long;
256 } __attribute__((packed)) partition_t;
258 typedef struct mbr_t {
259 uint8_t ignored[0x1be];
260 partition_t partition[4];
261 uint8_t magic[2];
262 } __attribute__((packed)) mbr_t;
264 typedef struct direntry_t {
265 uint8_t name[8];
266 uint8_t extension[3];
267 uint8_t attributes;
268 uint8_t reserved[2];
269 uint16_t ctime;
270 uint16_t cdate;
271 uint16_t adate;
272 uint16_t begin_hi;
273 uint16_t mtime;
274 uint16_t mdate;
275 uint16_t begin;
276 uint32_t size;
277 } __attribute__((packed)) direntry_t;
279 /* this structure are used to transparently access the files */
281 typedef struct mapping_t {
282 /* begin is the first cluster, end is the last+1 */
283 uint32_t begin,end;
284 /* as s->directory is growable, no pointer may be used here */
285 unsigned int dir_index;
286 /* the clusters of a file may be in any order; this points to the first */
287 int first_mapping_index;
288 union {
289 /* offset is
290 * - the offset in the file (in clusters) for a file, or
291 * - the next cluster of the directory for a directory, and
292 * - the address of the buffer for a faked entry
294 struct {
295 uint32_t offset;
296 } file;
297 struct {
298 int parent_mapping_index;
299 int first_dir_index;
300 } dir;
301 } info;
302 /* path contains the full path, i.e. it always starts with s->path */
303 char* path;
305 enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2,
306 MODE_DIRECTORY = 4, MODE_FAKED = 8,
307 MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
308 int read_only;
309 } mapping_t;
311 #ifdef DEBUG
312 static void print_direntry(const struct direntry_t*);
313 static void print_mapping(const struct mapping_t* mapping);
314 #endif
316 /* here begins the real VVFAT driver */
318 typedef struct BDRVVVFATState {
319 BlockDriverState* bs; /* pointer to parent */
320 unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
321 unsigned char first_sectors[0x40*0x200];
323 int fat_type; /* 16 or 32 */
324 array_t fat,directory,mapping;
326 unsigned int cluster_size;
327 unsigned int sectors_per_cluster;
328 unsigned int sectors_per_fat;
329 unsigned int sectors_of_root_directory;
330 uint32_t last_cluster_of_root_directory;
331 unsigned int faked_sectors; /* how many sectors are faked before file data */
332 uint32_t sector_count; /* total number of sectors of the partition */
333 uint32_t cluster_count; /* total number of clusters of this partition */
334 uint32_t max_fat_value;
336 int current_fd;
337 mapping_t* current_mapping;
338 unsigned char* cluster; /* points to current cluster */
339 unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
340 unsigned int current_cluster;
342 /* write support */
343 BlockDriverState* write_target;
344 char* qcow_filename;
345 BlockDriverState* qcow;
346 void* fat2;
347 char* used_clusters;
348 array_t commits;
349 const char* path;
350 int downcase_short_names;
351 } BDRVVVFATState;
354 static int vvfat_probe(const uint8_t *buf, int buf_size, const char *filename)
356 if (strstart(filename, "fat:", NULL))
357 return 100;
358 return 0;
361 static void init_mbr(BDRVVVFATState* s)
363 /* TODO: if the files mbr.img and bootsect.img exist, use them */
364 mbr_t* real_mbr=(mbr_t*)s->first_sectors;
365 partition_t* partition=&(real_mbr->partition[0]);
367 memset(s->first_sectors,0,512);
369 partition->attributes=0x80; /* bootable */
370 partition->start_head=1;
371 partition->start_sector=1;
372 partition->start_cylinder=0;
373 /* FAT12/FAT16/FAT32 */
374 partition->fs_type=(s->fat_type==12?0x1:s->fat_type==16?0x6:0xb);
375 partition->end_head=s->bs->heads-1;
376 partition->end_sector=0xff; /* end sector & upper 2 bits of cylinder */;
377 partition->end_cylinder=0xff; /* lower 8 bits of end cylinder */;
378 partition->start_sector_long=cpu_to_le32(s->bs->secs);
379 partition->end_sector_long=cpu_to_le32(s->sector_count);
381 real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
384 /* direntry functions */
386 /* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
387 static inline int short2long_name(unsigned char* dest,const char* src)
389 int i;
390 for(i=0;i<129 && src[i];i++) {
391 dest[2*i]=src[i];
392 dest[2*i+1]=0;
394 dest[2*i]=dest[2*i+1]=0;
395 for(i=2*i+2;(i%26);i++)
396 dest[i]=0xff;
397 return i;
400 static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
402 char buffer[258];
403 int length=short2long_name(buffer,filename),
404 number_of_entries=(length+25)/26,i;
405 direntry_t* entry;
407 for(i=0;i<number_of_entries;i++) {
408 entry=array_get_next(&(s->directory));
409 entry->attributes=0xf;
410 entry->reserved[0]=0;
411 entry->begin=0;
412 entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
414 for(i=0;i<length;i++) {
415 int offset=(i%26);
416 if(offset<10) offset=1+offset;
417 else if(offset<22) offset=14+offset-10;
418 else offset=28+offset-22;
419 entry=array_get(&(s->directory),s->directory.next-1-(i/26));
420 entry->name[offset]=buffer[i];
422 return array_get(&(s->directory),s->directory.next-number_of_entries);
425 static char is_free(const direntry_t* direntry)
427 /* return direntry->name[0]==0 ; */
428 return direntry->attributes == 0 || direntry->name[0]==0xe5;
431 static char is_volume_label(const direntry_t* direntry)
433 return direntry->attributes == 0x28;
436 static char is_long_name(const direntry_t* direntry)
438 return direntry->attributes == 0xf;
441 static char is_short_name(const direntry_t* direntry)
443 return !is_volume_label(direntry) && !is_long_name(direntry)
444 && !is_free(direntry);
447 static char is_directory(const direntry_t* direntry)
449 return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
452 static inline char is_dot(const direntry_t* direntry)
454 return is_short_name(direntry) && direntry->name[0] == '.';
457 static char is_file(const direntry_t* direntry)
459 return is_short_name(direntry) && !is_directory(direntry);
462 static inline uint32_t begin_of_direntry(const direntry_t* direntry)
464 return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
467 static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
469 return le32_to_cpu(direntry->size);
472 static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
474 direntry->begin = cpu_to_le16(begin & 0xffff);
475 direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
478 /* fat functions */
480 static inline uint8_t fat_chksum(const direntry_t* entry)
482 uint8_t chksum=0;
483 int i;
485 for(i=0;i<11;i++)
486 chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0))
487 +(unsigned char)entry->name[i];
489 return chksum;
492 /* if return_time==0, this returns the fat_date, else the fat_time */
493 static uint16_t fat_datetime(time_t time,int return_time) {
494 struct tm* t;
495 #ifdef _WIN32
496 t=localtime(&time); /* this is not thread safe */
497 #else
498 struct tm t1;
499 t=&t1;
500 localtime_r(&time,t);
501 #endif
502 if(return_time)
503 return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
504 return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
507 static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
509 if(s->fat_type==32) {
510 uint32_t* entry=array_get(&(s->fat),cluster);
511 *entry=cpu_to_le32(value);
512 } else if(s->fat_type==16) {
513 uint16_t* entry=array_get(&(s->fat),cluster);
514 *entry=cpu_to_le16(value&0xffff);
515 } else {
516 int offset = (cluster*3/2);
517 unsigned char* p = array_get(&(s->fat), offset);
518 switch (cluster&1) {
519 case 0:
520 p[0] = value&0xff;
521 p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
522 break;
523 case 1:
524 p[0] = (p[0]&0xf) | ((value&0xf)<<4);
525 p[1] = (value>>4);
526 break;
531 static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
533 if(s->fat_type==32) {
534 uint32_t* entry=array_get(&(s->fat),cluster);
535 return le32_to_cpu(*entry);
536 } else if(s->fat_type==16) {
537 uint16_t* entry=array_get(&(s->fat),cluster);
538 return le16_to_cpu(*entry);
539 } else {
540 const uint8_t* x=s->fat.pointer+cluster*3/2;
541 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
545 static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
547 if(fat_entry>s->max_fat_value-8)
548 return -1;
549 return 0;
552 static inline void init_fat(BDRVVVFATState* s)
554 if (s->fat_type == 12) {
555 array_init(&(s->fat),1);
556 array_ensure_allocated(&(s->fat),
557 s->sectors_per_fat * 0x200 * 3 / 2 - 1);
558 } else {
559 array_init(&(s->fat),(s->fat_type==32?4:2));
560 array_ensure_allocated(&(s->fat),
561 s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
563 memset(s->fat.pointer,0,s->fat.size);
565 switch(s->fat_type) {
566 case 12: s->max_fat_value=0xfff; break;
567 case 16: s->max_fat_value=0xffff; break;
568 case 32: s->max_fat_value=0x0fffffff; break;
569 default: s->max_fat_value=0; /* error... */
574 /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
575 /* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
576 static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
577 unsigned int directory_start, const char* filename, int is_dot)
579 int i,j,long_index=s->directory.next;
580 direntry_t* entry=0;
581 direntry_t* entry_long=0;
583 if(is_dot) {
584 entry=array_get_next(&(s->directory));
585 memset(entry->name,0x20,11);
586 memcpy(entry->name,filename,strlen(filename));
587 return entry;
590 entry_long=create_long_filename(s,filename);
592 i = strlen(filename);
593 for(j = i - 1; j>0 && filename[j]!='.';j--);
594 if (j > 0)
595 i = (j > 8 ? 8 : j);
596 else if (i > 8)
597 i = 8;
599 entry=array_get_next(&(s->directory));
600 memset(entry->name,0x20,11);
601 strncpy(entry->name,filename,i);
603 if(j > 0)
604 for (i = 0; i < 3 && filename[j+1+i]; i++)
605 entry->extension[i] = filename[j+1+i];
607 /* upcase & remove unwanted characters */
608 for(i=10;i>=0;i--) {
609 if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
610 if(entry->name[i]<=' ' || entry->name[i]>0x7f
611 || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
612 entry->name[i]='_';
613 else if(entry->name[i]>='a' && entry->name[i]<='z')
614 entry->name[i]+='A'-'a';
617 /* mangle duplicates */
618 while(1) {
619 direntry_t* entry1=array_get(&(s->directory),directory_start);
620 int j;
622 for(;entry1<entry;entry1++)
623 if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
624 break; /* found dupe */
625 if(entry1==entry) /* no dupe found */
626 break;
628 /* use all 8 characters of name */
629 if(entry->name[7]==' ') {
630 int j;
631 for(j=6;j>0 && entry->name[j]==' ';j--)
632 entry->name[j]='~';
635 /* increment number */
636 for(j=7;j>0 && entry->name[j]=='9';j--)
637 entry->name[j]='0';
638 if(j>0) {
639 if(entry->name[j]<'0' || entry->name[j]>'9')
640 entry->name[j]='0';
641 else
642 entry->name[j]++;
646 /* calculate checksum; propagate to long name */
647 if(entry_long) {
648 uint8_t chksum=fat_chksum(entry);
650 /* calculate anew, because realloc could have taken place */
651 entry_long=array_get(&(s->directory),long_index);
652 while(entry_long<entry && is_long_name(entry_long)) {
653 entry_long->reserved[1]=chksum;
654 entry_long++;
658 return entry;
662 * Read a directory. (the index of the corresponding mapping must be passed).
664 static int read_directory(BDRVVVFATState* s, int mapping_index)
666 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
667 direntry_t* direntry;
668 const char* dirname = mapping->path;
669 int first_cluster = mapping->begin;
670 int parent_index = mapping->info.dir.parent_mapping_index;
671 mapping_t* parent_mapping = (mapping_t*)
672 (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : 0);
673 int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
675 DIR* dir=opendir(dirname);
676 struct dirent* entry;
677 int i;
679 assert(mapping->mode & MODE_DIRECTORY);
681 if(!dir) {
682 mapping->end = mapping->begin;
683 return -1;
686 i = mapping->info.dir.first_dir_index =
687 first_cluster == 0 ? 0 : s->directory.next;
689 /* actually read the directory, and allocate the mappings */
690 while((entry=readdir(dir))) {
691 unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
692 char* buffer;
693 direntry_t* direntry;
694 struct stat st;
695 int is_dot=!strcmp(entry->d_name,".");
696 int is_dotdot=!strcmp(entry->d_name,"..");
698 if(first_cluster == 0 && (is_dotdot || is_dot))
699 continue;
701 buffer=(char*)malloc(length);
702 assert(buffer);
703 snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
705 if(stat(buffer,&st)<0) {
706 free(buffer);
707 continue;
710 /* create directory entry for this file */
711 direntry=create_short_and_long_name(s, i, entry->d_name,
712 is_dot || is_dotdot);
713 direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
714 direntry->reserved[0]=direntry->reserved[1]=0;
715 direntry->ctime=fat_datetime(st.st_ctime,1);
716 direntry->cdate=fat_datetime(st.st_ctime,0);
717 direntry->adate=fat_datetime(st.st_atime,0);
718 direntry->begin_hi=0;
719 direntry->mtime=fat_datetime(st.st_mtime,1);
720 direntry->mdate=fat_datetime(st.st_mtime,0);
721 if(is_dotdot)
722 set_begin_of_direntry(direntry, first_cluster_of_parent);
723 else if(is_dot)
724 set_begin_of_direntry(direntry, first_cluster);
725 else
726 direntry->begin=0; /* do that later */
727 if (st.st_size > 0x7fffffff) {
728 fprintf(stderr, "File %s is larger than 2GB\n", buffer);
729 free(buffer);
730 return -2;
732 direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
734 /* create mapping for this file */
735 if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
736 s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
737 s->current_mapping->begin=0;
738 s->current_mapping->end=st.st_size;
740 * we get the direntry of the most recent direntry, which
741 * contains the short name and all the relevant information.
743 s->current_mapping->dir_index=s->directory.next-1;
744 s->current_mapping->first_mapping_index = -1;
745 if (S_ISDIR(st.st_mode)) {
746 s->current_mapping->mode = MODE_DIRECTORY;
747 s->current_mapping->info.dir.parent_mapping_index =
748 mapping_index;
749 } else {
750 s->current_mapping->mode = MODE_UNDEFINED;
751 s->current_mapping->info.file.offset = 0;
753 s->current_mapping->path=buffer;
754 s->current_mapping->read_only =
755 (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
758 closedir(dir);
760 /* fill with zeroes up to the end of the cluster */
761 while(s->directory.next%(0x10*s->sectors_per_cluster)) {
762 direntry_t* direntry=array_get_next(&(s->directory));
763 memset(direntry,0,sizeof(direntry_t));
766 /* TODO: if there are more entries, bootsector has to be adjusted! */
767 #define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
768 if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
769 /* root directory */
770 int cur = s->directory.next;
771 array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
772 memset(array_get(&(s->directory), cur), 0,
773 (ROOT_ENTRIES - cur) * sizeof(direntry_t));
776 /* reget the mapping, since s->mapping was possibly realloc()ed */
777 mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
778 first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
779 * 0x20 / s->cluster_size;
780 mapping->end = first_cluster;
782 direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
783 set_begin_of_direntry(direntry, mapping->begin);
785 return 0;
788 static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
790 return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
793 static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
795 return s->faked_sectors + s->sectors_per_cluster * cluster_num;
798 static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
800 return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
803 #ifdef DBG
804 static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
806 if(mapping->mode==MODE_UNDEFINED)
807 return 0;
808 return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
810 #endif
812 static int init_directories(BDRVVVFATState* s,
813 const char* dirname)
815 bootsector_t* bootsector;
816 mapping_t* mapping;
817 unsigned int i;
818 unsigned int cluster;
820 memset(&(s->first_sectors[0]),0,0x40*0x200);
822 s->cluster_size=s->sectors_per_cluster*0x200;
823 s->cluster_buffer=malloc(s->cluster_size);
824 assert(s->cluster_buffer);
827 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
828 * where sc is sector_count,
829 * spf is sectors_per_fat,
830 * spc is sectors_per_clusters, and
831 * fat_type = 12, 16 or 32.
833 i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
834 s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
836 array_init(&(s->mapping),sizeof(mapping_t));
837 array_init(&(s->directory),sizeof(direntry_t));
839 /* add volume label */
841 direntry_t* entry=array_get_next(&(s->directory));
842 entry->attributes=0x28; /* archive | volume label */
843 snprintf(entry->name,11,"QEMU VVFAT");
846 /* Now build FAT, and write back information into directory */
847 init_fat(s);
849 s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
850 s->cluster_count=sector2cluster(s, s->sector_count);
852 mapping = array_get_next(&(s->mapping));
853 mapping->begin = 0;
854 mapping->dir_index = 0;
855 mapping->info.dir.parent_mapping_index = -1;
856 mapping->first_mapping_index = -1;
857 mapping->path = strdup(dirname);
858 i = strlen(mapping->path);
859 if (i > 0 && mapping->path[i - 1] == '/')
860 mapping->path[i - 1] = '\0';
861 mapping->mode = MODE_DIRECTORY;
862 mapping->read_only = 0;
863 s->path = mapping->path;
865 for (i = 0, cluster = 0; i < s->mapping.next; i++) {
866 int j;
867 /* MS-DOS expects the FAT to be 0 for the root directory
868 * (except for the media byte). */
869 /* LATER TODO: still true for FAT32? */
870 int fix_fat = (i != 0);
871 mapping = array_get(&(s->mapping), i);
873 if (mapping->mode & MODE_DIRECTORY) {
874 mapping->begin = cluster;
875 if(read_directory(s, i)) {
876 fprintf(stderr, "Could not read directory %s\n",
877 mapping->path);
878 return -1;
880 mapping = array_get(&(s->mapping), i);
881 } else {
882 assert(mapping->mode == MODE_UNDEFINED);
883 mapping->mode=MODE_NORMAL;
884 mapping->begin = cluster;
885 if (mapping->end > 0) {
886 direntry_t* direntry = array_get(&(s->directory),
887 mapping->dir_index);
889 mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
890 set_begin_of_direntry(direntry, mapping->begin);
891 } else {
892 mapping->end = cluster + 1;
893 fix_fat = 0;
897 assert(mapping->begin < mapping->end);
899 /* fix fat for entry */
900 if (fix_fat) {
901 for(j = mapping->begin; j < mapping->end - 1; j++)
902 fat_set(s, j, j+1);
903 fat_set(s, mapping->end - 1, s->max_fat_value);
906 /* next free cluster */
907 cluster = mapping->end;
909 if(cluster > s->cluster_count) {
910 fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type);
911 return -1;
915 mapping = array_get(&(s->mapping), 0);
916 s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
917 s->last_cluster_of_root_directory = mapping->end;
919 /* the FAT signature */
920 fat_set(s,0,s->max_fat_value);
921 fat_set(s,1,s->max_fat_value);
923 s->current_mapping = NULL;
925 bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
926 bootsector->jump[0]=0xeb;
927 bootsector->jump[1]=0x3e;
928 bootsector->jump[2]=0x90;
929 memcpy(bootsector->name,"QEMU ",8);
930 bootsector->sector_size=cpu_to_le16(0x200);
931 bootsector->sectors_per_cluster=s->sectors_per_cluster;
932 bootsector->reserved_sectors=cpu_to_le16(1);
933 bootsector->number_of_fats=0x2; /* number of FATs */
934 bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
935 bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
936 bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
937 s->fat.pointer[0] = bootsector->media_type;
938 bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
939 bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
940 bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
941 bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
942 bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
944 /* LATER TODO: if FAT32, this is wrong */
945 bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
946 bootsector->u.fat16.current_head=0;
947 bootsector->u.fat16.signature=0x29;
948 bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
950 memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
951 memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12 ":s->fat_type==16?"FAT16 ":"FAT32 "),8);
952 bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
954 return 0;
957 static BDRVVVFATState *vvv = NULL;
959 static int enable_write_target(BDRVVVFATState *s);
960 static int is_consistent(BDRVVVFATState *s);
962 static int vvfat_open(BlockDriverState *bs, const char* dirname)
964 BDRVVVFATState *s = bs->opaque;
965 int floppy = 0;
966 int i;
968 vvv = s;
970 DLOG(if (stderr == NULL) {
971 stderr = fopen("vvfat.log", "a");
972 setbuf(stderr, NULL);
975 s->bs = bs;
977 s->fat_type=16;
978 /* LATER TODO: if FAT32, adjust */
979 s->sector_count=0xec04f;
980 s->sectors_per_cluster=0x10;
981 /* LATER TODO: this could be wrong for FAT32 */
982 bs->cyls=1023; bs->heads=15; bs->secs=63;
984 s->current_cluster=0xffffffff;
986 s->first_sectors_number=0x40;
987 /* read only is the default for safety */
988 bs->read_only = 1;
989 s->qcow = s->write_target = NULL;
990 s->qcow_filename = NULL;
991 s->fat2 = NULL;
992 s->downcase_short_names = 1;
994 if (!strstart(dirname, "fat:", NULL))
995 return -1;
997 if (strstr(dirname, ":rw:")) {
998 if (enable_write_target(s))
999 return -1;
1000 bs->read_only = 0;
1003 if (strstr(dirname, ":floppy:")) {
1004 floppy = 1;
1005 s->fat_type = 12;
1006 s->first_sectors_number = 1;
1007 s->sectors_per_cluster=2;
1008 bs->cyls = 80; bs->heads = 2; bs->secs = 36;
1011 if (strstr(dirname, ":32:")) {
1012 fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1013 s->fat_type = 32;
1014 } else if (strstr(dirname, ":16:")) {
1015 s->fat_type = 16;
1016 } else if (strstr(dirname, ":12:")) {
1017 s->fat_type = 12;
1018 s->sector_count=2880;
1021 i = strrchr(dirname, ':') - dirname;
1022 assert(i >= 3);
1023 if (dirname[i-2] == ':' && isalpha(dirname[i-1]))
1024 /* workaround for DOS drive names */
1025 dirname += i-1;
1026 else
1027 dirname += i+1;
1029 bs->total_sectors=bs->cyls*bs->heads*bs->secs;
1030 if (s->sector_count > bs->total_sectors)
1031 s->sector_count = bs->total_sectors;
1032 if(init_directories(s, dirname))
1033 return -1;
1035 if(s->first_sectors_number==0x40)
1036 init_mbr(s);
1038 /* for some reason or other, MS-DOS does not like to know about CHS... */
1039 if (floppy)
1040 bs->heads = bs->cyls = bs->secs = 0;
1042 // assert(is_consistent(s));
1044 return 0;
1047 static inline void vvfat_close_current_file(BDRVVVFATState *s)
1049 if(s->current_mapping) {
1050 s->current_mapping = NULL;
1051 if (s->current_fd) {
1052 close(s->current_fd);
1053 s->current_fd = 0;
1056 s->current_cluster = -1;
1059 /* mappings between index1 and index2-1 are supposed to be ordered
1060 * return value is the index of the last mapping for which end>cluster_num
1062 static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1064 int index3=index1+1;
1065 while(1) {
1066 mapping_t* mapping;
1067 index3=(index1+index2)/2;
1068 mapping=array_get(&(s->mapping),index3);
1069 assert(mapping->begin < mapping->end);
1070 if(mapping->begin>=cluster_num) {
1071 assert(index2!=index3 || index2==0);
1072 if(index2==index3)
1073 return index1;
1074 index2=index3;
1075 } else {
1076 if(index1==index3)
1077 return mapping->end<=cluster_num ? index2 : index1;
1078 index1=index3;
1080 assert(index1<=index2);
1081 DLOG(mapping=array_get(&(s->mapping),index1);
1082 assert(mapping->begin<=cluster_num);
1083 assert(index2 >= s->mapping.next ||
1084 ((mapping = array_get(&(s->mapping),index2)) &&
1085 mapping->end>cluster_num)));
1089 static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
1091 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
1092 mapping_t* mapping;
1093 if(index>=s->mapping.next)
1094 return 0;
1095 mapping=array_get(&(s->mapping),index);
1096 if(mapping->begin>cluster_num)
1097 return 0;
1098 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
1099 return mapping;
1103 * This function simply compares path == mapping->path. Since the mappings
1104 * are sorted by cluster, this is expensive: O(n).
1106 static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
1107 const char* path)
1109 int i;
1111 for (i = 0; i < s->mapping.next; i++) {
1112 mapping_t* mapping = array_get(&(s->mapping), i);
1113 if (mapping->first_mapping_index < 0 &&
1114 !strcmp(path, mapping->path))
1115 return mapping;
1118 return NULL;
1121 static int open_file(BDRVVVFATState* s,mapping_t* mapping)
1123 if(!mapping)
1124 return -1;
1125 if(!s->current_mapping ||
1126 strcmp(s->current_mapping->path,mapping->path)) {
1127 /* open file */
1128 int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
1129 if(fd<0)
1130 return -1;
1131 vvfat_close_current_file(s);
1132 s->current_fd = fd;
1133 s->current_mapping = mapping;
1135 return 0;
1138 static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1140 if(s->current_cluster != cluster_num) {
1141 int result=0;
1142 off_t offset;
1143 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
1144 if(!s->current_mapping
1145 || s->current_mapping->begin>cluster_num
1146 || s->current_mapping->end<=cluster_num) {
1147 /* binary search of mappings for file */
1148 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
1150 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1152 if (mapping && mapping->mode & MODE_DIRECTORY) {
1153 vvfat_close_current_file(s);
1154 s->current_mapping = mapping;
1155 read_cluster_directory:
1156 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
1157 s->cluster = s->directory.pointer+offset
1158 + 0x20*s->current_mapping->info.dir.first_dir_index;
1159 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1160 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1161 s->current_cluster = cluster_num;
1162 return 0;
1165 if(open_file(s,mapping))
1166 return -2;
1167 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1168 goto read_cluster_directory;
1170 assert(s->current_fd);
1172 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
1173 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1174 return -3;
1175 s->cluster=s->cluster_buffer;
1176 result=read(s->current_fd,s->cluster,s->cluster_size);
1177 if(result<0) {
1178 s->current_cluster = -1;
1179 return -1;
1181 s->current_cluster = cluster_num;
1183 return 0;
1186 #ifdef DEBUG
1187 static void hexdump(const void* address, uint32_t len)
1189 const unsigned char* p = address;
1190 int i, j;
1192 for (i = 0; i < len; i += 16) {
1193 for (j = 0; j < 16 && i + j < len; j++)
1194 fprintf(stderr, "%02x ", p[i + j]);
1195 for (; j < 16; j++)
1196 fprintf(stderr, " ");
1197 fprintf(stderr, " ");
1198 for (j = 0; j < 16 && i + j < len; j++)
1199 fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
1200 fprintf(stderr, "\n");
1204 static void print_direntry(const direntry_t* direntry)
1206 int j = 0;
1207 char buffer[1024];
1209 fprintf(stderr, "direntry 0x%x: ", (int)direntry);
1210 if(!direntry)
1211 return;
1212 if(is_long_name(direntry)) {
1213 unsigned char* c=(unsigned char*)direntry;
1214 int i;
1215 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
1216 #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = '°'; j++;}
1217 ADD_CHAR(c[i]);
1218 for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
1219 ADD_CHAR(c[i]);
1220 for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
1221 ADD_CHAR(c[i]);
1222 buffer[j] = 0;
1223 fprintf(stderr, "%s\n", buffer);
1224 } else {
1225 int i;
1226 for(i=0;i<11;i++)
1227 ADD_CHAR(direntry->name[i]);
1228 buffer[j] = 0;
1229 fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1230 buffer,
1231 direntry->attributes,
1232 begin_of_direntry(direntry),le32_to_cpu(direntry->size));
1236 static void print_mapping(const mapping_t* mapping)
1238 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);
1239 if (mapping->mode & MODE_DIRECTORY)
1240 fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1241 else
1242 fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
1244 #endif
1246 static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
1247 uint8_t *buf, int nb_sectors)
1249 BDRVVVFATState *s = bs->opaque;
1250 int i;
1252 for(i=0;i<nb_sectors;i++,sector_num++) {
1253 if (sector_num >= s->sector_count)
1254 return -1;
1255 if (s->qcow) {
1256 int n;
1257 if (s->qcow->drv->bdrv_is_allocated(s->qcow,
1258 sector_num, nb_sectors-i, &n)) {
1259 DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
1260 if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
1261 return -1;
1262 i += n - 1;
1263 sector_num += n - 1;
1264 continue;
1266 DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
1268 if(sector_num<s->faked_sectors) {
1269 if(sector_num<s->first_sectors_number)
1270 memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
1271 else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
1272 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
1273 else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
1274 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
1275 } else {
1276 uint32_t sector=sector_num-s->faked_sectors,
1277 sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1278 cluster_num=sector/s->sectors_per_cluster;
1279 if(read_cluster(s, cluster_num) != 0) {
1280 /* LATER TODO: strict: return -1; */
1281 memset(buf+i*0x200,0,0x200);
1282 continue;
1284 memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
1287 return 0;
1290 /* LATER TODO: statify all functions */
1293 * Idea of the write support (use snapshot):
1295 * 1. check if all data is consistent, recording renames, modifications,
1296 * new files and directories (in s->commits).
1298 * 2. if the data is not consistent, stop committing
1300 * 3. handle renames, and create new files and directories (do not yet
1301 * write their contents)
1303 * 4. walk the directories, fixing the mapping and direntries, and marking
1304 * the handled mappings as not deleted
1306 * 5. commit the contents of the files
1308 * 6. handle deleted files and directories
1312 typedef struct commit_t {
1313 char* path;
1314 union {
1315 struct { uint32_t cluster; } rename;
1316 struct { int dir_index; uint32_t modified_offset; } writeout;
1317 struct { uint32_t first_cluster; } new_file;
1318 struct { uint32_t cluster; } mkdir;
1319 } param;
1320 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1321 enum {
1322 ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1323 } action;
1324 } commit_t;
1326 static void clear_commits(BDRVVVFATState* s)
1328 int i;
1329 DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1330 for (i = 0; i < s->commits.next; i++) {
1331 commit_t* commit = array_get(&(s->commits), i);
1332 assert(commit->path || commit->action == ACTION_WRITEOUT);
1333 if (commit->action != ACTION_WRITEOUT) {
1334 assert(commit->path);
1335 free(commit->path);
1336 } else
1337 assert(commit->path == NULL);
1339 s->commits.next = 0;
1342 static void schedule_rename(BDRVVVFATState* s,
1343 uint32_t cluster, char* new_path)
1345 commit_t* commit = array_get_next(&(s->commits));
1346 commit->path = new_path;
1347 commit->param.rename.cluster = cluster;
1348 commit->action = ACTION_RENAME;
1351 static void schedule_writeout(BDRVVVFATState* s,
1352 int dir_index, uint32_t modified_offset)
1354 commit_t* commit = array_get_next(&(s->commits));
1355 commit->path = NULL;
1356 commit->param.writeout.dir_index = dir_index;
1357 commit->param.writeout.modified_offset = modified_offset;
1358 commit->action = ACTION_WRITEOUT;
1361 static void schedule_new_file(BDRVVVFATState* s,
1362 char* path, uint32_t first_cluster)
1364 commit_t* commit = array_get_next(&(s->commits));
1365 commit->path = path;
1366 commit->param.new_file.first_cluster = first_cluster;
1367 commit->action = ACTION_NEW_FILE;
1370 static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1372 commit_t* commit = array_get_next(&(s->commits));
1373 commit->path = path;
1374 commit->param.mkdir.cluster = cluster;
1375 commit->action = ACTION_MKDIR;
1378 typedef struct {
1379 unsigned char name[1024];
1380 int checksum, len;
1381 int sequence_number;
1382 } long_file_name;
1384 static void lfn_init(long_file_name* lfn)
1386 lfn->sequence_number = lfn->len = 0;
1387 lfn->checksum = 0x100;
1390 /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1391 static int parse_long_name(long_file_name* lfn,
1392 const direntry_t* direntry)
1394 int i, j, offset;
1395 const unsigned char* pointer = (const unsigned char*)direntry;
1397 if (!is_long_name(direntry))
1398 return 1;
1400 if (pointer[0] & 0x40) {
1401 lfn->sequence_number = pointer[0] & 0x3f;
1402 lfn->checksum = pointer[13];
1403 lfn->name[0] = 0;
1404 } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
1405 return -1;
1406 else if (pointer[13] != lfn->checksum)
1407 return -2;
1408 else if (pointer[12] || pointer[26] || pointer[27])
1409 return -3;
1411 offset = 13 * (lfn->sequence_number - 1);
1412 for (i = 0, j = 1; i < 13; i++, j+=2) {
1413 if (j == 11)
1414 j = 14;
1415 else if (j == 26)
1416 j = 28;
1418 if (pointer[j+1] == 0)
1419 lfn->name[offset + i] = pointer[j];
1420 else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1421 return -4;
1422 else
1423 lfn->name[offset + i] = 0;
1426 if (pointer[0] & 0x40)
1427 lfn->len = offset + strlen(lfn->name + offset);
1429 return 0;
1432 /* returns 0 if successful, >0 if no short_name, and <0 on error */
1433 static int parse_short_name(BDRVVVFATState* s,
1434 long_file_name* lfn, direntry_t* direntry)
1436 int i, j;
1438 if (!is_short_name(direntry))
1439 return 1;
1441 for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1442 for (i = 0; i <= j; i++) {
1443 if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
1444 return -1;
1445 else if (s->downcase_short_names)
1446 lfn->name[i] = tolower(direntry->name[i]);
1447 else
1448 lfn->name[i] = direntry->name[i];
1451 for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
1452 if (j >= 0) {
1453 lfn->name[i++] = '.';
1454 lfn->name[i + j + 1] = '\0';
1455 for (;j >= 0; j--) {
1456 if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
1457 return -2;
1458 else if (s->downcase_short_names)
1459 lfn->name[i + j] = tolower(direntry->extension[j]);
1460 else
1461 lfn->name[i + j] = direntry->extension[j];
1463 } else
1464 lfn->name[i + j + 1] = '\0';
1466 lfn->len = strlen(lfn->name);
1468 return 0;
1471 static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1472 unsigned int cluster)
1474 if (cluster < s->last_cluster_of_root_directory) {
1475 if (cluster + 1 == s->last_cluster_of_root_directory)
1476 return s->max_fat_value;
1477 else
1478 return cluster + 1;
1481 if (s->fat_type==32) {
1482 uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1483 return le32_to_cpu(*entry);
1484 } else if (s->fat_type==16) {
1485 uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1486 return le16_to_cpu(*entry);
1487 } else {
1488 const uint8_t* x=s->fat2+cluster*3/2;
1489 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1493 static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1495 int was_modified = 0;
1496 int i, dummy;
1498 if (s->qcow == NULL)
1499 return 0;
1501 for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
1502 was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
1503 cluster2sector(s, cluster_num) + i, 1, &dummy);
1505 return was_modified;
1508 static const char* get_basename(const char* path)
1510 char* basename = strrchr(path, '/');
1511 if (basename == NULL)
1512 return path;
1513 else
1514 return basename + 1; /* strip '/' */
1518 * The array s->used_clusters holds the states of the clusters. If it is
1519 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1520 * was modified, bit 3 is set.
1521 * If any cluster is allocated, but not part of a file or directory, this
1522 * driver refuses to commit.
1524 typedef enum {
1525 USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
1526 } used_t;
1529 * get_cluster_count_for_direntry() not only determines how many clusters
1530 * are occupied by direntry, but also if it was renamed or modified.
1532 * A file is thought to be renamed *only* if there already was a file with
1533 * exactly the same first cluster, but a different name.
1535 * Further, the files/directories handled by this function are
1536 * assumed to be *not* deleted (and *only* those).
1538 static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
1539 direntry_t* direntry, const char* path)
1542 * This is a little bit tricky:
1543 * IF the guest OS just inserts a cluster into the file chain,
1544 * and leaves the rest alone, (i.e. the original file had clusters
1545 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1547 * - do_commit will write the cluster into the file at the given
1548 * offset, but
1550 * - the cluster which is overwritten should be moved to a later
1551 * position in the file.
1553 * I am not aware that any OS does something as braindead, but this
1554 * situation could happen anyway when not committing for a long time.
1555 * Just to be sure that this does not bite us, detect it, and copy the
1556 * contents of the clusters to-be-overwritten into the qcow.
1558 int copy_it = 0;
1559 int was_modified = 0;
1560 int32_t ret = 0;
1562 uint32_t cluster_num = begin_of_direntry(direntry);
1563 uint32_t offset = 0;
1564 int first_mapping_index = -1;
1565 mapping_t* mapping = NULL;
1566 const char* basename2 = NULL;
1568 vvfat_close_current_file(s);
1570 /* the root directory */
1571 if (cluster_num == 0)
1572 return 0;
1574 /* write support */
1575 if (s->qcow) {
1576 basename2 = get_basename(path);
1578 mapping = find_mapping_for_cluster(s, cluster_num);
1580 if (mapping) {
1581 assert(mapping->mode & MODE_DELETED);
1582 mapping->mode &= ~MODE_DELETED;
1584 const char* basename = get_basename(mapping->path);
1586 assert(mapping->mode & MODE_NORMAL);
1588 /* rename */
1589 if (strcmp(basename, basename2))
1590 schedule_rename(s, cluster_num, strdup(path));
1591 } else if (is_file(direntry))
1592 /* new file */
1593 schedule_new_file(s, strdup(path), cluster_num);
1594 else {
1595 assert(0);
1596 return 0;
1600 while(1) {
1601 if (s->qcow) {
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);
1609 if (mapping &&
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 */
1616 assert(0);
1617 copy_it = 1;
1618 } else if (offset == 0) {
1619 const char* basename = get_basename(mapping->path);
1621 if (strcmp(basename, basename2))
1622 copy_it = 1;
1623 first_mapping_index = array_index(&(s->mapping), mapping);
1626 if (mapping->first_mapping_index != first_mapping_index
1627 && mapping->info.file.offset > 0) {
1628 assert(0);
1629 copy_it = 1;
1632 /* need to write out? */
1633 if (!was_modified && is_file(direntry)) {
1634 was_modified = 1;
1635 schedule_writeout(s, mapping->dir_index, offset);
1640 if (copy_it) {
1641 int i, dummy;
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))
1654 return -1;
1655 if (s->qcow->drv->bdrv_write(s->qcow,
1656 offset, s->cluster_buffer, 1))
1657 return -2;
1662 ret++;
1663 if (s->used_clusters[cluster_num] & USED_ANY)
1664 return 0;
1665 s->used_clusters[cluster_num] = USED_FILE;
1667 cluster_num = modified_fat_get(s, cluster_num);
1669 if (fat_eof(s, cluster_num))
1670 return ret;
1671 else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
1672 return -1;
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)
1686 int ret = 0;
1687 unsigned char* cluster = malloc(s->cluster_size);
1688 direntry_t* direntries = (direntry_t*)cluster;
1689 mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
1691 long_file_name lfn;
1692 int path_len = strlen(path);
1693 char path2[PATH_MAX];
1695 assert(path_len < PATH_MAX); /* len was tested before! */
1696 strcpy(path2, path);
1697 path2[path_len] = '/';
1698 path2[path_len + 1] = '\0';
1700 if (mapping) {
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, strdup(path));
1711 } else
1712 /* new directory */
1713 schedule_mkdir(s, cluster_num, strdup(path));
1715 lfn_init(&lfn);
1716 do {
1717 int i;
1718 int subret = 0;
1720 ret++;
1722 if (s->used_clusters[cluster_num] & USED_ANY) {
1723 fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
1724 return 0;
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);
1731 if (subret) {
1732 fprintf(stderr, "Error fetching direntries\n");
1733 fail:
1734 free(cluster);
1735 return 0;
1738 for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
1739 int cluster_count;
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))
1744 continue;
1746 subret = parse_long_name(&lfn, direntries + i);
1747 if (subret < 0) {
1748 fprintf(stderr, "Error in long name\n");
1749 goto fail;
1751 if (subret == 0 || is_free(direntries + i))
1752 continue;
1754 if (fat_chksum(direntries+i) != lfn.checksum) {
1755 subret = parse_short_name(s, &lfn, direntries + i);
1756 if (subret < 0) {
1757 fprintf(stderr, "Error in short name (%d)\n", subret);
1758 goto fail;
1760 if (subret > 0 || !strcmp(lfn.name, ".")
1761 || !strcmp(lfn.name, ".."))
1762 continue;
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);
1768 goto fail;
1770 strcpy(path2 + path_len + 1, lfn.name);
1772 if (is_directory(direntries + i)) {
1773 if (begin_of_direntry(direntries + i) == 0) {
1774 DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
1775 goto fail;
1777 cluster_count = check_directory_consistency(s,
1778 begin_of_direntry(direntries + i), path2);
1779 if (cluster_count == 0) {
1780 DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
1781 goto fail;
1783 } else if (is_file(direntries + i)) {
1784 /* check file size with FAT */
1785 cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
1786 if (cluster_count !=
1787 (le32_to_cpu(direntries[i].size) + s->cluster_size
1788 - 1) / s->cluster_size) {
1789 DLOG(fprintf(stderr, "Cluster count mismatch\n"));
1790 goto fail;
1792 } else
1793 assert(0); /* cluster_count = 0; */
1795 ret += cluster_count;
1798 cluster_num = modified_fat_get(s, cluster_num);
1799 } while(!fat_eof(s, cluster_num));
1801 free(cluster);
1802 return ret;
1805 /* returns 1 on success */
1806 static int is_consistent(BDRVVVFATState* s)
1808 int i, check;
1809 int used_clusters_count = 0;
1811 DLOG(checkpoint());
1813 * - get modified FAT
1814 * - compare the two FATs (TODO)
1815 * - get buffer for marking used clusters
1816 * - recurse direntries from root (using bs->bdrv_read to make
1817 * sure to get the new data)
1818 * - check that the FAT agrees with the size
1819 * - count the number of clusters occupied by this directory and
1820 * its files
1821 * - check that the cumulative used cluster count agrees with the
1822 * FAT
1823 * - if all is fine, return number of used clusters
1825 if (s->fat2 == NULL) {
1826 int size = 0x200 * s->sectors_per_fat;
1827 s->fat2 = malloc(size);
1828 memcpy(s->fat2, s->fat.pointer, size);
1830 check = vvfat_read(s->bs,
1831 s->first_sectors_number, s->fat2, s->sectors_per_fat);
1832 if (check) {
1833 fprintf(stderr, "Could not copy fat\n");
1834 return 0;
1836 assert (s->used_clusters);
1837 for (i = 0; i < sector2cluster(s, s->sector_count); i++)
1838 s->used_clusters[i] &= ~USED_ANY;
1840 clear_commits(s);
1842 /* mark every mapped file/directory as deleted.
1843 * (check_directory_consistency() will unmark those still present). */
1844 if (s->qcow)
1845 for (i = 0; i < s->mapping.next; i++) {
1846 mapping_t* mapping = array_get(&(s->mapping), i);
1847 if (mapping->first_mapping_index < 0)
1848 mapping->mode |= MODE_DELETED;
1851 used_clusters_count = check_directory_consistency(s, 0, s->path);
1852 if (used_clusters_count <= 0) {
1853 DLOG(fprintf(stderr, "problem in directory\n"));
1854 return 0;
1857 check = s->last_cluster_of_root_directory;
1858 for (i = check; i < sector2cluster(s, s->sector_count); i++) {
1859 if (modified_fat_get(s, i)) {
1860 if(!s->used_clusters[i]) {
1861 DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
1862 return 0;
1864 check++;
1867 if (s->used_clusters[i] == USED_ALLOCATED) {
1868 /* allocated, but not used... */
1869 DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
1870 return 0;
1874 if (check != used_clusters_count)
1875 return 0;
1877 return used_clusters_count;
1880 static inline void adjust_mapping_indices(BDRVVVFATState* s,
1881 int offset, int adjust)
1883 int i;
1885 for (i = 0; i < s->mapping.next; i++) {
1886 mapping_t* mapping = array_get(&(s->mapping), i);
1888 #define ADJUST_MAPPING_INDEX(name) \
1889 if (mapping->name >= offset) \
1890 mapping->name += adjust
1892 ADJUST_MAPPING_INDEX(first_mapping_index);
1893 if (mapping->mode & MODE_DIRECTORY)
1894 ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
1898 /* insert or update mapping */
1899 static mapping_t* insert_mapping(BDRVVVFATState* s,
1900 uint32_t begin, uint32_t end)
1903 * - find mapping where mapping->begin >= begin,
1904 * - if mapping->begin > begin: insert
1905 * - adjust all references to mappings!
1906 * - else: adjust
1907 * - replace name
1909 int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
1910 mapping_t* mapping = NULL;
1911 mapping_t* first_mapping = array_get(&(s->mapping), 0);
1913 if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
1914 && mapping->begin < begin) {
1915 mapping->end = begin;
1916 index++;
1917 mapping = array_get(&(s->mapping), index);
1919 if (index >= s->mapping.next || mapping->begin > begin) {
1920 mapping = array_insert(&(s->mapping), index, 1);
1921 mapping->path = NULL;
1922 adjust_mapping_indices(s, index, +1);
1925 mapping->begin = begin;
1926 mapping->end = end;
1928 DLOG(mapping_t* next_mapping;
1929 assert(index + 1 >= s->mapping.next ||
1930 ((next_mapping = array_get(&(s->mapping), index + 1)) &&
1931 next_mapping->begin >= end)));
1933 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1934 s->current_mapping = array_get(&(s->mapping),
1935 s->current_mapping - first_mapping);
1937 return mapping;
1940 static int remove_mapping(BDRVVVFATState* s, int mapping_index)
1942 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
1943 mapping_t* first_mapping = array_get(&(s->mapping), 0);
1945 /* free mapping */
1946 if (mapping->first_mapping_index < 0)
1947 free(mapping->path);
1949 /* remove from s->mapping */
1950 array_remove(&(s->mapping), mapping_index);
1952 /* adjust all references to mappings */
1953 adjust_mapping_indices(s, mapping_index, -1);
1955 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1956 s->current_mapping = array_get(&(s->mapping),
1957 s->current_mapping - first_mapping);
1959 return 0;
1962 static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
1964 int i;
1965 for (i = 0; i < s->mapping.next; i++) {
1966 mapping_t* mapping = array_get(&(s->mapping), i);
1967 if (mapping->dir_index >= offset)
1968 mapping->dir_index += adjust;
1969 if ((mapping->mode & MODE_DIRECTORY) &&
1970 mapping->info.dir.first_dir_index >= offset)
1971 mapping->info.dir.first_dir_index += adjust;
1975 static direntry_t* insert_direntries(BDRVVVFATState* s,
1976 int dir_index, int count)
1979 * make room in s->directory,
1980 * adjust_dirindices
1982 direntry_t* result = array_insert(&(s->directory), dir_index, count);
1983 if (result == NULL)
1984 return NULL;
1985 adjust_dirindices(s, dir_index, count);
1986 return result;
1989 static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
1991 int ret = array_remove_slice(&(s->directory), dir_index, count);
1992 if (ret)
1993 return ret;
1994 adjust_dirindices(s, dir_index, -count);
1995 return 0;
1999 * Adapt the mappings of the cluster chain starting at first cluster
2000 * (i.e. if a file starts at first_cluster, the chain is followed according
2001 * to the modified fat, and the corresponding entries in s->mapping are
2002 * adjusted)
2004 static int commit_mappings(BDRVVVFATState* s,
2005 uint32_t first_cluster, int dir_index)
2007 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2008 direntry_t* direntry = array_get(&(s->directory), dir_index);
2009 uint32_t cluster = first_cluster;
2011 vvfat_close_current_file(s);
2013 assert(mapping);
2014 assert(mapping->begin == first_cluster);
2015 mapping->first_mapping_index = -1;
2016 mapping->dir_index = dir_index;
2017 mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2018 MODE_DIRECTORY : MODE_NORMAL;
2020 while (!fat_eof(s, cluster)) {
2021 uint32_t c, c1;
2023 for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2024 c = c1, c1 = modified_fat_get(s, c1));
2026 c++;
2027 if (c > mapping->end) {
2028 int index = array_index(&(s->mapping), mapping);
2029 int i, max_i = s->mapping.next - index;
2030 for (i = 1; i < max_i && mapping[i].begin < c; i++);
2031 while (--i > 0)
2032 remove_mapping(s, index + 1);
2034 assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2035 || mapping[1].begin >= c);
2036 mapping->end = c;
2038 if (!fat_eof(s, c1)) {
2039 int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2040 mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2041 array_get(&(s->mapping), i);
2043 if (next_mapping == NULL || next_mapping->begin > c1) {
2044 int i1 = array_index(&(s->mapping), mapping);
2046 next_mapping = insert_mapping(s, c1, c1+1);
2048 if (c1 < c)
2049 i1++;
2050 mapping = array_get(&(s->mapping), i1);
2053 next_mapping->dir_index = mapping->dir_index;
2054 next_mapping->first_mapping_index =
2055 mapping->first_mapping_index < 0 ?
2056 array_index(&(s->mapping), mapping) :
2057 mapping->first_mapping_index;
2058 next_mapping->path = mapping->path;
2059 next_mapping->mode = mapping->mode;
2060 next_mapping->read_only = mapping->read_only;
2061 if (mapping->mode & MODE_DIRECTORY) {
2062 next_mapping->info.dir.parent_mapping_index =
2063 mapping->info.dir.parent_mapping_index;
2064 next_mapping->info.dir.first_dir_index =
2065 mapping->info.dir.first_dir_index +
2066 0x10 * s->sectors_per_cluster *
2067 (mapping->end - mapping->begin);
2068 } else
2069 next_mapping->info.file.offset = mapping->info.file.offset +
2070 mapping->end - mapping->begin;
2072 mapping = next_mapping;
2075 cluster = c1;
2078 return 0;
2081 static int commit_direntries(BDRVVVFATState* s,
2082 int dir_index, int parent_mapping_index)
2084 direntry_t* direntry = array_get(&(s->directory), dir_index);
2085 uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
2086 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2088 int factor = 0x10 * s->sectors_per_cluster;
2089 int old_cluster_count, new_cluster_count;
2090 int current_dir_index = mapping->info.dir.first_dir_index;
2091 int first_dir_index = current_dir_index;
2092 int ret, i;
2093 uint32_t c;
2095 DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
2097 assert(direntry);
2098 assert(mapping);
2099 assert(mapping->begin == first_cluster);
2100 assert(mapping->info.dir.first_dir_index < s->directory.next);
2101 assert(mapping->mode & MODE_DIRECTORY);
2102 assert(dir_index == 0 || is_directory(direntry));
2104 mapping->info.dir.parent_mapping_index = parent_mapping_index;
2106 if (first_cluster == 0) {
2107 old_cluster_count = new_cluster_count =
2108 s->last_cluster_of_root_directory;
2109 } else {
2110 for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2111 c = fat_get(s, c))
2112 old_cluster_count++;
2114 for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2115 c = modified_fat_get(s, c))
2116 new_cluster_count++;
2119 if (new_cluster_count > old_cluster_count) {
2120 if (insert_direntries(s,
2121 current_dir_index + factor * old_cluster_count,
2122 factor * (new_cluster_count - old_cluster_count)) == NULL)
2123 return -1;
2124 } else if (new_cluster_count < old_cluster_count)
2125 remove_direntries(s,
2126 current_dir_index + factor * new_cluster_count,
2127 factor * (old_cluster_count - new_cluster_count));
2129 for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
2130 void* direntry = array_get(&(s->directory), current_dir_index);
2131 int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2132 s->sectors_per_cluster);
2133 if (ret)
2134 return ret;
2135 assert(!strncmp(s->directory.pointer, "QEMU", 4));
2136 current_dir_index += factor;
2139 ret = commit_mappings(s, first_cluster, dir_index);
2140 if (ret)
2141 return ret;
2143 /* recurse */
2144 for (i = 0; i < factor * new_cluster_count; i++) {
2145 direntry = array_get(&(s->directory), first_dir_index + i);
2146 if (is_directory(direntry) && !is_dot(direntry)) {
2147 mapping = find_mapping_for_cluster(s, first_cluster);
2148 assert(mapping->mode & MODE_DIRECTORY);
2149 ret = commit_direntries(s, first_dir_index + i,
2150 array_index(&(s->mapping), mapping));
2151 if (ret)
2152 return ret;
2156 return 0;
2159 /* commit one file (adjust contents, adjust mapping),
2160 return first_mapping_index */
2161 static int commit_one_file(BDRVVVFATState* s,
2162 int dir_index, uint32_t offset)
2164 direntry_t* direntry = array_get(&(s->directory), dir_index);
2165 uint32_t c = begin_of_direntry(direntry);
2166 uint32_t first_cluster = c;
2167 mapping_t* mapping = find_mapping_for_cluster(s, c);
2168 uint32_t size = filesize_of_direntry(direntry);
2169 char* cluster = malloc(s->cluster_size);
2170 uint32_t i;
2171 int fd = 0;
2173 assert(offset < size);
2174 assert((offset % s->cluster_size) == 0);
2176 for (i = s->cluster_size; i < offset; i += s->cluster_size)
2177 c = modified_fat_get(s, c);
2179 fd = open(mapping->path, O_RDWR | O_CREAT, 0666);
2180 if (fd < 0) {
2181 fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2182 strerror(errno), errno);
2183 return fd;
2185 if (offset > 0)
2186 if (lseek(fd, offset, SEEK_SET) != offset)
2187 return -3;
2189 while (offset < size) {
2190 uint32_t c1;
2191 int rest_size = (size - offset > s->cluster_size ?
2192 s->cluster_size : size - offset);
2193 int ret;
2195 c1 = modified_fat_get(s, c);
2197 assert((size - offset == 0 && fat_eof(s, c)) ||
2198 (size > offset && c >=2 && !fat_eof(s, c)));
2199 assert(size >= 0);
2201 ret = vvfat_read(s->bs, cluster2sector(s, c),
2202 cluster, (rest_size + 0x1ff) / 0x200);
2204 if (ret < 0)
2205 return ret;
2207 if (write(fd, cluster, rest_size) < 0)
2208 return -2;
2210 offset += rest_size;
2211 c = c1;
2214 ftruncate(fd, size);
2215 close(fd);
2217 return commit_mappings(s, first_cluster, dir_index);
2220 #ifdef DEBUG
2221 /* test, if all mappings point to valid direntries */
2222 static void check1(BDRVVVFATState* s)
2224 int i;
2225 for (i = 0; i < s->mapping.next; i++) {
2226 mapping_t* mapping = array_get(&(s->mapping), i);
2227 if (mapping->mode & MODE_DELETED) {
2228 fprintf(stderr, "deleted\n");
2229 continue;
2231 assert(mapping->dir_index >= 0);
2232 assert(mapping->dir_index < s->directory.next);
2233 direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2234 assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2235 if (mapping->mode & MODE_DIRECTORY) {
2236 assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2237 assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2242 /* test, if all direntries have mappings */
2243 static void check2(BDRVVVFATState* s)
2245 int i;
2246 int first_mapping = -1;
2248 for (i = 0; i < s->directory.next; i++) {
2249 direntry_t* direntry = array_get(&(s->directory), i);
2251 if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2252 mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2253 assert(mapping);
2254 assert(mapping->dir_index == i || is_dot(direntry));
2255 assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2258 if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2259 /* cluster start */
2260 int j, count = 0;
2262 for (j = 0; j < s->mapping.next; j++) {
2263 mapping_t* mapping = array_get(&(s->mapping), j);
2264 if (mapping->mode & MODE_DELETED)
2265 continue;
2266 if (mapping->mode & MODE_DIRECTORY) {
2267 if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2268 assert(++count == 1);
2269 if (mapping->first_mapping_index == -1)
2270 first_mapping = array_index(&(s->mapping), mapping);
2271 else
2272 assert(first_mapping == mapping->first_mapping_index);
2273 if (mapping->info.dir.parent_mapping_index < 0)
2274 assert(j == 0);
2275 else {
2276 mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2277 assert(parent->mode & MODE_DIRECTORY);
2278 assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2283 if (count == 0)
2284 first_mapping = -1;
2288 #endif
2290 static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2292 int i;
2294 #ifdef DEBUG
2295 fprintf(stderr, "handle_renames\n");
2296 for (i = 0; i < s->commits.next; i++) {
2297 commit_t* commit = array_get(&(s->commits), i);
2298 fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
2300 #endif
2302 for (i = 0; i < s->commits.next;) {
2303 commit_t* commit = array_get(&(s->commits), i);
2304 if (commit->action == ACTION_RENAME) {
2305 mapping_t* mapping = find_mapping_for_cluster(s,
2306 commit->param.rename.cluster);
2307 char* old_path = mapping->path;
2309 assert(commit->path);
2310 mapping->path = commit->path;
2311 if (rename(old_path, mapping->path))
2312 return -2;
2314 if (mapping->mode & MODE_DIRECTORY) {
2315 int l1 = strlen(mapping->path);
2316 int l2 = strlen(old_path);
2317 int diff = l1 - l2;
2318 direntry_t* direntry = array_get(&(s->directory),
2319 mapping->info.dir.first_dir_index);
2320 uint32_t c = mapping->begin;
2321 int i = 0;
2323 /* recurse */
2324 while (!fat_eof(s, c)) {
2325 do {
2326 direntry_t* d = direntry + i;
2328 if (is_file(d) || (is_directory(d) && !is_dot(d))) {
2329 mapping_t* m = find_mapping_for_cluster(s,
2330 begin_of_direntry(d));
2331 int l = strlen(m->path);
2332 char* new_path = malloc(l + diff + 1);
2334 assert(!strncmp(m->path, mapping->path, l2));
2336 strcpy(new_path, mapping->path);
2337 strcpy(new_path + l1, m->path + l2);
2339 schedule_rename(s, m->begin, new_path);
2341 i++;
2342 } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2343 c = fat_get(s, c);
2347 free(old_path);
2348 array_remove(&(s->commits), i);
2349 continue;
2350 } else if (commit->action == ACTION_MKDIR) {
2351 mapping_t* mapping;
2352 int j, parent_path_len;
2354 #ifdef __MINGW32__
2355 if (mkdir(commit->path))
2356 return -5;
2357 #else
2358 if (mkdir(commit->path, 0755))
2359 return -5;
2360 #endif
2362 mapping = insert_mapping(s, commit->param.mkdir.cluster,
2363 commit->param.mkdir.cluster + 1);
2364 if (mapping == NULL)
2365 return -6;
2367 mapping->mode = MODE_DIRECTORY;
2368 mapping->read_only = 0;
2369 mapping->path = commit->path;
2370 j = s->directory.next;
2371 assert(j);
2372 insert_direntries(s, s->directory.next,
2373 0x10 * s->sectors_per_cluster);
2374 mapping->info.dir.first_dir_index = j;
2376 parent_path_len = strlen(commit->path)
2377 - strlen(get_basename(commit->path)) - 1;
2378 for (j = 0; j < s->mapping.next; j++) {
2379 mapping_t* m = array_get(&(s->mapping), j);
2380 if (m->first_mapping_index < 0 && m != mapping &&
2381 !strncmp(m->path, mapping->path, parent_path_len) &&
2382 strlen(m->path) == parent_path_len)
2383 break;
2385 assert(j < s->mapping.next);
2386 mapping->info.dir.parent_mapping_index = j;
2388 array_remove(&(s->commits), i);
2389 continue;
2392 i++;
2394 return 0;
2398 * TODO: make sure that the short name is not matching *another* file
2400 static int handle_commits(BDRVVVFATState* s)
2402 int i, fail = 0;
2404 vvfat_close_current_file(s);
2406 for (i = 0; !fail && i < s->commits.next; i++) {
2407 commit_t* commit = array_get(&(s->commits), i);
2408 switch(commit->action) {
2409 case ACTION_RENAME: case ACTION_MKDIR:
2410 assert(0);
2411 fail = -2;
2412 break;
2413 case ACTION_WRITEOUT: {
2414 direntry_t* entry = array_get(&(s->directory),
2415 commit->param.writeout.dir_index);
2416 uint32_t begin = begin_of_direntry(entry);
2417 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2419 assert(mapping);
2420 assert(mapping->begin == begin);
2421 assert(commit->path == NULL);
2423 if (commit_one_file(s, commit->param.writeout.dir_index,
2424 commit->param.writeout.modified_offset))
2425 fail = -3;
2427 break;
2429 case ACTION_NEW_FILE: {
2430 int begin = commit->param.new_file.first_cluster;
2431 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2432 direntry_t* entry;
2433 int i;
2435 /* find direntry */
2436 for (i = 0; i < s->directory.next; i++) {
2437 entry = array_get(&(s->directory), i);
2438 if (is_file(entry) && begin_of_direntry(entry) == begin)
2439 break;
2442 if (i >= s->directory.next) {
2443 fail = -6;
2444 continue;
2447 /* make sure there exists an initial mapping */
2448 if (mapping && mapping->begin != begin) {
2449 mapping->end = begin;
2450 mapping = NULL;
2452 if (mapping == NULL) {
2453 mapping = insert_mapping(s, begin, begin+1);
2455 /* most members will be fixed in commit_mappings() */
2456 assert(commit->path);
2457 mapping->path = commit->path;
2458 mapping->read_only = 0;
2459 mapping->mode = MODE_NORMAL;
2460 mapping->info.file.offset = 0;
2462 if (commit_one_file(s, i, 0))
2463 fail = -7;
2465 break;
2467 default:
2468 assert(0);
2471 if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2472 return -1;
2473 return fail;
2476 static int handle_deletes(BDRVVVFATState* s)
2478 int i, deferred = 1, deleted = 1;
2480 /* delete files corresponding to mappings marked as deleted */
2481 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2482 while (deferred && deleted) {
2483 deferred = 0;
2484 deleted = 0;
2486 for (i = 1; i < s->mapping.next; i++) {
2487 mapping_t* mapping = array_get(&(s->mapping), i);
2488 if (mapping->mode & MODE_DELETED) {
2489 direntry_t* entry = array_get(&(s->directory),
2490 mapping->dir_index);
2492 if (is_free(entry)) {
2493 /* remove file/directory */
2494 if (mapping->mode & MODE_DIRECTORY) {
2495 int j, next_dir_index = s->directory.next,
2496 first_dir_index = mapping->info.dir.first_dir_index;
2498 if (rmdir(mapping->path) < 0) {
2499 if (errno == ENOTEMPTY) {
2500 deferred++;
2501 continue;
2502 } else
2503 return -5;
2506 for (j = 1; j < s->mapping.next; j++) {
2507 mapping_t* m = array_get(&(s->mapping), j);
2508 if (m->mode & MODE_DIRECTORY &&
2509 m->info.dir.first_dir_index >
2510 first_dir_index &&
2511 m->info.dir.first_dir_index <
2512 next_dir_index)
2513 next_dir_index =
2514 m->info.dir.first_dir_index;
2516 remove_direntries(s, first_dir_index,
2517 next_dir_index - first_dir_index);
2519 deleted++;
2521 } else {
2522 if (unlink(mapping->path))
2523 return -4;
2524 deleted++;
2526 DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2527 remove_mapping(s, i);
2532 return 0;
2536 * synchronize mapping with new state:
2538 * - copy FAT (with bdrv_read)
2539 * - mark all filenames corresponding to mappings as deleted
2540 * - recurse direntries from root (using bs->bdrv_read)
2541 * - delete files corresponding to mappings marked as deleted
2543 static int do_commit(BDRVVVFATState* s)
2545 int ret = 0;
2547 /* the real meat are the commits. Nothing to do? Move along! */
2548 if (s->commits.next == 0)
2549 return 0;
2551 vvfat_close_current_file(s);
2553 ret = handle_renames_and_mkdirs(s);
2554 if (ret) {
2555 fprintf(stderr, "Error handling renames (%d)\n", ret);
2556 assert(0);
2557 return ret;
2560 /* copy FAT (with bdrv_read) */
2561 memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2563 /* recurse direntries from root (using bs->bdrv_read) */
2564 ret = commit_direntries(s, 0, -1);
2565 if (ret) {
2566 fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
2567 assert(0);
2568 return ret;
2571 ret = handle_commits(s);
2572 if (ret) {
2573 fprintf(stderr, "Error handling commits (%d)\n", ret);
2574 assert(0);
2575 return ret;
2578 ret = handle_deletes(s);
2579 if (ret) {
2580 fprintf(stderr, "Error deleting\n");
2581 assert(0);
2582 return ret;
2585 s->qcow->drv->bdrv_make_empty(s->qcow);
2587 memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2589 DLOG(checkpoint());
2590 return 0;
2593 static int try_commit(BDRVVVFATState* s)
2595 vvfat_close_current_file(s);
2596 DLOG(checkpoint());
2597 if(!is_consistent(s))
2598 return -1;
2599 return do_commit(s);
2602 static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
2603 const uint8_t *buf, int nb_sectors)
2605 BDRVVVFATState *s = bs->opaque;
2606 int i, ret;
2608 DLOG(checkpoint());
2610 vvfat_close_current_file(s);
2613 * Some sanity checks:
2614 * - do not allow writing to the boot sector
2615 * - do not allow to write non-ASCII filenames
2618 if (sector_num < s->first_sectors_number)
2619 return -1;
2621 for (i = sector2cluster(s, sector_num);
2622 i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
2623 mapping_t* mapping = find_mapping_for_cluster(s, i);
2624 if (mapping) {
2625 if (mapping->read_only) {
2626 fprintf(stderr, "Tried to write to write-protected file %s\n",
2627 mapping->path);
2628 return -1;
2631 if (mapping->mode & MODE_DIRECTORY) {
2632 int begin = cluster2sector(s, i);
2633 int end = begin + s->sectors_per_cluster, k;
2634 int dir_index;
2635 const direntry_t* direntries;
2636 long_file_name lfn;
2638 lfn_init(&lfn);
2640 if (begin < sector_num)
2641 begin = sector_num;
2642 if (end > sector_num + nb_sectors)
2643 end = sector_num + nb_sectors;
2644 dir_index = mapping->dir_index +
2645 0x10 * (begin - mapping->begin * s->sectors_per_cluster);
2646 direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
2648 for (k = 0; k < (end - begin) * 0x10; k++) {
2649 /* do not allow non-ASCII filenames */
2650 if (parse_long_name(&lfn, direntries + k) < 0) {
2651 fprintf(stderr, "Warning: non-ASCII filename\n");
2652 return -1;
2654 /* no access to the direntry of a read-only file */
2655 else if (is_short_name(direntries+k) &&
2656 (direntries[k].attributes & 1)) {
2657 if (memcmp(direntries + k,
2658 array_get(&(s->directory), dir_index + k),
2659 sizeof(direntry_t))) {
2660 fprintf(stderr, "Warning: tried to write to write-protected file\n");
2661 return -1;
2666 i = mapping->end;
2667 } else
2668 i++;
2672 * Use qcow backend. Commit later.
2674 DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
2675 ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
2676 if (ret < 0) {
2677 fprintf(stderr, "Error writing to qcow backend\n");
2678 return ret;
2681 for (i = sector2cluster(s, sector_num);
2682 i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
2683 if (i >= 0)
2684 s->used_clusters[i] |= USED_ALLOCATED;
2686 DLOG(checkpoint());
2687 /* TODO: add timeout */
2688 try_commit(s);
2690 DLOG(checkpoint());
2691 return 0;
2694 static int vvfat_is_allocated(BlockDriverState *bs,
2695 int64_t sector_num, int nb_sectors, int* n)
2697 BDRVVVFATState* s = bs->opaque;
2698 *n = s->sector_count - sector_num;
2699 if (*n > nb_sectors)
2700 *n = nb_sectors;
2701 else if (*n < 0)
2702 return 0;
2703 return 1;
2706 static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
2707 const uint8_t* buffer, int nb_sectors) {
2708 BDRVVVFATState* s = bs->opaque;
2709 return try_commit(s);
2712 static void write_target_close(BlockDriverState *bs) {
2713 BDRVVVFATState* s = bs->opaque;
2714 bdrv_delete(s->qcow);
2715 free(s->qcow_filename);
2718 static BlockDriver vvfat_write_target = {
2719 "vvfat_write_target", 0, NULL, NULL, NULL,
2720 write_target_commit,
2721 write_target_close,
2722 NULL, NULL, NULL
2725 static int enable_write_target(BDRVVVFATState *s)
2727 int size = sector2cluster(s, s->sector_count);
2728 s->used_clusters = calloc(size, 1);
2730 array_init(&(s->commits), sizeof(commit_t));
2732 s->qcow_filename = malloc(1024);
2733 strcpy(s->qcow_filename, "/tmp/vl.XXXXXX");
2734 get_tmp_filename(s->qcow_filename, strlen(s->qcow_filename) + 1);
2735 if (bdrv_create(&bdrv_qcow,
2736 s->qcow_filename, s->sector_count, "fat:", 0) < 0)
2737 return -1;
2738 s->qcow = bdrv_new("");
2739 if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
2740 return -1;
2742 #ifndef _WIN32
2743 unlink(s->qcow_filename);
2744 #endif
2746 s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
2747 s->bs->backing_hd->drv = &vvfat_write_target;
2748 s->bs->backing_hd->opaque = s;
2750 return 0;
2753 static void vvfat_close(BlockDriverState *bs)
2755 BDRVVVFATState *s = bs->opaque;
2757 vvfat_close_current_file(s);
2758 array_free(&(s->fat));
2759 array_free(&(s->directory));
2760 array_free(&(s->mapping));
2761 if(s->cluster_buffer)
2762 free(s->cluster_buffer);
2765 BlockDriver bdrv_vvfat = {
2766 "vvfat",
2767 sizeof(BDRVVVFATState),
2768 vvfat_probe,
2769 vvfat_open,
2770 vvfat_read,
2771 vvfat_write,
2772 vvfat_close,
2773 NULL,
2774 vvfat_is_allocated
2777 #ifdef DEBUG
2778 static void checkpoint() {
2779 assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
2780 check1(vvv);
2781 check2(vvv);
2782 assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
2783 #if 0
2784 if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
2785 fprintf(stderr, "Nonono!\n");
2786 mapping_t* mapping;
2787 direntry_t* direntry;
2788 assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
2789 assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
2790 if (vvv->mapping.next<47)
2791 return;
2792 assert((mapping = array_get(&(vvv->mapping), 47)));
2793 assert(mapping->dir_index < vvv->directory.next);
2794 direntry = array_get(&(vvv->directory), mapping->dir_index);
2795 assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0);
2796 #endif
2797 return;
2798 /* avoid compiler warnings: */
2799 hexdump(NULL, 100);
2800 remove_mapping(vvv, NULL);
2801 print_mapping(NULL);
2802 print_direntry(NULL);
2804 #endif