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