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