1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include "qemu/osdep.h"
27#include <dirent.h>
28#include "qapi/error.h"
29#include "block/block_int.h"
30#include "block/qdict.h"
31#include "qemu/module.h"
32#include "qemu/option.h"
33#include "qemu/bswap.h"
34#include "migration/blocker.h"
35#include "qapi/qmp/qdict.h"
36#include "qapi/qmp/qstring.h"
37#include "qemu/cutils.h"
38#include "qemu/error-report.h"
39
40#ifndef S_IWGRP
41#define S_IWGRP 0
42#endif
43#ifndef S_IWOTH
44#define S_IWOTH 0
45#endif
46
47
48
49
50
51
52
53
54
55
56
57#ifdef DEBUG
58
59#define DLOG(a) a
60
61static void checkpoint(void);
62
63#else
64
65#define DLOG(a)
66
67#endif
68
69
70
71
72
73#define BOOTSECTOR_OEM_NAME "MSWIN4.1"
74
75#define DIR_DELETED 0xe5
76#define DIR_KANJI DIR_DELETED
77#define DIR_KANJI_FAKE 0x05
78#define DIR_FREE 0x00
79
80
81typedef struct array_t {
82 char* pointer;
83 unsigned int size,next,item_size;
84} array_t;
85
86static inline void array_init(array_t* array,unsigned int item_size)
87{
88 array->pointer = NULL;
89 array->size=0;
90 array->next=0;
91 array->item_size=item_size;
92}
93
94static inline void array_free(array_t* array)
95{
96 g_free(array->pointer);
97 array->size=array->next=0;
98}
99
100
101static inline void* array_get(array_t* array,unsigned int index) {
102 assert(index < array->next);
103 return array->pointer + index * array->item_size;
104}
105
106static inline int array_ensure_allocated(array_t* array, int index)
107{
108 if((index + 1) * array->item_size > array->size) {
109 int new_size = (index + 32) * array->item_size;
110 array->pointer = g_realloc(array->pointer, new_size);
111 if (!array->pointer)
112 return -1;
113 memset(array->pointer + array->size, 0, new_size - array->size);
114 array->size = new_size;
115 array->next = index + 1;
116 }
117
118 return 0;
119}
120
121static inline void* array_get_next(array_t* array) {
122 unsigned int next = array->next;
123
124 if (array_ensure_allocated(array, next) < 0)
125 return NULL;
126
127 array->next = next + 1;
128 return array_get(array, next);
129}
130
131static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
132 if((array->next+count)*array->item_size>array->size) {
133 int increment=count*array->item_size;
134 array->pointer=g_realloc(array->pointer,array->size+increment);
135 if(!array->pointer)
136 return NULL;
137 array->size+=increment;
138 }
139 memmove(array->pointer+(index+count)*array->item_size,
140 array->pointer+index*array->item_size,
141 (array->next-index)*array->item_size);
142 array->next+=count;
143 return array->pointer+index*array->item_size;
144}
145
146
147
148static inline int array_roll(array_t* array,int index_to,int index_from,int count)
149{
150 char* buf;
151 char* from;
152 char* to;
153 int is;
154
155 if(!array ||
156 index_to<0 || index_to>=array->next ||
157 index_from<0 || index_from>=array->next)
158 return -1;
159
160 if(index_to==index_from)
161 return 0;
162
163 is=array->item_size;
164 from=array->pointer+index_from*is;
165 to=array->pointer+index_to*is;
166 buf=g_malloc(is*count);
167 memcpy(buf,from,is*count);
168
169 if(index_to<index_from)
170 memmove(to+is*count,to,from-to);
171 else
172 memmove(from,from+is*count,to-from);
173
174 memcpy(to,buf,is*count);
175
176 g_free(buf);
177
178 return 0;
179}
180
181static inline int array_remove_slice(array_t* array,int index, int count)
182{
183 assert(index >=0);
184 assert(count > 0);
185 assert(index + count <= array->next);
186 if(array_roll(array,array->next-1,index,count))
187 return -1;
188 array->next -= count;
189 return 0;
190}
191
192static int array_remove(array_t* array,int index)
193{
194 return array_remove_slice(array, index, 1);
195}
196
197
198static int array_index(array_t* array, void* pointer)
199{
200 size_t offset = (char*)pointer - array->pointer;
201 assert((offset % array->item_size) == 0);
202 assert(offset/array->item_size < array->next);
203 return offset/array->item_size;
204}
205
206
207
208
209typedef struct bootsector_t {
210 uint8_t jump[3];
211 uint8_t name[8];
212 uint16_t sector_size;
213 uint8_t sectors_per_cluster;
214 uint16_t reserved_sectors;
215 uint8_t number_of_fats;
216 uint16_t root_entries;
217 uint16_t total_sectors16;
218 uint8_t media_type;
219 uint16_t sectors_per_fat;
220 uint16_t sectors_per_track;
221 uint16_t number_of_heads;
222 uint32_t hidden_sectors;
223 uint32_t total_sectors;
224 union {
225 struct {
226 uint8_t drive_number;
227 uint8_t reserved1;
228 uint8_t signature;
229 uint32_t id;
230 uint8_t volume_label[11];
231 uint8_t fat_type[8];
232 uint8_t ignored[0x1c0];
233 } QEMU_PACKED fat16;
234 struct {
235 uint32_t sectors_per_fat;
236 uint16_t flags;
237 uint8_t major,minor;
238 uint32_t first_cluster_of_root_dir;
239 uint16_t info_sector;
240 uint16_t backup_boot_sector;
241 uint8_t reserved[12];
242 uint8_t drive_number;
243 uint8_t reserved1;
244 uint8_t signature;
245 uint32_t id;
246 uint8_t volume_label[11];
247 uint8_t fat_type[8];
248 uint8_t ignored[0x1a4];
249 } QEMU_PACKED fat32;
250 } u;
251 uint8_t magic[2];
252} QEMU_PACKED bootsector_t;
253
254typedef struct {
255 uint8_t head;
256 uint8_t sector;
257 uint8_t cylinder;
258} mbr_chs_t;
259
260typedef struct partition_t {
261 uint8_t attributes;
262 mbr_chs_t start_CHS;
263 uint8_t fs_type;
264 mbr_chs_t end_CHS;
265 uint32_t start_sector_long;
266 uint32_t length_sector_long;
267} QEMU_PACKED partition_t;
268
269typedef struct mbr_t {
270 uint8_t ignored[0x1b8];
271 uint32_t nt_id;
272 uint8_t ignored2[2];
273 partition_t partition[4];
274 uint8_t magic[2];
275} QEMU_PACKED mbr_t;
276
277typedef struct direntry_t {
278 uint8_t name[8 + 3];
279 uint8_t attributes;
280 uint8_t reserved[2];
281 uint16_t ctime;
282 uint16_t cdate;
283 uint16_t adate;
284 uint16_t begin_hi;
285 uint16_t mtime;
286 uint16_t mdate;
287 uint16_t begin;
288 uint32_t size;
289} QEMU_PACKED direntry_t;
290
291
292
293typedef struct mapping_t {
294
295 uint32_t begin,end;
296
297 unsigned int dir_index;
298
299 int first_mapping_index;
300 union {
301
302
303
304
305 struct {
306 uint32_t offset;
307 } file;
308 struct {
309 int parent_mapping_index;
310 int first_dir_index;
311 } dir;
312 } info;
313
314 char* path;
315
316 enum {
317 MODE_UNDEFINED = 0,
318 MODE_NORMAL = 1,
319 MODE_MODIFIED = 2,
320 MODE_DIRECTORY = 4,
321 MODE_DELETED = 8,
322 } mode;
323 int read_only;
324} mapping_t;
325
326#ifdef DEBUG
327static void print_direntry(const struct direntry_t*);
328static void print_mapping(const struct mapping_t* mapping);
329#endif
330
331
332
333typedef struct BDRVVVFATState {
334 CoMutex lock;
335 BlockDriverState* bs;
336 unsigned char first_sectors[0x40*0x200];
337
338 int fat_type;
339 array_t fat,directory,mapping;
340 char volume_label[11];
341
342 uint32_t offset_to_bootsector;
343
344 unsigned int cluster_size;
345 unsigned int sectors_per_cluster;
346 unsigned int sectors_per_fat;
347 uint32_t last_cluster_of_root_directory;
348
349 uint16_t root_entries;
350 uint32_t sector_count;
351 uint32_t cluster_count;
352 uint32_t max_fat_value;
353 uint32_t offset_to_fat;
354 uint32_t offset_to_root_dir;
355
356 int current_fd;
357 mapping_t* current_mapping;
358 unsigned char* cluster;
359 unsigned char* cluster_buffer;
360 unsigned int current_cluster;
361
362
363 char* qcow_filename;
364 BdrvChild* qcow;
365 void* fat2;
366 char* used_clusters;
367 array_t commits;
368 const char* path;
369 int downcase_short_names;
370
371 Error *migration_blocker;
372} BDRVVVFATState;
373
374
375
376
377
378static int sector2CHS(mbr_chs_t *chs, int spos, int cyls, int heads, int secs)
379{
380 int head,sector;
381 sector = spos % secs; spos /= secs;
382 head = spos % heads; spos /= heads;
383 if (spos >= cyls) {
384
385
386
387 chs->head = 0xFF;
388 chs->sector = 0xFF;
389 chs->cylinder = 0xFF;
390 return 1;
391 }
392 chs->head = (uint8_t)head;
393 chs->sector = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
394 chs->cylinder = (uint8_t)spos;
395 return 0;
396}
397
398static void init_mbr(BDRVVVFATState *s, int cyls, int heads, int secs)
399{
400
401 mbr_t* real_mbr=(mbr_t*)s->first_sectors;
402 partition_t* partition = &(real_mbr->partition[0]);
403 int lba;
404
405 memset(s->first_sectors,0,512);
406
407
408 real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
409
410 partition->attributes=0x80;
411
412
413 lba = sector2CHS(&partition->start_CHS, s->offset_to_bootsector,
414 cyls, heads, secs);
415 lba |= sector2CHS(&partition->end_CHS, s->bs->total_sectors - 1,
416 cyls, heads, secs);
417
418
419 partition->start_sector_long = cpu_to_le32(s->offset_to_bootsector);
420 partition->length_sector_long = cpu_to_le32(s->bs->total_sectors
421 - s->offset_to_bootsector);
422
423
424
425
426 partition->fs_type = s->fat_type == 12 ? 0x1 :
427 s->fat_type == 16 ? (lba ? 0xe : 0x06) :
428 (lba ? 0xc : 0x0b);
429
430 real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
431}
432
433
434
435static direntry_t *create_long_filename(BDRVVVFATState *s, const char *filename)
436{
437 int number_of_entries, i;
438 glong length;
439 direntry_t *entry;
440
441 gunichar2 *longname = g_utf8_to_utf16(filename, -1, NULL, &length, NULL);
442 if (!longname) {
443 fprintf(stderr, "vvfat: invalid UTF-8 name: %s\n", filename);
444 return NULL;
445 }
446
447 number_of_entries = DIV_ROUND_UP(length * 2, 26);
448
449 for(i=0;i<number_of_entries;i++) {
450 entry=array_get_next(&(s->directory));
451 entry->attributes=0xf;
452 entry->reserved[0]=0;
453 entry->begin=0;
454 entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
455 }
456 for(i=0;i<26*number_of_entries;i++) {
457 int offset=(i%26);
458 if(offset<10) offset=1+offset;
459 else if(offset<22) offset=14+offset-10;
460 else offset=28+offset-22;
461 entry=array_get(&(s->directory),s->directory.next-1-(i/26));
462 if (i >= 2 * length + 2) {
463 entry->name[offset] = 0xff;
464 } else if (i % 2 == 0) {
465 entry->name[offset] = longname[i / 2] & 0xff;
466 } else {
467 entry->name[offset] = longname[i / 2] >> 8;
468 }
469 }
470 g_free(longname);
471 return array_get(&(s->directory),s->directory.next-number_of_entries);
472}
473
474static char is_free(const direntry_t* direntry)
475{
476 return direntry->name[0] == DIR_DELETED || direntry->name[0] == DIR_FREE;
477}
478
479static char is_volume_label(const direntry_t* direntry)
480{
481 return direntry->attributes == 0x28;
482}
483
484static char is_long_name(const direntry_t* direntry)
485{
486 return direntry->attributes == 0xf;
487}
488
489static char is_short_name(const direntry_t* direntry)
490{
491 return !is_volume_label(direntry) && !is_long_name(direntry)
492 && !is_free(direntry);
493}
494
495static char is_directory(const direntry_t* direntry)
496{
497 return direntry->attributes & 0x10 && direntry->name[0] != DIR_DELETED;
498}
499
500static inline char is_dot(const direntry_t* direntry)
501{
502 return is_short_name(direntry) && direntry->name[0] == '.';
503}
504
505static char is_file(const direntry_t* direntry)
506{
507 return is_short_name(direntry) && !is_directory(direntry);
508}
509
510static inline uint32_t begin_of_direntry(const direntry_t* direntry)
511{
512 return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
513}
514
515static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
516{
517 return le32_to_cpu(direntry->size);
518}
519
520static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
521{
522 direntry->begin = cpu_to_le16(begin & 0xffff);
523 direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
524}
525
526static uint8_t to_valid_short_char(gunichar c)
527{
528 c = g_unichar_toupper(c);
529 if ((c >= '0' && c <= '9') ||
530 (c >= 'A' && c <= 'Z') ||
531 strchr("$%'-_@~`!(){}^#&", c) != 0) {
532 return c;
533 } else {
534 return 0;
535 }
536}
537
538static direntry_t *create_short_filename(BDRVVVFATState *s,
539 const char *filename,
540 unsigned int directory_start)
541{
542 int i, j = 0;
543 direntry_t *entry = array_get_next(&(s->directory));
544 const gchar *p, *last_dot = NULL;
545 gunichar c;
546 bool lossy_conversion = false;
547 char tail[8];
548
549 if (!entry) {
550 return NULL;
551 }
552 memset(entry->name, 0x20, sizeof(entry->name));
553
554
555 for (p = filename; ; p = g_utf8_next_char(p)) {
556 c = g_utf8_get_char(p);
557 if (c == '\0') {
558 break;
559 } else if (c == '.') {
560 if (j == 0) {
561
562 lossy_conversion = true;
563 } else {
564 if (last_dot) {
565 lossy_conversion = true;
566 }
567 last_dot = p;
568 }
569 } else if (!last_dot) {
570
571 uint8_t v = to_valid_short_char(c);
572 if (j < 8 && v) {
573 entry->name[j++] = v;
574 } else {
575 lossy_conversion = true;
576 }
577 }
578 }
579
580
581 if (last_dot) {
582 j = 0;
583 for (p = g_utf8_next_char(last_dot); ; p = g_utf8_next_char(p)) {
584 c = g_utf8_get_char(p);
585 if (c == '\0') {
586 break;
587 } else {
588
589 uint8_t v = to_valid_short_char(c);
590 if (j < 3 && v) {
591 entry->name[8 + (j++)] = v;
592 } else {
593 lossy_conversion = true;
594 }
595 }
596 }
597 }
598
599 if (entry->name[0] == DIR_KANJI) {
600 entry->name[0] = DIR_KANJI_FAKE;
601 }
602
603
604 for (j = 0; j < 8; j++) {
605 if (entry->name[j] == ' ') {
606 break;
607 }
608 }
609 for (i = lossy_conversion ? 1 : 0; i < 999999; i++) {
610 direntry_t *entry1;
611 if (i > 0) {
612 int len = snprintf(tail, sizeof(tail), "~%u", (unsigned)i);
613 assert(len <= 7);
614 memcpy(entry->name + MIN(j, 8 - len), tail, len);
615 }
616 for (entry1 = array_get(&(s->directory), directory_start);
617 entry1 < entry; entry1++) {
618 if (!is_long_name(entry1) &&
619 !memcmp(entry1->name, entry->name, 11)) {
620 break;
621 }
622 }
623 if (entry1 == entry) {
624
625 return entry;
626 }
627 }
628 return NULL;
629}
630
631
632
633static inline uint8_t fat_chksum(const direntry_t* entry)
634{
635 uint8_t chksum=0;
636 int i;
637
638 for (i = 0; i < ARRAY_SIZE(entry->name); i++) {
639 chksum = (((chksum & 0xfe) >> 1) |
640 ((chksum & 0x01) ? 0x80 : 0)) + entry->name[i];
641 }
642
643 return chksum;
644}
645
646
647static uint16_t fat_datetime(time_t time,int return_time) {
648 struct tm* t;
649 struct tm t1;
650 t = &t1;
651 localtime_r(&time,t);
652 if(return_time)
653 return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
654 return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
655}
656
657static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
658{
659 if(s->fat_type==32) {
660 uint32_t* entry=array_get(&(s->fat),cluster);
661 *entry=cpu_to_le32(value);
662 } else if(s->fat_type==16) {
663 uint16_t* entry=array_get(&(s->fat),cluster);
664 *entry=cpu_to_le16(value&0xffff);
665 } else {
666 int offset = (cluster*3/2);
667 unsigned char* p = array_get(&(s->fat), offset);
668 switch (cluster&1) {
669 case 0:
670 p[0] = value&0xff;
671 p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
672 break;
673 case 1:
674 p[0] = (p[0]&0xf) | ((value&0xf)<<4);
675 p[1] = (value>>4);
676 break;
677 }
678 }
679}
680
681static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
682{
683 if(s->fat_type==32) {
684 uint32_t* entry=array_get(&(s->fat),cluster);
685 return le32_to_cpu(*entry);
686 } else if(s->fat_type==16) {
687 uint16_t* entry=array_get(&(s->fat),cluster);
688 return le16_to_cpu(*entry);
689 } else {
690 const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
691 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
692 }
693}
694
695static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
696{
697 if(fat_entry>s->max_fat_value-8)
698 return -1;
699 return 0;
700}
701
702static inline void init_fat(BDRVVVFATState* s)
703{
704 if (s->fat_type == 12) {
705 array_init(&(s->fat),1);
706 array_ensure_allocated(&(s->fat),
707 s->sectors_per_fat * 0x200 * 3 / 2 - 1);
708 } else {
709 array_init(&(s->fat),(s->fat_type==32?4:2));
710 array_ensure_allocated(&(s->fat),
711 s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
712 }
713 memset(s->fat.pointer,0,s->fat.size);
714
715 switch(s->fat_type) {
716 case 12: s->max_fat_value=0xfff; break;
717 case 16: s->max_fat_value=0xffff; break;
718 case 32: s->max_fat_value=0x0fffffff; break;
719 default: s->max_fat_value=0;
720 }
721
722}
723
724static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
725 unsigned int directory_start, const char* filename, int is_dot)
726{
727 int long_index = s->directory.next;
728 direntry_t* entry = NULL;
729 direntry_t* entry_long = NULL;
730
731 if(is_dot) {
732 entry=array_get_next(&(s->directory));
733 memset(entry->name, 0x20, sizeof(entry->name));
734 memcpy(entry->name,filename,strlen(filename));
735 return entry;
736 }
737
738 entry_long=create_long_filename(s,filename);
739 entry = create_short_filename(s, filename, directory_start);
740
741
742 if(entry_long) {
743 uint8_t chksum=fat_chksum(entry);
744
745
746 entry_long=array_get(&(s->directory),long_index);
747 while(entry_long<entry && is_long_name(entry_long)) {
748 entry_long->reserved[1]=chksum;
749 entry_long++;
750 }
751 }
752
753 return entry;
754}
755
756
757
758
759static int read_directory(BDRVVVFATState* s, int mapping_index)
760{
761 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
762 direntry_t* direntry;
763 const char* dirname = mapping->path;
764 int first_cluster = mapping->begin;
765 int parent_index = mapping->info.dir.parent_mapping_index;
766 mapping_t* parent_mapping = (mapping_t*)
767 (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL);
768 int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
769
770 DIR* dir=opendir(dirname);
771 struct dirent* entry;
772 int i;
773
774 assert(mapping->mode & MODE_DIRECTORY);
775
776 if(!dir) {
777 mapping->end = mapping->begin;
778 return -1;
779 }
780
781 i = mapping->info.dir.first_dir_index =
782 first_cluster == 0 ? 0 : s->directory.next;
783
784 if (first_cluster != 0) {
785
786 (void)create_short_and_long_name(s, i, ".", 1);
787 (void)create_short_and_long_name(s, i, "..", 1);
788 }
789
790
791 while((entry=readdir(dir))) {
792 unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
793 char* buffer;
794 direntry_t* direntry;
795 struct stat st;
796 int is_dot=!strcmp(entry->d_name,".");
797 int is_dotdot=!strcmp(entry->d_name,"..");
798
799 if (first_cluster == 0 && s->directory.next >= s->root_entries - 1) {
800 fprintf(stderr, "Too many entries in root directory\n");
801 closedir(dir);
802 return -2;
803 }
804
805 if(first_cluster == 0 && (is_dotdot || is_dot))
806 continue;
807
808 buffer = g_malloc(length);
809 snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
810
811 if(stat(buffer,&st)<0) {
812 g_free(buffer);
813 continue;
814 }
815
816
817 if (!is_dot && !is_dotdot) {
818 direntry = create_short_and_long_name(s, i, entry->d_name, 0);
819 } else {
820 direntry = array_get(&(s->directory), is_dot ? i : i + 1);
821 }
822 direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
823 direntry->reserved[0]=direntry->reserved[1]=0;
824 direntry->ctime=fat_datetime(st.st_ctime,1);
825 direntry->cdate=fat_datetime(st.st_ctime,0);
826 direntry->adate=fat_datetime(st.st_atime,0);
827 direntry->begin_hi=0;
828 direntry->mtime=fat_datetime(st.st_mtime,1);
829 direntry->mdate=fat_datetime(st.st_mtime,0);
830 if(is_dotdot)
831 set_begin_of_direntry(direntry, first_cluster_of_parent);
832 else if(is_dot)
833 set_begin_of_direntry(direntry, first_cluster);
834 else
835 direntry->begin=0;
836 if (st.st_size > 0x7fffffff) {
837 fprintf(stderr, "File %s is larger than 2GB\n", buffer);
838 g_free(buffer);
839 closedir(dir);
840 return -2;
841 }
842 direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
843
844
845 if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
846 s->current_mapping = array_get_next(&(s->mapping));
847 s->current_mapping->begin=0;
848 s->current_mapping->end=st.st_size;
849
850
851
852
853 s->current_mapping->dir_index=s->directory.next-1;
854 s->current_mapping->first_mapping_index = -1;
855 if (S_ISDIR(st.st_mode)) {
856 s->current_mapping->mode = MODE_DIRECTORY;
857 s->current_mapping->info.dir.parent_mapping_index =
858 mapping_index;
859 } else {
860 s->current_mapping->mode = MODE_UNDEFINED;
861 s->current_mapping->info.file.offset = 0;
862 }
863 s->current_mapping->path=buffer;
864 s->current_mapping->read_only =
865 (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
866 } else {
867 g_free(buffer);
868 }
869 }
870 closedir(dir);
871
872
873 while(s->directory.next%(0x10*s->sectors_per_cluster)) {
874 direntry_t* direntry=array_get_next(&(s->directory));
875 memset(direntry,0,sizeof(direntry_t));
876 }
877
878 if (s->fat_type != 32 &&
879 mapping_index == 0 &&
880 s->directory.next < s->root_entries) {
881
882 int cur = s->directory.next;
883 array_ensure_allocated(&(s->directory), s->root_entries - 1);
884 s->directory.next = s->root_entries;
885 memset(array_get(&(s->directory), cur), 0,
886 (s->root_entries - cur) * sizeof(direntry_t));
887 }
888
889
890 mapping = array_get(&(s->mapping), mapping_index);
891 first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
892 * 0x20 / s->cluster_size;
893 mapping->end = first_cluster;
894
895 direntry = array_get(&(s->directory), mapping->dir_index);
896 set_begin_of_direntry(direntry, mapping->begin);
897
898 return 0;
899}
900
901static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
902{
903 return (sector_num - s->offset_to_root_dir) / s->sectors_per_cluster;
904}
905
906static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
907{
908 return s->offset_to_root_dir + s->sectors_per_cluster * cluster_num;
909}
910
911static int init_directories(BDRVVVFATState* s,
912 const char *dirname, int heads, int secs,
913 Error **errp)
914{
915 bootsector_t* bootsector;
916 mapping_t* mapping;
917 unsigned int i;
918 unsigned int cluster;
919
920 memset(&(s->first_sectors[0]),0,0x40*0x200);
921
922 s->cluster_size=s->sectors_per_cluster*0x200;
923 s->cluster_buffer=g_malloc(s->cluster_size);
924
925
926
927
928
929
930
931
932 i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
933 s->sectors_per_fat=(s->sector_count+i)/i;
934
935 s->offset_to_fat = s->offset_to_bootsector + 1;
936 s->offset_to_root_dir = s->offset_to_fat + s->sectors_per_fat * 2;
937
938 array_init(&(s->mapping),sizeof(mapping_t));
939 array_init(&(s->directory),sizeof(direntry_t));
940
941
942 {
943 direntry_t* entry=array_get_next(&(s->directory));
944 entry->attributes=0x28;
945 memcpy(entry->name, s->volume_label, sizeof(entry->name));
946 }
947
948
949 init_fat(s);
950
951
952 s->root_entries = 0x02 * 0x10 * s->sectors_per_cluster;
953 s->cluster_count=sector2cluster(s, s->sector_count);
954
955 mapping = array_get_next(&(s->mapping));
956 mapping->begin = 0;
957 mapping->dir_index = 0;
958 mapping->info.dir.parent_mapping_index = -1;
959 mapping->first_mapping_index = -1;
960 mapping->path = g_strdup(dirname);
961 i = strlen(mapping->path);
962 if (i > 0 && mapping->path[i - 1] == '/')
963 mapping->path[i - 1] = '\0';
964 mapping->mode = MODE_DIRECTORY;
965 mapping->read_only = 0;
966 s->path = mapping->path;
967
968 for (i = 0, cluster = 0; i < s->mapping.next; i++) {
969
970
971
972 int fix_fat = (i != 0);
973 mapping = array_get(&(s->mapping), i);
974
975 if (mapping->mode & MODE_DIRECTORY) {
976 mapping->begin = cluster;
977 if(read_directory(s, i)) {
978 error_setg(errp, "Could not read directory %s",
979 mapping->path);
980 return -1;
981 }
982 mapping = array_get(&(s->mapping), i);
983 } else {
984 assert(mapping->mode == MODE_UNDEFINED);
985 mapping->mode=MODE_NORMAL;
986 mapping->begin = cluster;
987 if (mapping->end > 0) {
988 direntry_t* direntry = array_get(&(s->directory),
989 mapping->dir_index);
990
991 mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
992 set_begin_of_direntry(direntry, mapping->begin);
993 } else {
994 mapping->end = cluster + 1;
995 fix_fat = 0;
996 }
997 }
998
999 assert(mapping->begin < mapping->end);
1000
1001
1002 cluster = mapping->end;
1003
1004 if(cluster > s->cluster_count) {
1005 error_setg(errp,
1006 "Directory does not fit in FAT%d (capacity %.2f MB)",
1007 s->fat_type, s->sector_count / 2000.0);
1008 return -1;
1009 }
1010
1011
1012 if (fix_fat) {
1013 int j;
1014 for(j = mapping->begin; j < mapping->end - 1; j++)
1015 fat_set(s, j, j+1);
1016 fat_set(s, mapping->end - 1, s->max_fat_value);
1017 }
1018 }
1019
1020 mapping = array_get(&(s->mapping), 0);
1021 s->last_cluster_of_root_directory = mapping->end;
1022
1023
1024 fat_set(s,0,s->max_fat_value);
1025 fat_set(s,1,s->max_fat_value);
1026
1027 s->current_mapping = NULL;
1028
1029 bootsector = (bootsector_t *)(s->first_sectors
1030 + s->offset_to_bootsector * 0x200);
1031 bootsector->jump[0]=0xeb;
1032 bootsector->jump[1]=0x3e;
1033 bootsector->jump[2]=0x90;
1034 memcpy(bootsector->name, BOOTSECTOR_OEM_NAME, 8);
1035 bootsector->sector_size=cpu_to_le16(0x200);
1036 bootsector->sectors_per_cluster=s->sectors_per_cluster;
1037 bootsector->reserved_sectors=cpu_to_le16(1);
1038 bootsector->number_of_fats=0x2;
1039 bootsector->root_entries = cpu_to_le16(s->root_entries);
1040 bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
1041
1042 bootsector->media_type = (s->offset_to_bootsector > 0 ? 0xf8 : 0xf0);
1043 s->fat.pointer[0] = bootsector->media_type;
1044 bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
1045 bootsector->sectors_per_track = cpu_to_le16(secs);
1046 bootsector->number_of_heads = cpu_to_le16(heads);
1047 bootsector->hidden_sectors = cpu_to_le32(s->offset_to_bootsector);
1048 bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
1049
1050
1051
1052 bootsector->u.fat16.drive_number = s->offset_to_bootsector == 0 ? 0 : 0x80;
1053 bootsector->u.fat16.signature=0x29;
1054 bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
1055
1056 memcpy(bootsector->u.fat16.volume_label, s->volume_label,
1057 sizeof(bootsector->u.fat16.volume_label));
1058 memcpy(bootsector->u.fat16.fat_type,
1059 s->fat_type == 12 ? "FAT12 " : "FAT16 ", 8);
1060 bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
1061
1062 return 0;
1063}
1064
1065#ifdef DEBUG
1066static BDRVVVFATState *vvv = NULL;
1067#endif
1068
1069static int enable_write_target(BlockDriverState *bs, Error **errp);
1070static int is_consistent(BDRVVVFATState *s);
1071
1072static QemuOptsList runtime_opts = {
1073 .name = "vvfat",
1074 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
1075 .desc = {
1076 {
1077 .name = "dir",
1078 .type = QEMU_OPT_STRING,
1079 .help = "Host directory to map to the vvfat device",
1080 },
1081 {
1082 .name = "fat-type",
1083 .type = QEMU_OPT_NUMBER,
1084 .help = "FAT type (12, 16 or 32)",
1085 },
1086 {
1087 .name = "floppy",
1088 .type = QEMU_OPT_BOOL,
1089 .help = "Create a floppy rather than a hard disk image",
1090 },
1091 {
1092 .name = "label",
1093 .type = QEMU_OPT_STRING,
1094 .help = "Use a volume label other than QEMU VVFAT",
1095 },
1096 {
1097 .name = "rw",
1098 .type = QEMU_OPT_BOOL,
1099 .help = "Make the image writable",
1100 },
1101 { }
1102 },
1103};
1104
1105static void vvfat_parse_filename(const char *filename, QDict *options,
1106 Error **errp)
1107{
1108 int fat_type = 0;
1109 bool floppy = false;
1110 bool rw = false;
1111 int i;
1112
1113 if (!strstart(filename, "fat:", NULL)) {
1114 error_setg(errp, "File name string must start with 'fat:'");
1115 return;
1116 }
1117
1118
1119 if (strstr(filename, ":32:")) {
1120 fat_type = 32;
1121 } else if (strstr(filename, ":16:")) {
1122 fat_type = 16;
1123 } else if (strstr(filename, ":12:")) {
1124 fat_type = 12;
1125 }
1126
1127 if (strstr(filename, ":floppy:")) {
1128 floppy = true;
1129 }
1130
1131 if (strstr(filename, ":rw:")) {
1132 rw = true;
1133 }
1134
1135
1136 i = strrchr(filename, ':') - filename;
1137 assert(i >= 3);
1138 if (filename[i - 2] == ':' && qemu_isalpha(filename[i - 1])) {
1139
1140 filename += i - 1;
1141 } else {
1142 filename += i + 1;
1143 }
1144
1145
1146 qdict_put_str(options, "dir", filename);
1147 qdict_put_int(options, "fat-type", fat_type);
1148 qdict_put_bool(options, "floppy", floppy);
1149 qdict_put_bool(options, "rw", rw);
1150}
1151
1152static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
1153 Error **errp)
1154{
1155 BDRVVVFATState *s = bs->opaque;
1156 int cyls, heads, secs;
1157 bool floppy;
1158 const char *dirname, *label;
1159 QemuOpts *opts;
1160 Error *local_err = NULL;
1161 int ret;
1162
1163#ifdef DEBUG
1164 vvv = s;
1165#endif
1166
1167 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
1168 qemu_opts_absorb_qdict(opts, options, &local_err);
1169 if (local_err) {
1170 error_propagate(errp, local_err);
1171 ret = -EINVAL;
1172 goto fail;
1173 }
1174
1175 dirname = qemu_opt_get(opts, "dir");
1176 if (!dirname) {
1177 error_setg(errp, "vvfat block driver requires a 'dir' option");
1178 ret = -EINVAL;
1179 goto fail;
1180 }
1181
1182 s->fat_type = qemu_opt_get_number(opts, "fat-type", 0);
1183 floppy = qemu_opt_get_bool(opts, "floppy", false);
1184
1185 memset(s->volume_label, ' ', sizeof(s->volume_label));
1186 label = qemu_opt_get(opts, "label");
1187 if (label) {
1188 size_t label_length = strlen(label);
1189 if (label_length > 11) {
1190 error_setg(errp, "vvfat label cannot be longer than 11 bytes");
1191 ret = -EINVAL;
1192 goto fail;
1193 }
1194 memcpy(s->volume_label, label, label_length);
1195 } else {
1196 memcpy(s->volume_label, "QEMU VVFAT", 10);
1197 }
1198
1199 if (floppy) {
1200
1201 if (!s->fat_type) {
1202 s->fat_type = 12;
1203 secs = 36;
1204 s->sectors_per_cluster = 2;
1205 } else {
1206 secs = s->fat_type == 12 ? 18 : 36;
1207 s->sectors_per_cluster = 1;
1208 }
1209 cyls = 80;
1210 heads = 2;
1211 } else {
1212
1213 if (!s->fat_type) {
1214 s->fat_type = 16;
1215 }
1216 s->offset_to_bootsector = 0x3f;
1217 cyls = s->fat_type == 12 ? 64 : 1024;
1218 heads = 16;
1219 secs = 63;
1220 }
1221
1222 switch (s->fat_type) {
1223 case 32:
1224 warn_report("FAT32 has not been tested. You are welcome to do so!");
1225 break;
1226 case 16:
1227 case 12:
1228 break;
1229 default:
1230 error_setg(errp, "Valid FAT types are only 12, 16 and 32");
1231 ret = -EINVAL;
1232 goto fail;
1233 }
1234
1235
1236 s->bs = bs;
1237
1238
1239 s->sectors_per_cluster=0x10;
1240
1241 s->current_cluster=0xffffffff;
1242
1243 s->qcow = NULL;
1244 s->qcow_filename = NULL;
1245 s->fat2 = NULL;
1246 s->downcase_short_names = 1;
1247
1248 DLOG(fprintf(stderr, "vvfat %s chs %d,%d,%d\n",
1249 dirname, cyls, heads, secs));
1250
1251 s->sector_count = cyls * heads * secs - s->offset_to_bootsector;
1252
1253 if (qemu_opt_get_bool(opts, "rw", false)) {
1254 if (!bdrv_is_read_only(bs)) {
1255 ret = enable_write_target(bs, errp);
1256 if (ret < 0) {
1257 goto fail;
1258 }
1259 } else {
1260 ret = -EPERM;
1261 error_setg(errp,
1262 "Unable to set VVFAT to 'rw' when drive is read-only");
1263 goto fail;
1264 }
1265 } else if (!bdrv_is_read_only(bs)) {
1266 error_report("Opening non-rw vvfat images without an explicit "
1267 "read-only=on option is deprecated. Future versions "
1268 "will refuse to open the image instead of "
1269 "automatically marking the image read-only.");
1270
1271 ret = bdrv_set_read_only(bs, true, &local_err);
1272 if (ret < 0) {
1273 error_propagate(errp, local_err);
1274 goto fail;
1275 }
1276 }
1277
1278 bs->total_sectors = cyls * heads * secs;
1279
1280 if (init_directories(s, dirname, heads, secs, errp)) {
1281 ret = -EIO;
1282 goto fail;
1283 }
1284
1285 s->sector_count = s->offset_to_root_dir
1286 + s->sectors_per_cluster * s->cluster_count;
1287
1288
1289 if (s->qcow) {
1290 error_setg(&s->migration_blocker,
1291 "The vvfat (rw) format used by node '%s' "
1292 "does not support live migration",
1293 bdrv_get_device_or_node_name(bs));
1294 ret = migrate_add_blocker(s->migration_blocker, &local_err);
1295 if (local_err) {
1296 error_propagate(errp, local_err);
1297 error_free(s->migration_blocker);
1298 goto fail;
1299 }
1300 }
1301
1302 if (s->offset_to_bootsector > 0) {
1303 init_mbr(s, cyls, heads, secs);
1304 }
1305
1306 qemu_co_mutex_init(&s->lock);
1307
1308 ret = 0;
1309fail:
1310 qemu_opts_del(opts);
1311 return ret;
1312}
1313
1314static void vvfat_refresh_limits(BlockDriverState *bs, Error **errp)
1315{
1316 bs->bl.request_alignment = BDRV_SECTOR_SIZE;
1317}
1318
1319static inline void vvfat_close_current_file(BDRVVVFATState *s)
1320{
1321 if(s->current_mapping) {
1322 s->current_mapping = NULL;
1323 if (s->current_fd) {
1324 qemu_close(s->current_fd);
1325 s->current_fd = 0;
1326 }
1327 }
1328 s->current_cluster = -1;
1329}
1330
1331
1332
1333
1334static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1335{
1336 while(1) {
1337 int index3;
1338 mapping_t* mapping;
1339 index3=(index1+index2)/2;
1340 mapping=array_get(&(s->mapping),index3);
1341 assert(mapping->begin < mapping->end);
1342 if(mapping->begin>=cluster_num) {
1343 assert(index2!=index3 || index2==0);
1344 if(index2==index3)
1345 return index1;
1346 index2=index3;
1347 } else {
1348 if(index1==index3)
1349 return mapping->end<=cluster_num ? index2 : index1;
1350 index1=index3;
1351 }
1352 assert(index1<=index2);
1353 DLOG(mapping=array_get(&(s->mapping),index1);
1354 assert(mapping->begin<=cluster_num);
1355 assert(index2 >= s->mapping.next ||
1356 ((mapping = array_get(&(s->mapping),index2)) &&
1357 mapping->end>cluster_num)));
1358 }
1359}
1360
1361static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
1362{
1363 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
1364 mapping_t* mapping;
1365 if(index>=s->mapping.next)
1366 return NULL;
1367 mapping=array_get(&(s->mapping),index);
1368 if(mapping->begin>cluster_num)
1369 return NULL;
1370 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
1371 return mapping;
1372}
1373
1374static int open_file(BDRVVVFATState* s,mapping_t* mapping)
1375{
1376 if(!mapping)
1377 return -1;
1378 if(!s->current_mapping ||
1379 strcmp(s->current_mapping->path,mapping->path)) {
1380
1381 int fd = qemu_open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
1382 if(fd<0)
1383 return -1;
1384 vvfat_close_current_file(s);
1385 s->current_fd = fd;
1386 s->current_mapping = mapping;
1387 }
1388 return 0;
1389}
1390
1391static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1392{
1393 if(s->current_cluster != cluster_num) {
1394 int result=0;
1395 off_t offset;
1396 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
1397 if(!s->current_mapping
1398 || s->current_mapping->begin>cluster_num
1399 || s->current_mapping->end<=cluster_num) {
1400
1401 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
1402
1403 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1404
1405 if (mapping && mapping->mode & MODE_DIRECTORY) {
1406 vvfat_close_current_file(s);
1407 s->current_mapping = mapping;
1408read_cluster_directory:
1409 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
1410 s->cluster = (unsigned char*)s->directory.pointer+offset
1411 + 0x20*s->current_mapping->info.dir.first_dir_index;
1412 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1413 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1414 s->current_cluster = cluster_num;
1415 return 0;
1416 }
1417
1418 if(open_file(s,mapping))
1419 return -2;
1420 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1421 goto read_cluster_directory;
1422
1423 assert(s->current_fd);
1424
1425 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
1426 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1427 return -3;
1428 s->cluster=s->cluster_buffer;
1429 result=read(s->current_fd,s->cluster,s->cluster_size);
1430 if(result<0) {
1431 s->current_cluster = -1;
1432 return -1;
1433 }
1434 s->current_cluster = cluster_num;
1435 }
1436 return 0;
1437}
1438
1439#ifdef DEBUG
1440static void print_direntry(const direntry_t* direntry)
1441{
1442 int j = 0;
1443 char buffer[1024];
1444
1445 fprintf(stderr, "direntry %p: ", direntry);
1446 if(!direntry)
1447 return;
1448 if(is_long_name(direntry)) {
1449 unsigned char* c=(unsigned char*)direntry;
1450 int i;
1451 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
1452#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
1453 ADD_CHAR(c[i]);
1454 for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
1455 ADD_CHAR(c[i]);
1456 for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
1457 ADD_CHAR(c[i]);
1458 buffer[j] = 0;
1459 fprintf(stderr, "%s\n", buffer);
1460 } else {
1461 int i;
1462 for(i=0;i<11;i++)
1463 ADD_CHAR(direntry->name[i]);
1464 buffer[j] = 0;
1465 fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1466 buffer,
1467 direntry->attributes,
1468 begin_of_direntry(direntry),le32_to_cpu(direntry->size));
1469 }
1470}
1471
1472static void print_mapping(const mapping_t* mapping)
1473{
1474 fprintf(stderr, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1475 "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1476 mapping, mapping->begin, mapping->end, mapping->dir_index,
1477 mapping->first_mapping_index, mapping->path, mapping->mode);
1478
1479 if (mapping->mode & MODE_DIRECTORY)
1480 fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1481 else
1482 fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
1483}
1484#endif
1485
1486static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
1487 uint8_t *buf, int nb_sectors)
1488{
1489 BDRVVVFATState *s = bs->opaque;
1490 int i;
1491
1492 for(i=0;i<nb_sectors;i++,sector_num++) {
1493 if (sector_num >= bs->total_sectors)
1494 return -1;
1495 if (s->qcow) {
1496 int64_t n;
1497 int ret;
1498 ret = bdrv_is_allocated(s->qcow->bs, sector_num * BDRV_SECTOR_SIZE,
1499 (nb_sectors - i) * BDRV_SECTOR_SIZE, &n);
1500 if (ret < 0) {
1501 return ret;
1502 }
1503 if (ret) {
1504 DLOG(fprintf(stderr, "sectors %" PRId64 "+%" PRId64
1505 " allocated\n", sector_num,
1506 n >> BDRV_SECTOR_BITS));
1507 if (bdrv_read(s->qcow, sector_num, buf + i * 0x200,
1508 n >> BDRV_SECTOR_BITS)) {
1509 return -1;
1510 }
1511 i += (n >> BDRV_SECTOR_BITS) - 1;
1512 sector_num += (n >> BDRV_SECTOR_BITS) - 1;
1513 continue;
1514 }
1515 DLOG(fprintf(stderr, "sector %" PRId64 " not allocated\n",
1516 sector_num));
1517 }
1518 if (sector_num < s->offset_to_root_dir) {
1519 if (sector_num < s->offset_to_fat) {
1520 memcpy(buf + i * 0x200,
1521 &(s->first_sectors[sector_num * 0x200]),
1522 0x200);
1523 } else if (sector_num < s->offset_to_fat + s->sectors_per_fat) {
1524 memcpy(buf + i * 0x200,
1525 &(s->fat.pointer[(sector_num
1526 - s->offset_to_fat) * 0x200]),
1527 0x200);
1528 } else if (sector_num < s->offset_to_root_dir) {
1529 memcpy(buf + i * 0x200,
1530 &(s->fat.pointer[(sector_num - s->offset_to_fat
1531 - s->sectors_per_fat) * 0x200]),
1532 0x200);
1533 }
1534 } else {
1535 uint32_t sector = sector_num - s->offset_to_root_dir,
1536 sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1537 cluster_num=sector/s->sectors_per_cluster;
1538 if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) {
1539
1540 memset(buf+i*0x200,0,0x200);
1541 continue;
1542 }
1543 memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
1544 }
1545 }
1546 return 0;
1547}
1548
1549static int coroutine_fn
1550vvfat_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
1551 QEMUIOVector *qiov, int flags)
1552{
1553 int ret;
1554 BDRVVVFATState *s = bs->opaque;
1555 uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
1556 int nb_sectors = bytes >> BDRV_SECTOR_BITS;
1557 void *buf;
1558
1559 assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
1560 assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
1561
1562 buf = g_try_malloc(bytes);
1563 if (bytes && buf == NULL) {
1564 return -ENOMEM;
1565 }
1566
1567 qemu_co_mutex_lock(&s->lock);
1568 ret = vvfat_read(bs, sector_num, buf, nb_sectors);
1569 qemu_co_mutex_unlock(&s->lock);
1570
1571 qemu_iovec_from_buf(qiov, 0, buf, bytes);
1572 g_free(buf);
1573
1574 return ret;
1575}
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599typedef struct commit_t {
1600 char* path;
1601 union {
1602 struct { uint32_t cluster; } rename;
1603 struct { int dir_index; uint32_t modified_offset; } writeout;
1604 struct { uint32_t first_cluster; } new_file;
1605 struct { uint32_t cluster; } mkdir;
1606 } param;
1607
1608 enum {
1609 ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1610 } action;
1611} commit_t;
1612
1613static void clear_commits(BDRVVVFATState* s)
1614{
1615 int i;
1616DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1617 for (i = 0; i < s->commits.next; i++) {
1618 commit_t* commit = array_get(&(s->commits), i);
1619 assert(commit->path || commit->action == ACTION_WRITEOUT);
1620 if (commit->action != ACTION_WRITEOUT) {
1621 assert(commit->path);
1622 g_free(commit->path);
1623 } else
1624 assert(commit->path == NULL);
1625 }
1626 s->commits.next = 0;
1627}
1628
1629static void schedule_rename(BDRVVVFATState* s,
1630 uint32_t cluster, char* new_path)
1631{
1632 commit_t* commit = array_get_next(&(s->commits));
1633 commit->path = new_path;
1634 commit->param.rename.cluster = cluster;
1635 commit->action = ACTION_RENAME;
1636}
1637
1638static void schedule_writeout(BDRVVVFATState* s,
1639 int dir_index, uint32_t modified_offset)
1640{
1641 commit_t* commit = array_get_next(&(s->commits));
1642 commit->path = NULL;
1643 commit->param.writeout.dir_index = dir_index;
1644 commit->param.writeout.modified_offset = modified_offset;
1645 commit->action = ACTION_WRITEOUT;
1646}
1647
1648static void schedule_new_file(BDRVVVFATState* s,
1649 char* path, uint32_t first_cluster)
1650{
1651 commit_t* commit = array_get_next(&(s->commits));
1652 commit->path = path;
1653 commit->param.new_file.first_cluster = first_cluster;
1654 commit->action = ACTION_NEW_FILE;
1655}
1656
1657static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1658{
1659 commit_t* commit = array_get_next(&(s->commits));
1660 commit->path = path;
1661 commit->param.mkdir.cluster = cluster;
1662 commit->action = ACTION_MKDIR;
1663}
1664
1665typedef struct {
1666
1667
1668
1669
1670
1671 unsigned char name[0x3f * 13 + 1];
1672 gunichar2 name2[0x3f * 13 + 1];
1673 int checksum, len;
1674 int sequence_number;
1675} long_file_name;
1676
1677static void lfn_init(long_file_name* lfn)
1678{
1679 lfn->sequence_number = lfn->len = 0;
1680 lfn->checksum = 0x100;
1681}
1682
1683
1684static int parse_long_name(long_file_name* lfn,
1685 const direntry_t* direntry)
1686{
1687 int i, j, offset;
1688 const unsigned char* pointer = (const unsigned char*)direntry;
1689
1690 if (!is_long_name(direntry))
1691 return 1;
1692
1693 if (pointer[0] & 0x40) {
1694
1695 lfn->sequence_number = pointer[0] & 0x3f;
1696 lfn->checksum = pointer[13];
1697 lfn->name[0] = 0;
1698 lfn->name[lfn->sequence_number * 13] = 0;
1699 } else if ((pointer[0] & 0x3f) != --lfn->sequence_number) {
1700
1701 return -1;
1702 } else if (pointer[13] != lfn->checksum) {
1703
1704 return -2;
1705 } else if (pointer[12] || pointer[26] || pointer[27]) {
1706
1707 return -3;
1708 }
1709
1710 offset = 13 * (lfn->sequence_number - 1);
1711 for (i = 0, j = 1; i < 13; i++, j+=2) {
1712 if (j == 11)
1713 j = 14;
1714 else if (j == 26)
1715 j = 28;
1716
1717 if (pointer[j] == 0 && pointer[j + 1] == 0) {
1718
1719 break;
1720 }
1721 gunichar2 c = (pointer[j + 1] << 8) + pointer[j];
1722 lfn->name2[offset + i] = c;
1723 }
1724
1725 if (pointer[0] & 0x40) {
1726
1727 lfn->len = offset + i;
1728 }
1729 if ((pointer[0] & 0x3f) == 0x01) {
1730
1731 glong olen;
1732 gchar *utf8 = g_utf16_to_utf8(lfn->name2, lfn->len, NULL, &olen, NULL);
1733 if (!utf8) {
1734 return -4;
1735 }
1736 lfn->len = olen;
1737 memcpy(lfn->name, utf8, olen + 1);
1738 g_free(utf8);
1739 }
1740
1741 return 0;
1742}
1743
1744
1745static int parse_short_name(BDRVVVFATState* s,
1746 long_file_name* lfn, direntry_t* direntry)
1747{
1748 int i, j;
1749
1750 if (!is_short_name(direntry))
1751 return 1;
1752
1753 for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1754 for (i = 0; i <= j; i++) {
1755 uint8_t c = direntry->name[i];
1756 if (c != to_valid_short_char(c)) {
1757 return -1;
1758 } else if (s->downcase_short_names) {
1759 lfn->name[i] = qemu_tolower(direntry->name[i]);
1760 } else {
1761 lfn->name[i] = direntry->name[i];
1762 }
1763 }
1764
1765 for (j = 2; j >= 0 && direntry->name[8 + j] == ' '; j--) {
1766 }
1767 if (j >= 0) {
1768 lfn->name[i++] = '.';
1769 lfn->name[i + j + 1] = '\0';
1770 for (;j >= 0; j--) {
1771 uint8_t c = direntry->name[8 + j];
1772 if (c != to_valid_short_char(c)) {
1773 return -2;
1774 } else if (s->downcase_short_names) {
1775 lfn->name[i + j] = qemu_tolower(c);
1776 } else {
1777 lfn->name[i + j] = c;
1778 }
1779 }
1780 } else
1781 lfn->name[i + j + 1] = '\0';
1782
1783 if (lfn->name[0] == DIR_KANJI_FAKE) {
1784 lfn->name[0] = DIR_KANJI;
1785 }
1786 lfn->len = strlen((char*)lfn->name);
1787
1788 return 0;
1789}
1790
1791static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1792 unsigned int cluster)
1793{
1794 if (cluster < s->last_cluster_of_root_directory) {
1795 if (cluster + 1 == s->last_cluster_of_root_directory)
1796 return s->max_fat_value;
1797 else
1798 return cluster + 1;
1799 }
1800
1801 if (s->fat_type==32) {
1802 uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1803 return le32_to_cpu(*entry);
1804 } else if (s->fat_type==16) {
1805 uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1806 return le16_to_cpu(*entry);
1807 } else {
1808 const uint8_t* x=s->fat2+cluster*3/2;
1809 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1810 }
1811}
1812
1813static inline bool cluster_was_modified(BDRVVVFATState *s,
1814 uint32_t cluster_num)
1815{
1816 int was_modified = 0;
1817 int i;
1818
1819 if (s->qcow == NULL) {
1820 return 0;
1821 }
1822
1823 for (i = 0; !was_modified && i < s->sectors_per_cluster; i++) {
1824 was_modified = bdrv_is_allocated(s->qcow->bs,
1825 (cluster2sector(s, cluster_num) +
1826 i) * BDRV_SECTOR_SIZE,
1827 BDRV_SECTOR_SIZE, NULL);
1828 }
1829
1830
1831
1832
1833
1834
1835
1836 return !!was_modified;
1837}
1838
1839static const char* get_basename(const char* path)
1840{
1841 char* basename = strrchr(path, '/');
1842 if (basename == NULL)
1843 return path;
1844 else
1845 return basename + 1;
1846}
1847
1848
1849
1850
1851
1852
1853
1854
1855typedef enum {
1856 USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
1857} used_t;
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
1870 direntry_t* direntry, const char* path)
1871{
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889 int copy_it = 0;
1890 int was_modified = 0;
1891 int32_t ret = 0;
1892
1893 uint32_t cluster_num = begin_of_direntry(direntry);
1894 uint32_t offset = 0;
1895 int first_mapping_index = -1;
1896 mapping_t* mapping = NULL;
1897 const char* basename2 = NULL;
1898
1899 vvfat_close_current_file(s);
1900
1901
1902 if (cluster_num == 0)
1903 return 0;
1904
1905
1906 if (s->qcow) {
1907 basename2 = get_basename(path);
1908
1909 mapping = find_mapping_for_cluster(s, cluster_num);
1910
1911 if (mapping) {
1912 const char* basename;
1913
1914 assert(mapping->mode & MODE_DELETED);
1915 mapping->mode &= ~MODE_DELETED;
1916
1917 basename = get_basename(mapping->path);
1918
1919 assert(mapping->mode & MODE_NORMAL);
1920
1921
1922 if (strcmp(basename, basename2))
1923 schedule_rename(s, cluster_num, g_strdup(path));
1924 } else if (is_file(direntry))
1925
1926 schedule_new_file(s, g_strdup(path), cluster_num);
1927 else {
1928 abort();
1929 return 0;
1930 }
1931 }
1932
1933 while(1) {
1934 if (s->qcow) {
1935 if (!copy_it && cluster_was_modified(s, cluster_num)) {
1936 if (mapping == NULL ||
1937 mapping->begin > cluster_num ||
1938 mapping->end <= cluster_num)
1939 mapping = find_mapping_for_cluster(s, cluster_num);
1940
1941
1942 if (mapping &&
1943 (mapping->mode & MODE_DIRECTORY) == 0) {
1944
1945
1946 if (offset != mapping->info.file.offset + s->cluster_size
1947 * (cluster_num - mapping->begin)) {
1948
1949 abort();
1950 copy_it = 1;
1951 } else if (offset == 0) {
1952 const char* basename = get_basename(mapping->path);
1953
1954 if (strcmp(basename, basename2))
1955 copy_it = 1;
1956 first_mapping_index = array_index(&(s->mapping), mapping);
1957 }
1958
1959 if (mapping->first_mapping_index != first_mapping_index
1960 && mapping->info.file.offset > 0) {
1961 abort();
1962 copy_it = 1;
1963 }
1964
1965
1966 if (!was_modified && is_file(direntry)) {
1967 was_modified = 1;
1968 schedule_writeout(s, mapping->dir_index, offset);
1969 }
1970 }
1971 }
1972
1973 if (copy_it) {
1974 int i;
1975
1976
1977
1978
1979 int64_t offset = cluster2sector(s, cluster_num);
1980
1981 vvfat_close_current_file(s);
1982 for (i = 0; i < s->sectors_per_cluster; i++) {
1983 int res;
1984
1985 res = bdrv_is_allocated(s->qcow->bs,
1986 (offset + i) * BDRV_SECTOR_SIZE,
1987 BDRV_SECTOR_SIZE, NULL);
1988 if (res < 0) {
1989 return -1;
1990 }
1991 if (!res) {
1992 res = vvfat_read(s->bs, offset, s->cluster_buffer, 1);
1993 if (res) {
1994 return -1;
1995 }
1996 res = bdrv_write(s->qcow, offset, s->cluster_buffer, 1);
1997 if (res) {
1998 return -2;
1999 }
2000 }
2001 }
2002 }
2003 }
2004
2005 ret++;
2006 if (s->used_clusters[cluster_num] & USED_ANY)
2007 return 0;
2008 s->used_clusters[cluster_num] = USED_FILE;
2009
2010 cluster_num = modified_fat_get(s, cluster_num);
2011
2012 if (fat_eof(s, cluster_num))
2013 return ret;
2014 else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
2015 return -1;
2016
2017 offset += s->cluster_size;
2018 }
2019}
2020
2021
2022
2023
2024
2025
2026static int check_directory_consistency(BDRVVVFATState *s,
2027 int cluster_num, const char* path)
2028{
2029 int ret = 0;
2030 unsigned char* cluster = g_malloc(s->cluster_size);
2031 direntry_t* direntries = (direntry_t*)cluster;
2032 mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
2033
2034 long_file_name lfn;
2035 int path_len = strlen(path);
2036 char path2[PATH_MAX + 1];
2037
2038 assert(path_len < PATH_MAX);
2039 pstrcpy(path2, sizeof(path2), path);
2040 path2[path_len] = '/';
2041 path2[path_len + 1] = '\0';
2042
2043 if (mapping) {
2044 const char* basename = get_basename(mapping->path);
2045 const char* basename2 = get_basename(path);
2046
2047 assert(mapping->mode & MODE_DIRECTORY);
2048
2049 assert(mapping->mode & MODE_DELETED);
2050 mapping->mode &= ~MODE_DELETED;
2051
2052 if (strcmp(basename, basename2))
2053 schedule_rename(s, cluster_num, g_strdup(path));
2054 } else
2055
2056 schedule_mkdir(s, cluster_num, g_strdup(path));
2057
2058 lfn_init(&lfn);
2059 do {
2060 int i;
2061 int subret = 0;
2062
2063 ret++;
2064
2065 if (s->used_clusters[cluster_num] & USED_ANY) {
2066 fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
2067 goto fail;
2068 }
2069 s->used_clusters[cluster_num] = USED_DIRECTORY;
2070
2071DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
2072 subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
2073 s->sectors_per_cluster);
2074 if (subret) {
2075 fprintf(stderr, "Error fetching direntries\n");
2076 fail:
2077 g_free(cluster);
2078 return 0;
2079 }
2080
2081 for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
2082 int cluster_count = 0;
2083
2084DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i));
2085 if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
2086 is_free(direntries + i))
2087 continue;
2088
2089 subret = parse_long_name(&lfn, direntries + i);
2090 if (subret < 0) {
2091 fprintf(stderr, "Error in long name\n");
2092 goto fail;
2093 }
2094 if (subret == 0 || is_free(direntries + i))
2095 continue;
2096
2097 if (fat_chksum(direntries+i) != lfn.checksum) {
2098 subret = parse_short_name(s, &lfn, direntries + i);
2099 if (subret < 0) {
2100 fprintf(stderr, "Error in short name (%d)\n", subret);
2101 goto fail;
2102 }
2103 if (subret > 0 || !strcmp((char*)lfn.name, ".")
2104 || !strcmp((char*)lfn.name, ".."))
2105 continue;
2106 }
2107 lfn.checksum = 0x100;
2108
2109 if (path_len + 1 + lfn.len >= PATH_MAX) {
2110 fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
2111 goto fail;
2112 }
2113 pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
2114 (char*)lfn.name);
2115
2116 if (is_directory(direntries + i)) {
2117 if (begin_of_direntry(direntries + i) == 0) {
2118 DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
2119 goto fail;
2120 }
2121 cluster_count = check_directory_consistency(s,
2122 begin_of_direntry(direntries + i), path2);
2123 if (cluster_count == 0) {
2124 DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
2125 goto fail;
2126 }
2127 } else if (is_file(direntries + i)) {
2128
2129 cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
2130 if (cluster_count !=
2131 DIV_ROUND_UP(le32_to_cpu(direntries[i].size), s->cluster_size)) {
2132 DLOG(fprintf(stderr, "Cluster count mismatch\n"));
2133 goto fail;
2134 }
2135 } else
2136 abort();
2137
2138 ret += cluster_count;
2139 }
2140
2141 cluster_num = modified_fat_get(s, cluster_num);
2142 } while(!fat_eof(s, cluster_num));
2143
2144 g_free(cluster);
2145 return ret;
2146}
2147
2148
2149static int is_consistent(BDRVVVFATState* s)
2150{
2151 int i, check;
2152 int used_clusters_count = 0;
2153
2154DLOG(checkpoint());
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168 if (s->fat2 == NULL) {
2169 int size = 0x200 * s->sectors_per_fat;
2170 s->fat2 = g_malloc(size);
2171 memcpy(s->fat2, s->fat.pointer, size);
2172 }
2173 check = vvfat_read(s->bs,
2174 s->offset_to_fat, s->fat2, s->sectors_per_fat);
2175 if (check) {
2176 fprintf(stderr, "Could not copy fat\n");
2177 return 0;
2178 }
2179 assert (s->used_clusters);
2180 for (i = 0; i < sector2cluster(s, s->sector_count); i++)
2181 s->used_clusters[i] &= ~USED_ANY;
2182
2183 clear_commits(s);
2184
2185
2186
2187 if (s->qcow)
2188 for (i = 0; i < s->mapping.next; i++) {
2189 mapping_t* mapping = array_get(&(s->mapping), i);
2190 if (mapping->first_mapping_index < 0)
2191 mapping->mode |= MODE_DELETED;
2192 }
2193
2194 used_clusters_count = check_directory_consistency(s, 0, s->path);
2195 if (used_clusters_count <= 0) {
2196 DLOG(fprintf(stderr, "problem in directory\n"));
2197 return 0;
2198 }
2199
2200 check = s->last_cluster_of_root_directory;
2201 for (i = check; i < sector2cluster(s, s->sector_count); i++) {
2202 if (modified_fat_get(s, i)) {
2203 if(!s->used_clusters[i]) {
2204 DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
2205 return 0;
2206 }
2207 check++;
2208 }
2209
2210 if (s->used_clusters[i] == USED_ALLOCATED) {
2211
2212 DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
2213 return 0;
2214 }
2215 }
2216
2217 if (check != used_clusters_count)
2218 return 0;
2219
2220 return used_clusters_count;
2221}
2222
2223static inline void adjust_mapping_indices(BDRVVVFATState* s,
2224 int offset, int adjust)
2225{
2226 int i;
2227
2228 for (i = 0; i < s->mapping.next; i++) {
2229 mapping_t* mapping = array_get(&(s->mapping), i);
2230
2231#define ADJUST_MAPPING_INDEX(name) \
2232 if (mapping->name >= offset) \
2233 mapping->name += adjust
2234
2235 ADJUST_MAPPING_INDEX(first_mapping_index);
2236 if (mapping->mode & MODE_DIRECTORY)
2237 ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
2238 }
2239}
2240
2241
2242static mapping_t* insert_mapping(BDRVVVFATState* s,
2243 uint32_t begin, uint32_t end)
2244{
2245
2246
2247
2248
2249
2250
2251
2252 int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
2253 mapping_t* mapping = NULL;
2254 mapping_t* first_mapping = array_get(&(s->mapping), 0);
2255
2256 if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
2257 && mapping->begin < begin) {
2258 mapping->end = begin;
2259 index++;
2260 mapping = array_get(&(s->mapping), index);
2261 }
2262 if (index >= s->mapping.next || mapping->begin > begin) {
2263 mapping = array_insert(&(s->mapping), index, 1);
2264 mapping->path = NULL;
2265 adjust_mapping_indices(s, index, +1);
2266 }
2267
2268 mapping->begin = begin;
2269 mapping->end = end;
2270
2271DLOG(mapping_t* next_mapping;
2272assert(index + 1 >= s->mapping.next ||
2273((next_mapping = array_get(&(s->mapping), index + 1)) &&
2274 next_mapping->begin >= end)));
2275
2276 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
2277 s->current_mapping = array_get(&(s->mapping),
2278 s->current_mapping - first_mapping);
2279
2280 return mapping;
2281}
2282
2283static int remove_mapping(BDRVVVFATState* s, int mapping_index)
2284{
2285 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
2286 mapping_t* first_mapping = array_get(&(s->mapping), 0);
2287
2288
2289 if (mapping->first_mapping_index < 0) {
2290 g_free(mapping->path);
2291 }
2292
2293
2294 array_remove(&(s->mapping), mapping_index);
2295
2296
2297 adjust_mapping_indices(s, mapping_index, -1);
2298
2299 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
2300 s->current_mapping = array_get(&(s->mapping),
2301 s->current_mapping - first_mapping);
2302
2303 return 0;
2304}
2305
2306static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
2307{
2308 int i;
2309 for (i = 0; i < s->mapping.next; i++) {
2310 mapping_t* mapping = array_get(&(s->mapping), i);
2311 if (mapping->dir_index >= offset)
2312 mapping->dir_index += adjust;
2313 if ((mapping->mode & MODE_DIRECTORY) &&
2314 mapping->info.dir.first_dir_index >= offset)
2315 mapping->info.dir.first_dir_index += adjust;
2316 }
2317}
2318
2319static direntry_t* insert_direntries(BDRVVVFATState* s,
2320 int dir_index, int count)
2321{
2322
2323
2324
2325
2326 direntry_t* result = array_insert(&(s->directory), dir_index, count);
2327 if (result == NULL)
2328 return NULL;
2329 adjust_dirindices(s, dir_index, count);
2330 return result;
2331}
2332
2333static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
2334{
2335 int ret = array_remove_slice(&(s->directory), dir_index, count);
2336 if (ret)
2337 return ret;
2338 adjust_dirindices(s, dir_index, -count);
2339 return 0;
2340}
2341
2342
2343
2344
2345
2346
2347
2348static int commit_mappings(BDRVVVFATState* s,
2349 uint32_t first_cluster, int dir_index)
2350{
2351 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2352 direntry_t* direntry = array_get(&(s->directory), dir_index);
2353 uint32_t cluster = first_cluster;
2354
2355 vvfat_close_current_file(s);
2356
2357 assert(mapping);
2358 assert(mapping->begin == first_cluster);
2359 mapping->first_mapping_index = -1;
2360 mapping->dir_index = dir_index;
2361 mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2362 MODE_DIRECTORY : MODE_NORMAL;
2363
2364 while (!fat_eof(s, cluster)) {
2365 uint32_t c, c1;
2366
2367 for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2368 c = c1, c1 = modified_fat_get(s, c1));
2369
2370 c++;
2371 if (c > mapping->end) {
2372 int index = array_index(&(s->mapping), mapping);
2373 int i, max_i = s->mapping.next - index;
2374 for (i = 1; i < max_i && mapping[i].begin < c; i++);
2375 while (--i > 0)
2376 remove_mapping(s, index + 1);
2377 }
2378 assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2379 || mapping[1].begin >= c);
2380 mapping->end = c;
2381
2382 if (!fat_eof(s, c1)) {
2383 int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2384 mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2385 array_get(&(s->mapping), i);
2386
2387 if (next_mapping == NULL || next_mapping->begin > c1) {
2388 int i1 = array_index(&(s->mapping), mapping);
2389
2390 next_mapping = insert_mapping(s, c1, c1+1);
2391
2392 if (c1 < c)
2393 i1++;
2394 mapping = array_get(&(s->mapping), i1);
2395 }
2396
2397 next_mapping->dir_index = mapping->dir_index;
2398 next_mapping->first_mapping_index =
2399 mapping->first_mapping_index < 0 ?
2400 array_index(&(s->mapping), mapping) :
2401 mapping->first_mapping_index;
2402 next_mapping->path = mapping->path;
2403 next_mapping->mode = mapping->mode;
2404 next_mapping->read_only = mapping->read_only;
2405 if (mapping->mode & MODE_DIRECTORY) {
2406 next_mapping->info.dir.parent_mapping_index =
2407 mapping->info.dir.parent_mapping_index;
2408 next_mapping->info.dir.first_dir_index =
2409 mapping->info.dir.first_dir_index +
2410 0x10 * s->sectors_per_cluster *
2411 (mapping->end - mapping->begin);
2412 } else
2413 next_mapping->info.file.offset = mapping->info.file.offset +
2414 mapping->end - mapping->begin;
2415
2416 mapping = next_mapping;
2417 }
2418
2419 cluster = c1;
2420 }
2421
2422 return 0;
2423}
2424
2425static int commit_direntries(BDRVVVFATState* s,
2426 int dir_index, int parent_mapping_index)
2427{
2428 direntry_t* direntry = array_get(&(s->directory), dir_index);
2429 uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
2430 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2431
2432 int factor = 0x10 * s->sectors_per_cluster;
2433 int old_cluster_count, new_cluster_count;
2434 int current_dir_index = mapping->info.dir.first_dir_index;
2435 int first_dir_index = current_dir_index;
2436 int ret, i;
2437 uint32_t c;
2438
2439DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
2440
2441 assert(direntry);
2442 assert(mapping);
2443 assert(mapping->begin == first_cluster);
2444 assert(mapping->info.dir.first_dir_index < s->directory.next);
2445 assert(mapping->mode & MODE_DIRECTORY);
2446 assert(dir_index == 0 || is_directory(direntry));
2447
2448 mapping->info.dir.parent_mapping_index = parent_mapping_index;
2449
2450 if (first_cluster == 0) {
2451 old_cluster_count = new_cluster_count =
2452 s->last_cluster_of_root_directory;
2453 } else {
2454 for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2455 c = fat_get(s, c))
2456 old_cluster_count++;
2457
2458 for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2459 c = modified_fat_get(s, c))
2460 new_cluster_count++;
2461 }
2462
2463 if (new_cluster_count > old_cluster_count) {
2464 if (insert_direntries(s,
2465 current_dir_index + factor * old_cluster_count,
2466 factor * (new_cluster_count - old_cluster_count)) == NULL)
2467 return -1;
2468 } else if (new_cluster_count < old_cluster_count)
2469 remove_direntries(s,
2470 current_dir_index + factor * new_cluster_count,
2471 factor * (old_cluster_count - new_cluster_count));
2472
2473 for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
2474 direntry_t *first_direntry;
2475 void* direntry = array_get(&(s->directory), current_dir_index);
2476 int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2477 s->sectors_per_cluster);
2478 if (ret)
2479 return ret;
2480
2481
2482 first_direntry = (direntry_t*) s->directory.pointer;
2483 assert(!memcmp(first_direntry->name, s->volume_label, 11));
2484
2485 current_dir_index += factor;
2486 }
2487
2488 ret = commit_mappings(s, first_cluster, dir_index);
2489 if (ret)
2490 return ret;
2491
2492
2493 for (i = 0; i < factor * new_cluster_count; i++) {
2494 direntry = array_get(&(s->directory), first_dir_index + i);
2495 if (is_directory(direntry) && !is_dot(direntry)) {
2496 mapping = find_mapping_for_cluster(s, first_cluster);
2497 assert(mapping->mode & MODE_DIRECTORY);
2498 ret = commit_direntries(s, first_dir_index + i,
2499 array_index(&(s->mapping), mapping));
2500 if (ret)
2501 return ret;
2502 }
2503 }
2504
2505 return 0;
2506}
2507
2508
2509
2510static int commit_one_file(BDRVVVFATState* s,
2511 int dir_index, uint32_t offset)
2512{
2513 direntry_t* direntry = array_get(&(s->directory), dir_index);
2514 uint32_t c = begin_of_direntry(direntry);
2515 uint32_t first_cluster = c;
2516 mapping_t* mapping = find_mapping_for_cluster(s, c);
2517 uint32_t size = filesize_of_direntry(direntry);
2518 char* cluster = g_malloc(s->cluster_size);
2519 uint32_t i;
2520 int fd = 0;
2521
2522 assert(offset < size);
2523 assert((offset % s->cluster_size) == 0);
2524
2525 for (i = s->cluster_size; i < offset; i += s->cluster_size)
2526 c = modified_fat_get(s, c);
2527
2528 fd = qemu_open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
2529 if (fd < 0) {
2530 fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2531 strerror(errno), errno);
2532 g_free(cluster);
2533 return fd;
2534 }
2535 if (offset > 0) {
2536 if (lseek(fd, offset, SEEK_SET) != offset) {
2537 qemu_close(fd);
2538 g_free(cluster);
2539 return -3;
2540 }
2541 }
2542
2543 while (offset < size) {
2544 uint32_t c1;
2545 int rest_size = (size - offset > s->cluster_size ?
2546 s->cluster_size : size - offset);
2547 int ret;
2548
2549 c1 = modified_fat_get(s, c);
2550
2551 assert((size - offset == 0 && fat_eof(s, c)) ||
2552 (size > offset && c >=2 && !fat_eof(s, c)));
2553
2554 ret = vvfat_read(s->bs, cluster2sector(s, c),
2555 (uint8_t*)cluster, DIV_ROUND_UP(rest_size, 0x200));
2556
2557 if (ret < 0) {
2558 qemu_close(fd);
2559 g_free(cluster);
2560 return ret;
2561 }
2562
2563 if (write(fd, cluster, rest_size) < 0) {
2564 qemu_close(fd);
2565 g_free(cluster);
2566 return -2;
2567 }
2568
2569 offset += rest_size;
2570 c = c1;
2571 }
2572
2573 if (ftruncate(fd, size)) {
2574 perror("ftruncate()");
2575 qemu_close(fd);
2576 g_free(cluster);
2577 return -4;
2578 }
2579 qemu_close(fd);
2580 g_free(cluster);
2581
2582 return commit_mappings(s, first_cluster, dir_index);
2583}
2584
2585#ifdef DEBUG
2586
2587static void check1(BDRVVVFATState* s)
2588{
2589 int i;
2590 for (i = 0; i < s->mapping.next; i++) {
2591 mapping_t* mapping = array_get(&(s->mapping), i);
2592 if (mapping->mode & MODE_DELETED) {
2593 fprintf(stderr, "deleted\n");
2594 continue;
2595 }
2596 assert(mapping->dir_index < s->directory.next);
2597 direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2598 assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2599 if (mapping->mode & MODE_DIRECTORY) {
2600 assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2601 assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2602 }
2603 }
2604}
2605
2606
2607static void check2(BDRVVVFATState* s)
2608{
2609 int i;
2610 int first_mapping = -1;
2611
2612 for (i = 0; i < s->directory.next; i++) {
2613 direntry_t* direntry = array_get(&(s->directory), i);
2614
2615 if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2616 mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2617 assert(mapping);
2618 assert(mapping->dir_index == i || is_dot(direntry));
2619 assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2620 }
2621
2622 if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2623
2624 int j, count = 0;
2625
2626 for (j = 0; j < s->mapping.next; j++) {
2627 mapping_t* mapping = array_get(&(s->mapping), j);
2628 if (mapping->mode & MODE_DELETED)
2629 continue;
2630 if (mapping->mode & MODE_DIRECTORY) {
2631 if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2632 assert(++count == 1);
2633 if (mapping->first_mapping_index == -1)
2634 first_mapping = array_index(&(s->mapping), mapping);
2635 else
2636 assert(first_mapping == mapping->first_mapping_index);
2637 if (mapping->info.dir.parent_mapping_index < 0)
2638 assert(j == 0);
2639 else {
2640 mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2641 assert(parent->mode & MODE_DIRECTORY);
2642 assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2643 }
2644 }
2645 }
2646 }
2647 if (count == 0)
2648 first_mapping = -1;
2649 }
2650 }
2651}
2652#endif
2653
2654static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2655{
2656 int i;
2657
2658#ifdef DEBUG
2659 fprintf(stderr, "handle_renames\n");
2660 for (i = 0; i < s->commits.next; i++) {
2661 commit_t* commit = array_get(&(s->commits), i);
2662 fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
2663 }
2664#endif
2665
2666 for (i = 0; i < s->commits.next;) {
2667 commit_t* commit = array_get(&(s->commits), i);
2668 if (commit->action == ACTION_RENAME) {
2669 mapping_t* mapping = find_mapping_for_cluster(s,
2670 commit->param.rename.cluster);
2671 char* old_path = mapping->path;
2672
2673 assert(commit->path);
2674 mapping->path = commit->path;
2675 if (rename(old_path, mapping->path))
2676 return -2;
2677
2678 if (mapping->mode & MODE_DIRECTORY) {
2679 int l1 = strlen(mapping->path);
2680 int l2 = strlen(old_path);
2681 int diff = l1 - l2;
2682 direntry_t* direntry = array_get(&(s->directory),
2683 mapping->info.dir.first_dir_index);
2684 uint32_t c = mapping->begin;
2685 int i = 0;
2686
2687
2688 while (!fat_eof(s, c)) {
2689 do {
2690 direntry_t* d = direntry + i;
2691
2692 if (is_file(d) || (is_directory(d) && !is_dot(d))) {
2693 mapping_t* m = find_mapping_for_cluster(s,
2694 begin_of_direntry(d));
2695 int l = strlen(m->path);
2696 char* new_path = g_malloc(l + diff + 1);
2697
2698 assert(!strncmp(m->path, mapping->path, l2));
2699
2700 pstrcpy(new_path, l + diff + 1, mapping->path);
2701 pstrcpy(new_path + l1, l + diff + 1 - l1,
2702 m->path + l2);
2703
2704 schedule_rename(s, m->begin, new_path);
2705 }
2706 i++;
2707 } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2708 c = fat_get(s, c);
2709 }
2710 }
2711
2712 g_free(old_path);
2713 array_remove(&(s->commits), i);
2714 continue;
2715 } else if (commit->action == ACTION_MKDIR) {
2716 mapping_t* mapping;
2717 int j, parent_path_len;
2718
2719#ifdef __MINGW32__
2720 if (mkdir(commit->path))
2721 return -5;
2722#else
2723 if (mkdir(commit->path, 0755))
2724 return -5;
2725#endif
2726
2727 mapping = insert_mapping(s, commit->param.mkdir.cluster,
2728 commit->param.mkdir.cluster + 1);
2729 if (mapping == NULL)
2730 return -6;
2731
2732 mapping->mode = MODE_DIRECTORY;
2733 mapping->read_only = 0;
2734 mapping->path = commit->path;
2735 j = s->directory.next;
2736 assert(j);
2737 insert_direntries(s, s->directory.next,
2738 0x10 * s->sectors_per_cluster);
2739 mapping->info.dir.first_dir_index = j;
2740
2741 parent_path_len = strlen(commit->path)
2742 - strlen(get_basename(commit->path)) - 1;
2743 for (j = 0; j < s->mapping.next; j++) {
2744 mapping_t* m = array_get(&(s->mapping), j);
2745 if (m->first_mapping_index < 0 && m != mapping &&
2746 !strncmp(m->path, mapping->path, parent_path_len) &&
2747 strlen(m->path) == parent_path_len)
2748 break;
2749 }
2750 assert(j < s->mapping.next);
2751 mapping->info.dir.parent_mapping_index = j;
2752
2753 array_remove(&(s->commits), i);
2754 continue;
2755 }
2756
2757 i++;
2758 }
2759 return 0;
2760}
2761
2762
2763
2764
2765static int handle_commits(BDRVVVFATState* s)
2766{
2767 int i, fail = 0;
2768
2769 vvfat_close_current_file(s);
2770
2771 for (i = 0; !fail && i < s->commits.next; i++) {
2772 commit_t* commit = array_get(&(s->commits), i);
2773 switch(commit->action) {
2774 case ACTION_RENAME: case ACTION_MKDIR:
2775 abort();
2776 fail = -2;
2777 break;
2778 case ACTION_WRITEOUT: {
2779#ifndef NDEBUG
2780
2781 direntry_t* entry = array_get(&(s->directory),
2782 commit->param.writeout.dir_index);
2783 uint32_t begin = begin_of_direntry(entry);
2784 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2785#endif
2786
2787 assert(mapping);
2788 assert(mapping->begin == begin);
2789 assert(commit->path == NULL);
2790
2791 if (commit_one_file(s, commit->param.writeout.dir_index,
2792 commit->param.writeout.modified_offset))
2793 fail = -3;
2794
2795 break;
2796 }
2797 case ACTION_NEW_FILE: {
2798 int begin = commit->param.new_file.first_cluster;
2799 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2800 direntry_t* entry;
2801 int i;
2802
2803
2804 for (i = 0; i < s->directory.next; i++) {
2805 entry = array_get(&(s->directory), i);
2806 if (is_file(entry) && begin_of_direntry(entry) == begin)
2807 break;
2808 }
2809
2810 if (i >= s->directory.next) {
2811 fail = -6;
2812 continue;
2813 }
2814
2815
2816 if (mapping && mapping->begin != begin) {
2817 mapping->end = begin;
2818 mapping = NULL;
2819 }
2820 if (mapping == NULL) {
2821 mapping = insert_mapping(s, begin, begin+1);
2822 }
2823
2824 assert(commit->path);
2825 mapping->path = commit->path;
2826 mapping->read_only = 0;
2827 mapping->mode = MODE_NORMAL;
2828 mapping->info.file.offset = 0;
2829
2830 if (commit_one_file(s, i, 0))
2831 fail = -7;
2832
2833 break;
2834 }
2835 default:
2836 abort();
2837 }
2838 }
2839 if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2840 return -1;
2841 return fail;
2842}
2843
2844static int handle_deletes(BDRVVVFATState* s)
2845{
2846 int i, deferred = 1, deleted = 1;
2847
2848
2849
2850 while (deferred && deleted) {
2851 deferred = 0;
2852 deleted = 0;
2853
2854 for (i = 1; i < s->mapping.next; i++) {
2855 mapping_t* mapping = array_get(&(s->mapping), i);
2856 if (mapping->mode & MODE_DELETED) {
2857 direntry_t* entry = array_get(&(s->directory),
2858 mapping->dir_index);
2859
2860 if (is_free(entry)) {
2861
2862 if (mapping->mode & MODE_DIRECTORY) {
2863 int j, next_dir_index = s->directory.next,
2864 first_dir_index = mapping->info.dir.first_dir_index;
2865
2866 if (rmdir(mapping->path) < 0) {
2867 if (errno == ENOTEMPTY) {
2868 deferred++;
2869 continue;
2870 } else
2871 return -5;
2872 }
2873
2874 for (j = 1; j < s->mapping.next; j++) {
2875 mapping_t* m = array_get(&(s->mapping), j);
2876 if (m->mode & MODE_DIRECTORY &&
2877 m->info.dir.first_dir_index >
2878 first_dir_index &&
2879 m->info.dir.first_dir_index <
2880 next_dir_index)
2881 next_dir_index =
2882 m->info.dir.first_dir_index;
2883 }
2884 remove_direntries(s, first_dir_index,
2885 next_dir_index - first_dir_index);
2886
2887 deleted++;
2888 }
2889 } else {
2890 if (unlink(mapping->path))
2891 return -4;
2892 deleted++;
2893 }
2894 DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2895 remove_mapping(s, i);
2896 }
2897 }
2898 }
2899
2900 return 0;
2901}
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911static int do_commit(BDRVVVFATState* s)
2912{
2913 int ret = 0;
2914
2915
2916 if (s->commits.next == 0)
2917 return 0;
2918
2919 vvfat_close_current_file(s);
2920
2921 ret = handle_renames_and_mkdirs(s);
2922 if (ret) {
2923 fprintf(stderr, "Error handling renames (%d)\n", ret);
2924 abort();
2925 return ret;
2926 }
2927
2928
2929 memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2930
2931
2932 ret = commit_direntries(s, 0, -1);
2933 if (ret) {
2934 fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
2935 abort();
2936 return ret;
2937 }
2938
2939 ret = handle_commits(s);
2940 if (ret) {
2941 fprintf(stderr, "Error handling commits (%d)\n", ret);
2942 abort();
2943 return ret;
2944 }
2945
2946 ret = handle_deletes(s);
2947 if (ret) {
2948 fprintf(stderr, "Error deleting\n");
2949 abort();
2950 return ret;
2951 }
2952
2953 if (s->qcow->bs->drv && s->qcow->bs->drv->bdrv_make_empty) {
2954 s->qcow->bs->drv->bdrv_make_empty(s->qcow->bs);
2955 }
2956
2957 memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2958
2959DLOG(checkpoint());
2960 return 0;
2961}
2962
2963static int try_commit(BDRVVVFATState* s)
2964{
2965 vvfat_close_current_file(s);
2966DLOG(checkpoint());
2967 if(!is_consistent(s))
2968 return -1;
2969 return do_commit(s);
2970}
2971
2972static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
2973 const uint8_t *buf, int nb_sectors)
2974{
2975 BDRVVVFATState *s = bs->opaque;
2976 int i, ret;
2977
2978DLOG(checkpoint());
2979
2980
2981 if (s->qcow == NULL) {
2982 return -EACCES;
2983 }
2984
2985 vvfat_close_current_file(s);
2986
2987
2988
2989
2990
2991
2992 if (sector_num < s->offset_to_fat)
2993 return -1;
2994
2995 for (i = sector2cluster(s, sector_num);
2996 i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
2997 mapping_t* mapping = find_mapping_for_cluster(s, i);
2998 if (mapping) {
2999 if (mapping->read_only) {
3000 fprintf(stderr, "Tried to write to write-protected file %s\n",
3001 mapping->path);
3002 return -1;
3003 }
3004
3005 if (mapping->mode & MODE_DIRECTORY) {
3006 int begin = cluster2sector(s, i);
3007 int end = begin + s->sectors_per_cluster, k;
3008 int dir_index;
3009 const direntry_t* direntries;
3010 long_file_name lfn;
3011
3012 lfn_init(&lfn);
3013
3014 if (begin < sector_num)
3015 begin = sector_num;
3016 if (end > sector_num + nb_sectors)
3017 end = sector_num + nb_sectors;
3018 dir_index = mapping->dir_index +
3019 0x10 * (begin - mapping->begin * s->sectors_per_cluster);
3020 direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
3021
3022 for (k = 0; k < (end - begin) * 0x10; k++) {
3023
3024 if (is_short_name(direntries + k) &&
3025 (direntries[k].attributes & 1)) {
3026 if (memcmp(direntries + k,
3027 array_get(&(s->directory), dir_index + k),
3028 sizeof(direntry_t))) {
3029 warn_report("tried to write to write-protected "
3030 "file");
3031 return -1;
3032 }
3033 }
3034 }
3035 }
3036 i = mapping->end;
3037 } else
3038 i++;
3039 }
3040
3041
3042
3043
3044DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
3045 ret = bdrv_write(s->qcow, sector_num, buf, nb_sectors);
3046 if (ret < 0) {
3047 fprintf(stderr, "Error writing to qcow backend\n");
3048 return ret;
3049 }
3050
3051 for (i = sector2cluster(s, sector_num);
3052 i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
3053 if (i >= 0)
3054 s->used_clusters[i] |= USED_ALLOCATED;
3055
3056DLOG(checkpoint());
3057
3058 try_commit(s);
3059
3060DLOG(checkpoint());
3061 return 0;
3062}
3063
3064static int coroutine_fn
3065vvfat_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
3066 QEMUIOVector *qiov, int flags)
3067{
3068 int ret;
3069 BDRVVVFATState *s = bs->opaque;
3070 uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
3071 int nb_sectors = bytes >> BDRV_SECTOR_BITS;
3072 void *buf;
3073
3074 assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
3075 assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
3076
3077 buf = g_try_malloc(bytes);
3078 if (bytes && buf == NULL) {
3079 return -ENOMEM;
3080 }
3081 qemu_iovec_to_buf(qiov, 0, buf, bytes);
3082
3083 qemu_co_mutex_lock(&s->lock);
3084 ret = vvfat_write(bs, sector_num, buf, nb_sectors);
3085 qemu_co_mutex_unlock(&s->lock);
3086
3087 g_free(buf);
3088
3089 return ret;
3090}
3091
3092static int coroutine_fn vvfat_co_block_status(BlockDriverState *bs,
3093 bool want_zero, int64_t offset,
3094 int64_t bytes, int64_t *n,
3095 int64_t *map,
3096 BlockDriverState **file)
3097{
3098 *n = bytes;
3099 return BDRV_BLOCK_DATA;
3100}
3101
3102static int coroutine_fn
3103write_target_commit(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
3104 QEMUIOVector *qiov, int flags)
3105{
3106 int ret;
3107
3108 BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
3109 qemu_co_mutex_lock(&s->lock);
3110 ret = try_commit(s);
3111 qemu_co_mutex_unlock(&s->lock);
3112
3113 return ret;
3114}
3115
3116static void write_target_close(BlockDriverState *bs) {
3117 BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
3118 bdrv_unref_child(s->bs, s->qcow);
3119 g_free(s->qcow_filename);
3120}
3121
3122static BlockDriver vvfat_write_target = {
3123 .format_name = "vvfat_write_target",
3124 .instance_size = sizeof(void*),
3125 .bdrv_co_pwritev = write_target_commit,
3126 .bdrv_close = write_target_close,
3127};
3128
3129static void vvfat_qcow_options(int *child_flags, QDict *child_options,
3130 int parent_flags, QDict *parent_options)
3131{
3132 qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off");
3133 qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on");
3134}
3135
3136static const BdrvChildRole child_vvfat_qcow = {
3137 .parent_is_bds = true,
3138 .inherit_options = vvfat_qcow_options,
3139};
3140
3141static int enable_write_target(BlockDriverState *bs, Error **errp)
3142{
3143 BDRVVVFATState *s = bs->opaque;
3144 BlockDriver *bdrv_qcow = NULL;
3145 BlockDriverState *backing;
3146 QemuOpts *opts = NULL;
3147 int ret;
3148 int size = sector2cluster(s, s->sector_count);
3149 QDict *options;
3150
3151 s->used_clusters = calloc(size, 1);
3152
3153 array_init(&(s->commits), sizeof(commit_t));
3154
3155 s->qcow_filename = g_malloc(PATH_MAX);
3156 ret = get_tmp_filename(s->qcow_filename, PATH_MAX);
3157 if (ret < 0) {
3158 error_setg_errno(errp, -ret, "can't create temporary file");
3159 goto err;
3160 }
3161
3162 bdrv_qcow = bdrv_find_format("qcow");
3163 if (!bdrv_qcow) {
3164 error_setg(errp, "Failed to locate qcow driver");
3165 ret = -ENOENT;
3166 goto err;
3167 }
3168
3169 opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort);
3170 qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512,
3171 &error_abort);
3172 qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:", &error_abort);
3173
3174 ret = bdrv_create(bdrv_qcow, s->qcow_filename, opts, errp);
3175 qemu_opts_del(opts);
3176 if (ret < 0) {
3177 goto err;
3178 }
3179
3180 options = qdict_new();
3181 qdict_put_str(options, "write-target.driver", "qcow");
3182 s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs,
3183 &child_vvfat_qcow, false, errp);
3184 qobject_unref(options);
3185 if (!s->qcow) {
3186 ret = -EINVAL;
3187 goto err;
3188 }
3189
3190#ifndef _WIN32
3191 unlink(s->qcow_filename);
3192#endif
3193
3194 backing = bdrv_new_open_driver(&vvfat_write_target, NULL, BDRV_O_ALLOW_RDWR,
3195 &error_abort);
3196 *(void**) backing->opaque = s;
3197
3198 bdrv_set_backing_hd(s->bs, backing, &error_abort);
3199 bdrv_unref(backing);
3200
3201 return 0;
3202
3203err:
3204 g_free(s->qcow_filename);
3205 s->qcow_filename = NULL;
3206 return ret;
3207}
3208
3209static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c,
3210 const BdrvChildRole *role,
3211 BlockReopenQueue *reopen_queue,
3212 uint64_t perm, uint64_t shared,
3213 uint64_t *nperm, uint64_t *nshared)
3214{
3215 BDRVVVFATState *s = bs->opaque;
3216
3217 assert(c == s->qcow || role == &child_backing);
3218
3219 if (c == s->qcow) {
3220
3221 *nperm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE;
3222 *nshared = BLK_PERM_WRITE_UNCHANGED;
3223 } else {
3224
3225
3226 *nperm = 0;
3227 *nshared = BLK_PERM_ALL;
3228 }
3229}
3230
3231static void vvfat_close(BlockDriverState *bs)
3232{
3233 BDRVVVFATState *s = bs->opaque;
3234
3235 vvfat_close_current_file(s);
3236 array_free(&(s->fat));
3237 array_free(&(s->directory));
3238 array_free(&(s->mapping));
3239 g_free(s->cluster_buffer);
3240
3241 if (s->qcow) {
3242 migrate_del_blocker(s->migration_blocker);
3243 error_free(s->migration_blocker);
3244 }
3245}
3246
3247static BlockDriver bdrv_vvfat = {
3248 .format_name = "vvfat",
3249 .protocol_name = "fat",
3250 .instance_size = sizeof(BDRVVVFATState),
3251
3252 .bdrv_parse_filename = vvfat_parse_filename,
3253 .bdrv_file_open = vvfat_open,
3254 .bdrv_refresh_limits = vvfat_refresh_limits,
3255 .bdrv_close = vvfat_close,
3256 .bdrv_child_perm = vvfat_child_perm,
3257
3258 .bdrv_co_preadv = vvfat_co_preadv,
3259 .bdrv_co_pwritev = vvfat_co_pwritev,
3260 .bdrv_co_block_status = vvfat_co_block_status,
3261};
3262
3263static void bdrv_vvfat_init(void)
3264{
3265 bdrv_register(&bdrv_vvfat);
3266}
3267
3268block_init(bdrv_vvfat_init);
3269
3270#ifdef DEBUG
3271static void checkpoint(void)
3272{
3273 assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
3274 check1(vvv);
3275 check2(vvv);
3276 assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
3277}
3278#endif
3279