blob: 48a52e3116cfcd06b5b3bac04dbd059d46e05d5b [file] [log] [blame]
bellarda0464332005-12-18 18:29:50 +00001/* vim:set shiftwidth=4 ts=8: */
bellardde167e42005-04-28 21:15:08 +00002/*
3 * QEMU Block driver for virtual VFAT (shadows a local directory)
4 *
bellarda0464332005-12-18 18:29:50 +00005 * Copyright (c) 2004,2005 Johannes E. Schindelin
bellardde167e42005-04-28 21:15:08 +00006 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25#include <sys/stat.h>
26#include <dirent.h>
27#include <assert.h>
28#include "vl.h"
29#include "block_int.h"
30
bellarda0464332005-12-18 18:29:50 +000031#ifndef S_IWGRP
32#define S_IWGRP 0
33#endif
34#ifndef S_IWOTH
35#define S_IWOTH 0
36#endif
bellardde167e42005-04-28 21:15:08 +000037
bellarda0464332005-12-18 18:29:50 +000038/* 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 */
bellardde167e42005-04-28 21:15:08 +000045
bellarda0464332005-12-18 18:29:50 +000046/* #define DEBUG */
47
48#ifdef DEBUG
49
50#define DLOG(a) a
51
52#undef stderr
53#define stderr STDERR
54FILE* stderr = NULL;
55
56static void checkpoint();
57
58#ifdef __MINGW32__
59void 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
bellard6bcb76c2006-09-09 12:03:20 +000064#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
bellarda0464332005-12-18 18:29:50 +000065#endif
66
67#else
68
69#define DLOG(a)
70
71#endif
bellardde167e42005-04-28 21:15:08 +000072
73/* dynamic array functions */
74typedef struct array_t {
75 char* pointer;
76 unsigned int size,next,item_size;
77} array_t;
78
79static inline void array_init(array_t* array,unsigned int item_size)
80{
81 array->pointer=0;
82 array->size=0;
83 array->next=0;
84 array->item_size=item_size;
85}
86
87static inline void array_free(array_t* array)
88{
89 if(array->pointer)
90 free(array->pointer);
91 array->size=array->next=0;
92}
93
bellarda0464332005-12-18 18:29:50 +000094/* does not automatically grow */
bellardde167e42005-04-28 21:15:08 +000095static inline void* array_get(array_t* array,unsigned int index) {
bellarda0464332005-12-18 18:29:50 +000096 assert(index >= 0);
97 assert(index < array->next);
98 return array->pointer + index * array->item_size;
99}
100
101static inline int array_ensure_allocated(array_t* array, int index)
102{
103 if((index + 1) * array->item_size > array->size) {
104 int new_size = (index + 32) * array->item_size;
105 array->pointer = realloc(array->pointer, new_size);
106 if (!array->pointer)
107 return -1;
108 array->size = new_size;
109 array->next = index + 1;
bellardde167e42005-04-28 21:15:08 +0000110 }
bellarda0464332005-12-18 18:29:50 +0000111
112 return 0;
bellardde167e42005-04-28 21:15:08 +0000113}
114
115static inline void* array_get_next(array_t* array) {
bellarda0464332005-12-18 18:29:50 +0000116 unsigned int next = array->next;
117 void* result;
118
119 if (array_ensure_allocated(array, next) < 0)
120 return NULL;
121
122 array->next = next + 1;
123 result = array_get(array, next);
124
bellardde167e42005-04-28 21:15:08 +0000125 return result;
126}
127
128static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
129 if((array->next+count)*array->item_size>array->size) {
130 int increment=count*array->item_size;
131 array->pointer=realloc(array->pointer,array->size+increment);
132 if(!array->pointer)
133 return 0;
134 array->size+=increment;
135 }
136 memmove(array->pointer+(index+count)*array->item_size,
137 array->pointer+index*array->item_size,
138 (array->next-index)*array->item_size);
139 array->next+=count;
140 return array->pointer+index*array->item_size;
141}
142
143/* this performs a "roll", so that the element which was at index_from becomes
144 * index_to, but the order of all other elements is preserved. */
145static inline int array_roll(array_t* array,int index_to,int index_from,int count)
146{
147 char* buf;
148 char* from;
149 char* to;
150 int is;
151
152 if(!array ||
153 index_to<0 || index_to>=array->next ||
154 index_from<0 || index_from>=array->next)
155 return -1;
156
157 if(index_to==index_from)
158 return 0;
159
160 is=array->item_size;
161 from=array->pointer+index_from*is;
162 to=array->pointer+index_to*is;
163 buf=malloc(is*count);
164 memcpy(buf,from,is*count);
165
166 if(index_to<index_from)
167 memmove(to+is*count,to,from-to);
168 else
169 memmove(from,from+is*count,to-from);
170
171 memcpy(to,buf,is*count);
172
173 free(buf);
174
175 return 0;
176}
177
bellarda0464332005-12-18 18:29:50 +0000178inline int array_remove_slice(array_t* array,int index, int count)
179{
180 assert(index >=0);
181 assert(count > 0);
182 assert(index + count <= array->next);
183 if(array_roll(array,array->next-1,index,count))
184 return -1;
185 array->next -= count;
186 return 0;
187}
188
bellardde167e42005-04-28 21:15:08 +0000189int array_remove(array_t* array,int index)
190{
bellarda0464332005-12-18 18:29:50 +0000191 return array_remove_slice(array, index, 1);
192}
193
194/* return the index for a given member */
195int array_index(array_t* array, void* pointer)
196{
197 size_t offset = (char*)pointer - array->pointer;
198 assert(offset >= 0);
199 assert((offset % array->item_size) == 0);
200 assert(offset/array->item_size < array->next);
201 return offset/array->item_size;
bellardde167e42005-04-28 21:15:08 +0000202}
203
204/* These structures are used to fake a disk and the VFAT filesystem.
205 * For this reason we need to use __attribute__((packed)). */
206
207typedef struct bootsector_t {
208 uint8_t jump[3];
209 uint8_t name[8];
210 uint16_t sector_size;
211 uint8_t sectors_per_cluster;
212 uint16_t reserved_sectors;
213 uint8_t number_of_fats;
214 uint16_t root_entries;
bellarda0464332005-12-18 18:29:50 +0000215 uint16_t total_sectors16;
bellardde167e42005-04-28 21:15:08 +0000216 uint8_t media_type;
217 uint16_t sectors_per_fat;
218 uint16_t sectors_per_track;
219 uint16_t number_of_heads;
220 uint32_t hidden_sectors;
221 uint32_t total_sectors;
222 union {
223 struct {
224 uint8_t drive_number;
225 uint8_t current_head;
226 uint8_t signature;
227 uint32_t id;
228 uint8_t volume_label[11];
229 } __attribute__((packed)) fat16;
230 struct {
231 uint32_t sectors_per_fat;
232 uint16_t flags;
233 uint8_t major,minor;
234 uint32_t first_cluster_of_root_directory;
235 uint16_t info_sector;
236 uint16_t backup_boot_sector;
237 uint16_t ignored;
238 } __attribute__((packed)) fat32;
239 } u;
240 uint8_t fat_type[8];
241 uint8_t ignored[0x1c0];
242 uint8_t magic[2];
243} __attribute__((packed)) bootsector_t;
244
245typedef struct partition_t {
246 uint8_t attributes; /* 0x80 = bootable */
247 uint8_t start_head;
248 uint8_t start_sector;
249 uint8_t start_cylinder;
bellarda0464332005-12-18 18:29:50 +0000250 uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xb = FAT32 */
bellardde167e42005-04-28 21:15:08 +0000251 uint8_t end_head;
252 uint8_t end_sector;
253 uint8_t end_cylinder;
254 uint32_t start_sector_long;
255 uint32_t end_sector_long;
256} __attribute__((packed)) partition_t;
257
258typedef struct mbr_t {
259 uint8_t ignored[0x1be];
260 partition_t partition[4];
261 uint8_t magic[2];
262} __attribute__((packed)) mbr_t;
263
264typedef struct direntry_t {
265 uint8_t name[8];
266 uint8_t extension[3];
267 uint8_t attributes;
268 uint8_t reserved[2];
269 uint16_t ctime;
270 uint16_t cdate;
271 uint16_t adate;
272 uint16_t begin_hi;
273 uint16_t mtime;
274 uint16_t mdate;
275 uint16_t begin;
276 uint32_t size;
277} __attribute__((packed)) direntry_t;
278
279/* this structure are used to transparently access the files */
280
281typedef struct mapping_t {
bellarda0464332005-12-18 18:29:50 +0000282 /* begin is the first cluster, end is the last+1 */
283 uint32_t begin,end;
bellardde167e42005-04-28 21:15:08 +0000284 /* as s->directory is growable, no pointer may be used here */
285 unsigned int dir_index;
bellarda0464332005-12-18 18:29:50 +0000286 /* the clusters of a file may be in any order; this points to the first */
287 int first_mapping_index;
288 union {
289 /* offset is
290 * - the offset in the file (in clusters) for a file, or
291 * - the next cluster of the directory for a directory, and
292 * - the address of the buffer for a faked entry
293 */
294 struct {
295 uint32_t offset;
296 } file;
297 struct {
298 int parent_mapping_index;
299 int first_dir_index;
300 } dir;
301 } info;
302 /* path contains the full path, i.e. it always starts with s->path */
303 char* path;
304
305 enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2,
306 MODE_DIRECTORY = 4, MODE_FAKED = 8,
307 MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
308 int read_only;
bellardde167e42005-04-28 21:15:08 +0000309} mapping_t;
310
bellarda0464332005-12-18 18:29:50 +0000311#ifdef DEBUG
312static void print_direntry(const struct direntry_t*);
313static void print_mapping(const struct mapping_t* mapping);
314#endif
bellardde167e42005-04-28 21:15:08 +0000315
316/* here begins the real VVFAT driver */
317
318typedef struct BDRVVVFATState {
bellarda0464332005-12-18 18:29:50 +0000319 BlockDriverState* bs; /* pointer to parent */
bellardde167e42005-04-28 21:15:08 +0000320 unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
321 unsigned char first_sectors[0x40*0x200];
322
323 int fat_type; /* 16 or 32 */
324 array_t fat,directory,mapping;
325
326 unsigned int cluster_size;
327 unsigned int sectors_per_cluster;
328 unsigned int sectors_per_fat;
329 unsigned int sectors_of_root_directory;
bellarda0464332005-12-18 18:29:50 +0000330 uint32_t last_cluster_of_root_directory;
bellardde167e42005-04-28 21:15:08 +0000331 unsigned int faked_sectors; /* how many sectors are faked before file data */
332 uint32_t sector_count; /* total number of sectors of the partition */
333 uint32_t cluster_count; /* total number of clusters of this partition */
bellardde167e42005-04-28 21:15:08 +0000334 uint32_t max_fat_value;
335
336 int current_fd;
bellardde167e42005-04-28 21:15:08 +0000337 mapping_t* current_mapping;
bellarda0464332005-12-18 18:29:50 +0000338 unsigned char* cluster; /* points to current cluster */
339 unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
bellardde167e42005-04-28 21:15:08 +0000340 unsigned int current_cluster;
341
342 /* write support */
bellarda0464332005-12-18 18:29:50 +0000343 BlockDriverState* write_target;
344 char* qcow_filename;
345 BlockDriverState* qcow;
346 void* fat2;
347 char* used_clusters;
348 array_t commits;
349 const char* path;
350 int downcase_short_names;
bellardde167e42005-04-28 21:15:08 +0000351} BDRVVVFATState;
352
353
bellardde167e42005-04-28 21:15:08 +0000354static void init_mbr(BDRVVVFATState* s)
355{
356 /* TODO: if the files mbr.img and bootsect.img exist, use them */
357 mbr_t* real_mbr=(mbr_t*)s->first_sectors;
358 partition_t* partition=&(real_mbr->partition[0]);
359
360 memset(s->first_sectors,0,512);
361
362 partition->attributes=0x80; /* bootable */
363 partition->start_head=1;
364 partition->start_sector=1;
365 partition->start_cylinder=0;
bellarda0464332005-12-18 18:29:50 +0000366 /* FAT12/FAT16/FAT32 */
367 partition->fs_type=(s->fat_type==12?0x1:s->fat_type==16?0x6:0xb);
368 partition->end_head=s->bs->heads-1;
bellardde167e42005-04-28 21:15:08 +0000369 partition->end_sector=0xff; /* end sector & upper 2 bits of cylinder */;
370 partition->end_cylinder=0xff; /* lower 8 bits of end cylinder */;
bellarda0464332005-12-18 18:29:50 +0000371 partition->start_sector_long=cpu_to_le32(s->bs->secs);
bellardde167e42005-04-28 21:15:08 +0000372 partition->end_sector_long=cpu_to_le32(s->sector_count);
373
374 real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
375}
376
bellarda0464332005-12-18 18:29:50 +0000377/* direntry functions */
378
bellardde167e42005-04-28 21:15:08 +0000379/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
380static inline int short2long_name(unsigned char* dest,const char* src)
381{
382 int i;
383 for(i=0;i<129 && src[i];i++) {
384 dest[2*i]=src[i];
385 dest[2*i+1]=0;
386 }
387 dest[2*i]=dest[2*i+1]=0;
388 for(i=2*i+2;(i%26);i++)
389 dest[i]=0xff;
390 return i;
391}
392
393static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
394{
395 char buffer[258];
396 int length=short2long_name(buffer,filename),
397 number_of_entries=(length+25)/26,i;
398 direntry_t* entry;
399
400 for(i=0;i<number_of_entries;i++) {
401 entry=array_get_next(&(s->directory));
402 entry->attributes=0xf;
403 entry->reserved[0]=0;
404 entry->begin=0;
405 entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
406 }
407 for(i=0;i<length;i++) {
408 int offset=(i%26);
409 if(offset<10) offset=1+offset;
410 else if(offset<22) offset=14+offset-10;
411 else offset=28+offset-22;
412 entry=array_get(&(s->directory),s->directory.next-1-(i/26));
413 entry->name[offset]=buffer[i];
414 }
415 return array_get(&(s->directory),s->directory.next-number_of_entries);
416}
417
bellarda0464332005-12-18 18:29:50 +0000418static char is_free(const direntry_t* direntry)
419{
420 /* return direntry->name[0]==0 ; */
421 return direntry->attributes == 0 || direntry->name[0]==0xe5;
422}
423
424static char is_volume_label(const direntry_t* direntry)
425{
426 return direntry->attributes == 0x28;
427}
428
429static char is_long_name(const direntry_t* direntry)
430{
431 return direntry->attributes == 0xf;
432}
433
434static char is_short_name(const direntry_t* direntry)
435{
436 return !is_volume_label(direntry) && !is_long_name(direntry)
437 && !is_free(direntry);
438}
439
440static char is_directory(const direntry_t* direntry)
441{
442 return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
443}
444
445static inline char is_dot(const direntry_t* direntry)
446{
447 return is_short_name(direntry) && direntry->name[0] == '.';
448}
449
450static char is_file(const direntry_t* direntry)
451{
452 return is_short_name(direntry) && !is_directory(direntry);
453}
454
455static inline uint32_t begin_of_direntry(const direntry_t* direntry)
456{
457 return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
458}
459
460static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
461{
462 return le32_to_cpu(direntry->size);
463}
464
465static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
466{
467 direntry->begin = cpu_to_le16(begin & 0xffff);
468 direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
469}
470
bellardde167e42005-04-28 21:15:08 +0000471/* fat functions */
472
bellarda0464332005-12-18 18:29:50 +0000473static inline uint8_t fat_chksum(const direntry_t* entry)
bellardde167e42005-04-28 21:15:08 +0000474{
475 uint8_t chksum=0;
476 int i;
477
478 for(i=0;i<11;i++)
479 chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0))
480 +(unsigned char)entry->name[i];
481
482 return chksum;
483}
484
485/* if return_time==0, this returns the fat_date, else the fat_time */
486static uint16_t fat_datetime(time_t time,int return_time) {
487 struct tm* t;
488#ifdef _WIN32
489 t=localtime(&time); /* this is not thread safe */
490#else
491 struct tm t1;
492 t=&t1;
493 localtime_r(&time,t);
494#endif
495 if(return_time)
496 return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
497 return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
498}
499
500static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
501{
bellarda0464332005-12-18 18:29:50 +0000502 if(s->fat_type==32) {
503 uint32_t* entry=array_get(&(s->fat),cluster);
504 *entry=cpu_to_le32(value);
bellardde167e42005-04-28 21:15:08 +0000505 } else if(s->fat_type==16) {
506 uint16_t* entry=array_get(&(s->fat),cluster);
507 *entry=cpu_to_le16(value&0xffff);
508 } else {
bellarda0464332005-12-18 18:29:50 +0000509 int offset = (cluster*3/2);
510 unsigned char* p = array_get(&(s->fat), offset);
511 switch (cluster&1) {
512 case 0:
513 p[0] = value&0xff;
514 p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
515 break;
516 case 1:
517 p[0] = (p[0]&0xf) | ((value&0xf)<<4);
518 p[1] = (value>>4);
519 break;
520 }
bellardde167e42005-04-28 21:15:08 +0000521 }
522}
523
524static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
525{
bellarda0464332005-12-18 18:29:50 +0000526 if(s->fat_type==32) {
527 uint32_t* entry=array_get(&(s->fat),cluster);
528 return le32_to_cpu(*entry);
bellardde167e42005-04-28 21:15:08 +0000529 } else if(s->fat_type==16) {
530 uint16_t* entry=array_get(&(s->fat),cluster);
531 return le16_to_cpu(*entry);
532 } else {
bellarda0464332005-12-18 18:29:50 +0000533 const uint8_t* x=s->fat.pointer+cluster*3/2;
534 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
bellardde167e42005-04-28 21:15:08 +0000535 }
536}
537
538static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
539{
540 if(fat_entry>s->max_fat_value-8)
541 return -1;
542 return 0;
543}
544
545static inline void init_fat(BDRVVVFATState* s)
546{
bellarda0464332005-12-18 18:29:50 +0000547 if (s->fat_type == 12) {
548 array_init(&(s->fat),1);
549 array_ensure_allocated(&(s->fat),
550 s->sectors_per_fat * 0x200 * 3 / 2 - 1);
551 } else {
552 array_init(&(s->fat),(s->fat_type==32?4:2));
553 array_ensure_allocated(&(s->fat),
554 s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
555 }
bellardde167e42005-04-28 21:15:08 +0000556 memset(s->fat.pointer,0,s->fat.size);
bellardde167e42005-04-28 21:15:08 +0000557
bellardde167e42005-04-28 21:15:08 +0000558 switch(s->fat_type) {
559 case 12: s->max_fat_value=0xfff; break;
560 case 16: s->max_fat_value=0xffff; break;
bellarda0464332005-12-18 18:29:50 +0000561 case 32: s->max_fat_value=0x0fffffff; break;
bellardde167e42005-04-28 21:15:08 +0000562 default: s->max_fat_value=0; /* error... */
563 }
564
565}
566
bellarda0464332005-12-18 18:29:50 +0000567/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
568/* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
569static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
570 unsigned int directory_start, const char* filename, int is_dot)
bellardde167e42005-04-28 21:15:08 +0000571{
bellarda0464332005-12-18 18:29:50 +0000572 int i,j,long_index=s->directory.next;
bellardde167e42005-04-28 21:15:08 +0000573 direntry_t* entry=0;
574 direntry_t* entry_long=0;
575
576 if(is_dot) {
577 entry=array_get_next(&(s->directory));
578 memset(entry->name,0x20,11);
579 memcpy(entry->name,filename,strlen(filename));
580 return entry;
581 }
582
bellardde167e42005-04-28 21:15:08 +0000583 entry_long=create_long_filename(s,filename);
bellarda0464332005-12-18 18:29:50 +0000584
585 i = strlen(filename);
586 for(j = i - 1; j>0 && filename[j]!='.';j--);
587 if (j > 0)
588 i = (j > 8 ? 8 : j);
589 else if (i > 8)
590 i = 8;
591
bellardde167e42005-04-28 21:15:08 +0000592 entry=array_get_next(&(s->directory));
593 memset(entry->name,0x20,11);
594 strncpy(entry->name,filename,i);
595
bellarda0464332005-12-18 18:29:50 +0000596 if(j > 0)
597 for (i = 0; i < 3 && filename[j+1+i]; i++)
598 entry->extension[i] = filename[j+1+i];
bellardde167e42005-04-28 21:15:08 +0000599
600 /* upcase & remove unwanted characters */
601 for(i=10;i>=0;i--) {
bellarda0464332005-12-18 18:29:50 +0000602 if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
bellardde167e42005-04-28 21:15:08 +0000603 if(entry->name[i]<=' ' || entry->name[i]>0x7f
bellarda0464332005-12-18 18:29:50 +0000604 || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
bellardde167e42005-04-28 21:15:08 +0000605 entry->name[i]='_';
606 else if(entry->name[i]>='a' && entry->name[i]<='z')
607 entry->name[i]+='A'-'a';
608 }
609
610 /* mangle duplicates */
611 while(1) {
612 direntry_t* entry1=array_get(&(s->directory),directory_start);
613 int j;
614
615 for(;entry1<entry;entry1++)
bellarda0464332005-12-18 18:29:50 +0000616 if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
bellardde167e42005-04-28 21:15:08 +0000617 break; /* found dupe */
618 if(entry1==entry) /* no dupe found */
619 break;
620
621 /* use all 8 characters of name */
622 if(entry->name[7]==' ') {
623 int j;
624 for(j=6;j>0 && entry->name[j]==' ';j--)
625 entry->name[j]='~';
626 }
627
628 /* increment number */
629 for(j=7;j>0 && entry->name[j]=='9';j--)
630 entry->name[j]='0';
631 if(j>0) {
632 if(entry->name[j]<'0' || entry->name[j]>'9')
633 entry->name[j]='0';
634 else
635 entry->name[j]++;
636 }
637 }
638
639 /* calculate checksum; propagate to long name */
640 if(entry_long) {
641 uint8_t chksum=fat_chksum(entry);
642
643 /* calculate anew, because realloc could have taken place */
644 entry_long=array_get(&(s->directory),long_index);
bellarda0464332005-12-18 18:29:50 +0000645 while(entry_long<entry && is_long_name(entry_long)) {
bellardde167e42005-04-28 21:15:08 +0000646 entry_long->reserved[1]=chksum;
647 entry_long++;
648 }
649 }
650
651 return entry;
652}
653
bellarda0464332005-12-18 18:29:50 +0000654/*
655 * Read a directory. (the index of the corresponding mapping must be passed).
656 */
657static int read_directory(BDRVVVFATState* s, int mapping_index)
bellardde167e42005-04-28 21:15:08 +0000658{
bellarda0464332005-12-18 18:29:50 +0000659 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
660 direntry_t* direntry;
661 const char* dirname = mapping->path;
662 int first_cluster = mapping->begin;
663 int parent_index = mapping->info.dir.parent_mapping_index;
664 mapping_t* parent_mapping = (mapping_t*)
665 (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : 0);
666 int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
bellardde167e42005-04-28 21:15:08 +0000667
668 DIR* dir=opendir(dirname);
669 struct dirent* entry;
bellardde167e42005-04-28 21:15:08 +0000670 int i;
671
bellarda0464332005-12-18 18:29:50 +0000672 assert(mapping->mode & MODE_DIRECTORY);
673
674 if(!dir) {
675 mapping->end = mapping->begin;
bellardde167e42005-04-28 21:15:08 +0000676 return -1;
bellarda0464332005-12-18 18:29:50 +0000677 }
678
679 i = mapping->info.dir.first_dir_index =
680 first_cluster == 0 ? 0 : s->directory.next;
681
682 /* actually read the directory, and allocate the mappings */
bellardde167e42005-04-28 21:15:08 +0000683 while((entry=readdir(dir))) {
684 unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
685 char* buffer;
686 direntry_t* direntry;
bellarda0464332005-12-18 18:29:50 +0000687 struct stat st;
bellardde167e42005-04-28 21:15:08 +0000688 int is_dot=!strcmp(entry->d_name,".");
689 int is_dotdot=!strcmp(entry->d_name,"..");
690
bellarda0464332005-12-18 18:29:50 +0000691 if(first_cluster == 0 && (is_dotdot || is_dot))
bellardde167e42005-04-28 21:15:08 +0000692 continue;
693
694 buffer=(char*)malloc(length);
bellarda0464332005-12-18 18:29:50 +0000695 assert(buffer);
bellardde167e42005-04-28 21:15:08 +0000696 snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
697
698 if(stat(buffer,&st)<0) {
699 free(buffer);
700 continue;
701 }
702
703 /* create directory entry for this file */
bellarda0464332005-12-18 18:29:50 +0000704 direntry=create_short_and_long_name(s, i, entry->d_name,
705 is_dot || is_dotdot);
bellardde167e42005-04-28 21:15:08 +0000706 direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
707 direntry->reserved[0]=direntry->reserved[1]=0;
708 direntry->ctime=fat_datetime(st.st_ctime,1);
709 direntry->cdate=fat_datetime(st.st_ctime,0);
710 direntry->adate=fat_datetime(st.st_atime,0);
711 direntry->begin_hi=0;
712 direntry->mtime=fat_datetime(st.st_mtime,1);
713 direntry->mdate=fat_datetime(st.st_mtime,0);
714 if(is_dotdot)
bellarda0464332005-12-18 18:29:50 +0000715 set_begin_of_direntry(direntry, first_cluster_of_parent);
bellardde167e42005-04-28 21:15:08 +0000716 else if(is_dot)
bellarda0464332005-12-18 18:29:50 +0000717 set_begin_of_direntry(direntry, first_cluster);
bellardde167e42005-04-28 21:15:08 +0000718 else
bellarda0464332005-12-18 18:29:50 +0000719 direntry->begin=0; /* do that later */
720 if (st.st_size > 0x7fffffff) {
721 fprintf(stderr, "File %s is larger than 2GB\n", buffer);
722 free(buffer);
723 return -2;
724 }
725 direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
bellardde167e42005-04-28 21:15:08 +0000726
727 /* create mapping for this file */
bellarda0464332005-12-18 18:29:50 +0000728 if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
729 s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
bellardde167e42005-04-28 21:15:08 +0000730 s->current_mapping->begin=0;
731 s->current_mapping->end=st.st_size;
bellarda0464332005-12-18 18:29:50 +0000732 /*
733 * we get the direntry of the most recent direntry, which
734 * contains the short name and all the relevant information.
735 */
bellardde167e42005-04-28 21:15:08 +0000736 s->current_mapping->dir_index=s->directory.next-1;
bellarda0464332005-12-18 18:29:50 +0000737 s->current_mapping->first_mapping_index = -1;
738 if (S_ISDIR(st.st_mode)) {
739 s->current_mapping->mode = MODE_DIRECTORY;
740 s->current_mapping->info.dir.parent_mapping_index =
741 mapping_index;
742 } else {
743 s->current_mapping->mode = MODE_UNDEFINED;
744 s->current_mapping->info.file.offset = 0;
745 }
746 s->current_mapping->path=buffer;
747 s->current_mapping->read_only =
748 (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
bellardde167e42005-04-28 21:15:08 +0000749 }
750 }
751 closedir(dir);
752
753 /* fill with zeroes up to the end of the cluster */
754 while(s->directory.next%(0x10*s->sectors_per_cluster)) {
755 direntry_t* direntry=array_get_next(&(s->directory));
756 memset(direntry,0,sizeof(direntry_t));
757 }
758
bellarda0464332005-12-18 18:29:50 +0000759/* TODO: if there are more entries, bootsector has to be adjusted! */
760#define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
761 if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
762 /* root directory */
763 int cur = s->directory.next;
764 array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
765 memset(array_get(&(s->directory), cur), 0,
766 (ROOT_ENTRIES - cur) * sizeof(direntry_t));
bellardde167e42005-04-28 21:15:08 +0000767 }
bellarda0464332005-12-18 18:29:50 +0000768
769 /* reget the mapping, since s->mapping was possibly realloc()ed */
770 mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
771 first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
772 * 0x20 / s->cluster_size;
773 mapping->end = first_cluster;
bellardde167e42005-04-28 21:15:08 +0000774
bellarda0464332005-12-18 18:29:50 +0000775 direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
776 set_begin_of_direntry(direntry, mapping->begin);
777
bellardde167e42005-04-28 21:15:08 +0000778 return 0;
779}
780
bellarda0464332005-12-18 18:29:50 +0000781static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
bellardde167e42005-04-28 21:15:08 +0000782{
bellarda0464332005-12-18 18:29:50 +0000783 return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
784}
785
786static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
787{
788 return s->faked_sectors + s->sectors_per_cluster * cluster_num;
789}
790
791static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
792{
793 return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
794}
795
796#ifdef DBG
797static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
798{
799 if(mapping->mode==MODE_UNDEFINED)
800 return 0;
801 return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
802}
803#endif
804
805static int init_directories(BDRVVVFATState* s,
806 const char* dirname)
807{
808 bootsector_t* bootsector;
809 mapping_t* mapping;
bellardde167e42005-04-28 21:15:08 +0000810 unsigned int i;
811 unsigned int cluster;
812
813 memset(&(s->first_sectors[0]),0,0x40*0x200);
814
bellardde167e42005-04-28 21:15:08 +0000815 s->cluster_size=s->sectors_per_cluster*0x200;
bellarda0464332005-12-18 18:29:50 +0000816 s->cluster_buffer=malloc(s->cluster_size);
817 assert(s->cluster_buffer);
818
819 /*
820 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
821 * where sc is sector_count,
822 * spf is sectors_per_fat,
823 * spc is sectors_per_clusters, and
824 * fat_type = 12, 16 or 32.
825 */
826 i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
827 s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
bellardde167e42005-04-28 21:15:08 +0000828
829 array_init(&(s->mapping),sizeof(mapping_t));
830 array_init(&(s->directory),sizeof(direntry_t));
bellardde167e42005-04-28 21:15:08 +0000831
832 /* add volume label */
833 {
834 direntry_t* entry=array_get_next(&(s->directory));
835 entry->attributes=0x28; /* archive | volume label */
836 snprintf(entry->name,11,"QEMU VVFAT");
837 }
838
bellardde167e42005-04-28 21:15:08 +0000839 /* Now build FAT, and write back information into directory */
840 init_fat(s);
841
bellarda0464332005-12-18 18:29:50 +0000842 s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
843 s->cluster_count=sector2cluster(s, s->sector_count);
bellardde167e42005-04-28 21:15:08 +0000844
bellarda0464332005-12-18 18:29:50 +0000845 mapping = array_get_next(&(s->mapping));
846 mapping->begin = 0;
847 mapping->dir_index = 0;
848 mapping->info.dir.parent_mapping_index = -1;
849 mapping->first_mapping_index = -1;
850 mapping->path = strdup(dirname);
851 i = strlen(mapping->path);
852 if (i > 0 && mapping->path[i - 1] == '/')
853 mapping->path[i - 1] = '\0';
854 mapping->mode = MODE_DIRECTORY;
855 mapping->read_only = 0;
856 s->path = mapping->path;
bellardde167e42005-04-28 21:15:08 +0000857
bellarda0464332005-12-18 18:29:50 +0000858 for (i = 0, cluster = 0; i < s->mapping.next; i++) {
859 int j;
860 /* MS-DOS expects the FAT to be 0 for the root directory
861 * (except for the media byte). */
862 /* LATER TODO: still true for FAT32? */
863 int fix_fat = (i != 0);
864 mapping = array_get(&(s->mapping), i);
bellardde167e42005-04-28 21:15:08 +0000865
bellarda0464332005-12-18 18:29:50 +0000866 if (mapping->mode & MODE_DIRECTORY) {
867 mapping->begin = cluster;
868 if(read_directory(s, i)) {
869 fprintf(stderr, "Could not read directory %s\n",
870 mapping->path);
bellardde167e42005-04-28 21:15:08 +0000871 return -1;
872 }
bellarda0464332005-12-18 18:29:50 +0000873 mapping = array_get(&(s->mapping), i);
874 } else {
875 assert(mapping->mode == MODE_UNDEFINED);
bellardde167e42005-04-28 21:15:08 +0000876 mapping->mode=MODE_NORMAL;
bellarda0464332005-12-18 18:29:50 +0000877 mapping->begin = cluster;
878 if (mapping->end > 0) {
879 direntry_t* direntry = array_get(&(s->directory),
880 mapping->dir_index);
bellardde167e42005-04-28 21:15:08 +0000881
bellarda0464332005-12-18 18:29:50 +0000882 mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
883 set_begin_of_direntry(direntry, mapping->begin);
884 } else {
885 mapping->end = cluster + 1;
886 fix_fat = 0;
887 }
888 }
889
890 assert(mapping->begin < mapping->end);
891
892 /* fix fat for entry */
893 if (fix_fat) {
894 for(j = mapping->begin; j < mapping->end - 1; j++)
895 fat_set(s, j, j+1);
896 fat_set(s, mapping->end - 1, s->max_fat_value);
897 }
898
899 /* next free cluster */
900 cluster = mapping->end;
901
902 if(cluster > s->cluster_count) {
903 fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type);
904 return -1;
bellardde167e42005-04-28 21:15:08 +0000905 }
906 }
907
bellarda0464332005-12-18 18:29:50 +0000908 mapping = array_get(&(s->mapping), 0);
909 s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
910 s->last_cluster_of_root_directory = mapping->end;
bellardde167e42005-04-28 21:15:08 +0000911
bellarda0464332005-12-18 18:29:50 +0000912 /* the FAT signature */
913 fat_set(s,0,s->max_fat_value);
914 fat_set(s,1,s->max_fat_value);
915
916 s->current_mapping = NULL;
917
918 bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
bellardde167e42005-04-28 21:15:08 +0000919 bootsector->jump[0]=0xeb;
920 bootsector->jump[1]=0x3e;
921 bootsector->jump[2]=0x90;
922 memcpy(bootsector->name,"QEMU ",8);
923 bootsector->sector_size=cpu_to_le16(0x200);
924 bootsector->sectors_per_cluster=s->sectors_per_cluster;
925 bootsector->reserved_sectors=cpu_to_le16(1);
926 bootsector->number_of_fats=0x2; /* number of FATs */
927 bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
bellarda0464332005-12-18 18:29:50 +0000928 bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
929 bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
930 s->fat.pointer[0] = bootsector->media_type;
bellardde167e42005-04-28 21:15:08 +0000931 bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
bellarda0464332005-12-18 18:29:50 +0000932 bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
933 bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
bellardde167e42005-04-28 21:15:08 +0000934 bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
bellarda0464332005-12-18 18:29:50 +0000935 bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
bellardde167e42005-04-28 21:15:08 +0000936
bellarda0464332005-12-18 18:29:50 +0000937 /* LATER TODO: if FAT32, this is wrong */
938 bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
bellardde167e42005-04-28 21:15:08 +0000939 bootsector->u.fat16.current_head=0;
940 bootsector->u.fat16.signature=0x29;
941 bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
942
943 memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
944 memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12 ":s->fat_type==16?"FAT16 ":"FAT32 "),8);
945 bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
946
947 return 0;
948}
949
bellard83f64092006-08-01 16:21:11 +0000950#ifdef DEBUG
bellarda0464332005-12-18 18:29:50 +0000951static BDRVVVFATState *vvv = NULL;
bellard83f64092006-08-01 16:21:11 +0000952#endif
bellarda0464332005-12-18 18:29:50 +0000953
954static int enable_write_target(BDRVVVFATState *s);
955static int is_consistent(BDRVVVFATState *s);
956
bellard83f64092006-08-01 16:21:11 +0000957static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
bellardde167e42005-04-28 21:15:08 +0000958{
959 BDRVVVFATState *s = bs->opaque;
bellarda0464332005-12-18 18:29:50 +0000960 int floppy = 0;
bellardde167e42005-04-28 21:15:08 +0000961 int i;
962
bellard83f64092006-08-01 16:21:11 +0000963#ifdef DEBUG
bellarda0464332005-12-18 18:29:50 +0000964 vvv = s;
bellard83f64092006-08-01 16:21:11 +0000965#endif
bellarda0464332005-12-18 18:29:50 +0000966
967DLOG(if (stderr == NULL) {
968 stderr = fopen("vvfat.log", "a");
969 setbuf(stderr, NULL);
970})
971
972 s->bs = bs;
973
bellardde167e42005-04-28 21:15:08 +0000974 s->fat_type=16;
bellarda0464332005-12-18 18:29:50 +0000975 /* LATER TODO: if FAT32, adjust */
bellardde167e42005-04-28 21:15:08 +0000976 s->sector_count=0xec04f;
bellarda0464332005-12-18 18:29:50 +0000977 s->sectors_per_cluster=0x10;
978 /* LATER TODO: this could be wrong for FAT32 */
979 bs->cyls=1023; bs->heads=15; bs->secs=63;
bellardde167e42005-04-28 21:15:08 +0000980
981 s->current_cluster=0xffffffff;
bellardde167e42005-04-28 21:15:08 +0000982
bellardde167e42005-04-28 21:15:08 +0000983 s->first_sectors_number=0x40;
bellarda0464332005-12-18 18:29:50 +0000984 /* read only is the default for safety */
985 bs->read_only = 1;
986 s->qcow = s->write_target = NULL;
987 s->qcow_filename = NULL;
988 s->fat2 = NULL;
989 s->downcase_short_names = 1;
bellardde167e42005-04-28 21:15:08 +0000990
bellarda0464332005-12-18 18:29:50 +0000991 if (!strstart(dirname, "fat:", NULL))
992 return -1;
993
994 if (strstr(dirname, ":rw:")) {
995 if (enable_write_target(s))
996 return -1;
997 bs->read_only = 0;
bellardde167e42005-04-28 21:15:08 +0000998 }
bellarda0464332005-12-18 18:29:50 +0000999
1000 if (strstr(dirname, ":floppy:")) {
1001 floppy = 1;
1002 s->fat_type = 12;
1003 s->first_sectors_number = 1;
1004 s->sectors_per_cluster=2;
1005 bs->cyls = 80; bs->heads = 2; bs->secs = 36;
1006 }
1007
1008 if (strstr(dirname, ":32:")) {
1009 fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1010 s->fat_type = 32;
1011 } else if (strstr(dirname, ":16:")) {
1012 s->fat_type = 16;
1013 } else if (strstr(dirname, ":12:")) {
1014 s->fat_type = 12;
1015 s->sector_count=2880;
1016 }
1017
1018 i = strrchr(dirname, ':') - dirname;
1019 assert(i >= 3);
1020 if (dirname[i-2] == ':' && isalpha(dirname[i-1]))
1021 /* workaround for DOS drive names */
1022 dirname += i-1;
1023 else
1024 dirname += i+1;
1025
1026 bs->total_sectors=bs->cyls*bs->heads*bs->secs;
1027 if (s->sector_count > bs->total_sectors)
1028 s->sector_count = bs->total_sectors;
1029 if(init_directories(s, dirname))
bellardde167e42005-04-28 21:15:08 +00001030 return -1;
1031
1032 if(s->first_sectors_number==0x40)
1033 init_mbr(s);
1034
bellarda0464332005-12-18 18:29:50 +00001035 /* for some reason or other, MS-DOS does not like to know about CHS... */
1036 if (floppy)
1037 bs->heads = bs->cyls = bs->secs = 0;
bellardde167e42005-04-28 21:15:08 +00001038
bellarda0464332005-12-18 18:29:50 +00001039 // assert(is_consistent(s));
bellardde167e42005-04-28 21:15:08 +00001040 return 0;
1041}
1042
1043static inline void vvfat_close_current_file(BDRVVVFATState *s)
1044{
1045 if(s->current_mapping) {
bellarda0464332005-12-18 18:29:50 +00001046 s->current_mapping = NULL;
1047 if (s->current_fd) {
1048 close(s->current_fd);
1049 s->current_fd = 0;
1050 }
bellardde167e42005-04-28 21:15:08 +00001051 }
bellarda0464332005-12-18 18:29:50 +00001052 s->current_cluster = -1;
bellardde167e42005-04-28 21:15:08 +00001053}
1054
1055/* mappings between index1 and index2-1 are supposed to be ordered
1056 * return value is the index of the last mapping for which end>cluster_num
1057 */
1058static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1059{
1060 int index3=index1+1;
bellardde167e42005-04-28 21:15:08 +00001061 while(1) {
1062 mapping_t* mapping;
1063 index3=(index1+index2)/2;
1064 mapping=array_get(&(s->mapping),index3);
bellarda0464332005-12-18 18:29:50 +00001065 assert(mapping->begin < mapping->end);
1066 if(mapping->begin>=cluster_num) {
bellardde167e42005-04-28 21:15:08 +00001067 assert(index2!=index3 || index2==0);
1068 if(index2==index3)
bellarda0464332005-12-18 18:29:50 +00001069 return index1;
bellardde167e42005-04-28 21:15:08 +00001070 index2=index3;
1071 } else {
1072 if(index1==index3)
bellarda0464332005-12-18 18:29:50 +00001073 return mapping->end<=cluster_num ? index2 : index1;
bellardde167e42005-04-28 21:15:08 +00001074 index1=index3;
1075 }
1076 assert(index1<=index2);
bellarda0464332005-12-18 18:29:50 +00001077 DLOG(mapping=array_get(&(s->mapping),index1);
1078 assert(mapping->begin<=cluster_num);
1079 assert(index2 >= s->mapping.next ||
1080 ((mapping = array_get(&(s->mapping),index2)) &&
1081 mapping->end>cluster_num)));
bellardde167e42005-04-28 21:15:08 +00001082 }
1083}
1084
1085static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
1086{
1087 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
1088 mapping_t* mapping;
1089 if(index>=s->mapping.next)
1090 return 0;
1091 mapping=array_get(&(s->mapping),index);
1092 if(mapping->begin>cluster_num)
1093 return 0;
bellarda0464332005-12-18 18:29:50 +00001094 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
bellardde167e42005-04-28 21:15:08 +00001095 return mapping;
1096}
1097
bellarda0464332005-12-18 18:29:50 +00001098/*
1099 * This function simply compares path == mapping->path. Since the mappings
1100 * are sorted by cluster, this is expensive: O(n).
1101 */
1102static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
1103 const char* path)
1104{
1105 int i;
1106
1107 for (i = 0; i < s->mapping.next; i++) {
1108 mapping_t* mapping = array_get(&(s->mapping), i);
1109 if (mapping->first_mapping_index < 0 &&
1110 !strcmp(path, mapping->path))
1111 return mapping;
1112 }
1113
1114 return NULL;
1115}
1116
1117static int open_file(BDRVVVFATState* s,mapping_t* mapping)
bellardde167e42005-04-28 21:15:08 +00001118{
1119 if(!mapping)
1120 return -1;
bellardde167e42005-04-28 21:15:08 +00001121 if(!s->current_mapping ||
bellarda0464332005-12-18 18:29:50 +00001122 strcmp(s->current_mapping->path,mapping->path)) {
bellardde167e42005-04-28 21:15:08 +00001123 /* open file */
bellarda0464332005-12-18 18:29:50 +00001124 int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
bellardde167e42005-04-28 21:15:08 +00001125 if(fd<0)
1126 return -1;
1127 vvfat_close_current_file(s);
1128 s->current_fd = fd;
bellardde167e42005-04-28 21:15:08 +00001129 s->current_mapping = mapping;
1130 }
1131 return 0;
1132}
1133
1134static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1135{
1136 if(s->current_cluster != cluster_num) {
1137 int result=0;
1138 off_t offset;
bellarda0464332005-12-18 18:29:50 +00001139 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
bellardde167e42005-04-28 21:15:08 +00001140 if(!s->current_mapping
1141 || s->current_mapping->begin>cluster_num
1142 || s->current_mapping->end<=cluster_num) {
1143 /* binary search of mappings for file */
1144 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
bellardde167e42005-04-28 21:15:08 +00001145
bellarda0464332005-12-18 18:29:50 +00001146 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1147
1148 if (mapping && mapping->mode & MODE_DIRECTORY) {
1149 vvfat_close_current_file(s);
1150 s->current_mapping = mapping;
1151read_cluster_directory:
1152 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
1153 s->cluster = s->directory.pointer+offset
1154 + 0x20*s->current_mapping->info.dir.first_dir_index;
1155 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1156 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1157 s->current_cluster = cluster_num;
1158 return 0;
1159 }
1160
1161 if(open_file(s,mapping))
1162 return -2;
1163 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1164 goto read_cluster_directory;
1165
1166 assert(s->current_fd);
1167
1168 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
bellardde167e42005-04-28 21:15:08 +00001169 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1170 return -3;
bellarda0464332005-12-18 18:29:50 +00001171 s->cluster=s->cluster_buffer;
bellardde167e42005-04-28 21:15:08 +00001172 result=read(s->current_fd,s->cluster,s->cluster_size);
1173 if(result<0) {
1174 s->current_cluster = -1;
1175 return -1;
1176 }
1177 s->current_cluster = cluster_num;
1178 }
1179 return 0;
1180}
1181
bellarda0464332005-12-18 18:29:50 +00001182#ifdef DEBUG
1183static void hexdump(const void* address, uint32_t len)
1184{
1185 const unsigned char* p = address;
1186 int i, j;
1187
1188 for (i = 0; i < len; i += 16) {
1189 for (j = 0; j < 16 && i + j < len; j++)
1190 fprintf(stderr, "%02x ", p[i + j]);
1191 for (; j < 16; j++)
1192 fprintf(stderr, " ");
1193 fprintf(stderr, " ");
1194 for (j = 0; j < 16 && i + j < len; j++)
1195 fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
1196 fprintf(stderr, "\n");
1197 }
1198}
1199
1200static void print_direntry(const direntry_t* direntry)
1201{
1202 int j = 0;
1203 char buffer[1024];
1204
1205 fprintf(stderr, "direntry 0x%x: ", (int)direntry);
1206 if(!direntry)
1207 return;
1208 if(is_long_name(direntry)) {
1209 unsigned char* c=(unsigned char*)direntry;
1210 int i;
1211 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
1212#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = '°'; j++;}
1213 ADD_CHAR(c[i]);
1214 for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
1215 ADD_CHAR(c[i]);
1216 for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
1217 ADD_CHAR(c[i]);
1218 buffer[j] = 0;
1219 fprintf(stderr, "%s\n", buffer);
1220 } else {
1221 int i;
1222 for(i=0;i<11;i++)
1223 ADD_CHAR(direntry->name[i]);
1224 buffer[j] = 0;
1225 fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1226 buffer,
1227 direntry->attributes,
1228 begin_of_direntry(direntry),le32_to_cpu(direntry->size));
1229 }
1230}
1231
1232static void print_mapping(const mapping_t* mapping)
1233{
1234 fprintf(stderr, "mapping (0x%x): begin, end = %d, %d, dir_index = %d, first_mapping_index = %d, name = %s, mode = 0x%x, " , (int)mapping, mapping->begin, mapping->end, mapping->dir_index, mapping->first_mapping_index, mapping->path, mapping->mode);
1235 if (mapping->mode & MODE_DIRECTORY)
1236 fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1237 else
1238 fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
1239}
1240#endif
1241
bellardde167e42005-04-28 21:15:08 +00001242static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
1243 uint8_t *buf, int nb_sectors)
1244{
1245 BDRVVVFATState *s = bs->opaque;
1246 int i;
1247
bellardde167e42005-04-28 21:15:08 +00001248 for(i=0;i<nb_sectors;i++,sector_num++) {
bellarda0464332005-12-18 18:29:50 +00001249 if (sector_num >= s->sector_count)
1250 return -1;
1251 if (s->qcow) {
1252 int n;
1253 if (s->qcow->drv->bdrv_is_allocated(s->qcow,
1254 sector_num, nb_sectors-i, &n)) {
1255DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
1256 if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
1257 return -1;
1258 i += n - 1;
1259 sector_num += n - 1;
1260 continue;
1261 }
1262DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
1263 }
bellardde167e42005-04-28 21:15:08 +00001264 if(sector_num<s->faked_sectors) {
bellarda0464332005-12-18 18:29:50 +00001265 if(sector_num<s->first_sectors_number)
1266 memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
1267 else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
1268 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
1269 else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
1270 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
bellardde167e42005-04-28 21:15:08 +00001271 } else {
bellarda0464332005-12-18 18:29:50 +00001272 uint32_t sector=sector_num-s->faked_sectors,
1273 sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1274 cluster_num=sector/s->sectors_per_cluster;
1275 if(read_cluster(s, cluster_num) != 0) {
1276 /* LATER TODO: strict: return -1; */
1277 memset(buf+i*0x200,0,0x200);
1278 continue;
1279 }
1280 memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
1281 }
1282 }
1283 return 0;
1284}
1285
1286/* LATER TODO: statify all functions */
1287
1288/*
1289 * Idea of the write support (use snapshot):
1290 *
1291 * 1. check if all data is consistent, recording renames, modifications,
1292 * new files and directories (in s->commits).
1293 *
1294 * 2. if the data is not consistent, stop committing
1295 *
1296 * 3. handle renames, and create new files and directories (do not yet
1297 * write their contents)
1298 *
1299 * 4. walk the directories, fixing the mapping and direntries, and marking
1300 * the handled mappings as not deleted
1301 *
1302 * 5. commit the contents of the files
1303 *
1304 * 6. handle deleted files and directories
1305 *
1306 */
1307
1308typedef struct commit_t {
1309 char* path;
1310 union {
1311 struct { uint32_t cluster; } rename;
1312 struct { int dir_index; uint32_t modified_offset; } writeout;
1313 struct { uint32_t first_cluster; } new_file;
1314 struct { uint32_t cluster; } mkdir;
1315 } param;
1316 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1317 enum {
1318 ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1319 } action;
1320} commit_t;
1321
1322static void clear_commits(BDRVVVFATState* s)
1323{
1324 int i;
1325DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1326 for (i = 0; i < s->commits.next; i++) {
1327 commit_t* commit = array_get(&(s->commits), i);
1328 assert(commit->path || commit->action == ACTION_WRITEOUT);
1329 if (commit->action != ACTION_WRITEOUT) {
1330 assert(commit->path);
1331 free(commit->path);
1332 } else
1333 assert(commit->path == NULL);
1334 }
1335 s->commits.next = 0;
1336}
1337
1338static void schedule_rename(BDRVVVFATState* s,
1339 uint32_t cluster, char* new_path)
1340{
1341 commit_t* commit = array_get_next(&(s->commits));
1342 commit->path = new_path;
1343 commit->param.rename.cluster = cluster;
1344 commit->action = ACTION_RENAME;
1345}
1346
1347static void schedule_writeout(BDRVVVFATState* s,
1348 int dir_index, uint32_t modified_offset)
1349{
1350 commit_t* commit = array_get_next(&(s->commits));
1351 commit->path = NULL;
1352 commit->param.writeout.dir_index = dir_index;
1353 commit->param.writeout.modified_offset = modified_offset;
1354 commit->action = ACTION_WRITEOUT;
1355}
1356
1357static void schedule_new_file(BDRVVVFATState* s,
1358 char* path, uint32_t first_cluster)
1359{
1360 commit_t* commit = array_get_next(&(s->commits));
1361 commit->path = path;
1362 commit->param.new_file.first_cluster = first_cluster;
1363 commit->action = ACTION_NEW_FILE;
1364}
1365
1366static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1367{
1368 commit_t* commit = array_get_next(&(s->commits));
1369 commit->path = path;
1370 commit->param.mkdir.cluster = cluster;
1371 commit->action = ACTION_MKDIR;
1372}
1373
1374typedef struct {
1375 unsigned char name[1024];
1376 int checksum, len;
1377 int sequence_number;
1378} long_file_name;
1379
1380static void lfn_init(long_file_name* lfn)
1381{
1382 lfn->sequence_number = lfn->len = 0;
1383 lfn->checksum = 0x100;
1384}
1385
1386/* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1387static int parse_long_name(long_file_name* lfn,
1388 const direntry_t* direntry)
1389{
1390 int i, j, offset;
1391 const unsigned char* pointer = (const unsigned char*)direntry;
1392
1393 if (!is_long_name(direntry))
1394 return 1;
1395
1396 if (pointer[0] & 0x40) {
1397 lfn->sequence_number = pointer[0] & 0x3f;
1398 lfn->checksum = pointer[13];
1399 lfn->name[0] = 0;
1400 } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
1401 return -1;
1402 else if (pointer[13] != lfn->checksum)
1403 return -2;
1404 else if (pointer[12] || pointer[26] || pointer[27])
1405 return -3;
1406
1407 offset = 13 * (lfn->sequence_number - 1);
1408 for (i = 0, j = 1; i < 13; i++, j+=2) {
1409 if (j == 11)
1410 j = 14;
1411 else if (j == 26)
1412 j = 28;
1413
1414 if (pointer[j+1] == 0)
1415 lfn->name[offset + i] = pointer[j];
1416 else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1417 return -4;
1418 else
1419 lfn->name[offset + i] = 0;
1420 }
1421
1422 if (pointer[0] & 0x40)
1423 lfn->len = offset + strlen(lfn->name + offset);
1424
1425 return 0;
1426}
1427
1428/* returns 0 if successful, >0 if no short_name, and <0 on error */
1429static int parse_short_name(BDRVVVFATState* s,
1430 long_file_name* lfn, direntry_t* direntry)
1431{
1432 int i, j;
1433
1434 if (!is_short_name(direntry))
1435 return 1;
1436
1437 for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1438 for (i = 0; i <= j; i++) {
1439 if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
1440 return -1;
1441 else if (s->downcase_short_names)
1442 lfn->name[i] = tolower(direntry->name[i]);
1443 else
1444 lfn->name[i] = direntry->name[i];
1445 }
1446
1447 for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
1448 if (j >= 0) {
1449 lfn->name[i++] = '.';
1450 lfn->name[i + j + 1] = '\0';
1451 for (;j >= 0; j--) {
1452 if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
1453 return -2;
1454 else if (s->downcase_short_names)
1455 lfn->name[i + j] = tolower(direntry->extension[j]);
1456 else
1457 lfn->name[i + j] = direntry->extension[j];
1458 }
1459 } else
1460 lfn->name[i + j + 1] = '\0';
1461
1462 lfn->len = strlen(lfn->name);
1463
1464 return 0;
1465}
1466
1467static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1468 unsigned int cluster)
1469{
1470 if (cluster < s->last_cluster_of_root_directory) {
1471 if (cluster + 1 == s->last_cluster_of_root_directory)
1472 return s->max_fat_value;
1473 else
1474 return cluster + 1;
1475 }
1476
1477 if (s->fat_type==32) {
1478 uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1479 return le32_to_cpu(*entry);
1480 } else if (s->fat_type==16) {
1481 uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1482 return le16_to_cpu(*entry);
1483 } else {
1484 const uint8_t* x=s->fat2+cluster*3/2;
1485 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1486 }
1487}
1488
1489static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1490{
1491 int was_modified = 0;
1492 int i, dummy;
1493
1494 if (s->qcow == NULL)
1495 return 0;
1496
1497 for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
1498 was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
1499 cluster2sector(s, cluster_num) + i, 1, &dummy);
1500
1501 return was_modified;
1502}
1503
1504static const char* get_basename(const char* path)
1505{
1506 char* basename = strrchr(path, '/');
1507 if (basename == NULL)
1508 return path;
1509 else
1510 return basename + 1; /* strip '/' */
1511}
1512
1513/*
1514 * The array s->used_clusters holds the states of the clusters. If it is
1515 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1516 * was modified, bit 3 is set.
1517 * If any cluster is allocated, but not part of a file or directory, this
1518 * driver refuses to commit.
1519 */
1520typedef enum {
1521 USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
1522} used_t;
1523
1524/*
1525 * get_cluster_count_for_direntry() not only determines how many clusters
1526 * are occupied by direntry, but also if it was renamed or modified.
1527 *
1528 * A file is thought to be renamed *only* if there already was a file with
1529 * exactly the same first cluster, but a different name.
1530 *
1531 * Further, the files/directories handled by this function are
1532 * assumed to be *not* deleted (and *only* those).
1533 */
1534static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
1535 direntry_t* direntry, const char* path)
1536{
1537 /*
1538 * This is a little bit tricky:
1539 * IF the guest OS just inserts a cluster into the file chain,
1540 * and leaves the rest alone, (i.e. the original file had clusters
1541 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1542 *
1543 * - do_commit will write the cluster into the file at the given
1544 * offset, but
1545 *
1546 * - the cluster which is overwritten should be moved to a later
1547 * position in the file.
1548 *
1549 * I am not aware that any OS does something as braindead, but this
1550 * situation could happen anyway when not committing for a long time.
1551 * Just to be sure that this does not bite us, detect it, and copy the
1552 * contents of the clusters to-be-overwritten into the qcow.
1553 */
1554 int copy_it = 0;
1555 int was_modified = 0;
1556 int32_t ret = 0;
1557
1558 uint32_t cluster_num = begin_of_direntry(direntry);
1559 uint32_t offset = 0;
1560 int first_mapping_index = -1;
1561 mapping_t* mapping = NULL;
1562 const char* basename2 = NULL;
1563
1564 vvfat_close_current_file(s);
1565
1566 /* the root directory */
1567 if (cluster_num == 0)
1568 return 0;
1569
1570 /* write support */
1571 if (s->qcow) {
1572 basename2 = get_basename(path);
1573
1574 mapping = find_mapping_for_cluster(s, cluster_num);
1575
1576 if (mapping) {
bellardda2414e2006-04-23 14:36:41 +00001577 const char* basename;
1578
bellarda0464332005-12-18 18:29:50 +00001579 assert(mapping->mode & MODE_DELETED);
1580 mapping->mode &= ~MODE_DELETED;
1581
bellardda2414e2006-04-23 14:36:41 +00001582 basename = get_basename(mapping->path);
bellarda0464332005-12-18 18:29:50 +00001583
1584 assert(mapping->mode & MODE_NORMAL);
1585
1586 /* rename */
1587 if (strcmp(basename, basename2))
1588 schedule_rename(s, cluster_num, strdup(path));
1589 } else if (is_file(direntry))
1590 /* new file */
1591 schedule_new_file(s, strdup(path), cluster_num);
1592 else {
1593 assert(0);
1594 return 0;
1595 }
1596 }
1597
1598 while(1) {
1599 if (s->qcow) {
1600 if (!copy_it && cluster_was_modified(s, cluster_num)) {
1601 if (mapping == NULL ||
1602 mapping->begin > cluster_num ||
1603 mapping->end <= cluster_num)
1604 mapping = find_mapping_for_cluster(s, cluster_num);
1605
1606
1607 if (mapping &&
1608 (mapping->mode & MODE_DIRECTORY) == 0) {
1609
1610 /* was modified in qcow */
1611 if (offset != mapping->info.file.offset + s->cluster_size
1612 * (cluster_num - mapping->begin)) {
1613 /* offset of this cluster in file chain has changed */
1614 assert(0);
1615 copy_it = 1;
1616 } else if (offset == 0) {
1617 const char* basename = get_basename(mapping->path);
1618
1619 if (strcmp(basename, basename2))
1620 copy_it = 1;
1621 first_mapping_index = array_index(&(s->mapping), mapping);
1622 }
1623
1624 if (mapping->first_mapping_index != first_mapping_index
1625 && mapping->info.file.offset > 0) {
1626 assert(0);
1627 copy_it = 1;
1628 }
1629
1630 /* need to write out? */
1631 if (!was_modified && is_file(direntry)) {
1632 was_modified = 1;
1633 schedule_writeout(s, mapping->dir_index, offset);
1634 }
bellardde167e42005-04-28 21:15:08 +00001635 }
bellarda0464332005-12-18 18:29:50 +00001636 }
bellardde167e42005-04-28 21:15:08 +00001637
bellarda0464332005-12-18 18:29:50 +00001638 if (copy_it) {
1639 int i, dummy;
1640 /*
1641 * This is horribly inefficient, but that is okay, since
1642 * it is rarely executed, if at all.
1643 */
1644 int64_t offset = cluster2sector(s, cluster_num);
bellardde167e42005-04-28 21:15:08 +00001645
bellarda0464332005-12-18 18:29:50 +00001646 vvfat_close_current_file(s);
1647 for (i = 0; i < s->sectors_per_cluster; i++)
1648 if (!s->qcow->drv->bdrv_is_allocated(s->qcow,
1649 offset + i, 1, &dummy)) {
1650 if (vvfat_read(s->bs,
1651 offset, s->cluster_buffer, 1))
1652 return -1;
1653 if (s->qcow->drv->bdrv_write(s->qcow,
1654 offset, s->cluster_buffer, 1))
1655 return -2;
1656 }
bellardde167e42005-04-28 21:15:08 +00001657 }
1658 }
bellarda0464332005-12-18 18:29:50 +00001659
1660 ret++;
1661 if (s->used_clusters[cluster_num] & USED_ANY)
1662 return 0;
1663 s->used_clusters[cluster_num] = USED_FILE;
1664
1665 cluster_num = modified_fat_get(s, cluster_num);
1666
1667 if (fat_eof(s, cluster_num))
1668 return ret;
1669 else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
1670 return -1;
1671
1672 offset += s->cluster_size;
bellardde167e42005-04-28 21:15:08 +00001673 }
1674}
1675
bellarda0464332005-12-18 18:29:50 +00001676/*
1677 * This function looks at the modified data (qcow).
1678 * It returns 0 upon inconsistency or error, and the number of clusters
1679 * used by the directory, its subdirectories and their files.
1680 */
1681static int check_directory_consistency(BDRVVVFATState *s,
1682 int cluster_num, const char* path)
bellardde167e42005-04-28 21:15:08 +00001683{
bellarda0464332005-12-18 18:29:50 +00001684 int ret = 0;
1685 unsigned char* cluster = malloc(s->cluster_size);
1686 direntry_t* direntries = (direntry_t*)cluster;
1687 mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
bellardde167e42005-04-28 21:15:08 +00001688
bellarda0464332005-12-18 18:29:50 +00001689 long_file_name lfn;
1690 int path_len = strlen(path);
1691 char path2[PATH_MAX];
bellardde167e42005-04-28 21:15:08 +00001692
bellarda0464332005-12-18 18:29:50 +00001693 assert(path_len < PATH_MAX); /* len was tested before! */
1694 strcpy(path2, path);
1695 path2[path_len] = '/';
1696 path2[path_len + 1] = '\0';
bellardde167e42005-04-28 21:15:08 +00001697
bellarda0464332005-12-18 18:29:50 +00001698 if (mapping) {
1699 const char* basename = get_basename(mapping->path);
1700 const char* basename2 = get_basename(path);
1701
1702 assert(mapping->mode & MODE_DIRECTORY);
1703
1704 assert(mapping->mode & MODE_DELETED);
1705 mapping->mode &= ~MODE_DELETED;
1706
1707 if (strcmp(basename, basename2))
1708 schedule_rename(s, cluster_num, strdup(path));
1709 } else
1710 /* new directory */
1711 schedule_mkdir(s, cluster_num, strdup(path));
1712
1713 lfn_init(&lfn);
1714 do {
1715 int i;
1716 int subret = 0;
1717
1718 ret++;
1719
1720 if (s->used_clusters[cluster_num] & USED_ANY) {
1721 fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
1722 return 0;
bellardde167e42005-04-28 21:15:08 +00001723 }
bellarda0464332005-12-18 18:29:50 +00001724 s->used_clusters[cluster_num] = USED_DIRECTORY;
bellardde167e42005-04-28 21:15:08 +00001725
bellarda0464332005-12-18 18:29:50 +00001726DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
1727 subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
1728 s->sectors_per_cluster);
1729 if (subret) {
1730 fprintf(stderr, "Error fetching direntries\n");
1731 fail:
1732 free(cluster);
1733 return 0;
1734 }
1735
1736 for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
1737 int cluster_count;
1738
1739DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
1740 if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
1741 is_free(direntries + i))
1742 continue;
1743
1744 subret = parse_long_name(&lfn, direntries + i);
1745 if (subret < 0) {
1746 fprintf(stderr, "Error in long name\n");
1747 goto fail;
bellardde167e42005-04-28 21:15:08 +00001748 }
bellarda0464332005-12-18 18:29:50 +00001749 if (subret == 0 || is_free(direntries + i))
1750 continue;
1751
1752 if (fat_chksum(direntries+i) != lfn.checksum) {
1753 subret = parse_short_name(s, &lfn, direntries + i);
1754 if (subret < 0) {
1755 fprintf(stderr, "Error in short name (%d)\n", subret);
1756 goto fail;
1757 }
1758 if (subret > 0 || !strcmp(lfn.name, ".")
1759 || !strcmp(lfn.name, ".."))
1760 continue;
1761 }
1762 lfn.checksum = 0x100; /* cannot use long name twice */
1763
1764 if (path_len + 1 + lfn.len >= PATH_MAX) {
1765 fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
1766 goto fail;
1767 }
1768 strcpy(path2 + path_len + 1, lfn.name);
1769
1770 if (is_directory(direntries + i)) {
1771 if (begin_of_direntry(direntries + i) == 0) {
1772 DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
1773 goto fail;
1774 }
1775 cluster_count = check_directory_consistency(s,
1776 begin_of_direntry(direntries + i), path2);
1777 if (cluster_count == 0) {
1778 DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
1779 goto fail;
1780 }
1781 } else if (is_file(direntries + i)) {
1782 /* check file size with FAT */
1783 cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
1784 if (cluster_count !=
1785 (le32_to_cpu(direntries[i].size) + s->cluster_size
1786 - 1) / s->cluster_size) {
1787 DLOG(fprintf(stderr, "Cluster count mismatch\n"));
1788 goto fail;
1789 }
1790 } else
1791 assert(0); /* cluster_count = 0; */
1792
1793 ret += cluster_count;
bellardde167e42005-04-28 21:15:08 +00001794 }
bellarda0464332005-12-18 18:29:50 +00001795
1796 cluster_num = modified_fat_get(s, cluster_num);
1797 } while(!fat_eof(s, cluster_num));
1798
1799 free(cluster);
1800 return ret;
bellardde167e42005-04-28 21:15:08 +00001801}
1802
bellarda0464332005-12-18 18:29:50 +00001803/* returns 1 on success */
1804static int is_consistent(BDRVVVFATState* s)
bellardde167e42005-04-28 21:15:08 +00001805{
bellarda0464332005-12-18 18:29:50 +00001806 int i, check;
1807 int used_clusters_count = 0;
1808
1809DLOG(checkpoint());
1810 /*
1811 * - get modified FAT
1812 * - compare the two FATs (TODO)
1813 * - get buffer for marking used clusters
1814 * - recurse direntries from root (using bs->bdrv_read to make
1815 * sure to get the new data)
1816 * - check that the FAT agrees with the size
1817 * - count the number of clusters occupied by this directory and
1818 * its files
1819 * - check that the cumulative used cluster count agrees with the
1820 * FAT
1821 * - if all is fine, return number of used clusters
1822 */
1823 if (s->fat2 == NULL) {
1824 int size = 0x200 * s->sectors_per_fat;
1825 s->fat2 = malloc(size);
1826 memcpy(s->fat2, s->fat.pointer, size);
1827 }
1828 check = vvfat_read(s->bs,
1829 s->first_sectors_number, s->fat2, s->sectors_per_fat);
1830 if (check) {
1831 fprintf(stderr, "Could not copy fat\n");
bellardde167e42005-04-28 21:15:08 +00001832 return 0;
1833 }
bellarda0464332005-12-18 18:29:50 +00001834 assert (s->used_clusters);
1835 for (i = 0; i < sector2cluster(s, s->sector_count); i++)
1836 s->used_clusters[i] &= ~USED_ANY;
1837
1838 clear_commits(s);
1839
1840 /* mark every mapped file/directory as deleted.
1841 * (check_directory_consistency() will unmark those still present). */
1842 if (s->qcow)
1843 for (i = 0; i < s->mapping.next; i++) {
1844 mapping_t* mapping = array_get(&(s->mapping), i);
1845 if (mapping->first_mapping_index < 0)
1846 mapping->mode |= MODE_DELETED;
1847 }
1848
1849 used_clusters_count = check_directory_consistency(s, 0, s->path);
1850 if (used_clusters_count <= 0) {
1851 DLOG(fprintf(stderr, "problem in directory\n"));
1852 return 0;
1853 }
1854
1855 check = s->last_cluster_of_root_directory;
1856 for (i = check; i < sector2cluster(s, s->sector_count); i++) {
1857 if (modified_fat_get(s, i)) {
1858 if(!s->used_clusters[i]) {
1859 DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
1860 return 0;
1861 }
1862 check++;
1863 }
1864
1865 if (s->used_clusters[i] == USED_ALLOCATED) {
1866 /* allocated, but not used... */
1867 DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
1868 return 0;
1869 }
1870 }
1871
1872 if (check != used_clusters_count)
1873 return 0;
1874
1875 return used_clusters_count;
bellardde167e42005-04-28 21:15:08 +00001876}
1877
bellarda0464332005-12-18 18:29:50 +00001878static inline void adjust_mapping_indices(BDRVVVFATState* s,
1879 int offset, int adjust)
bellardde167e42005-04-28 21:15:08 +00001880{
bellarda0464332005-12-18 18:29:50 +00001881 int i;
1882
1883 for (i = 0; i < s->mapping.next; i++) {
1884 mapping_t* mapping = array_get(&(s->mapping), i);
1885
1886#define ADJUST_MAPPING_INDEX(name) \
1887 if (mapping->name >= offset) \
1888 mapping->name += adjust
1889
1890 ADJUST_MAPPING_INDEX(first_mapping_index);
1891 if (mapping->mode & MODE_DIRECTORY)
1892 ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
1893 }
bellardde167e42005-04-28 21:15:08 +00001894}
1895
bellarda0464332005-12-18 18:29:50 +00001896/* insert or update mapping */
1897static mapping_t* insert_mapping(BDRVVVFATState* s,
1898 uint32_t begin, uint32_t end)
bellardde167e42005-04-28 21:15:08 +00001899{
bellarda0464332005-12-18 18:29:50 +00001900 /*
1901 * - find mapping where mapping->begin >= begin,
1902 * - if mapping->begin > begin: insert
1903 * - adjust all references to mappings!
1904 * - else: adjust
1905 * - replace name
1906 */
1907 int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
1908 mapping_t* mapping = NULL;
1909 mapping_t* first_mapping = array_get(&(s->mapping), 0);
1910
1911 if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
1912 && mapping->begin < begin) {
1913 mapping->end = begin;
1914 index++;
1915 mapping = array_get(&(s->mapping), index);
1916 }
1917 if (index >= s->mapping.next || mapping->begin > begin) {
1918 mapping = array_insert(&(s->mapping), index, 1);
1919 mapping->path = NULL;
1920 adjust_mapping_indices(s, index, +1);
1921 }
1922
bellardde167e42005-04-28 21:15:08 +00001923 mapping->begin = begin;
bellarda0464332005-12-18 18:29:50 +00001924 mapping->end = end;
1925
1926DLOG(mapping_t* next_mapping;
1927assert(index + 1 >= s->mapping.next ||
1928((next_mapping = array_get(&(s->mapping), index + 1)) &&
1929 next_mapping->begin >= end)));
1930
1931 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1932 s->current_mapping = array_get(&(s->mapping),
1933 s->current_mapping - first_mapping);
1934
1935 return mapping;
bellardde167e42005-04-28 21:15:08 +00001936}
1937
bellarda0464332005-12-18 18:29:50 +00001938static int remove_mapping(BDRVVVFATState* s, int mapping_index)
bellardde167e42005-04-28 21:15:08 +00001939{
bellarda0464332005-12-18 18:29:50 +00001940 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
1941 mapping_t* first_mapping = array_get(&(s->mapping), 0);
bellardde167e42005-04-28 21:15:08 +00001942
bellarda0464332005-12-18 18:29:50 +00001943 /* free mapping */
1944 if (mapping->first_mapping_index < 0)
1945 free(mapping->path);
bellardde167e42005-04-28 21:15:08 +00001946
bellarda0464332005-12-18 18:29:50 +00001947 /* remove from s->mapping */
1948 array_remove(&(s->mapping), mapping_index);
bellardde167e42005-04-28 21:15:08 +00001949
bellarda0464332005-12-18 18:29:50 +00001950 /* adjust all references to mappings */
1951 adjust_mapping_indices(s, mapping_index, -1);
bellardde167e42005-04-28 21:15:08 +00001952
bellarda0464332005-12-18 18:29:50 +00001953 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1954 s->current_mapping = array_get(&(s->mapping),
1955 s->current_mapping - first_mapping);
bellardde167e42005-04-28 21:15:08 +00001956
1957 return 0;
1958}
1959
bellarda0464332005-12-18 18:29:50 +00001960static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
bellardde167e42005-04-28 21:15:08 +00001961{
bellarda0464332005-12-18 18:29:50 +00001962 int i;
1963 for (i = 0; i < s->mapping.next; i++) {
1964 mapping_t* mapping = array_get(&(s->mapping), i);
1965 if (mapping->dir_index >= offset)
1966 mapping->dir_index += adjust;
1967 if ((mapping->mode & MODE_DIRECTORY) &&
1968 mapping->info.dir.first_dir_index >= offset)
1969 mapping->info.dir.first_dir_index += adjust;
bellardde167e42005-04-28 21:15:08 +00001970 }
bellardde167e42005-04-28 21:15:08 +00001971}
1972
bellarda0464332005-12-18 18:29:50 +00001973static direntry_t* insert_direntries(BDRVVVFATState* s,
1974 int dir_index, int count)
bellardde167e42005-04-28 21:15:08 +00001975{
bellarda0464332005-12-18 18:29:50 +00001976 /*
1977 * make room in s->directory,
1978 * adjust_dirindices
1979 */
1980 direntry_t* result = array_insert(&(s->directory), dir_index, count);
1981 if (result == NULL)
1982 return NULL;
1983 adjust_dirindices(s, dir_index, count);
bellardde167e42005-04-28 21:15:08 +00001984 return result;
1985}
1986
bellarda0464332005-12-18 18:29:50 +00001987static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
bellardde167e42005-04-28 21:15:08 +00001988{
bellarda0464332005-12-18 18:29:50 +00001989 int ret = array_remove_slice(&(s->directory), dir_index, count);
1990 if (ret)
1991 return ret;
1992 adjust_dirindices(s, dir_index, -count);
bellardde167e42005-04-28 21:15:08 +00001993 return 0;
1994}
1995
bellarda0464332005-12-18 18:29:50 +00001996/*
1997 * Adapt the mappings of the cluster chain starting at first cluster
1998 * (i.e. if a file starts at first_cluster, the chain is followed according
1999 * to the modified fat, and the corresponding entries in s->mapping are
2000 * adjusted)
2001 */
2002static int commit_mappings(BDRVVVFATState* s,
2003 uint32_t first_cluster, int dir_index)
bellardde167e42005-04-28 21:15:08 +00002004{
bellarda0464332005-12-18 18:29:50 +00002005 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2006 direntry_t* direntry = array_get(&(s->directory), dir_index);
2007 uint32_t cluster = first_cluster;
bellardde167e42005-04-28 21:15:08 +00002008
bellarda0464332005-12-18 18:29:50 +00002009 vvfat_close_current_file(s);
bellardde167e42005-04-28 21:15:08 +00002010
bellarda0464332005-12-18 18:29:50 +00002011 assert(mapping);
2012 assert(mapping->begin == first_cluster);
2013 mapping->first_mapping_index = -1;
2014 mapping->dir_index = dir_index;
2015 mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2016 MODE_DIRECTORY : MODE_NORMAL;
bellardde167e42005-04-28 21:15:08 +00002017
bellarda0464332005-12-18 18:29:50 +00002018 while (!fat_eof(s, cluster)) {
2019 uint32_t c, c1;
bellardde167e42005-04-28 21:15:08 +00002020
bellarda0464332005-12-18 18:29:50 +00002021 for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2022 c = c1, c1 = modified_fat_get(s, c1));
bellardde167e42005-04-28 21:15:08 +00002023
bellarda0464332005-12-18 18:29:50 +00002024 c++;
2025 if (c > mapping->end) {
2026 int index = array_index(&(s->mapping), mapping);
2027 int i, max_i = s->mapping.next - index;
2028 for (i = 1; i < max_i && mapping[i].begin < c; i++);
2029 while (--i > 0)
2030 remove_mapping(s, index + 1);
2031 }
2032 assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2033 || mapping[1].begin >= c);
2034 mapping->end = c;
2035
2036 if (!fat_eof(s, c1)) {
2037 int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2038 mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2039 array_get(&(s->mapping), i);
2040
2041 if (next_mapping == NULL || next_mapping->begin > c1) {
2042 int i1 = array_index(&(s->mapping), mapping);
2043
2044 next_mapping = insert_mapping(s, c1, c1+1);
2045
2046 if (c1 < c)
2047 i1++;
2048 mapping = array_get(&(s->mapping), i1);
bellardde167e42005-04-28 21:15:08 +00002049 }
bellarda0464332005-12-18 18:29:50 +00002050
2051 next_mapping->dir_index = mapping->dir_index;
2052 next_mapping->first_mapping_index =
2053 mapping->first_mapping_index < 0 ?
2054 array_index(&(s->mapping), mapping) :
2055 mapping->first_mapping_index;
2056 next_mapping->path = mapping->path;
2057 next_mapping->mode = mapping->mode;
2058 next_mapping->read_only = mapping->read_only;
2059 if (mapping->mode & MODE_DIRECTORY) {
2060 next_mapping->info.dir.parent_mapping_index =
2061 mapping->info.dir.parent_mapping_index;
2062 next_mapping->info.dir.first_dir_index =
2063 mapping->info.dir.first_dir_index +
2064 0x10 * s->sectors_per_cluster *
2065 (mapping->end - mapping->begin);
2066 } else
2067 next_mapping->info.file.offset = mapping->info.file.offset +
2068 mapping->end - mapping->begin;
2069
2070 mapping = next_mapping;
2071 }
2072
2073 cluster = c1;
2074 }
2075
2076 return 0;
2077}
2078
2079static int commit_direntries(BDRVVVFATState* s,
2080 int dir_index, int parent_mapping_index)
2081{
2082 direntry_t* direntry = array_get(&(s->directory), dir_index);
2083 uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
2084 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2085
2086 int factor = 0x10 * s->sectors_per_cluster;
2087 int old_cluster_count, new_cluster_count;
2088 int current_dir_index = mapping->info.dir.first_dir_index;
2089 int first_dir_index = current_dir_index;
2090 int ret, i;
2091 uint32_t c;
2092
2093DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
2094
2095 assert(direntry);
2096 assert(mapping);
2097 assert(mapping->begin == first_cluster);
2098 assert(mapping->info.dir.first_dir_index < s->directory.next);
2099 assert(mapping->mode & MODE_DIRECTORY);
2100 assert(dir_index == 0 || is_directory(direntry));
2101
2102 mapping->info.dir.parent_mapping_index = parent_mapping_index;
2103
2104 if (first_cluster == 0) {
2105 old_cluster_count = new_cluster_count =
2106 s->last_cluster_of_root_directory;
2107 } else {
2108 for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2109 c = fat_get(s, c))
2110 old_cluster_count++;
2111
2112 for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2113 c = modified_fat_get(s, c))
2114 new_cluster_count++;
2115 }
2116
2117 if (new_cluster_count > old_cluster_count) {
2118 if (insert_direntries(s,
2119 current_dir_index + factor * old_cluster_count,
2120 factor * (new_cluster_count - old_cluster_count)) == NULL)
2121 return -1;
2122 } else if (new_cluster_count < old_cluster_count)
2123 remove_direntries(s,
2124 current_dir_index + factor * new_cluster_count,
2125 factor * (old_cluster_count - new_cluster_count));
2126
2127 for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
2128 void* direntry = array_get(&(s->directory), current_dir_index);
2129 int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2130 s->sectors_per_cluster);
2131 if (ret)
2132 return ret;
2133 assert(!strncmp(s->directory.pointer, "QEMU", 4));
2134 current_dir_index += factor;
2135 }
2136
2137 ret = commit_mappings(s, first_cluster, dir_index);
2138 if (ret)
2139 return ret;
2140
2141 /* recurse */
2142 for (i = 0; i < factor * new_cluster_count; i++) {
2143 direntry = array_get(&(s->directory), first_dir_index + i);
2144 if (is_directory(direntry) && !is_dot(direntry)) {
2145 mapping = find_mapping_for_cluster(s, first_cluster);
2146 assert(mapping->mode & MODE_DIRECTORY);
2147 ret = commit_direntries(s, first_dir_index + i,
2148 array_index(&(s->mapping), mapping));
2149 if (ret)
2150 return ret;
bellardde167e42005-04-28 21:15:08 +00002151 }
2152 }
bellarda0464332005-12-18 18:29:50 +00002153
bellardde167e42005-04-28 21:15:08 +00002154 return 0;
2155}
2156
bellarda0464332005-12-18 18:29:50 +00002157/* commit one file (adjust contents, adjust mapping),
2158 return first_mapping_index */
2159static int commit_one_file(BDRVVVFATState* s,
2160 int dir_index, uint32_t offset)
2161{
2162 direntry_t* direntry = array_get(&(s->directory), dir_index);
2163 uint32_t c = begin_of_direntry(direntry);
2164 uint32_t first_cluster = c;
2165 mapping_t* mapping = find_mapping_for_cluster(s, c);
2166 uint32_t size = filesize_of_direntry(direntry);
2167 char* cluster = malloc(s->cluster_size);
2168 uint32_t i;
2169 int fd = 0;
2170
2171 assert(offset < size);
2172 assert((offset % s->cluster_size) == 0);
2173
2174 for (i = s->cluster_size; i < offset; i += s->cluster_size)
2175 c = modified_fat_get(s, c);
2176
bellard6bcb76c2006-09-09 12:03:20 +00002177 fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
bellarda0464332005-12-18 18:29:50 +00002178 if (fd < 0) {
2179 fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2180 strerror(errno), errno);
2181 return fd;
2182 }
2183 if (offset > 0)
2184 if (lseek(fd, offset, SEEK_SET) != offset)
2185 return -3;
2186
2187 while (offset < size) {
2188 uint32_t c1;
2189 int rest_size = (size - offset > s->cluster_size ?
2190 s->cluster_size : size - offset);
2191 int ret;
2192
2193 c1 = modified_fat_get(s, c);
2194
2195 assert((size - offset == 0 && fat_eof(s, c)) ||
2196 (size > offset && c >=2 && !fat_eof(s, c)));
2197 assert(size >= 0);
2198
2199 ret = vvfat_read(s->bs, cluster2sector(s, c),
2200 cluster, (rest_size + 0x1ff) / 0x200);
2201
2202 if (ret < 0)
2203 return ret;
2204
2205 if (write(fd, cluster, rest_size) < 0)
2206 return -2;
2207
2208 offset += rest_size;
2209 c = c1;
2210 }
2211
2212 ftruncate(fd, size);
2213 close(fd);
2214
2215 return commit_mappings(s, first_cluster, dir_index);
2216}
2217
2218#ifdef DEBUG
2219/* test, if all mappings point to valid direntries */
2220static void check1(BDRVVVFATState* s)
2221{
2222 int i;
2223 for (i = 0; i < s->mapping.next; i++) {
2224 mapping_t* mapping = array_get(&(s->mapping), i);
2225 if (mapping->mode & MODE_DELETED) {
2226 fprintf(stderr, "deleted\n");
2227 continue;
2228 }
2229 assert(mapping->dir_index >= 0);
2230 assert(mapping->dir_index < s->directory.next);
2231 direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2232 assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2233 if (mapping->mode & MODE_DIRECTORY) {
2234 assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2235 assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2236 }
2237 }
2238}
2239
2240/* test, if all direntries have mappings */
2241static void check2(BDRVVVFATState* s)
2242{
2243 int i;
2244 int first_mapping = -1;
2245
2246 for (i = 0; i < s->directory.next; i++) {
2247 direntry_t* direntry = array_get(&(s->directory), i);
2248
2249 if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2250 mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2251 assert(mapping);
2252 assert(mapping->dir_index == i || is_dot(direntry));
2253 assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2254 }
2255
2256 if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2257 /* cluster start */
2258 int j, count = 0;
2259
2260 for (j = 0; j < s->mapping.next; j++) {
2261 mapping_t* mapping = array_get(&(s->mapping), j);
2262 if (mapping->mode & MODE_DELETED)
2263 continue;
2264 if (mapping->mode & MODE_DIRECTORY) {
2265 if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2266 assert(++count == 1);
2267 if (mapping->first_mapping_index == -1)
2268 first_mapping = array_index(&(s->mapping), mapping);
2269 else
2270 assert(first_mapping == mapping->first_mapping_index);
2271 if (mapping->info.dir.parent_mapping_index < 0)
2272 assert(j == 0);
2273 else {
2274 mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2275 assert(parent->mode & MODE_DIRECTORY);
2276 assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2277 }
2278 }
2279 }
2280 }
2281 if (count == 0)
2282 first_mapping = -1;
2283 }
2284 }
2285}
2286#endif
2287
2288static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2289{
2290 int i;
2291
2292#ifdef DEBUG
2293 fprintf(stderr, "handle_renames\n");
2294 for (i = 0; i < s->commits.next; i++) {
2295 commit_t* commit = array_get(&(s->commits), i);
2296 fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
2297 }
2298#endif
2299
2300 for (i = 0; i < s->commits.next;) {
2301 commit_t* commit = array_get(&(s->commits), i);
2302 if (commit->action == ACTION_RENAME) {
2303 mapping_t* mapping = find_mapping_for_cluster(s,
2304 commit->param.rename.cluster);
2305 char* old_path = mapping->path;
2306
2307 assert(commit->path);
2308 mapping->path = commit->path;
2309 if (rename(old_path, mapping->path))
2310 return -2;
2311
2312 if (mapping->mode & MODE_DIRECTORY) {
2313 int l1 = strlen(mapping->path);
2314 int l2 = strlen(old_path);
2315 int diff = l1 - l2;
2316 direntry_t* direntry = array_get(&(s->directory),
2317 mapping->info.dir.first_dir_index);
2318 uint32_t c = mapping->begin;
2319 int i = 0;
2320
2321 /* recurse */
2322 while (!fat_eof(s, c)) {
2323 do {
2324 direntry_t* d = direntry + i;
2325
2326 if (is_file(d) || (is_directory(d) && !is_dot(d))) {
2327 mapping_t* m = find_mapping_for_cluster(s,
2328 begin_of_direntry(d));
2329 int l = strlen(m->path);
2330 char* new_path = malloc(l + diff + 1);
2331
2332 assert(!strncmp(m->path, mapping->path, l2));
2333
2334 strcpy(new_path, mapping->path);
2335 strcpy(new_path + l1, m->path + l2);
2336
2337 schedule_rename(s, m->begin, new_path);
2338 }
2339 i++;
2340 } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2341 c = fat_get(s, c);
2342 }
2343 }
2344
2345 free(old_path);
2346 array_remove(&(s->commits), i);
2347 continue;
2348 } else if (commit->action == ACTION_MKDIR) {
2349 mapping_t* mapping;
2350 int j, parent_path_len;
2351
bellard48c2f062005-12-19 22:11:49 +00002352#ifdef __MINGW32__
2353 if (mkdir(commit->path))
2354 return -5;
2355#else
2356 if (mkdir(commit->path, 0755))
2357 return -5;
2358#endif
bellarda0464332005-12-18 18:29:50 +00002359
2360 mapping = insert_mapping(s, commit->param.mkdir.cluster,
2361 commit->param.mkdir.cluster + 1);
2362 if (mapping == NULL)
2363 return -6;
2364
2365 mapping->mode = MODE_DIRECTORY;
2366 mapping->read_only = 0;
2367 mapping->path = commit->path;
2368 j = s->directory.next;
2369 assert(j);
2370 insert_direntries(s, s->directory.next,
2371 0x10 * s->sectors_per_cluster);
2372 mapping->info.dir.first_dir_index = j;
2373
2374 parent_path_len = strlen(commit->path)
2375 - strlen(get_basename(commit->path)) - 1;
2376 for (j = 0; j < s->mapping.next; j++) {
2377 mapping_t* m = array_get(&(s->mapping), j);
2378 if (m->first_mapping_index < 0 && m != mapping &&
2379 !strncmp(m->path, mapping->path, parent_path_len) &&
2380 strlen(m->path) == parent_path_len)
2381 break;
2382 }
2383 assert(j < s->mapping.next);
2384 mapping->info.dir.parent_mapping_index = j;
2385
2386 array_remove(&(s->commits), i);
2387 continue;
2388 }
2389
2390 i++;
2391 }
2392 return 0;
2393}
2394
2395/*
2396 * TODO: make sure that the short name is not matching *another* file
2397 */
2398static int handle_commits(BDRVVVFATState* s)
2399{
2400 int i, fail = 0;
2401
2402 vvfat_close_current_file(s);
2403
2404 for (i = 0; !fail && i < s->commits.next; i++) {
2405 commit_t* commit = array_get(&(s->commits), i);
2406 switch(commit->action) {
2407 case ACTION_RENAME: case ACTION_MKDIR:
2408 assert(0);
2409 fail = -2;
2410 break;
2411 case ACTION_WRITEOUT: {
2412 direntry_t* entry = array_get(&(s->directory),
2413 commit->param.writeout.dir_index);
2414 uint32_t begin = begin_of_direntry(entry);
2415 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2416
2417 assert(mapping);
2418 assert(mapping->begin == begin);
2419 assert(commit->path == NULL);
2420
2421 if (commit_one_file(s, commit->param.writeout.dir_index,
2422 commit->param.writeout.modified_offset))
2423 fail = -3;
2424
2425 break;
2426 }
2427 case ACTION_NEW_FILE: {
2428 int begin = commit->param.new_file.first_cluster;
2429 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2430 direntry_t* entry;
2431 int i;
2432
2433 /* find direntry */
2434 for (i = 0; i < s->directory.next; i++) {
2435 entry = array_get(&(s->directory), i);
2436 if (is_file(entry) && begin_of_direntry(entry) == begin)
2437 break;
2438 }
2439
2440 if (i >= s->directory.next) {
2441 fail = -6;
2442 continue;
2443 }
2444
2445 /* make sure there exists an initial mapping */
2446 if (mapping && mapping->begin != begin) {
2447 mapping->end = begin;
2448 mapping = NULL;
2449 }
2450 if (mapping == NULL) {
2451 mapping = insert_mapping(s, begin, begin+1);
2452 }
2453 /* most members will be fixed in commit_mappings() */
2454 assert(commit->path);
2455 mapping->path = commit->path;
2456 mapping->read_only = 0;
2457 mapping->mode = MODE_NORMAL;
2458 mapping->info.file.offset = 0;
2459
2460 if (commit_one_file(s, i, 0))
2461 fail = -7;
2462
2463 break;
2464 }
2465 default:
2466 assert(0);
2467 }
2468 }
2469 if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2470 return -1;
2471 return fail;
2472}
2473
2474static int handle_deletes(BDRVVVFATState* s)
2475{
2476 int i, deferred = 1, deleted = 1;
2477
2478 /* delete files corresponding to mappings marked as deleted */
2479 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2480 while (deferred && deleted) {
2481 deferred = 0;
2482 deleted = 0;
2483
2484 for (i = 1; i < s->mapping.next; i++) {
2485 mapping_t* mapping = array_get(&(s->mapping), i);
2486 if (mapping->mode & MODE_DELETED) {
2487 direntry_t* entry = array_get(&(s->directory),
2488 mapping->dir_index);
2489
2490 if (is_free(entry)) {
2491 /* remove file/directory */
2492 if (mapping->mode & MODE_DIRECTORY) {
2493 int j, next_dir_index = s->directory.next,
2494 first_dir_index = mapping->info.dir.first_dir_index;
2495
2496 if (rmdir(mapping->path) < 0) {
2497 if (errno == ENOTEMPTY) {
2498 deferred++;
2499 continue;
2500 } else
2501 return -5;
2502 }
2503
2504 for (j = 1; j < s->mapping.next; j++) {
2505 mapping_t* m = array_get(&(s->mapping), j);
2506 if (m->mode & MODE_DIRECTORY &&
2507 m->info.dir.first_dir_index >
2508 first_dir_index &&
2509 m->info.dir.first_dir_index <
2510 next_dir_index)
2511 next_dir_index =
2512 m->info.dir.first_dir_index;
2513 }
2514 remove_direntries(s, first_dir_index,
2515 next_dir_index - first_dir_index);
2516
2517 deleted++;
2518 }
2519 } else {
2520 if (unlink(mapping->path))
2521 return -4;
2522 deleted++;
2523 }
2524 DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2525 remove_mapping(s, i);
2526 }
2527 }
2528 }
2529
2530 return 0;
2531}
2532
2533/*
2534 * synchronize mapping with new state:
2535 *
2536 * - copy FAT (with bdrv_read)
2537 * - mark all filenames corresponding to mappings as deleted
2538 * - recurse direntries from root (using bs->bdrv_read)
2539 * - delete files corresponding to mappings marked as deleted
2540 */
2541static int do_commit(BDRVVVFATState* s)
2542{
2543 int ret = 0;
2544
2545 /* the real meat are the commits. Nothing to do? Move along! */
2546 if (s->commits.next == 0)
2547 return 0;
2548
2549 vvfat_close_current_file(s);
2550
2551 ret = handle_renames_and_mkdirs(s);
2552 if (ret) {
2553 fprintf(stderr, "Error handling renames (%d)\n", ret);
2554 assert(0);
2555 return ret;
2556 }
2557
2558 /* copy FAT (with bdrv_read) */
2559 memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2560
2561 /* recurse direntries from root (using bs->bdrv_read) */
2562 ret = commit_direntries(s, 0, -1);
2563 if (ret) {
2564 fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
2565 assert(0);
2566 return ret;
2567 }
2568
2569 ret = handle_commits(s);
2570 if (ret) {
2571 fprintf(stderr, "Error handling commits (%d)\n", ret);
2572 assert(0);
2573 return ret;
2574 }
2575
2576 ret = handle_deletes(s);
2577 if (ret) {
2578 fprintf(stderr, "Error deleting\n");
2579 assert(0);
2580 return ret;
2581 }
2582
2583 s->qcow->drv->bdrv_make_empty(s->qcow);
2584
2585 memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2586
2587DLOG(checkpoint());
2588 return 0;
2589}
2590
2591static int try_commit(BDRVVVFATState* s)
2592{
2593 vvfat_close_current_file(s);
2594DLOG(checkpoint());
2595 if(!is_consistent(s))
2596 return -1;
2597 return do_commit(s);
2598}
2599
bellardde167e42005-04-28 21:15:08 +00002600static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
2601 const uint8_t *buf, int nb_sectors)
2602{
bellarda0464332005-12-18 18:29:50 +00002603 BDRVVVFATState *s = bs->opaque;
2604 int i, ret;
bellardde167e42005-04-28 21:15:08 +00002605
bellarda0464332005-12-18 18:29:50 +00002606DLOG(checkpoint());
bellardde167e42005-04-28 21:15:08 +00002607
bellarda0464332005-12-18 18:29:50 +00002608 vvfat_close_current_file(s);
bellardde167e42005-04-28 21:15:08 +00002609
bellarda0464332005-12-18 18:29:50 +00002610 /*
2611 * Some sanity checks:
2612 * - do not allow writing to the boot sector
2613 * - do not allow to write non-ASCII filenames
2614 */
bellardde167e42005-04-28 21:15:08 +00002615
bellarda0464332005-12-18 18:29:50 +00002616 if (sector_num < s->first_sectors_number)
2617 return -1;
bellardde167e42005-04-28 21:15:08 +00002618
bellarda0464332005-12-18 18:29:50 +00002619 for (i = sector2cluster(s, sector_num);
2620 i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
2621 mapping_t* mapping = find_mapping_for_cluster(s, i);
2622 if (mapping) {
2623 if (mapping->read_only) {
2624 fprintf(stderr, "Tried to write to write-protected file %s\n",
2625 mapping->path);
2626 return -1;
2627 }
bellardde167e42005-04-28 21:15:08 +00002628
bellarda0464332005-12-18 18:29:50 +00002629 if (mapping->mode & MODE_DIRECTORY) {
2630 int begin = cluster2sector(s, i);
2631 int end = begin + s->sectors_per_cluster, k;
2632 int dir_index;
2633 const direntry_t* direntries;
2634 long_file_name lfn;
bellardde167e42005-04-28 21:15:08 +00002635
bellarda0464332005-12-18 18:29:50 +00002636 lfn_init(&lfn);
bellardde167e42005-04-28 21:15:08 +00002637
bellarda0464332005-12-18 18:29:50 +00002638 if (begin < sector_num)
2639 begin = sector_num;
2640 if (end > sector_num + nb_sectors)
2641 end = sector_num + nb_sectors;
2642 dir_index = mapping->dir_index +
2643 0x10 * (begin - mapping->begin * s->sectors_per_cluster);
2644 direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
bellardde167e42005-04-28 21:15:08 +00002645
bellarda0464332005-12-18 18:29:50 +00002646 for (k = 0; k < (end - begin) * 0x10; k++) {
2647 /* do not allow non-ASCII filenames */
2648 if (parse_long_name(&lfn, direntries + k) < 0) {
2649 fprintf(stderr, "Warning: non-ASCII filename\n");
2650 return -1;
bellardde167e42005-04-28 21:15:08 +00002651 }
bellarda0464332005-12-18 18:29:50 +00002652 /* no access to the direntry of a read-only file */
2653 else if (is_short_name(direntries+k) &&
2654 (direntries[k].attributes & 1)) {
2655 if (memcmp(direntries + k,
2656 array_get(&(s->directory), dir_index + k),
2657 sizeof(direntry_t))) {
2658 fprintf(stderr, "Warning: tried to write to write-protected file\n");
2659 return -1;
bellardde167e42005-04-28 21:15:08 +00002660 }
bellardde167e42005-04-28 21:15:08 +00002661 }
2662 }
2663 }
bellarda0464332005-12-18 18:29:50 +00002664 i = mapping->end;
2665 } else
2666 i++;
bellardde167e42005-04-28 21:15:08 +00002667 }
bellarda0464332005-12-18 18:29:50 +00002668
2669 /*
2670 * Use qcow backend. Commit later.
2671 */
2672DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
2673 ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
2674 if (ret < 0) {
2675 fprintf(stderr, "Error writing to qcow backend\n");
2676 return ret;
2677 }
2678
2679 for (i = sector2cluster(s, sector_num);
2680 i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
2681 if (i >= 0)
2682 s->used_clusters[i] |= USED_ALLOCATED;
2683
2684DLOG(checkpoint());
2685 /* TODO: add timeout */
2686 try_commit(s);
2687
2688DLOG(checkpoint());
2689 return 0;
2690}
2691
2692static int vvfat_is_allocated(BlockDriverState *bs,
2693 int64_t sector_num, int nb_sectors, int* n)
2694{
2695 BDRVVVFATState* s = bs->opaque;
2696 *n = s->sector_count - sector_num;
2697 if (*n > nb_sectors)
2698 *n = nb_sectors;
2699 else if (*n < 0)
2700 return 0;
2701 return 1;
2702}
2703
2704static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
2705 const uint8_t* buffer, int nb_sectors) {
2706 BDRVVVFATState* s = bs->opaque;
2707 return try_commit(s);
2708}
2709
2710static void write_target_close(BlockDriverState *bs) {
2711 BDRVVVFATState* s = bs->opaque;
2712 bdrv_delete(s->qcow);
2713 free(s->qcow_filename);
2714}
2715
2716static BlockDriver vvfat_write_target = {
2717 "vvfat_write_target", 0, NULL, NULL, NULL,
2718 write_target_commit,
2719 write_target_close,
2720 NULL, NULL, NULL
2721};
2722
2723static int enable_write_target(BDRVVVFATState *s)
2724{
2725 int size = sector2cluster(s, s->sector_count);
2726 s->used_clusters = calloc(size, 1);
2727
2728 array_init(&(s->commits), sizeof(commit_t));
2729
2730 s->qcow_filename = malloc(1024);
bellard83f64092006-08-01 16:21:11 +00002731 get_tmp_filename(s->qcow_filename, 1024);
bellarda0464332005-12-18 18:29:50 +00002732 if (bdrv_create(&bdrv_qcow,
2733 s->qcow_filename, s->sector_count, "fat:", 0) < 0)
2734 return -1;
2735 s->qcow = bdrv_new("");
2736 if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
2737 return -1;
2738
2739#ifndef _WIN32
2740 unlink(s->qcow_filename);
2741#endif
2742
2743 s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
2744 s->bs->backing_hd->drv = &vvfat_write_target;
2745 s->bs->backing_hd->opaque = s;
2746
bellardde167e42005-04-28 21:15:08 +00002747 return 0;
2748}
2749
2750static void vvfat_close(BlockDriverState *bs)
2751{
2752 BDRVVVFATState *s = bs->opaque;
2753
2754 vvfat_close_current_file(s);
2755 array_free(&(s->fat));
2756 array_free(&(s->directory));
2757 array_free(&(s->mapping));
bellarda0464332005-12-18 18:29:50 +00002758 if(s->cluster_buffer)
2759 free(s->cluster_buffer);
bellardde167e42005-04-28 21:15:08 +00002760}
2761
2762BlockDriver bdrv_vvfat = {
2763 "vvfat",
2764 sizeof(BDRVVVFATState),
bellard83f64092006-08-01 16:21:11 +00002765 NULL, /* no probe for protocols */
bellardde167e42005-04-28 21:15:08 +00002766 vvfat_open,
2767 vvfat_read,
2768 vvfat_write,
2769 vvfat_close,
pbrook7a6cba62006-06-04 11:39:07 +00002770 NULL, /* ??? Not sure if we can do any meaningful flushing. */
bellarda0464332005-12-18 18:29:50 +00002771 NULL,
bellard83f64092006-08-01 16:21:11 +00002772 vvfat_is_allocated,
2773 .protocol_name = "fat",
bellardde167e42005-04-28 21:15:08 +00002774};
2775
bellarda0464332005-12-18 18:29:50 +00002776#ifdef DEBUG
2777static void checkpoint() {
2778 assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
2779 check1(vvv);
2780 check2(vvv);
2781 assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
2782#if 0
2783 if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
2784 fprintf(stderr, "Nonono!\n");
2785 mapping_t* mapping;
2786 direntry_t* direntry;
2787 assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
2788 assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
2789 if (vvv->mapping.next<47)
2790 return;
2791 assert((mapping = array_get(&(vvv->mapping), 47)));
2792 assert(mapping->dir_index < vvv->directory.next);
2793 direntry = array_get(&(vvv->directory), mapping->dir_index);
2794 assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0);
2795#endif
2796 return;
2797 /* avoid compiler warnings: */
2798 hexdump(NULL, 100);
2799 remove_mapping(vvv, NULL);
2800 print_mapping(NULL);
2801 print_direntry(NULL);
2802}
2803#endif
bellardde167e42005-04-28 21:15:08 +00002804