xref: /illumos-kvm-cmd/block/vvfat.c (revision 68396ea9)
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             closedir(dir);
760 	    return -2;
761         }
762 	direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
763 
764 	/* create mapping for this file */
765 	if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
766 	    s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
767 	    s->current_mapping->begin=0;
768 	    s->current_mapping->end=st.st_size;
769 	    /*
770 	     * we get the direntry of the most recent direntry, which
771 	     * contains the short name and all the relevant information.
772 	     */
773 	    s->current_mapping->dir_index=s->directory.next-1;
774 	    s->current_mapping->first_mapping_index = -1;
775 	    if (S_ISDIR(st.st_mode)) {
776 		s->current_mapping->mode = MODE_DIRECTORY;
777 		s->current_mapping->info.dir.parent_mapping_index =
778 		    mapping_index;
779 	    } else {
780 		s->current_mapping->mode = MODE_UNDEFINED;
781 		s->current_mapping->info.file.offset = 0;
782 	    }
783 	    s->current_mapping->path=buffer;
784 	    s->current_mapping->read_only =
785 		(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
786 	}
787     }
788     closedir(dir);
789 
790     /* fill with zeroes up to the end of the cluster */
791     while(s->directory.next%(0x10*s->sectors_per_cluster)) {
792 	direntry_t* direntry=array_get_next(&(s->directory));
793 	memset(direntry,0,sizeof(direntry_t));
794     }
795 
796 /* TODO: if there are more entries, bootsector has to be adjusted! */
797 #define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
798     if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
799 	/* root directory */
800 	int cur = s->directory.next;
801 	array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
802 	memset(array_get(&(s->directory), cur), 0,
803 		(ROOT_ENTRIES - cur) * sizeof(direntry_t));
804     }
805 
806      /* reget the mapping, since s->mapping was possibly realloc()ed */
807     mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
808     first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
809 	* 0x20 / s->cluster_size;
810     mapping->end = first_cluster;
811 
812     direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
813     set_begin_of_direntry(direntry, mapping->begin);
814 
815     return 0;
816 }
817 
sector2cluster(BDRVVVFATState * s,off_t sector_num)818 static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
819 {
820     return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
821 }
822 
cluster2sector(BDRVVVFATState * s,uint32_t cluster_num)823 static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
824 {
825     return s->faked_sectors + s->sectors_per_cluster * cluster_num;
826 }
827 
sector_offset_in_cluster(BDRVVVFATState * s,off_t sector_num)828 static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
829 {
830     return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
831 }
832 
833 #ifdef DBG
get_direntry_for_mapping(BDRVVVFATState * s,mapping_t * mapping)834 static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
835 {
836     if(mapping->mode==MODE_UNDEFINED)
837 	return 0;
838     return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
839 }
840 #endif
841 
init_directories(BDRVVVFATState * s,const char * dirname)842 static int init_directories(BDRVVVFATState* s,
843 	const char* dirname)
844 {
845     bootsector_t* bootsector;
846     mapping_t* mapping;
847     unsigned int i;
848     unsigned int cluster;
849 
850     memset(&(s->first_sectors[0]),0,0x40*0x200);
851 
852     s->cluster_size=s->sectors_per_cluster*0x200;
853     s->cluster_buffer=qemu_malloc(s->cluster_size);
854 
855     /*
856      * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
857      * where sc is sector_count,
858      * spf is sectors_per_fat,
859      * spc is sectors_per_clusters, and
860      * fat_type = 12, 16 or 32.
861      */
862     i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
863     s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
864 
865     array_init(&(s->mapping),sizeof(mapping_t));
866     array_init(&(s->directory),sizeof(direntry_t));
867 
868     /* add volume label */
869     {
870 	direntry_t* entry=array_get_next(&(s->directory));
871 	entry->attributes=0x28; /* archive | volume label */
872 	memcpy(entry->name,"QEMU VVF",8);
873 	memcpy(entry->extension,"AT ",3);
874     }
875 
876     /* Now build FAT, and write back information into directory */
877     init_fat(s);
878 
879     s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
880     s->cluster_count=sector2cluster(s, s->sector_count);
881 
882     mapping = array_get_next(&(s->mapping));
883     mapping->begin = 0;
884     mapping->dir_index = 0;
885     mapping->info.dir.parent_mapping_index = -1;
886     mapping->first_mapping_index = -1;
887     mapping->path = qemu_strdup(dirname);
888     i = strlen(mapping->path);
889     if (i > 0 && mapping->path[i - 1] == '/')
890 	mapping->path[i - 1] = '\0';
891     mapping->mode = MODE_DIRECTORY;
892     mapping->read_only = 0;
893     s->path = mapping->path;
894 
895     for (i = 0, cluster = 0; i < s->mapping.next; i++) {
896 	/* MS-DOS expects the FAT to be 0 for the root directory
897 	 * (except for the media byte). */
898 	/* LATER TODO: still true for FAT32? */
899 	int fix_fat = (i != 0);
900 	mapping = array_get(&(s->mapping), i);
901 
902         if (mapping->mode & MODE_DIRECTORY) {
903 	    mapping->begin = cluster;
904 	    if(read_directory(s, i)) {
905 		fprintf(stderr, "Could not read directory %s\n",
906 			mapping->path);
907 		return -1;
908 	    }
909 	    mapping = array_get(&(s->mapping), i);
910 	} else {
911 	    assert(mapping->mode == MODE_UNDEFINED);
912 	    mapping->mode=MODE_NORMAL;
913 	    mapping->begin = cluster;
914 	    if (mapping->end > 0) {
915 		direntry_t* direntry = array_get(&(s->directory),
916 			mapping->dir_index);
917 
918 		mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
919 		set_begin_of_direntry(direntry, mapping->begin);
920 	    } else {
921 		mapping->end = cluster + 1;
922 		fix_fat = 0;
923 	    }
924 	}
925 
926 	assert(mapping->begin < mapping->end);
927 
928 	/* next free cluster */
929 	cluster = mapping->end;
930 
931 	if(cluster > s->cluster_count) {
932 	    fprintf(stderr,"Directory does not fit in FAT%d (capacity %s)\n",
933 		    s->fat_type,
934 		    s->fat_type == 12 ? s->sector_count == 2880 ? "1.44 MB"
935 								: "2.88 MB"
936 				      : "504MB");
937 	    return -EINVAL;
938 	}
939 
940 	/* fix fat for entry */
941 	if (fix_fat) {
942 	    int j;
943 	    for(j = mapping->begin; j < mapping->end - 1; j++)
944 		fat_set(s, j, j+1);
945 	    fat_set(s, mapping->end - 1, s->max_fat_value);
946 	}
947     }
948 
949     mapping = array_get(&(s->mapping), 0);
950     s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
951     s->last_cluster_of_root_directory = mapping->end;
952 
953     /* the FAT signature */
954     fat_set(s,0,s->max_fat_value);
955     fat_set(s,1,s->max_fat_value);
956 
957     s->current_mapping = NULL;
958 
959     bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
960     bootsector->jump[0]=0xeb;
961     bootsector->jump[1]=0x3e;
962     bootsector->jump[2]=0x90;
963     memcpy(bootsector->name,"QEMU    ",8);
964     bootsector->sector_size=cpu_to_le16(0x200);
965     bootsector->sectors_per_cluster=s->sectors_per_cluster;
966     bootsector->reserved_sectors=cpu_to_le16(1);
967     bootsector->number_of_fats=0x2; /* number of FATs */
968     bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
969     bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
970     bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
971     s->fat.pointer[0] = bootsector->media_type;
972     bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
973     bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
974     bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
975     bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
976     bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
977 
978     /* LATER TODO: if FAT32, this is wrong */
979     bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
980     bootsector->u.fat16.current_head=0;
981     bootsector->u.fat16.signature=0x29;
982     bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
983 
984     memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
985     memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12   ":s->fat_type==16?"FAT16   ":"FAT32   "),8);
986     bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
987 
988     return 0;
989 }
990 
991 #ifdef DEBUG
992 static BDRVVVFATState *vvv = NULL;
993 #endif
994 
995 static int enable_write_target(BDRVVVFATState *s);
996 static int is_consistent(BDRVVVFATState *s);
997 
vvfat_open(BlockDriverState * bs,const char * dirname,int flags)998 static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
999 {
1000     BDRVVVFATState *s = bs->opaque;
1001     int floppy = 0;
1002     int i;
1003 
1004 #ifdef DEBUG
1005     vvv = s;
1006 #endif
1007 
1008 DLOG(if (stderr == NULL) {
1009     stderr = fopen("vvfat.log", "a");
1010     setbuf(stderr, NULL);
1011 })
1012 
1013     s->bs = bs;
1014 
1015     s->fat_type=16;
1016     /* LATER TODO: if FAT32, adjust */
1017     s->sectors_per_cluster=0x10;
1018     /* 504MB disk*/
1019     bs->cyls=1024; bs->heads=16; bs->secs=63;
1020 
1021     s->current_cluster=0xffffffff;
1022 
1023     s->first_sectors_number=0x40;
1024     /* read only is the default for safety */
1025     bs->read_only = 1;
1026     s->qcow = s->write_target = NULL;
1027     s->qcow_filename = NULL;
1028     s->fat2 = NULL;
1029     s->downcase_short_names = 1;
1030 
1031     if (!strstart(dirname, "fat:", NULL))
1032 	return -1;
1033 
1034     if (strstr(dirname, ":floppy:")) {
1035 	floppy = 1;
1036 	s->fat_type = 12;
1037 	s->first_sectors_number = 1;
1038 	s->sectors_per_cluster=2;
1039 	bs->cyls = 80; bs->heads = 2; bs->secs = 36;
1040     }
1041 
1042     s->sector_count=bs->cyls*bs->heads*bs->secs;
1043 
1044     if (strstr(dirname, ":32:")) {
1045 	fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1046 	s->fat_type = 32;
1047     } else if (strstr(dirname, ":16:")) {
1048 	s->fat_type = 16;
1049     } else if (strstr(dirname, ":12:")) {
1050 	s->fat_type = 12;
1051 	s->sector_count=2880;
1052     }
1053 
1054     if (strstr(dirname, ":rw:")) {
1055 	if (enable_write_target(s))
1056 	    return -1;
1057 	bs->read_only = 0;
1058     }
1059 
1060     i = strrchr(dirname, ':') - dirname;
1061     assert(i >= 3);
1062     if (dirname[i-2] == ':' && qemu_isalpha(dirname[i-1]))
1063 	/* workaround for DOS drive names */
1064 	dirname += i-1;
1065     else
1066 	dirname += i+1;
1067 
1068     bs->total_sectors=bs->cyls*bs->heads*bs->secs;
1069 
1070     if(init_directories(s, dirname))
1071 	return -1;
1072 
1073     s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
1074 
1075     if(s->first_sectors_number==0x40)
1076 	init_mbr(s);
1077 
1078     /* for some reason or other, MS-DOS does not like to know about CHS... */
1079     if (floppy)
1080 	bs->heads = bs->cyls = bs->secs = 0;
1081 
1082     //    assert(is_consistent(s));
1083     return 0;
1084 }
1085 
vvfat_close_current_file(BDRVVVFATState * s)1086 static inline void vvfat_close_current_file(BDRVVVFATState *s)
1087 {
1088     if(s->current_mapping) {
1089 	s->current_mapping = NULL;
1090 	if (s->current_fd) {
1091 		close(s->current_fd);
1092 		s->current_fd = 0;
1093 	}
1094     }
1095     s->current_cluster = -1;
1096 }
1097 
1098 /* mappings between index1 and index2-1 are supposed to be ordered
1099  * return value is the index of the last mapping for which end>cluster_num
1100  */
find_mapping_for_cluster_aux(BDRVVVFATState * s,int cluster_num,int index1,int index2)1101 static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1102 {
1103     while(1) {
1104         int index3;
1105 	mapping_t* mapping;
1106 	index3=(index1+index2)/2;
1107 	mapping=array_get(&(s->mapping),index3);
1108 	assert(mapping->begin < mapping->end);
1109 	if(mapping->begin>=cluster_num) {
1110 	    assert(index2!=index3 || index2==0);
1111 	    if(index2==index3)
1112 		return index1;
1113 	    index2=index3;
1114 	} else {
1115 	    if(index1==index3)
1116 		return mapping->end<=cluster_num ? index2 : index1;
1117 	    index1=index3;
1118 	}
1119 	assert(index1<=index2);
1120 	DLOG(mapping=array_get(&(s->mapping),index1);
1121 	assert(mapping->begin<=cluster_num);
1122 	assert(index2 >= s->mapping.next ||
1123 		((mapping = array_get(&(s->mapping),index2)) &&
1124 		mapping->end>cluster_num)));
1125     }
1126 }
1127 
find_mapping_for_cluster(BDRVVVFATState * s,int cluster_num)1128 static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
1129 {
1130     int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
1131     mapping_t* mapping;
1132     if(index>=s->mapping.next)
1133         return NULL;
1134     mapping=array_get(&(s->mapping),index);
1135     if(mapping->begin>cluster_num)
1136         return NULL;
1137     assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
1138     return mapping;
1139 }
1140 
1141 /*
1142  * This function simply compares path == mapping->path. Since the mappings
1143  * are sorted by cluster, this is expensive: O(n).
1144  */
find_mapping_for_path(BDRVVVFATState * s,const char * path)1145 static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
1146 	const char* path)
1147 {
1148     int i;
1149 
1150     for (i = 0; i < s->mapping.next; i++) {
1151 	mapping_t* mapping = array_get(&(s->mapping), i);
1152 	if (mapping->first_mapping_index < 0 &&
1153 		!strcmp(path, mapping->path))
1154 	    return mapping;
1155     }
1156 
1157     return NULL;
1158 }
1159 
open_file(BDRVVVFATState * s,mapping_t * mapping)1160 static int open_file(BDRVVVFATState* s,mapping_t* mapping)
1161 {
1162     if(!mapping)
1163 	return -1;
1164     if(!s->current_mapping ||
1165 	    strcmp(s->current_mapping->path,mapping->path)) {
1166 	/* open file */
1167 	int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
1168 	if(fd<0)
1169 	    return -1;
1170 	vvfat_close_current_file(s);
1171 	s->current_fd = fd;
1172 	s->current_mapping = mapping;
1173     }
1174     return 0;
1175 }
1176 
read_cluster(BDRVVVFATState * s,int cluster_num)1177 static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1178 {
1179     if(s->current_cluster != cluster_num) {
1180 	int result=0;
1181 	off_t offset;
1182 	assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
1183 	if(!s->current_mapping
1184 		|| s->current_mapping->begin>cluster_num
1185 		|| s->current_mapping->end<=cluster_num) {
1186 	    /* binary search of mappings for file */
1187 	    mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
1188 
1189 	    assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1190 
1191 	    if (mapping && mapping->mode & MODE_DIRECTORY) {
1192 		vvfat_close_current_file(s);
1193 		s->current_mapping = mapping;
1194 read_cluster_directory:
1195 		offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
1196 		s->cluster = (unsigned char*)s->directory.pointer+offset
1197 			+ 0x20*s->current_mapping->info.dir.first_dir_index;
1198 		assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1199 		assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1200 		s->current_cluster = cluster_num;
1201 		return 0;
1202 	    }
1203 
1204 	    if(open_file(s,mapping))
1205 		return -2;
1206 	} else if (s->current_mapping->mode & MODE_DIRECTORY)
1207 	    goto read_cluster_directory;
1208 
1209 	assert(s->current_fd);
1210 
1211 	offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
1212 	if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1213 	    return -3;
1214 	s->cluster=s->cluster_buffer;
1215 	result=read(s->current_fd,s->cluster,s->cluster_size);
1216 	if(result<0) {
1217 	    s->current_cluster = -1;
1218 	    return -1;
1219 	}
1220 	s->current_cluster = cluster_num;
1221     }
1222     return 0;
1223 }
1224 
1225 #ifdef DEBUG
hexdump(const void * address,uint32_t len)1226 static void hexdump(const void* address, uint32_t len)
1227 {
1228     const unsigned char* p = address;
1229     int i, j;
1230 
1231     for (i = 0; i < len; i += 16) {
1232 	for (j = 0; j < 16 && i + j < len; j++)
1233 	    fprintf(stderr, "%02x ", p[i + j]);
1234 	for (; j < 16; j++)
1235 	    fprintf(stderr, "   ");
1236 	fprintf(stderr, " ");
1237 	for (j = 0; j < 16 && i + j < len; j++)
1238 	    fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
1239 	fprintf(stderr, "\n");
1240     }
1241 }
1242 
print_direntry(const direntry_t * direntry)1243 static void print_direntry(const direntry_t* direntry)
1244 {
1245     int j = 0;
1246     char buffer[1024];
1247 
1248     fprintf(stderr, "direntry %p: ", direntry);
1249     if(!direntry)
1250 	return;
1251     if(is_long_name(direntry)) {
1252 	unsigned char* c=(unsigned char*)direntry;
1253 	int i;
1254 	for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
1255 #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
1256 	    ADD_CHAR(c[i]);
1257 	for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
1258 	    ADD_CHAR(c[i]);
1259 	for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
1260 	    ADD_CHAR(c[i]);
1261 	buffer[j] = 0;
1262 	fprintf(stderr, "%s\n", buffer);
1263     } else {
1264 	int i;
1265 	for(i=0;i<11;i++)
1266 	    ADD_CHAR(direntry->name[i]);
1267 	buffer[j] = 0;
1268 	fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1269 		buffer,
1270 		direntry->attributes,
1271 		begin_of_direntry(direntry),le32_to_cpu(direntry->size));
1272     }
1273 }
1274 
print_mapping(const mapping_t * mapping)1275 static void print_mapping(const mapping_t* mapping)
1276 {
1277     fprintf(stderr, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1278         "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1279         mapping, mapping->begin, mapping->end, mapping->dir_index,
1280         mapping->first_mapping_index, mapping->path, mapping->mode);
1281 
1282     if (mapping->mode & MODE_DIRECTORY)
1283 	fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1284     else
1285 	fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
1286 }
1287 #endif
1288 
vvfat_read(BlockDriverState * bs,int64_t sector_num,uint8_t * buf,int nb_sectors)1289 static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
1290                     uint8_t *buf, int nb_sectors)
1291 {
1292     BDRVVVFATState *s = bs->opaque;
1293     int i;
1294 
1295     for(i=0;i<nb_sectors;i++,sector_num++) {
1296 	if (sector_num >= s->sector_count)
1297 	   return -1;
1298 	if (s->qcow) {
1299 	    int n;
1300 	    if (s->qcow->drv->bdrv_is_allocated(s->qcow,
1301 			sector_num, nb_sectors-i, &n)) {
1302 DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
1303 		if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
1304 		    return -1;
1305 		i += n - 1;
1306 		sector_num += n - 1;
1307 		continue;
1308 	    }
1309 DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
1310 	}
1311 	if(sector_num<s->faked_sectors) {
1312 	    if(sector_num<s->first_sectors_number)
1313 		memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
1314 	    else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
1315 		memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
1316 	    else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
1317 		memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
1318 	} else {
1319 	    uint32_t sector=sector_num-s->faked_sectors,
1320 	    sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1321 	    cluster_num=sector/s->sectors_per_cluster;
1322 	    if(read_cluster(s, cluster_num) != 0) {
1323 		/* LATER TODO: strict: return -1; */
1324 		memset(buf+i*0x200,0,0x200);
1325 		continue;
1326 	    }
1327 	    memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
1328 	}
1329     }
1330     return 0;
1331 }
1332 
1333 /* LATER TODO: statify all functions */
1334 
1335 /*
1336  * Idea of the write support (use snapshot):
1337  *
1338  * 1. check if all data is consistent, recording renames, modifications,
1339  *    new files and directories (in s->commits).
1340  *
1341  * 2. if the data is not consistent, stop committing
1342  *
1343  * 3. handle renames, and create new files and directories (do not yet
1344  *    write their contents)
1345  *
1346  * 4. walk the directories, fixing the mapping and direntries, and marking
1347  *    the handled mappings as not deleted
1348  *
1349  * 5. commit the contents of the files
1350  *
1351  * 6. handle deleted files and directories
1352  *
1353  */
1354 
1355 typedef struct commit_t {
1356     char* path;
1357     union {
1358 	struct { uint32_t cluster; } rename;
1359 	struct { int dir_index; uint32_t modified_offset; } writeout;
1360 	struct { uint32_t first_cluster; } new_file;
1361 	struct { uint32_t cluster; } mkdir;
1362     } param;
1363     /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1364     enum {
1365 	ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1366     } action;
1367 } commit_t;
1368 
clear_commits(BDRVVVFATState * s)1369 static void clear_commits(BDRVVVFATState* s)
1370 {
1371     int i;
1372 DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1373     for (i = 0; i < s->commits.next; i++) {
1374 	commit_t* commit = array_get(&(s->commits), i);
1375 	assert(commit->path || commit->action == ACTION_WRITEOUT);
1376 	if (commit->action != ACTION_WRITEOUT) {
1377 	    assert(commit->path);
1378 	    free(commit->path);
1379 	} else
1380 	    assert(commit->path == NULL);
1381     }
1382     s->commits.next = 0;
1383 }
1384 
schedule_rename(BDRVVVFATState * s,uint32_t cluster,char * new_path)1385 static void schedule_rename(BDRVVVFATState* s,
1386 	uint32_t cluster, char* new_path)
1387 {
1388     commit_t* commit = array_get_next(&(s->commits));
1389     commit->path = new_path;
1390     commit->param.rename.cluster = cluster;
1391     commit->action = ACTION_RENAME;
1392 }
1393 
schedule_writeout(BDRVVVFATState * s,int dir_index,uint32_t modified_offset)1394 static void schedule_writeout(BDRVVVFATState* s,
1395 	int dir_index, uint32_t modified_offset)
1396 {
1397     commit_t* commit = array_get_next(&(s->commits));
1398     commit->path = NULL;
1399     commit->param.writeout.dir_index = dir_index;
1400     commit->param.writeout.modified_offset = modified_offset;
1401     commit->action = ACTION_WRITEOUT;
1402 }
1403 
schedule_new_file(BDRVVVFATState * s,char * path,uint32_t first_cluster)1404 static void schedule_new_file(BDRVVVFATState* s,
1405 	char* path, uint32_t first_cluster)
1406 {
1407     commit_t* commit = array_get_next(&(s->commits));
1408     commit->path = path;
1409     commit->param.new_file.first_cluster = first_cluster;
1410     commit->action = ACTION_NEW_FILE;
1411 }
1412 
schedule_mkdir(BDRVVVFATState * s,uint32_t cluster,char * path)1413 static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1414 {
1415     commit_t* commit = array_get_next(&(s->commits));
1416     commit->path = path;
1417     commit->param.mkdir.cluster = cluster;
1418     commit->action = ACTION_MKDIR;
1419 }
1420 
1421 typedef struct {
1422     /*
1423      * Since the sequence number is at most 0x3f, and the filename
1424      * length is at most 13 times the sequence number, the maximal
1425      * filename length is 0x3f * 13 bytes.
1426      */
1427     unsigned char name[0x3f * 13 + 1];
1428     int checksum, len;
1429     int sequence_number;
1430 } long_file_name;
1431 
lfn_init(long_file_name * lfn)1432 static void lfn_init(long_file_name* lfn)
1433 {
1434    lfn->sequence_number = lfn->len = 0;
1435    lfn->checksum = 0x100;
1436 }
1437 
1438 /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
parse_long_name(long_file_name * lfn,const direntry_t * direntry)1439 static int parse_long_name(long_file_name* lfn,
1440 	const direntry_t* direntry)
1441 {
1442     int i, j, offset;
1443     const unsigned char* pointer = (const unsigned char*)direntry;
1444 
1445     if (!is_long_name(direntry))
1446 	return 1;
1447 
1448     if (pointer[0] & 0x40) {
1449 	lfn->sequence_number = pointer[0] & 0x3f;
1450 	lfn->checksum = pointer[13];
1451 	lfn->name[0] = 0;
1452 	lfn->name[lfn->sequence_number * 13] = 0;
1453     } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
1454 	return -1;
1455     else if (pointer[13] != lfn->checksum)
1456 	return -2;
1457     else if (pointer[12] || pointer[26] || pointer[27])
1458 	return -3;
1459 
1460     offset = 13 * (lfn->sequence_number - 1);
1461     for (i = 0, j = 1; i < 13; i++, j+=2) {
1462 	if (j == 11)
1463 	    j = 14;
1464 	else if (j == 26)
1465 	    j = 28;
1466 
1467 	if (pointer[j+1] == 0)
1468 	    lfn->name[offset + i] = pointer[j];
1469 	else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1470 	    return -4;
1471 	else
1472 	    lfn->name[offset + i] = 0;
1473     }
1474 
1475     if (pointer[0] & 0x40)
1476 	lfn->len = offset + strlen((char*)lfn->name + offset);
1477 
1478     return 0;
1479 }
1480 
1481 /* 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)1482 static int parse_short_name(BDRVVVFATState* s,
1483 	long_file_name* lfn, direntry_t* direntry)
1484 {
1485     int i, j;
1486 
1487     if (!is_short_name(direntry))
1488 	return 1;
1489 
1490     for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1491     for (i = 0; i <= j; i++) {
1492 	if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
1493 	    return -1;
1494 	else if (s->downcase_short_names)
1495 	    lfn->name[i] = qemu_tolower(direntry->name[i]);
1496 	else
1497 	    lfn->name[i] = direntry->name[i];
1498     }
1499 
1500     for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
1501     if (j >= 0) {
1502 	lfn->name[i++] = '.';
1503 	lfn->name[i + j + 1] = '\0';
1504 	for (;j >= 0; j--) {
1505 	    if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
1506 		return -2;
1507 	    else if (s->downcase_short_names)
1508 		lfn->name[i + j] = qemu_tolower(direntry->extension[j]);
1509 	    else
1510 		lfn->name[i + j] = direntry->extension[j];
1511 	}
1512     } else
1513 	lfn->name[i + j + 1] = '\0';
1514 
1515     lfn->len = strlen((char*)lfn->name);
1516 
1517     return 0;
1518 }
1519 
modified_fat_get(BDRVVVFATState * s,unsigned int cluster)1520 static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1521 	unsigned int cluster)
1522 {
1523     if (cluster < s->last_cluster_of_root_directory) {
1524 	if (cluster + 1 == s->last_cluster_of_root_directory)
1525 	    return s->max_fat_value;
1526 	else
1527 	    return cluster + 1;
1528     }
1529 
1530     if (s->fat_type==32) {
1531         uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1532         return le32_to_cpu(*entry);
1533     } else if (s->fat_type==16) {
1534         uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1535         return le16_to_cpu(*entry);
1536     } else {
1537         const uint8_t* x=s->fat2+cluster*3/2;
1538         return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1539     }
1540 }
1541 
cluster_was_modified(BDRVVVFATState * s,uint32_t cluster_num)1542 static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1543 {
1544     int was_modified = 0;
1545     int i, dummy;
1546 
1547     if (s->qcow == NULL)
1548 	return 0;
1549 
1550     for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
1551 	was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
1552 		cluster2sector(s, cluster_num) + i, 1, &dummy);
1553 
1554     return was_modified;
1555 }
1556 
get_basename(const char * path)1557 static const char* get_basename(const char* path)
1558 {
1559     char* basename = strrchr(path, '/');
1560     if (basename == NULL)
1561 	return path;
1562     else
1563 	return basename + 1; /* strip '/' */
1564 }
1565 
1566 /*
1567  * The array s->used_clusters holds the states of the clusters. If it is
1568  * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1569  * was modified, bit 3 is set.
1570  * If any cluster is allocated, but not part of a file or directory, this
1571  * driver refuses to commit.
1572  */
1573 typedef enum {
1574      USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
1575 } used_t;
1576 
1577 /*
1578  * get_cluster_count_for_direntry() not only determines how many clusters
1579  * are occupied by direntry, but also if it was renamed or modified.
1580  *
1581  * A file is thought to be renamed *only* if there already was a file with
1582  * exactly the same first cluster, but a different name.
1583  *
1584  * Further, the files/directories handled by this function are
1585  * assumed to be *not* deleted (and *only* those).
1586  */
get_cluster_count_for_direntry(BDRVVVFATState * s,direntry_t * direntry,const char * path)1587 static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
1588 	direntry_t* direntry, const char* path)
1589 {
1590     /*
1591      * This is a little bit tricky:
1592      * IF the guest OS just inserts a cluster into the file chain,
1593      * and leaves the rest alone, (i.e. the original file had clusters
1594      * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1595      *
1596      * - do_commit will write the cluster into the file at the given
1597      *   offset, but
1598      *
1599      * - the cluster which is overwritten should be moved to a later
1600      *   position in the file.
1601      *
1602      * I am not aware that any OS does something as braindead, but this
1603      * situation could happen anyway when not committing for a long time.
1604      * Just to be sure that this does not bite us, detect it, and copy the
1605      * contents of the clusters to-be-overwritten into the qcow.
1606      */
1607     int copy_it = 0;
1608     int was_modified = 0;
1609     int32_t ret = 0;
1610 
1611     uint32_t cluster_num = begin_of_direntry(direntry);
1612     uint32_t offset = 0;
1613     int first_mapping_index = -1;
1614     mapping_t* mapping = NULL;
1615     const char* basename2 = NULL;
1616 
1617     vvfat_close_current_file(s);
1618 
1619     /* the root directory */
1620     if (cluster_num == 0)
1621 	return 0;
1622 
1623     /* write support */
1624     if (s->qcow) {
1625 	basename2 = get_basename(path);
1626 
1627 	mapping = find_mapping_for_cluster(s, cluster_num);
1628 
1629 	if (mapping) {
1630 	    const char* basename;
1631 
1632 	    assert(mapping->mode & MODE_DELETED);
1633 	    mapping->mode &= ~MODE_DELETED;
1634 
1635 	    basename = get_basename(mapping->path);
1636 
1637 	    assert(mapping->mode & MODE_NORMAL);
1638 
1639 	    /* rename */
1640 	    if (strcmp(basename, basename2))
1641 		schedule_rename(s, cluster_num, qemu_strdup(path));
1642 	} else if (is_file(direntry))
1643 	    /* new file */
1644 	    schedule_new_file(s, qemu_strdup(path), cluster_num);
1645 	else {
1646             abort();
1647 	    return 0;
1648 	}
1649     }
1650 
1651     while(1) {
1652 	if (s->qcow) {
1653 	    if (!copy_it && cluster_was_modified(s, cluster_num)) {
1654 		if (mapping == NULL ||
1655 			mapping->begin > cluster_num ||
1656 			mapping->end <= cluster_num)
1657 		mapping = find_mapping_for_cluster(s, cluster_num);
1658 
1659 
1660 		if (mapping &&
1661 			(mapping->mode & MODE_DIRECTORY) == 0) {
1662 
1663 		    /* was modified in qcow */
1664 		    if (offset != mapping->info.file.offset + s->cluster_size
1665 			    * (cluster_num - mapping->begin)) {
1666 			/* offset of this cluster in file chain has changed */
1667                         abort();
1668 			copy_it = 1;
1669 		    } else if (offset == 0) {
1670 			const char* basename = get_basename(mapping->path);
1671 
1672 			if (strcmp(basename, basename2))
1673 			    copy_it = 1;
1674 			first_mapping_index = array_index(&(s->mapping), mapping);
1675 		    }
1676 
1677 		    if (mapping->first_mapping_index != first_mapping_index
1678 			    && mapping->info.file.offset > 0) {
1679                         abort();
1680 			copy_it = 1;
1681 		    }
1682 
1683 		    /* need to write out? */
1684 		    if (!was_modified && is_file(direntry)) {
1685 			was_modified = 1;
1686 			schedule_writeout(s, mapping->dir_index, offset);
1687 		    }
1688 		}
1689 	    }
1690 
1691 	    if (copy_it) {
1692 		int i, dummy;
1693 		/*
1694 		 * This is horribly inefficient, but that is okay, since
1695 		 * it is rarely executed, if at all.
1696 		 */
1697 		int64_t offset = cluster2sector(s, cluster_num);
1698 
1699 		vvfat_close_current_file(s);
1700 		for (i = 0; i < s->sectors_per_cluster; i++)
1701 		    if (!s->qcow->drv->bdrv_is_allocated(s->qcow,
1702 				offset + i, 1, &dummy)) {
1703 			if (vvfat_read(s->bs,
1704 				    offset, s->cluster_buffer, 1))
1705 			    return -1;
1706 			if (s->qcow->drv->bdrv_write(s->qcow,
1707 				    offset, s->cluster_buffer, 1))
1708 			    return -2;
1709 		    }
1710 	    }
1711 	}
1712 
1713 	ret++;
1714 	if (s->used_clusters[cluster_num] & USED_ANY)
1715 	    return 0;
1716 	s->used_clusters[cluster_num] = USED_FILE;
1717 
1718 	cluster_num = modified_fat_get(s, cluster_num);
1719 
1720 	if (fat_eof(s, cluster_num))
1721 	    return ret;
1722 	else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
1723 	    return -1;
1724 
1725 	offset += s->cluster_size;
1726     }
1727 }
1728 
1729 /*
1730  * This function looks at the modified data (qcow).
1731  * It returns 0 upon inconsistency or error, and the number of clusters
1732  * used by the directory, its subdirectories and their files.
1733  */
check_directory_consistency(BDRVVVFATState * s,int cluster_num,const char * path)1734 static int check_directory_consistency(BDRVVVFATState *s,
1735 	int cluster_num, const char* path)
1736 {
1737     int ret = 0;
1738     unsigned char* cluster = qemu_malloc(s->cluster_size);
1739     direntry_t* direntries = (direntry_t*)cluster;
1740     mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
1741 
1742     long_file_name lfn;
1743     int path_len = strlen(path);
1744     char path2[PATH_MAX];
1745 
1746     assert(path_len < PATH_MAX); /* len was tested before! */
1747     pstrcpy(path2, sizeof(path2), path);
1748     path2[path_len] = '/';
1749     path2[path_len + 1] = '\0';
1750 
1751     if (mapping) {
1752 	const char* basename = get_basename(mapping->path);
1753 	const char* basename2 = get_basename(path);
1754 
1755 	assert(mapping->mode & MODE_DIRECTORY);
1756 
1757 	assert(mapping->mode & MODE_DELETED);
1758 	mapping->mode &= ~MODE_DELETED;
1759 
1760 	if (strcmp(basename, basename2))
1761 	    schedule_rename(s, cluster_num, qemu_strdup(path));
1762     } else
1763 	/* new directory */
1764 	schedule_mkdir(s, cluster_num, qemu_strdup(path));
1765 
1766     lfn_init(&lfn);
1767     do {
1768 	int i;
1769 	int subret = 0;
1770 
1771 	ret++;
1772 
1773 	if (s->used_clusters[cluster_num] & USED_ANY) {
1774 	    fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
1775 	    return 0;
1776 	}
1777 	s->used_clusters[cluster_num] = USED_DIRECTORY;
1778 
1779 DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
1780 	subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
1781 		s->sectors_per_cluster);
1782 	if (subret) {
1783 	    fprintf(stderr, "Error fetching direntries\n");
1784 	fail:
1785 	    free(cluster);
1786 	    return 0;
1787 	}
1788 
1789 	for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
1790 	    int cluster_count = 0;
1791 
1792 DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
1793 	    if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
1794 		    is_free(direntries + i))
1795 		continue;
1796 
1797 	    subret = parse_long_name(&lfn, direntries + i);
1798 	    if (subret < 0) {
1799 		fprintf(stderr, "Error in long name\n");
1800 		goto fail;
1801 	    }
1802 	    if (subret == 0 || is_free(direntries + i))
1803 		continue;
1804 
1805 	    if (fat_chksum(direntries+i) != lfn.checksum) {
1806 		subret = parse_short_name(s, &lfn, direntries + i);
1807 		if (subret < 0) {
1808 		    fprintf(stderr, "Error in short name (%d)\n", subret);
1809 		    goto fail;
1810 		}
1811 		if (subret > 0 || !strcmp((char*)lfn.name, ".")
1812 			|| !strcmp((char*)lfn.name, ".."))
1813 		    continue;
1814 	    }
1815 	    lfn.checksum = 0x100; /* cannot use long name twice */
1816 
1817 	    if (path_len + 1 + lfn.len >= PATH_MAX) {
1818 		fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
1819 		goto fail;
1820 	    }
1821             pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
1822                     (char*)lfn.name);
1823 
1824 	    if (is_directory(direntries + i)) {
1825 		if (begin_of_direntry(direntries + i) == 0) {
1826 		    DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
1827 		    goto fail;
1828 		}
1829 		cluster_count = check_directory_consistency(s,
1830 			begin_of_direntry(direntries + i), path2);
1831 		if (cluster_count == 0) {
1832 		    DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
1833 		    goto fail;
1834 		}
1835 	    } else if (is_file(direntries + i)) {
1836 		/* check file size with FAT */
1837 		cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
1838 		if (cluster_count !=
1839 			(le32_to_cpu(direntries[i].size) + s->cluster_size
1840 			 - 1) / s->cluster_size) {
1841 		    DLOG(fprintf(stderr, "Cluster count mismatch\n"));
1842 		    goto fail;
1843 		}
1844 	    } else
1845                 abort(); /* cluster_count = 0; */
1846 
1847 	    ret += cluster_count;
1848 	}
1849 
1850 	cluster_num = modified_fat_get(s, cluster_num);
1851     } while(!fat_eof(s, cluster_num));
1852 
1853     free(cluster);
1854     return ret;
1855 }
1856 
1857 /* returns 1 on success */
is_consistent(BDRVVVFATState * s)1858 static int is_consistent(BDRVVVFATState* s)
1859 {
1860     int i, check;
1861     int used_clusters_count = 0;
1862 
1863 DLOG(checkpoint());
1864     /*
1865      * - get modified FAT
1866      * - compare the two FATs (TODO)
1867      * - get buffer for marking used clusters
1868      * - recurse direntries from root (using bs->bdrv_read to make
1869      *    sure to get the new data)
1870      *   - check that the FAT agrees with the size
1871      *   - count the number of clusters occupied by this directory and
1872      *     its files
1873      * - check that the cumulative used cluster count agrees with the
1874      *   FAT
1875      * - if all is fine, return number of used clusters
1876      */
1877     if (s->fat2 == NULL) {
1878 	int size = 0x200 * s->sectors_per_fat;
1879 	s->fat2 = qemu_malloc(size);
1880 	memcpy(s->fat2, s->fat.pointer, size);
1881     }
1882     check = vvfat_read(s->bs,
1883 	    s->first_sectors_number, s->fat2, s->sectors_per_fat);
1884     if (check) {
1885 	fprintf(stderr, "Could not copy fat\n");
1886 	return 0;
1887     }
1888     assert (s->used_clusters);
1889     for (i = 0; i < sector2cluster(s, s->sector_count); i++)
1890 	s->used_clusters[i] &= ~USED_ANY;
1891 
1892     clear_commits(s);
1893 
1894     /* mark every mapped file/directory as deleted.
1895      * (check_directory_consistency() will unmark those still present). */
1896     if (s->qcow)
1897 	for (i = 0; i < s->mapping.next; i++) {
1898 	    mapping_t* mapping = array_get(&(s->mapping), i);
1899 	    if (mapping->first_mapping_index < 0)
1900 		mapping->mode |= MODE_DELETED;
1901 	}
1902 
1903     used_clusters_count = check_directory_consistency(s, 0, s->path);
1904     if (used_clusters_count <= 0) {
1905 	DLOG(fprintf(stderr, "problem in directory\n"));
1906 	return 0;
1907     }
1908 
1909     check = s->last_cluster_of_root_directory;
1910     for (i = check; i < sector2cluster(s, s->sector_count); i++) {
1911 	if (modified_fat_get(s, i)) {
1912 	    if(!s->used_clusters[i]) {
1913 		DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
1914 		return 0;
1915 	    }
1916 	    check++;
1917 	}
1918 
1919 	if (s->used_clusters[i] == USED_ALLOCATED) {
1920 	    /* allocated, but not used... */
1921 	    DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
1922 	    return 0;
1923 	}
1924     }
1925 
1926     if (check != used_clusters_count)
1927 	return 0;
1928 
1929     return used_clusters_count;
1930 }
1931 
adjust_mapping_indices(BDRVVVFATState * s,int offset,int adjust)1932 static inline void adjust_mapping_indices(BDRVVVFATState* s,
1933 	int offset, int adjust)
1934 {
1935     int i;
1936 
1937     for (i = 0; i < s->mapping.next; i++) {
1938 	mapping_t* mapping = array_get(&(s->mapping), i);
1939 
1940 #define ADJUST_MAPPING_INDEX(name) \
1941 	if (mapping->name >= offset) \
1942 	    mapping->name += adjust
1943 
1944 	ADJUST_MAPPING_INDEX(first_mapping_index);
1945 	if (mapping->mode & MODE_DIRECTORY)
1946 	    ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
1947     }
1948 }
1949 
1950 /* insert or update mapping */
insert_mapping(BDRVVVFATState * s,uint32_t begin,uint32_t end)1951 static mapping_t* insert_mapping(BDRVVVFATState* s,
1952 	uint32_t begin, uint32_t end)
1953 {
1954     /*
1955      * - find mapping where mapping->begin >= begin,
1956      * - if mapping->begin > begin: insert
1957      *   - adjust all references to mappings!
1958      * - else: adjust
1959      * - replace name
1960      */
1961     int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
1962     mapping_t* mapping = NULL;
1963     mapping_t* first_mapping = array_get(&(s->mapping), 0);
1964 
1965     if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
1966 	    && mapping->begin < begin) {
1967 	mapping->end = begin;
1968 	index++;
1969 	mapping = array_get(&(s->mapping), index);
1970     }
1971     if (index >= s->mapping.next || mapping->begin > begin) {
1972 	mapping = array_insert(&(s->mapping), index, 1);
1973 	mapping->path = NULL;
1974 	adjust_mapping_indices(s, index, +1);
1975     }
1976 
1977     mapping->begin = begin;
1978     mapping->end = end;
1979 
1980 DLOG(mapping_t* next_mapping;
1981 assert(index + 1 >= s->mapping.next ||
1982 ((next_mapping = array_get(&(s->mapping), index + 1)) &&
1983  next_mapping->begin >= end)));
1984 
1985     if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1986 	s->current_mapping = array_get(&(s->mapping),
1987 		s->current_mapping - first_mapping);
1988 
1989     return mapping;
1990 }
1991 
remove_mapping(BDRVVVFATState * s,int mapping_index)1992 static int remove_mapping(BDRVVVFATState* s, int mapping_index)
1993 {
1994     mapping_t* mapping = array_get(&(s->mapping), mapping_index);
1995     mapping_t* first_mapping = array_get(&(s->mapping), 0);
1996 
1997     /* free mapping */
1998     if (mapping->first_mapping_index < 0)
1999 	free(mapping->path);
2000 
2001     /* remove from s->mapping */
2002     array_remove(&(s->mapping), mapping_index);
2003 
2004     /* adjust all references to mappings */
2005     adjust_mapping_indices(s, mapping_index, -1);
2006 
2007     if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
2008 	s->current_mapping = array_get(&(s->mapping),
2009 		s->current_mapping - first_mapping);
2010 
2011     return 0;
2012 }
2013 
adjust_dirindices(BDRVVVFATState * s,int offset,int adjust)2014 static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
2015 {
2016     int i;
2017     for (i = 0; i < s->mapping.next; i++) {
2018 	mapping_t* mapping = array_get(&(s->mapping), i);
2019 	if (mapping->dir_index >= offset)
2020 	    mapping->dir_index += adjust;
2021 	if ((mapping->mode & MODE_DIRECTORY) &&
2022 		mapping->info.dir.first_dir_index >= offset)
2023 	    mapping->info.dir.first_dir_index += adjust;
2024     }
2025 }
2026 
insert_direntries(BDRVVVFATState * s,int dir_index,int count)2027 static direntry_t* insert_direntries(BDRVVVFATState* s,
2028 	int dir_index, int count)
2029 {
2030     /*
2031      * make room in s->directory,
2032      * adjust_dirindices
2033      */
2034     direntry_t* result = array_insert(&(s->directory), dir_index, count);
2035     if (result == NULL)
2036 	return NULL;
2037     adjust_dirindices(s, dir_index, count);
2038     return result;
2039 }
2040 
remove_direntries(BDRVVVFATState * s,int dir_index,int count)2041 static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
2042 {
2043     int ret = array_remove_slice(&(s->directory), dir_index, count);
2044     if (ret)
2045 	return ret;
2046     adjust_dirindices(s, dir_index, -count);
2047     return 0;
2048 }
2049 
2050 /*
2051  * Adapt the mappings of the cluster chain starting at first cluster
2052  * (i.e. if a file starts at first_cluster, the chain is followed according
2053  * to the modified fat, and the corresponding entries in s->mapping are
2054  * adjusted)
2055  */
commit_mappings(BDRVVVFATState * s,uint32_t first_cluster,int dir_index)2056 static int commit_mappings(BDRVVVFATState* s,
2057 	uint32_t first_cluster, int dir_index)
2058 {
2059     mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2060     direntry_t* direntry = array_get(&(s->directory), dir_index);
2061     uint32_t cluster = first_cluster;
2062 
2063     vvfat_close_current_file(s);
2064 
2065     assert(mapping);
2066     assert(mapping->begin == first_cluster);
2067     mapping->first_mapping_index = -1;
2068     mapping->dir_index = dir_index;
2069     mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2070 	MODE_DIRECTORY : MODE_NORMAL;
2071 
2072     while (!fat_eof(s, cluster)) {
2073 	uint32_t c, c1;
2074 
2075 	for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2076 		c = c1, c1 = modified_fat_get(s, c1));
2077 
2078 	c++;
2079 	if (c > mapping->end) {
2080 	    int index = array_index(&(s->mapping), mapping);
2081 	    int i, max_i = s->mapping.next - index;
2082 	    for (i = 1; i < max_i && mapping[i].begin < c; i++);
2083 	    while (--i > 0)
2084 		remove_mapping(s, index + 1);
2085 	}
2086 	assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2087 		|| mapping[1].begin >= c);
2088 	mapping->end = c;
2089 
2090 	if (!fat_eof(s, c1)) {
2091 	    int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2092 	    mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2093 		array_get(&(s->mapping), i);
2094 
2095 	    if (next_mapping == NULL || next_mapping->begin > c1) {
2096 		int i1 = array_index(&(s->mapping), mapping);
2097 
2098 		next_mapping = insert_mapping(s, c1, c1+1);
2099 
2100 		if (c1 < c)
2101 		    i1++;
2102 		mapping = array_get(&(s->mapping), i1);
2103 	    }
2104 
2105 	    next_mapping->dir_index = mapping->dir_index;
2106 	    next_mapping->first_mapping_index =
2107 		mapping->first_mapping_index < 0 ?
2108 		array_index(&(s->mapping), mapping) :
2109 		mapping->first_mapping_index;
2110 	    next_mapping->path = mapping->path;
2111 	    next_mapping->mode = mapping->mode;
2112 	    next_mapping->read_only = mapping->read_only;
2113 	    if (mapping->mode & MODE_DIRECTORY) {
2114 		next_mapping->info.dir.parent_mapping_index =
2115 			mapping->info.dir.parent_mapping_index;
2116 		next_mapping->info.dir.first_dir_index =
2117 			mapping->info.dir.first_dir_index +
2118 			0x10 * s->sectors_per_cluster *
2119 			(mapping->end - mapping->begin);
2120 	    } else
2121 		next_mapping->info.file.offset = mapping->info.file.offset +
2122 			mapping->end - mapping->begin;
2123 
2124 	    mapping = next_mapping;
2125 	}
2126 
2127 	cluster = c1;
2128     }
2129 
2130     return 0;
2131 }
2132 
commit_direntries(BDRVVVFATState * s,int dir_index,int parent_mapping_index)2133 static int commit_direntries(BDRVVVFATState* s,
2134 	int dir_index, int parent_mapping_index)
2135 {
2136     direntry_t* direntry = array_get(&(s->directory), dir_index);
2137     uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
2138     mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2139 
2140     int factor = 0x10 * s->sectors_per_cluster;
2141     int old_cluster_count, new_cluster_count;
2142     int current_dir_index = mapping->info.dir.first_dir_index;
2143     int first_dir_index = current_dir_index;
2144     int ret, i;
2145     uint32_t c;
2146 
2147 DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
2148 
2149     assert(direntry);
2150     assert(mapping);
2151     assert(mapping->begin == first_cluster);
2152     assert(mapping->info.dir.first_dir_index < s->directory.next);
2153     assert(mapping->mode & MODE_DIRECTORY);
2154     assert(dir_index == 0 || is_directory(direntry));
2155 
2156     mapping->info.dir.parent_mapping_index = parent_mapping_index;
2157 
2158     if (first_cluster == 0) {
2159 	old_cluster_count = new_cluster_count =
2160 	    s->last_cluster_of_root_directory;
2161     } else {
2162 	for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2163 		c = fat_get(s, c))
2164 	    old_cluster_count++;
2165 
2166 	for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2167 		c = modified_fat_get(s, c))
2168 	    new_cluster_count++;
2169     }
2170 
2171     if (new_cluster_count > old_cluster_count) {
2172 	if (insert_direntries(s,
2173 		current_dir_index + factor * old_cluster_count,
2174 		factor * (new_cluster_count - old_cluster_count)) == NULL)
2175 	    return -1;
2176     } else if (new_cluster_count < old_cluster_count)
2177 	remove_direntries(s,
2178 		current_dir_index + factor * new_cluster_count,
2179 		factor * (old_cluster_count - new_cluster_count));
2180 
2181     for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
2182 	void* direntry = array_get(&(s->directory), current_dir_index);
2183 	int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2184 		s->sectors_per_cluster);
2185 	if (ret)
2186 	    return ret;
2187 	assert(!strncmp(s->directory.pointer, "QEMU", 4));
2188 	current_dir_index += factor;
2189     }
2190 
2191     ret = commit_mappings(s, first_cluster, dir_index);
2192     if (ret)
2193 	return ret;
2194 
2195     /* recurse */
2196     for (i = 0; i < factor * new_cluster_count; i++) {
2197 	direntry = array_get(&(s->directory), first_dir_index + i);
2198 	if (is_directory(direntry) && !is_dot(direntry)) {
2199 	    mapping = find_mapping_for_cluster(s, first_cluster);
2200 	    assert(mapping->mode & MODE_DIRECTORY);
2201 	    ret = commit_direntries(s, first_dir_index + i,
2202 		array_index(&(s->mapping), mapping));
2203 	    if (ret)
2204 		return ret;
2205 	}
2206     }
2207 
2208     return 0;
2209 }
2210 
2211 /* commit one file (adjust contents, adjust mapping),
2212    return first_mapping_index */
commit_one_file(BDRVVVFATState * s,int dir_index,uint32_t offset)2213 static int commit_one_file(BDRVVVFATState* s,
2214 	int dir_index, uint32_t offset)
2215 {
2216     direntry_t* direntry = array_get(&(s->directory), dir_index);
2217     uint32_t c = begin_of_direntry(direntry);
2218     uint32_t first_cluster = c;
2219     mapping_t* mapping = find_mapping_for_cluster(s, c);
2220     uint32_t size = filesize_of_direntry(direntry);
2221     char* cluster = qemu_malloc(s->cluster_size);
2222     uint32_t i;
2223     int fd = 0;
2224 
2225     assert(offset < size);
2226     assert((offset % s->cluster_size) == 0);
2227 
2228     for (i = s->cluster_size; i < offset; i += s->cluster_size)
2229 	c = modified_fat_get(s, c);
2230 
2231     fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
2232     if (fd < 0) {
2233 	fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2234 		strerror(errno), errno);
2235 	return fd;
2236     }
2237     if (offset > 0)
2238 	if (lseek(fd, offset, SEEK_SET) != offset)
2239 	    return -3;
2240 
2241     while (offset < size) {
2242 	uint32_t c1;
2243 	int rest_size = (size - offset > s->cluster_size ?
2244 		s->cluster_size : size - offset);
2245 	int ret;
2246 
2247 	c1 = modified_fat_get(s, c);
2248 
2249 	assert((size - offset == 0 && fat_eof(s, c)) ||
2250 		(size > offset && c >=2 && !fat_eof(s, c)));
2251 
2252 	ret = vvfat_read(s->bs, cluster2sector(s, c),
2253 	    (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
2254 
2255 	if (ret < 0)
2256 	    return ret;
2257 
2258 	if (write(fd, cluster, rest_size) < 0)
2259 	    return -2;
2260 
2261 	offset += rest_size;
2262 	c = c1;
2263     }
2264 
2265     if (ftruncate(fd, size)) {
2266         perror("ftruncate()");
2267         close(fd);
2268         return -4;
2269     }
2270     close(fd);
2271 
2272     return commit_mappings(s, first_cluster, dir_index);
2273 }
2274 
2275 #ifdef DEBUG
2276 /* test, if all mappings point to valid direntries */
check1(BDRVVVFATState * s)2277 static void check1(BDRVVVFATState* s)
2278 {
2279     int i;
2280     for (i = 0; i < s->mapping.next; i++) {
2281 	mapping_t* mapping = array_get(&(s->mapping), i);
2282 	if (mapping->mode & MODE_DELETED) {
2283 	    fprintf(stderr, "deleted\n");
2284 	    continue;
2285 	}
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     /* Check if we're operating in read-only mode */
2669     if (s->qcow == NULL) {
2670         return -EACCES;
2671     }
2672 
2673     vvfat_close_current_file(s);
2674 
2675     /*
2676      * Some sanity checks:
2677      * - do not allow writing to the boot sector
2678      * - do not allow to write non-ASCII filenames
2679      */
2680 
2681     if (sector_num < s->first_sectors_number)
2682 	return -1;
2683 
2684     for (i = sector2cluster(s, sector_num);
2685 	    i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
2686 	mapping_t* mapping = find_mapping_for_cluster(s, i);
2687 	if (mapping) {
2688 	    if (mapping->read_only) {
2689 		fprintf(stderr, "Tried to write to write-protected file %s\n",
2690 			mapping->path);
2691 		return -1;
2692 	    }
2693 
2694 	    if (mapping->mode & MODE_DIRECTORY) {
2695 		int begin = cluster2sector(s, i);
2696 		int end = begin + s->sectors_per_cluster, k;
2697 		int dir_index;
2698 		const direntry_t* direntries;
2699 		long_file_name lfn;
2700 
2701 		lfn_init(&lfn);
2702 
2703 		if (begin < sector_num)
2704 		    begin =