]> git.proxmox.com Git - qemu.git/blob - block-vvfat.c
moved misplaced declaration
[qemu.git] / block-vvfat.c
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:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
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.
24 */
25 #include <sys/stat.h>
26 #include <dirent.h>
27 #include <assert.h>
28 #include "vl.h"
29 #include "block_int.h"
30
31 #ifndef S_IWGRP
32 #define S_IWGRP 0
33 #endif
34 #ifndef S_IWOTH
35 #define S_IWOTH 0
36 #endif
37
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 */
45
46 /* #define DEBUG */
47
48 #ifdef DEBUG
49
50 #define DLOG(a) a
51
52 #undef stderr
53 #define stderr STDERR
54 FILE* stderr = NULL;
55
56 static void checkpoint();
57
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);
62 }
63 #undef assert
64 #define assert(a) if (!(a)) nonono(__FILE__, __LINE__, #a)
65 #endif
66
67 #else
68
69 #define DLOG(a)
70
71 #endif
72
73 /* dynamic array functions */
74 typedef struct array_t {
75 char* pointer;
76 unsigned int size,next,item_size;
77 } array_t;
78
79 static inline void array_init(array_t* array,unsigned int item_size)
80 {
81 array->pointer=0;
82 array->size=0;
83 array->next=0;
84 array->item_size=item_size;
85 }
86
87 static inline void array_free(array_t* array)
88 {
89 if(array->pointer)
90 free(array->pointer);
91 array->size=array->next=0;
92 }
93
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;
99 }
100
101 static inline int array_ensure_allocated(array_t* array, int index)
102 {
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;
110 }
111
112 return 0;
113 }
114
115 static inline void* array_get_next(array_t* array) {
116 unsigned int next = array->next;
117 void* result;
118
119 if (array_ensure_allocated(array, next) < 0)
120 return NULL;
121
122 array->next = next + 1;
123 result = array_get(array, next);
124
125 return result;
126 }
127
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;
135 }
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;
141 }
142
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)
146 {
147 char* buf;
148 char* from;
149 char* to;
150 int is;
151
152 if(!array ||
153 index_to<0 || index_to>=array->next ||
154 index_from<0 || index_from>=array->next)
155 return -1;
156
157 if(index_to==index_from)
158 return 0;
159
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);
165
166 if(index_to<index_from)
167 memmove(to+is*count,to,from-to);
168 else
169 memmove(from,from+is*count,to-from);
170
171 memcpy(to,buf,is*count);
172
173 free(buf);
174
175 return 0;
176 }
177
178 inline int array_remove_slice(array_t* array,int index, int count)
179 {
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;
187 }
188
189 int array_remove(array_t* array,int index)
190 {
191 return array_remove_slice(array, index, 1);
192 }
193
194 /* return the index for a given member */
195 int array_index(array_t* array, void* pointer)
196 {
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;
202 }
203
204 /* These structures are used to fake a disk and the VFAT filesystem.
205 * For this reason we need to use __attribute__((packed)). */
206
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;
244
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;
257
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;
263
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;
278
279 /* this structure are used to transparently access the files */
280
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
293 */
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;
304
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;
310
311 #ifdef DEBUG
312 static void print_direntry(const struct direntry_t*);
313 static void print_mapping(const struct mapping_t* mapping);
314 #endif
315
316 /* here begins the real VVFAT driver */
317
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];
322
323 int fat_type; /* 16 or 32 */
324 array_t fat,directory,mapping;
325
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;
335
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;
341
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;
352
353
354 static int vvfat_probe(const uint8_t *buf, int buf_size, const char *filename)
355 {
356 if (strstart(filename, "fat:", NULL))
357 return 100;
358 return 0;
359 }
360
361 static void init_mbr(BDRVVVFATState* s)
362 {
363 /* TODO: if the files mbr.img and bootsect.img exist, use them */
364 mbr_t* real_mbr=(mbr_t*)s->first_sectors;
365 partition_t* partition=&(real_mbr->partition[0]);
366
367 memset(s->first_sectors,0,512);
368
369 partition->attributes=0x80; /* bootable */
370 partition->start_head=1;
371 partition->start_sector=1;
372 partition->start_cylinder=0;
373 /* FAT12/FAT16/FAT32 */
374 partition->fs_type=(s->fat_type==12?0x1:s->fat_type==16?0x6:0xb);
375 partition->end_head=s->bs->heads-1;
376 partition->end_sector=0xff; /* end sector & upper 2 bits of cylinder */;
377 partition->end_cylinder=0xff; /* lower 8 bits of end cylinder */;
378 partition->start_sector_long=cpu_to_le32(s->bs->secs);
379 partition->end_sector_long=cpu_to_le32(s->sector_count);
380
381 real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
382 }
383
384 /* direntry functions */
385
386 /* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
387 static inline int short2long_name(unsigned char* dest,const char* src)
388 {
389 int i;
390 for(i=0;i<129 && src[i];i++) {
391 dest[2*i]=src[i];
392 dest[2*i+1]=0;
393 }
394 dest[2*i]=dest[2*i+1]=0;
395 for(i=2*i+2;(i%26);i++)
396 dest[i]=0xff;
397 return i;
398 }
399
400 static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
401 {
402 char buffer[258];
403 int length=short2long_name(buffer,filename),
404 number_of_entries=(length+25)/26,i;
405 direntry_t* entry;
406
407 for(i=0;i<number_of_entries;i++) {
408 entry=array_get_next(&(s->directory));
409 entry->attributes=0xf;
410 entry->reserved[0]=0;
411 entry->begin=0;
412 entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
413 }
414 for(i=0;i<length;i++) {
415 int offset=(i%26);
416 if(offset<10) offset=1+offset;
417 else if(offset<22) offset=14+offset-10;
418 else offset=28+offset-22;
419 entry=array_get(&(s->directory),s->directory.next-1-(i/26));
420 entry->name[offset]=buffer[i];
421 }
422 return array_get(&(s->directory),s->directory.next-number_of_entries);
423 }
424
425 static char is_free(const direntry_t* direntry)
426 {
427 /* return direntry->name[0]==0 ; */
428 return direntry->attributes == 0 || direntry->name[0]==0xe5;
429 }
430
431 static char is_volume_label(const direntry_t* direntry)
432 {
433 return direntry->attributes == 0x28;
434 }
435
436 static char is_long_name(const direntry_t* direntry)
437 {
438 return direntry->attributes == 0xf;
439 }
440
441 static char is_short_name(const direntry_t* direntry)
442 {
443 return !is_volume_label(direntry) && !is_long_name(direntry)
444 && !is_free(direntry);
445 }
446
447 static char is_directory(const direntry_t* direntry)
448 {
449 return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
450 }
451
452 static inline char is_dot(const direntry_t* direntry)
453 {
454 return is_short_name(direntry) && direntry->name[0] == '.';
455 }
456
457 static char is_file(const direntry_t* direntry)
458 {
459 return is_short_name(direntry) && !is_directory(direntry);
460 }
461
462 static inline uint32_t begin_of_direntry(const direntry_t* direntry)
463 {
464 return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
465 }
466
467 static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
468 {
469 return le32_to_cpu(direntry->size);
470 }
471
472 static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
473 {
474 direntry->begin = cpu_to_le16(begin & 0xffff);
475 direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
476 }
477
478 /* fat functions */
479
480 static inline uint8_t fat_chksum(const direntry_t* entry)
481 {
482 uint8_t chksum=0;
483 int i;
484
485 for(i=0;i<11;i++)
486 chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0))
487 +(unsigned char)entry->name[i];
488
489 return chksum;
490 }
491
492 /* if return_time==0, this returns the fat_date, else the fat_time */
493 static uint16_t fat_datetime(time_t time,int return_time) {
494 struct tm* t;
495 #ifdef _WIN32
496 t=localtime(&time); /* this is not thread safe */
497 #else
498 struct tm t1;
499 t=&t1;
500 localtime_r(&time,t);
501 #endif
502 if(return_time)
503 return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
504 return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
505 }
506
507 static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
508 {
509 if(s->fat_type==32) {
510 uint32_t* entry=array_get(&(s->fat),cluster);
511 *entry=cpu_to_le32(value);
512 } else if(s->fat_type==16) {
513 uint16_t* entry=array_get(&(s->fat),cluster);
514 *entry=cpu_to_le16(value&0xffff);
515 } else {
516 int offset = (cluster*3/2);
517 unsigned char* p = array_get(&(s->fat), offset);
518 switch (cluster&1) {
519 case 0:
520 p[0] = value&0xff;
521 p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
522 break;
523 case 1:
524 p[0] = (p[0]&0xf) | ((value&0xf)<<4);
525 p[1] = (value>>4);
526 break;
527 }
528 }
529 }
530
531 static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
532 {
533 if(s->fat_type==32) {
534 uint32_t* entry=array_get(&(s->fat),cluster);
535 return le32_to_cpu(*entry);
536 } else if(s->fat_type==16) {
537 uint16_t* entry=array_get(&(s->fat),cluster);
538 return le16_to_cpu(*entry);
539 } else {
540 const uint8_t* x=s->fat.pointer+cluster*3/2;
541 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
542 }
543 }
544
545 static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
546 {
547 if(fat_entry>s->max_fat_value-8)
548 return -1;
549 return 0;
550 }
551
552 static inline void init_fat(BDRVVVFATState* s)
553 {
554 if (s->fat_type == 12) {
555 array_init(&(s->fat),1);
556 array_ensure_allocated(&(s->fat),
557 s->sectors_per_fat * 0x200 * 3 / 2 - 1);
558 } else {
559 array_init(&(s->fat),(s->fat_type==32?4:2));
560 array_ensure_allocated(&(s->fat),
561 s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
562 }
563 memset(s->fat.pointer,0,s->fat.size);
564
565 switch(s->fat_type) {
566 case 12: s->max_fat_value=0xfff; break;
567 case 16: s->max_fat_value=0xffff; break;
568 case 32: s->max_fat_value=0x0fffffff; break;
569 default: s->max_fat_value=0; /* error... */
570 }
571
572 }
573
574 /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
575 /* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
576 static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
577 unsigned int directory_start, const char* filename, int is_dot)
578 {
579 int i,j,long_index=s->directory.next;
580 direntry_t* entry=0;
581 direntry_t* entry_long=0;
582
583 if(is_dot) {
584 entry=array_get_next(&(s->directory));
585 memset(entry->name,0x20,11);
586 memcpy(entry->name,filename,strlen(filename));
587 return entry;
588 }
589
590 entry_long=create_long_filename(s,filename);
591
592 i = strlen(filename);
593 for(j = i - 1; j>0 && filename[j]!='.';j--);
594 if (j > 0)
595 i = (j > 8 ? 8 : j);
596 else if (i > 8)
597 i = 8;
598
599 entry=array_get_next(&(s->directory));
600 memset(entry->name,0x20,11);
601 strncpy(entry->name,filename,i);
602
603 if(j > 0)
604 for (i = 0; i < 3 && filename[j+1+i]; i++)
605 entry->extension[i] = filename[j+1+i];
606
607 /* upcase & remove unwanted characters */
608 for(i=10;i>=0;i--) {
609 if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
610 if(entry->name[i]<=' ' || entry->name[i]>0x7f
611 || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
612 entry->name[i]='_';
613 else if(entry->name[i]>='a' && entry->name[i]<='z')
614 entry->name[i]+='A'-'a';
615 }
616
617 /* mangle duplicates */
618 while(1) {
619 direntry_t* entry1=array_get(&(s->directory),directory_start);
620 int j;
621
622 for(;entry1<entry;entry1++)
623 if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
624 break; /* found dupe */
625 if(entry1==entry) /* no dupe found */
626 break;
627
628 /* use all 8 characters of name */
629 if(entry->name[7]==' ') {
630 int j;
631 for(j=6;j>0 && entry->name[j]==' ';j--)
632 entry->name[j]='~';
633 }
634
635 /* increment number */
636 for(j=7;j>0 && entry->name[j]=='9';j--)
637 entry->name[j]='0';
638 if(j>0) {
639 if(entry->name[j]<'0' || entry->name[j]>'9')
640 entry->name[j]='0';
641 else
642 entry->name[j]++;
643 }
644 }
645
646 /* calculate checksum; propagate to long name */
647 if(entry_long) {
648 uint8_t chksum=fat_chksum(entry);
649
650 /* calculate anew, because realloc could have taken place */
651 entry_long=array_get(&(s->directory),long_index);
652 while(entry_long<entry && is_long_name(entry_long)) {
653 entry_long->reserved[1]=chksum;
654 entry_long++;
655 }
656 }
657
658 return entry;
659 }
660
661 /*
662 * Read a directory. (the index of the corresponding mapping must be passed).
663 */
664 static int read_directory(BDRVVVFATState* s, int mapping_index)
665 {
666 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
667 direntry_t* direntry;
668 const char* dirname = mapping->path;
669 int first_cluster = mapping->begin;
670 int parent_index = mapping->info.dir.parent_mapping_index;
671 mapping_t* parent_mapping = (mapping_t*)
672 (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : 0);
673 int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
674
675 DIR* dir=opendir(dirname);
676 struct dirent* entry;
677 int i;
678
679 assert(mapping->mode & MODE_DIRECTORY);
680
681 if(!dir) {
682 mapping->end = mapping->begin;
683 return -1;
684 }
685
686 i = mapping->info.dir.first_dir_index =
687 first_cluster == 0 ? 0 : s->directory.next;
688
689 /* actually read the directory, and allocate the mappings */
690 while((entry=readdir(dir))) {
691 unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
692 char* buffer;
693 direntry_t* direntry;
694 struct stat st;
695 int is_dot=!strcmp(entry->d_name,".");
696 int is_dotdot=!strcmp(entry->d_name,"..");
697
698 if(first_cluster == 0 && (is_dotdot || is_dot))
699 continue;
700
701 buffer=(char*)malloc(length);
702 assert(buffer);
703 snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
704
705 if(stat(buffer,&st)<0) {
706 free(buffer);
707 continue;
708 }
709
710 /* create directory entry for this file */
711 direntry=create_short_and_long_name(s, i, entry->d_name,
712 is_dot || is_dotdot);
713 direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
714 direntry->reserved[0]=direntry->reserved[1]=0;
715 direntry->ctime=fat_datetime(st.st_ctime,1);
716 direntry->cdate=fat_datetime(st.st_ctime,0);
717 direntry->adate=fat_datetime(st.st_atime,0);
718 direntry->begin_hi=0;
719 direntry->mtime=fat_datetime(st.st_mtime,1);
720 direntry->mdate=fat_datetime(st.st_mtime,0);
721 if(is_dotdot)
722 set_begin_of_direntry(direntry, first_cluster_of_parent);
723 else if(is_dot)
724 set_begin_of_direntry(direntry, first_cluster);
725 else
726 direntry->begin=0; /* do that later */
727 if (st.st_size > 0x7fffffff) {
728 fprintf(stderr, "File %s is larger than 2GB\n", buffer);
729 free(buffer);
730 return -2;
731 }
732 direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
733
734 /* create mapping for this file */
735 if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
736 s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
737 s->current_mapping->begin=0;
738 s->current_mapping->end=st.st_size;
739 /*
740 * we get the direntry of the most recent direntry, which
741 * contains the short name and all the relevant information.
742 */
743 s->current_mapping->dir_index=s->directory.next-1;
744 s->current_mapping->first_mapping_index = -1;
745 if (S_ISDIR(st.st_mode)) {
746 s->current_mapping->mode = MODE_DIRECTORY;
747 s->current_mapping->info.dir.parent_mapping_index =
748 mapping_index;
749 } else {
750 s->current_mapping->mode = MODE_UNDEFINED;
751 s->current_mapping->info.file.offset = 0;
752 }
753 s->current_mapping->path=buffer;
754 s->current_mapping->read_only =
755 (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
756 }
757 }
758 closedir(dir);
759
760 /* fill with zeroes up to the end of the cluster */
761 while(s->directory.next%(0x10*s->sectors_per_cluster)) {
762 direntry_t* direntry=array_get_next(&(s->directory));
763 memset(direntry,0,sizeof(direntry_t));
764 }
765
766 /* TODO: if there are more entries, bootsector has to be adjusted! */
767 #define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
768 if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
769 /* root directory */
770 int cur = s->directory.next;
771 array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
772 memset(array_get(&(s->directory), cur), 0,
773 (ROOT_ENTRIES - cur) * sizeof(direntry_t));
774 }
775
776 /* reget the mapping, since s->mapping was possibly realloc()ed */
777 mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
778 first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
779 * 0x20 / s->cluster_size;
780 mapping->end = first_cluster;
781
782 direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
783 set_begin_of_direntry(direntry, mapping->begin);
784
785 return 0;
786 }
787
788 static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
789 {
790 return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
791 }
792
793 static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
794 {
795 return s->faked_sectors + s->sectors_per_cluster * cluster_num;
796 }
797
798 static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
799 {
800 return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
801 }
802
803 #ifdef DBG
804 static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
805 {
806 if(mapping->mode==MODE_UNDEFINED)
807 return 0;
808 return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
809 }
810 #endif
811
812 static int init_directories(BDRVVVFATState* s,
813 const char* dirname)
814 {
815 bootsector_t* bootsector;
816 mapping_t* mapping;
817 unsigned int i;
818 unsigned int cluster;
819
820 memset(&(s->first_sectors[0]),0,0x40*0x200);
821
822 s->cluster_size=s->sectors_per_cluster*0x200;
823 s->cluster_buffer=malloc(s->cluster_size);
824 assert(s->cluster_buffer);
825
826 /*
827 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
828 * where sc is sector_count,
829 * spf is sectors_per_fat,
830 * spc is sectors_per_clusters, and
831 * fat_type = 12, 16 or 32.
832 */
833 i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
834 s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
835
836 array_init(&(s->mapping),sizeof(mapping_t));
837 array_init(&(s->directory),sizeof(direntry_t));
838
839 /* add volume label */
840 {
841 direntry_t* entry=array_get_next(&(s->directory));
842 entry->attributes=0x28; /* archive | volume label */
843 snprintf(entry->name,11,"QEMU VVFAT");
844 }
845
846 /* Now build FAT, and write back information into directory */
847 init_fat(s);
848
849 s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
850 s->cluster_count=sector2cluster(s, s->sector_count);
851
852 mapping = array_get_next(&(s->mapping));
853 mapping->begin = 0;
854 mapping->dir_index = 0;
855 mapping->info.dir.parent_mapping_index = -1;
856 mapping->first_mapping_index = -1;
857 mapping->path = strdup(dirname);
858 i = strlen(mapping->path);
859 if (i > 0 && mapping->path[i - 1] == '/')
860 mapping->path[i - 1] = '\0';
861 mapping->mode = MODE_DIRECTORY;
862 mapping->read_only = 0;
863 s->path = mapping->path;
864
865 for (i = 0, cluster = 0; i < s->mapping.next; i++) {
866 int j;
867 /* MS-DOS expects the FAT to be 0 for the root directory
868 * (except for the media byte). */
869 /* LATER TODO: still true for FAT32? */
870 int fix_fat = (i != 0);
871 mapping = array_get(&(s->mapping), i);
872
873 if (mapping->mode & MODE_DIRECTORY) {
874 mapping->begin = cluster;
875 if(read_directory(s, i)) {
876 fprintf(stderr, "Could not read directory %s\n",
877 mapping->path);
878 return -1;
879 }
880 mapping = array_get(&(s->mapping), i);
881 } else {
882 assert(mapping->mode == MODE_UNDEFINED);
883 mapping->mode=MODE_NORMAL;
884 mapping->begin = cluster;
885 if (mapping->end > 0) {
886 direntry_t* direntry = array_get(&(s->directory),
887 mapping->dir_index);
888
889 mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
890 set_begin_of_direntry(direntry, mapping->begin);
891 } else {
892 mapping->end = cluster + 1;
893 fix_fat = 0;
894 }
895 }
896
897 assert(mapping->begin < mapping->end);
898
899 /* fix fat for entry */
900 if (fix_fat) {
901 for(j = mapping->begin; j < mapping->end - 1; j++)
902 fat_set(s, j, j+1);
903 fat_set(s, mapping->end - 1, s->max_fat_value);
904 }
905
906 /* next free cluster */
907 cluster = mapping->end;
908
909 if(cluster > s->cluster_count) {
910 fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type);
911 return -1;
912 }
913 }
914
915 mapping = array_get(&(s->mapping), 0);
916 s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
917 s->last_cluster_of_root_directory = mapping->end;
918
919 /* the FAT signature */
920 fat_set(s,0,s->max_fat_value);
921 fat_set(s,1,s->max_fat_value);
922
923 s->current_mapping = NULL;
924
925 bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
926 bootsector->jump[0]=0xeb;
927 bootsector->jump[1]=0x3e;
928 bootsector->jump[2]=0x90;
929 memcpy(bootsector->name,"QEMU ",8);
930 bootsector->sector_size=cpu_to_le16(0x200);
931 bootsector->sectors_per_cluster=s->sectors_per_cluster;
932 bootsector->reserved_sectors=cpu_to_le16(1);
933 bootsector->number_of_fats=0x2; /* number of FATs */
934 bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
935 bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
936 bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
937 s->fat.pointer[0] = bootsector->media_type;
938 bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
939 bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
940 bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
941 bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
942 bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
943
944 /* LATER TODO: if FAT32, this is wrong */
945 bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
946 bootsector->u.fat16.current_head=0;
947 bootsector->u.fat16.signature=0x29;
948 bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
949
950 memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
951 memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12 ":s->fat_type==16?"FAT16 ":"FAT32 "),8);
952 bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
953
954 return 0;
955 }
956
957 static BDRVVVFATState *vvv = NULL;
958
959 static int enable_write_target(BDRVVVFATState *s);
960 static int is_consistent(BDRVVVFATState *s);
961
962 static int vvfat_open(BlockDriverState *bs, const char* dirname)
963 {
964 BDRVVVFATState *s = bs->opaque;
965 int floppy = 0;
966 int i;
967
968 vvv = s;
969
970 DLOG(if (stderr == NULL) {
971 stderr = fopen("vvfat.log", "a");
972 setbuf(stderr, NULL);
973 })
974
975 s->bs = bs;
976
977 s->fat_type=16;
978 /* LATER TODO: if FAT32, adjust */
979 s->sector_count=0xec04f;
980 s->sectors_per_cluster=0x10;
981 /* LATER TODO: this could be wrong for FAT32 */
982 bs->cyls=1023; bs->heads=15; bs->secs=63;
983
984 s->current_cluster=0xffffffff;
985
986 s->first_sectors_number=0x40;
987 /* read only is the default for safety */
988 bs->read_only = 1;
989 s->qcow = s->write_target = NULL;
990 s->qcow_filename = NULL;
991 s->fat2 = NULL;
992 s->downcase_short_names = 1;
993
994 if (!strstart(dirname, "fat:", NULL))
995 return -1;
996
997 if (strstr(dirname, ":rw:")) {
998 if (enable_write_target(s))
999 return -1;
1000 bs->read_only = 0;
1001 }
1002
1003 if (strstr(dirname, ":floppy:")) {
1004 floppy = 1;
1005 s->fat_type = 12;
1006 s->first_sectors_number = 1;
1007 s->sectors_per_cluster=2;
1008 bs->cyls = 80; bs->heads = 2; bs->secs = 36;
1009 }
1010
1011 if (strstr(dirname, ":32:")) {
1012 fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1013 s->fat_type = 32;
1014 } else if (strstr(dirname, ":16:")) {
1015 s->fat_type = 16;
1016 } else if (strstr(dirname, ":12:")) {
1017 s->fat_type = 12;
1018 s->sector_count=2880;
1019 }
1020
1021 i = strrchr(dirname, ':') - dirname;
1022 assert(i >= 3);
1023 if (dirname[i-2] == ':' && isalpha(dirname[i-1]))
1024 /* workaround for DOS drive names */
1025 dirname += i-1;
1026 else
1027 dirname += i+1;
1028
1029 bs->total_sectors=bs->cyls*bs->heads*bs->secs;
1030 if (s->sector_count > bs->total_sectors)
1031 s->sector_count = bs->total_sectors;
1032 if(init_directories(s, dirname))
1033 return -1;
1034
1035 if(s->first_sectors_number==0x40)
1036 init_mbr(s);
1037
1038 /* for some reason or other, MS-DOS does not like to know about CHS... */
1039 if (floppy)
1040 bs->heads = bs->cyls = bs->secs = 0;
1041
1042 // assert(is_consistent(s));
1043
1044 return 0;
1045 }
1046
1047 static inline void vvfat_close_current_file(BDRVVVFATState *s)
1048 {
1049 if(s->current_mapping) {
1050 s->current_mapping = NULL;
1051 if (s->current_fd) {
1052 close(s->current_fd);
1053 s->current_fd = 0;
1054 }
1055 }
1056 s->current_cluster = -1;
1057 }
1058
1059 /* mappings between index1 and index2-1 are supposed to be ordered
1060 * return value is the index of the last mapping for which end>cluster_num
1061 */
1062 static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1063 {
1064 int index3=index1+1;
1065 while(1) {
1066 mapping_t* mapping;
1067 index3=(index1+index2)/2;
1068 mapping=array_get(&(s->mapping),index3);
1069 assert(mapping->begin < mapping->end);
1070 if(mapping->begin>=cluster_num) {
1071 assert(index2!=index3 || index2==0);
1072 if(index2==index3)
1073 return index1;
1074 index2=index3;
1075 } else {
1076 if(index1==index3)
1077 return mapping->end<=cluster_num ? index2 : index1;
1078 index1=index3;
1079 }
1080 assert(index1<=index2);
1081 DLOG(mapping=array_get(&(s->mapping),index1);
1082 assert(mapping->begin<=cluster_num);
1083 assert(index2 >= s->mapping.next ||
1084 ((mapping = array_get(&(s->mapping),index2)) &&
1085 mapping->end>cluster_num)));
1086 }
1087 }
1088
1089 static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
1090 {
1091 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
1092 mapping_t* mapping;
1093 if(index>=s->mapping.next)
1094 return 0;
1095 mapping=array_get(&(s->mapping),index);
1096 if(mapping->begin>cluster_num)
1097 return 0;
1098 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
1099 return mapping;
1100 }
1101
1102 /*
1103 * This function simply compares path == mapping->path. Since the mappings
1104 * are sorted by cluster, this is expensive: O(n).
1105 */
1106 static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
1107 const char* path)
1108 {
1109 int i;
1110
1111 for (i = 0; i < s->mapping.next; i++) {
1112 mapping_t* mapping = array_get(&(s->mapping), i);
1113 if (mapping->first_mapping_index < 0 &&
1114 !strcmp(path, mapping->path))
1115 return mapping;
1116 }
1117
1118 return NULL;
1119 }
1120
1121 static int open_file(BDRVVVFATState* s,mapping_t* mapping)
1122 {
1123 if(!mapping)
1124 return -1;
1125 if(!s->current_mapping ||
1126 strcmp(s->current_mapping->path,mapping->path)) {
1127 /* open file */
1128 int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
1129 if(fd<0)
1130 return -1;
1131 vvfat_close_current_file(s);
1132 s->current_fd = fd;
1133 s->current_mapping = mapping;
1134 }
1135 return 0;
1136 }
1137
1138 static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1139 {
1140 if(s->current_cluster != cluster_num) {
1141 int result=0;
1142 off_t offset;
1143 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
1144 if(!s->current_mapping
1145 || s->current_mapping->begin>cluster_num
1146 || s->current_mapping->end<=cluster_num) {
1147 /* binary search of mappings for file */
1148 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
1149
1150 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1151
1152 if (mapping && mapping->mode & MODE_DIRECTORY) {
1153 vvfat_close_current_file(s);
1154 s->current_mapping = mapping;
1155 read_cluster_directory:
1156 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
1157 s->cluster = s->directory.pointer+offset
1158 + 0x20*s->current_mapping->info.dir.first_dir_index;
1159 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1160 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1161 s->current_cluster = cluster_num;
1162 return 0;
1163 }
1164
1165 if(open_file(s,mapping))
1166 return -2;
1167 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1168 goto read_cluster_directory;
1169
1170 assert(s->current_fd);
1171
1172 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
1173 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1174 return -3;
1175 s->cluster=s->cluster_buffer;
1176 result=read(s->current_fd,s->cluster,s->cluster_size);
1177 if(result<0) {
1178 s->current_cluster = -1;
1179 return -1;
1180 }
1181 s->current_cluster = cluster_num;
1182 }
1183 return 0;
1184 }
1185
1186 #ifdef DEBUG
1187 static void hexdump(const void* address, uint32_t len)
1188 {
1189 const unsigned char* p = address;
1190 int i, j;
1191
1192 for (i = 0; i < len; i += 16) {
1193 for (j = 0; j < 16 && i + j < len; j++)
1194 fprintf(stderr, "%02x ", p[i + j]);
1195 for (; j < 16; j++)
1196 fprintf(stderr, " ");
1197 fprintf(stderr, " ");
1198 for (j = 0; j < 16 && i + j < len; j++)
1199 fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
1200 fprintf(stderr, "\n");
1201 }
1202 }
1203
1204 static void print_direntry(const direntry_t* direntry)
1205 {
1206 int j = 0;
1207 char buffer[1024];
1208
1209 fprintf(stderr, "direntry 0x%x: ", (int)direntry);
1210 if(!direntry)
1211 return;
1212 if(is_long_name(direntry)) {
1213 unsigned char* c=(unsigned char*)direntry;
1214 int i;
1215 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
1216 #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = '°'; j++;}
1217 ADD_CHAR(c[i]);
1218 for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
1219 ADD_CHAR(c[i]);
1220 for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
1221 ADD_CHAR(c[i]);
1222 buffer[j] = 0;
1223 fprintf(stderr, "%s\n", buffer);
1224 } else {
1225 int i;
1226 for(i=0;i<11;i++)
1227 ADD_CHAR(direntry->name[i]);
1228 buffer[j] = 0;
1229 fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1230 buffer,
1231 direntry->attributes,
1232 begin_of_direntry(direntry),le32_to_cpu(direntry->size));
1233 }
1234 }
1235
1236 static void print_mapping(const mapping_t* mapping)
1237 {
1238 fprintf(stderr, "mapping (0x%x): begin, end = %d, %d, dir_index = %d, first_mapping_index = %d, name = %s, mode = 0x%x, " , (int)mapping, mapping->begin, mapping->end, mapping->dir_index, mapping->first_mapping_index, mapping->path, mapping->mode);
1239 if (mapping->mode & MODE_DIRECTORY)
1240 fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1241 else
1242 fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
1243 }
1244 #endif
1245
1246 static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
1247 uint8_t *buf, int nb_sectors)
1248 {
1249 BDRVVVFATState *s = bs->opaque;
1250 int i;
1251
1252 for(i=0;i<nb_sectors;i++,sector_num++) {
1253 if (sector_num >= s->sector_count)
1254 return -1;
1255 if (s->qcow) {
1256 int n;
1257 if (s->qcow->drv->bdrv_is_allocated(s->qcow,
1258 sector_num, nb_sectors-i, &n)) {
1259 DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
1260 if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
1261 return -1;
1262 i += n - 1;
1263 sector_num += n - 1;
1264 continue;
1265 }
1266 DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
1267 }
1268 if(sector_num<s->faked_sectors) {
1269 if(sector_num<s->first_sectors_number)
1270 memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
1271 else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
1272 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
1273 else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
1274 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
1275 } else {
1276 uint32_t sector=sector_num-s->faked_sectors,
1277 sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1278 cluster_num=sector/s->sectors_per_cluster;
1279 if(read_cluster(s, cluster_num) != 0) {
1280 /* LATER TODO: strict: return -1; */
1281 memset(buf+i*0x200,0,0x200);
1282 continue;
1283 }
1284 memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
1285 }
1286 }
1287 return 0;
1288 }
1289
1290 /* LATER TODO: statify all functions */
1291
1292 /*
1293 * Idea of the write support (use snapshot):
1294 *
1295 * 1. check if all data is consistent, recording renames, modifications,
1296 * new files and directories (in s->commits).
1297 *
1298 * 2. if the data is not consistent, stop committing
1299 *
1300 * 3. handle renames, and create new files and directories (do not yet
1301 * write their contents)
1302 *
1303 * 4. walk the directories, fixing the mapping and direntries, and marking
1304 * the handled mappings as not deleted
1305 *
1306 * 5. commit the contents of the files
1307 *
1308 * 6. handle deleted files and directories
1309 *
1310 */
1311
1312 typedef struct commit_t {
1313 char* path;
1314 union {
1315 struct { uint32_t cluster; } rename;
1316 struct { int dir_index; uint32_t modified_offset; } writeout;
1317 struct { uint32_t first_cluster; } new_file;
1318 struct { uint32_t cluster; } mkdir;
1319 } param;
1320 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1321 enum {
1322 ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1323 } action;
1324 } commit_t;
1325
1326 static void clear_commits(BDRVVVFATState* s)
1327 {
1328 int i;
1329 DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1330 for (i = 0; i < s->commits.next; i++) {
1331 commit_t* commit = array_get(&(s->commits), i);
1332 assert(commit->path || commit->action == ACTION_WRITEOUT);
1333 if (commit->action != ACTION_WRITEOUT) {
1334 assert(commit->path);
1335 free(commit->path);
1336 } else
1337 assert(commit->path == NULL);
1338 }
1339 s->commits.next = 0;
1340 }
1341
1342 static void schedule_rename(BDRVVVFATState* s,
1343 uint32_t cluster, char* new_path)
1344 {
1345 commit_t* commit = array_get_next(&(s->commits));
1346 commit->path = new_path;
1347 commit->param.rename.cluster = cluster;
1348 commit->action = ACTION_RENAME;
1349 }
1350
1351 static void schedule_writeout(BDRVVVFATState* s,
1352 int dir_index, uint32_t modified_offset)
1353 {
1354 commit_t* commit = array_get_next(&(s->commits));
1355 commit->path = NULL;
1356 commit->param.writeout.dir_index = dir_index;
1357 commit->param.writeout.modified_offset = modified_offset;
1358 commit->action = ACTION_WRITEOUT;
1359 }
1360
1361 static void schedule_new_file(BDRVVVFATState* s,
1362 char* path, uint32_t first_cluster)
1363 {
1364 commit_t* commit = array_get_next(&(s->commits));
1365 commit->path = path;
1366 commit->param.new_file.first_cluster = first_cluster;
1367 commit->action = ACTION_NEW_FILE;
1368 }
1369
1370 static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1371 {
1372 commit_t* commit = array_get_next(&(s->commits));
1373 commit->path = path;
1374 commit->param.mkdir.cluster = cluster;
1375 commit->action = ACTION_MKDIR;
1376 }
1377
1378 typedef struct {
1379 unsigned char name[1024];
1380 int checksum, len;
1381 int sequence_number;
1382 } long_file_name;
1383
1384 static void lfn_init(long_file_name* lfn)
1385 {
1386 lfn->sequence_number = lfn->len = 0;
1387 lfn->checksum = 0x100;
1388 }
1389
1390 /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1391 static int parse_long_name(long_file_name* lfn,
1392 const direntry_t* direntry)
1393 {
1394 int i, j, offset;
1395 const unsigned char* pointer = (const unsigned char*)direntry;
1396
1397 if (!is_long_name(direntry))
1398 return 1;
1399
1400 if (pointer[0] & 0x40) {
1401 lfn->sequence_number = pointer[0] & 0x3f;
1402 lfn->checksum = pointer[13];
1403 lfn->name[0] = 0;
1404 } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
1405 return -1;
1406 else if (pointer[13] != lfn->checksum)
1407 return -2;
1408 else if (pointer[12] || pointer[26] || pointer[27])
1409 return -3;
1410
1411 offset = 13 * (lfn->sequence_number - 1);
1412 for (i = 0, j = 1; i < 13; i++, j+=2) {
1413 if (j == 11)
1414 j = 14;
1415 else if (j == 26)
1416 j = 28;
1417
1418 if (pointer[j+1] == 0)
1419 lfn->name[offset + i] = pointer[j];
1420 else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1421 return -4;
1422 else
1423 lfn->name[offset + i] = 0;
1424 }
1425
1426 if (pointer[0] & 0x40)
1427 lfn->len = offset + strlen(lfn->name + offset);
1428
1429 return 0;
1430 }
1431
1432 /* returns 0 if successful, >0 if no short_name, and <0 on error */
1433 static int parse_short_name(BDRVVVFATState* s,
1434 long_file_name* lfn, direntry_t* direntry)
1435 {
1436 int i, j;
1437
1438 if (!is_short_name(direntry))
1439 return 1;
1440
1441 for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1442 for (i = 0; i <= j; i++) {
1443 if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
1444 return -1;
1445 else if (s->downcase_short_names)
1446 lfn->name[i] = tolower(direntry->name[i]);
1447 else
1448 lfn->name[i] = direntry->name[i];
1449 }
1450
1451 for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
1452 if (j >= 0) {
1453 lfn->name[i++] = '.';
1454 lfn->name[i + j + 1] = '\0';
1455 for (;j >= 0; j--) {
1456 if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
1457 return -2;
1458 else if (s->downcase_short_names)
1459 lfn->name[i + j] = tolower(direntry->extension[j]);
1460 else
1461 lfn->name[i + j] = direntry->extension[j];
1462 }
1463 } else
1464 lfn->name[i + j + 1] = '\0';
1465
1466 lfn->len = strlen(lfn->name);
1467
1468 return 0;
1469 }
1470
1471 static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1472 unsigned int cluster)
1473 {
1474 if (cluster < s->last_cluster_of_root_directory) {
1475 if (cluster + 1 == s->last_cluster_of_root_directory)
1476 return s->max_fat_value;
1477 else
1478 return cluster + 1;
1479 }
1480
1481 if (s->fat_type==32) {
1482 uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1483 return le32_to_cpu(*entry);
1484 } else if (s->fat_type==16) {
1485 uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1486 return le16_to_cpu(*entry);
1487 } else {
1488 const uint8_t* x=s->fat2+cluster*3/2;
1489 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1490 }
1491 }
1492
1493 static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1494 {
1495 int was_modified = 0;
1496 int i, dummy;
1497
1498 if (s->qcow == NULL)
1499 return 0;
1500
1501 for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
1502 was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
1503 cluster2sector(s, cluster_num) + i, 1, &dummy);
1504
1505 return was_modified;
1506 }
1507
1508 static const char* get_basename(const char* path)
1509 {
1510 char* basename = strrchr(path, '/');
1511 if (basename == NULL)
1512 return path;
1513 else
1514 return basename + 1; /* strip '/' */
1515 }
1516
1517 /*
1518 * The array s->used_clusters holds the states of the clusters. If it is
1519 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1520 * was modified, bit 3 is set.
1521 * If any cluster is allocated, but not part of a file or directory, this
1522 * driver refuses to commit.
1523 */
1524 typedef enum {
1525 USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
1526 } used_t;
1527
1528 /*
1529 * get_cluster_count_for_direntry() not only determines how many clusters
1530 * are occupied by direntry, but also if it was renamed or modified.
1531 *
1532 * A file is thought to be renamed *only* if there already was a file with
1533 * exactly the same first cluster, but a different name.
1534 *
1535 * Further, the files/directories handled by this function are
1536 * assumed to be *not* deleted (and *only* those).
1537 */
1538 static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
1539 direntry_t* direntry, const char* path)
1540 {
1541 /*
1542 * This is a little bit tricky:
1543 * IF the guest OS just inserts a cluster into the file chain,
1544 * and leaves the rest alone, (i.e. the original file had clusters
1545 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1546 *
1547 * - do_commit will write the cluster into the file at the given
1548 * offset, but
1549 *
1550 * - the cluster which is overwritten should be moved to a later
1551 * position in the file.
1552 *
1553 * I am not aware that any OS does something as braindead, but this
1554 * situation could happen anyway when not committing for a long time.
1555 * Just to be sure that this does not bite us, detect it, and copy the
1556 * contents of the clusters to-be-overwritten into the qcow.
1557 */
1558 int copy_it = 0;
1559 int was_modified = 0;
1560 int32_t ret = 0;
1561
1562 uint32_t cluster_num = begin_of_direntry(direntry);
1563 uint32_t offset = 0;
1564 int first_mapping_index = -1;
1565 mapping_t* mapping = NULL;
1566 const char* basename2 = NULL;
1567
1568 vvfat_close_current_file(s);
1569
1570 /* the root directory */
1571 if (cluster_num == 0)
1572 return 0;
1573
1574 /* write support */
1575 if (s->qcow) {
1576 basename2 = get_basename(path);
1577
1578 mapping = find_mapping_for_cluster(s, cluster_num);
1579
1580 if (mapping) {
1581 const char* basename;
1582
1583 assert(mapping->mode & MODE_DELETED);
1584 mapping->mode &= ~MODE_DELETED;
1585
1586 basename = get_basename(mapping->path);
1587
1588 assert(mapping->mode & MODE_NORMAL);
1589
1590 /* rename */
1591 if (strcmp(basename, basename2))
1592 schedule_rename(s, cluster_num, strdup(path));
1593 } else if (is_file(direntry))
1594 /* new file */
1595 schedule_new_file(s, strdup(path), cluster_num);
1596 else {
1597 assert(0);
1598 return 0;
1599 }
1600 }
1601
1602 while(1) {
1603 if (s->qcow) {
1604 if (!copy_it && cluster_was_modified(s, cluster_num)) {
1605 if (mapping == NULL ||
1606 mapping->begin > cluster_num ||
1607 mapping->end <= cluster_num)
1608 mapping = find_mapping_for_cluster(s, cluster_num);
1609
1610
1611 if (mapping &&
1612 (mapping->mode & MODE_DIRECTORY) == 0) {
1613
1614 /* was modified in qcow */
1615 if (offset != mapping->info.file.offset + s->cluster_size
1616 * (cluster_num - mapping->begin)) {
1617 /* offset of this cluster in file chain has changed */
1618 assert(0);
1619 copy_it = 1;
1620 } else if (offset == 0) {
1621 const char* basename = get_basename(mapping->path);
1622
1623 if (strcmp(basename, basename2))
1624 copy_it = 1;
1625 first_mapping_index = array_index(&(s->mapping), mapping);
1626 }
1627
1628 if (mapping->first_mapping_index != first_mapping_index
1629 && mapping->info.file.offset > 0) {
1630 assert(0);
1631 copy_it = 1;
1632 }
1633
1634 /* need to write out? */
1635 if (!was_modified && is_file(direntry)) {
1636 was_modified = 1;
1637 schedule_writeout(s, mapping->dir_index, offset);
1638 }
1639 }
1640 }
1641
1642 if (copy_it) {
1643 int i, dummy;
1644 /*
1645 * This is horribly inefficient, but that is okay, since
1646 * it is rarely executed, if at all.
1647 */
1648 int64_t offset = cluster2sector(s, cluster_num);
1649
1650 vvfat_close_current_file(s);
1651 for (i = 0; i < s->sectors_per_cluster; i++)
1652 if (!s->qcow->drv->bdrv_is_allocated(s->qcow,
1653 offset + i, 1, &dummy)) {
1654 if (vvfat_read(s->bs,
1655 offset, s->cluster_buffer, 1))
1656 return -1;
1657 if (s->qcow->drv->bdrv_write(s->qcow,
1658 offset, s->cluster_buffer, 1))
1659 return -2;
1660 }
1661 }
1662 }
1663
1664 ret++;
1665 if (s->used_clusters[cluster_num] & USED_ANY)
1666 return 0;
1667 s->used_clusters[cluster_num] = USED_FILE;
1668
1669 cluster_num = modified_fat_get(s, cluster_num);
1670
1671 if (fat_eof(s, cluster_num))
1672 return ret;
1673 else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
1674 return -1;
1675
1676 offset += s->cluster_size;
1677 }
1678 }
1679
1680 /*
1681 * This function looks at the modified data (qcow).
1682 * It returns 0 upon inconsistency or error, and the number of clusters
1683 * used by the directory, its subdirectories and their files.
1684 */
1685 static int check_directory_consistency(BDRVVVFATState *s,
1686 int cluster_num, const char* path)
1687 {
1688 int ret = 0;
1689 unsigned char* cluster = malloc(s->cluster_size);
1690 direntry_t* direntries = (direntry_t*)cluster;
1691 mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
1692
1693 long_file_name lfn;
1694 int path_len = strlen(path);
1695 char path2[PATH_MAX];
1696
1697 assert(path_len < PATH_MAX); /* len was tested before! */
1698 strcpy(path2, path);
1699 path2[path_len] = '/';
1700 path2[path_len + 1] = '\0';
1701
1702 if (mapping) {
1703 const char* basename = get_basename(mapping->path);
1704 const char* basename2 = get_basename(path);
1705
1706 assert(mapping->mode & MODE_DIRECTORY);
1707
1708 assert(mapping->mode & MODE_DELETED);
1709 mapping->mode &= ~MODE_DELETED;
1710
1711 if (strcmp(basename, basename2))
1712 schedule_rename(s, cluster_num, strdup(path));
1713 } else
1714 /* new directory */
1715 schedule_mkdir(s, cluster_num, strdup(path));
1716
1717 lfn_init(&lfn);
1718 do {
1719 int i;
1720 int subret = 0;
1721
1722 ret++;
1723
1724 if (s->used_clusters[cluster_num] & USED_ANY) {
1725 fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
1726 return 0;
1727 }
1728 s->used_clusters[cluster_num] = USED_DIRECTORY;
1729
1730 DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
1731 subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
1732 s->sectors_per_cluster);
1733 if (subret) {
1734 fprintf(stderr, "Error fetching direntries\n");
1735 fail:
1736 free(cluster);
1737 return 0;
1738 }
1739
1740 for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
1741 int cluster_count;
1742
1743 DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
1744 if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
1745 is_free(direntries + i))
1746 continue;
1747
1748 subret = parse_long_name(&lfn, direntries + i);
1749 if (subret < 0) {
1750 fprintf(stderr, "Error in long name\n");
1751 goto fail;
1752 }
1753 if (subret == 0 || is_free(direntries + i))
1754 continue;
1755
1756 if (fat_chksum(direntries+i) != lfn.checksum) {
1757 subret = parse_short_name(s, &lfn, direntries + i);
1758 if (subret < 0) {
1759 fprintf(stderr, "Error in short name (%d)\n", subret);
1760 goto fail;
1761 }
1762 if (subret > 0 || !strcmp(lfn.name, ".")
1763 || !strcmp(lfn.name, ".."))
1764 continue;
1765 }
1766 lfn.checksum = 0x100; /* cannot use long name twice */
1767
1768 if (path_len + 1 + lfn.len >= PATH_MAX) {
1769 fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
1770 goto fail;
1771 }
1772 strcpy(path2 + path_len + 1, lfn.name);
1773
1774 if (is_directory(direntries + i)) {
1775 if (begin_of_direntry(direntries + i) == 0) {
1776 DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
1777 goto fail;
1778 }
1779 cluster_count = check_directory_consistency(s,
1780 begin_of_direntry(direntries + i), path2);
1781 if (cluster_count == 0) {
1782 DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
1783 goto fail;
1784 }
1785 } else if (is_file(direntries + i)) {
1786 /* check file size with FAT */
1787 cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
1788 if (cluster_count !=
1789 (le32_to_cpu(direntries[i].size) + s->cluster_size
1790 - 1) / s->cluster_size) {
1791 DLOG(fprintf(stderr, "Cluster count mismatch\n"));
1792 goto fail;
1793 }
1794 } else
1795 assert(0); /* cluster_count = 0; */
1796
1797 ret += cluster_count;
1798 }
1799
1800 cluster_num = modified_fat_get(s, cluster_num);
1801 } while(!fat_eof(s, cluster_num));
1802
1803 free(cluster);
1804 return ret;
1805 }
1806
1807 /* returns 1 on success */
1808 static int is_consistent(BDRVVVFATState* s)
1809 {
1810 int i, check;
1811 int used_clusters_count = 0;
1812
1813 DLOG(checkpoint());
1814 /*
1815 * - get modified FAT
1816 * - compare the two FATs (TODO)
1817 * - get buffer for marking used clusters
1818 * - recurse direntries from root (using bs->bdrv_read to make
1819 * sure to get the new data)
1820 * - check that the FAT agrees with the size
1821 * - count the number of clusters occupied by this directory and
1822 * its files
1823 * - check that the cumulative used cluster count agrees with the
1824 * FAT
1825 * - if all is fine, return number of used clusters
1826 */
1827 if (s->fat2 == NULL) {
1828 int size = 0x200 * s->sectors_per_fat;
1829 s->fat2 = malloc(size);
1830 memcpy(s->fat2, s->fat.pointer, size);
1831 }
1832 check = vvfat_read(s->bs,
1833 s->first_sectors_number, s->fat2, s->sectors_per_fat);
1834 if (check) {
1835 fprintf(stderr, "Could not copy fat\n");
1836 return 0;
1837 }
1838 assert (s->used_clusters);
1839 for (i = 0; i < sector2cluster(s, s->sector_count); i++)
1840 s->used_clusters[i] &= ~USED_ANY;
1841
1842 clear_commits(s);
1843
1844 /* mark every mapped file/directory as deleted.
1845 * (check_directory_consistency() will unmark those still present). */
1846 if (s->qcow)
1847 for (i = 0; i < s->mapping.next; i++) {
1848 mapping_t* mapping = array_get(&(s->mapping), i);
1849 if (mapping->first_mapping_index < 0)
1850 mapping->mode |= MODE_DELETED;
1851 }
1852
1853 used_clusters_count = check_directory_consistency(s, 0, s->path);
1854 if (used_clusters_count <= 0) {
1855 DLOG(fprintf(stderr, "problem in directory\n"));
1856 return 0;
1857 }
1858
1859 check = s->last_cluster_of_root_directory;
1860 for (i = check; i < sector2cluster(s, s->sector_count); i++) {
1861 if (modified_fat_get(s, i)) {
1862 if(!s->used_clusters[i]) {
1863 DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
1864 return 0;
1865 }
1866 check++;
1867 }
1868
1869 if (s->used_clusters[i] == USED_ALLOCATED) {
1870 /* allocated, but not used... */
1871 DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
1872 return 0;
1873 }
1874 }
1875
1876 if (check != used_clusters_count)
1877 return 0;
1878
1879 return used_clusters_count;
1880 }
1881
1882 static inline void adjust_mapping_indices(BDRVVVFATState* s,
1883 int offset, int adjust)
1884 {
1885 int i;
1886
1887 for (i = 0; i < s->mapping.next; i++) {
1888 mapping_t* mapping = array_get(&(s->mapping), i);
1889
1890 #define ADJUST_MAPPING_INDEX(name) \
1891 if (mapping->name >= offset) \
1892 mapping->name += adjust
1893
1894 ADJUST_MAPPING_INDEX(first_mapping_index);
1895 if (mapping->mode & MODE_DIRECTORY)
1896 ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
1897 }
1898 }
1899
1900 /* insert or update mapping */
1901 static mapping_t* insert_mapping(BDRVVVFATState* s,
1902 uint32_t begin, uint32_t end)
1903 {
1904 /*
1905 * - find mapping where mapping->begin >= begin,
1906 * - if mapping->begin > begin: insert
1907 * - adjust all references to mappings!
1908 * - else: adjust
1909 * - replace name
1910 */
1911 int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
1912 mapping_t* mapping = NULL;
1913 mapping_t* first_mapping = array_get(&(s->mapping), 0);
1914
1915 if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
1916 && mapping->begin < begin) {
1917 mapping->end = begin;
1918 index++;
1919 mapping = array_get(&(s->mapping), index);
1920 }
1921 if (index >= s->mapping.next || mapping->begin > begin) {
1922 mapping = array_insert(&(s->mapping), index, 1);
1923 mapping->path = NULL;
1924 adjust_mapping_indices(s, index, +1);
1925 }
1926
1927 mapping->begin = begin;
1928 mapping->end = end;
1929
1930 DLOG(mapping_t* next_mapping;
1931 assert(index + 1 >= s->mapping.next ||
1932 ((next_mapping = array_get(&(s->mapping), index + 1)) &&
1933 next_mapping->begin >= end)));
1934
1935 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1936 s->current_mapping = array_get(&(s->mapping),
1937 s->current_mapping - first_mapping);
1938
1939 return mapping;
1940 }
1941
1942 static int remove_mapping(BDRVVVFATState* s, int mapping_index)
1943 {
1944 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
1945 mapping_t* first_mapping = array_get(&(s->mapping), 0);
1946
1947 /* free mapping */
1948 if (mapping->first_mapping_index < 0)
1949 free(mapping->path);
1950
1951 /* remove from s->mapping */
1952 array_remove(&(s->mapping), mapping_index);
1953
1954 /* adjust all references to mappings */
1955 adjust_mapping_indices(s, mapping_index, -1);
1956
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);
1960
1961 return 0;
1962 }
1963
1964 static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
1965 {
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;
1974 }
1975 }
1976
1977 static direntry_t* insert_direntries(BDRVVVFATState* s,
1978 int dir_index, int count)
1979 {
1980 /*
1981 * make room in s->directory,
1982 * adjust_dirindices
1983 */
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;
1989 }
1990
1991 static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
1992 {
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;
1998 }
1999
2000 /*
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)
2005 */
2006 static int commit_mappings(BDRVVVFATState* s,
2007 uint32_t first_cluster, int dir_index)
2008 {
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;
2012
2013 vvfat_close_current_file(s);
2014
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;
2021
2022 while (!fat_eof(s, cluster)) {
2023 uint32_t c, c1;
2024
2025 for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2026 c = c1, c1 = modified_fat_get(s, c1));
2027
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);
2035 }
2036 assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2037 || mapping[1].begin >= c);
2038 mapping->end = c;
2039
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);
2044
2045 if (next_mapping == NULL || next_mapping->begin > c1) {
2046 int i1 = array_index(&(s->mapping), mapping);
2047
2048 next_mapping = insert_mapping(s, c1, c1+1);
2049
2050 if (c1 < c)
2051 i1++;
2052 mapping = array_get(&(s->mapping), i1);
2053 }
2054
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;
2073
2074 mapping = next_mapping;
2075 }
2076
2077 cluster = c1;
2078 }
2079
2080 return 0;
2081 }
2082
2083 static int commit_direntries(BDRVVVFATState* s,
2084 int dir_index, int parent_mapping_index)
2085 {
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);
2089
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;
2096
2097 DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
2098
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));
2105
2106 mapping->info.dir.parent_mapping_index = parent_mapping_index;
2107
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++;
2115
2116 for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2117 c = modified_fat_get(s, c))
2118 new_cluster_count++;
2119 }
2120
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));
2130
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;
2139 }
2140
2141 ret = commit_mappings(s, first_cluster, dir_index);
2142 if (ret)
2143 return ret;
2144
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;
2155 }
2156 }
2157
2158 return 0;
2159 }
2160
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)
2165 {
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 = malloc(s->cluster_size);
2172 uint32_t i;
2173 int fd = 0;
2174
2175 assert(offset < size);
2176 assert((offset % s->cluster_size) == 0);
2177
2178 for (i = s->cluster_size; i < offset; i += s->cluster_size)
2179 c = modified_fat_get(s, c);
2180
2181 fd = open(mapping->path, O_RDWR | O_CREAT, 0666);
2182 if (fd < 0) {
2183 fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2184 strerror(errno), errno);
2185 return fd;
2186 }
2187 if (offset > 0)
2188 if (lseek(fd, offset, SEEK_SET) != offset)
2189 return -3;
2190
2191 while (offset < size) {
2192 uint32_t c1;
2193 int rest_size = (size - offset > s->cluster_size ?
2194 s->cluster_size : size - offset);
2195 int ret;
2196
2197 c1 = modified_fat_get(s, c);
2198
2199 assert((size - offset == 0 && fat_eof(s, c)) ||
2200 (size > offset && c >=2 && !fat_eof(s, c)));
2201 assert(size >= 0);
2202
2203 ret = vvfat_read(s->bs, cluster2sector(s, c),
2204 cluster, (rest_size + 0x1ff) / 0x200);
2205
2206 if (ret < 0)
2207 return ret;
2208
2209 if (write(fd, cluster, rest_size) < 0)
2210 return -2;
2211
2212 offset += rest_size;
2213 c = c1;
2214 }
2215
2216 ftruncate(fd, size);
2217 close(fd);
2218
2219 return commit_mappings(s, first_cluster, dir_index);
2220 }
2221
2222 #ifdef DEBUG
2223 /* test, if all mappings point to valid direntries */
2224 static void check1(BDRVVVFATState* s)
2225 {
2226 int i;
2227 for (i = 0; i < s->mapping.next; i++) {
2228 mapping_t* mapping = array_get(&(s->mapping), i);
2229 if (mapping->mode & MODE_DELETED) {
2230 fprintf(stderr, "deleted\n");
2231 continue;
2232 }
2233 assert(mapping->dir_index >= 0);
2234 assert(mapping->dir_index < s->directory.next);
2235 direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2236 assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2237 if (mapping->mode & MODE_DIRECTORY) {
2238 assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2239 assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2240 }
2241 }
2242 }
2243
2244 /* test, if all direntries have mappings */
2245 static void check2(BDRVVVFATState* s)
2246 {
2247 int i;
2248 int first_mapping = -1;
2249
2250 for (i = 0; i < s->directory.next; i++) {
2251 direntry_t* direntry = array_get(&(s->directory), i);
2252
2253 if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2254 mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2255 assert(mapping);
2256 assert(mapping->dir_index == i || is_dot(direntry));
2257 assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2258 }
2259
2260 if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2261 /* cluster start */
2262 int j, count = 0;
2263
2264 for (j = 0; j < s->mapping.next; j++) {
2265 mapping_t* mapping = array_get(&(s->mapping), j);
2266 if (mapping->mode & MODE_DELETED)
2267 continue;
2268 if (mapping->mode & MODE_DIRECTORY) {
2269 if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2270 assert(++count == 1);
2271 if (mapping->first_mapping_index == -1)
2272 first_mapping = array_index(&(s->mapping), mapping);
2273 else
2274 assert(first_mapping == mapping->first_mapping_index);
2275 if (mapping->info.dir.parent_mapping_index < 0)
2276 assert(j == 0);
2277 else {
2278 mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2279 assert(parent->mode & MODE_DIRECTORY);
2280 assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2281 }
2282 }
2283 }
2284 }
2285 if (count == 0)
2286 first_mapping = -1;
2287 }
2288 }
2289 }
2290 #endif
2291
2292 static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2293 {
2294 int i;
2295
2296 #ifdef DEBUG
2297 fprintf(stderr, "handle_renames\n");
2298 for (i = 0; i < s->commits.next; i++) {
2299 commit_t* commit = array_get(&(s->commits), i);
2300 fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
2301 }
2302 #endif
2303
2304 for (i = 0; i < s->commits.next;) {
2305 commit_t* commit = array_get(&(s->commits), i);
2306 if (commit->action == ACTION_RENAME) {
2307 mapping_t* mapping = find_mapping_for_cluster(s,
2308 commit->param.rename.cluster);
2309 char* old_path = mapping->path;
2310
2311 assert(commit->path);
2312 mapping->path = commit->path;
2313 if (rename(old_path, mapping->path))
2314 return -2;
2315
2316 if (mapping->mode & MODE_DIRECTORY) {
2317 int l1 = strlen(mapping->path);
2318 int l2 = strlen(old_path);
2319 int diff = l1 - l2;
2320 direntry_t* direntry = array_get(&(s->directory),
2321 mapping->info.dir.first_dir_index);
2322 uint32_t c = mapping->begin;
2323 int i = 0;
2324
2325 /* recurse */
2326 while (!fat_eof(s, c)) {
2327 do {
2328 direntry_t* d = direntry + i;
2329
2330 if (is_file(d) || (is_directory(d) && !is_dot(d))) {
2331 mapping_t* m = find_mapping_for_cluster(s,
2332 begin_of_direntry(d));
2333 int l = strlen(m->path);
2334 char* new_path = malloc(l + diff + 1);
2335
2336 assert(!strncmp(m->path, mapping->path, l2));
2337
2338 strcpy(new_path, mapping->path);
2339 strcpy(new_path + l1, m->path + l2);
2340
2341 schedule_rename(s, m->begin, new_path);
2342 }
2343 i++;
2344 } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2345 c = fat_get(s, c);
2346 }
2347 }
2348
2349 free(old_path);
2350 array_remove(&(s->commits), i);
2351 continue;
2352 } else if (commit->action == ACTION_MKDIR) {
2353 mapping_t* mapping;
2354 int j, parent_path_len;
2355
2356 #ifdef __MINGW32__
2357 if (mkdir(commit->path))
2358 return -5;
2359 #else
2360 if (mkdir(commit->path, 0755))
2361 return -5;
2362 #endif
2363
2364 mapping = insert_mapping(s, commit->param.mkdir.cluster,
2365 commit->param.mkdir.cluster + 1);
2366 if (mapping == NULL)
2367 return -6;
2368
2369 mapping->mode = MODE_DIRECTORY;
2370 mapping->read_only = 0;
2371 mapping->path = commit->path;
2372 j = s->directory.next;
2373 assert(j);
2374 insert_direntries(s, s->directory.next,
2375 0x10 * s->sectors_per_cluster);
2376 mapping->info.dir.first_dir_index = j;
2377
2378 parent_path_len = strlen(commit->path)
2379 - strlen(get_basename(commit->path)) - 1;
2380 for (j = 0; j < s->mapping.next; j++) {
2381 mapping_t* m = array_get(&(s->mapping), j);
2382 if (m->first_mapping_index < 0 && m != mapping &&
2383 !strncmp(m->path, mapping->path, parent_path_len) &&
2384 strlen(m->path) == parent_path_len)
2385 break;
2386 }
2387 assert(j < s->mapping.next);
2388 mapping->info.dir.parent_mapping_index = j;
2389
2390 array_remove(&(s->commits), i);
2391 continue;
2392 }
2393
2394 i++;
2395 }
2396 return 0;
2397 }
2398
2399 /*
2400 * TODO: make sure that the short name is not matching *another* file
2401 */
2402 static int handle_commits(BDRVVVFATState* s)
2403 {
2404 int i, fail = 0;
2405
2406 vvfat_close_current_file(s);
2407
2408 for (i = 0; !fail && i < s->commits.next; i++) {
2409 commit_t* commit = array_get(&(s->commits), i);
2410 switch(commit->action) {
2411 case ACTION_RENAME: case ACTION_MKDIR:
2412 assert(0);
2413 fail = -2;
2414 break;
2415 case ACTION_WRITEOUT: {
2416 direntry_t* entry = array_get(&(s->directory),
2417 commit->param.writeout.dir_index);
2418 uint32_t begin = begin_of_direntry(entry);
2419 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2420
2421 assert(mapping);
2422 assert(mapping->begin == begin);
2423 assert(commit->path == NULL);
2424
2425 if (commit_one_file(s, commit->param.writeout.dir_index,
2426 commit->param.writeout.modified_offset))
2427 fail = -3;
2428
2429 break;
2430 }
2431 case ACTION_NEW_FILE: {
2432 int begin = commit->param.new_file.first_cluster;
2433 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2434 direntry_t* entry;
2435 int i;
2436
2437 /* find direntry */
2438 for (i = 0; i < s->directory.next; i++) {
2439 entry = array_get(&(s->directory), i);
2440 if (is_file(entry) && begin_of_direntry(entry) == begin)
2441 break;
2442 }
2443
2444 if (i >= s->directory.next) {
2445 fail = -6;
2446 continue;
2447 }
2448
2449 /* make sure there exists an initial mapping */
2450 if (mapping && mapping->begin != begin) {
2451 mapping->end = begin;
2452 mapping = NULL;
2453 }
2454 if (mapping == NULL) {
2455 mapping = insert_mapping(s, begin, begin+1);
2456 }
2457 /* most members will be fixed in commit_mappings() */
2458 assert(commit->path);
2459 mapping->path = commit->path;
2460 mapping->read_only = 0;
2461 mapping->mode = MODE_NORMAL;
2462 mapping->info.file.offset = 0;
2463
2464 if (commit_one_file(s, i, 0))
2465 fail = -7;
2466
2467 break;
2468 }
2469 default:
2470 assert(0);
2471 }
2472 }
2473 if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2474 return -1;
2475 return fail;
2476 }
2477
2478 static int handle_deletes(BDRVVVFATState* s)
2479 {
2480 int i, deferred = 1, deleted = 1;
2481
2482 /* delete files corresponding to mappings marked as deleted */
2483 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2484 while (deferred && deleted) {
2485 deferred = 0;
2486 deleted = 0;
2487
2488 for (i = 1; i < s->mapping.next; i++) {
2489 mapping_t* mapping = array_get(&(s->mapping), i);
2490 if (mapping->mode & MODE_DELETED) {
2491 direntry_t* entry = array_get(&(s->directory),
2492 mapping->dir_index);
2493
2494 if (is_free(entry)) {
2495 /* remove file/directory */
2496 if (mapping->mode & MODE_DIRECTORY) {
2497 int j, next_dir_index = s->directory.next,
2498 first_dir_index = mapping->info.dir.first_dir_index;
2499
2500 if (rmdir(mapping->path) < 0) {
2501 if (errno == ENOTEMPTY) {
2502 deferred++;
2503 continue;
2504 } else
2505 return -5;
2506 }
2507
2508 for (j = 1; j < s->mapping.next; j++) {
2509 mapping_t* m = array_get(&(s->mapping), j);
2510 if (m->mode & MODE_DIRECTORY &&
2511 m->info.dir.first_dir_index >
2512 first_dir_index &&
2513 m->info.dir.first_dir_index <
2514 next_dir_index)
2515 next_dir_index =
2516 m->info.dir.first_dir_index;
2517 }
2518 remove_direntries(s, first_dir_index,
2519 next_dir_index - first_dir_index);
2520
2521 deleted++;
2522 }
2523 } else {
2524 if (unlink(mapping->path))
2525 return -4;
2526 deleted++;
2527 }
2528 DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2529 remove_mapping(s, i);
2530 }
2531 }
2532 }
2533
2534 return 0;
2535 }
2536
2537 /*
2538 * synchronize mapping with new state:
2539 *
2540 * - copy FAT (with bdrv_read)
2541 * - mark all filenames corresponding to mappings as deleted
2542 * - recurse direntries from root (using bs->bdrv_read)
2543 * - delete files corresponding to mappings marked as deleted
2544 */
2545 static int do_commit(BDRVVVFATState* s)
2546 {
2547 int ret = 0;
2548
2549 /* the real meat are the commits. Nothing to do? Move along! */
2550 if (s->commits.next == 0)
2551 return 0;
2552
2553 vvfat_close_current_file(s);
2554
2555 ret = handle_renames_and_mkdirs(s);
2556 if (ret) {
2557 fprintf(stderr, "Error handling renames (%d)\n", ret);
2558 assert(0);
2559 return ret;
2560 }
2561
2562 /* copy FAT (with bdrv_read) */
2563 memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2564
2565 /* recurse direntries from root (using bs->bdrv_read) */
2566 ret = commit_direntries(s, 0, -1);
2567 if (ret) {
2568 fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
2569 assert(0);
2570 return ret;
2571 }
2572
2573 ret = handle_commits(s);
2574 if (ret) {
2575 fprintf(stderr, "Error handling commits (%d)\n", ret);
2576 assert(0);
2577 return ret;
2578 }
2579
2580 ret = handle_deletes(s);
2581 if (ret) {
2582 fprintf(stderr, "Error deleting\n");
2583 assert(0);
2584 return ret;
2585 }
2586
2587 s->qcow->drv->bdrv_make_empty(s->qcow);
2588
2589 memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2590
2591 DLOG(checkpoint());
2592 return 0;
2593 }
2594
2595 static int try_commit(BDRVVVFATState* s)
2596 {
2597 vvfat_close_current_file(s);
2598 DLOG(checkpoint());
2599 if(!is_consistent(s))
2600 return -1;
2601 return do_commit(s);
2602 }
2603
2604 static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
2605 const uint8_t *buf, int nb_sectors)
2606 {
2607 BDRVVVFATState *s = bs->opaque;
2608 int i, ret;
2609
2610 DLOG(checkpoint());
2611
2612 vvfat_close_current_file(s);
2613
2614 /*
2615 * Some sanity checks:
2616 * - do not allow writing to the boot sector
2617 * - do not allow to write non-ASCII filenames
2618 */
2619
2620 if (sector_num < s->first_sectors_number)
2621 return -1;
2622
2623 for (i = sector2cluster(s, sector_num);
2624 i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
2625 mapping_t* mapping = find_mapping_for_cluster(s, i);
2626 if (mapping) {
2627 if (mapping->read_only) {
2628 fprintf(stderr, "Tried to write to write-protected file %s\n",
2629 mapping->path);
2630 return -1;
2631 }
2632
2633 if (mapping->mode & MODE_DIRECTORY) {
2634 int begin = cluster2sector(s, i);
2635 int end = begin + s->sectors_per_cluster, k;
2636 int dir_index;
2637 const direntry_t* direntries;
2638 long_file_name lfn;
2639
2640 lfn_init(&lfn);
2641
2642 if (begin < sector_num)
2643 begin = sector_num;
2644 if (end > sector_num + nb_sectors)
2645 end = sector_num + nb_sectors;
2646 dir_index = mapping->dir_index +
2647 0x10 * (begin - mapping->begin * s->sectors_per_cluster);
2648 direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
2649
2650 for (k = 0; k < (end - begin) * 0x10; k++) {
2651 /* do not allow non-ASCII filenames */
2652 if (parse_long_name(&lfn, direntries + k) < 0) {
2653 fprintf(stderr, "Warning: non-ASCII filename\n");
2654 return -1;
2655 }
2656 /* no access to the direntry of a read-only file */
2657 else if (is_short_name(direntries+k) &&
2658 (direntries[k].attributes & 1)) {
2659 if (memcmp(direntries + k,
2660 array_get(&(s->directory), dir_index + k),
2661 sizeof(direntry_t))) {
2662 fprintf(stderr, "Warning: tried to write to write-protected file\n");
2663 return -1;
2664 }
2665 }
2666 }
2667 }
2668 i = mapping->end;
2669 } else
2670 i++;
2671 }
2672
2673 /*
2674 * Use qcow backend. Commit later.
2675 */
2676 DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
2677 ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
2678 if (ret < 0) {
2679 fprintf(stderr, "Error writing to qcow backend\n");
2680 return ret;
2681 }
2682
2683 for (i = sector2cluster(s, sector_num);
2684 i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
2685 if (i >= 0)
2686 s->used_clusters[i] |= USED_ALLOCATED;
2687
2688 DLOG(checkpoint());
2689 /* TODO: add timeout */
2690 try_commit(s);
2691
2692 DLOG(checkpoint());
2693 return 0;
2694 }
2695
2696 static int vvfat_is_allocated(BlockDriverState *bs,
2697 int64_t sector_num, int nb_sectors, int* n)
2698 {
2699 BDRVVVFATState* s = bs->opaque;
2700 *n = s->sector_count - sector_num;
2701 if (*n > nb_sectors)
2702 *n = nb_sectors;
2703 else if (*n < 0)
2704 return 0;
2705 return 1;
2706 }
2707
2708 static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
2709 const uint8_t* buffer, int nb_sectors) {
2710 BDRVVVFATState* s = bs->opaque;
2711 return try_commit(s);
2712 }
2713
2714 static void write_target_close(BlockDriverState *bs) {
2715 BDRVVVFATState* s = bs->opaque;
2716 bdrv_delete(s->qcow);
2717 free(s->qcow_filename);
2718 }
2719
2720 static BlockDriver vvfat_write_target = {
2721 "vvfat_write_target", 0, NULL, NULL, NULL,
2722 write_target_commit,
2723 write_target_close,
2724 NULL, NULL, NULL
2725 };
2726
2727 static int enable_write_target(BDRVVVFATState *s)
2728 {
2729 int size = sector2cluster(s, s->sector_count);
2730 s->used_clusters = calloc(size, 1);
2731
2732 array_init(&(s->commits), sizeof(commit_t));
2733
2734 s->qcow_filename = malloc(1024);
2735 strcpy(s->qcow_filename, "/tmp/vl.XXXXXX");
2736 get_tmp_filename(s->qcow_filename, strlen(s->qcow_filename) + 1);
2737 if (bdrv_create(&bdrv_qcow,
2738 s->qcow_filename, s->sector_count, "fat:", 0) < 0)
2739 return -1;
2740 s->qcow = bdrv_new("");
2741 if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
2742 return -1;
2743
2744 #ifndef _WIN32
2745 unlink(s->qcow_filename);
2746 #endif
2747
2748 s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
2749 s->bs->backing_hd->drv = &vvfat_write_target;
2750 s->bs->backing_hd->opaque = s;
2751
2752 return 0;
2753 }
2754
2755 static void vvfat_close(BlockDriverState *bs)
2756 {
2757 BDRVVVFATState *s = bs->opaque;
2758
2759 vvfat_close_current_file(s);
2760 array_free(&(s->fat));
2761 array_free(&(s->directory));
2762 array_free(&(s->mapping));
2763 if(s->cluster_buffer)
2764 free(s->cluster_buffer);
2765 }
2766
2767 BlockDriver bdrv_vvfat = {
2768 "vvfat",
2769 sizeof(BDRVVVFATState),
2770 vvfat_probe,
2771 vvfat_open,
2772 vvfat_read,
2773 vvfat_write,
2774 vvfat_close,
2775 NULL,
2776 vvfat_is_allocated
2777 };
2778
2779 #ifdef DEBUG
2780 static void checkpoint() {
2781 assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
2782 check1(vvv);
2783 check2(vvv);
2784 assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
2785 #if 0
2786 if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
2787 fprintf(stderr, "Nonono!\n");
2788 mapping_t* mapping;
2789 direntry_t* direntry;
2790 assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
2791 assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
2792 if (vvv->mapping.next<47)
2793 return;
2794 assert((mapping = array_get(&(vvv->mapping), 47)));
2795 assert(mapping->dir_index < vvv->directory.next);
2796 direntry = array_get(&(vvv->directory), mapping->dir_index);
2797 assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0);
2798 #endif
2799 return;
2800 /* avoid compiler warnings: */
2801 hexdump(NULL, 100);
2802 remove_mapping(vvv, NULL);
2803 print_mapping(NULL);
2804 print_direntry(NULL);
2805 }
2806 #endif
2807