]> git.proxmox.com Git - mirror_qemu.git/blame - block/vvfat.c
Merge tag 'pull-riscv-to-apply-20231107' of https://github.com/alistair23/qemu into...
[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;
a046433a 780 struct stat st;
d6a7e54e
HP
781 int is_dot=!strcmp(entry->d_name,".");
782 int is_dotdot=!strcmp(entry->d_name,"..");
de167e41 783
6817efea
HP
784 if (first_cluster == 0 && s->directory.next >= s->root_entries - 1) {
785 fprintf(stderr, "Too many entries in root directory\n");
786 closedir(dir);
787 return -2;
788 }
789
d6a7e54e
HP
790 if(first_cluster == 0 && (is_dotdot || is_dot))
791 continue;
5fafdf24 792
d6a7e54e
HP
793 buffer = g_malloc(length);
794 snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
de167e41 795
d6a7e54e 796 if(stat(buffer,&st)<0) {
ce137829 797 g_free(buffer);
de167e41 798 continue;
d6a7e54e
HP
799 }
800
801 /* create directory entry for this file */
f82d92bb
HP
802 if (!is_dot && !is_dotdot) {
803 direntry = create_short_and_long_name(s, i, entry->d_name, 0);
804 } else {
805 direntry = array_get(&(s->directory), is_dot ? i : i + 1);
806 }
d6a7e54e
HP
807 direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
808 direntry->reserved[0]=direntry->reserved[1]=0;
809 direntry->ctime=fat_datetime(st.st_ctime,1);
810 direntry->cdate=fat_datetime(st.st_ctime,0);
811 direntry->adate=fat_datetime(st.st_atime,0);
812 direntry->begin_hi=0;
813 direntry->mtime=fat_datetime(st.st_mtime,1);
814 direntry->mdate=fat_datetime(st.st_mtime,0);
815 if(is_dotdot)
816 set_begin_of_direntry(direntry, first_cluster_of_parent);
817 else if(is_dot)
818 set_begin_of_direntry(direntry, first_cluster);
819 else
820 direntry->begin=0; /* do that later */
a046433a 821 if (st.st_size > 0x7fffffff) {
d6a7e54e 822 fprintf(stderr, "File %s is larger than 2GB\n", buffer);
ce137829 823 g_free(buffer);
08089edc 824 closedir(dir);
d6a7e54e 825 return -2;
a046433a 826 }
d6a7e54e
HP
827 direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
828
829 /* create mapping for this file */
830 if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
831 s->current_mapping = array_get_next(&(s->mapping));
832 s->current_mapping->begin=0;
833 s->current_mapping->end=st.st_size;
834 /*
835 * we get the direntry of the most recent direntry, which
836 * contains the short name and all the relevant information.
837 */
838 s->current_mapping->dir_index=s->directory.next-1;
839 s->current_mapping->first_mapping_index = -1;
840 if (S_ISDIR(st.st_mode)) {
841 s->current_mapping->mode = MODE_DIRECTORY;
842 s->current_mapping->info.dir.parent_mapping_index =
843 mapping_index;
844 } else {
845 s->current_mapping->mode = MODE_UNDEFINED;
846 s->current_mapping->info.file.offset = 0;
847 }
848 s->current_mapping->path=buffer;
849 s->current_mapping->read_only =
850 (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
b122c3b6
MA
851 } else {
852 g_free(buffer);
853 }
de167e41
FB
854 }
855 closedir(dir);
856
857 /* fill with zeroes up to the end of the cluster */
858 while(s->directory.next%(0x10*s->sectors_per_cluster)) {
fb2575f9 859 direntry = array_get_next(&(s->directory));
d6a7e54e 860 memset(direntry,0,sizeof(direntry_t));
de167e41
FB
861 }
862
6817efea
HP
863 if (s->fat_type != 32 &&
864 mapping_index == 0 &&
865 s->directory.next < s->root_entries) {
d6a7e54e
HP
866 /* root directory */
867 int cur = s->directory.next;
6817efea
HP
868 array_ensure_allocated(&(s->directory), s->root_entries - 1);
869 s->directory.next = s->root_entries;
d6a7e54e 870 memset(array_get(&(s->directory), cur), 0,
6817efea 871 (s->root_entries - cur) * sizeof(direntry_t));
de167e41 872 }
5fafdf24 873
5f5b29df 874 /* re-get the mapping, since s->mapping was possibly realloc()ed */
d4df3dbc 875 mapping = array_get(&(s->mapping), mapping_index);
a046433a 876 first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
d6a7e54e 877 * 0x20 / s->cluster_size;
a046433a
FB
878 mapping->end = first_cluster;
879
d4df3dbc 880 direntry = array_get(&(s->directory), mapping->dir_index);
a046433a 881 set_begin_of_direntry(direntry, mapping->begin);
3b46e624 882
a046433a
FB
883 return 0;
884}
de167e41 885
b9b8860d 886static inline int32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
a046433a 887{
4dc705dc 888 return (sector_num - s->offset_to_root_dir) / s->sectors_per_cluster;
a046433a 889}
de167e41 890
a046433a
FB
891static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
892{
4dc705dc 893 return s->offset_to_root_dir + s->sectors_per_cluster * cluster_num;
a046433a 894}
de167e41 895
a046433a 896static int init_directories(BDRVVVFATState* s,
d11c8917
MA
897 const char *dirname, int heads, int secs,
898 Error **errp)
de167e41 899{
c227f099
AL
900 bootsector_t* bootsector;
901 mapping_t* mapping;
de167e41
FB
902 unsigned int i;
903 unsigned int cluster;
904
905 memset(&(s->first_sectors[0]),0,0x40*0x200);
906
de167e41 907 s->cluster_size=s->sectors_per_cluster*0x200;
7267c094 908 s->cluster_buffer=g_malloc(s->cluster_size);
a046433a
FB
909
910 /*
911 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
912 * where sc is sector_count,
913 * spf is sectors_per_fat,
914 * spc is sectors_per_clusters, and
915 * fat_type = 12, 16 or 32.
916 */
917 i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
918 s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
3b46e624 919
4dc705dc
HP
920 s->offset_to_fat = s->offset_to_bootsector + 1;
921 s->offset_to_root_dir = s->offset_to_fat + s->sectors_per_fat * 2;
922
c227f099
AL
923 array_init(&(s->mapping),sizeof(mapping_t));
924 array_init(&(s->directory),sizeof(direntry_t));
de167e41
FB
925
926 /* add volume label */
927 {
d6a7e54e
HP
928 direntry_t* entry=array_get_next(&(s->directory));
929 entry->attributes=0x28; /* archive | volume label */
d5941dda 930 memcpy(entry->name, s->volume_label, sizeof(entry->name));
de167e41
FB
931 }
932
de167e41
FB
933 /* Now build FAT, and write back information into directory */
934 init_fat(s);
935
6817efea
HP
936 /* TODO: if there are more entries, bootsector has to be adjusted! */
937 s->root_entries = 0x02 * 0x10 * s->sectors_per_cluster;
a046433a
FB
938 s->cluster_count=sector2cluster(s, s->sector_count);
939
940 mapping = array_get_next(&(s->mapping));
941 mapping->begin = 0;
942 mapping->dir_index = 0;
943 mapping->info.dir.parent_mapping_index = -1;
944 mapping->first_mapping_index = -1;
7267c094 945 mapping->path = g_strdup(dirname);
a046433a
FB
946 i = strlen(mapping->path);
947 if (i > 0 && mapping->path[i - 1] == '/')
d6a7e54e 948 mapping->path[i - 1] = '\0';
a046433a
FB
949 mapping->mode = MODE_DIRECTORY;
950 mapping->read_only = 0;
951 s->path = mapping->path;
952
953 for (i = 0, cluster = 0; i < s->mapping.next; i++) {
d6a7e54e
HP
954 /* MS-DOS expects the FAT to be 0 for the root directory
955 * (except for the media byte). */
956 /* LATER TODO: still true for FAT32? */
957 int fix_fat = (i != 0);
958 mapping = array_get(&(s->mapping), i);
a046433a
FB
959
960 if (mapping->mode & MODE_DIRECTORY) {
a2b83a51 961 char *path = mapping->path;
d6a7e54e
HP
962 mapping->begin = cluster;
963 if(read_directory(s, i)) {
a2b83a51 964 error_setg(errp, "Could not read directory %s", path);
d6a7e54e
HP
965 return -1;
966 }
967 mapping = array_get(&(s->mapping), i);
968 } else {
969 assert(mapping->mode == MODE_UNDEFINED);
970 mapping->mode=MODE_NORMAL;
971 mapping->begin = cluster;
972 if (mapping->end > 0) {
973 direntry_t* direntry = array_get(&(s->directory),
974 mapping->dir_index);
975
976 mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
977 set_begin_of_direntry(direntry, mapping->begin);
978 } else {
979 mapping->end = cluster + 1;
980 fix_fat = 0;
981 }
982 }
983
984 assert(mapping->begin < mapping->end);
985
986 /* next free cluster */
987 cluster = mapping->end;
988
989 if(cluster > s->cluster_count) {
d11c8917
MA
990 error_setg(errp,
991 "Directory does not fit in FAT%d (capacity %.2f MB)",
992 s->fat_type, s->sector_count / 2000.0);
993 return -1;
d6a7e54e 994 }
8ce0f869 995
d6a7e54e
HP
996 /* fix fat for entry */
997 if (fix_fat) {
998 int j;
999 for(j = mapping->begin; j < mapping->end - 1; j++)
1000 fat_set(s, j, j+1);
1001 fat_set(s, mapping->end - 1, s->max_fat_value);
1002 }
de167e41
FB
1003 }
1004
a046433a 1005 mapping = array_get(&(s->mapping), 0);
a046433a
FB
1006 s->last_cluster_of_root_directory = mapping->end;
1007
1008 /* the FAT signature */
1009 fat_set(s,0,s->max_fat_value);
1010 fat_set(s,1,s->max_fat_value);
de167e41 1011
a046433a
FB
1012 s->current_mapping = NULL;
1013
4dc705dc
HP
1014 bootsector = (bootsector_t *)(s->first_sectors
1015 + s->offset_to_bootsector * 0x200);
de167e41
FB
1016 bootsector->jump[0]=0xeb;
1017 bootsector->jump[1]=0x3e;
1018 bootsector->jump[2]=0x90;
63d261cb 1019 memcpy(bootsector->name, BOOTSECTOR_OEM_NAME, 8);
de167e41
FB
1020 bootsector->sector_size=cpu_to_le16(0x200);
1021 bootsector->sectors_per_cluster=s->sectors_per_cluster;
1022 bootsector->reserved_sectors=cpu_to_le16(1);
1023 bootsector->number_of_fats=0x2; /* number of FATs */
6817efea 1024 bootsector->root_entries = cpu_to_le16(s->root_entries);
a046433a 1025 bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
4dc705dc
HP
1026 /* media descriptor: hard disk=0xf8, floppy=0xf0 */
1027 bootsector->media_type = (s->offset_to_bootsector > 0 ? 0xf8 : 0xf0);
a046433a 1028 s->fat.pointer[0] = bootsector->media_type;
de167e41 1029 bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
4480e0f9
MA
1030 bootsector->sectors_per_track = cpu_to_le16(secs);
1031 bootsector->number_of_heads = cpu_to_le16(heads);
4dc705dc 1032 bootsector->hidden_sectors = cpu_to_le32(s->offset_to_bootsector);
a046433a 1033 bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
de167e41 1034
a046433a 1035 /* LATER TODO: if FAT32, this is wrong */
4dc705dc
HP
1036 /* drive_number: fda=0, hda=0x80 */
1037 bootsector->u.fat16.drive_number = s->offset_to_bootsector == 0 ? 0 : 0x80;
de167e41
FB
1038 bootsector->u.fat16.signature=0x29;
1039 bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
1040
d5941dda
WB
1041 memcpy(bootsector->u.fat16.volume_label, s->volume_label,
1042 sizeof(bootsector->u.fat16.volume_label));
92e28d82
HP
1043 memcpy(bootsector->u.fat16.fat_type,
1044 s->fat_type == 12 ? "FAT12 " : "FAT16 ", 8);
de167e41
FB
1045 bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
1046
1047 return 0;
1048}
1049
83f64091 1050#ifdef DEBUG
a046433a 1051static BDRVVVFATState *vvv = NULL;
83f64091 1052#endif
a046433a 1053
eecc7747 1054static int enable_write_target(BlockDriverState *bs, Error **errp);
eab76d58 1055static int coroutine_fn is_consistent(BDRVVVFATState *s);
a046433a 1056
7ad9be64
KW
1057static QemuOptsList runtime_opts = {
1058 .name = "vvfat",
1059 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
1060 .desc = {
1061 {
1062 .name = "dir",
1063 .type = QEMU_OPT_STRING,
1064 .help = "Host directory to map to the vvfat device",
1065 },
1066 {
1067 .name = "fat-type",
1068 .type = QEMU_OPT_NUMBER,
1069 .help = "FAT type (12, 16 or 32)",
1070 },
1071 {
1072 .name = "floppy",
1073 .type = QEMU_OPT_BOOL,
1074 .help = "Create a floppy rather than a hard disk image",
1075 },
d5941dda
WB
1076 {
1077 .name = "label",
1078 .type = QEMU_OPT_STRING,
1079 .help = "Use a volume label other than QEMU VVFAT",
1080 },
7ad9be64
KW
1081 {
1082 .name = "rw",
1083 .type = QEMU_OPT_BOOL,
1084 .help = "Make the image writable",
1085 },
1086 { /* end of list */ }
1087 },
1088};
1089
1090static void vvfat_parse_filename(const char *filename, QDict *options,
1091 Error **errp)
1092{
1093 int fat_type = 0;
1094 bool floppy = false;
1095 bool rw = false;
1096 int i;
1097
1098 if (!strstart(filename, "fat:", NULL)) {
1099 error_setg(errp, "File name string must start with 'fat:'");
1100 return;
1101 }
1102
1103 /* Parse options */
1104 if (strstr(filename, ":32:")) {
1105 fat_type = 32;
1106 } else if (strstr(filename, ":16:")) {
1107 fat_type = 16;
1108 } else if (strstr(filename, ":12:")) {
1109 fat_type = 12;
1110 }
1111
1112 if (strstr(filename, ":floppy:")) {
1113 floppy = true;
1114 }
1115
1116 if (strstr(filename, ":rw:")) {
1117 rw = true;
1118 }
1119
1120 /* Get the directory name without options */
1121 i = strrchr(filename, ':') - filename;
1122 assert(i >= 3);
1123 if (filename[i - 2] == ':' && qemu_isalpha(filename[i - 1])) {
1124 /* workaround for DOS drive names */
1125 filename += i - 1;
1126 } else {
1127 filename += i + 1;
1128 }
1129
1130 /* Fill in the options QDict */
46f5ac20
EB
1131 qdict_put_str(options, "dir", filename);
1132 qdict_put_int(options, "fat-type", fat_type);
1133 qdict_put_bool(options, "floppy", floppy);
1134 qdict_put_bool(options, "rw", rw);
7ad9be64
KW
1135}
1136
015a1036
HR
1137static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
1138 Error **errp)
de167e41
FB
1139{
1140 BDRVVVFATState *s = bs->opaque;
7ad9be64
KW
1141 int cyls, heads, secs;
1142 bool floppy;
d5941dda 1143 const char *dirname, *label;
7ad9be64 1144 QemuOpts *opts;
7ad9be64 1145 int ret;
de167e41 1146
4026f1c4
KW
1147 GRAPH_RDLOCK_GUARD_MAINLOOP();
1148
83f64091 1149#ifdef DEBUG
a046433a 1150 vvv = s;
83f64091 1151#endif
a046433a 1152
87ea75d5 1153 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
af175e85 1154 if (!qemu_opts_absorb_qdict(opts, options, errp)) {
7ad9be64
KW
1155 ret = -EINVAL;
1156 goto fail;
1157 }
1158
1159 dirname = qemu_opt_get(opts, "dir");
1160 if (!dirname) {
c0f92b52 1161 error_setg(errp, "vvfat block driver requires a 'dir' option");
7ad9be64
KW
1162 ret = -EINVAL;
1163 goto fail;
1164 }
1165
1166 s->fat_type = qemu_opt_get_number(opts, "fat-type", 0);
1167 floppy = qemu_opt_get_bool(opts, "floppy", false);
1168
d5941dda
WB
1169 memset(s->volume_label, ' ', sizeof(s->volume_label));
1170 label = qemu_opt_get(opts, "label");
1171 if (label) {
1172 size_t label_length = strlen(label);
1173 if (label_length > 11) {
1174 error_setg(errp, "vvfat label cannot be longer than 11 bytes");
1175 ret = -EINVAL;
1176 goto fail;
1177 }
1178 memcpy(s->volume_label, label, label_length);
d208c50d
KW
1179 } else {
1180 memcpy(s->volume_label, "QEMU VVFAT", 10);
d5941dda
WB
1181 }
1182
7ad9be64
KW
1183 if (floppy) {
1184 /* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */
1185 if (!s->fat_type) {
1186 s->fat_type = 12;
1187 secs = 36;
1188 s->sectors_per_cluster = 2;
1189 } else {
1190 secs = s->fat_type == 12 ? 18 : 36;
1191 s->sectors_per_cluster = 1;
1192 }
7ad9be64
KW
1193 cyls = 80;
1194 heads = 2;
1195 } else {
1196 /* 32MB or 504MB disk*/
1197 if (!s->fat_type) {
1198 s->fat_type = 16;
1199 }
4dc705dc 1200 s->offset_to_bootsector = 0x3f;
7ad9be64
KW
1201 cyls = s->fat_type == 12 ? 64 : 1024;
1202 heads = 16;
1203 secs = 63;
1204 }
1205
1206 switch (s->fat_type) {
1207 case 32:
b62e39b4 1208 warn_report("FAT32 has not been tested. You are welcome to do so!");
7ad9be64
KW
1209 break;
1210 case 16:
1211 case 12:
1212 break;
1213 default:
c0f92b52 1214 error_setg(errp, "Valid FAT types are only 12, 16 and 32");
7ad9be64
KW
1215 ret = -EINVAL;
1216 goto fail;
1217 }
1218
1219
a046433a
FB
1220 s->bs = bs;
1221
a046433a 1222 /* LATER TODO: if FAT32, adjust */
a046433a 1223 s->sectors_per_cluster=0x10;
de167e41
FB
1224
1225 s->current_cluster=0xffffffff;
de167e41 1226
eecc7747 1227 s->qcow = NULL;
a046433a
FB
1228 s->qcow_filename = NULL;
1229 s->fat2 = NULL;
1230 s->downcase_short_names = 1;
3b46e624 1231
3e31b4e1
TH
1232 DLOG(fprintf(stderr, "vvfat %s chs %d,%d,%d\n",
1233 dirname, cyls, heads, secs));
a046433a 1234
4dc705dc 1235 s->sector_count = cyls * heads * secs - s->offset_to_bootsector;
2db9b9e9 1236 bs->total_sectors = cyls * heads * secs;
5a742b55 1237
7ad9be64 1238 if (qemu_opt_get_bool(opts, "rw", false)) {
e2b8247a
JC
1239 if (!bdrv_is_read_only(bs)) {
1240 ret = enable_write_target(bs, errp);
1241 if (ret < 0) {
1242 goto fail;
1243 }
1244 } else {
1245 ret = -EPERM;
1246 error_setg(errp,
1247 "Unable to set VVFAT to 'rw' when drive is read-only");
1248 goto fail;
1249 }
eaa2410f
KW
1250 } else {
1251 ret = bdrv_apply_auto_read_only(bs, NULL, errp);
78f27bd0 1252 if (ret < 0) {
7ad9be64
KW
1253 goto fail;
1254 }
b570094d
TS
1255 }
1256
d11c8917 1257 if (init_directories(s, dirname, heads, secs, errp)) {
7ad9be64
KW
1258 ret = -EIO;
1259 goto fail;
4480e0f9 1260 }
de167e41 1261
4dc705dc
HP
1262 s->sector_count = s->offset_to_root_dir
1263 + s->sectors_per_cluster * s->cluster_count;
b570094d 1264
3397f0cb
KW
1265 /* Disable migration when vvfat is used rw */
1266 if (s->qcow) {
81e5f78a
AG
1267 error_setg(&s->migration_blocker,
1268 "The vvfat (rw) format used by node '%s' "
1269 "does not support live migration",
1270 bdrv_get_device_or_node_name(bs));
e0ee3a8f 1271 ret = migrate_add_blocker_normal(&s->migration_blocker, errp);
386f6c07 1272 if (ret < 0) {
fe44dc91
AA
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;
cc323997
PB
1484 ret = bdrv_co_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 1809 for (i = 0; !was_modified && i < s->sectors_per_cluster; i++) {
cc323997
PB
1810 was_modified = bdrv_co_is_allocated(s->qcow->bs,
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 */
fb2575f9 1965 int64_t offs = cluster2sector(s, cluster_num);
d6a7e54e
HP
1966
1967 vvfat_close_current_file(s);
7704df98 1968 for (i = 0; i < s->sectors_per_cluster; i++) {
eecc7747
KW
1969 int res;
1970
cc323997
PB
1971 res = bdrv_co_is_allocated(s->qcow->bs,
1972 (offs + i) * BDRV_SECTOR_SIZE,
1973 BDRV_SECTOR_SIZE, NULL);
6f712ee0
EB
1974 if (res < 0) {
1975 return -1;
1976 }
eecc7747 1977 if (!res) {
fb2575f9 1978 res = vvfat_read(s->bs, offs, s->cluster_buffer, 1);
eecc7747 1979 if (res) {
7704df98
KW
1980 return -1;
1981 }
fb2575f9 1982 res = bdrv_co_pwrite(s->qcow, offs * BDRV_SECTOR_SIZE,
eab76d58
PB
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;
fb2575f9
MA
2470
2471 direntry = array_get(&(s->directory), current_dir_index);
2472 ret = vvfat_read(s->bs, cluster2sector(s, c), (uint8_t *)direntry,
d6a7e54e
HP
2473 s->sectors_per_cluster);
2474 if (ret)
2475 return ret;
ebb72c9f
KW
2476
2477 /* The first directory entry on the filesystem is the volume name */
2478 first_direntry = (direntry_t*) s->directory.pointer;
2479 assert(!memcmp(first_direntry->name, s->volume_label, 11));
2480
d6a7e54e 2481 current_dir_index += factor;
a046433a 2482 }
de167e41 2483
a046433a
FB
2484 ret = commit_mappings(s, first_cluster, dir_index);
2485 if (ret)
d6a7e54e 2486 return ret;
a046433a
FB
2487
2488 /* recurse */
2489 for (i = 0; i < factor * new_cluster_count; i++) {
d6a7e54e
HP
2490 direntry = array_get(&(s->directory), first_dir_index + i);
2491 if (is_directory(direntry) && !is_dot(direntry)) {
2492 mapping = find_mapping_for_cluster(s, first_cluster);
8d9401c2
LM
2493 if (mapping == NULL) {
2494 return -1;
2495 }
d6a7e54e
HP
2496 assert(mapping->mode & MODE_DIRECTORY);
2497 ret = commit_direntries(s, first_dir_index + i,
2498 array_index(&(s->mapping), mapping));
2499 if (ret)
2500 return ret;
2501 }
a046433a 2502 }
de167e41 2503
a046433a
FB
2504 return 0;
2505}
de167e41 2506
a046433a
FB
2507/* commit one file (adjust contents, adjust mapping),
2508 return first_mapping_index */
eab76d58
PB
2509static int coroutine_fn GRAPH_RDLOCK
2510commit_one_file(BDRVVVFATState* s, int dir_index, uint32_t offset)
a046433a 2511{
c227f099 2512 direntry_t* direntry = array_get(&(s->directory), dir_index);
a046433a
FB
2513 uint32_t c = begin_of_direntry(direntry);
2514 uint32_t first_cluster = c;
c227f099 2515 mapping_t* mapping = find_mapping_for_cluster(s, c);
a046433a 2516 uint32_t size = filesize_of_direntry(direntry);
443ba6be 2517 char *cluster;
a046433a
FB
2518 uint32_t i;
2519 int fd = 0;
2520
2521 assert(offset < size);
2522 assert((offset % s->cluster_size) == 0);
2523
8d9401c2
LM
2524 if (mapping == NULL) {
2525 return -1;
2526 }
2527
a046433a 2528 for (i = s->cluster_size; i < offset; i += s->cluster_size)
d6a7e54e 2529 c = modified_fat_get(s, c);
a046433a 2530
448058aa 2531 fd = qemu_open_old(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
a046433a 2532 if (fd < 0) {
d6a7e54e
HP
2533 fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2534 strerror(errno), errno);
d6a7e54e 2535 return fd;
de167e41 2536 }
ce137829
SW
2537 if (offset > 0) {
2538 if (lseek(fd, offset, SEEK_SET) != offset) {
2e1e79da 2539 qemu_close(fd);
ce137829
SW
2540 return -3;
2541 }
2542 }
a046433a 2543
443ba6be
KW
2544 cluster = g_malloc(s->cluster_size);
2545
a046433a 2546 while (offset < size) {
d6a7e54e
HP
2547 uint32_t c1;
2548 int rest_size = (size - offset > s->cluster_size ?
2549 s->cluster_size : size - offset);
2550 int ret;
a046433a 2551
d6a7e54e 2552 c1 = modified_fat_get(s, c);
a046433a 2553
d6a7e54e
HP
2554 assert((size - offset == 0 && fat_eof(s, c)) ||
2555 (size > offset && c >=2 && !fat_eof(s, c)));
a046433a 2556
d6a7e54e 2557 ret = vvfat_read(s->bs, cluster2sector(s, c),
78ee96de 2558 (uint8_t*)cluster, DIV_ROUND_UP(rest_size, 0x200));
a046433a 2559
ce137829 2560 if (ret < 0) {
2e1e79da 2561 qemu_close(fd);
ce137829
SW
2562 g_free(cluster);
2563 return ret;
2564 }
a046433a 2565
ce137829 2566 if (write(fd, cluster, rest_size) < 0) {
2e1e79da 2567 qemu_close(fd);
ce137829
SW
2568 g_free(cluster);
2569 return -2;
2570 }
a046433a 2571
d6a7e54e
HP
2572 offset += rest_size;
2573 c = c1;
a046433a
FB
2574 }
2575
2dedf83e
KS
2576 if (ftruncate(fd, size)) {
2577 perror("ftruncate()");
2e1e79da 2578 qemu_close(fd);
ce137829 2579 g_free(cluster);
2dedf83e
KS
2580 return -4;
2581 }
2e1e79da 2582 qemu_close(fd);
ce137829 2583 g_free(cluster);
a046433a
FB
2584
2585 return commit_mappings(s, first_cluster, dir_index);
2586}
2587
2588#ifdef DEBUG
2589/* test, if all mappings point to valid direntries */
2590static void check1(BDRVVVFATState* s)
2591{
2592 int i;
2593 for (i = 0; i < s->mapping.next; i++) {
d6a7e54e
HP
2594 mapping_t* mapping = array_get(&(s->mapping), i);
2595 if (mapping->mode & MODE_DELETED) {
2596 fprintf(stderr, "deleted\n");
2597 continue;
2598 }
2599 assert(mapping->dir_index < s->directory.next);
2600 direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2601 assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2602 if (mapping->mode & MODE_DIRECTORY) {
2603 assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2604 assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2605 }
de167e41 2606 }
de167e41
FB
2607}
2608
a046433a
FB
2609/* test, if all direntries have mappings */
2610static void check2(BDRVVVFATState* s)
de167e41 2611{
de167e41 2612 int i;
a046433a 2613 int first_mapping = -1;
de167e41 2614
a046433a 2615 for (i = 0; i < s->directory.next; i++) {
d6a7e54e
HP
2616 direntry_t* direntry = array_get(&(s->directory), i);
2617
2618 if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2619 mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2620 assert(mapping);
2621 assert(mapping->dir_index == i || is_dot(direntry));
2622 assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2623 }
2624
2625 if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2626 /* cluster start */
2627 int j, count = 0;
2628
2629 for (j = 0; j < s->mapping.next; j++) {
2630 mapping_t* mapping = array_get(&(s->mapping), j);
2631 if (mapping->mode & MODE_DELETED)
2632 continue;
2633 if (mapping->mode & MODE_DIRECTORY) {
2634 if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2635 assert(++count == 1);
2636 if (mapping->first_mapping_index == -1)
2637 first_mapping = array_index(&(s->mapping), mapping);
2638 else
2639 assert(first_mapping == mapping->first_mapping_index);
2640 if (mapping->info.dir.parent_mapping_index < 0)
2641 assert(j == 0);
2642 else {
2643 mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2644 assert(parent->mode & MODE_DIRECTORY);
2645 assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2646 }
2647 }
2648 }
2649 }
2650 if (count == 0)
2651 first_mapping = -1;
2652 }
a046433a
FB
2653 }
2654}
2655#endif
de167e41 2656
a046433a
FB
2657static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2658{
2659 int i;
de167e41 2660
a046433a
FB
2661#ifdef DEBUG
2662 fprintf(stderr, "handle_renames\n");
2663 for (i = 0; i < s->commits.next; i++) {
d6a7e54e 2664 commit_t* commit = array_get(&(s->commits), i);
c9eb2f3e
AC
2665 fprintf(stderr, "%d, %s (%u, %d)\n", i,
2666 commit->path ? commit->path : "(null)",
2667 commit->param.rename.cluster, commit->action);
a046433a
FB
2668 }
2669#endif
2670
2671 for (i = 0; i < s->commits.next;) {
d6a7e54e
HP
2672 commit_t* commit = array_get(&(s->commits), i);
2673 if (commit->action == ACTION_RENAME) {
2674 mapping_t* mapping = find_mapping_for_cluster(s,
2675 commit->param.rename.cluster);
8d9401c2 2676 char *old_path;
d6a7e54e 2677
8d9401c2
LM
2678 if (mapping == NULL) {
2679 return -1;
2680 }
2681 old_path = mapping->path;
d6a7e54e
HP
2682 assert(commit->path);
2683 mapping->path = commit->path;
2684 if (rename(old_path, mapping->path))
2685 return -2;
2686
2687 if (mapping->mode & MODE_DIRECTORY) {
2688 int l1 = strlen(mapping->path);
2689 int l2 = strlen(old_path);
2690 int diff = l1 - l2;
2691 direntry_t* direntry = array_get(&(s->directory),
2692 mapping->info.dir.first_dir_index);
2693 uint32_t c = mapping->begin;
fb2575f9 2694 int j = 0;
d6a7e54e
HP
2695
2696 /* recurse */
2697 while (!fat_eof(s, c)) {
2698 do {
fb2575f9 2699 direntry_t *d = direntry + j;
d6a7e54e
HP
2700
2701 if (is_file(d) || (is_directory(d) && !is_dot(d))) {
8d9401c2
LM
2702 int l;
2703 char *new_path;
d6a7e54e
HP
2704 mapping_t* m = find_mapping_for_cluster(s,
2705 begin_of_direntry(d));
8d9401c2
LM
2706 if (m == NULL) {
2707 return -1;
2708 }
2709 l = strlen(m->path);
2710 new_path = g_malloc(l + diff + 1);
d6a7e54e
HP
2711
2712 assert(!strncmp(m->path, mapping->path, l2));
a046433a 2713
363a37d5
BS
2714 pstrcpy(new_path, l + diff + 1, mapping->path);
2715 pstrcpy(new_path + l1, l + diff + 1 - l1,
2716 m->path + l2);
a046433a 2717
d6a7e54e
HP
2718 schedule_rename(s, m->begin, new_path);
2719 }
fb2575f9
MA
2720 j++;
2721 } while (j % (0x10 * s->sectors_per_cluster) != 0);
d6a7e54e
HP
2722 c = fat_get(s, c);
2723 }
2724 }
de167e41 2725
ce137829 2726 g_free(old_path);
d6a7e54e
HP
2727 array_remove(&(s->commits), i);
2728 continue;
2729 } else if (commit->action == ACTION_MKDIR) {
2730 mapping_t* mapping;
2731 int j, parent_path_len;
a046433a 2732
c2632994 2733 if (g_mkdir(commit->path, 0755)) {
48c2f068 2734 return -5;
c2632994 2735 }
a046433a 2736
d6a7e54e
HP
2737 mapping = insert_mapping(s, commit->param.mkdir.cluster,
2738 commit->param.mkdir.cluster + 1);
2739 if (mapping == NULL)
2740 return -6;
2741
2742 mapping->mode = MODE_DIRECTORY;
2743 mapping->read_only = 0;
2744 mapping->path = commit->path;
2745 j = s->directory.next;
2746 assert(j);
2747 insert_direntries(s, s->directory.next,
2748 0x10 * s->sectors_per_cluster);
2749 mapping->info.dir.first_dir_index = j;
2750
2751 parent_path_len = strlen(commit->path)
2752 - strlen(get_basename(commit->path)) - 1;
2753 for (j = 0; j < s->mapping.next; j++) {
2754 mapping_t* m = array_get(&(s->mapping), j);
2755 if (m->first_mapping_index < 0 && m != mapping &&
2756 !strncmp(m->path, mapping->path, parent_path_len) &&
2757 strlen(m->path) == parent_path_len)
2758 break;
2759 }
2760 assert(j < s->mapping.next);
2761 mapping->info.dir.parent_mapping_index = j;
2762
2763 array_remove(&(s->commits), i);
2764 continue;
2765 }
2766
2767 i++;
a046433a
FB
2768 }
2769 return 0;
2770}
2771
2772/*
2773 * TODO: make sure that the short name is not matching *another* file
2774 */
eab76d58 2775static int coroutine_fn GRAPH_RDLOCK handle_commits(BDRVVVFATState* s)
a046433a
FB
2776{
2777 int i, fail = 0;
2778
2779 vvfat_close_current_file(s);
2780
2781 for (i = 0; !fail && i < s->commits.next; i++) {
d6a7e54e
HP
2782 commit_t* commit = array_get(&(s->commits), i);
2783 switch(commit->action) {
2784 case ACTION_RENAME: case ACTION_MKDIR:
43dc2a64 2785 abort();
d6a7e54e
HP
2786 fail = -2;
2787 break;
2788 case ACTION_WRITEOUT: {
d6a7e54e
HP
2789 direntry_t* entry = array_get(&(s->directory),
2790 commit->param.writeout.dir_index);
2791 uint32_t begin = begin_of_direntry(entry);
2792 mapping_t* mapping = find_mapping_for_cluster(s, begin);
a046433a 2793
d6a7e54e
HP
2794 assert(mapping);
2795 assert(mapping->begin == begin);
2796 assert(commit->path == NULL);
2797
2798 if (commit_one_file(s, commit->param.writeout.dir_index,
2799 commit->param.writeout.modified_offset))
2800 fail = -3;
2801
2802 break;
2803 }
2804 case ACTION_NEW_FILE: {
2805 int begin = commit->param.new_file.first_cluster;
2806 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2807 direntry_t* entry;
fb2575f9 2808 int j;
d6a7e54e
HP
2809
2810 /* find direntry */
fb2575f9
MA
2811 for (j = 0; j < s->directory.next; j++) {
2812 entry = array_get(&(s->directory), j);
d6a7e54e
HP
2813 if (is_file(entry) && begin_of_direntry(entry) == begin)
2814 break;
2815 }
2816
fb2575f9 2817 if (j >= s->directory.next) {
d6a7e54e
HP
2818 fail = -6;
2819 continue;
2820 }
2821
2822 /* make sure there exists an initial mapping */
2823 if (mapping && mapping->begin != begin) {
2824 mapping->end = begin;
2825 mapping = NULL;
2826 }
2827 if (mapping == NULL) {
2828 mapping = insert_mapping(s, begin, begin+1);
2829 }
2830 /* most members will be fixed in commit_mappings() */
2831 assert(commit->path);
2832 mapping->path = commit->path;
2833 mapping->read_only = 0;
2834 mapping->mode = MODE_NORMAL;
2835 mapping->info.file.offset = 0;
2836
fb2575f9 2837 if (commit_one_file(s, j, 0)) {
d6a7e54e 2838 fail = -7;
fb2575f9 2839 }
d6a7e54e
HP
2840
2841 break;
2842 }
2843 default:
43dc2a64 2844 abort();
d6a7e54e 2845 }
a046433a
FB
2846 }
2847 if (i > 0 && array_remove_slice(&(s->commits), 0, i))
d6a7e54e 2848 return -1;
a046433a
FB
2849 return fail;
2850}
2851
2852static int handle_deletes(BDRVVVFATState* s)
2853{
2854 int i, deferred = 1, deleted = 1;
2855
2856 /* delete files corresponding to mappings marked as deleted */
2857 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2858 while (deferred && deleted) {
d6a7e54e
HP
2859 deferred = 0;
2860 deleted = 0;
2861
2862 for (i = 1; i < s->mapping.next; i++) {
2863 mapping_t* mapping = array_get(&(s->mapping), i);
2864 if (mapping->mode & MODE_DELETED) {
2865 direntry_t* entry = array_get(&(s->directory),
2866 mapping->dir_index);
2867
2868 if (is_free(entry)) {
2869 /* remove file/directory */
2870 if (mapping->mode & MODE_DIRECTORY) {
2871 int j, next_dir_index = s->directory.next,
2872 first_dir_index = mapping->info.dir.first_dir_index;
2873
2874 if (rmdir(mapping->path) < 0) {
2875 if (errno == ENOTEMPTY) {
2876 deferred++;
2877 continue;
2878 } else
2879 return -5;
2880 }
2881
2882 for (j = 1; j < s->mapping.next; j++) {
2883 mapping_t* m = array_get(&(s->mapping), j);
2884 if (m->mode & MODE_DIRECTORY &&
2885 m->info.dir.first_dir_index >
2886 first_dir_index &&
2887 m->info.dir.first_dir_index <
2888 next_dir_index)
2889 next_dir_index =
2890 m->info.dir.first_dir_index;
2891 }
2892 remove_direntries(s, first_dir_index,
2893 next_dir_index - first_dir_index);
2894
2895 deleted++;
2896 }
2897 } else {
2898 if (unlink(mapping->path))
2899 return -4;
2900 deleted++;
2901 }
2902 DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2903 remove_mapping(s, i);
2904 }
2905 }
de167e41 2906 }
a046433a
FB
2907
2908 return 0;
2909}
2910
2911/*
2912 * synchronize mapping with new state:
2913 *
f4649069 2914 * - copy FAT (with bdrv_pread)
a046433a 2915 * - mark all filenames corresponding to mappings as deleted
f4649069 2916 * - recurse direntries from root (using bs->bdrv_pread)
a046433a
FB
2917 * - delete files corresponding to mappings marked as deleted
2918 */
eab76d58 2919static int coroutine_fn GRAPH_RDLOCK do_commit(BDRVVVFATState* s)
a046433a
FB
2920{
2921 int ret = 0;
2922
2923 /* the real meat are the commits. Nothing to do? Move along! */
2924 if (s->commits.next == 0)
d6a7e54e 2925 return 0;
a046433a
FB
2926
2927 vvfat_close_current_file(s);
2928
2929 ret = handle_renames_and_mkdirs(s);
2930 if (ret) {
d6a7e54e 2931 fprintf(stderr, "Error handling renames (%d)\n", ret);
43dc2a64 2932 abort();
d6a7e54e 2933 return ret;
a046433a
FB
2934 }
2935
f4649069 2936 /* copy FAT (with bdrv_pread) */
a046433a
FB
2937 memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2938
f4649069 2939 /* recurse direntries from root (using bs->bdrv_pread) */
a046433a
FB
2940 ret = commit_direntries(s, 0, -1);
2941 if (ret) {
d6a7e54e 2942 fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
43dc2a64 2943 abort();
d6a7e54e 2944 return ret;
a046433a
FB
2945 }
2946
2947 ret = handle_commits(s);
2948 if (ret) {
d6a7e54e 2949 fprintf(stderr, "Error handling commits (%d)\n", ret);
43dc2a64 2950 abort();
d6a7e54e 2951 return ret;
a046433a
FB
2952 }
2953
2954 ret = handle_deletes(s);
2955 if (ret) {
d6a7e54e 2956 fprintf(stderr, "Error deleting\n");
43dc2a64 2957 abort();
d6a7e54e 2958 return ret;
a046433a
FB
2959 }
2960
f844ec01 2961 bdrv_make_empty(s->qcow, NULL);
a046433a
FB
2962
2963 memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2964
2965DLOG(checkpoint());
2966 return 0;
2967}
2968
eab76d58 2969static int coroutine_fn GRAPH_RDLOCK try_commit(BDRVVVFATState* s)
a046433a
FB
2970{
2971 vvfat_close_current_file(s);
2972DLOG(checkpoint());
2973 if(!is_consistent(s))
d6a7e54e 2974 return -1;
a046433a
FB
2975 return do_commit(s);
2976}
2977
eab76d58
PB
2978static int coroutine_fn GRAPH_RDLOCK
2979vvfat_write(BlockDriverState *bs, int64_t sector_num,
2980 const uint8_t *buf, int nb_sectors)
a046433a 2981{
5fafdf24 2982 BDRVVVFATState *s = bs->opaque;
a046433a 2983 int i, ret;
b9b8860d 2984 int first_cluster, last_cluster;
a046433a
FB
2985
2986DLOG(checkpoint());
2987
ac48e389
KW
2988 /* Check if we're operating in read-only mode */
2989 if (s->qcow == NULL) {
2990 return -EACCES;
2991 }
2992
a046433a
FB
2993 vvfat_close_current_file(s);
2994
d0f95b6c
HP
2995 if (sector_num == s->offset_to_bootsector && nb_sectors == 1) {
2996 /*
2997 * Write on bootsector. Allow only changing the reserved1 field,
2998 * used to mark volume dirtiness
2999 */
3000 unsigned char *bootsector = s->first_sectors
3001 + s->offset_to_bootsector * 0x200;
3002 /*
3003 * LATER TODO: if FAT32, this is wrong (see init_directories(),
3004 * which always creates a FAT16 bootsector)
3005 */
3006 const int reserved1_offset = offsetof(bootsector_t, u.fat16.reserved1);
3007
3008 for (i = 0; i < 0x200; i++) {
3009 if (i != reserved1_offset && bootsector[i] != buf[i]) {
3010 fprintf(stderr, "Tried to write to protected bootsector\n");
3011 return -1;
3012 }
3013 }
3014
3015 /* Update bootsector with the only updatable byte, and return success */
3016 bootsector[reserved1_offset] = buf[reserved1_offset];
3017 return 0;
3018 }
3019
a046433a
FB
3020 /*
3021 * Some sanity checks:
3022 * - do not allow writing to the boot sector
a046433a 3023 */
4dc705dc 3024 if (sector_num < s->offset_to_fat)
d6a7e54e 3025 return -1;
a046433a 3026
b9b8860d
KW
3027 /*
3028 * Values will be negative for writes to the FAT, which is located before
3029 * the root directory.
3030 */
3031 first_cluster = sector2cluster(s, sector_num);
3032 last_cluster = sector2cluster(s, sector_num + nb_sectors - 1);
3033
3034 for (i = first_cluster; i <= last_cluster;) {
3035 mapping_t *mapping = NULL;
3036
3037 if (i >= 0) {
3038 mapping = find_mapping_for_cluster(s, i);
3039 }
3040
d6a7e54e
HP
3041 if (mapping) {
3042 if (mapping->read_only) {
3043 fprintf(stderr, "Tried to write to write-protected file %s\n",
3044 mapping->path);
3045 return -1;
3046 }
3047
3048 if (mapping->mode & MODE_DIRECTORY) {
3049 int begin = cluster2sector(s, i);
3050 int end = begin + s->sectors_per_cluster, k;
3051 int dir_index;
3052 const direntry_t* direntries;
3053 long_file_name lfn;
3054
3055 lfn_init(&lfn);
3056
3057 if (begin < sector_num)
3058 begin = sector_num;
3059 if (end > sector_num + nb_sectors)
3060 end = sector_num + nb_sectors;
3061 dir_index = mapping->dir_index +
3062 0x10 * (begin - mapping->begin * s->sectors_per_cluster);
3063 direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
3064
3065 for (k = 0; k < (end - begin) * 0x10; k++) {
d6a7e54e 3066 /* no access to the direntry of a read-only file */
e03da26b 3067 if (is_short_name(direntries + k) &&
d6a7e54e
HP
3068 (direntries[k].attributes & 1)) {
3069 if (memcmp(direntries + k,
3070 array_get(&(s->directory), dir_index + k),
3071 sizeof(direntry_t))) {
2ab4b135
AF
3072 warn_report("tried to write to write-protected "
3073 "file");
d6a7e54e
HP
3074 return -1;
3075 }
3076 }
3077 }
3078 }
3079 i = mapping->end;
b9b8860d 3080 } else {
d6a7e54e 3081 i++;
b9b8860d 3082 }
a046433a
FB
3083 }
3084
3085 /*
3086 * Use qcow backend. Commit later.
3087 */
3088DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
eab76d58
PB
3089 ret = bdrv_co_pwrite(s->qcow, sector_num * BDRV_SECTOR_SIZE,
3090 nb_sectors * BDRV_SECTOR_SIZE, buf, 0);
a046433a 3091 if (ret < 0) {
d6a7e54e
HP
3092 fprintf(stderr, "Error writing to qcow backend\n");
3093 return ret;
a046433a
FB
3094 }
3095
b9b8860d
KW
3096 for (i = first_cluster; i <= last_cluster; i++) {
3097 if (i >= 0) {
d6a7e54e 3098 s->used_clusters[i] |= USED_ALLOCATED;
b9b8860d
KW
3099 }
3100 }
a046433a
FB
3101
3102DLOG(checkpoint());
3103 /* TODO: add timeout */
3104 try_commit(s);
3105
3106DLOG(checkpoint());
3107 return 0;
3108}
3109
eab76d58 3110static int coroutine_fn GRAPH_RDLOCK
e75abeda
VSO
3111vvfat_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
3112 QEMUIOVector *qiov, BdrvRequestFlags flags)
e183ef75
PB
3113{
3114 int ret;
3115 BDRVVVFATState *s = bs->opaque;
4575eb49
KW
3116 uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
3117 int nb_sectors = bytes >> BDRV_SECTOR_BITS;
3118 void *buf;
3119
1bbbf32d
NS
3120 assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE));
3121 assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE));
4575eb49
KW
3122
3123 buf = g_try_malloc(bytes);
3124 if (bytes && buf == NULL) {
3125 return -ENOMEM;
3126 }
3127 qemu_iovec_to_buf(qiov, 0, buf, bytes);
3128
e183ef75
PB
3129 qemu_co_mutex_lock(&s->lock);
3130 ret = vvfat_write(bs, sector_num, buf, nb_sectors);
3131 qemu_co_mutex_unlock(&s->lock);
4575eb49
KW
3132
3133 g_free(buf);
3134
e183ef75
PB
3135 return ret;
3136}
3137
fba3998d
EB
3138static int coroutine_fn vvfat_co_block_status(BlockDriverState *bs,
3139 bool want_zero, int64_t offset,
3140 int64_t bytes, int64_t *n,
3141 int64_t *map,
3142 BlockDriverState **file)
a046433a 3143{
fba3998d 3144 *n = bytes;
4bc74be9 3145 return BDRV_BLOCK_DATA;
a046433a
FB
3146}
3147
3cdc69d3 3148static void vvfat_qcow_options(BdrvChildRole role, bool parent_is_format,
272c02ea 3149 int *child_flags, QDict *child_options,
eecc7747 3150 int parent_flags, QDict *parent_options)
a046433a 3151{
f87a0e29 3152 qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off");
e35bdc12 3153 qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off");
4f8e3a1f 3154 qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on");
eecc7747
KW
3155}
3156
8081f064 3157static BdrvChildClass child_vvfat_qcow;
eecc7747
KW
3158
3159static int enable_write_target(BlockDriverState *bs, Error **errp)
3160{
3161 BDRVVVFATState *s = bs->opaque;
facdbb02 3162 BlockDriver *bdrv_qcow = NULL;
facdbb02 3163 QemuOpts *opts = NULL;
a655211a 3164 int ret;
a046433a 3165 int size = sector2cluster(s, s->sector_count);
e6641719
HR
3166 QDict *options;
3167
22c36b75 3168 s->used_clusters = g_malloc0(size);
a046433a 3169
c227f099 3170 array_init(&(s->commits), sizeof(commit_t));
a046433a 3171
69fbfff9
BM
3172 s->qcow_filename = create_tmp_file(errp);
3173 if (!s->qcow_filename) {
3174 ret = -ENOENT;
78f27bd0 3175 goto err;
eba25057 3176 }
91a073a9
KW
3177
3178 bdrv_qcow = bdrv_find_format("qcow");
1bcb15cf
HR
3179 if (!bdrv_qcow) {
3180 error_setg(errp, "Failed to locate qcow driver");
3181 ret = -ENOENT;
3182 goto err;
3183 }
3184
c282e1fd 3185 opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort);
2db9b9e9
KW
3186 qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
3187 bs->total_sectors * BDRV_SECTOR_SIZE, &error_abort);
f43e47db 3188 qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:", &error_abort);
91a073a9 3189
c282e1fd 3190 ret = bdrv_create(bdrv_qcow, s->qcow_filename, opts, errp);
facdbb02 3191 qemu_opts_del(opts);
78f27bd0
FZ
3192 if (ret < 0) {
3193 goto err;
3194 }
a655211a 3195
e6641719 3196 options = qdict_new();
46f5ac20 3197 qdict_put_str(options, "write-target.driver", "qcow");
eecc7747 3198 s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs,
1f38f04e
HR
3199 &child_vvfat_qcow,
3200 BDRV_CHILD_DATA | BDRV_CHILD_METADATA,
3201 false, errp);
cb3e7f08 3202 qobject_unref(options);
5b363937
HR
3203 if (!s->qcow) {
3204 ret = -EINVAL;
78f27bd0 3205 goto err;
d6e9098e 3206 }
a046433a
FB
3207
3208#ifndef _WIN32
3209 unlink(s->qcow_filename);
3210#endif
3211
de167e41 3212 return 0;
78f27bd0
FZ
3213
3214err:
78f27bd0 3215 return ret;
de167e41
FB
3216}
3217
91ef3825 3218static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c,
bf8e925e 3219 BdrvChildRole role,
e0995dc3 3220 BlockReopenQueue *reopen_queue,
91ef3825
KW
3221 uint64_t perm, uint64_t shared,
3222 uint64_t *nperm, uint64_t *nshared)
3223{
6af72274
VSO
3224 assert(role & BDRV_CHILD_DATA);
3225 /* This is a private node, nobody should try to attach to it */
3226 *nperm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE;
3227 *nshared = BLK_PERM_WRITE_UNCHANGED;
91ef3825
KW
3228}
3229
de167e41
FB
3230static void vvfat_close(BlockDriverState *bs)
3231{
3232 BDRVVVFATState *s = bs->opaque;
3233
3234 vvfat_close_current_file(s);
3235 array_free(&(s->fat));
3236 array_free(&(s->directory));
3237 array_free(&(s->mapping));
ce137829 3238 g_free(s->cluster_buffer);
3397f0cb
KW
3239
3240 if (s->qcow) {
c8a7fc51 3241 migrate_del_blocker(&s->migration_blocker);
3397f0cb 3242 }
de167e41
FB
3243}
3244
2654267c
HR
3245static const char *const vvfat_strong_runtime_opts[] = {
3246 "dir",
3247 "fat-type",
3248 "floppy",
3249 "label",
3250 "rw",
3251
3252 NULL
3253};
3254
5efa9d5a 3255static BlockDriver bdrv_vvfat = {
7ad9be64
KW
3256 .format_name = "vvfat",
3257 .protocol_name = "fat",
3258 .instance_size = sizeof(BDRVVVFATState),
3259
3260 .bdrv_parse_filename = vvfat_parse_filename,
3261 .bdrv_file_open = vvfat_open,
a6506481 3262 .bdrv_refresh_limits = vvfat_refresh_limits,
7ad9be64 3263 .bdrv_close = vvfat_close,
91ef3825 3264 .bdrv_child_perm = vvfat_child_perm,
7ad9be64 3265
4575eb49
KW
3266 .bdrv_co_preadv = vvfat_co_preadv,
3267 .bdrv_co_pwritev = vvfat_co_pwritev,
fba3998d 3268 .bdrv_co_block_status = vvfat_co_block_status,
2654267c
HR
3269
3270 .strong_runtime_opts = vvfat_strong_runtime_opts,
de167e41
FB
3271};
3272
5efa9d5a
AL
3273static void bdrv_vvfat_init(void)
3274{
8081f064
VSO
3275 child_vvfat_qcow = child_of_bds;
3276 child_vvfat_qcow.inherit_options = vvfat_qcow_options;
5efa9d5a
AL
3277 bdrv_register(&bdrv_vvfat);
3278}
3279
3280block_init(bdrv_vvfat_init);
3281
a046433a 3282#ifdef DEBUG
7a6ab45e
TH
3283static void checkpoint(void)
3284{
c227f099 3285 assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
a046433a
FB
3286 check1(vvv);
3287 check2(vvv);
3288 assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
a046433a
FB
3289}
3290#endif