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