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