darwin fix
[qemu/mdroth.git] / block-vvfat.c
blob48a52e3116cfcd06b5b3bac04dbd059d46e05d5b
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) 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 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 void init_mbr(BDRVVVFATState* s)
356 /* TODO: if the files mbr.img and bootsect.img exist, use them */
357 mbr_t* real_mbr=(mbr_t*)s->first_sectors;
358 partition_t* partition=&(real_mbr->partition[0]);
360 memset(s->first_sectors,0,512);
362 partition->attributes=0x80; /* bootable */
363 partition->start_head=1;
364 partition->start_sector=1;
365 partition->start_cylinder=0;
366 /* FAT12/FAT16/FAT32 */
367 partition->fs_type=(s->fat_type==12?0x1:s->fat_type==16?0x6:0xb);
368 partition->end_head=s->bs->heads-1;
369 partition->end_sector=0xff; /* end sector & upper 2 bits of cylinder */;
370 partition->end_cylinder=0xff; /* lower 8 bits of end cylinder */;
371 partition->start_sector_long=cpu_to_le32(s->bs->secs);
372 partition->end_sector_long=cpu_to_le32(s->sector_count);
374 real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
377 /* direntry functions */
379 /* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
380 static inline int short2long_name(unsigned char* dest,const char* src)
382 int i;
383 for(i=0;i<129 && src[i];i++) {
384 dest[2*i]=src[i];
385 dest[2*i+1]=0;
387 dest[2*i]=dest[2*i+1]=0;
388 for(i=2*i+2;(i%26);i++)
389 dest[i]=0xff;
390 return i;
393 static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
395 char buffer[258];
396 int length=short2long_name(buffer,filename),
397 number_of_entries=(length+25)/26,i;
398 direntry_t* entry;
400 for(i=0;i<number_of_entries;i++) {
401 entry=array_get_next(&(s->directory));
402 entry->attributes=0xf;
403 entry->reserved[0]=0;
404 entry->begin=0;
405 entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
407 for(i=0;i<length;i++) {
408 int offset=(i%26);
409 if(offset<10) offset=1+offset;
410 else if(offset<22) offset=14+offset-10;
411 else offset=28+offset-22;
412 entry=array_get(&(s->directory),s->directory.next-1-(i/26));
413 entry->name[offset]=buffer[i];
415 return array_get(&(s->directory),s->directory.next-number_of_entries);
418 static char is_free(const direntry_t* direntry)
420 /* return direntry->name[0]==0 ; */
421 return direntry->attributes == 0 || direntry->name[0]==0xe5;
424 static char is_volume_label(const direntry_t* direntry)
426 return direntry->attributes == 0x28;
429 static char is_long_name(const direntry_t* direntry)
431 return direntry->attributes == 0xf;
434 static char is_short_name(const direntry_t* direntry)
436 return !is_volume_label(direntry) && !is_long_name(direntry)
437 && !is_free(direntry);
440 static char is_directory(const direntry_t* direntry)
442 return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
445 static inline char is_dot(const direntry_t* direntry)
447 return is_short_name(direntry) && direntry->name[0] == '.';
450 static char is_file(const direntry_t* direntry)
452 return is_short_name(direntry) && !is_directory(direntry);
455 static inline uint32_t begin_of_direntry(const direntry_t* direntry)
457 return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
460 static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
462 return le32_to_cpu(direntry->size);
465 static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
467 direntry->begin = cpu_to_le16(begin & 0xffff);
468 direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
471 /* fat functions */
473 static inline uint8_t fat_chksum(const direntry_t* entry)
475 uint8_t chksum=0;
476 int i;
478 for(i=0;i<11;i++)
479 chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0))
480 +(unsigned char)entry->name[i];
482 return chksum;
485 /* if return_time==0, this returns the fat_date, else the fat_time */
486 static uint16_t fat_datetime(time_t time,int return_time) {
487 struct tm* t;
488 #ifdef _WIN32
489 t=localtime(&time); /* this is not thread safe */
490 #else
491 struct tm t1;
492 t=&t1;
493 localtime_r(&time,t);
494 #endif
495 if(return_time)
496 return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
497 return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
500 static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
502 if(s->fat_type==32) {
503 uint32_t* entry=array_get(&(s->fat),cluster);
504 *entry=cpu_to_le32(value);
505 } else if(s->fat_type==16) {
506 uint16_t* entry=array_get(&(s->fat),cluster);
507 *entry=cpu_to_le16(value&0xffff);
508 } else {
509 int offset = (cluster*3/2);
510 unsigned char* p = array_get(&(s->fat), offset);
511 switch (cluster&1) {
512 case 0:
513 p[0] = value&0xff;
514 p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
515 break;
516 case 1:
517 p[0] = (p[0]&0xf) | ((value&0xf)<<4);
518 p[1] = (value>>4);
519 break;
524 static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
526 if(s->fat_type==32) {
527 uint32_t* entry=array_get(&(s->fat),cluster);
528 return le32_to_cpu(*entry);
529 } else if(s->fat_type==16) {
530 uint16_t* entry=array_get(&(s->fat),cluster);
531 return le16_to_cpu(*entry);
532 } else {
533 const uint8_t* x=s->fat.pointer+cluster*3/2;
534 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
538 static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
540 if(fat_entry>s->max_fat_value-8)
541 return -1;
542 return 0;
545 static inline void init_fat(BDRVVVFATState* s)
547 if (s->fat_type == 12) {
548 array_init(&(s->fat),1);
549 array_ensure_allocated(&(s->fat),
550 s->sectors_per_fat * 0x200 * 3 / 2 - 1);
551 } else {
552 array_init(&(s->fat),(s->fat_type==32?4:2));
553 array_ensure_allocated(&(s->fat),
554 s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
556 memset(s->fat.pointer,0,s->fat.size);
558 switch(s->fat_type) {
559 case 12: s->max_fat_value=0xfff; break;
560 case 16: s->max_fat_value=0xffff; break;
561 case 32: s->max_fat_value=0x0fffffff; break;
562 default: s->max_fat_value=0; /* error... */
567 /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
568 /* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
569 static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
570 unsigned int directory_start, const char* filename, int is_dot)
572 int i,j,long_index=s->directory.next;
573 direntry_t* entry=0;
574 direntry_t* entry_long=0;
576 if(is_dot) {
577 entry=array_get_next(&(s->directory));
578 memset(entry->name,0x20,11);
579 memcpy(entry->name,filename,strlen(filename));
580 return entry;
583 entry_long=create_long_filename(s,filename);
585 i = strlen(filename);
586 for(j = i - 1; j>0 && filename[j]!='.';j--);
587 if (j > 0)
588 i = (j > 8 ? 8 : j);
589 else if (i > 8)
590 i = 8;
592 entry=array_get_next(&(s->directory));
593 memset(entry->name,0x20,11);
594 strncpy(entry->name,filename,i);
596 if(j > 0)
597 for (i = 0; i < 3 && filename[j+1+i]; i++)
598 entry->extension[i] = filename[j+1+i];
600 /* upcase & remove unwanted characters */
601 for(i=10;i>=0;i--) {
602 if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
603 if(entry->name[i]<=' ' || entry->name[i]>0x7f
604 || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
605 entry->name[i]='_';
606 else if(entry->name[i]>='a' && entry->name[i]<='z')
607 entry->name[i]+='A'-'a';
610 /* mangle duplicates */
611 while(1) {
612 direntry_t* entry1=array_get(&(s->directory),directory_start);
613 int j;
615 for(;entry1<entry;entry1++)
616 if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
617 break; /* found dupe */
618 if(entry1==entry) /* no dupe found */
619 break;
621 /* use all 8 characters of name */
622 if(entry->name[7]==' ') {
623 int j;
624 for(j=6;j>0 && entry->name[j]==' ';j--)
625 entry->name[j]='~';
628 /* increment number */
629 for(j=7;j>0 && entry->name[j]=='9';j--)
630 entry->name[j]='0';
631 if(j>0) {
632 if(entry->name[j]<'0' || entry->name[j]>'9')
633 entry->name[j]='0';
634 else
635 entry->name[j]++;
639 /* calculate checksum; propagate to long name */
640 if(entry_long) {
641 uint8_t chksum=fat_chksum(entry);
643 /* calculate anew, because realloc could have taken place */
644 entry_long=array_get(&(s->directory),long_index);
645 while(entry_long<entry && is_long_name(entry_long)) {
646 entry_long->reserved[1]=chksum;
647 entry_long++;
651 return entry;
655 * Read a directory. (the index of the corresponding mapping must be passed).
657 static int read_directory(BDRVVVFATState* s, int mapping_index)
659 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
660 direntry_t* direntry;
661 const char* dirname = mapping->path;
662 int first_cluster = mapping->begin;
663 int parent_index = mapping->info.dir.parent_mapping_index;
664 mapping_t* parent_mapping = (mapping_t*)
665 (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : 0);
666 int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
668 DIR* dir=opendir(dirname);
669 struct dirent* entry;
670 int i;
672 assert(mapping->mode & MODE_DIRECTORY);
674 if(!dir) {
675 mapping->end = mapping->begin;
676 return -1;
679 i = mapping->info.dir.first_dir_index =
680 first_cluster == 0 ? 0 : s->directory.next;
682 /* actually read the directory, and allocate the mappings */
683 while((entry=readdir(dir))) {
684 unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
685 char* buffer;
686 direntry_t* direntry;
687 struct stat st;
688 int is_dot=!strcmp(entry->d_name,".");
689 int is_dotdot=!strcmp(entry->d_name,"..");
691 if(first_cluster == 0 && (is_dotdot || is_dot))
692 continue;
694 buffer=(char*)malloc(length);
695 assert(buffer);
696 snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
698 if(stat(buffer,&st)<0) {
699 free(buffer);
700 continue;
703 /* create directory entry for this file */
704 direntry=create_short_and_long_name(s, i, entry->d_name,
705 is_dot || is_dotdot);
706 direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
707 direntry->reserved[0]=direntry->reserved[1]=0;
708 direntry->ctime=fat_datetime(st.st_ctime,1);
709 direntry->cdate=fat_datetime(st.st_ctime,0);
710 direntry->adate=fat_datetime(st.st_atime,0);
711 direntry->begin_hi=0;
712 direntry->mtime=fat_datetime(st.st_mtime,1);
713 direntry->mdate=fat_datetime(st.st_mtime,0);
714 if(is_dotdot)
715 set_begin_of_direntry(direntry, first_cluster_of_parent);
716 else if(is_dot)
717 set_begin_of_direntry(direntry, first_cluster);
718 else
719 direntry->begin=0; /* do that later */
720 if (st.st_size > 0x7fffffff) {
721 fprintf(stderr, "File %s is larger than 2GB\n", buffer);
722 free(buffer);
723 return -2;
725 direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
727 /* create mapping for this file */
728 if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
729 s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
730 s->current_mapping->begin=0;
731 s->current_mapping->end=st.st_size;
733 * we get the direntry of the most recent direntry, which
734 * contains the short name and all the relevant information.
736 s->current_mapping->dir_index=s->directory.next-1;
737 s->current_mapping->first_mapping_index = -1;
738 if (S_ISDIR(st.st_mode)) {
739 s->current_mapping->mode = MODE_DIRECTORY;
740 s->current_mapping->info.dir.parent_mapping_index =
741 mapping_index;
742 } else {
743 s->current_mapping->mode = MODE_UNDEFINED;
744 s->current_mapping->info.file.offset = 0;
746 s->current_mapping->path=buffer;
747 s->current_mapping->read_only =
748 (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
751 closedir(dir);
753 /* fill with zeroes up to the end of the cluster */
754 while(s->directory.next%(0x10*s->sectors_per_cluster)) {
755 direntry_t* direntry=array_get_next(&(s->directory));
756 memset(direntry,0,sizeof(direntry_t));
759 /* TODO: if there are more entries, bootsector has to be adjusted! */
760 #define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
761 if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
762 /* root directory */
763 int cur = s->directory.next;
764 array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
765 memset(array_get(&(s->directory), cur), 0,
766 (ROOT_ENTRIES - cur) * sizeof(direntry_t));
769 /* reget the mapping, since s->mapping was possibly realloc()ed */
770 mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
771 first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
772 * 0x20 / s->cluster_size;
773 mapping->end = first_cluster;
775 direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
776 set_begin_of_direntry(direntry, mapping->begin);
778 return 0;
781 static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
783 return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
786 static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
788 return s->faked_sectors + s->sectors_per_cluster * cluster_num;
791 static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
793 return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
796 #ifdef DBG
797 static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
799 if(mapping->mode==MODE_UNDEFINED)
800 return 0;
801 return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
803 #endif
805 static int init_directories(BDRVVVFATState* s,
806 const char* dirname)
808 bootsector_t* bootsector;
809 mapping_t* mapping;
810 unsigned int i;
811 unsigned int cluster;
813 memset(&(s->first_sectors[0]),0,0x40*0x200);
815 s->cluster_size=s->sectors_per_cluster*0x200;
816 s->cluster_buffer=malloc(s->cluster_size);
817 assert(s->cluster_buffer);
820 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
821 * where sc is sector_count,
822 * spf is sectors_per_fat,
823 * spc is sectors_per_clusters, and
824 * fat_type = 12, 16 or 32.
826 i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
827 s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
829 array_init(&(s->mapping),sizeof(mapping_t));
830 array_init(&(s->directory),sizeof(direntry_t));
832 /* add volume label */
834 direntry_t* entry=array_get_next(&(s->directory));
835 entry->attributes=0x28; /* archive | volume label */
836 snprintf(entry->name,11,"QEMU VVFAT");
839 /* Now build FAT, and write back information into directory */
840 init_fat(s);
842 s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
843 s->cluster_count=sector2cluster(s, s->sector_count);
845 mapping = array_get_next(&(s->mapping));
846 mapping->begin = 0;
847 mapping->dir_index = 0;
848 mapping->info.dir.parent_mapping_index = -1;
849 mapping->first_mapping_index = -1;
850 mapping->path = strdup(dirname);
851 i = strlen(mapping->path);
852 if (i > 0 && mapping->path[i - 1] == '/')
853 mapping->path[i - 1] = '\0';
854 mapping->mode = MODE_DIRECTORY;
855 mapping->read_only = 0;
856 s->path = mapping->path;
858 for (i = 0, cluster = 0; i < s->mapping.next; i++) {
859 int j;
860 /* MS-DOS expects the FAT to be 0 for the root directory
861 * (except for the media byte). */
862 /* LATER TODO: still true for FAT32? */
863 int fix_fat = (i != 0);
864 mapping = array_get(&(s->mapping), i);
866 if (mapping->mode & MODE_DIRECTORY) {
867 mapping->begin = cluster;
868 if(read_directory(s, i)) {
869 fprintf(stderr, "Could not read directory %s\n",
870 mapping->path);
871 return -1;
873 mapping = array_get(&(s->mapping), i);
874 } else {
875 assert(mapping->mode == MODE_UNDEFINED);
876 mapping->mode=MODE_NORMAL;
877 mapping->begin = cluster;
878 if (mapping->end > 0) {
879 direntry_t* direntry = array_get(&(s->directory),
880 mapping->dir_index);
882 mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
883 set_begin_of_direntry(direntry, mapping->begin);
884 } else {
885 mapping->end = cluster + 1;
886 fix_fat = 0;
890 assert(mapping->begin < mapping->end);
892 /* fix fat for entry */
893 if (fix_fat) {
894 for(j = mapping->begin; j < mapping->end - 1; j++)
895 fat_set(s, j, j+1);
896 fat_set(s, mapping->end - 1, s->max_fat_value);
899 /* next free cluster */
900 cluster = mapping->end;
902 if(cluster > s->cluster_count) {
903 fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type);
904 return -1;
908 mapping = array_get(&(s->mapping), 0);
909 s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
910 s->last_cluster_of_root_directory = mapping->end;
912 /* the FAT signature */
913 fat_set(s,0,s->max_fat_value);
914 fat_set(s,1,s->max_fat_value);
916 s->current_mapping = NULL;
918 bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
919 bootsector->jump[0]=0xeb;
920 bootsector->jump[1]=0x3e;
921 bootsector->jump[2]=0x90;
922 memcpy(bootsector->name,"QEMU ",8);
923 bootsector->sector_size=cpu_to_le16(0x200);
924 bootsector->sectors_per_cluster=s->sectors_per_cluster;
925 bootsector->reserved_sectors=cpu_to_le16(1);
926 bootsector->number_of_fats=0x2; /* number of FATs */
927 bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
928 bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
929 bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
930 s->fat.pointer[0] = bootsector->media_type;
931 bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
932 bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
933 bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
934 bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
935 bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
937 /* LATER TODO: if FAT32, this is wrong */
938 bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
939 bootsector->u.fat16.current_head=0;
940 bootsector->u.fat16.signature=0x29;
941 bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
943 memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
944 memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12 ":s->fat_type==16?"FAT16 ":"FAT32 "),8);
945 bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
947 return 0;
950 #ifdef DEBUG
951 static BDRVVVFATState *vvv = NULL;
952 #endif
954 static int enable_write_target(BDRVVVFATState *s);
955 static int is_consistent(BDRVVVFATState *s);
957 static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
959 BDRVVVFATState *s = bs->opaque;
960 int floppy = 0;
961 int i;
963 #ifdef DEBUG
964 vvv = s;
965 #endif
967 DLOG(if (stderr == NULL) {
968 stderr = fopen("vvfat.log", "a");
969 setbuf(stderr, NULL);
972 s->bs = bs;
974 s->fat_type=16;
975 /* LATER TODO: if FAT32, adjust */
976 s->sector_count=0xec04f;
977 s->sectors_per_cluster=0x10;
978 /* LATER TODO: this could be wrong for FAT32 */
979 bs->cyls=1023; bs->heads=15; bs->secs=63;
981 s->current_cluster=0xffffffff;
983 s->first_sectors_number=0x40;
984 /* read only is the default for safety */
985 bs->read_only = 1;
986 s->qcow = s->write_target = NULL;
987 s->qcow_filename = NULL;
988 s->fat2 = NULL;
989 s->downcase_short_names = 1;
991 if (!strstart(dirname, "fat:", NULL))
992 return -1;
994 if (strstr(dirname, ":rw:")) {
995 if (enable_write_target(s))
996 return -1;
997 bs->read_only = 0;
1000 if (strstr(dirname, ":floppy:")) {
1001 floppy = 1;
1002 s->fat_type = 12;
1003 s->first_sectors_number = 1;
1004 s->sectors_per_cluster=2;
1005 bs->cyls = 80; bs->heads = 2; bs->secs = 36;
1008 if (strstr(dirname, ":32:")) {
1009 fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1010 s->fat_type = 32;
1011 } else if (strstr(dirname, ":16:")) {
1012 s->fat_type = 16;
1013 } else if (strstr(dirname, ":12:")) {
1014 s->fat_type = 12;
1015 s->sector_count=2880;
1018 i = strrchr(dirname, ':') - dirname;
1019 assert(i >= 3);
1020 if (dirname[i-2] == ':' && isalpha(dirname[i-1]))
1021 /* workaround for DOS drive names */
1022 dirname += i-1;
1023 else
1024 dirname += i+1;
1026 bs->total_sectors=bs->cyls*bs->heads*bs->secs;
1027 if (s->sector_count > bs->total_sectors)
1028 s->sector_count = bs->total_sectors;
1029 if(init_directories(s, dirname))
1030 return -1;
1032 if(s->first_sectors_number==0x40)
1033 init_mbr(s);
1035 /* for some reason or other, MS-DOS does not like to know about CHS... */
1036 if (floppy)
1037 bs->heads = bs->cyls = bs->secs = 0;
1039 // assert(is_consistent(s));
1040 return 0;
1043 static inline void vvfat_close_current_file(BDRVVVFATState *s)
1045 if(s->current_mapping) {
1046 s->current_mapping = NULL;
1047 if (s->current_fd) {
1048 close(s->current_fd);
1049 s->current_fd = 0;
1052 s->current_cluster = -1;
1055 /* mappings between index1 and index2-1 are supposed to be ordered
1056 * return value is the index of the last mapping for which end>cluster_num
1058 static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1060 int index3=index1+1;
1061 while(1) {
1062 mapping_t* mapping;
1063 index3=(index1+index2)/2;
1064 mapping=array_get(&(s->mapping),index3);
1065 assert(mapping->begin < mapping->end);
1066 if(mapping->begin>=cluster_num) {
1067 assert(index2!=index3 || index2==0);
1068 if(index2==index3)
1069 return index1;
1070 index2=index3;
1071 } else {
1072 if(index1==index3)
1073 return mapping->end<=cluster_num ? index2 : index1;
1074 index1=index3;
1076 assert(index1<=index2);
1077 DLOG(mapping=array_get(&(s->mapping),index1);
1078 assert(mapping->begin<=cluster_num);
1079 assert(index2 >= s->mapping.next ||
1080 ((mapping = array_get(&(s->mapping),index2)) &&
1081 mapping->end>cluster_num)));
1085 static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
1087 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
1088 mapping_t* mapping;
1089 if(index>=s->mapping.next)
1090 return 0;
1091 mapping=array_get(&(s->mapping),index);
1092 if(mapping->begin>cluster_num)
1093 return 0;
1094 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
1095 return mapping;
1099 * This function simply compares path == mapping->path. Since the mappings
1100 * are sorted by cluster, this is expensive: O(n).
1102 static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
1103 const char* path)
1105 int i;
1107 for (i = 0; i < s->mapping.next; i++) {
1108 mapping_t* mapping = array_get(&(s->mapping), i);
1109 if (mapping->first_mapping_index < 0 &&
1110 !strcmp(path, mapping->path))
1111 return mapping;
1114 return NULL;
1117 static int open_file(BDRVVVFATState* s,mapping_t* mapping)
1119 if(!mapping)
1120 return -1;
1121 if(!s->current_mapping ||
1122 strcmp(s->current_mapping->path,mapping->path)) {
1123 /* open file */
1124 int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
1125 if(fd<0)
1126 return -1;
1127 vvfat_close_current_file(s);
1128 s->current_fd = fd;
1129 s->current_mapping = mapping;
1131 return 0;
1134 static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1136 if(s->current_cluster != cluster_num) {
1137 int result=0;
1138 off_t offset;
1139 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
1140 if(!s->current_mapping
1141 || s->current_mapping->begin>cluster_num
1142 || s->current_mapping->end<=cluster_num) {
1143 /* binary search of mappings for file */
1144 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
1146 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1148 if (mapping && mapping->mode & MODE_DIRECTORY) {
1149 vvfat_close_current_file(s);
1150 s->current_mapping = mapping;
1151 read_cluster_directory:
1152 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
1153 s->cluster = s->directory.pointer+offset
1154 + 0x20*s->current_mapping->info.dir.first_dir_index;
1155 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1156 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1157 s->current_cluster = cluster_num;
1158 return 0;
1161 if(open_file(s,mapping))
1162 return -2;
1163 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1164 goto read_cluster_directory;
1166 assert(s->current_fd);
1168 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
1169 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1170 return -3;
1171 s->cluster=s->cluster_buffer;
1172 result=read(s->current_fd,s->cluster,s->cluster_size);
1173 if(result<0) {
1174 s->current_cluster = -1;
1175 return -1;
1177 s->current_cluster = cluster_num;
1179 return 0;
1182 #ifdef DEBUG
1183 static void hexdump(const void* address, uint32_t len)
1185 const unsigned char* p = address;
1186 int i, j;
1188 for (i = 0; i < len; i += 16) {
1189 for (j = 0; j < 16 && i + j < len; j++)
1190 fprintf(stderr, "%02x ", p[i + j]);
1191 for (; j < 16; j++)
1192 fprintf(stderr, " ");
1193 fprintf(stderr, " ");
1194 for (j = 0; j < 16 && i + j < len; j++)
1195 fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
1196 fprintf(stderr, "\n");
1200 static void print_direntry(const direntry_t* direntry)
1202 int j = 0;
1203 char buffer[1024];
1205 fprintf(stderr, "direntry 0x%x: ", (int)direntry);
1206 if(!direntry)
1207 return;
1208 if(is_long_name(direntry)) {
1209 unsigned char* c=(unsigned char*)direntry;
1210 int i;
1211 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
1212 #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = '°'; j++;}
1213 ADD_CHAR(c[i]);
1214 for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
1215 ADD_CHAR(c[i]);
1216 for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
1217 ADD_CHAR(c[i]);
1218 buffer[j] = 0;
1219 fprintf(stderr, "%s\n", buffer);
1220 } else {
1221 int i;
1222 for(i=0;i<11;i++)
1223 ADD_CHAR(direntry->name[i]);
1224 buffer[j] = 0;
1225 fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1226 buffer,
1227 direntry->attributes,
1228 begin_of_direntry(direntry),le32_to_cpu(direntry->size));
1232 static void print_mapping(const mapping_t* mapping)
1234 fprintf(stderr, "mapping (0x%x): begin, end = %d, %d, dir_index = %d, first_mapping_index = %d, name = %s, mode = 0x%x, " , (int)mapping, mapping->begin, mapping->end, mapping->dir_index, mapping->first_mapping_index, mapping->path, mapping->mode);
1235 if (mapping->mode & MODE_DIRECTORY)
1236 fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1237 else
1238 fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
1240 #endif
1242 static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
1243 uint8_t *buf, int nb_sectors)
1245 BDRVVVFATState *s = bs->opaque;
1246 int i;
1248 for(i=0;i<nb_sectors;i++,sector_num++) {
1249 if (sector_num >= s->sector_count)
1250 return -1;
1251 if (s->qcow) {
1252 int n;
1253 if (s->qcow->drv->bdrv_is_allocated(s->qcow,
1254 sector_num, nb_sectors-i, &n)) {
1255 DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
1256 if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
1257 return -1;
1258 i += n - 1;
1259 sector_num += n - 1;
1260 continue;
1262 DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
1264 if(sector_num<s->faked_sectors) {
1265 if(sector_num<s->first_sectors_number)
1266 memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
1267 else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
1268 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
1269 else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
1270 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
1271 } else {
1272 uint32_t sector=sector_num-s->faked_sectors,
1273 sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1274 cluster_num=sector/s->sectors_per_cluster;
1275 if(read_cluster(s, cluster_num) != 0) {
1276 /* LATER TODO: strict: return -1; */
1277 memset(buf+i*0x200,0,0x200);
1278 continue;
1280 memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
1283 return 0;
1286 /* LATER TODO: statify all functions */
1289 * Idea of the write support (use snapshot):
1291 * 1. check if all data is consistent, recording renames, modifications,
1292 * new files and directories (in s->commits).
1294 * 2. if the data is not consistent, stop committing
1296 * 3. handle renames, and create new files and directories (do not yet
1297 * write their contents)
1299 * 4. walk the directories, fixing the mapping and direntries, and marking
1300 * the handled mappings as not deleted
1302 * 5. commit the contents of the files
1304 * 6. handle deleted files and directories
1308 typedef struct commit_t {
1309 char* path;
1310 union {
1311 struct { uint32_t cluster; } rename;
1312 struct { int dir_index; uint32_t modified_offset; } writeout;
1313 struct { uint32_t first_cluster; } new_file;
1314 struct { uint32_t cluster; } mkdir;
1315 } param;
1316 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1317 enum {
1318 ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1319 } action;
1320 } commit_t;
1322 static void clear_commits(BDRVVVFATState* s)
1324 int i;
1325 DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1326 for (i = 0; i < s->commits.next; i++) {
1327 commit_t* commit = array_get(&(s->commits), i);
1328 assert(commit->path || commit->action == ACTION_WRITEOUT);
1329 if (commit->action != ACTION_WRITEOUT) {
1330 assert(commit->path);
1331 free(commit->path);
1332 } else
1333 assert(commit->path == NULL);
1335 s->commits.next = 0;
1338 static void schedule_rename(BDRVVVFATState* s,
1339 uint32_t cluster, char* new_path)
1341 commit_t* commit = array_get_next(&(s->commits));
1342 commit->path = new_path;
1343 commit->param.rename.cluster = cluster;
1344 commit->action = ACTION_RENAME;
1347 static void schedule_writeout(BDRVVVFATState* s,
1348 int dir_index, uint32_t modified_offset)
1350 commit_t* commit = array_get_next(&(s->commits));
1351 commit->path = NULL;
1352 commit->param.writeout.dir_index = dir_index;
1353 commit->param.writeout.modified_offset = modified_offset;
1354 commit->action = ACTION_WRITEOUT;
1357 static void schedule_new_file(BDRVVVFATState* s,
1358 char* path, uint32_t first_cluster)
1360 commit_t* commit = array_get_next(&(s->commits));
1361 commit->path = path;
1362 commit->param.new_file.first_cluster = first_cluster;
1363 commit->action = ACTION_NEW_FILE;
1366 static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1368 commit_t* commit = array_get_next(&(s->commits));
1369 commit->path = path;
1370 commit->param.mkdir.cluster = cluster;
1371 commit->action = ACTION_MKDIR;
1374 typedef struct {
1375 unsigned char name[1024];
1376 int checksum, len;
1377 int sequence_number;
1378 } long_file_name;
1380 static void lfn_init(long_file_name* lfn)
1382 lfn->sequence_number = lfn->len = 0;
1383 lfn->checksum = 0x100;
1386 /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1387 static int parse_long_name(long_file_name* lfn,
1388 const direntry_t* direntry)
1390 int i, j, offset;
1391 const unsigned char* pointer = (const unsigned char*)direntry;
1393 if (!is_long_name(direntry))
1394 return 1;
1396 if (pointer[0] & 0x40) {
1397 lfn->sequence_number = pointer[0] & 0x3f;
1398 lfn->checksum = pointer[13];
1399 lfn->name[0] = 0;
1400 } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
1401 return -1;
1402 else if (pointer[13] != lfn->checksum)
1403 return -2;
1404 else if (pointer[12] || pointer[26] || pointer[27])
1405 return -3;
1407 offset = 13 * (lfn->sequence_number - 1);
1408 for (i = 0, j = 1; i < 13; i++, j+=2) {
1409 if (j == 11)
1410 j = 14;
1411 else if (j == 26)
1412 j = 28;
1414 if (pointer[j+1] == 0)
1415 lfn->name[offset + i] = pointer[j];
1416 else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1417 return -4;
1418 else
1419 lfn->name[offset + i] = 0;
1422 if (pointer[0] & 0x40)
1423 lfn->len = offset + strlen(lfn->name + offset);
1425 return 0;
1428 /* returns 0 if successful, >0 if no short_name, and <0 on error */
1429 static int parse_short_name(BDRVVVFATState* s,
1430 long_file_name* lfn, direntry_t* direntry)
1432 int i, j;
1434 if (!is_short_name(direntry))
1435 return 1;
1437 for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1438 for (i = 0; i <= j; i++) {
1439 if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
1440 return -1;
1441 else if (s->downcase_short_names)
1442 lfn->name[i] = tolower(direntry->name[i]);
1443 else
1444 lfn->name[i] = direntry->name[i];
1447 for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
1448 if (j >= 0) {
1449 lfn->name[i++] = '.';
1450 lfn->name[i + j + 1] = '\0';
1451 for (;j >= 0; j--) {
1452 if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
1453 return -2;
1454 else if (s->downcase_short_names)
1455 lfn->name[i + j] = tolower(direntry->extension[j]);
1456 else
1457 lfn->name[i + j] = direntry->extension[j];
1459 } else
1460 lfn->name[i + j + 1] = '\0';
1462 lfn->len = strlen(lfn->name);
1464 return 0;
1467 static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1468 unsigned int cluster)
1470 if (cluster < s->last_cluster_of_root_directory) {
1471 if (cluster + 1 == s->last_cluster_of_root_directory)
1472 return s->max_fat_value;
1473 else
1474 return cluster + 1;
1477 if (s->fat_type==32) {
1478 uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1479 return le32_to_cpu(*entry);
1480 } else if (s->fat_type==16) {
1481 uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1482 return le16_to_cpu(*entry);
1483 } else {
1484 const uint8_t* x=s->fat2+cluster*3/2;
1485 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1489 static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1491 int was_modified = 0;
1492 int i, dummy;
1494 if (s->qcow == NULL)
1495 return 0;
1497 for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
1498 was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
1499 cluster2sector(s, cluster_num) + i, 1, &dummy);
1501 return was_modified;
1504 static const char* get_basename(const char* path)
1506 char* basename = strrchr(path, '/');
1507 if (basename == NULL)
1508 return path;
1509 else
1510 return basename + 1; /* strip '/' */
1514 * The array s->used_clusters holds the states of the clusters. If it is
1515 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1516 * was modified, bit 3 is set.
1517 * If any cluster is allocated, but not part of a file or directory, this
1518 * driver refuses to commit.
1520 typedef enum {
1521 USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
1522 } used_t;
1525 * get_cluster_count_for_direntry() not only determines how many clusters
1526 * are occupied by direntry, but also if it was renamed or modified.
1528 * A file is thought to be renamed *only* if there already was a file with
1529 * exactly the same first cluster, but a different name.
1531 * Further, the files/directories handled by this function are
1532 * assumed to be *not* deleted (and *only* those).
1534 static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
1535 direntry_t* direntry, const char* path)
1538 * This is a little bit tricky:
1539 * IF the guest OS just inserts a cluster into the file chain,
1540 * and leaves the rest alone, (i.e. the original file had clusters
1541 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1543 * - do_commit will write the cluster into the file at the given
1544 * offset, but
1546 * - the cluster which is overwritten should be moved to a later
1547 * position in the file.
1549 * I am not aware that any OS does something as braindead, but this
1550 * situation could happen anyway when not committing for a long time.
1551 * Just to be sure that this does not bite us, detect it, and copy the
1552 * contents of the clusters to-be-overwritten into the qcow.
1554 int copy_it = 0;
1555 int was_modified = 0;
1556 int32_t ret = 0;
1558 uint32_t cluster_num = begin_of_direntry(direntry);
1559 uint32_t offset = 0;
1560 int first_mapping_index = -1;
1561 mapping_t* mapping = NULL;
1562 const char* basename2 = NULL;
1564 vvfat_close_current_file(s);
1566 /* the root directory */
1567 if (cluster_num == 0)
1568 return 0;
1570 /* write support */
1571 if (s->qcow) {
1572 basename2 = get_basename(path);
1574 mapping = find_mapping_for_cluster(s, cluster_num);
1576 if (mapping) {
1577 const char* basename;
1579 assert(mapping->mode & MODE_DELETED);
1580 mapping->mode &= ~MODE_DELETED;
1582 basename = get_basename(mapping->path);
1584 assert(mapping->mode & MODE_NORMAL);
1586 /* rename */
1587 if (strcmp(basename, basename2))
1588 schedule_rename(s, cluster_num, strdup(path));
1589 } else if (is_file(direntry))
1590 /* new file */
1591 schedule_new_file(s, strdup(path), cluster_num);
1592 else {
1593 assert(0);
1594 return 0;
1598 while(1) {
1599 if (s->qcow) {
1600 if (!copy_it && cluster_was_modified(s, cluster_num)) {
1601 if (mapping == NULL ||
1602 mapping->begin > cluster_num ||
1603 mapping->end <= cluster_num)
1604 mapping = find_mapping_for_cluster(s, cluster_num);
1607 if (mapping &&
1608 (mapping->mode & MODE_DIRECTORY) == 0) {
1610 /* was modified in qcow */
1611 if (offset != mapping->info.file.offset + s->cluster_size
1612 * (cluster_num - mapping->begin)) {
1613 /* offset of this cluster in file chain has changed */
1614 assert(0);
1615 copy_it = 1;
1616 } else if (offset == 0) {
1617 const char* basename = get_basename(mapping->path);
1619 if (strcmp(basename, basename2))
1620 copy_it = 1;
1621 first_mapping_index = array_index(&(s->mapping), mapping);
1624 if (mapping->first_mapping_index != first_mapping_index
1625 && mapping->info.file.offset > 0) {
1626 assert(0);
1627 copy_it = 1;
1630 /* need to write out? */
1631 if (!was_modified && is_file(direntry)) {
1632 was_modified = 1;
1633 schedule_writeout(s, mapping->dir_index, offset);
1638 if (copy_it) {
1639 int i, dummy;
1641 * This is horribly inefficient, but that is okay, since
1642 * it is rarely executed, if at all.
1644 int64_t offset = cluster2sector(s, cluster_num);
1646 vvfat_close_current_file(s);
1647 for (i = 0; i < s->sectors_per_cluster; i++)
1648 if (!s->qcow->drv->bdrv_is_allocated(s->qcow,
1649 offset + i, 1, &dummy)) {
1650 if (vvfat_read(s->bs,
1651 offset, s->cluster_buffer, 1))
1652 return -1;
1653 if (s->qcow->drv->bdrv_write(s->qcow,
1654 offset, s->cluster_buffer, 1))
1655 return -2;
1660 ret++;
1661 if (s->used_clusters[cluster_num] & USED_ANY)
1662 return 0;
1663 s->used_clusters[cluster_num] = USED_FILE;
1665 cluster_num = modified_fat_get(s, cluster_num);
1667 if (fat_eof(s, cluster_num))
1668 return ret;
1669 else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
1670 return -1;
1672 offset += s->cluster_size;
1677 * This function looks at the modified data (qcow).
1678 * It returns 0 upon inconsistency or error, and the number of clusters
1679 * used by the directory, its subdirectories and their files.
1681 static int check_directory_consistency(BDRVVVFATState *s,
1682 int cluster_num, const char* path)
1684 int ret = 0;
1685 unsigned char* cluster = malloc(s->cluster_size);
1686 direntry_t* direntries = (direntry_t*)cluster;
1687 mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
1689 long_file_name lfn;
1690 int path_len = strlen(path);
1691 char path2[PATH_MAX];
1693 assert(path_len < PATH_MAX); /* len was tested before! */
1694 strcpy(path2, path);
1695 path2[path_len] = '/';
1696 path2[path_len + 1] = '\0';
1698 if (mapping) {
1699 const char* basename = get_basename(mapping->path);
1700 const char* basename2 = get_basename(path);
1702 assert(mapping->mode & MODE_DIRECTORY);
1704 assert(mapping->mode & MODE_DELETED);
1705 mapping->mode &= ~MODE_DELETED;
1707 if (strcmp(basename, basename2))
1708 schedule_rename(s, cluster_num, strdup(path));
1709 } else
1710 /* new directory */
1711 schedule_mkdir(s, cluster_num, strdup(path));
1713 lfn_init(&lfn);
1714 do {
1715 int i;
1716 int subret = 0;
1718 ret++;
1720 if (s->used_clusters[cluster_num] & USED_ANY) {
1721 fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
1722 return 0;
1724 s->used_clusters[cluster_num] = USED_DIRECTORY;
1726 DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
1727 subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
1728 s->sectors_per_cluster);
1729 if (subret) {
1730 fprintf(stderr, "Error fetching direntries\n");
1731 fail:
1732 free(cluster);
1733 return 0;
1736 for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
1737 int cluster_count;
1739 DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
1740 if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
1741 is_free(direntries + i))
1742 continue;
1744 subret = parse_long_name(&lfn, direntries + i);
1745 if (subret < 0) {
1746 fprintf(stderr, "Error in long name\n");
1747 goto fail;
1749 if (subret == 0 || is_free(direntries + i))
1750 continue;
1752 if (fat_chksum(direntries+i) != lfn.checksum) {
1753 subret = parse_short_name(s, &lfn, direntries + i);
1754 if (subret < 0) {
1755 fprintf(stderr, "Error in short name (%d)\n", subret);
1756 goto fail;
1758 if (subret > 0 || !strcmp(lfn.name, ".")
1759 || !strcmp(lfn.name, ".."))
1760 continue;
1762 lfn.checksum = 0x100; /* cannot use long name twice */
1764 if (path_len + 1 + lfn.len >= PATH_MAX) {
1765 fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
1766 goto fail;
1768 strcpy(path2 + path_len + 1, lfn.name);
1770 if (is_directory(direntries + i)) {
1771 if (begin_of_direntry(direntries + i) == 0) {
1772 DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
1773 goto fail;
1775 cluster_count = check_directory_consistency(s,
1776 begin_of_direntry(direntries + i), path2);
1777 if (cluster_count == 0) {
1778 DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
1779 goto fail;
1781 } else if (is_file(direntries + i)) {
1782 /* check file size with FAT */
1783 cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
1784 if (cluster_count !=
1785 (le32_to_cpu(direntries[i].size) + s->cluster_size
1786 - 1) / s->cluster_size) {
1787 DLOG(fprintf(stderr, "Cluster count mismatch\n"));
1788 goto fail;
1790 } else
1791 assert(0); /* cluster_count = 0; */
1793 ret += cluster_count;
1796 cluster_num = modified_fat_get(s, cluster_num);
1797 } while(!fat_eof(s, cluster_num));
1799 free(cluster);
1800 return ret;
1803 /* returns 1 on success */
1804 static int is_consistent(BDRVVVFATState* s)
1806 int i, check;
1807 int used_clusters_count = 0;
1809 DLOG(checkpoint());
1811 * - get modified FAT
1812 * - compare the two FATs (TODO)
1813 * - get buffer for marking used clusters
1814 * - recurse direntries from root (using bs->bdrv_read to make
1815 * sure to get the new data)
1816 * - check that the FAT agrees with the size
1817 * - count the number of clusters occupied by this directory and
1818 * its files
1819 * - check that the cumulative used cluster count agrees with the
1820 * FAT
1821 * - if all is fine, return number of used clusters
1823 if (s->fat2 == NULL) {
1824 int size = 0x200 * s->sectors_per_fat;
1825 s->fat2 = malloc(size);
1826 memcpy(s->fat2, s->fat.pointer, size);
1828 check = vvfat_read(s->bs,
1829 s->first_sectors_number, s->fat2, s->sectors_per_fat);
1830 if (check) {
1831 fprintf(stderr, "Could not copy fat\n");
1832 return 0;
1834 assert (s->used_clusters);
1835 for (i = 0; i < sector2cluster(s, s->sector_count); i++)
1836 s->used_clusters[i] &= ~USED_ANY;
1838 clear_commits(s);
1840 /* mark every mapped file/directory as deleted.
1841 * (check_directory_consistency() will unmark those still present). */
1842 if (s->qcow)
1843 for (i = 0; i < s->mapping.next; i++) {
1844 mapping_t* mapping = array_get(&(s->mapping), i);
1845 if (mapping->first_mapping_index < 0)
1846 mapping->mode |= MODE_DELETED;
1849 used_clusters_count = check_directory_consistency(s, 0, s->path);
1850 if (used_clusters_count <= 0) {
1851 DLOG(fprintf(stderr, "problem in directory\n"));
1852 return 0;
1855 check = s->last_cluster_of_root_directory;
1856 for (i = check; i < sector2cluster(s, s->sector_count); i++) {
1857 if (modified_fat_get(s, i)) {
1858 if(!s->used_clusters[i]) {
1859 DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
1860 return 0;
1862 check++;
1865 if (s->used_clusters[i] == USED_ALLOCATED) {
1866 /* allocated, but not used... */
1867 DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
1868 return 0;
1872 if (check != used_clusters_count)
1873 return 0;
1875 return used_clusters_count;
1878 static inline void adjust_mapping_indices(BDRVVVFATState* s,
1879 int offset, int adjust)
1881 int i;
1883 for (i = 0; i < s->mapping.next; i++) {
1884 mapping_t* mapping = array_get(&(s->mapping), i);
1886 #define ADJUST_MAPPING_INDEX(name) \
1887 if (mapping->name >= offset) \
1888 mapping->name += adjust
1890 ADJUST_MAPPING_INDEX(first_mapping_index);
1891 if (mapping->mode & MODE_DIRECTORY)
1892 ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
1896 /* insert or update mapping */
1897 static mapping_t* insert_mapping(BDRVVVFATState* s,
1898 uint32_t begin, uint32_t end)
1901 * - find mapping where mapping->begin >= begin,
1902 * - if mapping->begin > begin: insert
1903 * - adjust all references to mappings!
1904 * - else: adjust
1905 * - replace name
1907 int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
1908 mapping_t* mapping = NULL;
1909 mapping_t* first_mapping = array_get(&(s->mapping), 0);
1911 if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
1912 && mapping->begin < begin) {
1913 mapping->end = begin;
1914 index++;
1915 mapping = array_get(&(s->mapping), index);
1917 if (index >= s->mapping.next || mapping->begin > begin) {
1918 mapping = array_insert(&(s->mapping), index, 1);
1919 mapping->path = NULL;
1920 adjust_mapping_indices(s, index, +1);
1923 mapping->begin = begin;
1924 mapping->end = end;
1926 DLOG(mapping_t* next_mapping;
1927 assert(index + 1 >= s->mapping.next ||
1928 ((next_mapping = array_get(&(s->mapping), index + 1)) &&
1929 next_mapping->begin >= end)));
1931 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1932 s->current_mapping = array_get(&(s->mapping),
1933 s->current_mapping - first_mapping);
1935 return mapping;
1938 static int remove_mapping(BDRVVVFATState* s, int mapping_index)
1940 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
1941 mapping_t* first_mapping = array_get(&(s->mapping), 0);
1943 /* free mapping */
1944 if (mapping->first_mapping_index < 0)
1945 free(mapping->path);
1947 /* remove from s->mapping */
1948 array_remove(&(s->mapping), mapping_index);
1950 /* adjust all references to mappings */
1951 adjust_mapping_indices(s, mapping_index, -1);
1953 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1954 s->current_mapping = array_get(&(s->mapping),
1955 s->current_mapping - first_mapping);
1957 return 0;
1960 static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
1962 int i;
1963 for (i = 0; i < s->mapping.next; i++) {
1964 mapping_t* mapping = array_get(&(s->mapping), i);
1965 if (mapping->dir_index >= offset)
1966 mapping->dir_index += adjust;
1967 if ((mapping->mode & MODE_DIRECTORY) &&
1968 mapping->info.dir.first_dir_index >= offset)
1969 mapping->info.dir.first_dir_index += adjust;
1973 static direntry_t* insert_direntries(BDRVVVFATState* s,
1974 int dir_index, int count)
1977 * make room in s->directory,
1978 * adjust_dirindices
1980 direntry_t* result = array_insert(&(s->directory), dir_index, count);
1981 if (result == NULL)
1982 return NULL;
1983 adjust_dirindices(s, dir_index, count);
1984 return result;
1987 static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
1989 int ret = array_remove_slice(&(s->directory), dir_index, count);
1990 if (ret)
1991 return ret;
1992 adjust_dirindices(s, dir_index, -count);
1993 return 0;
1997 * Adapt the mappings of the cluster chain starting at first cluster
1998 * (i.e. if a file starts at first_cluster, the chain is followed according
1999 * to the modified fat, and the corresponding entries in s->mapping are
2000 * adjusted)
2002 static int commit_mappings(BDRVVVFATState* s,
2003 uint32_t first_cluster, int dir_index)
2005 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2006 direntry_t* direntry = array_get(&(s->directory), dir_index);
2007 uint32_t cluster = first_cluster;
2009 vvfat_close_current_file(s);
2011 assert(mapping);
2012 assert(mapping->begin == first_cluster);
2013 mapping->first_mapping_index = -1;
2014 mapping->dir_index = dir_index;
2015 mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2016 MODE_DIRECTORY : MODE_NORMAL;
2018 while (!fat_eof(s, cluster)) {
2019 uint32_t c, c1;
2021 for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2022 c = c1, c1 = modified_fat_get(s, c1));
2024 c++;
2025 if (c > mapping->end) {
2026 int index = array_index(&(s->mapping), mapping);
2027 int i, max_i = s->mapping.next - index;
2028 for (i = 1; i < max_i && mapping[i].begin < c; i++);
2029 while (--i > 0)
2030 remove_mapping(s, index + 1);
2032 assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2033 || mapping[1].begin >= c);
2034 mapping->end = c;
2036 if (!fat_eof(s, c1)) {
2037 int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2038 mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2039 array_get(&(s->mapping), i);
2041 if (next_mapping == NULL || next_mapping->begin > c1) {
2042 int i1 = array_index(&(s->mapping), mapping);
2044 next_mapping = insert_mapping(s, c1, c1+1);
2046 if (c1 < c)
2047 i1++;
2048 mapping = array_get(&(s->mapping), i1);
2051 next_mapping->dir_index = mapping->dir_index;
2052 next_mapping->first_mapping_index =
2053 mapping->first_mapping_index < 0 ?
2054 array_index(&(s->mapping), mapping) :
2055 mapping->first_mapping_index;
2056 next_mapping->path = mapping->path;
2057 next_mapping->mode = mapping->mode;
2058 next_mapping->read_only = mapping->read_only;
2059 if (mapping->mode & MODE_DIRECTORY) {
2060 next_mapping->info.dir.parent_mapping_index =
2061 mapping->info.dir.parent_mapping_index;
2062 next_mapping->info.dir.first_dir_index =
2063 mapping->info.dir.first_dir_index +
2064 0x10 * s->sectors_per_cluster *
2065 (mapping->end - mapping->begin);
2066 } else
2067 next_mapping->info.file.offset = mapping->info.file.offset +
2068 mapping->end - mapping->begin;
2070 mapping = next_mapping;
2073 cluster = c1;
2076 return 0;
2079 static int commit_direntries(BDRVVVFATState* s,
2080 int dir_index, int parent_mapping_index)
2082 direntry_t* direntry = array_get(&(s->directory), dir_index);
2083 uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
2084 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2086 int factor = 0x10 * s->sectors_per_cluster;
2087 int old_cluster_count, new_cluster_count;
2088 int current_dir_index = mapping->info.dir.first_dir_index;
2089 int first_dir_index = current_dir_index;
2090 int ret, i;
2091 uint32_t c;
2093 DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
2095 assert(direntry);
2096 assert(mapping);
2097 assert(mapping->begin == first_cluster);
2098 assert(mapping->info.dir.first_dir_index < s->directory.next);
2099 assert(mapping->mode & MODE_DIRECTORY);
2100 assert(dir_index == 0 || is_directory(direntry));
2102 mapping->info.dir.parent_mapping_index = parent_mapping_index;
2104 if (first_cluster == 0) {
2105 old_cluster_count = new_cluster_count =
2106 s->last_cluster_of_root_directory;
2107 } else {
2108 for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2109 c = fat_get(s, c))
2110 old_cluster_count++;
2112 for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2113 c = modified_fat_get(s, c))
2114 new_cluster_count++;
2117 if (new_cluster_count > old_cluster_count) {
2118 if (insert_direntries(s,
2119 current_dir_index + factor * old_cluster_count,
2120 factor * (new_cluster_count - old_cluster_count)) == NULL)
2121 return -1;
2122 } else if (new_cluster_count < old_cluster_count)
2123 remove_direntries(s,
2124 current_dir_index + factor * new_cluster_count,
2125 factor * (old_cluster_count - new_cluster_count));
2127 for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
2128 void* direntry = array_get(&(s->directory), current_dir_index);
2129 int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2130 s->sectors_per_cluster);
2131 if (ret)
2132 return ret;
2133 assert(!strncmp(s->directory.pointer, "QEMU", 4));
2134 current_dir_index += factor;
2137 ret = commit_mappings(s, first_cluster, dir_index);
2138 if (ret)
2139 return ret;
2141 /* recurse */
2142 for (i = 0; i < factor * new_cluster_count; i++) {
2143 direntry = array_get(&(s->directory), first_dir_index + i);
2144 if (is_directory(direntry) && !is_dot(direntry)) {
2145 mapping = find_mapping_for_cluster(s, first_cluster);
2146 assert(mapping->mode & MODE_DIRECTORY);
2147 ret = commit_direntries(s, first_dir_index + i,
2148 array_index(&(s->mapping), mapping));
2149 if (ret)
2150 return ret;
2154 return 0;
2157 /* commit one file (adjust contents, adjust mapping),
2158 return first_mapping_index */
2159 static int commit_one_file(BDRVVVFATState* s,
2160 int dir_index, uint32_t offset)
2162 direntry_t* direntry = array_get(&(s->directory), dir_index);
2163 uint32_t c = begin_of_direntry(direntry);
2164 uint32_t first_cluster = c;
2165 mapping_t* mapping = find_mapping_for_cluster(s, c);
2166 uint32_t size = filesize_of_direntry(direntry);
2167 char* cluster = malloc(s->cluster_size);
2168 uint32_t i;
2169 int fd = 0;
2171 assert(offset < size);
2172 assert((offset % s->cluster_size) == 0);
2174 for (i = s->cluster_size; i < offset; i += s->cluster_size)
2175 c = modified_fat_get(s, c);
2177 fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
2178 if (fd < 0) {
2179 fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2180 strerror(errno), errno);
2181 return fd;
2183 if (offset > 0)
2184 if (lseek(fd, offset, SEEK_SET) != offset)
2185 return -3;
2187 while (offset < size) {
2188 uint32_t c1;
2189 int rest_size = (size - offset > s->cluster_size ?
2190 s->cluster_size : size - offset);
2191 int ret;
2193 c1 = modified_fat_get(s, c);
2195 assert((size - offset == 0 && fat_eof(s, c)) ||
2196 (size > offset && c >=2 && !fat_eof(s, c)));
2197 assert(size >= 0);
2199 ret = vvfat_read(s->bs, cluster2sector(s, c),
2200 cluster, (rest_size + 0x1ff) / 0x200);
2202 if (ret < 0)
2203 return ret;
2205 if (write(fd, cluster, rest_size) < 0)
2206 return -2;
2208 offset += rest_size;
2209 c = c1;
2212 ftruncate(fd, size);
2213 close(fd);
2215 return commit_mappings(s, first_cluster, dir_index);
2218 #ifdef DEBUG
2219 /* test, if all mappings point to valid direntries */
2220 static void check1(BDRVVVFATState* s)
2222 int i;
2223 for (i = 0; i < s->mapping.next; i++) {
2224 mapping_t* mapping = array_get(&(s->mapping), i);
2225 if (mapping->mode & MODE_DELETED) {
2226 fprintf(stderr, "deleted\n");
2227 continue;
2229 assert(mapping->dir_index >= 0);
2230 assert(mapping->dir_index < s->directory.next);
2231 direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2232 assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2233 if (mapping->mode & MODE_DIRECTORY) {
2234 assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2235 assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2240 /* test, if all direntries have mappings */
2241 static void check2(BDRVVVFATState* s)
2243 int i;
2244 int first_mapping = -1;
2246 for (i = 0; i < s->directory.next; i++) {
2247 direntry_t* direntry = array_get(&(s->directory), i);
2249 if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2250 mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2251 assert(mapping);
2252 assert(mapping->dir_index == i || is_dot(direntry));
2253 assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2256 if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2257 /* cluster start */
2258 int j, count = 0;
2260 for (j = 0; j < s->mapping.next; j++) {
2261 mapping_t* mapping = array_get(&(s->mapping), j);
2262 if (mapping->mode & MODE_DELETED)
2263 continue;
2264 if (mapping->mode & MODE_DIRECTORY) {
2265 if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2266 assert(++count == 1);
2267 if (mapping->first_mapping_index == -1)
2268 first_mapping = array_index(&(s->mapping), mapping);
2269 else
2270 assert(first_mapping == mapping->first_mapping_index);
2271 if (mapping->info.dir.parent_mapping_index < 0)
2272 assert(j == 0);
2273 else {
2274 mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2275 assert(parent->mode & MODE_DIRECTORY);
2276 assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2281 if (count == 0)
2282 first_mapping = -1;
2286 #endif
2288 static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2290 int i;
2292 #ifdef DEBUG
2293 fprintf(stderr, "handle_renames\n");
2294 for (i = 0; i < s->commits.next; i++) {
2295 commit_t* commit = array_get(&(s->commits), i);
2296 fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
2298 #endif
2300 for (i = 0; i < s->commits.next;) {
2301 commit_t* commit = array_get(&(s->commits), i);
2302 if (commit->action == ACTION_RENAME) {
2303 mapping_t* mapping = find_mapping_for_cluster(s,
2304 commit->param.rename.cluster);
2305 char* old_path = mapping->path;
2307 assert(commit->path);
2308 mapping->path = commit->path;
2309 if (rename(old_path, mapping->path))
2310 return -2;
2312 if (mapping->mode & MODE_DIRECTORY) {
2313 int l1 = strlen(mapping->path);
2314 int l2 = strlen(old_path);
2315 int diff = l1 - l2;
2316 direntry_t* direntry = array_get(&(s->directory),
2317 mapping->info.dir.first_dir_index);
2318 uint32_t c = mapping->begin;
2319 int i = 0;
2321 /* recurse */
2322 while (!fat_eof(s, c)) {
2323 do {
2324 direntry_t* d = direntry + i;
2326 if (is_file(d) || (is_directory(d) && !is_dot(d))) {
2327 mapping_t* m = find_mapping_for_cluster(s,
2328 begin_of_direntry(d));
2329 int l = strlen(m->path);
2330 char* new_path = malloc(l + diff + 1);
2332 assert(!strncmp(m->path, mapping->path, l2));
2334 strcpy(new_path, mapping->path);
2335 strcpy(new_path + l1, m->path + l2);
2337 schedule_rename(s, m->begin, new_path);
2339 i++;
2340 } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2341 c = fat_get(s, c);
2345 free(old_path);
2346 array_remove(&(s->commits), i);
2347 continue;
2348 } else if (commit->action == ACTION_MKDIR) {
2349 mapping_t* mapping;
2350 int j, parent_path_len;
2352 #ifdef __MINGW32__
2353 if (mkdir(commit->path))
2354 return -5;
2355 #else
2356 if (mkdir(commit->path, 0755))
2357 return -5;
2358 #endif
2360 mapping = insert_mapping(s, commit->param.mkdir.cluster,
2361 commit->param.mkdir.cluster + 1);
2362 if (mapping == NULL)
2363 return -6;
2365 mapping->mode = MODE_DIRECTORY;
2366 mapping->read_only = 0;
2367 mapping->path = commit->path;
2368 j = s->directory.next;
2369 assert(j);
2370 insert_direntries(s, s->directory.next,
2371 0x10 * s->sectors_per_cluster);
2372 mapping->info.dir.first_dir_index = j;
2374 parent_path_len = strlen(commit->path)
2375 - strlen(get_basename(commit->path)) - 1;
2376 for (j = 0; j < s->mapping.next; j++) {
2377 mapping_t* m = array_get(&(s->mapping), j);
2378 if (m->first_mapping_index < 0 && m != mapping &&
2379 !strncmp(m->path, mapping->path, parent_path_len) &&
2380 strlen(m->path) == parent_path_len)
2381 break;
2383 assert(j < s->mapping.next);
2384 mapping->info.dir.parent_mapping_index = j;
2386 array_remove(&(s->commits), i);
2387 continue;
2390 i++;
2392 return 0;
2396 * TODO: make sure that the short name is not matching *another* file
2398 static int handle_commits(BDRVVVFATState* s)
2400 int i, fail = 0;
2402 vvfat_close_current_file(s);
2404 for (i = 0; !fail && i < s->commits.next; i++) {
2405 commit_t* commit = array_get(&(s->commits), i);
2406 switch(commit->action) {
2407 case ACTION_RENAME: case ACTION_MKDIR:
2408 assert(0);
2409 fail = -2;
2410 break;
2411 case ACTION_WRITEOUT: {
2412 direntry_t* entry = array_get(&(s->directory),
2413 commit->param.writeout.dir_index);
2414 uint32_t begin = begin_of_direntry(entry);
2415 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2417 assert(mapping);
2418 assert(mapping->begin == begin);
2419 assert(commit->path == NULL);
2421 if (commit_one_file(s, commit->param.writeout.dir_index,
2422 commit->param.writeout.modified_offset))
2423 fail = -3;
2425 break;
2427 case ACTION_NEW_FILE: {
2428 int begin = commit->param.new_file.first_cluster;
2429 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2430 direntry_t* entry;
2431 int i;
2433 /* find direntry */
2434 for (i = 0; i < s->directory.next; i++) {
2435 entry = array_get(&(s->directory), i);
2436 if (is_file(entry) && begin_of_direntry(entry) == begin)
2437 break;
2440 if (i >= s->directory.next) {
2441 fail = -6;
2442 continue;
2445 /* make sure there exists an initial mapping */
2446 if (mapping && mapping->begin != begin) {
2447 mapping->end = begin;
2448 mapping = NULL;
2450 if (mapping == NULL) {
2451 mapping = insert_mapping(s, begin, begin+1);
2453 /* most members will be fixed in commit_mappings() */
2454 assert(commit->path);
2455 mapping->path = commit->path;
2456 mapping->read_only = 0;
2457 mapping->mode = MODE_NORMAL;
2458 mapping->info.file.offset = 0;
2460 if (commit_one_file(s, i, 0))
2461 fail = -7;
2463 break;
2465 default:
2466 assert(0);
2469 if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2470 return -1;
2471 return fail;
2474 static int handle_deletes(BDRVVVFATState* s)
2476 int i, deferred = 1, deleted = 1;
2478 /* delete files corresponding to mappings marked as deleted */
2479 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2480 while (deferred && deleted) {
2481 deferred = 0;
2482 deleted = 0;
2484 for (i = 1; i < s->mapping.next; i++) {
2485 mapping_t* mapping = array_get(&(s->mapping), i);
2486 if (mapping->mode & MODE_DELETED) {
2487 direntry_t* entry = array_get(&(s->directory),
2488 mapping->dir_index);
2490 if (is_free(entry)) {
2491 /* remove file/directory */
2492 if (mapping->mode & MODE_DIRECTORY) {
2493 int j, next_dir_index = s->directory.next,
2494 first_dir_index = mapping->info.dir.first_dir_index;
2496 if (rmdir(mapping->path) < 0) {
2497 if (errno == ENOTEMPTY) {
2498 deferred++;
2499 continue;
2500 } else
2501 return -5;
2504 for (j = 1; j < s->mapping.next; j++) {
2505 mapping_t* m = array_get(&(s->mapping), j);
2506 if (m->mode & MODE_DIRECTORY &&
2507 m->info.dir.first_dir_index >
2508 first_dir_index &&
2509 m->info.dir.first_dir_index <
2510 next_dir_index)
2511 next_dir_index =
2512 m->info.dir.first_dir_index;
2514 remove_direntries(s, first_dir_index,
2515 next_dir_index - first_dir_index);
2517 deleted++;
2519 } else {
2520 if (unlink(mapping->path))
2521 return -4;
2522 deleted++;
2524 DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2525 remove_mapping(s, i);
2530 return 0;
2534 * synchronize mapping with new state:
2536 * - copy FAT (with bdrv_read)
2537 * - mark all filenames corresponding to mappings as deleted
2538 * - recurse direntries from root (using bs->bdrv_read)
2539 * - delete files corresponding to mappings marked as deleted
2541 static int do_commit(BDRVVVFATState* s)
2543 int ret = 0;
2545 /* the real meat are the commits. Nothing to do? Move along! */
2546 if (s->commits.next == 0)
2547 return 0;
2549 vvfat_close_current_file(s);
2551 ret = handle_renames_and_mkdirs(s);
2552 if (ret) {
2553 fprintf(stderr, "Error handling renames (%d)\n", ret);
2554 assert(0);
2555 return ret;
2558 /* copy FAT (with bdrv_read) */
2559 memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2561 /* recurse direntries from root (using bs->bdrv_read) */
2562 ret = commit_direntries(s, 0, -1);
2563 if (ret) {
2564 fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
2565 assert(0);
2566 return ret;
2569 ret = handle_commits(s);
2570 if (ret) {
2571 fprintf(stderr, "Error handling commits (%d)\n", ret);
2572 assert(0);
2573 return ret;
2576 ret = handle_deletes(s);
2577 if (ret) {
2578 fprintf(stderr, "Error deleting\n");
2579 assert(0);
2580 return ret;
2583 s->qcow->drv->bdrv_make_empty(s->qcow);
2585 memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2587 DLOG(checkpoint());
2588 return 0;
2591 static int try_commit(BDRVVVFATState* s)
2593 vvfat_close_current_file(s);
2594 DLOG(checkpoint());
2595 if(!is_consistent(s))
2596 return -1;
2597 return do_commit(s);
2600 static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
2601 const uint8_t *buf, int nb_sectors)
2603 BDRVVVFATState *s = bs->opaque;
2604 int i, ret;
2606 DLOG(checkpoint());
2608 vvfat_close_current_file(s);
2611 * Some sanity checks:
2612 * - do not allow writing to the boot sector
2613 * - do not allow to write non-ASCII filenames
2616 if (sector_num < s->first_sectors_number)
2617 return -1;
2619 for (i = sector2cluster(s, sector_num);
2620 i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
2621 mapping_t* mapping = find_mapping_for_cluster(s, i);
2622 if (mapping) {
2623 if (mapping->read_only) {
2624 fprintf(stderr, "Tried to write to write-protected file %s\n",
2625 mapping->path);
2626 return -1;
2629 if (mapping->mode & MODE_DIRECTORY) {
2630 int begin = cluster2sector(s, i);
2631 int end = begin + s->sectors_per_cluster, k;
2632 int dir_index;
2633 const direntry_t* direntries;
2634 long_file_name lfn;
2636 lfn_init(&lfn);
2638 if (begin < sector_num)
2639 begin = sector_num;
2640 if (end > sector_num + nb_sectors)
2641 end = sector_num + nb_sectors;
2642 dir_index = mapping->dir_index +
2643 0x10 * (begin - mapping->begin * s->sectors_per_cluster);
2644 direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
2646 for (k = 0; k < (end - begin) * 0x10; k++) {
2647 /* do not allow non-ASCII filenames */
2648 if (parse_long_name(&lfn, direntries + k) < 0) {
2649 fprintf(stderr, "Warning: non-ASCII filename\n");
2650 return -1;
2652 /* no access to the direntry of a read-only file */
2653 else if (is_short_name(direntries+k) &&
2654 (direntries[k].attributes & 1)) {
2655 if (memcmp(direntries + k,
2656 array_get(&(s->directory), dir_index + k),
2657 sizeof(direntry_t))) {
2658 fprintf(stderr, "Warning: tried to write to write-protected file\n");
2659 return -1;
2664 i = mapping->end;
2665 } else
2666 i++;
2670 * Use qcow backend. Commit later.
2672 DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
2673 ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
2674 if (ret < 0) {
2675 fprintf(stderr, "Error writing to qcow backend\n");
2676 return ret;
2679 for (i = sector2cluster(s, sector_num);
2680 i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
2681 if (i >= 0)
2682 s->used_clusters[i] |= USED_ALLOCATED;
2684 DLOG(checkpoint());
2685 /* TODO: add timeout */
2686 try_commit(s);
2688 DLOG(checkpoint());
2689 return 0;
2692 static int vvfat_is_allocated(BlockDriverState *bs,
2693 int64_t sector_num, int nb_sectors, int* n)
2695 BDRVVVFATState* s = bs->opaque;
2696 *n = s->sector_count - sector_num;
2697 if (*n > nb_sectors)
2698 *n = nb_sectors;
2699 else if (*n < 0)
2700 return 0;
2701 return 1;
2704 static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
2705 const uint8_t* buffer, int nb_sectors) {
2706 BDRVVVFATState* s = bs->opaque;
2707 return try_commit(s);
2710 static void write_target_close(BlockDriverState *bs) {
2711 BDRVVVFATState* s = bs->opaque;
2712 bdrv_delete(s->qcow);
2713 free(s->qcow_filename);
2716 static BlockDriver vvfat_write_target = {
2717 "vvfat_write_target", 0, NULL, NULL, NULL,
2718 write_target_commit,
2719 write_target_close,
2720 NULL, NULL, NULL
2723 static int enable_write_target(BDRVVVFATState *s)
2725 int size = sector2cluster(s, s->sector_count);
2726 s->used_clusters = calloc(size, 1);
2728 array_init(&(s->commits), sizeof(commit_t));
2730 s->qcow_filename = malloc(1024);
2731 get_tmp_filename(s->qcow_filename, 1024);
2732 if (bdrv_create(&bdrv_qcow,
2733 s->qcow_filename, s->sector_count, "fat:", 0) < 0)
2734 return -1;
2735 s->qcow = bdrv_new("");
2736 if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
2737 return -1;
2739 #ifndef _WIN32
2740 unlink(s->qcow_filename);
2741 #endif
2743 s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
2744 s->bs->backing_hd->drv = &vvfat_write_target;
2745 s->bs->backing_hd->opaque = s;
2747 return 0;
2750 static void vvfat_close(BlockDriverState *bs)
2752 BDRVVVFATState *s = bs->opaque;
2754 vvfat_close_current_file(s);
2755 array_free(&(s->fat));
2756 array_free(&(s->directory));
2757 array_free(&(s->mapping));
2758 if(s->cluster_buffer)
2759 free(s->cluster_buffer);
2762 BlockDriver bdrv_vvfat = {
2763 "vvfat",
2764 sizeof(BDRVVVFATState),
2765 NULL, /* no probe for protocols */
2766 vvfat_open,
2767 vvfat_read,
2768 vvfat_write,
2769 vvfat_close,
2770 NULL, /* ??? Not sure if we can do any meaningful flushing. */
2771 NULL,
2772 vvfat_is_allocated,
2773 .protocol_name = "fat",
2776 #ifdef DEBUG
2777 static void checkpoint() {
2778 assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
2779 check1(vvv);
2780 check2(vvv);
2781 assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
2782 #if 0
2783 if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
2784 fprintf(stderr, "Nonono!\n");
2785 mapping_t* mapping;
2786 direntry_t* direntry;
2787 assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
2788 assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
2789 if (vvv->mapping.next<47)
2790 return;
2791 assert((mapping = array_get(&(vvv->mapping), 47)));
2792 assert(mapping->dir_index < vvv->directory.next);
2793 direntry = array_get(&(vvv->directory), mapping->dir_index);
2794 assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0);
2795 #endif
2796 return;
2797 /* avoid compiler warnings: */
2798 hexdump(NULL, 100);
2799 remove_mapping(vvv, NULL);
2800 print_mapping(NULL);
2801 print_direntry(NULL);
2803 #endif