]> git.proxmox.com Git - mirror_qemu.git/blame - block/vvfat.c
CODING_STYLE: specify the indent rule for multiline code
[mirror_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));
1497 if (bdrv_read(s->qcow, sector_num, buf + i * 0x200,
1498 n >> BDRV_SECTOR_BITS)) {
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 }
18d51c4b 1986 res = bdrv_write(s->qcow, offset, s->cluster_buffer, 1);
eecc7747 1987 if (res) {
7704df98
KW
1988 return -2;
1989 }
1990 }
1991 }
d6a7e54e
HP
1992 }
1993 }
a046433a 1994
d6a7e54e
HP
1995 ret++;
1996 if (s->used_clusters[cluster_num] & USED_ANY)
1997 return 0;
1998 s->used_clusters[cluster_num] = USED_FILE;
a046433a 1999
d6a7e54e 2000 cluster_num = modified_fat_get(s, cluster_num);
a046433a 2001
d6a7e54e
HP
2002 if (fat_eof(s, cluster_num))
2003 return ret;
2004 else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
2005 return -1;
a046433a 2006
d6a7e54e 2007 offset += s->cluster_size;
a046433a 2008 }
de167e41
FB
2009}
2010
a046433a 2011/*
5fafdf24 2012 * This function looks at the modified data (qcow).
a046433a
FB
2013 * It returns 0 upon inconsistency or error, and the number of clusters
2014 * used by the directory, its subdirectories and their files.
2015 */
2016static int check_directory_consistency(BDRVVVFATState *s,
d6a7e54e 2017 int cluster_num, const char* path)
de167e41 2018{
a046433a 2019 int ret = 0;
7267c094 2020 unsigned char* cluster = g_malloc(s->cluster_size);
c227f099
AL
2021 direntry_t* direntries = (direntry_t*)cluster;
2022 mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
a046433a
FB
2023
2024 long_file_name lfn;
2025 int path_len = strlen(path);
0d460d6f 2026 char path2[PATH_MAX + 1];
a046433a
FB
2027
2028 assert(path_len < PATH_MAX); /* len was tested before! */
363a37d5 2029 pstrcpy(path2, sizeof(path2), path);
a046433a
FB
2030 path2[path_len] = '/';
2031 path2[path_len + 1] = '\0';
2032
2033 if (mapping) {
d6a7e54e
HP
2034 const char* basename = get_basename(mapping->path);
2035 const char* basename2 = get_basename(path);
a046433a 2036
d6a7e54e 2037 assert(mapping->mode & MODE_DIRECTORY);
a046433a 2038
d6a7e54e
HP
2039 assert(mapping->mode & MODE_DELETED);
2040 mapping->mode &= ~MODE_DELETED;
a046433a 2041
d6a7e54e
HP
2042 if (strcmp(basename, basename2))
2043 schedule_rename(s, cluster_num, g_strdup(path));
a046433a 2044 } else
d6a7e54e
HP
2045 /* new directory */
2046 schedule_mkdir(s, cluster_num, g_strdup(path));
3b46e624 2047
a046433a
FB
2048 lfn_init(&lfn);
2049 do {
d6a7e54e
HP
2050 int i;
2051 int subret = 0;
a046433a 2052
d6a7e54e 2053 ret++;
a046433a 2054
d6a7e54e
HP
2055 if (s->used_clusters[cluster_num] & USED_ANY) {
2056 fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
6262bbd3 2057 goto fail;
d6a7e54e
HP
2058 }
2059 s->used_clusters[cluster_num] = USED_DIRECTORY;
a046433a
FB
2060
2061DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
d6a7e54e
HP
2062 subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
2063 s->sectors_per_cluster);
2064 if (subret) {
2065 fprintf(stderr, "Error fetching direntries\n");
2066 fail:
ce137829 2067 g_free(cluster);
d6a7e54e
HP
2068 return 0;
2069 }
a046433a 2070
d6a7e54e
HP
2071 for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
2072 int cluster_count = 0;
a046433a 2073
b2bedb21 2074DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i));
d6a7e54e
HP
2075 if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
2076 is_free(direntries + i))
2077 continue;
2078
2079 subret = parse_long_name(&lfn, direntries + i);
2080 if (subret < 0) {
2081 fprintf(stderr, "Error in long name\n");
2082 goto fail;
2083 }
2084 if (subret == 0 || is_free(direntries + i))
2085 continue;
2086
2087 if (fat_chksum(direntries+i) != lfn.checksum) {
2088 subret = parse_short_name(s, &lfn, direntries + i);
2089 if (subret < 0) {
2090 fprintf(stderr, "Error in short name (%d)\n", subret);
2091 goto fail;
2092 }
2093 if (subret > 0 || !strcmp((char*)lfn.name, ".")
2094 || !strcmp((char*)lfn.name, ".."))
2095 continue;
2096 }
2097 lfn.checksum = 0x100; /* cannot use long name twice */
2098
2099 if (path_len + 1 + lfn.len >= PATH_MAX) {
2100 fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
2101 goto fail;
2102 }
363a37d5
BS
2103 pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
2104 (char*)lfn.name);
a046433a 2105
d6a7e54e
HP
2106 if (is_directory(direntries + i)) {
2107 if (begin_of_direntry(direntries + i) == 0) {
2108 DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
2109 goto fail;
2110 }
2111 cluster_count = check_directory_consistency(s,
2112 begin_of_direntry(direntries + i), path2);
2113 if (cluster_count == 0) {
2114 DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
2115 goto fail;
2116 }
2117 } else if (is_file(direntries + i)) {
2118 /* check file size with FAT */
2119 cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
2120 if (cluster_count !=
13385ae1 2121 DIV_ROUND_UP(le32_to_cpu(direntries[i].size), s->cluster_size)) {
d6a7e54e
HP
2122 DLOG(fprintf(stderr, "Cluster count mismatch\n"));
2123 goto fail;
2124 }
2125 } else
43dc2a64 2126 abort(); /* cluster_count = 0; */
a046433a 2127
d6a7e54e
HP
2128 ret += cluster_count;
2129 }
de167e41 2130
d6a7e54e 2131 cluster_num = modified_fat_get(s, cluster_num);
a046433a 2132 } while(!fat_eof(s, cluster_num));
de167e41 2133
ce137829 2134 g_free(cluster);
a046433a
FB
2135 return ret;
2136}
2137
2138/* returns 1 on success */
2139static int is_consistent(BDRVVVFATState* s)
2140{
2141 int i, check;
2142 int used_clusters_count = 0;
2143
2144DLOG(checkpoint());
2145 /*
2146 * - get modified FAT
2147 * - compare the two FATs (TODO)
2148 * - get buffer for marking used clusters
2149 * - recurse direntries from root (using bs->bdrv_read to make
2150 * sure to get the new data)
2151 * - check that the FAT agrees with the size
2152 * - count the number of clusters occupied by this directory and
2153 * its files
2154 * - check that the cumulative used cluster count agrees with the
2155 * FAT
2156 * - if all is fine, return number of used clusters
2157 */
2158 if (s->fat2 == NULL) {
d6a7e54e
HP
2159 int size = 0x200 * s->sectors_per_fat;
2160 s->fat2 = g_malloc(size);
2161 memcpy(s->fat2, s->fat.pointer, size);
a046433a
FB
2162 }
2163 check = vvfat_read(s->bs,
4dc705dc 2164 s->offset_to_fat, s->fat2, s->sectors_per_fat);
a046433a 2165 if (check) {
d6a7e54e
HP
2166 fprintf(stderr, "Could not copy fat\n");
2167 return 0;
a046433a
FB
2168 }
2169 assert (s->used_clusters);
2170 for (i = 0; i < sector2cluster(s, s->sector_count); i++)
d6a7e54e 2171 s->used_clusters[i] &= ~USED_ANY;
a046433a
FB
2172
2173 clear_commits(s);
2174
2175 /* mark every mapped file/directory as deleted.
2176 * (check_directory_consistency() will unmark those still present). */
2177 if (s->qcow)
d6a7e54e
HP
2178 for (i = 0; i < s->mapping.next; i++) {
2179 mapping_t* mapping = array_get(&(s->mapping), i);
2180 if (mapping->first_mapping_index < 0)
2181 mapping->mode |= MODE_DELETED;
2182 }
a046433a
FB
2183
2184 used_clusters_count = check_directory_consistency(s, 0, s->path);
2185 if (used_clusters_count <= 0) {
d6a7e54e
HP
2186 DLOG(fprintf(stderr, "problem in directory\n"));
2187 return 0;
de167e41
FB
2188 }
2189
a046433a
FB
2190 check = s->last_cluster_of_root_directory;
2191 for (i = check; i < sector2cluster(s, s->sector_count); i++) {
d6a7e54e
HP
2192 if (modified_fat_get(s, i)) {
2193 if(!s->used_clusters[i]) {
2194 DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
2195 return 0;
2196 }
2197 check++;
2198 }
a046433a 2199
d6a7e54e
HP
2200 if (s->used_clusters[i] == USED_ALLOCATED) {
2201 /* allocated, but not used... */
2202 DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
2203 return 0;
2204 }
a046433a
FB
2205 }
2206
2207 if (check != used_clusters_count)
d6a7e54e 2208 return 0;
a046433a
FB
2209
2210 return used_clusters_count;
2211}
2212
2213static inline void adjust_mapping_indices(BDRVVVFATState* s,
d6a7e54e 2214 int offset, int adjust)
a046433a
FB
2215{
2216 int i;
2217
2218 for (i = 0; i < s->mapping.next; i++) {
d6a7e54e 2219 mapping_t* mapping = array_get(&(s->mapping), i);
a046433a
FB
2220
2221#define ADJUST_MAPPING_INDEX(name) \
d6a7e54e
HP
2222 if (mapping->name >= offset) \
2223 mapping->name += adjust
a046433a 2224
d6a7e54e
HP
2225 ADJUST_MAPPING_INDEX(first_mapping_index);
2226 if (mapping->mode & MODE_DIRECTORY)
2227 ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
de167e41 2228 }
a046433a
FB
2229}
2230
2231/* insert or update mapping */
c227f099 2232static mapping_t* insert_mapping(BDRVVVFATState* s,
d6a7e54e 2233 uint32_t begin, uint32_t end)
a046433a
FB
2234{
2235 /*
2236 * - find mapping where mapping->begin >= begin,
2237 * - if mapping->begin > begin: insert
2238 * - adjust all references to mappings!
2239 * - else: adjust
2240 * - replace name
2241 */
2242 int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
c227f099
AL
2243 mapping_t* mapping = NULL;
2244 mapping_t* first_mapping = array_get(&(s->mapping), 0);
a046433a
FB
2245
2246 if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
d6a7e54e
HP
2247 && mapping->begin < begin) {
2248 mapping->end = begin;
2249 index++;
2250 mapping = array_get(&(s->mapping), index);
a046433a
FB
2251 }
2252 if (index >= s->mapping.next || mapping->begin > begin) {
d6a7e54e
HP
2253 mapping = array_insert(&(s->mapping), index, 1);
2254 mapping->path = NULL;
2255 adjust_mapping_indices(s, index, +1);
a046433a
FB
2256 }
2257
2258 mapping->begin = begin;
2259 mapping->end = end;
de167e41 2260
c227f099 2261DLOG(mapping_t* next_mapping;
a046433a
FB
2262assert(index + 1 >= s->mapping.next ||
2263((next_mapping = array_get(&(s->mapping), index + 1)) &&
2264 next_mapping->begin >= end)));
2265
c227f099 2266 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
d6a7e54e
HP
2267 s->current_mapping = array_get(&(s->mapping),
2268 s->current_mapping - first_mapping);
a046433a
FB
2269
2270 return mapping;
2271}
2272
2273static int remove_mapping(BDRVVVFATState* s, int mapping_index)
2274{
c227f099
AL
2275 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
2276 mapping_t* first_mapping = array_get(&(s->mapping), 0);
a046433a
FB
2277
2278 /* free mapping */
ce137829
SW
2279 if (mapping->first_mapping_index < 0) {
2280 g_free(mapping->path);
2281 }
a046433a
FB
2282
2283 /* remove from s->mapping */
2284 array_remove(&(s->mapping), mapping_index);
2285
2286 /* adjust all references to mappings */
2287 adjust_mapping_indices(s, mapping_index, -1);
2288
c227f099 2289 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
d6a7e54e
HP
2290 s->current_mapping = array_get(&(s->mapping),
2291 s->current_mapping - first_mapping);
de167e41 2292
de167e41
FB
2293 return 0;
2294}
2295
a046433a
FB
2296static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
2297{
2298 int i;
2299 for (i = 0; i < s->mapping.next; i++) {
d6a7e54e
HP
2300 mapping_t* mapping = array_get(&(s->mapping), i);
2301 if (mapping->dir_index >= offset)
2302 mapping->dir_index += adjust;
2303 if ((mapping->mode & MODE_DIRECTORY) &&
2304 mapping->info.dir.first_dir_index >= offset)
2305 mapping->info.dir.first_dir_index += adjust;
a046433a
FB
2306 }
2307}
de167e41 2308
c227f099 2309static direntry_t* insert_direntries(BDRVVVFATState* s,
d6a7e54e 2310 int dir_index, int count)
de167e41 2311{
a046433a
FB
2312 /*
2313 * make room in s->directory,
2314 * adjust_dirindices
2315 */
c227f099 2316 direntry_t* result = array_insert(&(s->directory), dir_index, count);
a046433a 2317 if (result == NULL)
d6a7e54e 2318 return NULL;
a046433a 2319 adjust_dirindices(s, dir_index, count);
de167e41
FB
2320 return result;
2321}
2322
a046433a
FB
2323static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
2324{
2325 int ret = array_remove_slice(&(s->directory), dir_index, count);
2326 if (ret)
d6a7e54e 2327 return ret;
a046433a
FB
2328 adjust_dirindices(s, dir_index, -count);
2329 return 0;
2330}
de167e41 2331
a046433a
FB
2332/*
2333 * Adapt the mappings of the cluster chain starting at first cluster
2334 * (i.e. if a file starts at first_cluster, the chain is followed according
2335 * to the modified fat, and the corresponding entries in s->mapping are
2336 * adjusted)
2337 */
2338static int commit_mappings(BDRVVVFATState* s,
d6a7e54e 2339 uint32_t first_cluster, int dir_index)
de167e41 2340{
c227f099
AL
2341 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2342 direntry_t* direntry = array_get(&(s->directory), dir_index);
a046433a
FB
2343 uint32_t cluster = first_cluster;
2344
2345 vvfat_close_current_file(s);
2346
2347 assert(mapping);
2348 assert(mapping->begin == first_cluster);
2349 mapping->first_mapping_index = -1;
2350 mapping->dir_index = dir_index;
2351 mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
d6a7e54e 2352 MODE_DIRECTORY : MODE_NORMAL;
a046433a
FB
2353
2354 while (!fat_eof(s, cluster)) {
d6a7e54e
HP
2355 uint32_t c, c1;
2356
2357 for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2358 c = c1, c1 = modified_fat_get(s, c1));
2359
2360 c++;
2361 if (c > mapping->end) {
2362 int index = array_index(&(s->mapping), mapping);
2363 int i, max_i = s->mapping.next - index;
2364 for (i = 1; i < max_i && mapping[i].begin < c; i++);
2365 while (--i > 0)
2366 remove_mapping(s, index + 1);
2367 }
2368 assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2369 || mapping[1].begin >= c);
2370 mapping->end = c;
2371
2372 if (!fat_eof(s, c1)) {
2373 int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2374 mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2375 array_get(&(s->mapping), i);
2376
2377 if (next_mapping == NULL || next_mapping->begin > c1) {
2378 int i1 = array_index(&(s->mapping), mapping);
2379
2380 next_mapping = insert_mapping(s, c1, c1+1);
2381
2382 if (c1 < c)
2383 i1++;
2384 mapping = array_get(&(s->mapping), i1);
2385 }
2386
2387 next_mapping->dir_index = mapping->dir_index;
2388 next_mapping->first_mapping_index =
2389 mapping->first_mapping_index < 0 ?
2390 array_index(&(s->mapping), mapping) :
2391 mapping->first_mapping_index;
2392 next_mapping->path = mapping->path;
2393 next_mapping->mode = mapping->mode;
2394 next_mapping->read_only = mapping->read_only;
2395 if (mapping->mode & MODE_DIRECTORY) {
2396 next_mapping->info.dir.parent_mapping_index =
2397 mapping->info.dir.parent_mapping_index;
2398 next_mapping->info.dir.first_dir_index =
2399 mapping->info.dir.first_dir_index +
2400 0x10 * s->sectors_per_cluster *
2401 (mapping->end - mapping->begin);
2402 } else
2403 next_mapping->info.file.offset = mapping->info.file.offset +
2404 mapping->end - mapping->begin;
2405
2406 mapping = next_mapping;
2407 }
2408
2409 cluster = c1;
a046433a 2410 }
de167e41 2411
de167e41
FB
2412 return 0;
2413}
2414
a046433a 2415static int commit_direntries(BDRVVVFATState* s,
d6a7e54e 2416 int dir_index, int parent_mapping_index)
de167e41 2417{
c227f099 2418 direntry_t* direntry = array_get(&(s->directory), dir_index);
a046433a 2419 uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
c227f099 2420 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
a046433a
FB
2421 int factor = 0x10 * s->sectors_per_cluster;
2422 int old_cluster_count, new_cluster_count;
8d9401c2
LM
2423 int current_dir_index;
2424 int first_dir_index;
a046433a
FB
2425 int ret, i;
2426 uint32_t c;
2427
a046433a
FB
2428 assert(direntry);
2429 assert(mapping);
2430 assert(mapping->begin == first_cluster);
2431 assert(mapping->info.dir.first_dir_index < s->directory.next);
2432 assert(mapping->mode & MODE_DIRECTORY);
2433 assert(dir_index == 0 || is_directory(direntry));
2434
8d9401c2
LM
2435 DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n",
2436 mapping->path, parent_mapping_index));
2437
2438 current_dir_index = mapping->info.dir.first_dir_index;
2439 first_dir_index = current_dir_index;
a046433a
FB
2440 mapping->info.dir.parent_mapping_index = parent_mapping_index;
2441
2442 if (first_cluster == 0) {
d6a7e54e
HP
2443 old_cluster_count = new_cluster_count =
2444 s->last_cluster_of_root_directory;
a046433a 2445 } else {
d6a7e54e
HP
2446 for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2447 c = fat_get(s, c))
2448 old_cluster_count++;
de167e41 2449
d6a7e54e
HP
2450 for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2451 c = modified_fat_get(s, c))
2452 new_cluster_count++;
a046433a 2453 }
de167e41 2454
a046433a 2455 if (new_cluster_count > old_cluster_count) {
d6a7e54e
HP
2456 if (insert_direntries(s,
2457 current_dir_index + factor * old_cluster_count,
2458 factor * (new_cluster_count - old_cluster_count)) == NULL)
2459 return -1;
a046433a 2460 } else if (new_cluster_count < old_cluster_count)
d6a7e54e
HP
2461 remove_direntries(s,
2462 current_dir_index + factor * new_cluster_count,
2463 factor * (old_cluster_count - new_cluster_count));
a046433a
FB
2464
2465 for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
ebb72c9f 2466 direntry_t *first_direntry;
d6a7e54e
HP
2467 void* direntry = array_get(&(s->directory), current_dir_index);
2468 int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2469 s->sectors_per_cluster);
2470 if (ret)
2471 return ret;
ebb72c9f
KW
2472
2473 /* The first directory entry on the filesystem is the volume name */
2474 first_direntry = (direntry_t*) s->directory.pointer;
2475 assert(!memcmp(first_direntry->name, s->volume_label, 11));
2476
d6a7e54e 2477 current_dir_index += factor;
a046433a 2478 }
de167e41 2479
a046433a
FB
2480 ret = commit_mappings(s, first_cluster, dir_index);
2481 if (ret)
d6a7e54e 2482 return ret;
a046433a
FB
2483
2484 /* recurse */
2485 for (i = 0; i < factor * new_cluster_count; i++) {
d6a7e54e
HP
2486 direntry = array_get(&(s->directory), first_dir_index + i);
2487 if (is_directory(direntry) && !is_dot(direntry)) {
2488 mapping = find_mapping_for_cluster(s, first_cluster);
8d9401c2
LM
2489 if (mapping == NULL) {
2490 return -1;
2491 }
d6a7e54e
HP
2492 assert(mapping->mode & MODE_DIRECTORY);
2493 ret = commit_direntries(s, first_dir_index + i,
2494 array_index(&(s->mapping), mapping));
2495 if (ret)
2496 return ret;
2497 }
a046433a 2498 }
de167e41 2499
a046433a
FB
2500 return 0;
2501}
de167e41 2502
a046433a
FB
2503/* commit one file (adjust contents, adjust mapping),
2504 return first_mapping_index */
2505static int commit_one_file(BDRVVVFATState* s,
d6a7e54e 2506 int dir_index, uint32_t offset)
a046433a 2507{
c227f099 2508 direntry_t* direntry = array_get(&(s->directory), dir_index);
a046433a
FB
2509 uint32_t c = begin_of_direntry(direntry);
2510 uint32_t first_cluster = c;
c227f099 2511 mapping_t* mapping = find_mapping_for_cluster(s, c);
a046433a 2512 uint32_t size = filesize_of_direntry(direntry);
443ba6be 2513 char *cluster;
a046433a
FB
2514 uint32_t i;
2515 int fd = 0;
2516
2517 assert(offset < size);
2518 assert((offset % s->cluster_size) == 0);
2519
8d9401c2
LM
2520 if (mapping == NULL) {
2521 return -1;
2522 }
2523
a046433a 2524 for (i = s->cluster_size; i < offset; i += s->cluster_size)
d6a7e54e 2525 c = modified_fat_get(s, c);
a046433a 2526
6165f4d8 2527 fd = qemu_open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
a046433a 2528 if (fd < 0) {
d6a7e54e
HP
2529 fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2530 strerror(errno), errno);
d6a7e54e 2531 return fd;
de167e41 2532 }
ce137829
SW
2533 if (offset > 0) {
2534 if (lseek(fd, offset, SEEK_SET) != offset) {
2e1e79da 2535 qemu_close(fd);
ce137829
SW
2536 return -3;
2537 }
2538 }
a046433a 2539
443ba6be
KW
2540 cluster = g_malloc(s->cluster_size);
2541
a046433a 2542 while (offset < size) {
d6a7e54e
HP
2543 uint32_t c1;
2544 int rest_size = (size - offset > s->cluster_size ?
2545 s->cluster_size : size - offset);
2546 int ret;
a046433a 2547
d6a7e54e 2548 c1 = modified_fat_get(s, c);
a046433a 2549
d6a7e54e
HP
2550 assert((size - offset == 0 && fat_eof(s, c)) ||
2551 (size > offset && c >=2 && !fat_eof(s, c)));
a046433a 2552
d6a7e54e 2553 ret = vvfat_read(s->bs, cluster2sector(s, c),
78ee96de 2554 (uint8_t*)cluster, DIV_ROUND_UP(rest_size, 0x200));
a046433a 2555
ce137829 2556 if (ret < 0) {
2e1e79da 2557 qemu_close(fd);
ce137829
SW
2558 g_free(cluster);
2559 return ret;
2560 }
a046433a 2561
ce137829 2562 if (write(fd, cluster, rest_size) < 0) {
2e1e79da 2563 qemu_close(fd);
ce137829
SW
2564 g_free(cluster);
2565 return -2;
2566 }
a046433a 2567
d6a7e54e
HP
2568 offset += rest_size;
2569 c = c1;
a046433a
FB
2570 }
2571
2dedf83e
KS
2572 if (ftruncate(fd, size)) {
2573 perror("ftruncate()");
2e1e79da 2574 qemu_close(fd);
ce137829 2575 g_free(cluster);
2dedf83e
KS
2576 return -4;
2577 }
2e1e79da 2578 qemu_close(fd);
ce137829 2579 g_free(cluster);
a046433a
FB
2580
2581 return commit_mappings(s, first_cluster, dir_index);
2582}
2583
2584#ifdef DEBUG
2585/* test, if all mappings point to valid direntries */
2586static void check1(BDRVVVFATState* s)
2587{
2588 int i;
2589 for (i = 0; i < s->mapping.next; i++) {
d6a7e54e
HP
2590 mapping_t* mapping = array_get(&(s->mapping), i);
2591 if (mapping->mode & MODE_DELETED) {
2592 fprintf(stderr, "deleted\n");
2593 continue;
2594 }
2595 assert(mapping->dir_index < s->directory.next);
2596 direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2597 assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2598 if (mapping->mode & MODE_DIRECTORY) {
2599 assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2600 assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2601 }
de167e41 2602 }
de167e41
FB
2603}
2604
a046433a
FB
2605/* test, if all direntries have mappings */
2606static void check2(BDRVVVFATState* s)
de167e41 2607{
de167e41 2608 int i;
a046433a 2609 int first_mapping = -1;
de167e41 2610
a046433a 2611 for (i = 0; i < s->directory.next; i++) {
d6a7e54e
HP
2612 direntry_t* direntry = array_get(&(s->directory), i);
2613
2614 if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2615 mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2616 assert(mapping);
2617 assert(mapping->dir_index == i || is_dot(direntry));
2618 assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2619 }
2620
2621 if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2622 /* cluster start */
2623 int j, count = 0;
2624
2625 for (j = 0; j < s->mapping.next; j++) {
2626 mapping_t* mapping = array_get(&(s->mapping), j);
2627 if (mapping->mode & MODE_DELETED)
2628 continue;
2629 if (mapping->mode & MODE_DIRECTORY) {
2630 if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2631 assert(++count == 1);
2632 if (mapping->first_mapping_index == -1)
2633 first_mapping = array_index(&(s->mapping), mapping);
2634 else
2635 assert(first_mapping == mapping->first_mapping_index);
2636 if (mapping->info.dir.parent_mapping_index < 0)
2637 assert(j == 0);
2638 else {
2639 mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2640 assert(parent->mode & MODE_DIRECTORY);
2641 assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2642 }
2643 }
2644 }
2645 }
2646 if (count == 0)
2647 first_mapping = -1;
2648 }
a046433a
FB
2649 }
2650}
2651#endif
de167e41 2652
a046433a
FB
2653static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2654{
2655 int i;
de167e41 2656
a046433a
FB
2657#ifdef DEBUG
2658 fprintf(stderr, "handle_renames\n");
2659 for (i = 0; i < s->commits.next; i++) {
d6a7e54e
HP
2660 commit_t* commit = array_get(&(s->commits), i);
2661 fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
a046433a
FB
2662 }
2663#endif
2664
2665 for (i = 0; i < s->commits.next;) {
d6a7e54e
HP
2666 commit_t* commit = array_get(&(s->commits), i);
2667 if (commit->action == ACTION_RENAME) {
2668 mapping_t* mapping = find_mapping_for_cluster(s,
2669 commit->param.rename.cluster);
8d9401c2 2670 char *old_path;
d6a7e54e 2671
8d9401c2
LM
2672 if (mapping == NULL) {
2673 return -1;
2674 }
2675 old_path = mapping->path;
d6a7e54e
HP
2676 assert(commit->path);
2677 mapping->path = commit->path;
2678 if (rename(old_path, mapping->path))
2679 return -2;
2680
2681 if (mapping->mode & MODE_DIRECTORY) {
2682 int l1 = strlen(mapping->path);
2683 int l2 = strlen(old_path);
2684 int diff = l1 - l2;
2685 direntry_t* direntry = array_get(&(s->directory),
2686 mapping->info.dir.first_dir_index);
2687 uint32_t c = mapping->begin;
2688 int i = 0;
2689
2690 /* recurse */
2691 while (!fat_eof(s, c)) {
2692 do {
2693 direntry_t* d = direntry + i;
2694
2695 if (is_file(d) || (is_directory(d) && !is_dot(d))) {
8d9401c2
LM
2696 int l;
2697 char *new_path;
d6a7e54e
HP
2698 mapping_t* m = find_mapping_for_cluster(s,
2699 begin_of_direntry(d));
8d9401c2
LM
2700 if (m == NULL) {
2701 return -1;
2702 }
2703 l = strlen(m->path);
2704 new_path = g_malloc(l + diff + 1);
d6a7e54e
HP
2705
2706 assert(!strncmp(m->path, mapping->path, l2));
a046433a 2707
363a37d5
BS
2708 pstrcpy(new_path, l + diff + 1, mapping->path);
2709 pstrcpy(new_path + l1, l + diff + 1 - l1,
2710 m->path + l2);
a046433a 2711
d6a7e54e
HP
2712 schedule_rename(s, m->begin, new_path);
2713 }
2714 i++;
2715 } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2716 c = fat_get(s, c);
2717 }
2718 }
de167e41 2719
ce137829 2720 g_free(old_path);
d6a7e54e
HP
2721 array_remove(&(s->commits), i);
2722 continue;
2723 } else if (commit->action == ACTION_MKDIR) {
2724 mapping_t* mapping;
2725 int j, parent_path_len;
a046433a 2726
48c2f068
FB
2727#ifdef __MINGW32__
2728 if (mkdir(commit->path))
2729 return -5;
2730#else
2731 if (mkdir(commit->path, 0755))
2732 return -5;
2733#endif
a046433a 2734
d6a7e54e
HP
2735 mapping = insert_mapping(s, commit->param.mkdir.cluster,
2736 commit->param.mkdir.cluster + 1);
2737 if (mapping == NULL)
2738 return -6;
2739
2740 mapping->mode = MODE_DIRECTORY;
2741 mapping->read_only = 0;
2742 mapping->path = commit->path;
2743 j = s->directory.next;
2744 assert(j);
2745 insert_direntries(s, s->directory.next,
2746 0x10 * s->sectors_per_cluster);
2747 mapping->info.dir.first_dir_index = j;
2748
2749 parent_path_len = strlen(commit->path)
2750 - strlen(get_basename(commit->path)) - 1;
2751 for (j = 0; j < s->mapping.next; j++) {
2752 mapping_t* m = array_get(&(s->mapping), j);
2753 if (m->first_mapping_index < 0 && m != mapping &&
2754 !strncmp(m->path, mapping->path, parent_path_len) &&
2755 strlen(m->path) == parent_path_len)
2756 break;
2757 }
2758 assert(j < s->mapping.next);
2759 mapping->info.dir.parent_mapping_index = j;
2760
2761 array_remove(&(s->commits), i);
2762 continue;
2763 }
2764
2765 i++;
a046433a
FB
2766 }
2767 return 0;
2768}
2769
2770/*
2771 * TODO: make sure that the short name is not matching *another* file
2772 */
2773static int handle_commits(BDRVVVFATState* s)
2774{
2775 int i, fail = 0;
2776
2777 vvfat_close_current_file(s);
2778
2779 for (i = 0; !fail && i < s->commits.next; i++) {
d6a7e54e
HP
2780 commit_t* commit = array_get(&(s->commits), i);
2781 switch(commit->action) {
2782 case ACTION_RENAME: case ACTION_MKDIR:
43dc2a64 2783 abort();
d6a7e54e
HP
2784 fail = -2;
2785 break;
2786 case ACTION_WRITEOUT: {
a6c6f76c
BS
2787#ifndef NDEBUG
2788 /* these variables are only used by assert() below */
d6a7e54e
HP
2789 direntry_t* entry = array_get(&(s->directory),
2790 commit->param.writeout.dir_index);
2791 uint32_t begin = begin_of_direntry(entry);
2792 mapping_t* mapping = find_mapping_for_cluster(s, begin);
a6c6f76c 2793#endif
a046433a 2794
d6a7e54e
HP
2795 assert(mapping);
2796 assert(mapping->begin == begin);
2797 assert(commit->path == NULL);
2798
2799 if (commit_one_file(s, commit->param.writeout.dir_index,
2800 commit->param.writeout.modified_offset))
2801 fail = -3;
2802
2803 break;
2804 }
2805 case ACTION_NEW_FILE: {
2806 int begin = commit->param.new_file.first_cluster;
2807 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2808 direntry_t* entry;
2809 int i;
2810
2811 /* find direntry */
2812 for (i = 0; i < s->directory.next; i++) {
2813 entry = array_get(&(s->directory), i);
2814 if (is_file(entry) && begin_of_direntry(entry) == begin)
2815 break;
2816 }
2817
2818 if (i >= s->directory.next) {
2819 fail = -6;
2820 continue;
2821 }
2822
2823 /* make sure there exists an initial mapping */
2824 if (mapping && mapping->begin != begin) {
2825 mapping->end = begin;
2826 mapping = NULL;
2827 }
2828 if (mapping == NULL) {
2829 mapping = insert_mapping(s, begin, begin+1);
2830 }
2831 /* most members will be fixed in commit_mappings() */
2832 assert(commit->path);
2833 mapping->path = commit->path;
2834 mapping->read_only = 0;
2835 mapping->mode = MODE_NORMAL;
2836 mapping->info.file.offset = 0;
2837
2838 if (commit_one_file(s, i, 0))
2839 fail = -7;
2840
2841 break;
2842 }
2843 default:
43dc2a64 2844 abort();
d6a7e54e 2845 }
a046433a
FB
2846 }
2847 if (i > 0 && array_remove_slice(&(s->commits), 0, i))
d6a7e54e 2848 return -1;
a046433a
FB
2849 return fail;
2850}
2851
2852static int handle_deletes(BDRVVVFATState* s)
2853{
2854 int i, deferred = 1, deleted = 1;
2855
2856 /* delete files corresponding to mappings marked as deleted */
2857 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2858 while (deferred && deleted) {
d6a7e54e
HP
2859 deferred = 0;
2860 deleted = 0;
2861
2862 for (i = 1; i < s->mapping.next; i++) {
2863 mapping_t* mapping = array_get(&(s->mapping), i);
2864 if (mapping->mode & MODE_DELETED) {
2865 direntry_t* entry = array_get(&(s->directory),
2866 mapping->dir_index);
2867
2868 if (is_free(entry)) {
2869 /* remove file/directory */
2870 if (mapping->mode & MODE_DIRECTORY) {
2871 int j, next_dir_index = s->directory.next,
2872 first_dir_index = mapping->info.dir.first_dir_index;
2873
2874 if (rmdir(mapping->path) < 0) {
2875 if (errno == ENOTEMPTY) {
2876 deferred++;
2877 continue;
2878 } else
2879 return -5;
2880 }
2881
2882 for (j = 1; j < s->mapping.next; j++) {
2883 mapping_t* m = array_get(&(s->mapping), j);
2884 if (m->mode & MODE_DIRECTORY &&
2885 m->info.dir.first_dir_index >
2886 first_dir_index &&
2887 m->info.dir.first_dir_index <
2888 next_dir_index)
2889 next_dir_index =
2890 m->info.dir.first_dir_index;
2891 }
2892 remove_direntries(s, first_dir_index,
2893 next_dir_index - first_dir_index);
2894
2895 deleted++;
2896 }
2897 } else {
2898 if (unlink(mapping->path))
2899 return -4;
2900 deleted++;
2901 }
2902 DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2903 remove_mapping(s, i);
2904 }
2905 }
de167e41 2906 }
a046433a
FB
2907
2908 return 0;
2909}
2910
2911/*
2912 * synchronize mapping with new state:
2913 *
2914 * - copy FAT (with bdrv_read)
2915 * - mark all filenames corresponding to mappings as deleted
2916 * - recurse direntries from root (using bs->bdrv_read)
2917 * - delete files corresponding to mappings marked as deleted
2918 */
2919static int do_commit(BDRVVVFATState* s)
2920{
2921 int ret = 0;
2922
2923 /* the real meat are the commits. Nothing to do? Move along! */
2924 if (s->commits.next == 0)
d6a7e54e 2925 return 0;
a046433a
FB
2926
2927 vvfat_close_current_file(s);
2928
2929 ret = handle_renames_and_mkdirs(s);
2930 if (ret) {
d6a7e54e 2931 fprintf(stderr, "Error handling renames (%d)\n", ret);
43dc2a64 2932 abort();
d6a7e54e 2933 return ret;
a046433a
FB
2934 }
2935
5fafdf24 2936 /* copy FAT (with bdrv_read) */
a046433a
FB
2937 memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2938
2939 /* recurse direntries from root (using bs->bdrv_read) */
2940 ret = commit_direntries(s, 0, -1);
2941 if (ret) {
d6a7e54e 2942 fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
43dc2a64 2943 abort();
d6a7e54e 2944 return ret;
a046433a
FB
2945 }
2946
2947 ret = handle_commits(s);
2948 if (ret) {
d6a7e54e 2949 fprintf(stderr, "Error handling commits (%d)\n", ret);
43dc2a64 2950 abort();
d6a7e54e 2951 return ret;
a046433a
FB
2952 }
2953
2954 ret = handle_deletes(s);
2955 if (ret) {
d6a7e54e 2956 fprintf(stderr, "Error deleting\n");
43dc2a64 2957 abort();
d6a7e54e 2958 return ret;
a046433a
FB
2959 }
2960
d470ad42 2961 if (s->qcow->bs->drv && s->qcow->bs->drv->bdrv_make_empty) {
eecc7747 2962 s->qcow->bs->drv->bdrv_make_empty(s->qcow->bs);
7704df98 2963 }
a046433a
FB
2964
2965 memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2966
2967DLOG(checkpoint());
2968 return 0;
2969}
2970
2971static int try_commit(BDRVVVFATState* s)
2972{
2973 vvfat_close_current_file(s);
2974DLOG(checkpoint());
2975 if(!is_consistent(s))
d6a7e54e 2976 return -1;
a046433a
FB
2977 return do_commit(s);
2978}
2979
5fafdf24 2980static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
a046433a
FB
2981 const uint8_t *buf, int nb_sectors)
2982{
5fafdf24 2983 BDRVVVFATState *s = bs->opaque;
a046433a
FB
2984 int i, ret;
2985
2986DLOG(checkpoint());
2987
ac48e389
KW
2988 /* Check if we're operating in read-only mode */
2989 if (s->qcow == NULL) {
2990 return -EACCES;
2991 }
2992
a046433a
FB
2993 vvfat_close_current_file(s);
2994
2995 /*
2996 * Some sanity checks:
2997 * - do not allow writing to the boot sector
a046433a
FB
2998 */
2999
4dc705dc 3000 if (sector_num < s->offset_to_fat)
d6a7e54e 3001 return -1;
a046433a
FB
3002
3003 for (i = sector2cluster(s, sector_num);
d6a7e54e
HP
3004 i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
3005 mapping_t* mapping = find_mapping_for_cluster(s, i);
3006 if (mapping) {
3007 if (mapping->read_only) {
3008 fprintf(stderr, "Tried to write to write-protected file %s\n",
3009 mapping->path);
3010 return -1;
3011 }
3012
3013 if (mapping->mode & MODE_DIRECTORY) {
3014 int begin = cluster2sector(s, i);
3015 int end = begin + s->sectors_per_cluster, k;
3016 int dir_index;
3017 const direntry_t* direntries;
3018 long_file_name lfn;
3019
3020 lfn_init(&lfn);
3021
3022 if (begin < sector_num)
3023 begin = sector_num;
3024 if (end > sector_num + nb_sectors)
3025 end = sector_num + nb_sectors;
3026 dir_index = mapping->dir_index +
3027 0x10 * (begin - mapping->begin * s->sectors_per_cluster);
3028 direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
3029
3030 for (k = 0; k < (end - begin) * 0x10; k++) {
d6a7e54e 3031 /* no access to the direntry of a read-only file */
e03da26b 3032 if (is_short_name(direntries + k) &&
d6a7e54e
HP
3033 (direntries[k].attributes & 1)) {
3034 if (memcmp(direntries + k,
3035 array_get(&(s->directory), dir_index + k),
3036 sizeof(direntry_t))) {
2ab4b135
AF
3037 warn_report("tried to write to write-protected "
3038 "file");
d6a7e54e
HP
3039 return -1;
3040 }
3041 }
3042 }
3043 }
3044 i = mapping->end;
3045 } else
3046 i++;
a046433a
FB
3047 }
3048
3049 /*
3050 * Use qcow backend. Commit later.
3051 */
3052DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
18d51c4b 3053 ret = bdrv_write(s->qcow, sector_num, buf, nb_sectors);
a046433a 3054 if (ret < 0) {
d6a7e54e
HP
3055 fprintf(stderr, "Error writing to qcow backend\n");
3056 return ret;
a046433a
FB
3057 }
3058
3059 for (i = sector2cluster(s, sector_num);
d6a7e54e
HP
3060 i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
3061 if (i >= 0)
3062 s->used_clusters[i] |= USED_ALLOCATED;
a046433a
FB
3063
3064DLOG(checkpoint());
3065 /* TODO: add timeout */
3066 try_commit(s);
3067
3068DLOG(checkpoint());
3069 return 0;
3070}
3071
4575eb49
KW
3072static int coroutine_fn
3073vvfat_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
3074 QEMUIOVector *qiov, int flags)
e183ef75
PB
3075{
3076 int ret;
3077 BDRVVVFATState *s = bs->opaque;
4575eb49
KW
3078 uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
3079 int nb_sectors = bytes >> BDRV_SECTOR_BITS;
3080 void *buf;
3081
3082 assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
3083 assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
3084
3085 buf = g_try_malloc(bytes);
3086 if (bytes && buf == NULL) {
3087 return -ENOMEM;
3088 }
3089 qemu_iovec_to_buf(qiov, 0, buf, bytes);
3090
e183ef75
PB
3091 qemu_co_mutex_lock(&s->lock);
3092 ret = vvfat_write(bs, sector_num, buf, nb_sectors);
3093 qemu_co_mutex_unlock(&s->lock);
4575eb49
KW
3094
3095 g_free(buf);
3096
e183ef75
PB
3097 return ret;
3098}
3099
fba3998d
EB
3100static int coroutine_fn vvfat_co_block_status(BlockDriverState *bs,
3101 bool want_zero, int64_t offset,
3102 int64_t bytes, int64_t *n,
3103 int64_t *map,
3104 BlockDriverState **file)
a046433a 3105{
fba3998d 3106 *n = bytes;
4bc74be9 3107 return BDRV_BLOCK_DATA;
a046433a
FB
3108}
3109
4575eb49
KW
3110static int coroutine_fn
3111write_target_commit(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
3112 QEMUIOVector *qiov, int flags)
3113{
254aee4d
PB
3114 int ret;
3115
9217e26f 3116 BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
254aee4d
PB
3117 qemu_co_mutex_lock(&s->lock);
3118 ret = try_commit(s);
3119 qemu_co_mutex_unlock(&s->lock);
3120
3121 return ret;
a046433a
FB
3122}
3123
3124static void write_target_close(BlockDriverState *bs) {
9217e26f 3125 BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
eecc7747 3126 bdrv_unref_child(s->bs, s->qcow);
ce137829 3127 g_free(s->qcow_filename);
a046433a
FB
3128}
3129
3130static BlockDriver vvfat_write_target = {
f9e96436 3131 .format_name = "vvfat_write_target",
a8a4d15c 3132 .instance_size = sizeof(void*),
4575eb49 3133 .bdrv_co_pwritev = write_target_commit,
f9e96436 3134 .bdrv_close = write_target_close,
a046433a
FB
3135};
3136
eecc7747
KW
3137static void vvfat_qcow_options(int *child_flags, QDict *child_options,
3138 int parent_flags, QDict *parent_options)
a046433a 3139{
f87a0e29 3140 qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off");
e35bdc12 3141 qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off");
4f8e3a1f 3142 qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on");
eecc7747
KW
3143}
3144
3145static const BdrvChildRole child_vvfat_qcow = {
6cd5c9d7 3146 .parent_is_bds = true,
eecc7747
KW
3147 .inherit_options = vvfat_qcow_options,
3148};
3149
3150static int enable_write_target(BlockDriverState *bs, Error **errp)
3151{
3152 BDRVVVFATState *s = bs->opaque;
facdbb02 3153 BlockDriver *bdrv_qcow = NULL;
5db15a57 3154 BlockDriverState *backing;
facdbb02 3155 QemuOpts *opts = NULL;
a655211a 3156 int ret;
a046433a 3157 int size = sector2cluster(s, s->sector_count);
e6641719
HR
3158 QDict *options;
3159
a046433a
FB
3160 s->used_clusters = calloc(size, 1);
3161
c227f099 3162 array_init(&(s->commits), sizeof(commit_t));
a046433a 3163
9a29e18f
JC
3164 s->qcow_filename = g_malloc(PATH_MAX);
3165 ret = get_tmp_filename(s->qcow_filename, PATH_MAX);
eba25057 3166 if (ret < 0) {
68c70af1 3167 error_setg_errno(errp, -ret, "can't create temporary file");
78f27bd0 3168 goto err;
eba25057 3169 }
91a073a9
KW
3170
3171 bdrv_qcow = bdrv_find_format("qcow");
1bcb15cf
HR
3172 if (!bdrv_qcow) {
3173 error_setg(errp, "Failed to locate qcow driver");
3174 ret = -ENOENT;
3175 goto err;
3176 }
3177
c282e1fd 3178 opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort);
39101f25
MA
3179 qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512,
3180 &error_abort);
f43e47db 3181 qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:", &error_abort);
91a073a9 3182
c282e1fd 3183 ret = bdrv_create(bdrv_qcow, s->qcow_filename, opts, errp);
facdbb02 3184 qemu_opts_del(opts);
78f27bd0
FZ
3185 if (ret < 0) {
3186 goto err;
3187 }
a655211a 3188
e6641719 3189 options = qdict_new();
46f5ac20 3190 qdict_put_str(options, "write-target.driver", "qcow");
eecc7747
KW
3191 s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs,
3192 &child_vvfat_qcow, false, errp);
cb3e7f08 3193 qobject_unref(options);
5b363937
HR
3194 if (!s->qcow) {
3195 ret = -EINVAL;
78f27bd0 3196 goto err;
d6e9098e 3197 }
a046433a
FB
3198
3199#ifndef _WIN32
3200 unlink(s->qcow_filename);
3201#endif
3202
a8a4d15c
KW
3203 backing = bdrv_new_open_driver(&vvfat_write_target, NULL, BDRV_O_ALLOW_RDWR,
3204 &error_abort);
3205 *(void**) backing->opaque = s;
3206
12fa4af6 3207 bdrv_set_backing_hd(s->bs, backing, &error_abort);
5db15a57
KW
3208 bdrv_unref(backing);
3209
de167e41 3210 return 0;
78f27bd0
FZ
3211
3212err:
3213 g_free(s->qcow_filename);
3214 s->qcow_filename = NULL;
3215 return ret;
de167e41
FB
3216}
3217
91ef3825
KW
3218static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c,
3219 const BdrvChildRole *role,
e0995dc3 3220 BlockReopenQueue *reopen_queue,
91ef3825
KW
3221 uint64_t perm, uint64_t shared,
3222 uint64_t *nperm, uint64_t *nshared)
3223{
3224 BDRVVVFATState *s = bs->opaque;
3225
3226 assert(c == s->qcow || role == &child_backing);
3227
3228 if (c == s->qcow) {
3229 /* This is a private node, nobody should try to attach to it */
3230 *nperm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE;
3231 *nshared = BLK_PERM_WRITE_UNCHANGED;
3232 } else {
3233 /* The backing file is there so 'commit' can use it. vvfat doesn't
3234 * access it in any way. */
3235 *nperm = 0;
3236 *nshared = BLK_PERM_ALL;
3237 }
3238}
3239
de167e41
FB
3240static void vvfat_close(BlockDriverState *bs)
3241{
3242 BDRVVVFATState *s = bs->opaque;
3243
3244 vvfat_close_current_file(s);
3245 array_free(&(s->fat));
3246 array_free(&(s->directory));
3247 array_free(&(s->mapping));
ce137829 3248 g_free(s->cluster_buffer);
3397f0cb
KW
3249
3250 if (s->qcow) {
3251 migrate_del_blocker(s->migration_blocker);
3252 error_free(s->migration_blocker);
3253 }
de167e41
FB
3254}
3255
2654267c
HR
3256static const char *const vvfat_strong_runtime_opts[] = {
3257 "dir",
3258 "fat-type",
3259 "floppy",
3260 "label",
3261 "rw",
3262
3263 NULL
3264};
3265
5efa9d5a 3266static BlockDriver bdrv_vvfat = {
7ad9be64
KW
3267 .format_name = "vvfat",
3268 .protocol_name = "fat",
3269 .instance_size = sizeof(BDRVVVFATState),
3270
3271 .bdrv_parse_filename = vvfat_parse_filename,
3272 .bdrv_file_open = vvfat_open,
a6506481 3273 .bdrv_refresh_limits = vvfat_refresh_limits,
7ad9be64 3274 .bdrv_close = vvfat_close,
91ef3825 3275 .bdrv_child_perm = vvfat_child_perm,
7ad9be64 3276
4575eb49
KW
3277 .bdrv_co_preadv = vvfat_co_preadv,
3278 .bdrv_co_pwritev = vvfat_co_pwritev,
fba3998d 3279 .bdrv_co_block_status = vvfat_co_block_status,
2654267c
HR
3280
3281 .strong_runtime_opts = vvfat_strong_runtime_opts,
de167e41
FB
3282};
3283
5efa9d5a
AL
3284static void bdrv_vvfat_init(void)
3285{
3286 bdrv_register(&bdrv_vvfat);
3287}
3288
3289block_init(bdrv_vvfat_init);
3290
a046433a 3291#ifdef DEBUG
7a6ab45e
TH
3292static void checkpoint(void)
3293{
c227f099 3294 assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
a046433a
FB
3295 check1(vvv);
3296 check2(vvv);
3297 assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
a046433a
FB
3298}
3299#endif