Fix typo: buf -> bus
[qemu.git] / block / vvfat.c
blob7e9e35a3a3048b3a4835ee6cbc67d8c06595f4de
1 /* vim:set shiftwidth=4 ts=8: */
2 /*
3 * QEMU Block driver for virtual VFAT (shadows a local directory)
5 * Copyright (c) 2004,2005 Johannes E. Schindelin
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
25 #include <sys/stat.h>
26 #include <dirent.h>
27 #include "qemu-common.h"
28 #include "block_int.h"
29 #include "module.h"
31 #ifndef S_IWGRP
32 #define S_IWGRP 0
33 #endif
34 #ifndef S_IWOTH
35 #define S_IWOTH 0
36 #endif
38 /* TODO: add ":bootsector=blabla.img:" */
39 /* LATER TODO: add automatic boot sector generation from
40 BOOTEASY.ASM and Ranish Partition Manager
41 Note that DOS assumes the system files to be the first files in the
42 file system (test if the boot sector still relies on that fact)! */
43 /* MAYBE TODO: write block-visofs.c */
44 /* TODO: call try_commit() only after a timeout */
46 /* #define DEBUG */
48 #ifdef DEBUG
50 #define DLOG(a) a
52 #undef stderr
53 #define stderr STDERR
54 FILE* stderr = NULL;
56 static void checkpoint(void);
58 #ifdef __MINGW32__
59 void nonono(const char* file, int line, const char* msg) {
60 fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg);
61 exit(-5);
63 #undef assert
64 #define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
65 #endif
67 #else
69 #define DLOG(a)
71 #endif
73 /* dynamic array functions */
74 typedef struct array_t {
75 char* pointer;
76 unsigned int size,next,item_size;
77 } array_t;
79 static inline void array_init(array_t* array,unsigned int item_size)
81 array->pointer = NULL;
82 array->size=0;
83 array->next=0;
84 array->item_size=item_size;
87 static inline void array_free(array_t* array)
89 g_free(array->pointer);
90 array->size=array->next=0;
93 /* does not automatically grow */
94 static inline void* array_get(array_t* array,unsigned int index) {
95 assert(index < array->next);
96 return array->pointer + index * array->item_size;
99 static inline int array_ensure_allocated(array_t* array, int index)
101 if((index + 1) * array->item_size > array->size) {
102 int new_size = (index + 32) * array->item_size;
103 array->pointer = g_realloc(array->pointer, new_size);
104 if (!array->pointer)
105 return -1;
106 array->size = new_size;
107 array->next = index + 1;
110 return 0;
113 static inline void* array_get_next(array_t* array) {
114 unsigned int next = array->next;
115 void* result;
117 if (array_ensure_allocated(array, next) < 0)
118 return NULL;
120 array->next = next + 1;
121 result = array_get(array, next);
123 return result;
126 static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
127 if((array->next+count)*array->item_size>array->size) {
128 int increment=count*array->item_size;
129 array->pointer=g_realloc(array->pointer,array->size+increment);
130 if(!array->pointer)
131 return NULL;
132 array->size+=increment;
134 memmove(array->pointer+(index+count)*array->item_size,
135 array->pointer+index*array->item_size,
136 (array->next-index)*array->item_size);
137 array->next+=count;
138 return array->pointer+index*array->item_size;
141 /* this performs a "roll", so that the element which was at index_from becomes
142 * index_to, but the order of all other elements is preserved. */
143 static inline int array_roll(array_t* array,int index_to,int index_from,int count)
145 char* buf;
146 char* from;
147 char* to;
148 int is;
150 if(!array ||
151 index_to<0 || index_to>=array->next ||
152 index_from<0 || index_from>=array->next)
153 return -1;
155 if(index_to==index_from)
156 return 0;
158 is=array->item_size;
159 from=array->pointer+index_from*is;
160 to=array->pointer+index_to*is;
161 buf=g_malloc(is*count);
162 memcpy(buf,from,is*count);
164 if(index_to<index_from)
165 memmove(to+is*count,to,from-to);
166 else
167 memmove(from,from+is*count,to-from);
169 memcpy(to,buf,is*count);
171 g_free(buf);
173 return 0;
176 static inline int array_remove_slice(array_t* array,int index, int count)
178 assert(index >=0);
179 assert(count > 0);
180 assert(index + count <= array->next);
181 if(array_roll(array,array->next-1,index,count))
182 return -1;
183 array->next -= count;
184 return 0;
187 static int array_remove(array_t* array,int index)
189 return array_remove_slice(array, index, 1);
192 /* return the index for a given member */
193 static int array_index(array_t* array, void* pointer)
195 size_t offset = (char*)pointer - array->pointer;
196 assert((offset % array->item_size) == 0);
197 assert(offset/array->item_size < array->next);
198 return offset/array->item_size;
201 /* These structures are used to fake a disk and the VFAT filesystem.
202 * For this reason we need to use QEMU_PACKED. */
204 typedef struct bootsector_t {
205 uint8_t jump[3];
206 uint8_t name[8];
207 uint16_t sector_size;
208 uint8_t sectors_per_cluster;
209 uint16_t reserved_sectors;
210 uint8_t number_of_fats;
211 uint16_t root_entries;
212 uint16_t total_sectors16;
213 uint8_t media_type;
214 uint16_t sectors_per_fat;
215 uint16_t sectors_per_track;
216 uint16_t number_of_heads;
217 uint32_t hidden_sectors;
218 uint32_t total_sectors;
219 union {
220 struct {
221 uint8_t drive_number;
222 uint8_t current_head;
223 uint8_t signature;
224 uint32_t id;
225 uint8_t volume_label[11];
226 } QEMU_PACKED fat16;
227 struct {
228 uint32_t sectors_per_fat;
229 uint16_t flags;
230 uint8_t major,minor;
231 uint32_t first_cluster_of_root_directory;
232 uint16_t info_sector;
233 uint16_t backup_boot_sector;
234 uint16_t ignored;
235 } QEMU_PACKED fat32;
236 } u;
237 uint8_t fat_type[8];
238 uint8_t ignored[0x1c0];
239 uint8_t magic[2];
240 } QEMU_PACKED bootsector_t;
242 typedef struct {
243 uint8_t head;
244 uint8_t sector;
245 uint8_t cylinder;
246 } mbr_chs_t;
248 typedef struct partition_t {
249 uint8_t attributes; /* 0x80 = bootable */
250 mbr_chs_t start_CHS;
251 uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
252 mbr_chs_t end_CHS;
253 uint32_t start_sector_long;
254 uint32_t length_sector_long;
255 } QEMU_PACKED partition_t;
257 typedef struct mbr_t {
258 uint8_t ignored[0x1b8];
259 uint32_t nt_id;
260 uint8_t ignored2[2];
261 partition_t partition[4];
262 uint8_t magic[2];
263 } QEMU_PACKED mbr_t;
265 typedef struct direntry_t {
266 uint8_t name[8];
267 uint8_t extension[3];
268 uint8_t attributes;
269 uint8_t reserved[2];
270 uint16_t ctime;
271 uint16_t cdate;
272 uint16_t adate;
273 uint16_t begin_hi;
274 uint16_t mtime;
275 uint16_t mdate;
276 uint16_t begin;
277 uint32_t size;
278 } QEMU_PACKED direntry_t;
280 /* this structure are used to transparently access the files */
282 typedef struct mapping_t {
283 /* begin is the first cluster, end is the last+1 */
284 uint32_t begin,end;
285 /* as s->directory is growable, no pointer may be used here */
286 unsigned int dir_index;
287 /* the clusters of a file may be in any order; this points to the first */
288 int first_mapping_index;
289 union {
290 /* offset is
291 * - the offset in the file (in clusters) for a file, or
292 * - the next cluster of the directory for a directory, and
293 * - the address of the buffer for a faked entry
295 struct {
296 uint32_t offset;
297 } file;
298 struct {
299 int parent_mapping_index;
300 int first_dir_index;
301 } dir;
302 } info;
303 /* path contains the full path, i.e. it always starts with s->path */
304 char* path;
306 enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2,
307 MODE_DIRECTORY = 4, MODE_FAKED = 8,
308 MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
309 int read_only;
310 } mapping_t;
312 #ifdef DEBUG
313 static void print_direntry(const struct direntry_t*);
314 static void print_mapping(const struct mapping_t* mapping);
315 #endif
317 /* here begins the real VVFAT driver */
319 typedef struct BDRVVVFATState {
320 BlockDriverState* bs; /* pointer to parent */
321 unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
322 unsigned char first_sectors[0x40*0x200];
324 int fat_type; /* 16 or 32 */
325 array_t fat,directory,mapping;
327 unsigned int cluster_size;
328 unsigned int sectors_per_cluster;
329 unsigned int sectors_per_fat;
330 unsigned int sectors_of_root_directory;
331 uint32_t last_cluster_of_root_directory;
332 unsigned int faked_sectors; /* how many sectors are faked before file data */
333 uint32_t sector_count; /* total number of sectors of the partition */
334 uint32_t cluster_count; /* total number of clusters of this partition */
335 uint32_t max_fat_value;
337 int current_fd;
338 mapping_t* current_mapping;
339 unsigned char* cluster; /* points to current cluster */
340 unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
341 unsigned int current_cluster;
343 /* write support */
344 BlockDriverState* write_target;
345 char* qcow_filename;
346 BlockDriverState* qcow;
347 void* fat2;
348 char* used_clusters;
349 array_t commits;
350 const char* path;
351 int downcase_short_names;
352 } BDRVVVFATState;
354 /* take the sector position spos and convert it to Cylinder/Head/Sector position
355 * if the position is outside the specified geometry, fill maximum value for CHS
356 * and return 1 to signal overflow.
358 static int sector2CHS(BlockDriverState* bs, mbr_chs_t * chs, int spos){
359 int head,sector;
360 sector = spos % (bs->secs); spos/= bs->secs;
361 head = spos % (bs->heads); spos/= bs->heads;
362 if(spos >= bs->cyls){
363 /* Overflow,
364 it happens if 32bit sector positions are used, while CHS is only 24bit.
365 Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
366 chs->head = 0xFF;
367 chs->sector = 0xFF;
368 chs->cylinder = 0xFF;
369 return 1;
371 chs->head = (uint8_t)head;
372 chs->sector = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
373 chs->cylinder = (uint8_t)spos;
374 return 0;
377 static void init_mbr(BDRVVVFATState* s)
379 /* TODO: if the files mbr.img and bootsect.img exist, use them */
380 mbr_t* real_mbr=(mbr_t*)s->first_sectors;
381 partition_t* partition = &(real_mbr->partition[0]);
382 int lba;
384 memset(s->first_sectors,0,512);
386 /* Win NT Disk Signature */
387 real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
389 partition->attributes=0x80; /* bootable */
391 /* LBA is used when partition is outside the CHS geometry */
392 lba = sector2CHS(s->bs, &partition->start_CHS, s->first_sectors_number-1);
393 lba|= sector2CHS(s->bs, &partition->end_CHS, s->sector_count);
395 /*LBA partitions are identified only by start/length_sector_long not by CHS*/
396 partition->start_sector_long =cpu_to_le32(s->first_sectors_number-1);
397 partition->length_sector_long=cpu_to_le32(s->sector_count - s->first_sectors_number+1);
399 /* FAT12/FAT16/FAT32 */
400 /* DOS uses different types when partition is LBA,
401 probably to prevent older versions from using CHS on them */
402 partition->fs_type= s->fat_type==12 ? 0x1:
403 s->fat_type==16 ? (lba?0xe:0x06):
404 /*fat_tyoe==32*/ (lba?0xc:0x0b);
406 real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
409 /* direntry functions */
411 /* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
412 static inline int short2long_name(char* dest,const char* src)
414 int i;
415 int len;
416 for(i=0;i<129 && src[i];i++) {
417 dest[2*i]=src[i];
418 dest[2*i+1]=0;
420 len=2*i;
421 dest[2*i]=dest[2*i+1]=0;
422 for(i=2*i+2;(i%26);i++)
423 dest[i]=0xff;
424 return len;
427 static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
429 char buffer[258];
430 int length=short2long_name(buffer,filename),
431 number_of_entries=(length+25)/26,i;
432 direntry_t* entry;
434 for(i=0;i<number_of_entries;i++) {
435 entry=array_get_next(&(s->directory));
436 entry->attributes=0xf;
437 entry->reserved[0]=0;
438 entry->begin=0;
439 entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
441 for(i=0;i<26*number_of_entries;i++) {
442 int offset=(i%26);
443 if(offset<10) offset=1+offset;
444 else if(offset<22) offset=14+offset-10;
445 else offset=28+offset-22;
446 entry=array_get(&(s->directory),s->directory.next-1-(i/26));
447 entry->name[offset]=buffer[i];
449 return array_get(&(s->directory),s->directory.next-number_of_entries);
452 static char is_free(const direntry_t* direntry)
454 return direntry->name[0]==0xe5 || direntry->name[0]==0x00;
457 static char is_volume_label(const direntry_t* direntry)
459 return direntry->attributes == 0x28;
462 static char is_long_name(const direntry_t* direntry)
464 return direntry->attributes == 0xf;
467 static char is_short_name(const direntry_t* direntry)
469 return !is_volume_label(direntry) && !is_long_name(direntry)
470 && !is_free(direntry);
473 static char is_directory(const direntry_t* direntry)
475 return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
478 static inline char is_dot(const direntry_t* direntry)
480 return is_short_name(direntry) && direntry->name[0] == '.';
483 static char is_file(const direntry_t* direntry)
485 return is_short_name(direntry) && !is_directory(direntry);
488 static inline uint32_t begin_of_direntry(const direntry_t* direntry)
490 return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
493 static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
495 return le32_to_cpu(direntry->size);
498 static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
500 direntry->begin = cpu_to_le16(begin & 0xffff);
501 direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
504 /* fat functions */
506 static inline uint8_t fat_chksum(const direntry_t* entry)
508 uint8_t chksum=0;
509 int i;
511 for(i=0;i<11;i++) {
512 unsigned char c;
514 c = (i < 8) ? entry->name[i] : entry->extension[i-8];
515 chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0)) + c;
518 return chksum;
521 /* if return_time==0, this returns the fat_date, else the fat_time */
522 static uint16_t fat_datetime(time_t time,int return_time) {
523 struct tm* t;
524 #ifdef _WIN32
525 t=localtime(&time); /* this is not thread safe */
526 #else
527 struct tm t1;
528 t = &t1;
529 localtime_r(&time,t);
530 #endif
531 if(return_time)
532 return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
533 return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
536 static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
538 if(s->fat_type==32) {
539 uint32_t* entry=array_get(&(s->fat),cluster);
540 *entry=cpu_to_le32(value);
541 } else if(s->fat_type==16) {
542 uint16_t* entry=array_get(&(s->fat),cluster);
543 *entry=cpu_to_le16(value&0xffff);
544 } else {
545 int offset = (cluster*3/2);
546 unsigned char* p = array_get(&(s->fat), offset);
547 switch (cluster&1) {
548 case 0:
549 p[0] = value&0xff;
550 p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
551 break;
552 case 1:
553 p[0] = (p[0]&0xf) | ((value&0xf)<<4);
554 p[1] = (value>>4);
555 break;
560 static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
562 if(s->fat_type==32) {
563 uint32_t* entry=array_get(&(s->fat),cluster);
564 return le32_to_cpu(*entry);
565 } else if(s->fat_type==16) {
566 uint16_t* entry=array_get(&(s->fat),cluster);
567 return le16_to_cpu(*entry);
568 } else {
569 const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
570 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
574 static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
576 if(fat_entry>s->max_fat_value-8)
577 return -1;
578 return 0;
581 static inline void init_fat(BDRVVVFATState* s)
583 if (s->fat_type == 12) {
584 array_init(&(s->fat),1);
585 array_ensure_allocated(&(s->fat),
586 s->sectors_per_fat * 0x200 * 3 / 2 - 1);
587 } else {
588 array_init(&(s->fat),(s->fat_type==32?4:2));
589 array_ensure_allocated(&(s->fat),
590 s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
592 memset(s->fat.pointer,0,s->fat.size);
594 switch(s->fat_type) {
595 case 12: s->max_fat_value=0xfff; break;
596 case 16: s->max_fat_value=0xffff; break;
597 case 32: s->max_fat_value=0x0fffffff; break;
598 default: s->max_fat_value=0; /* error... */
603 /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
604 /* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
605 static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
606 unsigned int directory_start, const char* filename, int is_dot)
608 int i,j,long_index=s->directory.next;
609 direntry_t* entry = NULL;
610 direntry_t* entry_long = NULL;
612 if(is_dot) {
613 entry=array_get_next(&(s->directory));
614 memset(entry->name,0x20,11);
615 memcpy(entry->name,filename,strlen(filename));
616 return entry;
619 entry_long=create_long_filename(s,filename);
621 i = strlen(filename);
622 for(j = i - 1; j>0 && filename[j]!='.';j--);
623 if (j > 0)
624 i = (j > 8 ? 8 : j);
625 else if (i > 8)
626 i = 8;
628 entry=array_get_next(&(s->directory));
629 memset(entry->name,0x20,11);
630 memcpy(entry->name, filename, i);
632 if(j > 0)
633 for (i = 0; i < 3 && filename[j+1+i]; i++)
634 entry->extension[i] = filename[j+1+i];
636 /* upcase & remove unwanted characters */
637 for(i=10;i>=0;i--) {
638 if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
639 if(entry->name[i]<=' ' || entry->name[i]>0x7f
640 || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
641 entry->name[i]='_';
642 else if(entry->name[i]>='a' && entry->name[i]<='z')
643 entry->name[i]+='A'-'a';
646 /* mangle duplicates */
647 while(1) {
648 direntry_t* entry1=array_get(&(s->directory),directory_start);
649 int j;
651 for(;entry1<entry;entry1++)
652 if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
653 break; /* found dupe */
654 if(entry1==entry) /* no dupe found */
655 break;
657 /* use all 8 characters of name */
658 if(entry->name[7]==' ') {
659 int j;
660 for(j=6;j>0 && entry->name[j]==' ';j--)
661 entry->name[j]='~';
664 /* increment number */
665 for(j=7;j>0 && entry->name[j]=='9';j--)
666 entry->name[j]='0';
667 if(j>0) {
668 if(entry->name[j]<'0' || entry->name[j]>'9')
669 entry->name[j]='0';
670 else
671 entry->name[j]++;
675 /* calculate checksum; propagate to long name */
676 if(entry_long) {
677 uint8_t chksum=fat_chksum(entry);
679 /* calculate anew, because realloc could have taken place */
680 entry_long=array_get(&(s->directory),long_index);
681 while(entry_long<entry && is_long_name(entry_long)) {
682 entry_long->reserved[1]=chksum;
683 entry_long++;
687 return entry;
691 * Read a directory. (the index of the corresponding mapping must be passed).
693 static int read_directory(BDRVVVFATState* s, int mapping_index)
695 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
696 direntry_t* direntry;
697 const char* dirname = mapping->path;
698 int first_cluster = mapping->begin;
699 int parent_index = mapping->info.dir.parent_mapping_index;
700 mapping_t* parent_mapping = (mapping_t*)
701 (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL);
702 int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
704 DIR* dir=opendir(dirname);
705 struct dirent* entry;
706 int i;
708 assert(mapping->mode & MODE_DIRECTORY);
710 if(!dir) {
711 mapping->end = mapping->begin;
712 return -1;
715 i = mapping->info.dir.first_dir_index =
716 first_cluster == 0 ? 0 : s->directory.next;
718 /* actually read the directory, and allocate the mappings */
719 while((entry=readdir(dir))) {
720 unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
721 char* buffer;
722 direntry_t* direntry;
723 struct stat st;
724 int is_dot=!strcmp(entry->d_name,".");
725 int is_dotdot=!strcmp(entry->d_name,"..");
727 if(first_cluster == 0 && (is_dotdot || is_dot))
728 continue;
730 buffer=(char*)g_malloc(length);
731 snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
733 if(stat(buffer,&st)<0) {
734 g_free(buffer);
735 continue;
738 /* create directory entry for this file */
739 direntry=create_short_and_long_name(s, i, entry->d_name,
740 is_dot || is_dotdot);
741 direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
742 direntry->reserved[0]=direntry->reserved[1]=0;
743 direntry->ctime=fat_datetime(st.st_ctime,1);
744 direntry->cdate=fat_datetime(st.st_ctime,0);
745 direntry->adate=fat_datetime(st.st_atime,0);
746 direntry->begin_hi=0;
747 direntry->mtime=fat_datetime(st.st_mtime,1);
748 direntry->mdate=fat_datetime(st.st_mtime,0);
749 if(is_dotdot)
750 set_begin_of_direntry(direntry, first_cluster_of_parent);
751 else if(is_dot)
752 set_begin_of_direntry(direntry, first_cluster);
753 else
754 direntry->begin=0; /* do that later */
755 if (st.st_size > 0x7fffffff) {
756 fprintf(stderr, "File %s is larger than 2GB\n", buffer);
757 g_free(buffer);
758 closedir(dir);
759 return -2;
761 direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
763 /* create mapping for this file */
764 if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
765 s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
766 s->current_mapping->begin=0;
767 s->current_mapping->end=st.st_size;
769 * we get the direntry of the most recent direntry, which
770 * contains the short name and all the relevant information.
772 s->current_mapping->dir_index=s->directory.next-1;
773 s->current_mapping->first_mapping_index = -1;
774 if (S_ISDIR(st.st_mode)) {
775 s->current_mapping->mode = MODE_DIRECTORY;
776 s->current_mapping->info.dir.parent_mapping_index =
777 mapping_index;
778 } else {
779 s->current_mapping->mode = MODE_UNDEFINED;
780 s->current_mapping->info.file.offset = 0;
782 s->current_mapping->path=buffer;
783 s->current_mapping->read_only =
784 (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
787 closedir(dir);
789 /* fill with zeroes up to the end of the cluster */
790 while(s->directory.next%(0x10*s->sectors_per_cluster)) {
791 direntry_t* direntry=array_get_next(&(s->directory));
792 memset(direntry,0,sizeof(direntry_t));
795 /* TODO: if there are more entries, bootsector has to be adjusted! */
796 #define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
797 if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
798 /* root directory */
799 int cur = s->directory.next;
800 array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
801 memset(array_get(&(s->directory), cur), 0,
802 (ROOT_ENTRIES - cur) * sizeof(direntry_t));
805 /* reget the mapping, since s->mapping was possibly realloc()ed */
806 mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
807 first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
808 * 0x20 / s->cluster_size;
809 mapping->end = first_cluster;
811 direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
812 set_begin_of_direntry(direntry, mapping->begin);
814 return 0;
817 static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
819 return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
822 static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
824 return s->faked_sectors + s->sectors_per_cluster * cluster_num;
827 static int init_directories(BDRVVVFATState* s,
828 const char* dirname)
830 bootsector_t* bootsector;
831 mapping_t* mapping;
832 unsigned int i;
833 unsigned int cluster;
835 memset(&(s->first_sectors[0]),0,0x40*0x200);
837 s->cluster_size=s->sectors_per_cluster*0x200;
838 s->cluster_buffer=g_malloc(s->cluster_size);
841 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
842 * where sc is sector_count,
843 * spf is sectors_per_fat,
844 * spc is sectors_per_clusters, and
845 * fat_type = 12, 16 or 32.
847 i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
848 s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
850 array_init(&(s->mapping),sizeof(mapping_t));
851 array_init(&(s->directory),sizeof(direntry_t));
853 /* add volume label */
855 direntry_t* entry=array_get_next(&(s->directory));
856 entry->attributes=0x28; /* archive | volume label */
857 memcpy(entry->name,"QEMU VVF",8);
858 memcpy(entry->extension,"AT ",3);
861 /* Now build FAT, and write back information into directory */
862 init_fat(s);
864 s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
865 s->cluster_count=sector2cluster(s, s->sector_count);
867 mapping = array_get_next(&(s->mapping));
868 mapping->begin = 0;
869 mapping->dir_index = 0;
870 mapping->info.dir.parent_mapping_index = -1;
871 mapping->first_mapping_index = -1;
872 mapping->path = g_strdup(dirname);
873 i = strlen(mapping->path);
874 if (i > 0 && mapping->path[i - 1] == '/')
875 mapping->path[i - 1] = '\0';
876 mapping->mode = MODE_DIRECTORY;
877 mapping->read_only = 0;
878 s->path = mapping->path;
880 for (i = 0, cluster = 0; i < s->mapping.next; i++) {
881 /* MS-DOS expects the FAT to be 0 for the root directory
882 * (except for the media byte). */
883 /* LATER TODO: still true for FAT32? */
884 int fix_fat = (i != 0);
885 mapping = array_get(&(s->mapping), i);
887 if (mapping->mode & MODE_DIRECTORY) {
888 mapping->begin = cluster;
889 if(read_directory(s, i)) {
890 fprintf(stderr, "Could not read directory %s\n",
891 mapping->path);
892 return -1;
894 mapping = array_get(&(s->mapping), i);
895 } else {
896 assert(mapping->mode == MODE_UNDEFINED);
897 mapping->mode=MODE_NORMAL;
898 mapping->begin = cluster;
899 if (mapping->end > 0) {
900 direntry_t* direntry = array_get(&(s->directory),
901 mapping->dir_index);
903 mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
904 set_begin_of_direntry(direntry, mapping->begin);
905 } else {
906 mapping->end = cluster + 1;
907 fix_fat = 0;
911 assert(mapping->begin < mapping->end);
913 /* next free cluster */
914 cluster = mapping->end;
916 if(cluster > s->cluster_count) {
917 fprintf(stderr,"Directory does not fit in FAT%d (capacity %s)\n",
918 s->fat_type,
919 s->fat_type == 12 ? s->sector_count == 2880 ? "1.44 MB"
920 : "2.88 MB"
921 : "504MB");
922 return -EINVAL;
925 /* fix fat for entry */
926 if (fix_fat) {
927 int j;
928 for(j = mapping->begin; j < mapping->end - 1; j++)
929 fat_set(s, j, j+1);
930 fat_set(s, mapping->end - 1, s->max_fat_value);
934 mapping = array_get(&(s->mapping), 0);
935 s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
936 s->last_cluster_of_root_directory = mapping->end;
938 /* the FAT signature */
939 fat_set(s,0,s->max_fat_value);
940 fat_set(s,1,s->max_fat_value);
942 s->current_mapping = NULL;
944 bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
945 bootsector->jump[0]=0xeb;
946 bootsector->jump[1]=0x3e;
947 bootsector->jump[2]=0x90;
948 memcpy(bootsector->name,"QEMU ",8);
949 bootsector->sector_size=cpu_to_le16(0x200);
950 bootsector->sectors_per_cluster=s->sectors_per_cluster;
951 bootsector->reserved_sectors=cpu_to_le16(1);
952 bootsector->number_of_fats=0x2; /* number of FATs */
953 bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
954 bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
955 bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
956 s->fat.pointer[0] = bootsector->media_type;
957 bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
958 bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
959 bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
960 bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
961 bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
963 /* LATER TODO: if FAT32, this is wrong */
964 bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
965 bootsector->u.fat16.current_head=0;
966 bootsector->u.fat16.signature=0x29;
967 bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
969 memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
970 memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12 ":s->fat_type==16?"FAT16 ":"FAT32 "),8);
971 bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
973 return 0;
976 #ifdef DEBUG
977 static BDRVVVFATState *vvv = NULL;
978 #endif
980 static int enable_write_target(BDRVVVFATState *s);
981 static int is_consistent(BDRVVVFATState *s);
983 static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
985 BDRVVVFATState *s = bs->opaque;
986 int floppy = 0;
987 int i;
989 #ifdef DEBUG
990 vvv = s;
991 #endif
993 DLOG(if (stderr == NULL) {
994 stderr = fopen("vvfat.log", "a");
995 setbuf(stderr, NULL);
998 s->bs = bs;
1000 s->fat_type=16;
1001 /* LATER TODO: if FAT32, adjust */
1002 s->sectors_per_cluster=0x10;
1003 /* 504MB disk*/
1004 bs->cyls=1024; bs->heads=16; bs->secs=63;
1006 s->current_cluster=0xffffffff;
1008 s->first_sectors_number=0x40;
1009 /* read only is the default for safety */
1010 bs->read_only = 1;
1011 s->qcow = s->write_target = NULL;
1012 s->qcow_filename = NULL;
1013 s->fat2 = NULL;
1014 s->downcase_short_names = 1;
1016 if (!strstart(dirname, "fat:", NULL))
1017 return -1;
1019 if (strstr(dirname, ":floppy:")) {
1020 floppy = 1;
1021 s->fat_type = 12;
1022 s->first_sectors_number = 1;
1023 s->sectors_per_cluster=2;
1024 bs->cyls = 80; bs->heads = 2; bs->secs = 36;
1027 s->sector_count=bs->cyls*bs->heads*bs->secs;
1029 if (strstr(dirname, ":32:")) {
1030 fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1031 s->fat_type = 32;
1032 } else if (strstr(dirname, ":16:")) {
1033 s->fat_type = 16;
1034 } else if (strstr(dirname, ":12:")) {
1035 s->fat_type = 12;
1036 s->sector_count=2880;
1039 if (strstr(dirname, ":rw:")) {
1040 if (enable_write_target(s))
1041 return -1;
1042 bs->read_only = 0;
1045 i = strrchr(dirname, ':') - dirname;
1046 assert(i >= 3);
1047 if (dirname[i-2] == ':' && qemu_isalpha(dirname[i-1]))
1048 /* workaround for DOS drive names */
1049 dirname += i-1;
1050 else
1051 dirname += i+1;
1053 bs->total_sectors=bs->cyls*bs->heads*bs->secs;
1055 if(init_directories(s, dirname))
1056 return -1;
1058 s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
1060 if(s->first_sectors_number==0x40)
1061 init_mbr(s);
1063 /* for some reason or other, MS-DOS does not like to know about CHS... */
1064 if (floppy)
1065 bs->heads = bs->cyls = bs->secs = 0;
1067 // assert(is_consistent(s));
1068 return 0;
1071 static inline void vvfat_close_current_file(BDRVVVFATState *s)
1073 if(s->current_mapping) {
1074 s->current_mapping = NULL;
1075 if (s->current_fd) {
1076 close(s->current_fd);
1077 s->current_fd = 0;
1080 s->current_cluster = -1;
1083 /* mappings between index1 and index2-1 are supposed to be ordered
1084 * return value is the index of the last mapping for which end>cluster_num
1086 static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1088 while(1) {
1089 int index3;
1090 mapping_t* mapping;
1091 index3=(index1+index2)/2;
1092 mapping=array_get(&(s->mapping),index3);
1093 assert(mapping->begin < mapping->end);
1094 if(mapping->begin>=cluster_num) {
1095 assert(index2!=index3 || index2==0);
1096 if(index2==index3)
1097 return index1;
1098 index2=index3;
1099 } else {
1100 if(index1==index3)
1101 return mapping->end<=cluster_num ? index2 : index1;
1102 index1=index3;
1104 assert(index1<=index2);
1105 DLOG(mapping=array_get(&(s->mapping),index1);
1106 assert(mapping->begin<=cluster_num);
1107 assert(index2 >= s->mapping.next ||
1108 ((mapping = array_get(&(s->mapping),index2)) &&
1109 mapping->end>cluster_num)));
1113 static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
1115 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
1116 mapping_t* mapping;
1117 if(index>=s->mapping.next)
1118 return NULL;
1119 mapping=array_get(&(s->mapping),index);
1120 if(mapping->begin>cluster_num)
1121 return NULL;
1122 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
1123 return mapping;
1126 static int open_file(BDRVVVFATState* s,mapping_t* mapping)
1128 if(!mapping)
1129 return -1;
1130 if(!s->current_mapping ||
1131 strcmp(s->current_mapping->path,mapping->path)) {
1132 /* open file */
1133 int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
1134 if(fd<0)
1135 return -1;
1136 vvfat_close_current_file(s);
1137 s->current_fd = fd;
1138 s->current_mapping = mapping;
1140 return 0;
1143 static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1145 if(s->current_cluster != cluster_num) {
1146 int result=0;
1147 off_t offset;
1148 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
1149 if(!s->current_mapping
1150 || s->current_mapping->begin>cluster_num
1151 || s->current_mapping->end<=cluster_num) {
1152 /* binary search of mappings for file */
1153 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
1155 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1157 if (mapping && mapping->mode & MODE_DIRECTORY) {
1158 vvfat_close_current_file(s);
1159 s->current_mapping = mapping;
1160 read_cluster_directory:
1161 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
1162 s->cluster = (unsigned char*)s->directory.pointer+offset
1163 + 0x20*s->current_mapping->info.dir.first_dir_index;
1164 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1165 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1166 s->current_cluster = cluster_num;
1167 return 0;
1170 if(open_file(s,mapping))
1171 return -2;
1172 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1173 goto read_cluster_directory;
1175 assert(s->current_fd);
1177 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
1178 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1179 return -3;
1180 s->cluster=s->cluster_buffer;
1181 result=read(s->current_fd,s->cluster,s->cluster_size);
1182 if(result<0) {
1183 s->current_cluster = -1;
1184 return -1;
1186 s->current_cluster = cluster_num;
1188 return 0;
1191 #ifdef DEBUG
1192 static void print_direntry(const direntry_t* direntry)
1194 int j = 0;
1195 char buffer[1024];
1197 fprintf(stderr, "direntry %p: ", direntry);
1198 if(!direntry)
1199 return;
1200 if(is_long_name(direntry)) {
1201 unsigned char* c=(unsigned char*)direntry;
1202 int i;
1203 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
1204 #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
1205 ADD_CHAR(c[i]);
1206 for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
1207 ADD_CHAR(c[i]);
1208 for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
1209 ADD_CHAR(c[i]);
1210 buffer[j] = 0;
1211 fprintf(stderr, "%s\n", buffer);
1212 } else {
1213 int i;
1214 for(i=0;i<11;i++)
1215 ADD_CHAR(direntry->name[i]);
1216 buffer[j] = 0;
1217 fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1218 buffer,
1219 direntry->attributes,
1220 begin_of_direntry(direntry),le32_to_cpu(direntry->size));
1224 static void print_mapping(const mapping_t* mapping)
1226 fprintf(stderr, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1227 "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1228 mapping, mapping->begin, mapping->end, mapping->dir_index,
1229 mapping->first_mapping_index, mapping->path, mapping->mode);
1231 if (mapping->mode & MODE_DIRECTORY)
1232 fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1233 else
1234 fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
1236 #endif
1238 static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
1239 uint8_t *buf, int nb_sectors)
1241 BDRVVVFATState *s = bs->opaque;
1242 int i;
1244 for(i=0;i<nb_sectors;i++,sector_num++) {
1245 if (sector_num >= s->sector_count)
1246 return -1;
1247 if (s->qcow) {
1248 int n;
1249 if (s->qcow->drv->bdrv_is_allocated(s->qcow,
1250 sector_num, nb_sectors-i, &n)) {
1251 DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
1252 if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
1253 return -1;
1254 i += n - 1;
1255 sector_num += n - 1;
1256 continue;
1258 DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
1260 if(sector_num<s->faked_sectors) {
1261 if(sector_num<s->first_sectors_number)
1262 memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
1263 else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
1264 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
1265 else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
1266 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
1267 } else {
1268 uint32_t sector=sector_num-s->faked_sectors,
1269 sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1270 cluster_num=sector/s->sectors_per_cluster;
1271 if(read_cluster(s, cluster_num) != 0) {
1272 /* LATER TODO: strict: return -1; */
1273 memset(buf+i*0x200,0,0x200);
1274 continue;
1276 memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
1279 return 0;
1282 /* LATER TODO: statify all functions */
1285 * Idea of the write support (use snapshot):
1287 * 1. check if all data is consistent, recording renames, modifications,
1288 * new files and directories (in s->commits).
1290 * 2. if the data is not consistent, stop committing
1292 * 3. handle renames, and create new files and directories (do not yet
1293 * write their contents)
1295 * 4. walk the directories, fixing the mapping and direntries, and marking
1296 * the handled mappings as not deleted
1298 * 5. commit the contents of the files
1300 * 6. handle deleted files and directories
1304 typedef struct commit_t {
1305 char* path;
1306 union {
1307 struct { uint32_t cluster; } rename;
1308 struct { int dir_index; uint32_t modified_offset; } writeout;
1309 struct { uint32_t first_cluster; } new_file;
1310 struct { uint32_t cluster; } mkdir;
1311 } param;
1312 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1313 enum {
1314 ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1315 } action;
1316 } commit_t;
1318 static void clear_commits(BDRVVVFATState* s)
1320 int i;
1321 DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1322 for (i = 0; i < s->commits.next; i++) {
1323 commit_t* commit = array_get(&(s->commits), i);
1324 assert(commit->path || commit->action == ACTION_WRITEOUT);
1325 if (commit->action != ACTION_WRITEOUT) {
1326 assert(commit->path);
1327 g_free(commit->path);
1328 } else
1329 assert(commit->path == NULL);
1331 s->commits.next = 0;
1334 static void schedule_rename(BDRVVVFATState* s,
1335 uint32_t cluster, char* new_path)
1337 commit_t* commit = array_get_next(&(s->commits));
1338 commit->path = new_path;
1339 commit->param.rename.cluster = cluster;
1340 commit->action = ACTION_RENAME;
1343 static void schedule_writeout(BDRVVVFATState* s,
1344 int dir_index, uint32_t modified_offset)
1346 commit_t* commit = array_get_next(&(s->commits));
1347 commit->path = NULL;
1348 commit->param.writeout.dir_index = dir_index;
1349 commit->param.writeout.modified_offset = modified_offset;
1350 commit->action = ACTION_WRITEOUT;
1353 static void schedule_new_file(BDRVVVFATState* s,
1354 char* path, uint32_t first_cluster)
1356 commit_t* commit = array_get_next(&(s->commits));
1357 commit->path = path;
1358 commit->param.new_file.first_cluster = first_cluster;
1359 commit->action = ACTION_NEW_FILE;
1362 static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1364 commit_t* commit = array_get_next(&(s->commits));
1365 commit->path = path;
1366 commit->param.mkdir.cluster = cluster;
1367 commit->action = ACTION_MKDIR;
1370 typedef struct {
1372 * Since the sequence number is at most 0x3f, and the filename
1373 * length is at most 13 times the sequence number, the maximal
1374 * filename length is 0x3f * 13 bytes.
1376 unsigned char name[0x3f * 13 + 1];
1377 int checksum, len;
1378 int sequence_number;
1379 } long_file_name;
1381 static void lfn_init(long_file_name* lfn)
1383 lfn->sequence_number = lfn->len = 0;
1384 lfn->checksum = 0x100;
1387 /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1388 static int parse_long_name(long_file_name* lfn,
1389 const direntry_t* direntry)
1391 int i, j, offset;
1392 const unsigned char* pointer = (const unsigned char*)direntry;
1394 if (!is_long_name(direntry))
1395 return 1;
1397 if (pointer[0] & 0x40) {
1398 lfn->sequence_number = pointer[0] & 0x3f;
1399 lfn->checksum = pointer[13];
1400 lfn->name[0] = 0;
1401 lfn->name[lfn->sequence_number * 13] = 0;
1402 } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
1403 return -1;
1404 else if (pointer[13] != lfn->checksum)
1405 return -2;
1406 else if (pointer[12] || pointer[26] || pointer[27])
1407 return -3;
1409 offset = 13 * (lfn->sequence_number - 1);
1410 for (i = 0, j = 1; i < 13; i++, j+=2) {
1411 if (j == 11)
1412 j = 14;
1413 else if (j == 26)
1414 j = 28;
1416 if (pointer[j+1] == 0)
1417 lfn->name[offset + i] = pointer[j];
1418 else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1419 return -4;
1420 else
1421 lfn->name[offset + i] = 0;
1424 if (pointer[0] & 0x40)
1425 lfn->len = offset + strlen((char*)lfn->name + offset);
1427 return 0;
1430 /* returns 0 if successful, >0 if no short_name, and <0 on error */
1431 static int parse_short_name(BDRVVVFATState* s,
1432 long_file_name* lfn, direntry_t* direntry)
1434 int i, j;
1436 if (!is_short_name(direntry))
1437 return 1;
1439 for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1440 for (i = 0; i <= j; i++) {
1441 if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
1442 return -1;
1443 else if (s->downcase_short_names)
1444 lfn->name[i] = qemu_tolower(direntry->name[i]);
1445 else
1446 lfn->name[i] = direntry->name[i];
1449 for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
1450 if (j >= 0) {
1451 lfn->name[i++] = '.';
1452 lfn->name[i + j + 1] = '\0';
1453 for (;j >= 0; j--) {
1454 if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
1455 return -2;
1456 else if (s->downcase_short_names)
1457 lfn->name[i + j] = qemu_tolower(direntry->extension[j]);
1458 else
1459 lfn->name[i + j] = direntry->extension[j];
1461 } else
1462 lfn->name[i + j + 1] = '\0';
1464 lfn->len = strlen((char*)lfn->name);
1466 return 0;
1469 static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1470 unsigned int cluster)
1472 if (cluster < s->last_cluster_of_root_directory) {
1473 if (cluster + 1 == s->last_cluster_of_root_directory)
1474 return s->max_fat_value;
1475 else
1476 return cluster + 1;
1479 if (s->fat_type==32) {
1480 uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1481 return le32_to_cpu(*entry);
1482 } else if (s->fat_type==16) {
1483 uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1484 return le16_to_cpu(*entry);
1485 } else {
1486 const uint8_t* x=s->fat2+cluster*3/2;
1487 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1491 static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1493 int was_modified = 0;
1494 int i, dummy;
1496 if (s->qcow == NULL)
1497 return 0;
1499 for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
1500 was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
1501 cluster2sector(s, cluster_num) + i, 1, &dummy);
1503 return was_modified;
1506 static const char* get_basename(const char* path)
1508 char* basename = strrchr(path, '/');
1509 if (basename == NULL)
1510 return path;
1511 else
1512 return basename + 1; /* strip '/' */
1516 * The array s->used_clusters holds the states of the clusters. If it is
1517 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1518 * was modified, bit 3 is set.
1519 * If any cluster is allocated, but not part of a file or directory, this
1520 * driver refuses to commit.
1522 typedef enum {
1523 USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
1524 } used_t;
1527 * get_cluster_count_for_direntry() not only determines how many clusters
1528 * are occupied by direntry, but also if it was renamed or modified.
1530 * A file is thought to be renamed *only* if there already was a file with
1531 * exactly the same first cluster, but a different name.
1533 * Further, the files/directories handled by this function are
1534 * assumed to be *not* deleted (and *only* those).
1536 static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
1537 direntry_t* direntry, const char* path)
1540 * This is a little bit tricky:
1541 * IF the guest OS just inserts a cluster into the file chain,
1542 * and leaves the rest alone, (i.e. the original file had clusters
1543 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1545 * - do_commit will write the cluster into the file at the given
1546 * offset, but
1548 * - the cluster which is overwritten should be moved to a later
1549 * position in the file.
1551 * I am not aware that any OS does something as braindead, but this
1552 * situation could happen anyway when not committing for a long time.
1553 * Just to be sure that this does not bite us, detect it, and copy the
1554 * contents of the clusters to-be-overwritten into the qcow.
1556 int copy_it = 0;
1557 int was_modified = 0;
1558 int32_t ret = 0;
1560 uint32_t cluster_num = begin_of_direntry(direntry);
1561 uint32_t offset = 0;
1562 int first_mapping_index = -1;
1563 mapping_t* mapping = NULL;
1564 const char* basename2 = NULL;
1566 vvfat_close_current_file(s);
1568 /* the root directory */
1569 if (cluster_num == 0)
1570 return 0;
1572 /* write support */
1573 if (s->qcow) {
1574 basename2 = get_basename(path);
1576 mapping = find_mapping_for_cluster(s, cluster_num);
1578 if (mapping) {
1579 const char* basename;
1581 assert(mapping->mode & MODE_DELETED);
1582 mapping->mode &= ~MODE_DELETED;
1584 basename = get_basename(mapping->path);
1586 assert(mapping->mode & MODE_NORMAL);
1588 /* rename */
1589 if (strcmp(basename, basename2))
1590 schedule_rename(s, cluster_num, g_strdup(path));
1591 } else if (is_file(direntry))
1592 /* new file */
1593 schedule_new_file(s, g_strdup(path), cluster_num);
1594 else {
1595 abort();
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 abort();
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 abort();
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 = g_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 + 1];
1695 assert(path_len < PATH_MAX); /* len was tested before! */
1696 pstrcpy(path2, sizeof(path2), path);
1697 path2[path_len] = '/';
1698 path2[path_len + 1] = '\0';
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, g_strdup(path));
1711 } else
1712 /* new directory */
1713 schedule_mkdir(s, cluster_num, g_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 g_free(cluster);
1735 return 0;
1738 for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
1739 int cluster_count = 0;
1741 DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i));
1742 if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
1743 is_free(direntries + i))
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((char*)lfn.name, ".")
1761 || !strcmp((char*)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 pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
1771 (char*)lfn.name);
1773 if (is_directory(direntries + i)) {
1774 if (begin_of_direntry(direntries + i) == 0) {
1775 DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
1776 goto fail;
1778 cluster_count = check_directory_consistency(s,
1779 begin_of_direntry(direntries + i), path2);
1780 if (cluster_count == 0) {
1781 DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
1782 goto fail;
1784 } else if (is_file(direntries + i)) {
1785 /* check file size with FAT */
1786 cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
1787 if (cluster_count !=
1788 (le32_to_cpu(direntries[i].size) + s->cluster_size
1789 - 1) / s->cluster_size) {
1790 DLOG(fprintf(stderr, "Cluster count mismatch\n"));
1791 goto fail;
1793 } else
1794 abort(); /* cluster_count = 0; */
1796 ret += cluster_count;
1799 cluster_num = modified_fat_get(s, cluster_num);
1800 } while(!fat_eof(s, cluster_num));
1802 g_free(cluster);
1803 return ret;
1806 /* returns 1 on success */
1807 static int is_consistent(BDRVVVFATState* s)
1809 int i, check;
1810 int used_clusters_count = 0;
1812 DLOG(checkpoint());
1814 * - get modified FAT
1815 * - compare the two FATs (TODO)
1816 * - get buffer for marking used clusters
1817 * - recurse direntries from root (using bs->bdrv_read to make
1818 * sure to get the new data)
1819 * - check that the FAT agrees with the size
1820 * - count the number of clusters occupied by this directory and
1821 * its files
1822 * - check that the cumulative used cluster count agrees with the
1823 * FAT
1824 * - if all is fine, return number of used clusters
1826 if (s->fat2 == NULL) {
1827 int size = 0x200 * s->sectors_per_fat;
1828 s->fat2 = g_malloc(size);
1829 memcpy(s->fat2, s->fat.pointer, size);
1831 check = vvfat_read(s->bs,
1832 s->first_sectors_number, s->fat2, s->sectors_per_fat);
1833 if (check) {
1834 fprintf(stderr, "Could not copy fat\n");
1835 return 0;
1837 assert (s->used_clusters);
1838 for (i = 0; i < sector2cluster(s, s->sector_count); i++)
1839 s->used_clusters[i] &= ~USED_ANY;
1841 clear_commits(s);
1843 /* mark every mapped file/directory as deleted.
1844 * (check_directory_consistency() will unmark those still present). */
1845 if (s->qcow)
1846 for (i = 0; i < s->mapping.next; i++) {
1847 mapping_t* mapping = array_get(&(s->mapping), i);
1848 if (mapping->first_mapping_index < 0)
1849 mapping->mode |= MODE_DELETED;
1852 used_clusters_count = check_directory_consistency(s, 0, s->path);
1853 if (used_clusters_count <= 0) {
1854 DLOG(fprintf(stderr, "problem in directory\n"));
1855 return 0;
1858 check = s->last_cluster_of_root_directory;
1859 for (i = check; i < sector2cluster(s, s->sector_count); i++) {
1860 if (modified_fat_get(s, i)) {
1861 if(!s->used_clusters[i]) {
1862 DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
1863 return 0;
1865 check++;
1868 if (s->used_clusters[i] == USED_ALLOCATED) {
1869 /* allocated, but not used... */
1870 DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
1871 return 0;
1875 if (check != used_clusters_count)
1876 return 0;
1878 return used_clusters_count;
1881 static inline void adjust_mapping_indices(BDRVVVFATState* s,
1882 int offset, int adjust)
1884 int i;
1886 for (i = 0; i < s->mapping.next; i++) {
1887 mapping_t* mapping = array_get(&(s->mapping), i);
1889 #define ADJUST_MAPPING_INDEX(name) \
1890 if (mapping->name >= offset) \
1891 mapping->name += adjust
1893 ADJUST_MAPPING_INDEX(first_mapping_index);
1894 if (mapping->mode & MODE_DIRECTORY)
1895 ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
1899 /* insert or update mapping */
1900 static mapping_t* insert_mapping(BDRVVVFATState* s,
1901 uint32_t begin, uint32_t end)
1904 * - find mapping where mapping->begin >= begin,
1905 * - if mapping->begin > begin: insert
1906 * - adjust all references to mappings!
1907 * - else: adjust
1908 * - replace name
1910 int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
1911 mapping_t* mapping = NULL;
1912 mapping_t* first_mapping = array_get(&(s->mapping), 0);
1914 if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
1915 && mapping->begin < begin) {
1916 mapping->end = begin;
1917 index++;
1918 mapping = array_get(&(s->mapping), index);
1920 if (index >= s->mapping.next || mapping->begin > begin) {
1921 mapping = array_insert(&(s->mapping), index, 1);
1922 mapping->path = NULL;
1923 adjust_mapping_indices(s, index, +1);
1926 mapping->begin = begin;
1927 mapping->end = end;
1929 DLOG(mapping_t* next_mapping;
1930 assert(index + 1 >= s->mapping.next ||
1931 ((next_mapping = array_get(&(s->mapping), index + 1)) &&
1932 next_mapping->begin >= end)));
1934 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1935 s->current_mapping = array_get(&(s->mapping),
1936 s->current_mapping - first_mapping);
1938 return mapping;
1941 static int remove_mapping(BDRVVVFATState* s, int mapping_index)
1943 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
1944 mapping_t* first_mapping = array_get(&(s->mapping), 0);
1946 /* free mapping */
1947 if (mapping->first_mapping_index < 0) {
1948 g_free(mapping->path);
1951 /* remove from s->mapping */
1952 array_remove(&(s->mapping), mapping_index);
1954 /* adjust all references to mappings */
1955 adjust_mapping_indices(s, mapping_index, -1);
1957 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1958 s->current_mapping = array_get(&(s->mapping),
1959 s->current_mapping - first_mapping);
1961 return 0;
1964 static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
1966 int i;
1967 for (i = 0; i < s->mapping.next; i++) {
1968 mapping_t* mapping = array_get(&(s->mapping), i);
1969 if (mapping->dir_index >= offset)
1970 mapping->dir_index += adjust;
1971 if ((mapping->mode & MODE_DIRECTORY) &&
1972 mapping->info.dir.first_dir_index >= offset)
1973 mapping->info.dir.first_dir_index += adjust;
1977 static direntry_t* insert_direntries(BDRVVVFATState* s,
1978 int dir_index, int count)
1981 * make room in s->directory,
1982 * adjust_dirindices
1984 direntry_t* result = array_insert(&(s->directory), dir_index, count);
1985 if (result == NULL)
1986 return NULL;
1987 adjust_dirindices(s, dir_index, count);
1988 return result;
1991 static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
1993 int ret = array_remove_slice(&(s->directory), dir_index, count);
1994 if (ret)
1995 return ret;
1996 adjust_dirindices(s, dir_index, -count);
1997 return 0;
2001 * Adapt the mappings of the cluster chain starting at first cluster
2002 * (i.e. if a file starts at first_cluster, the chain is followed according
2003 * to the modified fat, and the corresponding entries in s->mapping are
2004 * adjusted)
2006 static int commit_mappings(BDRVVVFATState* s,
2007 uint32_t first_cluster, int dir_index)
2009 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2010 direntry_t* direntry = array_get(&(s->directory), dir_index);
2011 uint32_t cluster = first_cluster;
2013 vvfat_close_current_file(s);
2015 assert(mapping);
2016 assert(mapping->begin == first_cluster);
2017 mapping->first_mapping_index = -1;
2018 mapping->dir_index = dir_index;
2019 mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2020 MODE_DIRECTORY : MODE_NORMAL;
2022 while (!fat_eof(s, cluster)) {
2023 uint32_t c, c1;
2025 for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2026 c = c1, c1 = modified_fat_get(s, c1));
2028 c++;
2029 if (c > mapping->end) {
2030 int index = array_index(&(s->mapping), mapping);
2031 int i, max_i = s->mapping.next - index;
2032 for (i = 1; i < max_i && mapping[i].begin < c; i++);
2033 while (--i > 0)
2034 remove_mapping(s, index + 1);
2036 assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2037 || mapping[1].begin >= c);
2038 mapping->end = c;
2040 if (!fat_eof(s, c1)) {
2041 int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2042 mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2043 array_get(&(s->mapping), i);
2045 if (next_mapping == NULL || next_mapping->begin > c1) {
2046 int i1 = array_index(&(s->mapping), mapping);
2048 next_mapping = insert_mapping(s, c1, c1+1);
2050 if (c1 < c)
2051 i1++;
2052 mapping = array_get(&(s->mapping), i1);
2055 next_mapping->dir_index = mapping->dir_index;
2056 next_mapping->first_mapping_index =
2057 mapping->first_mapping_index < 0 ?
2058 array_index(&(s->mapping), mapping) :
2059 mapping->first_mapping_index;
2060 next_mapping->path = mapping->path;
2061 next_mapping->mode = mapping->mode;
2062 next_mapping->read_only = mapping->read_only;
2063 if (mapping->mode & MODE_DIRECTORY) {
2064 next_mapping->info.dir.parent_mapping_index =
2065 mapping->info.dir.parent_mapping_index;
2066 next_mapping->info.dir.first_dir_index =
2067 mapping->info.dir.first_dir_index +
2068 0x10 * s->sectors_per_cluster *
2069 (mapping->end - mapping->begin);
2070 } else
2071 next_mapping->info.file.offset = mapping->info.file.offset +
2072 mapping->end - mapping->begin;
2074 mapping = next_mapping;
2077 cluster = c1;
2080 return 0;
2083 static int commit_direntries(BDRVVVFATState* s,
2084 int dir_index, int parent_mapping_index)
2086 direntry_t* direntry = array_get(&(s->directory), dir_index);
2087 uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
2088 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2090 int factor = 0x10 * s->sectors_per_cluster;
2091 int old_cluster_count, new_cluster_count;
2092 int current_dir_index = mapping->info.dir.first_dir_index;
2093 int first_dir_index = current_dir_index;
2094 int ret, i;
2095 uint32_t c;
2097 DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
2099 assert(direntry);
2100 assert(mapping);
2101 assert(mapping->begin == first_cluster);
2102 assert(mapping->info.dir.first_dir_index < s->directory.next);
2103 assert(mapping->mode & MODE_DIRECTORY);
2104 assert(dir_index == 0 || is_directory(direntry));
2106 mapping->info.dir.parent_mapping_index = parent_mapping_index;
2108 if (first_cluster == 0) {
2109 old_cluster_count = new_cluster_count =
2110 s->last_cluster_of_root_directory;
2111 } else {
2112 for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2113 c = fat_get(s, c))
2114 old_cluster_count++;
2116 for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2117 c = modified_fat_get(s, c))
2118 new_cluster_count++;
2121 if (new_cluster_count > old_cluster_count) {
2122 if (insert_direntries(s,
2123 current_dir_index + factor * old_cluster_count,
2124 factor * (new_cluster_count - old_cluster_count)) == NULL)
2125 return -1;
2126 } else if (new_cluster_count < old_cluster_count)
2127 remove_direntries(s,
2128 current_dir_index + factor * new_cluster_count,
2129 factor * (old_cluster_count - new_cluster_count));
2131 for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
2132 void* direntry = array_get(&(s->directory), current_dir_index);
2133 int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2134 s->sectors_per_cluster);
2135 if (ret)
2136 return ret;
2137 assert(!strncmp(s->directory.pointer, "QEMU", 4));
2138 current_dir_index += factor;
2141 ret = commit_mappings(s, first_cluster, dir_index);
2142 if (ret)
2143 return ret;
2145 /* recurse */
2146 for (i = 0; i < factor * new_cluster_count; i++) {
2147 direntry = array_get(&(s->directory), first_dir_index + i);
2148 if (is_directory(direntry) && !is_dot(direntry)) {
2149 mapping = find_mapping_for_cluster(s, first_cluster);
2150 assert(mapping->mode & MODE_DIRECTORY);
2151 ret = commit_direntries(s, first_dir_index + i,
2152 array_index(&(s->mapping), mapping));
2153 if (ret)
2154 return ret;
2158 return 0;
2161 /* commit one file (adjust contents, adjust mapping),
2162 return first_mapping_index */
2163 static int commit_one_file(BDRVVVFATState* s,
2164 int dir_index, uint32_t offset)
2166 direntry_t* direntry = array_get(&(s->directory), dir_index);
2167 uint32_t c = begin_of_direntry(direntry);
2168 uint32_t first_cluster = c;
2169 mapping_t* mapping = find_mapping_for_cluster(s, c);
2170 uint32_t size = filesize_of_direntry(direntry);
2171 char* cluster = g_malloc(s->cluster_size);
2172 uint32_t i;
2173 int fd = 0;
2175 assert(offset < size);
2176 assert((offset % s->cluster_size) == 0);
2178 for (i = s->cluster_size; i < offset; i += s->cluster_size)
2179 c = modified_fat_get(s, c);
2181 fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
2182 if (fd < 0) {
2183 fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2184 strerror(errno), errno);
2185 g_free(cluster);
2186 return fd;
2188 if (offset > 0) {
2189 if (lseek(fd, offset, SEEK_SET) != offset) {
2190 g_free(cluster);
2191 return -3;
2195 while (offset < size) {
2196 uint32_t c1;
2197 int rest_size = (size - offset > s->cluster_size ?
2198 s->cluster_size : size - offset);
2199 int ret;
2201 c1 = modified_fat_get(s, c);
2203 assert((size - offset == 0 && fat_eof(s, c)) ||
2204 (size > offset && c >=2 && !fat_eof(s, c)));
2206 ret = vvfat_read(s->bs, cluster2sector(s, c),
2207 (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
2209 if (ret < 0) {
2210 g_free(cluster);
2211 return ret;
2214 if (write(fd, cluster, rest_size) < 0) {
2215 g_free(cluster);
2216 return -2;
2219 offset += rest_size;
2220 c = c1;
2223 if (ftruncate(fd, size)) {
2224 perror("ftruncate()");
2225 close(fd);
2226 g_free(cluster);
2227 return -4;
2229 close(fd);
2230 g_free(cluster);
2232 return commit_mappings(s, first_cluster, dir_index);
2235 #ifdef DEBUG
2236 /* test, if all mappings point to valid direntries */
2237 static void check1(BDRVVVFATState* s)
2239 int i;
2240 for (i = 0; i < s->mapping.next; i++) {
2241 mapping_t* mapping = array_get(&(s->mapping), i);
2242 if (mapping->mode & MODE_DELETED) {
2243 fprintf(stderr, "deleted\n");
2244 continue;
2246 assert(mapping->dir_index < s->directory.next);
2247 direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2248 assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2249 if (mapping->mode & MODE_DIRECTORY) {
2250 assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2251 assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2256 /* test, if all direntries have mappings */
2257 static void check2(BDRVVVFATState* s)
2259 int i;
2260 int first_mapping = -1;
2262 for (i = 0; i < s->directory.next; i++) {
2263 direntry_t* direntry = array_get(&(s->directory), i);
2265 if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2266 mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2267 assert(mapping);
2268 assert(mapping->dir_index == i || is_dot(direntry));
2269 assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2272 if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2273 /* cluster start */
2274 int j, count = 0;
2276 for (j = 0; j < s->mapping.next; j++) {
2277 mapping_t* mapping = array_get(&(s->mapping), j);
2278 if (mapping->mode & MODE_DELETED)
2279 continue;
2280 if (mapping->mode & MODE_DIRECTORY) {
2281 if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2282 assert(++count == 1);
2283 if (mapping->first_mapping_index == -1)
2284 first_mapping = array_index(&(s->mapping), mapping);
2285 else
2286 assert(first_mapping == mapping->first_mapping_index);
2287 if (mapping->info.dir.parent_mapping_index < 0)
2288 assert(j == 0);
2289 else {
2290 mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2291 assert(parent->mode & MODE_DIRECTORY);
2292 assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2297 if (count == 0)
2298 first_mapping = -1;
2302 #endif
2304 static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2306 int i;
2308 #ifdef DEBUG
2309 fprintf(stderr, "handle_renames\n");
2310 for (i = 0; i < s->commits.next; i++) {
2311 commit_t* commit = array_get(&(s->commits), i);
2312 fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
2314 #endif
2316 for (i = 0; i < s->commits.next;) {
2317 commit_t* commit = array_get(&(s->commits), i);
2318 if (commit->action == ACTION_RENAME) {
2319 mapping_t* mapping = find_mapping_for_cluster(s,
2320 commit->param.rename.cluster);
2321 char* old_path = mapping->path;
2323 assert(commit->path);
2324 mapping->path = commit->path;
2325 if (rename(old_path, mapping->path))
2326 return -2;
2328 if (mapping->mode & MODE_DIRECTORY) {
2329 int l1 = strlen(mapping->path);
2330 int l2 = strlen(old_path);
2331 int diff = l1 - l2;
2332 direntry_t* direntry = array_get(&(s->directory),
2333 mapping->info.dir.first_dir_index);
2334 uint32_t c = mapping->begin;
2335 int i = 0;
2337 /* recurse */
2338 while (!fat_eof(s, c)) {
2339 do {
2340 direntry_t* d = direntry + i;
2342 if (is_file(d) || (is_directory(d) && !is_dot(d))) {
2343 mapping_t* m = find_mapping_for_cluster(s,
2344 begin_of_direntry(d));
2345 int l = strlen(m->path);
2346 char* new_path = g_malloc(l + diff + 1);
2348 assert(!strncmp(m->path, mapping->path, l2));
2350 pstrcpy(new_path, l + diff + 1, mapping->path);
2351 pstrcpy(new_path + l1, l + diff + 1 - l1,
2352 m->path + l2);
2354 schedule_rename(s, m->begin, new_path);
2356 i++;
2357 } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2358 c = fat_get(s, c);
2362 g_free(old_path);
2363 array_remove(&(s->commits), i);
2364 continue;
2365 } else if (commit->action == ACTION_MKDIR) {
2366 mapping_t* mapping;
2367 int j, parent_path_len;
2369 #ifdef __MINGW32__
2370 if (mkdir(commit->path))
2371 return -5;
2372 #else
2373 if (mkdir(commit->path, 0755))
2374 return -5;
2375 #endif
2377 mapping = insert_mapping(s, commit->param.mkdir.cluster,
2378 commit->param.mkdir.cluster + 1);
2379 if (mapping == NULL)
2380 return -6;
2382 mapping->mode = MODE_DIRECTORY;
2383 mapping->read_only = 0;
2384 mapping->path = commit->path;
2385 j = s->directory.next;
2386 assert(j);
2387 insert_direntries(s, s->directory.next,
2388 0x10 * s->sectors_per_cluster);
2389 mapping->info.dir.first_dir_index = j;
2391 parent_path_len = strlen(commit->path)
2392 - strlen(get_basename(commit->path)) - 1;
2393 for (j = 0; j < s->mapping.next; j++) {
2394 mapping_t* m = array_get(&(s->mapping), j);
2395 if (m->first_mapping_index < 0 && m != mapping &&
2396 !strncmp(m->path, mapping->path, parent_path_len) &&
2397 strlen(m->path) == parent_path_len)
2398 break;
2400 assert(j < s->mapping.next);
2401 mapping->info.dir.parent_mapping_index = j;
2403 array_remove(&(s->commits), i);
2404 continue;
2407 i++;
2409 return 0;
2413 * TODO: make sure that the short name is not matching *another* file
2415 static int handle_commits(BDRVVVFATState* s)
2417 int i, fail = 0;
2419 vvfat_close_current_file(s);
2421 for (i = 0; !fail && i < s->commits.next; i++) {
2422 commit_t* commit = array_get(&(s->commits), i);
2423 switch(commit->action) {
2424 case ACTION_RENAME: case ACTION_MKDIR:
2425 abort();
2426 fail = -2;
2427 break;
2428 case ACTION_WRITEOUT: {
2429 #ifndef NDEBUG
2430 /* these variables are only used by assert() below */
2431 direntry_t* entry = array_get(&(s->directory),
2432 commit->param.writeout.dir_index);
2433 uint32_t begin = begin_of_direntry(entry);
2434 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2435 #endif
2437 assert(mapping);
2438 assert(mapping->begin == begin);
2439 assert(commit->path == NULL);
2441 if (commit_one_file(s, commit->param.writeout.dir_index,
2442 commit->param.writeout.modified_offset))
2443 fail = -3;
2445 break;
2447 case ACTION_NEW_FILE: {
2448 int begin = commit->param.new_file.first_cluster;
2449 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2450 direntry_t* entry;
2451 int i;
2453 /* find direntry */
2454 for (i = 0; i < s->directory.next; i++) {
2455 entry = array_get(&(s->directory), i);
2456 if (is_file(entry) && begin_of_direntry(entry) == begin)
2457 break;
2460 if (i >= s->directory.next) {
2461 fail = -6;
2462 continue;
2465 /* make sure there exists an initial mapping */
2466 if (mapping && mapping->begin != begin) {
2467 mapping->end = begin;
2468 mapping = NULL;
2470 if (mapping == NULL) {
2471 mapping = insert_mapping(s, begin, begin+1);
2473 /* most members will be fixed in commit_mappings() */
2474 assert(commit->path);
2475 mapping->path = commit->path;
2476 mapping->read_only = 0;
2477 mapping->mode = MODE_NORMAL;
2478 mapping->info.file.offset = 0;
2480 if (commit_one_file(s, i, 0))
2481 fail = -7;
2483 break;
2485 default:
2486 abort();
2489 if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2490 return -1;
2491 return fail;
2494 static int handle_deletes(BDRVVVFATState* s)
2496 int i, deferred = 1, deleted = 1;
2498 /* delete files corresponding to mappings marked as deleted */
2499 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2500 while (deferred && deleted) {
2501 deferred = 0;
2502 deleted = 0;
2504 for (i = 1; i < s->mapping.next; i++) {
2505 mapping_t* mapping = array_get(&(s->mapping), i);
2506 if (mapping->mode & MODE_DELETED) {
2507 direntry_t* entry = array_get(&(s->directory),
2508 mapping->dir_index);
2510 if (is_free(entry)) {
2511 /* remove file/directory */
2512 if (mapping->mode & MODE_DIRECTORY) {
2513 int j, next_dir_index = s->directory.next,
2514 first_dir_index = mapping->info.dir.first_dir_index;
2516 if (rmdir(mapping->path) < 0) {
2517 if (errno == ENOTEMPTY) {
2518 deferred++;
2519 continue;
2520 } else
2521 return -5;
2524 for (j = 1; j < s->mapping.next; j++) {
2525 mapping_t* m = array_get(&(s->mapping), j);
2526 if (m->mode & MODE_DIRECTORY &&
2527 m->info.dir.first_dir_index >
2528 first_dir_index &&
2529 m->info.dir.first_dir_index <
2530 next_dir_index)
2531 next_dir_index =
2532 m->info.dir.first_dir_index;
2534 remove_direntries(s, first_dir_index,
2535 next_dir_index - first_dir_index);
2537 deleted++;
2539 } else {
2540 if (unlink(mapping->path))
2541 return -4;
2542 deleted++;
2544 DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2545 remove_mapping(s, i);
2550 return 0;
2554 * synchronize mapping with new state:
2556 * - copy FAT (with bdrv_read)
2557 * - mark all filenames corresponding to mappings as deleted
2558 * - recurse direntries from root (using bs->bdrv_read)
2559 * - delete files corresponding to mappings marked as deleted
2561 static int do_commit(BDRVVVFATState* s)
2563 int ret = 0;
2565 /* the real meat are the commits. Nothing to do? Move along! */
2566 if (s->commits.next == 0)
2567 return 0;
2569 vvfat_close_current_file(s);
2571 ret = handle_renames_and_mkdirs(s);
2572 if (ret) {
2573 fprintf(stderr, "Error handling renames (%d)\n", ret);
2574 abort();
2575 return ret;
2578 /* copy FAT (with bdrv_read) */
2579 memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2581 /* recurse direntries from root (using bs->bdrv_read) */
2582 ret = commit_direntries(s, 0, -1);
2583 if (ret) {
2584 fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
2585 abort();
2586 return ret;
2589 ret = handle_commits(s);
2590 if (ret) {
2591 fprintf(stderr, "Error handling commits (%d)\n", ret);
2592 abort();
2593 return ret;
2596 ret = handle_deletes(s);
2597 if (ret) {
2598 fprintf(stderr, "Error deleting\n");
2599 abort();
2600 return ret;
2603 s->qcow->drv->bdrv_make_empty(s->qcow);
2605 memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2607 DLOG(checkpoint());
2608 return 0;
2611 static int try_commit(BDRVVVFATState* s)
2613 vvfat_close_current_file(s);
2614 DLOG(checkpoint());
2615 if(!is_consistent(s))
2616 return -1;
2617 return do_commit(s);
2620 static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
2621 const uint8_t *buf, int nb_sectors)
2623 BDRVVVFATState *s = bs->opaque;
2624 int i, ret;
2626 DLOG(checkpoint());
2628 /* Check if we're operating in read-only mode */
2629 if (s->qcow == NULL) {
2630 return -EACCES;
2633 vvfat_close_current_file(s);
2636 * Some sanity checks:
2637 * - do not allow writing to the boot sector
2638 * - do not allow to write non-ASCII filenames
2641 if (sector_num < s->first_sectors_number)
2642 return -1;
2644 for (i = sector2cluster(s, sector_num);
2645 i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
2646 mapping_t* mapping = find_mapping_for_cluster(s, i);
2647 if (mapping) {
2648 if (mapping->read_only) {
2649 fprintf(stderr, "Tried to write to write-protected file %s\n",
2650 mapping->path);
2651 return -1;
2654 if (mapping->mode & MODE_DIRECTORY) {
2655 int begin = cluster2sector(s, i);
2656 int end = begin + s->sectors_per_cluster, k;
2657 int dir_index;
2658 const direntry_t* direntries;
2659 long_file_name lfn;
2661 lfn_init(&lfn);
2663 if (begin < sector_num)
2664 begin = sector_num;
2665 if (end > sector_num + nb_sectors)
2666 end = sector_num + nb_sectors;
2667 dir_index = mapping->dir_index +
2668 0x10 * (begin - mapping->begin * s->sectors_per_cluster);
2669 direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
2671 for (k = 0; k < (end - begin) * 0x10; k++) {
2672 /* do not allow non-ASCII filenames */
2673 if (parse_long_name(&lfn, direntries + k) < 0) {
2674 fprintf(stderr, "Warning: non-ASCII filename\n");
2675 return -1;
2677 /* no access to the direntry of a read-only file */
2678 else if (is_short_name(direntries+k) &&
2679 (direntries[k].attributes & 1)) {
2680 if (memcmp(direntries + k,
2681 array_get(&(s->directory), dir_index + k),
2682 sizeof(direntry_t))) {
2683 fprintf(stderr, "Warning: tried to write to write-protected file\n");
2684 return -1;
2689 i = mapping->end;
2690 } else
2691 i++;
2695 * Use qcow backend. Commit later.
2697 DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
2698 ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
2699 if (ret < 0) {
2700 fprintf(stderr, "Error writing to qcow backend\n");
2701 return ret;
2704 for (i = sector2cluster(s, sector_num);
2705 i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
2706 if (i >= 0)
2707 s->used_clusters[i] |= USED_ALLOCATED;
2709 DLOG(checkpoint());
2710 /* TODO: add timeout */
2711 try_commit(s);
2713 DLOG(checkpoint());
2714 return 0;
2717 static int vvfat_is_allocated(BlockDriverState *bs,
2718 int64_t sector_num, int nb_sectors, int* n)
2720 BDRVVVFATState* s = bs->opaque;
2721 *n = s->sector_count - sector_num;
2722 if (*n > nb_sectors)
2723 *n = nb_sectors;
2724 else if (*n < 0)
2725 return 0;
2726 return 1;
2729 static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
2730 const uint8_t* buffer, int nb_sectors) {
2731 BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
2732 return try_commit(s);
2735 static void write_target_close(BlockDriverState *bs) {
2736 BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
2737 bdrv_delete(s->qcow);
2738 g_free(s->qcow_filename);
2741 static BlockDriver vvfat_write_target = {
2742 .format_name = "vvfat_write_target",
2743 .bdrv_write = write_target_commit,
2744 .bdrv_close = write_target_close,
2747 static int enable_write_target(BDRVVVFATState *s)
2749 BlockDriver *bdrv_qcow;
2750 QEMUOptionParameter *options;
2751 int ret;
2752 int size = sector2cluster(s, s->sector_count);
2753 s->used_clusters = calloc(size, 1);
2755 array_init(&(s->commits), sizeof(commit_t));
2757 s->qcow_filename = g_malloc(1024);
2758 get_tmp_filename(s->qcow_filename, 1024);
2760 bdrv_qcow = bdrv_find_format("qcow");
2761 options = parse_option_parameters("", bdrv_qcow->create_options, NULL);
2762 set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512);
2763 set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:");
2765 if (bdrv_create(bdrv_qcow, s->qcow_filename, options) < 0)
2766 return -1;
2768 s->qcow = bdrv_new("");
2769 if (s->qcow == NULL) {
2770 return -1;
2773 ret = bdrv_open(s->qcow, s->qcow_filename,
2774 BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, bdrv_qcow);
2775 if (ret < 0) {
2776 return ret;
2779 #ifndef _WIN32
2780 unlink(s->qcow_filename);
2781 #endif
2783 s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
2784 s->bs->backing_hd->drv = &vvfat_write_target;
2785 s->bs->backing_hd->opaque = g_malloc(sizeof(void*));
2786 *(void**)s->bs->backing_hd->opaque = s;
2788 return 0;
2791 static void vvfat_close(BlockDriverState *bs)
2793 BDRVVVFATState *s = bs->opaque;
2795 vvfat_close_current_file(s);
2796 array_free(&(s->fat));
2797 array_free(&(s->directory));
2798 array_free(&(s->mapping));
2799 g_free(s->cluster_buffer);
2802 static BlockDriver bdrv_vvfat = {
2803 .format_name = "vvfat",
2804 .instance_size = sizeof(BDRVVVFATState),
2805 .bdrv_file_open = vvfat_open,
2806 .bdrv_read = vvfat_read,
2807 .bdrv_write = vvfat_write,
2808 .bdrv_close = vvfat_close,
2809 .bdrv_is_allocated = vvfat_is_allocated,
2810 .protocol_name = "fat",
2813 static void bdrv_vvfat_init(void)
2815 bdrv_register(&bdrv_vvfat);
2818 block_init(bdrv_vvfat_init);
2820 #ifdef DEBUG
2821 static void checkpoint(void) {
2822 assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
2823 check1(vvv);
2824 check2(vvv);
2825 assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
2826 #if 0
2827 if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
2828 fprintf(stderr, "Nonono!\n");
2829 mapping_t* mapping;
2830 direntry_t* direntry;
2831 assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
2832 assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
2833 if (vvv->mapping.next<47)
2834 return;
2835 assert((mapping = array_get(&(vvv->mapping), 47)));
2836 assert(mapping->dir_index < vvv->directory.next);
2837 direntry = array_get(&(vvv->directory), mapping->dir_index);
2838 assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0);
2839 #endif
2841 #endif