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