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