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