]> git.proxmox.com Git - mirror_qemu.git/blame - block/vvfat.c
swim: update IWM/ISM register block decoding
[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
83f64091 1147#ifdef DEBUG
a046433a 1148 vvv = s;
83f64091 1149#endif
a046433a 1150
87ea75d5 1151 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
af175e85 1152 if (!qemu_opts_absorb_qdict(opts, options, errp)) {
7ad9be64
KW
1153 ret = -EINVAL;
1154 goto fail;
1155 }
1156
1157 dirname = qemu_opt_get(opts, "dir");
1158 if (!dirname) {
c0f92b52 1159 error_setg(errp, "vvfat block driver requires a 'dir' option");
7ad9be64
KW
1160 ret = -EINVAL;
1161 goto fail;
1162 }
1163
1164 s->fat_type = qemu_opt_get_number(opts, "fat-type", 0);
1165 floppy = qemu_opt_get_bool(opts, "floppy", false);
1166
d5941dda
WB
1167 memset(s->volume_label, ' ', sizeof(s->volume_label));
1168 label = qemu_opt_get(opts, "label");
1169 if (label) {
1170 size_t label_length = strlen(label);
1171 if (label_length > 11) {
1172 error_setg(errp, "vvfat label cannot be longer than 11 bytes");
1173 ret = -EINVAL;
1174 goto fail;
1175 }
1176 memcpy(s->volume_label, label, label_length);
d208c50d
KW
1177 } else {
1178 memcpy(s->volume_label, "QEMU VVFAT", 10);
d5941dda
WB
1179 }
1180
7ad9be64
KW
1181 if (floppy) {
1182 /* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */
1183 if (!s->fat_type) {
1184 s->fat_type = 12;
1185 secs = 36;
1186 s->sectors_per_cluster = 2;
1187 } else {
1188 secs = s->fat_type == 12 ? 18 : 36;
1189 s->sectors_per_cluster = 1;
1190 }
7ad9be64
KW
1191 cyls = 80;
1192 heads = 2;
1193 } else {
1194 /* 32MB or 504MB disk*/
1195 if (!s->fat_type) {
1196 s->fat_type = 16;
1197 }
4dc705dc 1198 s->offset_to_bootsector = 0x3f;
7ad9be64
KW
1199 cyls = s->fat_type == 12 ? 64 : 1024;
1200 heads = 16;
1201 secs = 63;
1202 }
1203
1204 switch (s->fat_type) {
1205 case 32:
b62e39b4 1206 warn_report("FAT32 has not been tested. You are welcome to do so!");
7ad9be64
KW
1207 break;
1208 case 16:
1209 case 12:
1210 break;
1211 default:
c0f92b52 1212 error_setg(errp, "Valid FAT types are only 12, 16 and 32");
7ad9be64
KW
1213 ret = -EINVAL;
1214 goto fail;
1215 }
1216
1217
a046433a
FB
1218 s->bs = bs;
1219
a046433a 1220 /* LATER TODO: if FAT32, adjust */
a046433a 1221 s->sectors_per_cluster=0x10;
de167e41
FB
1222
1223 s->current_cluster=0xffffffff;
de167e41 1224
eecc7747 1225 s->qcow = NULL;
a046433a
FB
1226 s->qcow_filename = NULL;
1227 s->fat2 = NULL;
1228 s->downcase_short_names = 1;
3b46e624 1229
3e31b4e1
TH
1230 DLOG(fprintf(stderr, "vvfat %s chs %d,%d,%d\n",
1231 dirname, cyls, heads, secs));
a046433a 1232
4dc705dc 1233 s->sector_count = cyls * heads * secs - s->offset_to_bootsector;
2db9b9e9 1234 bs->total_sectors = cyls * heads * secs;
5a742b55 1235
7ad9be64 1236 if (qemu_opt_get_bool(opts, "rw", false)) {
e2b8247a
JC
1237 if (!bdrv_is_read_only(bs)) {
1238 ret = enable_write_target(bs, errp);
1239 if (ret < 0) {
1240 goto fail;
1241 }
1242 } else {
1243 ret = -EPERM;
1244 error_setg(errp,
1245 "Unable to set VVFAT to 'rw' when drive is read-only");
1246 goto fail;
1247 }
eaa2410f
KW
1248 } else {
1249 ret = bdrv_apply_auto_read_only(bs, NULL, errp);
78f27bd0 1250 if (ret < 0) {
7ad9be64
KW
1251 goto fail;
1252 }
b570094d
TS
1253 }
1254
d11c8917 1255 if (init_directories(s, dirname, heads, secs, errp)) {
7ad9be64
KW
1256 ret = -EIO;
1257 goto fail;
4480e0f9 1258 }
de167e41 1259
4dc705dc
HP
1260 s->sector_count = s->offset_to_root_dir
1261 + s->sectors_per_cluster * s->cluster_count;
b570094d 1262
3397f0cb
KW
1263 /* Disable migration when vvfat is used rw */
1264 if (s->qcow) {
81e5f78a
AG
1265 error_setg(&s->migration_blocker,
1266 "The vvfat (rw) format used by node '%s' "
1267 "does not support live migration",
1268 bdrv_get_device_or_node_name(bs));
386f6c07
MA
1269 ret = migrate_add_blocker(s->migration_blocker, errp);
1270 if (ret < 0) {
fe44dc91
AA
1271 error_free(s->migration_blocker);
1272 goto fail;
1273 }
3397f0cb
KW
1274 }
1275
4dc705dc 1276 if (s->offset_to_bootsector > 0) {
fe44dc91
AA
1277 init_mbr(s, cyls, heads, secs);
1278 }
1279
1280 qemu_co_mutex_init(&s->lock);
1281
22c36b75
DL
1282 qemu_opts_del(opts);
1283
1284 return 0;
1285
7ad9be64 1286fail:
22c36b75
DL
1287 g_free(s->qcow_filename);
1288 s->qcow_filename = NULL;
1289 g_free(s->cluster_buffer);
1290 s->cluster_buffer = NULL;
1291 g_free(s->used_clusters);
1292 s->used_clusters = NULL;
1293
7ad9be64
KW
1294 qemu_opts_del(opts);
1295 return ret;
de167e41
FB
1296}
1297
a6506481
EB
1298static void vvfat_refresh_limits(BlockDriverState *bs, Error **errp)
1299{
a5b8dd2c 1300 bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */
a6506481
EB
1301}
1302
de167e41
FB
1303static inline void vvfat_close_current_file(BDRVVVFATState *s)
1304{
1305 if(s->current_mapping) {
d6a7e54e
HP
1306 s->current_mapping = NULL;
1307 if (s->current_fd) {
1308 qemu_close(s->current_fd);
1309 s->current_fd = 0;
1310 }
de167e41 1311 }
a046433a 1312 s->current_cluster = -1;
de167e41
FB
1313}
1314
1315/* mappings between index1 and index2-1 are supposed to be ordered
1316 * return value is the index of the last mapping for which end>cluster_num
1317 */
1318static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1319{
de167e41 1320 while(1) {
88bf7950 1321 int index3;
d6a7e54e
HP
1322 mapping_t* mapping;
1323 index3=(index1+index2)/2;
1324 mapping=array_get(&(s->mapping),index3);
1325 assert(mapping->begin < mapping->end);
1326 if(mapping->begin>=cluster_num) {
1327 assert(index2!=index3 || index2==0);
1328 if(index2==index3)
1329 return index1;
1330 index2=index3;
1331 } else {
1332 if(index1==index3)
1333 return mapping->end<=cluster_num ? index2 : index1;
1334 index1=index3;
1335 }
1336 assert(index1<=index2);
1337 DLOG(mapping=array_get(&(s->mapping),index1);
1338 assert(mapping->begin<=cluster_num);
1339 assert(index2 >= s->mapping.next ||
1340 ((mapping = array_get(&(s->mapping),index2)) &&
1341 mapping->end>cluster_num)));
de167e41
FB
1342 }
1343}
1344
c227f099 1345static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
de167e41
FB
1346{
1347 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
c227f099 1348 mapping_t* mapping;
de167e41 1349 if(index>=s->mapping.next)
511d2b14 1350 return NULL;
de167e41
FB
1351 mapping=array_get(&(s->mapping),index);
1352 if(mapping->begin>cluster_num)
511d2b14 1353 return NULL;
a046433a 1354 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
de167e41
FB
1355 return mapping;
1356}
1357
c227f099 1358static int open_file(BDRVVVFATState* s,mapping_t* mapping)
de167e41
FB
1359{
1360 if(!mapping)
d6a7e54e 1361 return -1;
de167e41 1362 if(!s->current_mapping ||
d6a7e54e
HP
1363 strcmp(s->current_mapping->path,mapping->path)) {
1364 /* open file */
448058aa
DB
1365 int fd = qemu_open_old(mapping->path,
1366 O_RDONLY | O_BINARY | O_LARGEFILE);
d6a7e54e
HP
1367 if(fd<0)
1368 return -1;
1369 vvfat_close_current_file(s);
1370 s->current_fd = fd;
1371 s->current_mapping = mapping;
de167e41
FB
1372 }
1373 return 0;
1374}
1375
1376static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1377{
1378 if(s->current_cluster != cluster_num) {
d6a7e54e
HP
1379 int result=0;
1380 off_t offset;
1381 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
1382 if(!s->current_mapping
1383 || s->current_mapping->begin>cluster_num
1384 || s->current_mapping->end<=cluster_num) {
1385 /* binary search of mappings for file */
1386 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
1387
1388 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1389
1390 if (mapping && mapping->mode & MODE_DIRECTORY) {
1391 vvfat_close_current_file(s);
1392 s->current_mapping = mapping;
a046433a 1393read_cluster_directory:
d6a7e54e
HP
1394 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
1395 s->cluster = (unsigned char*)s->directory.pointer+offset
1396 + 0x20*s->current_mapping->info.dir.first_dir_index;
1397 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1398 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1399 s->current_cluster = cluster_num;
1400 return 0;
1401 }
1402
1403 if(open_file(s,mapping))
1404 return -2;
1405 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1406 goto read_cluster_directory;
1407
1408 assert(s->current_fd);
1409
1410 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
1411 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1412 return -3;
1413 s->cluster=s->cluster_buffer;
1414 result=read(s->current_fd,s->cluster,s->cluster_size);
1415 if(result<0) {
1416 s->current_cluster = -1;
1417 return -1;
1418 }
1419 s->current_cluster = cluster_num;
de167e41
FB
1420 }
1421 return 0;
1422}
1423
a046433a 1424#ifdef DEBUG
c227f099 1425static void print_direntry(const direntry_t* direntry)
de167e41 1426{
a046433a
FB
1427 int j = 0;
1428 char buffer[1024];
1429
3e89cb04 1430 fprintf(stderr, "direntry %p: ", direntry);
de167e41 1431 if(!direntry)
d6a7e54e 1432 return;
a046433a 1433 if(is_long_name(direntry)) {
d6a7e54e
HP
1434 unsigned char* c=(unsigned char*)direntry;
1435 int i;
1436 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
3891b370 1437#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
d6a7e54e
HP
1438 ADD_CHAR(c[i]);
1439 for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
1440 ADD_CHAR(c[i]);
1441 for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
1442 ADD_CHAR(c[i]);
1443 buffer[j] = 0;
1444 fprintf(stderr, "%s\n", buffer);
de167e41 1445 } else {
d6a7e54e
HP
1446 int i;
1447 for(i=0;i<11;i++)
1448 ADD_CHAR(direntry->name[i]);
1449 buffer[j] = 0;
c9eb2f3e 1450 fprintf(stderr, "%s attributes=0x%02x begin=%u size=%u\n",
d6a7e54e
HP
1451 buffer,
1452 direntry->attributes,
1453 begin_of_direntry(direntry),le32_to_cpu(direntry->size));
de167e41
FB
1454 }
1455}
1456
c227f099 1457static void print_mapping(const mapping_t* mapping)
de167e41 1458{
c9eb2f3e 1459 fprintf(stderr, "mapping (%p): begin, end = %u, %u, dir_index = %u, "
3e89cb04
KW
1460 "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1461 mapping, mapping->begin, mapping->end, mapping->dir_index,
1462 mapping->first_mapping_index, mapping->path, mapping->mode);
1463
a046433a 1464 if (mapping->mode & MODE_DIRECTORY)
d6a7e54e 1465 fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
a046433a 1466 else
c9eb2f3e 1467 fprintf(stderr, "offset = %u\n", mapping->info.file.offset);
de167e41 1468}
a046433a 1469#endif
de167e41 1470
eab76d58
PB
1471static int coroutine_fn GRAPH_RDLOCK
1472vvfat_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors)
de167e41 1473{
a046433a 1474 BDRVVVFATState *s = bs->opaque;
de167e41 1475 int i;
de167e41 1476
a046433a 1477 for(i=0;i<nb_sectors;i++,sector_num++) {
d6a7e54e
HP
1478 if (sector_num >= bs->total_sectors)
1479 return -1;
1480 if (s->qcow) {
d6a644bb 1481 int64_t n;
6f712ee0 1482 int ret;
d6a644bb
EB
1483 ret = bdrv_is_allocated(s->qcow->bs, sector_num * BDRV_SECTOR_SIZE,
1484 (nb_sectors - i) * BDRV_SECTOR_SIZE, &n);
6f712ee0
EB
1485 if (ret < 0) {
1486 return ret;
1487 }
1488 if (ret) {
d6a644bb
EB
1489 DLOG(fprintf(stderr, "sectors %" PRId64 "+%" PRId64
1490 " allocated\n", sector_num,
1491 n >> BDRV_SECTOR_BITS));
eab76d58
PB
1492 if (bdrv_co_pread(s->qcow, sector_num * BDRV_SECTOR_SIZE, n,
1493 buf + i * 0x200, 0) < 0) {
7704df98
KW
1494 return -1;
1495 }
d6a644bb
EB
1496 i += (n >> BDRV_SECTOR_BITS) - 1;
1497 sector_num += (n >> BDRV_SECTOR_BITS) - 1;
7704df98
KW
1498 continue;
1499 }
d6a644bb
EB
1500 DLOG(fprintf(stderr, "sector %" PRId64 " not allocated\n",
1501 sector_num));
d6a7e54e 1502 }
4dc705dc
HP
1503 if (sector_num < s->offset_to_root_dir) {
1504 if (sector_num < s->offset_to_fat) {
1505 memcpy(buf + i * 0x200,
1506 &(s->first_sectors[sector_num * 0x200]),
1507 0x200);
1508 } else if (sector_num < s->offset_to_fat + s->sectors_per_fat) {
1509 memcpy(buf + i * 0x200,
1510 &(s->fat.pointer[(sector_num
1511 - s->offset_to_fat) * 0x200]),
1512 0x200);
1513 } else if (sector_num < s->offset_to_root_dir) {
1514 memcpy(buf + i * 0x200,
1515 &(s->fat.pointer[(sector_num - s->offset_to_fat
1516 - s->sectors_per_fat) * 0x200]),
1517 0x200);
1518 }
d6a7e54e 1519 } else {
4dc705dc 1520 uint32_t sector = sector_num - s->offset_to_root_dir,
d6a7e54e
HP
1521 sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1522 cluster_num=sector/s->sectors_per_cluster;
1523 if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) {
1524 /* LATER TODO: strict: return -1; */
1525 memset(buf+i*0x200,0,0x200);
1526 continue;
1527 }
1528 memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
1529 }
de167e41 1530 }
de167e41
FB
1531 return 0;
1532}
1533
eab76d58 1534static int coroutine_fn GRAPH_RDLOCK
f7ef38dd
VSO
1535vvfat_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
1536 QEMUIOVector *qiov, BdrvRequestFlags flags)
2914caa0
PB
1537{
1538 int ret;
1539 BDRVVVFATState *s = bs->opaque;
4575eb49
KW
1540 uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
1541 int nb_sectors = bytes >> BDRV_SECTOR_BITS;
1542 void *buf;
1543
1bbbf32d
NS
1544 assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE));
1545 assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE));
4575eb49
KW
1546
1547 buf = g_try_malloc(bytes);
1548 if (bytes && buf == NULL) {
1549 return -ENOMEM;
1550 }
1551
2914caa0
PB
1552 qemu_co_mutex_lock(&s->lock);
1553 ret = vvfat_read(bs, sector_num, buf, nb_sectors);
1554 qemu_co_mutex_unlock(&s->lock);
4575eb49
KW
1555
1556 qemu_iovec_from_buf(qiov, 0, buf, bytes);
1557 g_free(buf);
1558
2914caa0
PB
1559 return ret;
1560}
1561
a046433a 1562/* LATER TODO: statify all functions */
de167e41 1563
a046433a
FB
1564/*
1565 * Idea of the write support (use snapshot):
de167e41 1566 *
a046433a
FB
1567 * 1. check if all data is consistent, recording renames, modifications,
1568 * new files and directories (in s->commits).
de167e41 1569 *
a046433a 1570 * 2. if the data is not consistent, stop committing
de167e41 1571 *
a046433a
FB
1572 * 3. handle renames, and create new files and directories (do not yet
1573 * write their contents)
de167e41 1574 *
a046433a
FB
1575 * 4. walk the directories, fixing the mapping and direntries, and marking
1576 * the handled mappings as not deleted
de167e41 1577 *
a046433a 1578 * 5. commit the contents of the files
de167e41 1579 *
a046433a 1580 * 6. handle deleted files and directories
de167e41
FB
1581 *
1582 */
1583
c227f099 1584typedef struct commit_t {
a046433a
FB
1585 char* path;
1586 union {
d6a7e54e
HP
1587 struct { uint32_t cluster; } rename;
1588 struct { int dir_index; uint32_t modified_offset; } writeout;
1589 struct { uint32_t first_cluster; } new_file;
1590 struct { uint32_t cluster; } mkdir;
a046433a
FB
1591 } param;
1592 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1593 enum {
d6a7e54e 1594 ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
a046433a 1595 } action;
c227f099 1596} commit_t;
de167e41 1597
a046433a 1598static void clear_commits(BDRVVVFATState* s)
de167e41
FB
1599{
1600 int i;
c9eb2f3e 1601DLOG(fprintf(stderr, "clear_commits (%u commits)\n", s->commits.next));
a046433a 1602 for (i = 0; i < s->commits.next; i++) {
d6a7e54e
HP
1603 commit_t* commit = array_get(&(s->commits), i);
1604 assert(commit->path || commit->action == ACTION_WRITEOUT);
1605 if (commit->action != ACTION_WRITEOUT) {
1606 assert(commit->path);
ce137829 1607 g_free(commit->path);
d6a7e54e
HP
1608 } else
1609 assert(commit->path == NULL);
de167e41 1610 }
a046433a 1611 s->commits.next = 0;
de167e41
FB
1612}
1613
a046433a 1614static void schedule_rename(BDRVVVFATState* s,
d6a7e54e 1615 uint32_t cluster, char* new_path)
de167e41 1616{
c227f099 1617 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1618 commit->path = new_path;
1619 commit->param.rename.cluster = cluster;
1620 commit->action = ACTION_RENAME;
de167e41
FB
1621}
1622
a046433a 1623static void schedule_writeout(BDRVVVFATState* s,
d6a7e54e 1624 int dir_index, uint32_t modified_offset)
de167e41 1625{
c227f099 1626 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1627 commit->path = NULL;
1628 commit->param.writeout.dir_index = dir_index;
1629 commit->param.writeout.modified_offset = modified_offset;
1630 commit->action = ACTION_WRITEOUT;
de167e41
FB
1631}
1632
a046433a 1633static void schedule_new_file(BDRVVVFATState* s,
d6a7e54e 1634 char* path, uint32_t first_cluster)
de167e41 1635{
c227f099 1636 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1637 commit->path = path;
1638 commit->param.new_file.first_cluster = first_cluster;
1639 commit->action = ACTION_NEW_FILE;
1640}
1641
1642static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1643{
c227f099 1644 commit_t* commit = array_get_next(&(s->commits));
a046433a
FB
1645 commit->path = path;
1646 commit->param.mkdir.cluster = cluster;
1647 commit->action = ACTION_MKDIR;
1648}
1649
1650typedef struct {
64eaabda
TS
1651 /*
1652 * Since the sequence number is at most 0x3f, and the filename
1653 * length is at most 13 times the sequence number, the maximal
1654 * filename length is 0x3f * 13 bytes.
1655 */
1656 unsigned char name[0x3f * 13 + 1];
e03da26b 1657 gunichar2 name2[0x3f * 13 + 1];
a046433a
FB
1658 int checksum, len;
1659 int sequence_number;
1660} long_file_name;
1661
1662static void lfn_init(long_file_name* lfn)
1663{
1664 lfn->sequence_number = lfn->len = 0;
1665 lfn->checksum = 0x100;
1666}
1667
1668/* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1669static int parse_long_name(long_file_name* lfn,
d6a7e54e 1670 const direntry_t* direntry)
a046433a
FB
1671{
1672 int i, j, offset;
1673 const unsigned char* pointer = (const unsigned char*)direntry;
1674
1675 if (!is_long_name(direntry))
d6a7e54e 1676 return 1;
a046433a
FB
1677
1678 if (pointer[0] & 0x40) {
e03da26b 1679 /* first entry; do some initialization */
d6a7e54e
HP
1680 lfn->sequence_number = pointer[0] & 0x3f;
1681 lfn->checksum = pointer[13];
1682 lfn->name[0] = 0;
1683 lfn->name[lfn->sequence_number * 13] = 0;
e03da26b
HP
1684 } else if ((pointer[0] & 0x3f) != --lfn->sequence_number) {
1685 /* not the expected sequence number */
d6a7e54e 1686 return -1;
e03da26b
HP
1687 } else if (pointer[13] != lfn->checksum) {
1688 /* not the expected checksum */
d6a7e54e 1689 return -2;
e03da26b
HP
1690 } else if (pointer[12] || pointer[26] || pointer[27]) {
1691 /* invalid zero fields */
d6a7e54e 1692 return -3;
e03da26b 1693 }
a046433a
FB
1694
1695 offset = 13 * (lfn->sequence_number - 1);
1696 for (i = 0, j = 1; i < 13; i++, j+=2) {
d6a7e54e
HP
1697 if (j == 11)
1698 j = 14;
1699 else if (j == 26)
1700 j = 28;
a046433a 1701
e03da26b
HP
1702 if (pointer[j] == 0 && pointer[j + 1] == 0) {
1703 /* end of long file name */
1704 break;
1705 }
1706 gunichar2 c = (pointer[j + 1] << 8) + pointer[j];
1707 lfn->name2[offset + i] = c;
de167e41 1708 }
a046433a 1709
e03da26b
HP
1710 if (pointer[0] & 0x40) {
1711 /* first entry; set len */
1712 lfn->len = offset + i;
1713 }
1714 if ((pointer[0] & 0x3f) == 0x01) {
1715 /* last entry; finalize entry */
1716 glong olen;
1717 gchar *utf8 = g_utf16_to_utf8(lfn->name2, lfn->len, NULL, &olen, NULL);
1718 if (!utf8) {
1719 return -4;
1720 }
1721 lfn->len = olen;
1722 memcpy(lfn->name, utf8, olen + 1);
1723 g_free(utf8);
1724 }
a046433a 1725
de167e41
FB
1726 return 0;
1727}
1728
a046433a
FB
1729/* returns 0 if successful, >0 if no short_name, and <0 on error */
1730static int parse_short_name(BDRVVVFATState* s,
d6a7e54e 1731 long_file_name* lfn, direntry_t* direntry)
de167e41 1732{
a046433a 1733 int i, j;
de167e41 1734
a046433a 1735 if (!is_short_name(direntry))
d6a7e54e 1736 return 1;
a046433a
FB
1737
1738 for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1739 for (i = 0; i <= j; i++) {
e03da26b
HP
1740 uint8_t c = direntry->name[i];
1741 if (c != to_valid_short_char(c)) {
d6a7e54e 1742 return -1;
e03da26b 1743 } else if (s->downcase_short_names) {
d6a7e54e 1744 lfn->name[i] = qemu_tolower(direntry->name[i]);
e03da26b 1745 } else {
d6a7e54e 1746 lfn->name[i] = direntry->name[i];
e03da26b 1747 }
de167e41
FB
1748 }
1749
f671d173
SW
1750 for (j = 2; j >= 0 && direntry->name[8 + j] == ' '; j--) {
1751 }
a046433a 1752 if (j >= 0) {
d6a7e54e
HP
1753 lfn->name[i++] = '.';
1754 lfn->name[i + j + 1] = '\0';
1755 for (;j >= 0; j--) {
f671d173 1756 uint8_t c = direntry->name[8 + j];
e03da26b 1757 if (c != to_valid_short_char(c)) {
f671d173
SW
1758 return -2;
1759 } else if (s->downcase_short_names) {
1760 lfn->name[i + j] = qemu_tolower(c);
1761 } else {
1762 lfn->name[i + j] = c;
1763 }
d6a7e54e 1764 }
a046433a 1765 } else
d6a7e54e 1766 lfn->name[i + j + 1] = '\0';
a046433a 1767
8c4517fd
HP
1768 if (lfn->name[0] == DIR_KANJI_FAKE) {
1769 lfn->name[0] = DIR_KANJI;
78f002c9 1770 }
ffe8ab83 1771 lfn->len = strlen((char*)lfn->name);
a046433a
FB
1772
1773 return 0;
de167e41
FB
1774}
1775
a046433a 1776static inline uint32_t modified_fat_get(BDRVVVFATState* s,
d6a7e54e 1777 unsigned int cluster)
de167e41 1778{
a046433a 1779 if (cluster < s->last_cluster_of_root_directory) {
d6a7e54e
HP
1780 if (cluster + 1 == s->last_cluster_of_root_directory)
1781 return s->max_fat_value;
1782 else
1783 return cluster + 1;
a046433a
FB
1784 }
1785
1786 if (s->fat_type==32) {
1787 uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1788 return le32_to_cpu(*entry);
1789 } else if (s->fat_type==16) {
1790 uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1791 return le16_to_cpu(*entry);
1792 } else {
1793 const uint8_t* x=s->fat2+cluster*3/2;
1794 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1795 }
1796}
1797
eab76d58
PB
1798static inline bool coroutine_fn GRAPH_RDLOCK
1799cluster_was_modified(BDRVVVFATState *s, uint32_t cluster_num)
a046433a
FB
1800{
1801 int was_modified = 0;
d6a644bb 1802 int i;
a046433a 1803
eecc7747
KW
1804 if (s->qcow == NULL) {
1805 return 0;
1806 }
a046433a 1807
eecc7747
KW
1808 for (i = 0; !was_modified && i < s->sectors_per_cluster; i++) {
1809 was_modified = bdrv_is_allocated(s->qcow->bs,
d6a644bb
EB
1810 (cluster2sector(s, cluster_num) +
1811 i) * BDRV_SECTOR_SIZE,
1812 BDRV_SECTOR_SIZE, NULL);
eecc7747 1813 }
a046433a 1814
6f712ee0
EB
1815 /*
1816 * Note that this treats failures to learn allocation status the
1817 * same as if an allocation has occurred. It's as safe as
1818 * anything else, given that a failure to learn allocation status
1819 * will probably result in more failures.
1820 */
1821 return !!was_modified;
de167e41
FB
1822}
1823
a046433a 1824static const char* get_basename(const char* path)
de167e41 1825{
a046433a
FB
1826 char* basename = strrchr(path, '/');
1827 if (basename == NULL)
d6a7e54e 1828 return path;
a046433a 1829 else
d6a7e54e 1830 return basename + 1; /* strip '/' */
de167e41
FB
1831}
1832
a046433a
FB
1833/*
1834 * The array s->used_clusters holds the states of the clusters. If it is
1835 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1836 * was modified, bit 3 is set.
1837 * If any cluster is allocated, but not part of a file or directory, this
1838 * driver refuses to commit.
1839 */
1840typedef enum {
1841 USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
c227f099 1842} used_t;
de167e41 1843
a046433a
FB
1844/*
1845 * get_cluster_count_for_direntry() not only determines how many clusters
1846 * are occupied by direntry, but also if it was renamed or modified.
1847 *
1848 * A file is thought to be renamed *only* if there already was a file with
1849 * exactly the same first cluster, but a different name.
1850 *
1851 * Further, the files/directories handled by this function are
1852 * assumed to be *not* deleted (and *only* those).
1853 */
eab76d58
PB
1854static uint32_t coroutine_fn GRAPH_RDLOCK
1855get_cluster_count_for_direntry(BDRVVVFATState* s, direntry_t* direntry, const char* path)
de167e41 1856{
a046433a
FB
1857 /*
1858 * This is a little bit tricky:
1859 * IF the guest OS just inserts a cluster into the file chain,
1860 * and leaves the rest alone, (i.e. the original file had clusters
1861 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1862 *
1863 * - do_commit will write the cluster into the file at the given
1864 * offset, but
1865 *
1866 * - the cluster which is overwritten should be moved to a later
1867 * position in the file.
1868 *
1869 * I am not aware that any OS does something as braindead, but this
1870 * situation could happen anyway when not committing for a long time.
1871 * Just to be sure that this does not bite us, detect it, and copy the
1872 * contents of the clusters to-be-overwritten into the qcow.
1873 */
1874 int copy_it = 0;
1875 int was_modified = 0;
1876 int32_t ret = 0;
1877
1878 uint32_t cluster_num = begin_of_direntry(direntry);
1879 uint32_t offset = 0;
1880 int first_mapping_index = -1;
c227f099 1881 mapping_t* mapping = NULL;
a046433a 1882 const char* basename2 = NULL;
de167e41 1883
a046433a 1884 vvfat_close_current_file(s);
de167e41 1885
a046433a
FB
1886 /* the root directory */
1887 if (cluster_num == 0)
d6a7e54e 1888 return 0;
de167e41 1889
a046433a
FB
1890 /* write support */
1891 if (s->qcow) {
d6a7e54e 1892 basename2 = get_basename(path);
de167e41 1893
d6a7e54e 1894 mapping = find_mapping_for_cluster(s, cluster_num);
a046433a 1895
d6a7e54e
HP
1896 if (mapping) {
1897 const char* basename;
da2414e9 1898
d6a7e54e
HP
1899 assert(mapping->mode & MODE_DELETED);
1900 mapping->mode &= ~MODE_DELETED;
a046433a 1901
d6a7e54e 1902 basename = get_basename(mapping->path);
a046433a 1903
d6a7e54e 1904 assert(mapping->mode & MODE_NORMAL);
a046433a 1905
d6a7e54e
HP
1906 /* rename */
1907 if (strcmp(basename, basename2))
1908 schedule_rename(s, cluster_num, g_strdup(path));
1909 } else if (is_file(direntry))
1910 /* new file */
1911 schedule_new_file(s, g_strdup(path), cluster_num);
1912 else {
43dc2a64 1913 abort();
d6a7e54e
HP
1914 return 0;
1915 }
de167e41
FB
1916 }
1917
a046433a 1918 while(1) {
d6a7e54e
HP
1919 if (s->qcow) {
1920 if (!copy_it && cluster_was_modified(s, cluster_num)) {
1921 if (mapping == NULL ||
1922 mapping->begin > cluster_num ||
1923 mapping->end <= cluster_num)
1924 mapping = find_mapping_for_cluster(s, cluster_num);
de167e41 1925
a046433a 1926
d6a7e54e
HP
1927 if (mapping &&
1928 (mapping->mode & MODE_DIRECTORY) == 0) {
a046433a 1929
d6a7e54e
HP
1930 /* was modified in qcow */
1931 if (offset != mapping->info.file.offset + s->cluster_size
1932 * (cluster_num - mapping->begin)) {
1933 /* offset of this cluster in file chain has changed */
43dc2a64 1934 abort();
d6a7e54e
HP
1935 copy_it = 1;
1936 } else if (offset == 0) {
1937 const char* basename = get_basename(mapping->path);
a046433a 1938
d6a7e54e
HP
1939 if (strcmp(basename, basename2))
1940 copy_it = 1;
1941 first_mapping_index = array_index(&(s->mapping), mapping);
1942 }
a046433a 1943
d6a7e54e
HP
1944 if (mapping->first_mapping_index != first_mapping_index
1945 && mapping->info.file.offset > 0) {
43dc2a64 1946 abort();
d6a7e54e
HP
1947 copy_it = 1;
1948 }
1949
1950 /* need to write out? */
1951 if (!was_modified && is_file(direntry)) {
1952 was_modified = 1;
1953 schedule_writeout(s, mapping->dir_index, offset);
1954 }
1955 }
1956 }
1957
1958 if (copy_it) {
d6a644bb 1959 int i;
d6a7e54e
HP
1960 /*
1961 * This is horribly inefficient, but that is okay, since
1962 * it is rarely executed, if at all.
1963 */
fb2575f9 1964 int64_t offs = cluster2sector(s, cluster_num);
d6a7e54e
HP
1965
1966 vvfat_close_current_file(s);
7704df98 1967 for (i = 0; i < s->sectors_per_cluster; i++) {
eecc7747
KW
1968 int res;
1969
d6a644bb 1970 res = bdrv_is_allocated(s->qcow->bs,
fb2575f9 1971 (offs + i) * BDRV_SECTOR_SIZE,
d6a644bb 1972 BDRV_SECTOR_SIZE, NULL);
6f712ee0
EB
1973 if (res < 0) {
1974 return -1;
1975 }
eecc7747 1976 if (!res) {
fb2575f9 1977 res = vvfat_read(s->bs, offs, s->cluster_buffer, 1);
eecc7747 1978 if (res) {
7704df98
KW
1979 return -1;
1980 }
fb2575f9 1981 res = bdrv_co_pwrite(s->qcow, offs * BDRV_SECTOR_SIZE,
eab76d58
PB
1982 BDRV_SECTOR_SIZE, s->cluster_buffer,
1983 0);
e5a0a678 1984 if (res < 0) {
7704df98
KW
1985 return -2;
1986 }
1987 }
1988 }
d6a7e54e
HP
1989 }
1990 }
a046433a 1991
d6a7e54e
HP
1992 ret++;
1993 if (s->used_clusters[cluster_num] & USED_ANY)
1994 return 0;
1995 s->used_clusters[cluster_num] = USED_FILE;
a046433a 1996
d6a7e54e 1997 cluster_num = modified_fat_get(s, cluster_num);
a046433a 1998
d6a7e54e
HP
1999 if (fat_eof(s, cluster_num))
2000 return ret;
2001 else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
2002 return -1;
a046433a 2003
d6a7e54e 2004 offset += s->cluster_size;
a046433a 2005 }
de167e41
FB
2006}
2007
a046433a 2008/*
5fafdf24 2009 * This function looks at the modified data (qcow).
a046433a
FB
2010 * It returns 0 upon inconsistency or error, and the number of clusters
2011 * used by the directory, its subdirectories and their files.
2012 */
eab76d58
PB
2013static int coroutine_fn GRAPH_RDLOCK
2014check_directory_consistency(BDRVVVFATState *s, int cluster_num, const char* path)
de167e41 2015{
a046433a 2016 int ret = 0;
7267c094 2017 unsigned char* cluster = g_malloc(s->cluster_size);
c227f099
AL
2018 direntry_t* direntries = (direntry_t*)cluster;
2019 mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
a046433a
FB
2020
2021 long_file_name lfn;
2022 int path_len = strlen(path);
0d460d6f 2023 char path2[PATH_MAX + 1];
a046433a
FB
2024
2025 assert(path_len < PATH_MAX); /* len was tested before! */
363a37d5 2026 pstrcpy(path2, sizeof(path2), path);
a046433a
FB
2027 path2[path_len] = '/';
2028 path2[path_len + 1] = '\0';
2029
2030 if (mapping) {
d6a7e54e
HP
2031 const char* basename = get_basename(mapping->path);
2032 const char* basename2 = get_basename(path);
a046433a 2033
d6a7e54e 2034 assert(mapping->mode & MODE_DIRECTORY);
a046433a 2035
d6a7e54e
HP
2036 assert(mapping->mode & MODE_DELETED);
2037 mapping->mode &= ~MODE_DELETED;
a046433a 2038
d6a7e54e
HP
2039 if (strcmp(basename, basename2))
2040 schedule_rename(s, cluster_num, g_strdup(path));
a046433a 2041 } else
d6a7e54e
HP
2042 /* new directory */
2043 schedule_mkdir(s, cluster_num, g_strdup(path));
3b46e624 2044
a046433a
FB
2045 lfn_init(&lfn);
2046 do {
d6a7e54e
HP
2047 int i;
2048 int subret = 0;
a046433a 2049
d6a7e54e 2050 ret++;
a046433a 2051
d6a7e54e
HP
2052 if (s->used_clusters[cluster_num] & USED_ANY) {
2053 fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
6262bbd3 2054 goto fail;
d6a7e54e
HP
2055 }
2056 s->used_clusters[cluster_num] = USED_DIRECTORY;
a046433a
FB
2057
2058DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
d6a7e54e
HP
2059 subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
2060 s->sectors_per_cluster);
2061 if (subret) {
2062 fprintf(stderr, "Error fetching direntries\n");
2063 fail:
ce137829 2064 g_free(cluster);
d6a7e54e
HP
2065 return 0;
2066 }
a046433a 2067
d6a7e54e
HP
2068 for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
2069 int cluster_count = 0;
a046433a 2070
b2bedb21 2071DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i));
d6a7e54e
HP
2072 if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
2073 is_free(direntries + i))
2074 continue;
2075
2076 subret = parse_long_name(&lfn, direntries + i);
2077 if (subret < 0) {
2078 fprintf(stderr, "Error in long name\n");
2079 goto fail;
2080 }
2081 if (subret == 0 || is_free(direntries + i))
2082 continue;
2083
2084 if (fat_chksum(direntries+i) != lfn.checksum) {
2085 subret = parse_short_name(s, &lfn, direntries + i);
2086 if (subret < 0) {
2087 fprintf(stderr, "Error in short name (%d)\n", subret);
2088 goto fail;
2089 }
2090 if (subret > 0 || !strcmp((char*)lfn.name, ".")
2091 || !strcmp((char*)lfn.name, ".."))
2092 continue;
2093 }
2094 lfn.checksum = 0x100; /* cannot use long name twice */
2095
c79e243e
KW
2096 if (!valid_filename(lfn.name)) {
2097 fprintf(stderr, "Invalid file name\n");
2098 goto fail;
2099 }
d6a7e54e
HP
2100 if (path_len + 1 + lfn.len >= PATH_MAX) {
2101 fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
2102 goto fail;
2103 }
363a37d5
BS
2104 pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
2105 (char*)lfn.name);
a046433a 2106
d6a7e54e
HP
2107 if (is_directory(direntries + i)) {
2108 if (begin_of_direntry(direntries + i) == 0) {
2109 DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
2110 goto fail;
2111 }
2112 cluster_count = check_directory_consistency(s,
2113 begin_of_direntry(direntries + i), path2);
2114 if (cluster_count == 0) {
2115 DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
2116 goto fail;
2117 }
2118 } else if (is_file(direntries + i)) {
2119 /* check file size with FAT */
2120 cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
2121 if (cluster_count !=
13385ae1 2122 DIV_ROUND_UP(le32_to_cpu(direntries[i].size), s->cluster_size)) {
d6a7e54e
HP
2123 DLOG(fprintf(stderr, "Cluster count mismatch\n"));
2124 goto fail;
2125 }
2126 } else
43dc2a64 2127 abort(); /* cluster_count = 0; */
a046433a 2128
d6a7e54e
HP
2129 ret += cluster_count;
2130 }
de167e41 2131
d6a7e54e 2132 cluster_num = modified_fat_get(s, cluster_num);
a046433a 2133 } while(!fat_eof(s, cluster_num));
de167e41 2134
ce137829 2135 g_free(cluster);
a046433a
FB
2136 return ret;
2137}
2138
2139/* returns 1 on success */
eab76d58
PB
2140static int coroutine_fn GRAPH_RDLOCK
2141is_consistent(BDRVVVFATState* s)
a046433a
FB
2142{
2143 int i, check;
2144 int used_clusters_count = 0;
2145
2146DLOG(checkpoint());
2147 /*
2148 * - get modified FAT
2149 * - compare the two FATs (TODO)
2150 * - get buffer for marking used clusters
f4649069 2151 * - recurse direntries from root (using bs->bdrv_pread to make
a046433a
FB
2152 * sure to get the new data)
2153 * - check that the FAT agrees with the size
2154 * - count the number of clusters occupied by this directory and
2155 * its files
2156 * - check that the cumulative used cluster count agrees with the
2157 * FAT
2158 * - if all is fine, return number of used clusters
2159 */
2160 if (s->fat2 == NULL) {
d6a7e54e
HP
2161 int size = 0x200 * s->sectors_per_fat;
2162 s->fat2 = g_malloc(size);
2163 memcpy(s->fat2, s->fat.pointer, size);
a046433a
FB
2164 }
2165 check = vvfat_read(s->bs,
4dc705dc 2166 s->offset_to_fat, s->fat2, s->sectors_per_fat);
a046433a 2167 if (check) {
d6a7e54e
HP
2168 fprintf(stderr, "Could not copy fat\n");
2169 return 0;
a046433a
FB
2170 }
2171 assert (s->used_clusters);
2172 for (i = 0; i < sector2cluster(s, s->sector_count); i++)
d6a7e54e 2173 s->used_clusters[i] &= ~USED_ANY;
a046433a
FB
2174
2175 clear_commits(s);
2176
2177 /* mark every mapped file/directory as deleted.
2178 * (check_directory_consistency() will unmark those still present). */
2179 if (s->qcow)
d6a7e54e
HP
2180 for (i = 0; i < s->mapping.next; i++) {
2181 mapping_t* mapping = array_get(&(s->mapping), i);
2182 if (mapping->first_mapping_index < 0)
2183 mapping->mode |= MODE_DELETED;
2184 }
a046433a
FB
2185
2186 used_clusters_count = check_directory_consistency(s, 0, s->path);
2187 if (used_clusters_count <= 0) {
d6a7e54e
HP
2188 DLOG(fprintf(stderr, "problem in directory\n"));
2189 return 0;
de167e41
FB
2190 }
2191
a046433a
FB
2192 check = s->last_cluster_of_root_directory;
2193 for (i = check; i < sector2cluster(s, s->sector_count); i++) {
d6a7e54e
HP
2194 if (modified_fat_get(s, i)) {
2195 if(!s->used_clusters[i]) {
2196 DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
2197 return 0;
2198 }
2199 check++;
2200 }
a046433a 2201
d6a7e54e
HP
2202 if (s->used_clusters[i] == USED_ALLOCATED) {
2203 /* allocated, but not used... */
2204 DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
2205 return 0;
2206 }
a046433a
FB
2207 }
2208
2209 if (check != used_clusters_count)
d6a7e54e 2210 return 0;
a046433a
FB
2211
2212 return used_clusters_count;
2213}
2214
2215static inline void adjust_mapping_indices(BDRVVVFATState* s,
d6a7e54e 2216 int offset, int adjust)
a046433a
FB
2217{
2218 int i;
2219
2220 for (i = 0; i < s->mapping.next; i++) {
d6a7e54e 2221 mapping_t* mapping = array_get(&(s->mapping), i);
a046433a
FB
2222
2223#define ADJUST_MAPPING_INDEX(name) \
d6a7e54e
HP
2224 if (mapping->name >= offset) \
2225 mapping->name += adjust
a046433a 2226
d6a7e54e
HP
2227 ADJUST_MAPPING_INDEX(first_mapping_index);
2228 if (mapping->mode & MODE_DIRECTORY)
2229 ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
de167e41 2230 }
a046433a
FB
2231}
2232
2233/* insert or update mapping */
c227f099 2234static mapping_t* insert_mapping(BDRVVVFATState* s,
d6a7e54e 2235 uint32_t begin, uint32_t end)
a046433a
FB
2236{
2237 /*
2238 * - find mapping where mapping->begin >= begin,
2239 * - if mapping->begin > begin: insert
2240 * - adjust all references to mappings!
2241 * - else: adjust
2242 * - replace name
2243 */
2244 int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
c227f099
AL
2245 mapping_t* mapping = NULL;
2246 mapping_t* first_mapping = array_get(&(s->mapping), 0);
a046433a
FB
2247
2248 if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
d6a7e54e
HP
2249 && mapping->begin < begin) {
2250 mapping->end = begin;
2251 index++;
2252 mapping = array_get(&(s->mapping), index);
a046433a
FB
2253 }
2254 if (index >= s->mapping.next || mapping->begin > begin) {
d6a7e54e
HP
2255 mapping = array_insert(&(s->mapping), index, 1);
2256 mapping->path = NULL;
2257 adjust_mapping_indices(s, index, +1);
a046433a
FB
2258 }
2259
2260 mapping->begin = begin;
2261 mapping->end = end;
de167e41 2262
c227f099 2263DLOG(mapping_t* next_mapping;
a046433a
FB
2264assert(index + 1 >= s->mapping.next ||
2265((next_mapping = array_get(&(s->mapping), index + 1)) &&
2266 next_mapping->begin >= end)));
2267
c227f099 2268 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
d6a7e54e
HP
2269 s->current_mapping = array_get(&(s->mapping),
2270 s->current_mapping - first_mapping);
a046433a
FB
2271
2272 return mapping;
2273}
2274
2275static int remove_mapping(BDRVVVFATState* s, int mapping_index)
2276{
c227f099
AL
2277 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
2278 mapping_t* first_mapping = array_get(&(s->mapping), 0);
a046433a
FB
2279
2280 /* free mapping */
ce137829
SW
2281 if (mapping->first_mapping_index < 0) {
2282 g_free(mapping->path);
2283 }
a046433a
FB
2284
2285 /* remove from s->mapping */
2286 array_remove(&(s->mapping), mapping_index);
2287
2288 /* adjust all references to mappings */
2289 adjust_mapping_indices(s, mapping_index, -1);
2290
c227f099 2291 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
d6a7e54e
HP
2292 s->current_mapping = array_get(&(s->mapping),
2293 s->current_mapping - first_mapping);
de167e41 2294
de167e41
FB
2295 return 0;
2296}
2297
a046433a
FB
2298static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
2299{
2300 int i;
2301 for (i = 0; i < s->mapping.next; i++) {
d6a7e54e
HP
2302 mapping_t* mapping = array_get(&(s->mapping), i);
2303 if (mapping->dir_index >= offset)
2304 mapping->dir_index += adjust;
2305 if ((mapping->mode & MODE_DIRECTORY) &&
2306 mapping->info.dir.first_dir_index >= offset)
2307 mapping->info.dir.first_dir_index += adjust;
a046433a
FB
2308 }
2309}
de167e41 2310
c227f099 2311static direntry_t* insert_direntries(BDRVVVFATState* s,
d6a7e54e 2312 int dir_index, int count)
de167e41 2313{
a046433a
FB
2314 /*
2315 * make room in s->directory,
2316 * adjust_dirindices
2317 */
c227f099 2318 direntry_t* result = array_insert(&(s->directory), dir_index, count);
a046433a 2319 if (result == NULL)
d6a7e54e 2320 return NULL;
a046433a 2321 adjust_dirindices(s, dir_index, count);
de167e41
FB
2322 return result;
2323}
2324
a046433a
FB
2325static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
2326{
2327 int ret = array_remove_slice(&(s->directory), dir_index, count);
2328 if (ret)
d6a7e54e 2329 return ret;
a046433a
FB
2330 adjust_dirindices(s, dir_index, -count);
2331 return 0;
2332}
de167e41 2333
a046433a
FB
2334/*
2335 * Adapt the mappings of the cluster chain starting at first cluster
2336 * (i.e. if a file starts at first_cluster, the chain is followed according
2337 * to the modified fat, and the corresponding entries in s->mapping are
2338 * adjusted)
2339 */
2340static int commit_mappings(BDRVVVFATState* s,
d6a7e54e 2341 uint32_t first_cluster, int dir_index)
de167e41 2342{
c227f099
AL
2343 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2344 direntry_t* direntry = array_get(&(s->directory), dir_index);
a046433a
FB
2345 uint32_t cluster = first_cluster;
2346
2347 vvfat_close_current_file(s);
2348
2349 assert(mapping);
2350 assert(mapping->begin == first_cluster);
2351 mapping->first_mapping_index = -1;
2352 mapping->dir_index = dir_index;
2353 mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
d6a7e54e 2354 MODE_DIRECTORY : MODE_NORMAL;
a046433a
FB
2355
2356 while (!fat_eof(s, cluster)) {
d6a7e54e
HP
2357 uint32_t c, c1;
2358
2359 for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2360 c = c1, c1 = modified_fat_get(s, c1));
2361
2362 c++;
2363 if (c > mapping->end) {
2364 int index = array_index(&(s->mapping), mapping);
2365 int i, max_i = s->mapping.next - index;
2366 for (i = 1; i < max_i && mapping[i].begin < c; i++);
2367 while (--i > 0)
2368 remove_mapping(s, index + 1);
2369 }
2370 assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2371 || mapping[1].begin >= c);
2372 mapping->end = c;
2373
2374 if (!fat_eof(s, c1)) {
2375 int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2376 mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2377 array_get(&(s->mapping), i);
2378
2379 if (next_mapping == NULL || next_mapping->begin > c1) {
2380 int i1 = array_index(&(s->mapping), mapping);
2381
2382 next_mapping = insert_mapping(s, c1, c1+1);
2383
2384 if (c1 < c)
2385 i1++;
2386 mapping = array_get(&(s->mapping), i1);
2387 }
2388
2389 next_mapping->dir_index = mapping->dir_index;
2390 next_mapping->first_mapping_index =
2391 mapping->first_mapping_index < 0 ?
2392 array_index(&(s->mapping), mapping) :
2393 mapping->first_mapping_index;
2394 next_mapping->path = mapping->path;
2395 next_mapping->mode = mapping->mode;
2396 next_mapping->read_only = mapping->read_only;
2397 if (mapping->mode & MODE_DIRECTORY) {
2398 next_mapping->info.dir.parent_mapping_index =
2399 mapping->info.dir.parent_mapping_index;
2400 next_mapping->info.dir.first_dir_index =
2401 mapping->info.dir.first_dir_index +
2402 0x10 * s->sectors_per_cluster *
2403 (mapping->end - mapping->begin);
2404 } else
2405 next_mapping->info.file.offset = mapping->info.file.offset +
2406 mapping->end - mapping->begin;
2407
2408 mapping = next_mapping;
2409 }
2410
2411 cluster = c1;
a046433a 2412 }
de167e41 2413
de167e41
FB
2414 return 0;
2415}
2416
eab76d58
PB
2417static int coroutine_fn GRAPH_RDLOCK
2418commit_direntries(BDRVVVFATState* s, int dir_index, int parent_mapping_index)
de167e41 2419{
c227f099 2420 direntry_t* direntry = array_get(&(s->directory), dir_index);
a046433a 2421 uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
c227f099 2422 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
a046433a
FB
2423 int factor = 0x10 * s->sectors_per_cluster;
2424 int old_cluster_count, new_cluster_count;
8d9401c2
LM
2425 int current_dir_index;
2426 int first_dir_index;
a046433a
FB
2427 int ret, i;
2428 uint32_t c;
2429
a046433a
FB
2430 assert(direntry);
2431 assert(mapping);
2432 assert(mapping->begin == first_cluster);
2433 assert(mapping->info.dir.first_dir_index < s->directory.next);
2434 assert(mapping->mode & MODE_DIRECTORY);
2435 assert(dir_index == 0 || is_directory(direntry));
2436
8d9401c2
LM
2437 DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n",
2438 mapping->path, parent_mapping_index));
2439
2440 current_dir_index = mapping->info.dir.first_dir_index;
2441 first_dir_index = current_dir_index;
a046433a
FB
2442 mapping->info.dir.parent_mapping_index = parent_mapping_index;
2443
2444 if (first_cluster == 0) {
d6a7e54e
HP
2445 old_cluster_count = new_cluster_count =
2446 s->last_cluster_of_root_directory;
a046433a 2447 } else {
d6a7e54e
HP
2448 for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2449 c = fat_get(s, c))
2450 old_cluster_count++;
de167e41 2451
d6a7e54e
HP
2452 for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2453 c = modified_fat_get(s, c))
2454 new_cluster_count++;
a046433a 2455 }
de167e41 2456
a046433a 2457 if (new_cluster_count > old_cluster_count) {
d6a7e54e
HP
2458 if (insert_direntries(s,
2459 current_dir_index + factor * old_cluster_count,
2460 factor * (new_cluster_count - old_cluster_count)) == NULL)
2461 return -1;
a046433a 2462 } else if (new_cluster_count < old_cluster_count)
d6a7e54e
HP
2463 remove_direntries(s,
2464 current_dir_index + factor * new_cluster_count,
2465 factor * (old_cluster_count - new_cluster_count));
a046433a
FB
2466
2467 for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
ebb72c9f 2468 direntry_t *first_direntry;
fb2575f9
MA
2469
2470 direntry = array_get(&(s->directory), current_dir_index);
2471 ret = vvfat_read(s->bs, cluster2sector(s, c), (uint8_t *)direntry,
d6a7e54e
HP
2472 s->sectors_per_cluster);
2473 if (ret)
2474 return ret;
ebb72c9f
KW
2475
2476 /* The first directory entry on the filesystem is the volume name */
2477 first_direntry = (direntry_t*) s->directory.pointer;
2478 assert(!memcmp(first_direntry->name, s->volume_label, 11));
2479
d6a7e54e 2480 current_dir_index += factor;
a046433a 2481 }
de167e41 2482
a046433a
FB
2483 ret = commit_mappings(s, first_cluster, dir_index);
2484 if (ret)
d6a7e54e 2485 return ret;
a046433a
FB
2486
2487 /* recurse */
2488 for (i = 0; i < factor * new_cluster_count; i++) {
d6a7e54e
HP
2489 direntry = array_get(&(s->directory), first_dir_index + i);
2490 if (is_directory(direntry) && !is_dot(direntry)) {
2491 mapping = find_mapping_for_cluster(s, first_cluster);
8d9401c2
LM
2492 if (mapping == NULL) {
2493 return -1;
2494 }
d6a7e54e
HP
2495 assert(mapping->mode & MODE_DIRECTORY);
2496 ret = commit_direntries(s, first_dir_index + i,
2497 array_index(&(s->mapping), mapping));
2498 if (ret)
2499 return ret;
2500 }
a046433a 2501 }
de167e41 2502
a046433a
FB
2503 return 0;
2504}
de167e41 2505
a046433a
FB
2506/* commit one file (adjust contents, adjust mapping),
2507 return first_mapping_index */
eab76d58
PB
2508static int coroutine_fn GRAPH_RDLOCK
2509commit_one_file(BDRVVVFATState* s, int dir_index, uint32_t offset)
a046433a 2510{
c227f099 2511 direntry_t* direntry = array_get(&(s->directory), dir_index);
a046433a
FB
2512 uint32_t c = begin_of_direntry(direntry);
2513 uint32_t first_cluster = c;
c227f099 2514 mapping_t* mapping = find_mapping_for_cluster(s, c);
a046433a 2515 uint32_t size = filesize_of_direntry(direntry);
443ba6be 2516 char *cluster;
a046433a
FB
2517 uint32_t i;
2518 int fd = 0;
2519
2520 assert(offset < size);
2521 assert((offset % s->cluster_size) == 0);
2522
8d9401c2
LM
2523 if (mapping == NULL) {
2524 return -1;
2525 }
2526
a046433a 2527 for (i = s->cluster_size; i < offset; i += s->cluster_size)
d6a7e54e 2528 c = modified_fat_get(s, c);
a046433a 2529
448058aa 2530 fd = qemu_open_old(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
a046433a 2531 if (fd < 0) {
d6a7e54e
HP
2532 fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2533 strerror(errno), errno);
d6a7e54e 2534 return fd;
de167e41 2535 }
ce137829
SW
2536 if (offset > 0) {
2537 if (lseek(fd, offset, SEEK_SET) != offset) {
2e1e79da 2538 qemu_close(fd);
ce137829
SW
2539 return -3;
2540 }
2541 }
a046433a 2542
443ba6be
KW
2543 cluster = g_malloc(s->cluster_size);
2544
a046433a 2545 while (offset < size) {
d6a7e54e
HP
2546 uint32_t c1;
2547 int rest_size = (size - offset > s->cluster_size ?
2548 s->cluster_size : size - offset);
2549 int ret;
a046433a 2550
d6a7e54e 2551 c1 = modified_fat_get(s, c);
a046433a 2552
d6a7e54e
HP
2553 assert((size - offset == 0 && fat_eof(s, c)) ||
2554 (size > offset && c >=2 && !fat_eof(s, c)));
a046433a 2555
d6a7e54e 2556 ret = vvfat_read(s->bs, cluster2sector(s, c),
78ee96de 2557 (uint8_t*)cluster, DIV_ROUND_UP(rest_size, 0x200));
a046433a 2558
ce137829 2559 if (ret < 0) {
2e1e79da 2560 qemu_close(fd);
ce137829
SW
2561 g_free(cluster);
2562 return ret;
2563 }
a046433a 2564
ce137829 2565 if (write(fd, cluster, rest_size) < 0) {
2e1e79da 2566 qemu_close(fd);
ce137829
SW
2567 g_free(cluster);
2568 return -2;
2569 }
a046433a 2570
d6a7e54e
HP
2571 offset += rest_size;
2572 c = c1;
a046433a
FB
2573 }
2574
2dedf83e
KS
2575 if (ftruncate(fd, size)) {
2576 perror("ftruncate()");
2e1e79da 2577 qemu_close(fd);
ce137829 2578 g_free(cluster);
2dedf83e
KS
2579 return -4;
2580 }
2e1e79da 2581 qemu_close(fd);
ce137829 2582 g_free(cluster);
a046433a
FB
2583
2584 return commit_mappings(s, first_cluster, dir_index);
2585}
2586
2587#ifdef DEBUG
2588/* test, if all mappings point to valid direntries */
2589static void check1(BDRVVVFATState* s)
2590{
2591 int i;
2592 for (i = 0; i < s->mapping.next; i++) {
d6a7e54e
HP
2593 mapping_t* mapping = array_get(&(s->mapping), i);
2594 if (mapping->mode & MODE_DELETED) {
2595 fprintf(stderr, "deleted\n");
2596 continue;
2597 }
2598 assert(mapping->dir_index < s->directory.next);
2599 direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2600 assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2601 if (mapping->mode & MODE_DIRECTORY) {
2602 assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2603 assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2604 }
de167e41 2605 }
de167e41
FB
2606}
2607
a046433a
FB
2608/* test, if all direntries have mappings */
2609static void check2(BDRVVVFATState* s)
de167e41 2610{
de167e41 2611 int i;
a046433a 2612 int first_mapping = -1;
de167e41 2613
a046433a 2614 for (i = 0; i < s->directory.next; i++) {
d6a7e54e
HP
2615 direntry_t* direntry = array_get(&(s->directory), i);
2616
2617 if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2618 mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2619 assert(mapping);
2620 assert(mapping->dir_index == i || is_dot(direntry));
2621 assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2622 }
2623
2624 if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2625 /* cluster start */
2626 int j, count = 0;
2627
2628 for (j = 0; j < s->mapping.next; j++) {
2629 mapping_t* mapping = array_get(&(s->mapping), j);
2630 if (mapping->mode & MODE_DELETED)
2631 continue;
2632 if (mapping->mode & MODE_DIRECTORY) {
2633 if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2634 assert(++count == 1);
2635 if (mapping->first_mapping_index == -1)
2636 first_mapping = array_index(&(s->mapping), mapping);
2637 else
2638 assert(first_mapping == mapping->first_mapping_index);
2639 if (mapping->info.dir.parent_mapping_index < 0)
2640 assert(j == 0);
2641 else {
2642 mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2643 assert(parent->mode & MODE_DIRECTORY);
2644 assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2645 }
2646 }
2647 }
2648 }
2649 if (count == 0)
2650 first_mapping = -1;
2651 }
a046433a
FB
2652 }
2653}
2654#endif
de167e41 2655
a046433a
FB
2656static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2657{
2658 int i;
de167e41 2659
a046433a
FB
2660#ifdef DEBUG
2661 fprintf(stderr, "handle_renames\n");
2662 for (i = 0; i < s->commits.next; i++) {
d6a7e54e 2663 commit_t* commit = array_get(&(s->commits), i);
c9eb2f3e
AC
2664 fprintf(stderr, "%d, %s (%u, %d)\n", i,
2665 commit->path ? commit->path : "(null)",
2666 commit->param.rename.cluster, commit->action);
a046433a
FB
2667 }
2668#endif
2669
2670 for (i = 0; i < s->commits.next;) {
d6a7e54e
HP
2671 commit_t* commit = array_get(&(s->commits), i);
2672 if (commit->action == ACTION_RENAME) {
2673 mapping_t* mapping = find_mapping_for_cluster(s,
2674 commit->param.rename.cluster);
8d9401c2 2675 char *old_path;
d6a7e54e 2676
8d9401c2
LM
2677 if (mapping == NULL) {
2678 return -1;
2679 }
2680 old_path = mapping->path;
d6a7e54e
HP
2681 assert(commit->path);
2682 mapping->path = commit->path;
2683 if (rename(old_path, mapping->path))
2684 return -2;
2685
2686 if (mapping->mode & MODE_DIRECTORY) {
2687 int l1 = strlen(mapping->path);
2688 int l2 = strlen(old_path);
2689 int diff = l1 - l2;
2690 direntry_t* direntry = array_get(&(s->directory),
2691 mapping->info.dir.first_dir_index);
2692 uint32_t c = mapping->begin;
fb2575f9 2693 int j = 0;
d6a7e54e
HP
2694
2695 /* recurse */
2696 while (!fat_eof(s, c)) {
2697 do {
fb2575f9 2698 direntry_t *d = direntry + j;
d6a7e54e
HP
2699
2700 if (is_file(d) || (is_directory(d) && !is_dot(d))) {
8d9401c2
LM
2701 int l;
2702 char *new_path;
d6a7e54e
HP
2703 mapping_t* m = find_mapping_for_cluster(s,
2704 begin_of_direntry(d));
8d9401c2
LM
2705 if (m == NULL) {
2706 return -1;
2707 }
2708 l = strlen(m->path);
2709 new_path = g_malloc(l + diff + 1);
d6a7e54e
HP
2710
2711 assert(!strncmp(m->path, mapping->path, l2));
a046433a 2712
363a37d5
BS
2713 pstrcpy(new_path, l + diff + 1, mapping->path);
2714 pstrcpy(new_path + l1, l + diff + 1 - l1,
2715 m->path + l2);
a046433a 2716
d6a7e54e
HP
2717 schedule_rename(s, m->begin, new_path);
2718 }
fb2575f9
MA
2719 j++;
2720 } while (j % (0x10 * s->sectors_per_cluster) != 0);
d6a7e54e
HP
2721 c = fat_get(s, c);
2722 }
2723 }
de167e41 2724
ce137829 2725 g_free(old_path);
d6a7e54e
HP
2726 array_remove(&(s->commits), i);
2727 continue;
2728 } else if (commit->action == ACTION_MKDIR) {
2729 mapping_t* mapping;
2730 int j, parent_path_len;
a046433a 2731
c2632994 2732 if (g_mkdir(commit->path, 0755)) {
48c2f068 2733 return -5;
c2632994 2734 }
a046433a 2735
d6a7e54e
HP
2736 mapping = insert_mapping(s, commit->param.mkdir.cluster,
2737 commit->param.mkdir.cluster + 1);
2738 if (mapping == NULL)
2739 return -6;
2740
2741 mapping->mode = MODE_DIRECTORY;
2742 mapping->read_only = 0;
2743 mapping->path = commit->path;
2744 j = s->directory.next;
2745 assert(j);
2746 insert_direntries(s, s->directory.next,
2747 0x10 * s->sectors_per_cluster);
2748 mapping->info.dir.first_dir_index = j;
2749
2750 parent_path_len = strlen(commit->path)
2751 - strlen(get_basename(commit->path)) - 1;
2752 for (j = 0; j < s->mapping.next; j++) {
2753 mapping_t* m = array_get(&(s->mapping), j);
2754 if (m->first_mapping_index < 0 && m != mapping &&
2755 !strncmp(m->path, mapping->path, parent_path_len) &&
2756 strlen(m->path) == parent_path_len)
2757 break;
2758 }
2759 assert(j < s->mapping.next);
2760 mapping->info.dir.parent_mapping_index = j;
2761
2762 array_remove(&(s->commits), i);
2763 continue;
2764 }
2765
2766 i++;
a046433a
FB
2767 }
2768 return 0;
2769}
2770
2771/*
2772 * TODO: make sure that the short name is not matching *another* file
2773 */
eab76d58 2774static int coroutine_fn GRAPH_RDLOCK handle_commits(BDRVVVFATState* s)
a046433a
FB
2775{
2776 int i, fail = 0;
2777
2778 vvfat_close_current_file(s);
2779
2780 for (i = 0; !fail && i < s->commits.next; i++) {
d6a7e54e
HP
2781 commit_t* commit = array_get(&(s->commits), i);
2782 switch(commit->action) {
2783 case ACTION_RENAME: case ACTION_MKDIR:
43dc2a64 2784 abort();
d6a7e54e
HP
2785 fail = -2;
2786 break;
2787 case ACTION_WRITEOUT: {
d6a7e54e
HP
2788 direntry_t* entry = array_get(&(s->directory),
2789 commit->param.writeout.dir_index);
2790 uint32_t begin = begin_of_direntry(entry);
2791 mapping_t* mapping = find_mapping_for_cluster(s, begin);
a046433a 2792
d6a7e54e
HP
2793 assert(mapping);
2794 assert(mapping->begin == begin);
2795 assert(commit->path == NULL);
2796
2797 if (commit_one_file(s, commit->param.writeout.dir_index,
2798 commit->param.writeout.modified_offset))
2799 fail = -3;
2800
2801 break;
2802 }
2803 case ACTION_NEW_FILE: {
2804 int begin = commit->param.new_file.first_cluster;
2805 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2806 direntry_t* entry;
fb2575f9 2807 int j;
d6a7e54e
HP
2808
2809 /* find direntry */
fb2575f9
MA
2810 for (j = 0; j < s->directory.next; j++) {
2811 entry = array_get(&(s->directory), j);
d6a7e54e
HP
2812 if (is_file(entry) && begin_of_direntry(entry) == begin)
2813 break;
2814 }
2815
fb2575f9 2816 if (j >= s->directory.next) {
d6a7e54e
HP
2817 fail = -6;
2818 continue;
2819 }
2820
2821 /* make sure there exists an initial mapping */
2822 if (mapping && mapping->begin != begin) {
2823 mapping->end = begin;
2824 mapping = NULL;
2825 }
2826 if (mapping == NULL) {
2827 mapping = insert_mapping(s, begin, begin+1);
2828 }
2829 /* most members will be fixed in commit_mappings() */
2830 assert(commit->path);
2831 mapping->path = commit->path;
2832 mapping->read_only = 0;
2833 mapping->mode = MODE_NORMAL;
2834 mapping->info.file.offset = 0;
2835
fb2575f9 2836 if (commit_one_file(s, j, 0)) {
d6a7e54e 2837 fail = -7;
fb2575f9 2838 }
d6a7e54e
HP
2839
2840 break;
2841 }
2842 default:
43dc2a64 2843 abort();
d6a7e54e 2844 }
a046433a
FB
2845 }
2846 if (i > 0 && array_remove_slice(&(s->commits), 0, i))
d6a7e54e 2847 return -1;
a046433a
FB
2848 return fail;
2849}
2850
2851static int handle_deletes(BDRVVVFATState* s)
2852{
2853 int i, deferred = 1, deleted = 1;
2854
2855 /* delete files corresponding to mappings marked as deleted */
2856 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2857 while (deferred && deleted) {
d6a7e54e
HP
2858 deferred = 0;
2859 deleted = 0;
2860
2861 for (i = 1; i < s->mapping.next; i++) {
2862 mapping_t* mapping = array_get(&(s->mapping), i);
2863 if (mapping->mode & MODE_DELETED) {
2864 direntry_t* entry = array_get(&(s->directory),
2865 mapping->dir_index);
2866
2867 if (is_free(entry)) {
2868 /* remove file/directory */
2869 if (mapping->mode & MODE_DIRECTORY) {
2870 int j, next_dir_index = s->directory.next,
2871 first_dir_index = mapping->info.dir.first_dir_index;
2872
2873 if (rmdir(mapping->path) < 0) {
2874 if (errno == ENOTEMPTY) {
2875 deferred++;
2876 continue;
2877 } else
2878 return -5;
2879 }
2880
2881 for (j = 1; j < s->mapping.next; j++) {
2882 mapping_t* m = array_get(&(s->mapping), j);
2883 if (m->mode & MODE_DIRECTORY &&
2884 m->info.dir.first_dir_index >
2885 first_dir_index &&
2886 m->info.dir.first_dir_index <
2887 next_dir_index)
2888 next_dir_index =
2889 m->info.dir.first_dir_index;
2890 }
2891 remove_direntries(s, first_dir_index,
2892 next_dir_index - first_dir_index);
2893
2894 deleted++;
2895 }
2896 } else {
2897 if (unlink(mapping->path))
2898 return -4;
2899 deleted++;
2900 }
2901 DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2902 remove_mapping(s, i);
2903 }
2904 }
de167e41 2905 }
a046433a
FB
2906
2907 return 0;
2908}
2909
2910/*
2911 * synchronize mapping with new state:
2912 *
f4649069 2913 * - copy FAT (with bdrv_pread)
a046433a 2914 * - mark all filenames corresponding to mappings as deleted
f4649069 2915 * - recurse direntries from root (using bs->bdrv_pread)
a046433a
FB
2916 * - delete files corresponding to mappings marked as deleted
2917 */
eab76d58 2918static int coroutine_fn GRAPH_RDLOCK do_commit(BDRVVVFATState* s)
a046433a
FB
2919{
2920 int ret = 0;
2921
2922 /* the real meat are the commits. Nothing to do? Move along! */
2923 if (s->commits.next == 0)
d6a7e54e 2924 return 0;
a046433a
FB
2925
2926 vvfat_close_current_file(s);
2927
2928 ret = handle_renames_and_mkdirs(s);
2929 if (ret) {
d6a7e54e 2930 fprintf(stderr, "Error handling renames (%d)\n", ret);
43dc2a64 2931 abort();
d6a7e54e 2932 return ret;
a046433a
FB
2933 }
2934
f4649069 2935 /* copy FAT (with bdrv_pread) */
a046433a
FB
2936 memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2937
f4649069 2938 /* recurse direntries from root (using bs->bdrv_pread) */
a046433a
FB
2939 ret = commit_direntries(s, 0, -1);
2940 if (ret) {
d6a7e54e 2941 fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
43dc2a64 2942 abort();
d6a7e54e 2943 return ret;
a046433a
FB
2944 }
2945
2946 ret = handle_commits(s);
2947 if (ret) {
d6a7e54e 2948 fprintf(stderr, "Error handling commits (%d)\n", ret);
43dc2a64 2949 abort();
d6a7e54e 2950 return ret;
a046433a
FB
2951 }
2952
2953 ret = handle_deletes(s);
2954 if (ret) {
d6a7e54e 2955 fprintf(stderr, "Error deleting\n");
43dc2a64 2956 abort();
d6a7e54e 2957 return ret;
a046433a
FB
2958 }
2959
f844ec01 2960 bdrv_make_empty(s->qcow, NULL);
a046433a
FB
2961
2962 memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2963
2964DLOG(checkpoint());
2965 return 0;
2966}
2967
eab76d58 2968static int coroutine_fn GRAPH_RDLOCK try_commit(BDRVVVFATState* s)
a046433a
FB
2969{
2970 vvfat_close_current_file(s);
2971DLOG(checkpoint());
2972 if(!is_consistent(s))
d6a7e54e 2973 return -1;
a046433a
FB
2974 return do_commit(s);
2975}
2976
eab76d58
PB
2977static int coroutine_fn GRAPH_RDLOCK
2978vvfat_write(BlockDriverState *bs, int64_t sector_num,
2979 const uint8_t *buf, int nb_sectors)
a046433a 2980{
5fafdf24 2981 BDRVVVFATState *s = bs->opaque;
a046433a 2982 int i, ret;
b9b8860d 2983 int first_cluster, last_cluster;
a046433a
FB
2984
2985DLOG(checkpoint());
2986
ac48e389
KW
2987 /* Check if we're operating in read-only mode */
2988 if (s->qcow == NULL) {
2989 return -EACCES;
2990 }
2991
a046433a
FB
2992 vvfat_close_current_file(s);
2993
d0f95b6c
HP
2994 if (sector_num == s->offset_to_bootsector && nb_sectors == 1) {
2995 /*
2996 * Write on bootsector. Allow only changing the reserved1 field,
2997 * used to mark volume dirtiness
2998 */
2999 unsigned char *bootsector = s->first_sectors
3000 + s->offset_to_bootsector * 0x200;
3001 /*
3002 * LATER TODO: if FAT32, this is wrong (see init_directories(),
3003 * which always creates a FAT16 bootsector)
3004 */
3005 const int reserved1_offset = offsetof(bootsector_t, u.fat16.reserved1);
3006
3007 for (i = 0; i < 0x200; i++) {
3008 if (i != reserved1_offset && bootsector[i] != buf[i]) {
3009 fprintf(stderr, "Tried to write to protected bootsector\n");
3010 return -1;
3011 }
3012 }
3013
3014 /* Update bootsector with the only updatable byte, and return success */
3015 bootsector[reserved1_offset] = buf[reserved1_offset];
3016 return 0;
3017 }
3018
a046433a
FB
3019 /*
3020 * Some sanity checks:
3021 * - do not allow writing to the boot sector
a046433a 3022 */
4dc705dc 3023 if (sector_num < s->offset_to_fat)
d6a7e54e 3024 return -1;
a046433a 3025
b9b8860d
KW
3026 /*
3027 * Values will be negative for writes to the FAT, which is located before
3028 * the root directory.
3029 */
3030 first_cluster = sector2cluster(s, sector_num);
3031 last_cluster = sector2cluster(s, sector_num + nb_sectors - 1);
3032
3033 for (i = first_cluster; i <= last_cluster;) {
3034 mapping_t *mapping = NULL;
3035
3036 if (i >= 0) {
3037 mapping = find_mapping_for_cluster(s, i);
3038 }
3039
d6a7e54e
HP
3040 if (mapping) {
3041 if (mapping->read_only) {
3042 fprintf(stderr, "Tried to write to write-protected file %s\n",
3043 mapping->path);
3044 return -1;
3045 }
3046
3047 if (mapping->mode & MODE_DIRECTORY) {
3048 int begin = cluster2sector(s, i);
3049 int end = begin + s->sectors_per_cluster, k;
3050 int dir_index;
3051 const direntry_t* direntries;
3052 long_file_name lfn;
3053
3054 lfn_init(&lfn);
3055
3056 if (begin < sector_num)
3057 begin = sector_num;
3058 if (end > sector_num + nb_sectors)
3059 end = sector_num + nb_sectors;
3060 dir_index = mapping->dir_index +
3061 0x10 * (begin - mapping->begin * s->sectors_per_cluster);
3062 direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
3063
3064 for (k = 0; k < (end - begin) * 0x10; k++) {
d6a7e54e 3065 /* no access to the direntry of a read-only file */
e03da26b 3066 if (is_short_name(direntries + k) &&
d6a7e54e
HP
3067 (direntries[k].attributes & 1)) {
3068 if (memcmp(direntries + k,
3069 array_get(&(s->directory), dir_index + k),
3070 sizeof(direntry_t))) {
2ab4b135
AF
3071 warn_report("tried to write to write-protected "
3072 "file");
d6a7e54e
HP
3073 return -1;
3074 }
3075 }
3076 }
3077 }
3078 i = mapping->end;
b9b8860d 3079 } else {
d6a7e54e 3080 i++;
b9b8860d 3081 }
a046433a
FB
3082 }
3083
3084 /*
3085 * Use qcow backend. Commit later.
3086 */
3087DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
eab76d58
PB
3088 ret = bdrv_co_pwrite(s->qcow, sector_num * BDRV_SECTOR_SIZE,
3089 nb_sectors * BDRV_SECTOR_SIZE, buf, 0);
a046433a 3090 if (ret < 0) {
d6a7e54e
HP
3091 fprintf(stderr, "Error writing to qcow backend\n");
3092 return ret;
a046433a
FB
3093 }
3094
b9b8860d
KW
3095 for (i = first_cluster; i <= last_cluster; i++) {
3096 if (i >= 0) {
d6a7e54e 3097 s->used_clusters[i] |= USED_ALLOCATED;
b9b8860d
KW
3098 }
3099 }
a046433a
FB
3100
3101DLOG(checkpoint());
3102 /* TODO: add timeout */
3103 try_commit(s);
3104
3105DLOG(checkpoint());
3106 return 0;
3107}
3108
eab76d58 3109static int coroutine_fn GRAPH_RDLOCK
e75abeda
VSO
3110vvfat_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
3111 QEMUIOVector *qiov, BdrvRequestFlags flags)
e183ef75
PB
3112{
3113 int ret;
3114 BDRVVVFATState *s = bs->opaque;
4575eb49
KW
3115 uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
3116 int nb_sectors = bytes >> BDRV_SECTOR_BITS;
3117 void *buf;
3118
1bbbf32d
NS
3119 assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE));
3120 assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE));
4575eb49
KW
3121
3122 buf = g_try_malloc(bytes);
3123 if (bytes && buf == NULL) {
3124 return -ENOMEM;
3125 }
3126 qemu_iovec_to_buf(qiov, 0, buf, bytes);
3127
e183ef75
PB
3128 qemu_co_mutex_lock(&s->lock);
3129 ret = vvfat_write(bs, sector_num, buf, nb_sectors);
3130 qemu_co_mutex_unlock(&s->lock);
4575eb49
KW
3131
3132 g_free(buf);
3133
e183ef75
PB
3134 return ret;
3135}
3136
fba3998d
EB
3137static int coroutine_fn vvfat_co_block_status(BlockDriverState *bs,
3138 bool want_zero, int64_t offset,
3139 int64_t bytes, int64_t *n,
3140 int64_t *map,
3141 BlockDriverState **file)
a046433a 3142{
fba3998d 3143 *n = bytes;
4bc74be9 3144 return BDRV_BLOCK_DATA;
a046433a
FB
3145}
3146
3cdc69d3 3147static void vvfat_qcow_options(BdrvChildRole role, bool parent_is_format,
272c02ea 3148 int *child_flags, QDict *child_options,
eecc7747 3149 int parent_flags, QDict *parent_options)
a046433a 3150{
f87a0e29 3151 qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off");
e35bdc12 3152 qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off");
4f8e3a1f 3153 qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on");
eecc7747
KW
3154}
3155
8081f064 3156static BdrvChildClass child_vvfat_qcow;
eecc7747
KW
3157
3158static int enable_write_target(BlockDriverState *bs, Error **errp)
3159{
3160 BDRVVVFATState *s = bs->opaque;
facdbb02 3161 BlockDriver *bdrv_qcow = NULL;
facdbb02 3162 QemuOpts *opts = NULL;
a655211a 3163 int ret;
a046433a 3164 int size = sector2cluster(s, s->sector_count);
e6641719
HR
3165 QDict *options;
3166
22c36b75 3167 s->used_clusters = g_malloc0(size);
a046433a 3168
c227f099 3169 array_init(&(s->commits), sizeof(commit_t));
a046433a 3170
69fbfff9
BM
3171 s->qcow_filename = create_tmp_file(errp);
3172 if (!s->qcow_filename) {
3173 ret = -ENOENT;
78f27bd0 3174 goto err;
eba25057 3175 }
91a073a9
KW
3176
3177 bdrv_qcow = bdrv_find_format("qcow");
1bcb15cf
HR
3178 if (!bdrv_qcow) {
3179 error_setg(errp, "Failed to locate qcow driver");
3180 ret = -ENOENT;
3181 goto err;
3182 }
3183
c282e1fd 3184 opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort);
2db9b9e9
KW
3185 qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
3186 bs->total_sectors * BDRV_SECTOR_SIZE, &error_abort);
f43e47db 3187 qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:", &error_abort);
91a073a9 3188
c282e1fd 3189 ret = bdrv_create(bdrv_qcow, s->qcow_filename, opts, errp);
facdbb02 3190 qemu_opts_del(opts);
78f27bd0
FZ
3191 if (ret < 0) {
3192 goto err;
3193 }
a655211a 3194
e6641719 3195 options = qdict_new();
46f5ac20 3196 qdict_put_str(options, "write-target.driver", "qcow");
eecc7747 3197 s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs,
1f38f04e
HR
3198 &child_vvfat_qcow,
3199 BDRV_CHILD_DATA | BDRV_CHILD_METADATA,
3200 false, errp);
cb3e7f08 3201 qobject_unref(options);
5b363937
HR
3202 if (!s->qcow) {
3203 ret = -EINVAL;
78f27bd0 3204 goto err;
d6e9098e 3205 }
a046433a
FB
3206
3207#ifndef _WIN32
3208 unlink(s->qcow_filename);
3209#endif
3210
de167e41 3211 return 0;
78f27bd0
FZ
3212
3213err:
78f27bd0 3214 return ret;
de167e41
FB
3215}
3216
91ef3825 3217static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c,
bf8e925e 3218 BdrvChildRole role,
e0995dc3 3219 BlockReopenQueue *reopen_queue,
91ef3825
KW
3220 uint64_t perm, uint64_t shared,
3221 uint64_t *nperm, uint64_t *nshared)
3222{
6af72274
VSO
3223 assert(role & BDRV_CHILD_DATA);
3224 /* This is a private node, nobody should try to attach to it */
3225 *nperm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE;
3226 *nshared = BLK_PERM_WRITE_UNCHANGED;
91ef3825
KW
3227}
3228
de167e41
FB
3229static void vvfat_close(BlockDriverState *bs)
3230{
3231 BDRVVVFATState *s = bs->opaque;
3232
3233 vvfat_close_current_file(s);
3234 array_free(&(s->fat));
3235 array_free(&(s->directory));
3236 array_free(&(s->mapping));
ce137829 3237 g_free(s->cluster_buffer);
3397f0cb
KW
3238
3239 if (s->qcow) {
3240 migrate_del_blocker(s->migration_blocker);
3241 error_free(s->migration_blocker);
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