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