• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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__
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 = NULL;
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 < array->next);
97     return array->pointer + index * array->item_size;
98 }
99 
array_ensure_allocated(array_t * array,int index)100 static inline int array_ensure_allocated(array_t* array, int index)
101 {
102     if((index + 1) * array->item_size > array->size) {
103 	int new_size = (index + 32) * array->item_size;
104 	array->pointer = qemu_realloc(array->pointer, new_size);
105 	if (!array->pointer)
106 	    return -1;
107 	array->size = new_size;
108 	array->next = index + 1;
109     }
110 
111     return 0;
112 }
113 
array_get_next(array_t * array)114 static inline void* array_get_next(array_t* array) {
115     unsigned int next = array->next;
116     void* result;
117 
118     if (array_ensure_allocated(array, next) < 0)
119 	return NULL;
120 
121     array->next = next + 1;
122     result = array_get(array, next);
123 
124     return result;
125 }
126 
array_insert(array_t * array,unsigned int index,unsigned int count)127 static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
128     if((array->next+count)*array->item_size>array->size) {
129 	int increment=count*array->item_size;
130 	array->pointer=qemu_realloc(array->pointer,array->size+increment);
131 	if(!array->pointer)
132             return NULL;
133 	array->size+=increment;
134     }
135     memmove(array->pointer+(index+count)*array->item_size,
136 		array->pointer+index*array->item_size,
137 		(array->next-index)*array->item_size);
138     array->next+=count;
139     return array->pointer+index*array->item_size;
140 }
141 
142 /* this performs a "roll", so that the element which was at index_from becomes
143  * index_to, but the order of all other elements is preserved. */
array_roll(array_t * array,int index_to,int index_from,int count)144 static inline int array_roll(array_t* array,int index_to,int index_from,int count)
145 {
146     char* buf;
147     char* from;
148     char* to;
149     int is;
150 
151     if(!array ||
152 	    index_to<0 || index_to>=array->next ||
153 	    index_from<0 || index_from>=array->next)
154 	return -1;
155 
156     if(index_to==index_from)
157 	return 0;
158 
159     is=array->item_size;
160     from=array->pointer+index_from*is;
161     to=array->pointer+index_to*is;
162     buf=qemu_malloc(is*count);
163     memcpy(buf,from,is*count);
164 
165     if(index_to<index_from)
166 	memmove(to+is*count,to,from-to);
167     else
168 	memmove(from,from+is*count,to-from);
169 
170     memcpy(to,buf,is*count);
171 
172     free(buf);
173 
174     return 0;
175 }
176 
array_remove_slice(array_t * array,int index,int count)177 static inline int array_remove_slice(array_t* array,int index, int count)
178 {
179     assert(index >=0);
180     assert(count > 0);
181     assert(index + count <= array->next);
182     if(array_roll(array,array->next-1,index,count))
183 	return -1;
184     array->next -= count;
185     return 0;
186 }
187 
array_remove(array_t * array,int index)188 static int array_remove(array_t* array,int index)
189 {
190     return array_remove_slice(array, index, 1);
191 }
192 
193 /* return the index for a given member */
array_index(array_t * array,void * pointer)194 static int array_index(array_t* array, void* pointer)
195 {
196     size_t offset = (char*)pointer - array->pointer;
197     assert((offset % array->item_size) == 0);
198     assert(offset/array->item_size < array->next);
199     return offset/array->item_size;
200 }
201 
202 /* These structures are used to fake a disk and the VFAT filesystem.
203  * For this reason we need to use __attribute__((packed)). */
204 
205 typedef struct bootsector_t {
206     uint8_t jump[3];
207     uint8_t name[8];
208     uint16_t sector_size;
209     uint8_t sectors_per_cluster;
210     uint16_t reserved_sectors;
211     uint8_t number_of_fats;
212     uint16_t root_entries;
213     uint16_t total_sectors16;
214     uint8_t media_type;
215     uint16_t sectors_per_fat;
216     uint16_t sectors_per_track;
217     uint16_t number_of_heads;
218     uint32_t hidden_sectors;
219     uint32_t total_sectors;
220     union {
221         struct {
222 	    uint8_t drive_number;
223 	    uint8_t current_head;
224 	    uint8_t signature;
225 	    uint32_t id;
226 	    uint8_t volume_label[11];
227 	} __attribute__((packed)) fat16;
228 	struct {
229 	    uint32_t sectors_per_fat;
230 	    uint16_t flags;
231 	    uint8_t major,minor;
232 	    uint32_t first_cluster_of_root_directory;
233 	    uint16_t info_sector;
234 	    uint16_t backup_boot_sector;
235 	    uint16_t ignored;
236 	} __attribute__((packed)) fat32;
237     } u;
238     uint8_t fat_type[8];
239     uint8_t ignored[0x1c0];
240     uint8_t magic[2];
241 } __attribute__((packed)) bootsector_t;
242 
243 typedef struct {
244     uint8_t head;
245     uint8_t sector;
246     uint8_t cylinder;
247 } mbr_chs_t;
248 
249 typedef struct partition_t {
250     uint8_t attributes; /* 0x80 = bootable */
251     mbr_chs_t start_CHS;
252     uint8_t   fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
253     mbr_chs_t end_CHS;
254     uint32_t start_sector_long;
255     uint32_t length_sector_long;
256 } __attribute__((packed)) partition_t;
257 
258 typedef struct mbr_t {
259     uint8_t ignored[0x1b8];
260     uint32_t nt_id;
261     uint8_t ignored2[2];
262     partition_t partition[4];
263     uint8_t magic[2];
264 } __attribute__((packed)) mbr_t;
265 
266 typedef struct direntry_t {
267     uint8_t name[8];
268     uint8_t extension[3];
269     uint8_t attributes;
270     uint8_t reserved[2];
271     uint16_t ctime;
272     uint16_t cdate;
273     uint16_t adate;
274     uint16_t begin_hi;
275     uint16_t mtime;
276     uint16_t mdate;
277     uint16_t begin;
278     uint32_t size;
279 } __attribute__((packed)) direntry_t;
280 
281 /* this structure are used to transparently access the files */
282 
283 typedef struct mapping_t {
284     /* begin is the first cluster, end is the last+1 */
285     uint32_t begin,end;
286     /* as s->directory is growable, no pointer may be used here */
287     unsigned int dir_index;
288     /* the clusters of a file may be in any order; this points to the first */
289     int first_mapping_index;
290     union {
291 	/* offset is
292 	 * - the offset in the file (in clusters) for a file, or
293 	 * - the next cluster of the directory for a directory, and
294 	 * - the address of the buffer for a faked entry
295 	 */
296 	struct {
297 	    uint32_t offset;
298 	} file;
299 	struct {
300 	    int parent_mapping_index;
301 	    int first_dir_index;
302 	} dir;
303     } info;
304     /* path contains the full path, i.e. it always starts with s->path */
305     char* path;
306 
307     enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2,
308 	MODE_DIRECTORY = 4, MODE_FAKED = 8,
309 	MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
310     int read_only;
311 } mapping_t;
312 
313 #ifdef DEBUG
314 static void print_direntry(const struct direntry_t*);
315 static void print_mapping(const struct mapping_t* mapping);
316 #endif
317 
318 /* here begins the real VVFAT driver */
319 
320 typedef struct BDRVVVFATState {
321     BlockDriverState* bs; /* pointer to parent */
322     unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
323     unsigned char first_sectors[0x40*0x200];
324 
325     int fat_type; /* 16 or 32 */
326     array_t fat,directory,mapping;
327 
328     unsigned int cluster_size;
329     unsigned int sectors_per_cluster;
330     unsigned int sectors_per_fat;
331     unsigned int sectors_of_root_directory;
332     uint32_t last_cluster_of_root_directory;
333     unsigned int faked_sectors; /* how many sectors are faked before file data */
334     uint32_t sector_count; /* total number of sectors of the partition */
335     uint32_t cluster_count; /* total number of clusters of this partition */
336     uint32_t max_fat_value;
337 
338     int current_fd;
339     mapping_t* current_mapping;
340     unsigned char* cluster; /* points to current cluster */
341     unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
342     unsigned int current_cluster;
343 
344     /* write support */
345     BlockDriverState* write_target;
346     char* qcow_filename;
347     BlockDriverState* qcow;
348     void* fat2;
349     char* used_clusters;
350     array_t commits;
351     const char* path;
352     int downcase_short_names;
353 } BDRVVVFATState;
354 
355 /* take the sector position spos and convert it to Cylinder/Head/Sector position
356  * if the position is outside the specified geometry, fill maximum value for CHS
357  * and return 1 to signal overflow.
358  */
sector2CHS(BlockDriverState * bs,mbr_chs_t * chs,int spos)359 static int sector2CHS(BlockDriverState* bs, mbr_chs_t * chs, int spos){
360     int head,sector;
361     sector   = spos % (bs->secs);  spos/= bs->secs;
362     head     = spos % (bs->heads); spos/= bs->heads;
363     if(spos >= bs->cyls){
364         /* Overflow,
365         it happens if 32bit sector positions are used, while CHS is only 24bit.
366         Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
367         chs->head     = 0xFF;
368         chs->sector   = 0xFF;
369         chs->cylinder = 0xFF;
370         return 1;
371     }
372     chs->head     = (uint8_t)head;
373     chs->sector   = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
374     chs->cylinder = (uint8_t)spos;
375     return 0;
376 }
377 
init_mbr(BDRVVVFATState * s)378 static void init_mbr(BDRVVVFATState* s)
379 {
380     /* TODO: if the files mbr.img and bootsect.img exist, use them */
381     mbr_t* real_mbr=(mbr_t*)s->first_sectors;
382     partition_t* partition = &(real_mbr->partition[0]);
383     int lba;
384 
385     memset(s->first_sectors,0,512);
386 
387     /* Win NT Disk Signature */
388     real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
389 
390     partition->attributes=0x80; /* bootable */
391 
392     /* LBA is used when partition is outside the CHS geometry */
393     lba = sector2CHS(s->bs, &partition->start_CHS, s->first_sectors_number-1);
394     lba|= sector2CHS(s->bs, &partition->end_CHS,   s->sector_count);
395 
396     /*LBA partitions are identified only by start/length_sector_long not by CHS*/
397     partition->start_sector_long =cpu_to_le32(s->first_sectors_number-1);
398     partition->length_sector_long=cpu_to_le32(s->sector_count - s->first_sectors_number+1);
399 
400     /* FAT12/FAT16/FAT32 */
401     /* DOS uses different types when partition is LBA,
402        probably to prevent older versions from using CHS on them */
403     partition->fs_type= s->fat_type==12 ? 0x1:
404                         s->fat_type==16 ? (lba?0xe:0x06):
405                          /*fat_tyoe==32*/ (lba?0xc:0x0b);
406 
407     real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
408 }
409 
410 /* direntry functions */
411 
412 /* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
short2long_name(char * dest,const char * src)413 static inline int short2long_name(char* dest,const char* src)
414 {
415     int i;
416     int len;
417     for(i=0;i<129 && src[i];i++) {
418         dest[2*i]=src[i];
419 	dest[2*i+1]=0;
420     }
421     len=2*i;
422     dest[2*i]=dest[2*i+1]=0;
423     for(i=2*i+2;(i%26);i++)
424 	dest[i]=0xff;
425     return len;
426 }
427 
create_long_filename(BDRVVVFATState * s,const char * filename)428 static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
429 {
430     char buffer[258];
431     int length=short2long_name(buffer,filename),
432         number_of_entries=(length+25)/26,i;
433     direntry_t* entry;
434 
435     for(i=0;i<number_of_entries;i++) {
436 	entry=array_get_next(&(s->directory));
437 	entry->attributes=0xf;
438 	entry->reserved[0]=0;
439 	entry->begin=0;
440 	entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
441     }
442     for(i=0;i<26*number_of_entries;i++) {
443 	int offset=(i%26);
444 	if(offset<10) offset=1+offset;
445 	else if(offset<22) offset=14+offset-10;
446 	else offset=28+offset-22;
447 	entry=array_get(&(s->directory),s->directory.next-1-(i/26));
448 	entry->name[offset]=buffer[i];
449     }
450     return array_get(&(s->directory),s->directory.next-number_of_entries);
451 }
452 
is_free(const direntry_t * direntry)453 static char is_free(const direntry_t* direntry)
454 {
455     return direntry->name[0]==0xe5 || direntry->name[0]==0x00;
456 }
457 
is_volume_label(const direntry_t * direntry)458 static char is_volume_label(const direntry_t* direntry)
459 {
460     return direntry->attributes == 0x28;
461 }
462 
is_long_name(const direntry_t * direntry)463 static char is_long_name(const direntry_t* direntry)
464 {
465     return direntry->attributes == 0xf;
466 }
467 
is_short_name(const direntry_t * direntry)468 static char is_short_name(const direntry_t* direntry)
469 {
470     return !is_volume_label(direntry) && !is_long_name(direntry)
471 	&& !is_free(direntry);
472 }
473 
is_directory(const direntry_t * direntry)474 static char is_directory(const direntry_t* direntry)
475 {
476     return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
477 }
478 
is_dot(const direntry_t * direntry)479 static inline char is_dot(const direntry_t* direntry)
480 {
481     return is_short_name(direntry) && direntry->name[0] == '.';
482 }
483 
is_file(const direntry_t * direntry)484 static char is_file(const direntry_t* direntry)
485 {
486     return is_short_name(direntry) && !is_directory(direntry);
487 }
488 
begin_of_direntry(const direntry_t * direntry)489 static inline uint32_t begin_of_direntry(const direntry_t* direntry)
490 {
491     return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
492 }
493 
filesize_of_direntry(const direntry_t * direntry)494 static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
495 {
496     return le32_to_cpu(direntry->size);
497 }
498 
set_begin_of_direntry(direntry_t * direntry,uint32_t begin)499 static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
500 {
501     direntry->begin = cpu_to_le16(begin & 0xffff);
502     direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
503 }
504 
505 /* fat functions */
506 
fat_chksum(const direntry_t * entry)507 static inline uint8_t fat_chksum(const direntry_t* entry)
508 {
509     uint8_t chksum=0;
510     int i;
511 
512     for(i=0;i<11;i++) {
513         unsigned char c;
514 
515         c = (i <= 8) ? entry->name[i] : entry->extension[i-8];
516         chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0)) + c;
517     }
518 
519     return chksum;
520 }
521 
522 /* if return_time==0, this returns the fat_date, else the fat_time */
fat_datetime(time_t time,int return_time)523 static uint16_t fat_datetime(time_t time,int return_time) {
524     struct tm* t;
525 #ifdef _WIN32
526     t=localtime(&time); /* this is not thread safe */
527 #else
528     struct tm t1;
529     t = &t1;
530     localtime_r(&time,t);
531 #endif
532     if(return_time)
533 	return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
534     return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
535 }
536 
fat_set(BDRVVVFATState * s,unsigned int cluster,uint32_t value)537 static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
538 {
539     if(s->fat_type==32) {
540 	uint32_t* entry=array_get(&(s->fat),cluster);
541 	*entry=cpu_to_le32(value);
542     } else if(s->fat_type==16) {
543 	uint16_t* entry=array_get(&(s->fat),cluster);
544 	*entry=cpu_to_le16(value&0xffff);
545     } else {
546 	int offset = (cluster*3/2);
547 	unsigned char* p = array_get(&(s->fat), offset);
548         switch (cluster&1) {
549 	case 0:
550 		p[0] = value&0xff;
551 		p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
552 		break;
553 	case 1:
554 		p[0] = (p[0]&0xf) | ((value&0xf)<<4);
555 		p[1] = (value>>4);
556 		break;
557 	}
558     }
559 }
560 
fat_get(BDRVVVFATState * s,unsigned int cluster)561 static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
562 {
563     if(s->fat_type==32) {
564 	uint32_t* entry=array_get(&(s->fat),cluster);
565 	return le32_to_cpu(*entry);
566     } else if(s->fat_type==16) {
567 	uint16_t* entry=array_get(&(s->fat),cluster);
568 	return le16_to_cpu(*entry);
569     } else {
570 	const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
571 	return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
572     }
573 }
574 
fat_eof(BDRVVVFATState * s,uint32_t fat_entry)575 static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
576 {
577     if(fat_entry>s->max_fat_value-8)
578 	return -1;
579     return 0;
580 }
581 
init_fat(BDRVVVFATState * s)582 static inline void init_fat(BDRVVVFATState* s)
583 {
584     if (s->fat_type == 12) {
585 	array_init(&(s->fat),1);
586 	array_ensure_allocated(&(s->fat),
587 		s->sectors_per_fat * 0x200 * 3 / 2 - 1);
588     } else {
589 	array_init(&(s->fat),(s->fat_type==32?4:2));
590 	array_ensure_allocated(&(s->fat),
591 		s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
592     }
593     memset(s->fat.pointer,0,s->fat.size);
594 
595     switch(s->fat_type) {
596 	case 12: s->max_fat_value=0xfff; break;
597 	case 16: s->max_fat_value=0xffff; break;
598 	case 32: s->max_fat_value=0x0fffffff; break;
599 	default: s->max_fat_value=0; /* error... */
600     }
601 
602 }
603 
604 /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
605 /* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
create_short_and_long_name(BDRVVVFATState * s,unsigned int directory_start,const char * filename,int is_dot)606 static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
607 	unsigned int directory_start, const char* filename, int is_dot)
608 {
609     int i,j,long_index=s->directory.next;
610     direntry_t* entry = NULL;
611     direntry_t* entry_long = NULL;
612 
613     if(is_dot) {
614 	entry=array_get_next(&(s->directory));
615 	memset(entry->name,0x20,11);
616 	memcpy(entry->name,filename,strlen(filename));
617 	return entry;
618     }
619 
620     entry_long=create_long_filename(s,filename);
621 
622     i = strlen(filename);
623     for(j = i - 1; j>0  && filename[j]!='.';j--);
624     if (j > 0)
625 	i = (j > 8 ? 8 : j);
626     else if (i > 8)
627 	i = 8;
628 
629     entry=array_get_next(&(s->directory));
630     memset(entry->name,0x20,11);
631     memcpy(entry->name, filename, i);
632 
633     if(j > 0)
634 	for (i = 0; i < 3 && filename[j+1+i]; i++)
635 	    entry->extension[i] = filename[j+1+i];
636 
637     /* upcase & remove unwanted characters */
638     for(i=10;i>=0;i--) {
639 	if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
640 	if(entry->name[i]<=' ' || entry->name[i]>0x7f
641 		|| strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
642 	    entry->name[i]='_';
643         else if(entry->name[i]>='a' && entry->name[i]<='z')
644             entry->name[i]+='A'-'a';
645     }
646 
647     /* mangle duplicates */
648     while(1) {
649 	direntry_t* entry1=array_get(&(s->directory),directory_start);
650 	int j;
651 
652 	for(;entry1<entry;entry1++)
653 	    if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
654 		break; /* found dupe */
655 	if(entry1==entry) /* no dupe found */
656 	    break;
657 
658 	/* use all 8 characters of name */
659 	if(entry->name[7]==' ') {
660 	    int j;
661 	    for(j=6;j>0 && entry->name[j]==' ';j--)
662 		entry->name[j]='~';
663 	}
664 
665 	/* increment number */
666 	for(j=7;j>0 && entry->name[j]=='9';j--)
667 	    entry->name[j]='0';
668 	if(j>0) {
669 	    if(entry->name[j]<'0' || entry->name[j]>'9')
670 	        entry->name[j]='0';
671 	    else
672 	        entry->name[j]++;
673 	}
674     }
675 
676     /* calculate checksum; propagate to long name */
677     if(entry_long) {
678         uint8_t chksum=fat_chksum(entry);
679 
680 	/* calculate anew, because realloc could have taken place */
681 	entry_long=array_get(&(s->directory),long_index);
682 	while(entry_long<entry && is_long_name(entry_long)) {
683 	    entry_long->reserved[1]=chksum;
684 	    entry_long++;
685 	}
686     }
687 
688     return entry;
689 }
690 
691 /*
692  * Read a directory. (the index of the corresponding mapping must be passed).
693  */
read_directory(BDRVVVFATState * s,int mapping_index)694 static int read_directory(BDRVVVFATState* s, int mapping_index)
695 {
696     mapping_t* mapping = array_get(&(s->mapping), mapping_index);
697     direntry_t* direntry;
698     const char* dirname = mapping->path;
699     int first_cluster = mapping->begin;
700     int parent_index = mapping->info.dir.parent_mapping_index;
701     mapping_t* parent_mapping = (mapping_t*)
702         (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL);
703     int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
704 
705     DIR* dir=opendir(dirname);
706     struct dirent* entry;
707     int i;
708 
709     assert(mapping->mode & MODE_DIRECTORY);
710 
711     if(!dir) {
712 	mapping->end = mapping->begin;
713 	return -1;
714     }
715 
716     i = mapping->info.dir.first_dir_index =
717 	    first_cluster == 0 ? 0 : s->directory.next;
718 
719     /* actually read the directory, and allocate the mappings */
720     while((entry=readdir(dir))) {
721 	unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
722         char* buffer;
723 	direntry_t* direntry;
724         struct stat st;
725 	int is_dot=!strcmp(entry->d_name,".");
726 	int is_dotdot=!strcmp(entry->d_name,"..");
727 
728 	if(first_cluster == 0 && (is_dotdot || is_dot))
729 	    continue;
730 
731 	buffer=(char*)qemu_malloc(length);
732 	snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
733 
734 	if(stat(buffer,&st)<0) {
735 	    free(buffer);
736             continue;
737 	}
738 
739 	/* create directory entry for this file */
740 	direntry=create_short_and_long_name(s, i, entry->d_name,
741 		is_dot || is_dotdot);
742 	direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
743 	direntry->reserved[0]=direntry->reserved[1]=0;
744 	direntry->ctime=fat_datetime(st.st_ctime,1);
745 	direntry->cdate=fat_datetime(st.st_ctime,0);
746 	direntry->adate=fat_datetime(st.st_atime,0);
747 	direntry->begin_hi=0;
748 	direntry->mtime=fat_datetime(st.st_mtime,1);
749 	direntry->mdate=fat_datetime(st.st_mtime,0);
750 	if(is_dotdot)
751 	    set_begin_of_direntry(direntry, first_cluster_of_parent);
752 	else if(is_dot)
753 	    set_begin_of_direntry(direntry, first_cluster);
754 	else
755 	    direntry->begin=0; /* do that later */
756         if (st.st_size > 0x7fffffff) {
757 	    fprintf(stderr, "File %s is larger than 2GB\n", buffer);
758 	    free(buffer);
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 
sector2cluster(BDRVVVFATState * s,off_t sector_num)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 
cluster2sector(BDRVVVFATState * s,uint32_t cluster_num)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 
sector_offset_in_cluster(BDRVVVFATState * s,off_t sector_num)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
get_direntry_for_mapping(BDRVVVFATState * s,mapping_t * mapping)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 
init_directories(BDRVVVFATState * s,const char * dirname)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=qemu_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 = qemu_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 
vvfat_open(BlockDriverState * bs,const char * dirname,int flags)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 
vvfat_close_current_file(BDRVVVFATState * s)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  */
find_mapping_for_cluster_aux(BDRVVVFATState * s,int cluster_num,int index1,int index2)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 
find_mapping_for_cluster(BDRVVVFATState * s,int cluster_num)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  */
find_mapping_for_path(BDRVVVFATState * s,const char * path)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 
open_file(BDRVVVFATState * s,mapping_t * mapping)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 
read_cluster(BDRVVVFATState * s,int cluster_num)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
hexdump(const void * address,uint32_t len)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 
print_direntry(const direntry_t * direntry)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 
print_mapping(const mapping_t * mapping)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 
vvfat_read(BlockDriverState * bs,int64_t sector_num,uint8_t * buf,int nb_sectors)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 
clear_commits(BDRVVVFATState * s)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 	    free(commit->path);
1378 	} else
1379 	    assert(commit->path == NULL);
1380     }
1381     s->commits.next = 0;
1382 }
1383 
schedule_rename(BDRVVVFATState * s,uint32_t cluster,char * new_path)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 
schedule_writeout(BDRVVVFATState * s,int dir_index,uint32_t modified_offset)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 
schedule_new_file(BDRVVVFATState * s,char * path,uint32_t first_cluster)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 
schedule_mkdir(BDRVVVFATState * s,uint32_t cluster,char * path)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 
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 	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 */
parse_short_name(BDRVVVFATState * s,long_file_name * lfn,direntry_t * direntry)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 
modified_fat_get(BDRVVVFATState * s,unsigned int cluster)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 
cluster_was_modified(BDRVVVFATState * s,uint32_t cluster_num)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 
get_basename(const char * path)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  */
get_cluster_count_for_direntry(BDRVVVFATState * s,direntry_t * direntry,const char * path)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, qemu_strdup(path));
1641 	} else if (is_file(direntry))
1642 	    /* new file */
1643 	    schedule_new_file(s, qemu_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  */
check_directory_consistency(BDRVVVFATState * s,int cluster_num,const char * path)1733 static int check_directory_consistency(BDRVVVFATState *s,
1734 	int cluster_num, const char* path)
1735 {
1736     int ret = 0;
1737     unsigned char* cluster = qemu_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, qemu_strdup(path));
1761     } else
1762 	/* new directory */
1763 	schedule_mkdir(s, cluster_num, qemu_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 	    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     free(cluster);
1853     return ret;
1854 }
1855 
1856 /* returns 1 on success */
is_consistent(BDRVVVFATState * s)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 = qemu_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 
adjust_mapping_indices(BDRVVVFATState * s,int offset,int adjust)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 */
insert_mapping(BDRVVVFATState * s,uint32_t begin,uint32_t end)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 
remove_mapping(BDRVVVFATState * s,int mapping_index)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 	free(mapping->path);
1999 
2000     /* remove from s->mapping */
2001     array_remove(&(s->mapping), mapping_index);
2002 
2003     /* adjust all references to mappings */
2004     adjust_mapping_indices(s, mapping_index, -1);
2005 
2006     if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
2007 	s->current_mapping = array_get(&(s->mapping),
2008 		s->current_mapping - first_mapping);
2009 
2010     return 0;
2011 }
2012 
adjust_dirindices(BDRVVVFATState * s,int offset,int adjust)2013 static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
2014 {
2015     int i;
2016     for (i = 0; i < s->mapping.next; i++) {
2017 	mapping_t* mapping = array_get(&(s->mapping), i);
2018 	if (mapping->dir_index >= offset)
2019 	    mapping->dir_index += adjust;
2020 	if ((mapping->mode & MODE_DIRECTORY) &&
2021 		mapping->info.dir.first_dir_index >= offset)
2022 	    mapping->info.dir.first_dir_index += adjust;
2023     }
2024 }
2025 
insert_direntries(BDRVVVFATState * s,int dir_index,int count)2026 static direntry_t* insert_direntries(BDRVVVFATState* s,
2027 	int dir_index, int count)
2028 {
2029     /*
2030      * make room in s->directory,
2031      * adjust_dirindices
2032      */
2033     direntry_t* result = array_insert(&(s->directory), dir_index, count);
2034     if (result == NULL)
2035 	return NULL;
2036     adjust_dirindices(s, dir_index, count);
2037     return result;
2038 }
2039 
remove_direntries(BDRVVVFATState * s,int dir_index,int count)2040 static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
2041 {
2042     int ret = array_remove_slice(&(s->directory), dir_index, count);
2043     if (ret)
2044 	return ret;
2045     adjust_dirindices(s, dir_index, -count);
2046     return 0;
2047 }
2048 
2049 /*
2050  * Adapt the mappings of the cluster chain starting at first cluster
2051  * (i.e. if a file starts at first_cluster, the chain is followed according
2052  * to the modified fat, and the corresponding entries in s->mapping are
2053  * adjusted)
2054  */
commit_mappings(BDRVVVFATState * s,uint32_t first_cluster,int dir_index)2055 static int commit_mappings(BDRVVVFATState* s,
2056 	uint32_t first_cluster, int dir_index)
2057 {
2058     mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2059     direntry_t* direntry = array_get(&(s->directory), dir_index);
2060     uint32_t cluster = first_cluster;
2061 
2062     vvfat_close_current_file(s);
2063 
2064     assert(mapping);
2065     assert(mapping->begin == first_cluster);
2066     mapping->first_mapping_index = -1;
2067     mapping->dir_index = dir_index;
2068     mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2069 	MODE_DIRECTORY : MODE_NORMAL;
2070 
2071     while (!fat_eof(s, cluster)) {
2072 	uint32_t c, c1;
2073 
2074 	for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2075 		c = c1, c1 = modified_fat_get(s, c1));
2076 
2077 	c++;
2078 	if (c > mapping->end) {
2079 	    int index = array_index(&(s->mapping), mapping);
2080 	    int i, max_i = s->mapping.next - index;
2081 	    for (i = 1; i < max_i && mapping[i].begin < c; i++);
2082 	    while (--i > 0)
2083 		remove_mapping(s, index + 1);
2084 	}
2085 	assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2086 		|| mapping[1].begin >= c);
2087 	mapping->end = c;
2088 
2089 	if (!fat_eof(s, c1)) {
2090 	    int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2091 	    mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2092 		array_get(&(s->mapping), i);
2093 
2094 	    if (next_mapping == NULL || next_mapping->begin > c1) {
2095 		int i1 = array_index(&(s->mapping), mapping);
2096 
2097 		next_mapping = insert_mapping(s, c1, c1+1);
2098 
2099 		if (c1 < c)
2100 		    i1++;
2101 		mapping = array_get(&(s->mapping), i1);
2102 	    }
2103 
2104 	    next_mapping->dir_index = mapping->dir_index;
2105 	    next_mapping->first_mapping_index =
2106 		mapping->first_mapping_index < 0 ?
2107 		array_index(&(s->mapping), mapping) :
2108 		mapping->first_mapping_index;
2109 	    next_mapping->path = mapping->path;
2110 	    next_mapping->mode = mapping->mode;
2111 	    next_mapping->read_only = mapping->read_only;
2112 	    if (mapping->mode & MODE_DIRECTORY) {
2113 		next_mapping->info.dir.parent_mapping_index =
2114 			mapping->info.dir.parent_mapping_index;
2115 		next_mapping->info.dir.first_dir_index =
2116 			mapping->info.dir.first_dir_index +
2117 			0x10 * s->sectors_per_cluster *
2118 			(mapping->end - mapping->begin);
2119 	    } else
2120 		next_mapping->info.file.offset = mapping->info.file.offset +
2121 			mapping->end - mapping->begin;
2122 
2123 	    mapping = next_mapping;
2124 	}
2125 
2126 	cluster = c1;
2127     }
2128 
2129     return 0;
2130 }
2131 
commit_direntries(BDRVVVFATState * s,int dir_index,int parent_mapping_index)2132 static int commit_direntries(BDRVVVFATState* s,
2133 	int dir_index, int parent_mapping_index)
2134 {
2135     direntry_t* direntry = array_get(&(s->directory), dir_index);
2136     uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
2137     mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2138 
2139     int factor = 0x10 * s->sectors_per_cluster;
2140     int old_cluster_count, new_cluster_count;
2141     int current_dir_index = mapping->info.dir.first_dir_index;
2142     int first_dir_index = current_dir_index;
2143     int ret, i;
2144     uint32_t c;
2145 
2146 DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
2147 
2148     assert(direntry);
2149     assert(mapping);
2150     assert(mapping->begin == first_cluster);
2151     assert(mapping->info.dir.first_dir_index < s->directory.next);
2152     assert(mapping->mode & MODE_DIRECTORY);
2153     assert(dir_index == 0 || is_directory(direntry));
2154 
2155     mapping->info.dir.parent_mapping_index = parent_mapping_index;
2156 
2157     if (first_cluster == 0) {
2158 	old_cluster_count = new_cluster_count =
2159 	    s->last_cluster_of_root_directory;
2160     } else {
2161 	for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2162 		c = fat_get(s, c))
2163 	    old_cluster_count++;
2164 
2165 	for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2166 		c = modified_fat_get(s, c))
2167 	    new_cluster_count++;
2168     }
2169 
2170     if (new_cluster_count > old_cluster_count) {
2171 	if (insert_direntries(s,
2172 		current_dir_index + factor * old_cluster_count,
2173 		factor * (new_cluster_count - old_cluster_count)) == NULL)
2174 	    return -1;
2175     } else if (new_cluster_count < old_cluster_count)
2176 	remove_direntries(s,
2177 		current_dir_index + factor * new_cluster_count,
2178 		factor * (old_cluster_count - new_cluster_count));
2179 
2180     for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
2181 	void* direntry = array_get(&(s->directory), current_dir_index);
2182 	int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2183 		s->sectors_per_cluster);
2184 	if (ret)
2185 	    return ret;
2186 	assert(!strncmp(s->directory.pointer, "QEMU", 4));
2187 	current_dir_index += factor;
2188     }
2189 
2190     ret = commit_mappings(s, first_cluster, dir_index);
2191     if (ret)
2192 	return ret;
2193 
2194     /* recurse */
2195     for (i = 0; i < factor * new_cluster_count; i++) {
2196 	direntry = array_get(&(s->directory), first_dir_index + i);
2197 	if (is_directory(direntry) && !is_dot(direntry)) {
2198 	    mapping = find_mapping_for_cluster(s, first_cluster);
2199 	    assert(mapping->mode & MODE_DIRECTORY);
2200 	    ret = commit_direntries(s, first_dir_index + i,
2201 		array_index(&(s->mapping), mapping));
2202 	    if (ret)
2203 		return ret;
2204 	}
2205     }
2206 
2207     return 0;
2208 }
2209 
2210 /* commit one file (adjust contents, adjust mapping),
2211    return first_mapping_index */
commit_one_file(BDRVVVFATState * s,int dir_index,uint32_t offset)2212 static int commit_one_file(BDRVVVFATState* s,
2213 	int dir_index, uint32_t offset)
2214 {
2215     direntry_t* direntry = array_get(&(s->directory), dir_index);
2216     uint32_t c = begin_of_direntry(direntry);
2217     uint32_t first_cluster = c;
2218     mapping_t* mapping = find_mapping_for_cluster(s, c);
2219     uint32_t size = filesize_of_direntry(direntry);
2220     char* cluster = qemu_malloc(s->cluster_size);
2221     uint32_t i;
2222     int fd = 0;
2223 
2224     assert(offset < size);
2225     assert((offset % s->cluster_size) == 0);
2226 
2227     for (i = s->cluster_size; i < offset; i += s->cluster_size)
2228 	c = modified_fat_get(s, c);
2229 
2230     fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
2231     if (fd < 0) {
2232 	fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2233 		strerror(errno), errno);
2234 	return fd;
2235     }
2236     if (offset > 0)
2237 	if (lseek(fd, offset, SEEK_SET) != offset)
2238 	    return -3;
2239 
2240     while (offset < size) {
2241 	uint32_t c1;
2242 	int rest_size = (size - offset > s->cluster_size ?
2243 		s->cluster_size : size - offset);
2244 	int ret;
2245 
2246 	c1 = modified_fat_get(s, c);
2247 
2248 	assert((size - offset == 0 && fat_eof(s, c)) ||
2249 		(size > offset && c >=2 && !fat_eof(s, c)));
2250 
2251 	ret = vvfat_read(s->bs, cluster2sector(s, c),
2252 	    (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
2253 
2254 	if (ret < 0)
2255 	    return ret;
2256 
2257 	if (write(fd, cluster, rest_size) < 0)
2258 	    return -2;
2259 
2260 	offset += rest_size;
2261 	c = c1;
2262     }
2263 
2264     if (ftruncate(fd, size)) {
2265         perror("ftruncate()");
2266         close(fd);
2267         return -4;
2268     }
2269     close(fd);
2270 
2271     return commit_mappings(s, first_cluster, dir_index);
2272 }
2273 
2274 #ifdef DEBUG
2275 /* test, if all mappings point to valid direntries */
check1(BDRVVVFATState * s)2276 static void check1(BDRVVVFATState* s)
2277 {
2278     int i;
2279     for (i = 0; i < s->mapping.next; i++) {
2280 	mapping_t* mapping = array_get(&(s->mapping), i);
2281 	if (mapping->mode & MODE_DELETED) {
2282 	    fprintf(stderr, "deleted\n");
2283 	    continue;
2284 	}
2285 	assert(mapping->dir_index >= 0);
2286 	assert(mapping->dir_index < s->directory.next);
2287 	direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2288 	assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2289 	if (mapping->mode & MODE_DIRECTORY) {
2290 	    assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2291 	    assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2292 	}
2293     }
2294 }
2295 
2296 /* test, if all direntries have mappings */
check2(BDRVVVFATState * s)2297 static void check2(BDRVVVFATState* s)
2298 {
2299     int i;
2300     int first_mapping = -1;
2301 
2302     for (i = 0; i < s->directory.next; i++) {
2303 	direntry_t* direntry = array_get(&(s->directory), i);
2304 
2305 	if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2306 	    mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2307 	    assert(mapping);
2308 	    assert(mapping->dir_index == i || is_dot(direntry));
2309 	    assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2310 	}
2311 
2312 	if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2313 	    /* cluster start */
2314 	    int j, count = 0;
2315 
2316 	    for (j = 0; j < s->mapping.next; j++) {
2317 		mapping_t* mapping = array_get(&(s->mapping), j);
2318 		if (mapping->mode & MODE_DELETED)
2319 		    continue;
2320 		if (mapping->mode & MODE_DIRECTORY) {
2321 		    if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2322 			assert(++count == 1);
2323 			if (mapping->first_mapping_index == -1)
2324 			    first_mapping = array_index(&(s->mapping), mapping);
2325 			else
2326 			    assert(first_mapping == mapping->first_mapping_index);
2327 			if (mapping->info.dir.parent_mapping_index < 0)
2328 			    assert(j == 0);
2329 			else {
2330 			    mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2331 			    assert(parent->mode & MODE_DIRECTORY);
2332 			    assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2333 			}
2334 		    }
2335 		}
2336 	    }
2337 	    if (count == 0)
2338 		first_mapping = -1;
2339 	}
2340     }
2341 }
2342 #endif
2343 
handle_renames_and_mkdirs(BDRVVVFATState * s)2344 static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2345 {
2346     int i;
2347 
2348 #ifdef DEBUG
2349     fprintf(stderr, "handle_renames\n");
2350     for (i = 0; i < s->commits.next; i++) {
2351 	commit_t* commit = array_get(&(s->commits), i);
2352 	fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
2353     }
2354 #endif
2355 
2356     for (i = 0; i < s->commits.next;) {
2357 	commit_t* commit = array_get(&(s->commits), i);
2358 	if (commit->action == ACTION_RENAME) {
2359 	    mapping_t* mapping = find_mapping_for_cluster(s,
2360 		    commit->param.rename.cluster);
2361 	    char* old_path = mapping->path;
2362 
2363 	    assert(commit->path);
2364 	    mapping->path = commit->path;
2365 	    if (rename(old_path, mapping->path))
2366 		return -2;
2367 
2368 	    if (mapping->mode & MODE_DIRECTORY) {
2369 		int l1 = strlen(mapping->path);
2370 		int l2 = strlen(old_path);
2371 		int diff = l1 - l2;
2372 		direntry_t* direntry = array_get(&(s->directory),
2373 			mapping->info.dir.first_dir_index);
2374 		uint32_t c = mapping->begin;
2375 		int i = 0;
2376 
2377 		/* recurse */
2378 		while (!fat_eof(s, c)) {
2379 		    do {
2380 			direntry_t* d = direntry + i;
2381 
2382 			if (is_file(d) || (is_directory(d) && !is_dot(d))) {
2383 			    mapping_t* m = find_mapping_for_cluster(s,
2384 				    begin_of_direntry(d));
2385 			    int l = strlen(m->path);
2386 			    char* new_path = qemu_malloc(l + diff + 1);
2387 
2388 			    assert(!strncmp(m->path, mapping->path, l2));
2389 
2390                             pstrcpy(new_path, l + diff + 1, mapping->path);
2391                             pstrcpy(new_path + l1, l + diff + 1 - l1,
2392                                     m->path + l2);
2393 
2394 			    schedule_rename(s, m->begin, new_path);
2395 			}
2396 			i++;
2397 		    } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2398 		    c = fat_get(s, c);
2399 		}
2400 	    }
2401 
2402 	    free(old_path);
2403 	    array_remove(&(s->commits), i);
2404 	    continue;
2405 	} else if (commit->action == ACTION_MKDIR) {
2406 	    mapping_t* mapping;
2407 	    int j, parent_path_len;
2408 
2409 #ifdef __MINGW32__
2410             if (mkdir(commit->path))
2411                 return -5;
2412 #else
2413             if (mkdir(commit->path, 0755))
2414                 return -5;
2415 #endif
2416 
2417 	    mapping = insert_mapping(s, commit->param.mkdir.cluster,
2418 		    commit->param.mkdir.cluster + 1);
2419 	    if (mapping == NULL)
2420 		return -6;
2421 
2422 	    mapping->mode = MODE_DIRECTORY;
2423 	    mapping->read_only = 0;
2424 	    mapping->path = commit->path;
2425 	    j = s->directory.next;
2426 	    assert(j);
2427 	    insert_direntries(s, s->directory.next,
2428 		    0x10 * s->sectors_per_cluster);
2429 	    mapping->info.dir.first_dir_index = j;
2430 
2431 	    parent_path_len = strlen(commit->path)
2432 		- strlen(get_basename(commit->path)) - 1;
2433 	    for (j = 0; j < s->mapping.next; j++) {
2434 		mapping_t* m = array_get(&(s->mapping), j);
2435 		if (m->first_mapping_index < 0 && m != mapping &&
2436 			!strncmp(m->path, mapping->path, parent_path_len) &&
2437 			strlen(m->path) == parent_path_len)
2438 		    break;
2439 	    }
2440 	    assert(j < s->mapping.next);
2441 	    mapping->info.dir.parent_mapping_index = j;
2442 
2443 	    array_remove(&(s->commits), i);
2444 	    continue;
2445 	}
2446 
2447 	i++;
2448     }
2449     return 0;
2450 }
2451 
2452 /*
2453  * TODO: make sure that the short name is not matching *another* file
2454  */
handle_commits(BDRVVVFATState * s)2455 static int handle_commits(BDRVVVFATState* s)
2456 {
2457     int i, fail = 0;
2458 
2459     vvfat_close_current_file(s);
2460 
2461     for (i = 0; !fail && i < s->commits.next; i++) {
2462 	commit_t* commit = array_get(&(s->commits), i);
2463 	switch(commit->action) {
2464 	case ACTION_RENAME: case ACTION_MKDIR:
2465             abort();
2466 	    fail = -2;
2467 	    break;
2468 	case ACTION_WRITEOUT: {
2469 #ifndef NDEBUG
2470             /* these variables are only used by assert() below */
2471 	    direntry_t* entry = array_get(&(s->directory),
2472 		    commit->param.writeout.dir_index);
2473 	    uint32_t begin = begin_of_direntry(entry);
2474 	    mapping_t* mapping = find_mapping_for_cluster(s, begin);
2475 #endif
2476 
2477 	    assert(mapping);
2478 	    assert(mapping->begin == begin);
2479 	    assert(commit->path == NULL);
2480 
2481 	    if (commit_one_file(s, commit->param.writeout.dir_index,
2482 			commit->param.writeout.modified_offset))
2483 		fail = -3;
2484 
2485 	    break;
2486 	}
2487 	case ACTION_NEW_FILE: {
2488 	    int begin = commit->param.new_file.first_cluster;
2489 	    mapping_t* mapping = find_mapping_for_cluster(s, begin);
2490 	    direntry_t* entry;
2491 	    int i;
2492 
2493 	    /* find direntry */
2494 	    for (i = 0; i < s->directory.next; i++) {
2495 		entry = array_get(&(s->directory), i);
2496 		if (is_file(entry) && begin_of_direntry(entry) == begin)
2497 		    break;
2498 	    }
2499 
2500 	    if (i >= s->directory.next) {
2501 		fail = -6;
2502 		continue;
2503 	    }
2504 
2505 	    /* make sure there exists an initial mapping */
2506 	    if (mapping && mapping->begin != begin) {
2507 		mapping->end = begin;
2508 		mapping = NULL;
2509 	    }
2510 	    if (mapping == NULL) {
2511 		mapping = insert_mapping(s, begin, begin+1);
2512 	    }
2513 	    /* most members will be fixed in commit_mappings() */
2514 	    assert(commit->path);
2515 	    mapping->path = commit->path;
2516 	    mapping->read_only = 0;
2517 	    mapping->mode = MODE_NORMAL;
2518 	    mapping->info.file.offset = 0;
2519 
2520 	    if (commit_one_file(s, i, 0))
2521 		fail = -7;
2522 
2523 	    break;
2524 	}
2525 	default:
2526             abort();
2527 	}
2528     }
2529     if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2530 	return -1;
2531     return fail;
2532 }
2533 
handle_deletes(BDRVVVFATState * s)2534 static int handle_deletes(BDRVVVFATState* s)
2535 {
2536     int i, deferred = 1, deleted = 1;
2537 
2538     /* delete files corresponding to mappings marked as deleted */
2539     /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2540     while (deferred && deleted) {
2541 	deferred = 0;
2542 	deleted = 0;
2543 
2544 	for (i = 1; i < s->mapping.next; i++) {
2545 	    mapping_t* mapping = array_get(&(s->mapping), i);
2546 	    if (mapping->mode & MODE_DELETED) {
2547 		direntry_t* entry = array_get(&(s->directory),
2548 			mapping->dir_index);
2549 
2550 		if (is_free(entry)) {
2551 		    /* remove file/directory */
2552 		    if (mapping->mode & MODE_DIRECTORY) {
2553 			int j, next_dir_index = s->directory.next,
2554 			first_dir_index = mapping->info.dir.first_dir_index;
2555 
2556 			if (rmdir(mapping->path) < 0) {
2557 			    if (errno == ENOTEMPTY) {
2558 				deferred++;
2559 				continue;
2560 			    } else
2561 				return -5;
2562 			}
2563 
2564 			for (j = 1; j < s->mapping.next; j++) {
2565 			    mapping_t* m = array_get(&(s->mapping), j);
2566 			    if (m->mode & MODE_DIRECTORY &&
2567 				    m->info.dir.first_dir_index >
2568 				    first_dir_index &&
2569 				    m->info.dir.first_dir_index <
2570 				    next_dir_index)
2571 				next_dir_index =
2572 				    m->info.dir.first_dir_index;
2573 			}
2574 			remove_direntries(s, first_dir_index,
2575 				next_dir_index - first_dir_index);
2576 
2577 			deleted++;
2578 		    }
2579 		} else {
2580 		    if (unlink(mapping->path))
2581 			return -4;
2582 		    deleted++;
2583 		}
2584 		DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2585 		remove_mapping(s, i);
2586 	    }
2587 	}
2588     }
2589 
2590     return 0;
2591 }
2592 
2593 /*
2594  * synchronize mapping with new state:
2595  *
2596  * - copy FAT (with bdrv_read)
2597  * - mark all filenames corresponding to mappings as deleted
2598  * - recurse direntries from root (using bs->bdrv_read)
2599  * - delete files corresponding to mappings marked as deleted
2600  */
do_commit(BDRVVVFATState * s)2601 static int do_commit(BDRVVVFATState* s)
2602 {
2603     int ret = 0;
2604 
2605     /* the real meat are the commits. Nothing to do? Move along! */
2606     if (s->commits.next == 0)
2607 	return 0;
2608 
2609     vvfat_close_current_file(s);
2610 
2611     ret = handle_renames_and_mkdirs(s);
2612     if (ret) {
2613 	fprintf(stderr, "Error handling renames (%d)\n", ret);
2614         abort();
2615 	return ret;
2616     }
2617 
2618     /* copy FAT (with bdrv_read) */
2619     memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2620 
2621     /* recurse direntries from root (using bs->bdrv_read) */
2622     ret = commit_direntries(s, 0, -1);
2623     if (ret) {
2624 	fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
2625         abort();
2626 	return ret;
2627     }
2628 
2629     ret = handle_commits(s);
2630     if (ret) {
2631 	fprintf(stderr, "Error handling commits (%d)\n", ret);
2632         abort();
2633 	return ret;
2634     }
2635 
2636     ret = handle_deletes(s);
2637     if (ret) {
2638 	fprintf(stderr, "Error deleting\n");
2639         abort();
2640 	return ret;
2641     }
2642 
2643     s->qcow->drv->bdrv_make_empty(s->qcow);
2644 
2645     memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2646 
2647 DLOG(checkpoint());
2648     return 0;
2649 }
2650 
try_commit(BDRVVVFATState * s)2651 static int try_commit(BDRVVVFATState* s)
2652 {
2653     vvfat_close_current_file(s);
2654 DLOG(checkpoint());
2655     if(!is_consistent(s))
2656 	return -1;
2657     return do_commit(s);
2658 }
2659 
vvfat_write(BlockDriverState * bs,int64_t sector_num,const uint8_t * buf,int nb_sectors)2660 static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
2661                     const uint8_t *buf, int nb_sectors)
2662 {
2663     BDRVVVFATState *s = bs->opaque;
2664     int i, ret;
2665 
2666 DLOG(checkpoint());
2667 
2668     vvfat_close_current_file(s);
2669 
2670     /*
2671      * Some sanity checks:
2672      * - do not allow writing to the boot sector
2673      * - do not allow to write non-ASCII filenames
2674      */
2675 
2676     if (sector_num < s->first_sectors_number)
2677 	return -1;
2678 
2679     for (i = sector2cluster(s, sector_num);
2680 	    i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
2681 	mapping_t* mapping = find_mapping_for_cluster(s, i);
2682 	if (mapping) {
2683 	    if (mapping->read_only) {
2684 		fprintf(stderr, "Tried to write to write-protected file %s\n",
2685 			mapping->path);
2686 		return -1;
2687 	    }
2688 
2689 	    if (mapping->mode & MODE_DIRECTORY) {
2690 		int begin = cluster2sector(s, i);
2691 		int end = begin + s->sectors_per_cluster, k;
2692 		int dir_index;
2693 		const direntry_t* direntries;
2694 		long_file_name lfn;
2695 
2696 		lfn_init(&lfn);
2697 
2698 		if (begin < sector_num)
2699 		    begin = sector_num;
2700 		if (end > sector_num + nb_sectors)
2701 		    end = sector_num + nb_sectors;
2702 		dir_index  = mapping->dir_index +
2703 		    0x10 * (begin - mapping->begin * s->sectors_per_cluster);
2704 		direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
2705 
2706 		for (k = 0; k < (end - begin) * 0x10; k++) {
2707 		    /* do not allow non-ASCII filenames */
2708 		    if (parse_long_name(&lfn, direntries + k) < 0) {
2709 			fprintf(stderr, "Warning: non-ASCII filename\n");
2710 			return -1;
2711 		    }
2712 		    /* no access to the direntry of a read-only file */
2713 		    else if (is_short_name(direntries+k) &&
2714 			    (direntries[k].attributes & 1)) {
2715 			if (memcmp(direntries + k,
2716 				    array_get(&(s->directory), dir_index + k),
2717 				    sizeof(direntry_t))) {
2718 			    fprintf(stderr, "Warning: tried to write to write-protected file\n");
2719 			    return -1;
2720 			}
2721 		    }
2722 		}
2723 	    }
2724 	    i = mapping->end;
2725 	} else
2726 	    i++;
2727     }
2728 
2729     /*
2730      * Use qcow backend. Commit later.
2731      */
2732 DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
2733     ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
2734     if (ret < 0) {
2735 	fprintf(stderr, "Error writing to qcow backend\n");
2736 	return ret;
2737     }
2738 
2739     for (i = sector2cluster(s, sector_num);
2740 	    i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
2741 	if (i >= 0)
2742 	    s->used_clusters[i] |= USED_ALLOCATED;
2743 
2744 DLOG(checkpoint());
2745     /* TODO: add timeout */
2746     try_commit(s);
2747 
2748 DLOG(checkpoint());
2749     return 0;
2750 }
2751 
vvfat_is_allocated(BlockDriverState * bs,int64_t sector_num,int nb_sectors,int * n)2752 static int vvfat_is_allocated(BlockDriverState *bs,
2753 	int64_t sector_num, int nb_sectors, int* n)
2754 {
2755     BDRVVVFATState* s = bs->opaque;
2756     *n = s->sector_count - sector_num;
2757     if (*n > nb_sectors)
2758 	*n = nb_sectors;
2759     else if (*n < 0)
2760 	return 0;
2761     return 1;
2762 }
2763 
write_target_commit(BlockDriverState * bs,int64_t sector_num,const uint8_t * buffer,int nb_sectors)2764 static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
2765 	const uint8_t* buffer, int nb_sectors) {
2766     BDRVVVFATState* s = bs->opaque;
2767     return try_commit(s);
2768 }
2769 
write_target_close(BlockDriverState * bs)2770 static void write_target_close(BlockDriverState *bs) {
2771     BDRVVVFATState* s = bs->opaque;
2772     bdrv_delete(s->qcow);
2773     free(s->qcow_filename);
2774 }
2775 
2776 static BlockDriver vvfat_write_target = {
2777     .format_name        = "vvfat_write_target",
2778     .bdrv_write         = write_target_commit,
2779     .bdrv_close         = write_target_close,
2780 };
2781 
enable_write_target(BDRVVVFATState * s)2782 static int enable_write_target(BDRVVVFATState *s)
2783 {
2784     BlockDriver *bdrv_qcow;
2785     QEMUOptionParameter *options;
2786     int size = sector2cluster(s, s->sector_count);
2787     s->used_clusters = calloc(size, 1);
2788 
2789     array_init(&(s->commits), sizeof(commit_t));
2790 
2791     s->qcow_filename = qemu_malloc(1024);
2792     get_tmp_filename(s->qcow_filename, 1024);
2793 
2794     bdrv_qcow = bdrv_find_format("qcow");
2795     options = parse_option_parameters("", bdrv_qcow->create_options, NULL);
2796     set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512);
2797     set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:");
2798 
2799     if (bdrv_create(bdrv_qcow, s->qcow_filename, options) < 0)
2800 	return -1;
2801     s->qcow = bdrv_new("");
2802     if (s->qcow == NULL ||
2803         bdrv_open(s->qcow, s->qcow_filename, BDRV_O_RDWR, bdrv_qcow) < 0)
2804     {
2805 	return -1;
2806     }
2807 
2808 #ifndef _WIN32
2809     unlink(s->qcow_filename);
2810 #endif
2811 
2812     s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
2813     s->bs->backing_hd->drv = &vvfat_write_target;
2814     s->bs->backing_hd->opaque = s;
2815 
2816     return 0;
2817 }
2818 
vvfat_close(BlockDriverState * bs)2819 static void vvfat_close(BlockDriverState *bs)
2820 {
2821     BDRVVVFATState *s = bs->opaque;
2822 
2823     vvfat_close_current_file(s);
2824     array_free(&(s->fat));
2825     array_free(&(s->directory));
2826     array_free(&(s->mapping));
2827     if(s->cluster_buffer)
2828         free(s->cluster_buffer);
2829 }
2830 
2831 static BlockDriver bdrv_vvfat = {
2832     .format_name	= "vvfat",
2833     .instance_size	= sizeof(BDRVVVFATState),
2834     .bdrv_file_open	= vvfat_open,
2835     .bdrv_read		= vvfat_read,
2836     .bdrv_write		= vvfat_write,
2837     .bdrv_close		= vvfat_close,
2838     .bdrv_is_allocated	= vvfat_is_allocated,
2839     .protocol_name	= "fat",
2840 };
2841 
bdrv_vvfat_init(void)2842 static void bdrv_vvfat_init(void)
2843 {
2844     bdrv_register(&bdrv_vvfat);
2845 }
2846 
2847 block_init(bdrv_vvfat_init);
2848 
2849 #ifdef DEBUG
checkpoint(void)2850 static void checkpoint(void) {
2851     assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
2852     check1(vvv);
2853     check2(vvv);
2854     assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
2855 #if 0
2856     if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
2857 	fprintf(stderr, "Nonono!\n");
2858     mapping_t* mapping;
2859     direntry_t* direntry;
2860     assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
2861     assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
2862     if (vvv->mapping.next<47)
2863 	return;
2864     assert((mapping = array_get(&(vvv->mapping), 47)));
2865     assert(mapping->dir_index < vvv->directory.next);
2866     direntry = array_get(&(vvv->directory), mapping->dir_index);
2867     assert(!memcmp(direntry->name, "USB     H  ", 11) || direntry->name[0]==0);
2868 #endif
2869     return;
2870     /* avoid compiler warnings: */
2871     hexdump(NULL, 100);
2872     remove_mapping(vvv, 0);
2873     print_mapping(NULL);
2874     print_direntry(NULL);
2875 }
2876 #endif
2877