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