]> git.proxmox.com Git - mirror_qemu.git/blame - block/vvfat.c
hw/misc/mos6522: Convert TYPE_MOS6522 to 3-phase reset
[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"
737e150e 30#include "block/block_int.h"
609f45ea 31#include "block/qdict.h"
1de7afc9 32#include "qemu/module.h"
922a01a0 33#include "qemu/option.h"
58369e22 34#include "qemu/bswap.h"
795c40b8 35#include "migration/blocker.h"
452fcdbc 36#include "qapi/qmp/qdict.h"
d49b6836 37#include "qapi/qmp/qstring.h"
856dfd8a 38#include "qemu/ctype.h"
f348b6d1 39#include "qemu/cutils.h"
2ab4b135 40#include "qemu/error-report.h"
de167e41 41
a046433a
FB
42#ifndef S_IWGRP
43#define S_IWGRP 0
44#endif
45#ifndef S_IWOTH
46#define S_IWOTH 0
47#endif
48
49/* TODO: add ":bootsector=blabla.img:" */
50/* LATER TODO: add automatic boot sector generation from
51 BOOTEASY.ASM and Ranish Partition Manager
5fafdf24 52 Note that DOS assumes the system files to be the first files in the
a046433a
FB
53 file system (test if the boot sector still relies on that fact)! */
54/* MAYBE TODO: write block-visofs.c */
55/* TODO: call try_commit() only after a timeout */
56
57/* #define DEBUG */
58
59#ifdef DEBUG
60
61#define DLOG(a) a
62
3f47aa8c 63static void checkpoint(void);
de167e41 64
a046433a
FB
65#else
66
67#define DLOG(a)
68
69#endif
de167e41 70
63d261cb
HP
71/* bootsector OEM name. see related compatibility problems at:
72 * https://jdebp.eu/FGA/volume-boot-block-oem-name-field.html
73 * http://seasip.info/Misc/oemid.html
74 */
75#define BOOTSECTOR_OEM_NAME "MSWIN4.1"
76
8c4517fd
HP
77#define DIR_DELETED 0xe5
78#define DIR_KANJI DIR_DELETED
79#define DIR_KANJI_FAKE 0x05
80#define DIR_FREE 0x00
81
de167e41 82/* dynamic array functions */
c227f099 83typedef struct array_t {
de167e41
FB
84 char* pointer;
85 unsigned int size,next,item_size;
c227f099 86} array_t;
de167e41 87
c227f099 88static inline void array_init(array_t* array,unsigned int item_size)
de167e41 89{
511d2b14 90 array->pointer = NULL;
de167e41
FB
91 array->size=0;
92 array->next=0;
93 array->item_size=item_size;
94}
95
c227f099 96static inline void array_free(array_t* array)
de167e41 97{
ce137829 98 g_free(array->pointer);
de167e41
FB
99 array->size=array->next=0;
100}
101
a046433a 102/* does not automatically grow */
c227f099 103static inline void* array_get(array_t* array,unsigned int index) {
a046433a 104 assert(index < array->next);
8d9401c2 105 assert(array->pointer);
a046433a
FB
106 return array->pointer + index * array->item_size;
107}
108
8d9401c2 109static inline void array_ensure_allocated(array_t *array, int index)
a046433a
FB
110{
111 if((index + 1) * array->item_size > array->size) {
d6a7e54e
HP
112 int new_size = (index + 32) * array->item_size;
113 array->pointer = g_realloc(array->pointer, new_size);
8d9401c2 114 assert(array->pointer);
f80256b7 115 memset(array->pointer + array->size, 0, new_size - array->size);
d6a7e54e
HP
116 array->size = new_size;
117 array->next = index + 1;
de167e41 118 }
de167e41
FB
119}
120
c227f099 121static inline void* array_get_next(array_t* array) {
a046433a 122 unsigned int next = array->next;
a046433a 123
8d9401c2 124 array_ensure_allocated(array, next);
a046433a 125 array->next = next + 1;
9be38598 126 return array_get(array, next);
de167e41
FB
127}
128
c227f099 129static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
de167e41 130 if((array->next+count)*array->item_size>array->size) {
d6a7e54e
HP
131 int increment=count*array->item_size;
132 array->pointer=g_realloc(array->pointer,array->size+increment);
133 if(!array->pointer)
511d2b14 134 return NULL;
d6a7e54e 135 array->size+=increment;
de167e41
FB
136 }
137 memmove(array->pointer+(index+count)*array->item_size,
d6a7e54e
HP
138 array->pointer+index*array->item_size,
139 (array->next-index)*array->item_size);
de167e41
FB
140 array->next+=count;
141 return array->pointer+index*array->item_size;
142}
143
c227f099 144static inline int array_remove_slice(array_t* array,int index, int count)
de167e41 145{
a046433a
FB
146 assert(index >=0);
147 assert(count > 0);
148 assert(index + count <= array->next);
3dfa23b9
KW
149
150 memmove(array->pointer + index * array->item_size,
151 array->pointer + (index + count) * array->item_size,
152 (array->next - index - count) * array->item_size);
153
a046433a 154 array->next -= count;
de167e41
FB
155 return 0;
156}
157
c227f099 158static int array_remove(array_t* array,int index)
a046433a
FB
159{
160 return array_remove_slice(array, index, 1);
161}
162
163/* return the index for a given member */
c227f099 164static int array_index(array_t* array, void* pointer)
a046433a
FB
165{
166 size_t offset = (char*)pointer - array->pointer;
a046433a
FB
167 assert((offset % array->item_size) == 0);
168 assert(offset/array->item_size < array->next);
169 return offset/array->item_size;
170}
171
de167e41 172/* These structures are used to fake a disk and the VFAT filesystem.
541dc0d4 173 * For this reason we need to use QEMU_PACKED. */
de167e41 174
c227f099 175typedef struct bootsector_t {
de167e41
FB
176 uint8_t jump[3];
177 uint8_t name[8];
178 uint16_t sector_size;
179 uint8_t sectors_per_cluster;
180 uint16_t reserved_sectors;
181 uint8_t number_of_fats;
182 uint16_t root_entries;
a046433a 183 uint16_t total_sectors16;
de167e41
FB
184 uint8_t media_type;
185 uint16_t sectors_per_fat;
186 uint16_t sectors_per_track;
187 uint16_t number_of_heads;
188 uint32_t hidden_sectors;
189 uint32_t total_sectors;
190 union {
191 struct {
d6a7e54e 192 uint8_t drive_number;
92e28d82 193 uint8_t reserved1;
d6a7e54e
HP
194 uint8_t signature;
195 uint32_t id;
196 uint8_t volume_label[11];
92e28d82
HP
197 uint8_t fat_type[8];
198 uint8_t ignored[0x1c0];
d6a7e54e
HP
199 } QEMU_PACKED fat16;
200 struct {
201 uint32_t sectors_per_fat;
202 uint16_t flags;
203 uint8_t major,minor;
92e28d82 204 uint32_t first_cluster_of_root_dir;
d6a7e54e
HP
205 uint16_t info_sector;
206 uint16_t backup_boot_sector;
92e28d82
HP
207 uint8_t reserved[12];
208 uint8_t drive_number;
209 uint8_t reserved1;
210 uint8_t signature;
211 uint32_t id;
212 uint8_t volume_label[11];
213 uint8_t fat_type[8];
214 uint8_t ignored[0x1a4];
d6a7e54e 215 } QEMU_PACKED fat32;
de167e41 216 } u;
de167e41 217 uint8_t magic[2];
541dc0d4 218} QEMU_PACKED bootsector_t;
de167e41 219
b570094d
TS
220typedef struct {
221 uint8_t head;
222 uint8_t sector;
223 uint8_t cylinder;
c227f099 224} mbr_chs_t;
b570094d 225
c227f099 226typedef struct partition_t {
de167e41 227 uint8_t attributes; /* 0x80 = bootable */
c227f099 228 mbr_chs_t start_CHS;
b570094d 229 uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
c227f099 230 mbr_chs_t end_CHS;
de167e41 231 uint32_t start_sector_long;
b570094d 232 uint32_t length_sector_long;
541dc0d4 233} QEMU_PACKED partition_t;
de167e41 234
c227f099 235typedef struct mbr_t {
b570094d
TS
236 uint8_t ignored[0x1b8];
237 uint32_t nt_id;
238 uint8_t ignored2[2];
c227f099 239 partition_t partition[4];
de167e41 240 uint8_t magic[2];
541dc0d4 241} QEMU_PACKED mbr_t;
de167e41 242
c227f099 243typedef struct direntry_t {
f671d173 244 uint8_t name[8 + 3];
de167e41
FB
245 uint8_t attributes;
246 uint8_t reserved[2];
247 uint16_t ctime;
248 uint16_t cdate;
249 uint16_t adate;
250 uint16_t begin_hi;
251 uint16_t mtime;
252 uint16_t mdate;
253 uint16_t begin;
254 uint32_t size;
541dc0d4 255} QEMU_PACKED direntry_t;
de167e41
FB
256
257/* this structure are used to transparently access the files */
258
c227f099 259typedef struct mapping_t {
a046433a
FB
260 /* begin is the first cluster, end is the last+1 */
261 uint32_t begin,end;
de167e41
FB
262 /* as s->directory is growable, no pointer may be used here */
263 unsigned int dir_index;
a046433a
FB
264 /* the clusters of a file may be in any order; this points to the first */
265 int first_mapping_index;
266 union {
d6a7e54e
HP
267 /* offset is
268 * - the offset in the file (in clusters) for a file, or
ad05b318 269 * - the next cluster of the directory for a directory
d6a7e54e
HP
270 */
271 struct {
272 uint32_t offset;
273 } file;
274 struct {
275 int parent_mapping_index;
276 int first_dir_index;
277 } dir;
a046433a
FB
278 } info;
279 /* path contains the full path, i.e. it always starts with s->path */
280 char* path;
281
ad05b318
HP
282 enum {
283 MODE_UNDEFINED = 0,
284 MODE_NORMAL = 1,
285 MODE_MODIFIED = 2,
286 MODE_DIRECTORY = 4,
287 MODE_DELETED = 8,
288 } mode;
a046433a 289 int read_only;
c227f099 290} mapping_t;
de167e41 291
a046433a 292#ifdef DEBUG
c227f099
AL
293static void print_direntry(const struct direntry_t*);
294static void print_mapping(const struct mapping_t* mapping);
a046433a 295#endif
de167e41
FB
296
297/* here begins the real VVFAT driver */
298
299typedef struct BDRVVVFATState {
848c66e8 300 CoMutex lock;
a046433a 301 BlockDriverState* bs; /* pointer to parent */
de167e41 302 unsigned char first_sectors[0x40*0x200];
3b46e624 303
de167e41 304 int fat_type; /* 16 or 32 */
c227f099 305 array_t fat,directory,mapping;
d5941dda 306 char volume_label[11];
3b46e624 307
4dc705dc
HP
308 uint32_t offset_to_bootsector; /* 0 for floppy, 0x3f for disk */
309
de167e41
FB
310 unsigned int cluster_size;
311 unsigned int sectors_per_cluster;
312 unsigned int sectors_per_fat;
a046433a 313 uint32_t last_cluster_of_root_directory;
6817efea
HP
314 /* how many entries are available in root directory (0 for FAT32) */
315 uint16_t root_entries;
de167e41
FB
316 uint32_t sector_count; /* total number of sectors of the partition */
317 uint32_t cluster_count; /* total number of clusters of this partition */
de167e41 318 uint32_t max_fat_value;
4dc705dc
HP
319 uint32_t offset_to_fat;
320 uint32_t offset_to_root_dir;
3b46e624 321
de167e41 322 int current_fd;
c227f099 323 mapping_t* current_mapping;
a046433a
FB
324 unsigned char* cluster; /* points to current cluster */
325 unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
de167e41
FB
326 unsigned int current_cluster;
327
328 /* write support */
a046433a 329 char* qcow_filename;
eecc7747 330 BdrvChild* qcow;
a046433a
FB
331 void* fat2;
332 char* used_clusters;
c227f099 333 array_t commits;
a046433a
FB
334 const char* path;
335 int downcase_short_names;
3397f0cb
KW
336
337 Error *migration_blocker;
de167e41
FB
338} BDRVVVFATState;
339
b570094d
TS
340/* take the sector position spos and convert it to Cylinder/Head/Sector position
341 * if the position is outside the specified geometry, fill maximum value for CHS
342 * and return 1 to signal overflow.
343 */
4480e0f9
MA
344static int sector2CHS(mbr_chs_t *chs, int spos, int cyls, int heads, int secs)
345{
b570094d 346 int head,sector;
4480e0f9
MA
347 sector = spos % secs; spos /= secs;
348 head = spos % heads; spos /= heads;
349 if (spos >= cyls) {
b570094d
TS
350 /* Overflow,
351 it happens if 32bit sector positions are used, while CHS is only 24bit.
352 Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
353 chs->head = 0xFF;
354 chs->sector = 0xFF;
355 chs->cylinder = 0xFF;
356 return 1;
357 }
358 chs->head = (uint8_t)head;
359 chs->sector = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
360 chs->cylinder = (uint8_t)spos;
361 return 0;
362}
de167e41 363
4480e0f9 364static void init_mbr(BDRVVVFATState *s, int cyls, int heads, int secs)
de167e41
FB
365{
366 /* TODO: if the files mbr.img and bootsect.img exist, use them */
c227f099
AL
367 mbr_t* real_mbr=(mbr_t*)s->first_sectors;
368 partition_t* partition = &(real_mbr->partition[0]);
b570094d 369 int lba;
de167e41
FB
370
371 memset(s->first_sectors,0,512);
3b46e624 372
b570094d
TS
373 /* Win NT Disk Signature */
374 real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
375
de167e41 376 partition->attributes=0x80; /* bootable */
b570094d
TS
377
378 /* LBA is used when partition is outside the CHS geometry */
4dc705dc 379 lba = sector2CHS(&partition->start_CHS, s->offset_to_bootsector,
4480e0f9
MA
380 cyls, heads, secs);
381 lba |= sector2CHS(&partition->end_CHS, s->bs->total_sectors - 1,
382 cyls, heads, secs);
b570094d
TS
383
384 /*LBA partitions are identified only by start/length_sector_long not by CHS*/
4dc705dc 385 partition->start_sector_long = cpu_to_le32(s->offset_to_bootsector);
f91cbefe 386 partition->length_sector_long = cpu_to_le32(s->bs->total_sectors
4dc705dc 387 - s->offset_to_bootsector);
b570094d 388
a046433a 389 /* FAT12/FAT16/FAT32 */
b570094d
TS
390 /* DOS uses different types when partition is LBA,
391 probably to prevent older versions from using CHS on them */
5f5b29df
HP
392 partition->fs_type = s->fat_type == 12 ? 0x1 :
393 s->fat_type == 16 ? (lba ? 0xe : 0x06) :
394 /*s->fat_type == 32*/ (lba ? 0xc : 0x0b);
de167e41
FB
395
396 real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
397}
398
a046433a
FB
399/* direntry functions */
400
09ec4119 401static direntry_t *create_long_filename(BDRVVVFATState *s, const char *filename)
de167e41 402{
09ec4119
HP
403 int number_of_entries, i;
404 glong length;
405 direntry_t *entry;
406
407 gunichar2 *longname = g_utf8_to_utf16(filename, -1, NULL, &length, NULL);
408 if (!longname) {
409 fprintf(stderr, "vvfat: invalid UTF-8 name: %s\n", filename);
410 return NULL;
de167e41 411 }
de167e41 412
78ee96de 413 number_of_entries = DIV_ROUND_UP(length * 2, 26);
de167e41
FB
414
415 for(i=0;i<number_of_entries;i++) {
d6a7e54e
HP
416 entry=array_get_next(&(s->directory));
417 entry->attributes=0xf;
418 entry->reserved[0]=0;
419 entry->begin=0;
420 entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
de167e41 421 }
1e080d5d 422 for(i=0;i<26*number_of_entries;i++) {
d6a7e54e
HP
423 int offset=(i%26);
424 if(offset<10) offset=1+offset;
425 else if(offset<22) offset=14+offset-10;
426 else offset=28+offset-22;
427 entry=array_get(&(s->directory),s->directory.next-1-(i/26));
09ec4119
HP
428 if (i >= 2 * length + 2) {
429 entry->name[offset] = 0xff;
430 } else if (i % 2 == 0) {
431 entry->name[offset] = longname[i / 2] & 0xff;
432 } else {
433 entry->name[offset] = longname[i / 2] >> 8;
434 }
de167e41 435 }
09ec4119 436 g_free(longname);
de167e41
FB
437 return array_get(&(s->directory),s->directory.next-number_of_entries);
438}
439
c227f099 440static char is_free(const direntry_t* direntry)
a046433a 441{
8c4517fd 442 return direntry->name[0] == DIR_DELETED || direntry->name[0] == DIR_FREE;
a046433a
FB
443}
444
c227f099 445static char is_volume_label(const direntry_t* direntry)
a046433a
FB
446{
447 return direntry->attributes == 0x28;
448}
449
c227f099 450static char is_long_name(const direntry_t* direntry)
a046433a
FB
451{
452 return direntry->attributes == 0xf;
453}
454
c227f099 455static char is_short_name(const direntry_t* direntry)
a046433a
FB
456{
457 return !is_volume_label(direntry) && !is_long_name(direntry)
d6a7e54e 458 && !is_free(direntry);
a046433a
FB
459}
460
c227f099 461static char is_directory(const direntry_t* direntry)
a046433a 462{
8c4517fd 463 return direntry->attributes & 0x10 && direntry->name[0] != DIR_DELETED;
a046433a
FB
464}
465
c227f099 466static inline char is_dot(const direntry_t* direntry)
a046433a
FB
467{
468 return is_short_name(direntry) && direntry->name[0] == '.';
469}
470
c227f099 471static char is_file(const direntry_t* direntry)
a046433a
FB
472{
473 return is_short_name(direntry) && !is_directory(direntry);
474}
475
c227f099 476static inline uint32_t begin_of_direntry(const direntry_t* direntry)
a046433a
FB
477{
478 return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
479}
480
c227f099 481static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
a046433a
FB
482{
483 return le32_to_cpu(direntry->size);
484}
485
c227f099 486static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
a046433a
FB
487{
488 direntry->begin = cpu_to_le16(begin & 0xffff);
489 direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
490}
491
c79e243e
KW
492static bool valid_filename(const unsigned char *name)
493{
494 unsigned char c;
495 if (!strcmp((const char*)name, ".") || !strcmp((const char*)name, "..")) {
496 return false;
497 }
498 for (; (c = *name); name++) {
499 if (!((c >= '0' && c <= '9') ||
500 (c >= 'A' && c <= 'Z') ||
501 (c >= 'a' && c <= 'z') ||
502 c > 127 ||
1e85c725 503 strchr(" $%'-_@~`!(){}^#&.+,;=[]", c) != NULL))
c79e243e
KW
504 {
505 return false;
506 }
507 }
508 return true;
509}
510
0c36111f
HP
511static uint8_t to_valid_short_char(gunichar c)
512{
513 c = g_unichar_toupper(c);
514 if ((c >= '0' && c <= '9') ||
515 (c >= 'A' && c <= 'Z') ||
c79e243e 516 strchr("$%'-_@~`!(){}^#&", c) != NULL) {
0c36111f
HP
517 return c;
518 } else {
519 return 0;
520 }
521}
522
523static direntry_t *create_short_filename(BDRVVVFATState *s,
339cebcc
HP
524 const char *filename,
525 unsigned int directory_start)
0c36111f 526{
339cebcc 527 int i, j = 0;
0c36111f
HP
528 direntry_t *entry = array_get_next(&(s->directory));
529 const gchar *p, *last_dot = NULL;
530 gunichar c;
531 bool lossy_conversion = false;
7c8730d4 532 char tail[8];
0c36111f
HP
533
534 if (!entry) {
535 return NULL;
536 }
537 memset(entry->name, 0x20, sizeof(entry->name));
538
539 /* copy filename and search last dot */
540 for (p = filename; ; p = g_utf8_next_char(p)) {
541 c = g_utf8_get_char(p);
542 if (c == '\0') {
543 break;
544 } else if (c == '.') {
545 if (j == 0) {
546 /* '.' at start of filename */
547 lossy_conversion = true;
548 } else {
549 if (last_dot) {
550 lossy_conversion = true;
551 }
552 last_dot = p;
553 }
554 } else if (!last_dot) {
555 /* first part of the name; copy it */
556 uint8_t v = to_valid_short_char(c);
557 if (j < 8 && v) {
558 entry->name[j++] = v;
559 } else {
560 lossy_conversion = true;
561 }
562 }
563 }
564
565 /* copy extension (if any) */
566 if (last_dot) {
567 j = 0;
568 for (p = g_utf8_next_char(last_dot); ; p = g_utf8_next_char(p)) {
569 c = g_utf8_get_char(p);
570 if (c == '\0') {
571 break;
572 } else {
573 /* extension; copy it */
574 uint8_t v = to_valid_short_char(c);
575 if (j < 3 && v) {
576 entry->name[8 + (j++)] = v;
577 } else {
578 lossy_conversion = true;
579 }
580 }
581 }
582 }
339cebcc 583
8c4517fd
HP
584 if (entry->name[0] == DIR_KANJI) {
585 entry->name[0] = DIR_KANJI_FAKE;
78f002c9
HP
586 }
587
339cebcc
HP
588 /* numeric-tail generation */
589 for (j = 0; j < 8; j++) {
590 if (entry->name[j] == ' ') {
591 break;
592 }
593 }
594 for (i = lossy_conversion ? 1 : 0; i < 999999; i++) {
595 direntry_t *entry1;
596 if (i > 0) {
7c8730d4
HR
597 int len = snprintf(tail, sizeof(tail), "~%u", (unsigned)i);
598 assert(len <= 7);
339cebcc
HP
599 memcpy(entry->name + MIN(j, 8 - len), tail, len);
600 }
601 for (entry1 = array_get(&(s->directory), directory_start);
602 entry1 < entry; entry1++) {
603 if (!is_long_name(entry1) &&
604 !memcmp(entry1->name, entry->name, 11)) {
605 break; /* found dupe */
606 }
607 }
608 if (entry1 == entry) {
609 /* no dupe found */
610 return entry;
611 }
612 }
613 return NULL;
0c36111f
HP
614}
615
de167e41
FB
616/* fat functions */
617
c227f099 618static inline uint8_t fat_chksum(const direntry_t* entry)
de167e41
FB
619{
620 uint8_t chksum=0;
621 int i;
622
f671d173
SW
623 for (i = 0; i < ARRAY_SIZE(entry->name); i++) {
624 chksum = (((chksum & 0xfe) >> 1) |
625 ((chksum & 0x01) ? 0x80 : 0)) + entry->name[i];
5606c220 626 }
3b46e624 627
de167e41
FB
628 return chksum;
629}
630
631/* if return_time==0, this returns the fat_date, else the fat_time */
632static uint16_t fat_datetime(time_t time,int return_time) {
633 struct tm* t;
de167e41 634 struct tm t1;
6ab00cee 635 t = &t1;
de167e41 636 localtime_r(&time,t);
de167e41 637 if(return_time)
d6a7e54e 638 return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
de167e41
FB
639 return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
640}
641
642static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
643{
a046433a 644 if(s->fat_type==32) {
d6a7e54e
HP
645 uint32_t* entry=array_get(&(s->fat),cluster);
646 *entry=cpu_to_le32(value);
de167e41 647 } else if(s->fat_type==16) {
d6a7e54e
HP
648 uint16_t* entry=array_get(&(s->fat),cluster);
649 *entry=cpu_to_le16(value&0xffff);
de167e41 650 } else {
d6a7e54e
HP
651 int offset = (cluster*3/2);
652 unsigned char* p = array_get(&(s->fat), offset);
a046433a 653 switch (cluster&1) {
d6a7e54e
HP
654 case 0:
655 p[0] = value&0xff;
656 p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
657 break;
658 case 1:
659 p[0] = (p[0]&0xf) | ((value&0xf)<<4);
660 p[1] = (value>>4);
661 break;
662 }
de167e41
FB
663 }
664}
665
666static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
667{
a046433a 668 if(s->fat_type==32) {
d6a7e54e
HP
669 uint32_t* entry=array_get(&(s->fat),cluster);
670 return le32_to_cpu(*entry);
de167e41 671 } else if(s->fat_type==16) {
d6a7e54e
HP
672 uint16_t* entry=array_get(&(s->fat),cluster);
673 return le16_to_cpu(*entry);
de167e41 674 } else {
d6a7e54e
HP
675 const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
676 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
de167e41
FB
677 }
678}
679
680static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
681{
682 if(fat_entry>s->max_fat_value-8)
d6a7e54e 683 return -1;
de167e41
FB
684 return 0;
685}
686
687static inline void init_fat(BDRVVVFATState* s)
688{
a046433a 689 if (s->fat_type == 12) {
d6a7e54e
HP
690 array_init(&(s->fat),1);
691 array_ensure_allocated(&(s->fat),
692 s->sectors_per_fat * 0x200 * 3 / 2 - 1);
a046433a 693 } else {
d6a7e54e
HP
694 array_init(&(s->fat),(s->fat_type==32?4:2));
695 array_ensure_allocated(&(s->fat),
696 s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
a046433a 697 }
de167e41 698 memset(s->fat.pointer,0,s->fat.size);
3b46e624 699
de167e41 700 switch(s->fat_type) {
d6a7e54e
HP
701 case 12: s->max_fat_value=0xfff; break;
702 case 16: s->max_fat_value=0xffff; break;
703 case 32: s->max_fat_value=0x0fffffff; break;
704 default: s->max_fat_value=0; /* error... */
de167e41
FB
705 }
706
707}
708
c227f099 709static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
d6a7e54e 710 unsigned int directory_start, const char* filename, int is_dot)
de167e41 711{
0c36111f 712 int long_index = s->directory.next;
c227f099
AL
713 direntry_t* entry = NULL;
714 direntry_t* entry_long = NULL;
de167e41
FB
715
716 if(is_dot) {
d6a7e54e 717 entry=array_get_next(&(s->directory));
f671d173 718 memset(entry->name, 0x20, sizeof(entry->name));
d6a7e54e
HP
719 memcpy(entry->name,filename,strlen(filename));
720 return entry;
de167e41 721 }
3b46e624 722
de167e41 723 entry_long=create_long_filename(s,filename);
339cebcc 724 entry = create_short_filename(s, filename, directory_start);
de167e41
FB
725
726 /* calculate checksum; propagate to long name */
727 if(entry_long) {
728 uint8_t chksum=fat_chksum(entry);
729
d6a7e54e
HP
730 /* calculate anew, because realloc could have taken place */
731 entry_long=array_get(&(s->directory),long_index);
732 while(entry_long<entry && is_long_name(entry_long)) {
733 entry_long->reserved[1]=chksum;
734 entry_long++;
735 }
de167e41
FB
736 }
737
738 return entry;
739}
740
a046433a
FB
741/*
742 * Read a directory. (the index of the corresponding mapping must be passed).
743 */
744static int read_directory(BDRVVVFATState* s, int mapping_index)
de167e41 745{
c227f099
AL
746 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
747 direntry_t* direntry;
a046433a
FB
748 const char* dirname = mapping->path;
749 int first_cluster = mapping->begin;
750 int parent_index = mapping->info.dir.parent_mapping_index;
c227f099 751 mapping_t* parent_mapping = (mapping_t*)
511d2b14 752 (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL);
a046433a 753 int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
de167e41
FB
754
755 DIR* dir=opendir(dirname);
756 struct dirent* entry;
de167e41
FB
757 int i;
758
a046433a
FB
759 assert(mapping->mode & MODE_DIRECTORY);
760
761 if(!dir) {
d6a7e54e
HP
762 mapping->end = mapping->begin;
763 return -1;
a046433a 764 }
3b46e624 765
a046433a 766 i = mapping->info.dir.first_dir_index =
d6a7e54e 767 first_cluster == 0 ? 0 : s->directory.next;
a046433a 768
f82d92bb
HP
769 if (first_cluster != 0) {
770 /* create the top entries of a subdirectory */
771 (void)create_short_and_long_name(s, i, ".", 1);
772 (void)create_short_and_long_name(s, i, "..", 1);
773 }
774
5fafdf24 775 /* actually read the directory, and allocate the mappings */
de167e41 776 while((entry=readdir(dir))) {
d6a7e54e 777 unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
de167e41 778 char* buffer;
d6a7e54e 779 direntry_t* direntry;
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)) {
d6a7e54e
HP
859 direntry_t* direntry=array_get_next(&(s->directory));
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);
a046433a
FB
1055static int is_consistent(BDRVVVFATState *s);
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
5fafdf24 1471static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
a046433a 1472 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));
32cc71de
AF
1492 if (bdrv_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
4575eb49 1534static int coroutine_fn
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
6f712ee0
EB
1798static inline bool cluster_was_modified(BDRVVVFATState *s,
1799 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 */
1854static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
d6a7e54e 1855 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 */
1964 int64_t offset = cluster2sector(s, cluster_num);
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
EB
1970 res = bdrv_is_allocated(s->qcow->bs,
1971 (offset + i) * BDRV_SECTOR_SIZE,
1972 BDRV_SECTOR_SIZE, NULL);
6f712ee0
EB
1973 if (res < 0) {
1974 return -1;
1975 }
eecc7747
KW
1976 if (!res) {
1977 res = vvfat_read(s->bs, offset, s->cluster_buffer, 1);
1978 if (res) {
7704df98
KW
1979 return -1;
1980 }
e5a0a678 1981 res = bdrv_pwrite(s->qcow, offset * BDRV_SECTOR_SIZE,
32cc71de 1982 BDRV_SECTOR_SIZE, s->cluster_buffer,
53fb7844 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 */
2013static int check_directory_consistency(BDRVVVFATState *s,
d6a7e54e 2014 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 */
2140static int is_consistent(BDRVVVFATState* s)
2141{
2142 int i, check;
2143 int used_clusters_count = 0;
2144
2145DLOG(checkpoint());
2146 /*
2147 * - get modified FAT
2148 * - compare the two FATs (TODO)
2149 * - get buffer for marking used clusters
f4649069 2150 * - recurse direntries from root (using bs->bdrv_pread to make
a046433a
FB
2151 * sure to get the new data)
2152 * - check that the FAT agrees with the size
2153 * - count the number of clusters occupied by this directory and
2154 * its files
2155 * - check that the cumulative used cluster count agrees with the
2156 * FAT
2157 * - if all is fine, return number of used clusters
2158 */
2159 if (s->fat2 == NULL) {
d6a7e54e
HP
2160 int size = 0x200 * s->sectors_per_fat;
2161 s->fat2 = g_malloc(size);
2162 memcpy(s->fat2, s->fat.pointer, size);
a046433a
FB
2163 }
2164 check = vvfat_read(s->bs,
4dc705dc 2165 s->offset_to_fat, s->fat2, s->sectors_per_fat);
a046433a 2166 if (check) {
d6a7e54e
HP
2167 fprintf(stderr, "Could not copy fat\n");
2168 return 0;
a046433a
FB
2169 }
2170 assert (s->used_clusters);
2171 for (i = 0; i < sector2cluster(s, s->sector_count); i++)
d6a7e54e 2172 s->used_clusters[i] &= ~USED_ANY;
a046433a
FB
2173
2174 clear_commits(s);
2175
2176 /* mark every mapped file/directory as deleted.
2177 * (check_directory_consistency() will unmark those still present). */
2178 if (s->qcow)
d6a7e54e
HP
2179 for (i = 0; i < s->mapping.next; i++) {
2180 mapping_t* mapping = array_get(&(s->mapping), i);
2181 if (mapping->first_mapping_index < 0)
2182 mapping->mode |= MODE_DELETED;
2183 }
a046433a
FB
2184
2185 used_clusters_count = check_directory_consistency(s, 0, s->path);
2186 if (used_clusters_count <= 0) {
d6a7e54e
HP
2187 DLOG(fprintf(stderr, "problem in directory\n"));
2188 return 0;
de167e41
FB
2189 }
2190
a046433a
FB
2191 check = s->last_cluster_of_root_directory;
2192 for (i = check; i < sector2cluster(s, s->sector_count); i++) {
d6a7e54e
HP
2193 if (modified_fat_get(s, i)) {
2194 if(!s->used_clusters[i]) {
2195 DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
2196 return 0;
2197 }
2198 check++;
2199 }
a046433a 2200
d6a7e54e
HP
2201 if (s->used_clusters[i] == USED_ALLOCATED) {
2202 /* allocated, but not used... */
2203 DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
2204 return 0;
2205 }
a046433a
FB
2206 }
2207
2208 if (check != used_clusters_count)
d6a7e54e 2209 return 0;
a046433a
FB
2210
2211 return used_clusters_count;
2212}
2213
2214static inline void adjust_mapping_indices(BDRVVVFATState* s,
d6a7e54e 2215 int offset, int adjust)
a046433a
FB
2216{
2217 int i;
2218
2219 for (i = 0; i < s->mapping.next; i++) {
d6a7e54e 2220 mapping_t* mapping = array_get(&(s->mapping), i);
a046433a
FB
2221
2222#define ADJUST_MAPPING_INDEX(name) \
d6a7e54e
HP
2223 if (mapping->name >= offset) \
2224 mapping->name += adjust
a046433a 2225
d6a7e54e
HP
2226 ADJUST_MAPPING_INDEX(first_mapping_index);
2227 if (mapping->mode & MODE_DIRECTORY)
2228 ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
de167e41 2229 }
a046433a
FB
2230}
2231
2232/* insert or update mapping */
c227f099 2233static mapping_t* insert_mapping(BDRVVVFATState* s,
d6a7e54e 2234 uint32_t begin, uint32_t end)
a046433a
FB
2235{
2236 /*
2237 * - find mapping where mapping->begin >= begin,
2238 * - if mapping->begin > begin: insert
2239 * - adjust all references to mappings!
2240 * - else: adjust
2241 * - replace name
2242 */
2243 int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
c227f099
AL
2244 mapping_t* mapping = NULL;
2245 mapping_t* first_mapping = array_get(&(s->mapping), 0);
a046433a
FB
2246
2247 if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
d6a7e54e
HP
2248 && mapping->begin < begin) {
2249 mapping->end = begin;
2250 index++;
2251 mapping = array_get(&(s->mapping), index);
a046433a
FB
2252 }
2253 if (index >= s->mapping.next || mapping->begin > begin) {
d6a7e54e
HP
2254 mapping = array_insert(&(s->mapping), index, 1);
2255 mapping->path = NULL;
2256 adjust_mapping_indices(s, index, +1);
a046433a
FB
2257 }
2258
2259 mapping->begin = begin;
2260 mapping->end = end;
de167e41 2261
c227f099 2262DLOG(mapping_t* next_mapping;
a046433a
FB
2263assert(index + 1 >= s->mapping.next ||
2264((next_mapping = array_get(&(s->mapping), index + 1)) &&
2265 next_mapping->begin >= end)));
2266
c227f099 2267 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
d6a7e54e
HP
2268 s->current_mapping = array_get(&(s->mapping),
2269 s->current_mapping - first_mapping);
a046433a
FB
2270
2271 return mapping;
2272}
2273
2274static int remove_mapping(BDRVVVFATState* s, int mapping_index)
2275{
c227f099
AL
2276 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
2277 mapping_t* first_mapping = array_get(&(s->mapping), 0);
a046433a
FB
2278
2279 /* free mapping */
ce137829
SW
2280 if (mapping->first_mapping_index < 0) {
2281 g_free(mapping->path);
2282 }
a046433a
FB
2283
2284 /* remove from s->mapping */
2285 array_remove(&(s->mapping), mapping_index);
2286
2287 /* adjust all references to mappings */
2288 adjust_mapping_indices(s, mapping_index, -1);
2289
c227f099 2290 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
d6a7e54e
HP
2291 s->current_mapping = array_get(&(s->mapping),
2292 s->current_mapping - first_mapping);
de167e41 2293
de167e41
FB
2294 return 0;
2295}
2296
a046433a
FB
2297static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
2298{
2299 int i;
2300 for (i = 0; i < s->mapping.next; i++) {
d6a7e54e
HP
2301 mapping_t* mapping = array_get(&(s->mapping), i);
2302 if (mapping->dir_index >= offset)
2303 mapping->dir_index += adjust;
2304 if ((mapping->mode & MODE_DIRECTORY) &&
2305 mapping->info.dir.first_dir_index >= offset)
2306 mapping->info.dir.first_dir_index += adjust;
a046433a
FB
2307 }
2308}
de167e41 2309
c227f099 2310static direntry_t* insert_direntries(BDRVVVFATState* s,
d6a7e54e 2311 int dir_index, int count)
de167e41 2312{
a046433a
FB
2313 /*
2314 * make room in s->directory,
2315 * adjust_dirindices
2316 */
c227f099 2317 direntry_t* result = array_insert(&(s->directory), dir_index, count);
a046433a 2318 if (result == NULL)
d6a7e54e 2319 return NULL;
a046433a 2320 adjust_dirindices(s, dir_index, count);
de167e41
FB
2321 return result;
2322}
2323
a046433a
FB
2324static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
2325{
2326 int ret = array_remove_slice(&(s->directory), dir_index, count);
2327 if (ret)
d6a7e54e 2328 return ret;
a046433a
FB
2329 adjust_dirindices(s, dir_index, -count);
2330 return 0;
2331}
de167e41 2332
a046433a
FB
2333/*
2334 * Adapt the mappings of the cluster chain starting at first cluster
2335 * (i.e. if a file starts at first_cluster, the chain is followed according
2336 * to the modified fat, and the corresponding entries in s->mapping are
2337 * adjusted)
2338 */
2339static int commit_mappings(BDRVVVFATState* s,
d6a7e54e 2340 uint32_t first_cluster, int dir_index)
de167e41 2341{
c227f099
AL
2342 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2343 direntry_t* direntry = array_get(&(s->directory), dir_index);
a046433a
FB
2344 uint32_t cluster = first_cluster;
2345
2346 vvfat_close_current_file(s);
2347
2348 assert(mapping);
2349 assert(mapping->begin == first_cluster);
2350 mapping->first_mapping_index = -1;
2351 mapping->dir_index = dir_index;
2352 mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
d6a7e54e 2353 MODE_DIRECTORY : MODE_NORMAL;
a046433a
FB
2354
2355 while (!fat_eof(s, cluster)) {
d6a7e54e
HP
2356 uint32_t c, c1;
2357
2358 for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2359 c = c1, c1 = modified_fat_get(s, c1));
2360
2361 c++;
2362 if (c > mapping->end) {
2363 int index = array_index(&(s->mapping), mapping);
2364 int i, max_i = s->mapping.next - index;
2365 for (i = 1; i < max_i && mapping[i].begin < c; i++);
2366 while (--i > 0)
2367 remove_mapping(s, index + 1);
2368 }
2369 assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2370 || mapping[1].begin >= c);
2371 mapping->end = c;
2372
2373 if (!fat_eof(s, c1)) {
2374 int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2375 mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2376 array_get(&(s->mapping), i);
2377
2378 if (next_mapping == NULL || next_mapping->begin > c1) {
2379 int i1 = array_index(&(s->mapping), mapping);
2380
2381 next_mapping = insert_mapping(s, c1, c1+1);
2382
2383 if (c1 < c)
2384 i1++;
2385 mapping = array_get(&(s->mapping), i1);
2386 }
2387
2388 next_mapping->dir_index = mapping->dir_index;
2389 next_mapping->first_mapping_index =
2390 mapping->first_mapping_index < 0 ?
2391 array_index(&(s->mapping), mapping) :
2392 mapping->first_mapping_index;
2393 next_mapping->path = mapping->path;
2394 next_mapping->mode = mapping->mode;
2395 next_mapping->read_only = mapping->read_only;
2396 if (mapping->mode & MODE_DIRECTORY) {
2397 next_mapping->info.dir.parent_mapping_index =
2398 mapping->info.dir.parent_mapping_index;
2399 next_mapping->info.dir.first_dir_index =
2400 mapping->info.dir.first_dir_index +
2401 0x10 * s->sectors_per_cluster *
2402 (mapping->end - mapping->begin);
2403 } else
2404 next_mapping->info.file.offset = mapping->info.file.offset +
2405 mapping->end - mapping->begin;
2406
2407 mapping = next_mapping;
2408 }
2409
2410 cluster = c1;
a046433a 2411 }
de167e41 2412
de167e41
FB
2413 return 0;
2414}
2415
a046433a 2416static int commit_direntries(BDRVVVFATState* s,
d6a7e54e 2417 int dir_index, int parent_mapping_index)
de167e41 2418{
c227f099 2419 direntry_t* direntry = array_get(&(s->directory), dir_index);
a046433a 2420 uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
c227f099 2421 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
a046433a
FB
2422 int factor = 0x10 * s->sectors_per_cluster;
2423 int old_cluster_count, new_cluster_count;
8d9401c2
LM
2424 int current_dir_index;
2425 int first_dir_index;
a046433a
FB
2426 int ret, i;
2427 uint32_t c;
2428
a046433a
FB
2429 assert(direntry);
2430 assert(mapping);
2431 assert(mapping->begin == first_cluster);
2432 assert(mapping->info.dir.first_dir_index < s->directory.next);
2433 assert(mapping->mode & MODE_DIRECTORY);
2434 assert(dir_index == 0 || is_directory(direntry));
2435
8d9401c2
LM
2436 DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n",
2437 mapping->path, parent_mapping_index));
2438
2439 current_dir_index = mapping->info.dir.first_dir_index;
2440 first_dir_index = current_dir_index;
a046433a
FB
2441 mapping->info.dir.parent_mapping_index = parent_mapping_index;
2442
2443 if (first_cluster == 0) {
d6a7e54e
HP
2444 old_cluster_count = new_cluster_count =
2445 s->last_cluster_of_root_directory;
a046433a 2446 } else {
d6a7e54e
HP
2447 for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2448 c = fat_get(s, c))
2449 old_cluster_count++;
de167e41 2450
d6a7e54e
HP
2451 for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2452 c = modified_fat_get(s, c))
2453 new_cluster_count++;
a046433a 2454 }
de167e41 2455
a046433a 2456 if (new_cluster_count > old_cluster_count) {
d6a7e54e
HP
2457 if (insert_direntries(s,
2458 current_dir_index + factor * old_cluster_count,
2459 factor * (new_cluster_count - old_cluster_count)) == NULL)
2460 return -1;
a046433a 2461 } else if (new_cluster_count < old_cluster_count)
d6a7e54e
HP
2462 remove_direntries(s,
2463 current_dir_index + factor * new_cluster_count,
2464 factor * (old_cluster_count - new_cluster_count));
a046433a
FB
2465
2466 for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
ebb72c9f 2467 direntry_t *first_direntry;
d6a7e54e
HP
2468 void* direntry = array_get(&(s->directory), current_dir_index);
2469 int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2470 s->sectors_per_cluster);
2471 if (ret)
2472 return ret;
ebb72c9f
KW
2473
2474 /* The first directory entry on the filesystem is the volume name */
2475 first_direntry = (direntry_t*) s->directory.pointer;
2476 assert(!memcmp(first_direntry->name, s->volume_label, 11));
2477
d6a7e54e 2478 current_dir_index += factor;
a046433a 2479 }
de167e41 2480
a046433a
FB
2481 ret = commit_mappings(s, first_cluster, dir_index);
2482 if (ret)
d6a7e54e 2483 return ret;
a046433a
FB
2484
2485 /* recurse */
2486 for (i = 0; i < factor * new_cluster_count; i++) {
d6a7e54e
HP
2487 direntry = array_get(&(s->directory), first_dir_index + i);
2488 if (is_directory(direntry) && !is_dot(direntry)) {
2489 mapping = find_mapping_for_cluster(s, first_cluster);
8d9401c2
LM
2490 if (mapping == NULL) {
2491 return -1;
2492 }
d6a7e54e
HP
2493 assert(mapping->mode & MODE_DIRECTORY);
2494 ret = commit_direntries(s, first_dir_index + i,
2495 array_index(&(s->mapping), mapping));
2496 if (ret)
2497 return ret;
2498 }
a046433a 2499 }
de167e41 2500
a046433a
FB
2501 return 0;
2502}
de167e41 2503
a046433a
FB
2504/* commit one file (adjust contents, adjust mapping),
2505 return first_mapping_index */
2506static int commit_one_file(BDRVVVFATState* s,
d6a7e54e 2507 int dir_index, uint32_t offset)
a046433a 2508{
c227f099 2509 direntry_t* direntry = array_get(&(s->directory), dir_index);
a046433a
FB
2510 uint32_t c = begin_of_direntry(direntry);
2511 uint32_t first_cluster = c;
c227f099 2512 mapping_t* mapping = find_mapping_for_cluster(s, c);
a046433a 2513 uint32_t size = filesize_of_direntry(direntry);
443ba6be 2514 char *cluster;
a046433a
FB
2515 uint32_t i;
2516 int fd = 0;
2517
2518 assert(offset < size);
2519 assert((offset % s->cluster_size) == 0);
2520
8d9401c2
LM
2521 if (mapping == NULL) {
2522 return -1;
2523 }
2524
a046433a 2525 for (i = s->cluster_size; i < offset; i += s->cluster_size)
d6a7e54e 2526 c = modified_fat_get(s, c);
a046433a 2527
448058aa 2528 fd = qemu_open_old(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
a046433a 2529 if (fd < 0) {
d6a7e54e
HP
2530 fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2531 strerror(errno), errno);
d6a7e54e 2532 return fd;
de167e41 2533 }
ce137829
SW
2534 if (offset > 0) {
2535 if (lseek(fd, offset, SEEK_SET) != offset) {
2e1e79da 2536 qemu_close(fd);
ce137829
SW
2537 return -3;
2538 }
2539 }
a046433a 2540
443ba6be
KW
2541 cluster = g_malloc(s->cluster_size);
2542
a046433a 2543 while (offset < size) {
d6a7e54e
HP
2544 uint32_t c1;
2545 int rest_size = (size - offset > s->cluster_size ?
2546 s->cluster_size : size - offset);
2547 int ret;
a046433a 2548
d6a7e54e 2549 c1 = modified_fat_get(s, c);
a046433a 2550
d6a7e54e
HP
2551 assert((size - offset == 0 && fat_eof(s, c)) ||
2552 (size > offset && c >=2 && !fat_eof(s, c)));
a046433a 2553
d6a7e54e 2554 ret = vvfat_read(s->bs, cluster2sector(s, c),
78ee96de 2555 (uint8_t*)cluster, DIV_ROUND_UP(rest_size, 0x200));
a046433a 2556
ce137829 2557 if (ret < 0) {
2e1e79da 2558 qemu_close(fd);
ce137829
SW
2559 g_free(cluster);
2560 return ret;
2561 }
a046433a 2562
ce137829 2563 if (write(fd, cluster, rest_size) < 0) {
2e1e79da 2564 qemu_close(fd);
ce137829
SW
2565 g_free(cluster);
2566 return -2;
2567 }
a046433a 2568
d6a7e54e
HP
2569 offset += rest_size;
2570 c = c1;
a046433a
FB
2571 }
2572
2dedf83e
KS
2573 if (ftruncate(fd, size)) {
2574 perror("ftruncate()");
2e1e79da 2575 qemu_close(fd);
ce137829 2576 g_free(cluster);
2dedf83e
KS
2577 return -4;
2578 }
2e1e79da 2579 qemu_close(fd);
ce137829 2580 g_free(cluster);
a046433a
FB
2581
2582 return commit_mappings(s, first_cluster, dir_index);
2583}
2584
2585#ifdef DEBUG
2586/* test, if all mappings point to valid direntries */
2587static void check1(BDRVVVFATState* s)
2588{
2589 int i;
2590 for (i = 0; i < s->mapping.next; i++) {
d6a7e54e
HP
2591 mapping_t* mapping = array_get(&(s->mapping), i);
2592 if (mapping->mode & MODE_DELETED) {
2593 fprintf(stderr, "deleted\n");
2594 continue;
2595 }
2596 assert(mapping->dir_index < s->directory.next);
2597 direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2598 assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2599 if (mapping->mode & MODE_DIRECTORY) {
2600 assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2601 assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2602 }
de167e41 2603 }
de167e41
FB
2604}
2605
a046433a
FB
2606/* test, if all direntries have mappings */
2607static void check2(BDRVVVFATState* s)
de167e41 2608{
de167e41 2609 int i;
a046433a 2610 int first_mapping = -1;
de167e41 2611
a046433a 2612 for (i = 0; i < s->directory.next; i++) {
d6a7e54e
HP
2613 direntry_t* direntry = array_get(&(s->directory), i);
2614
2615 if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2616 mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2617 assert(mapping);
2618 assert(mapping->dir_index == i || is_dot(direntry));
2619 assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2620 }
2621
2622 if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2623 /* cluster start */
2624 int j, count = 0;
2625
2626 for (j = 0; j < s->mapping.next; j++) {
2627 mapping_t* mapping = array_get(&(s->mapping), j);
2628 if (mapping->mode & MODE_DELETED)
2629 continue;
2630 if (mapping->mode & MODE_DIRECTORY) {
2631 if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2632 assert(++count == 1);
2633 if (mapping->first_mapping_index == -1)
2634 first_mapping = array_index(&(s->mapping), mapping);
2635 else
2636 assert(first_mapping == mapping->first_mapping_index);
2637 if (mapping->info.dir.parent_mapping_index < 0)
2638 assert(j == 0);
2639 else {
2640 mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2641 assert(parent->mode & MODE_DIRECTORY);
2642 assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2643 }
2644 }
2645 }
2646 }
2647 if (count == 0)
2648 first_mapping = -1;
2649 }
a046433a
FB
2650 }
2651}
2652#endif
de167e41 2653
a046433a
FB
2654static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2655{
2656 int i;
de167e41 2657
a046433a
FB
2658#ifdef DEBUG
2659 fprintf(stderr, "handle_renames\n");
2660 for (i = 0; i < s->commits.next; i++) {
d6a7e54e 2661 commit_t* commit = array_get(&(s->commits), i);
c9eb2f3e
AC
2662 fprintf(stderr, "%d, %s (%u, %d)\n", i,
2663 commit->path ? commit->path : "(null)",
2664 commit->param.rename.cluster, commit->action);
a046433a
FB
2665 }
2666#endif
2667
2668 for (i = 0; i < s->commits.next;) {
d6a7e54e
HP
2669 commit_t* commit = array_get(&(s->commits), i);
2670 if (commit->action == ACTION_RENAME) {
2671 mapping_t* mapping = find_mapping_for_cluster(s,
2672 commit->param.rename.cluster);
8d9401c2 2673 char *old_path;
d6a7e54e 2674
8d9401c2
LM
2675 if (mapping == NULL) {
2676 return -1;
2677 }
2678 old_path = mapping->path;
d6a7e54e
HP
2679 assert(commit->path);
2680 mapping->path = commit->path;
2681 if (rename(old_path, mapping->path))
2682 return -2;
2683
2684 if (mapping->mode & MODE_DIRECTORY) {
2685 int l1 = strlen(mapping->path);
2686 int l2 = strlen(old_path);
2687 int diff = l1 - l2;
2688 direntry_t* direntry = array_get(&(s->directory),
2689 mapping->info.dir.first_dir_index);
2690 uint32_t c = mapping->begin;
2691 int i = 0;
2692
2693 /* recurse */
2694 while (!fat_eof(s, c)) {
2695 do {
2696 direntry_t* d = direntry + i;
2697
2698 if (is_file(d) || (is_directory(d) && !is_dot(d))) {
8d9401c2
LM
2699 int l;
2700 char *new_path;
d6a7e54e
HP
2701 mapping_t* m = find_mapping_for_cluster(s,
2702 begin_of_direntry(d));
8d9401c2
LM
2703 if (m == NULL) {
2704 return -1;
2705 }
2706 l = strlen(m->path);
2707 new_path = g_malloc(l + diff + 1);
d6a7e54e
HP
2708
2709 assert(!strncmp(m->path, mapping->path, l2));
a046433a 2710
363a37d5
BS
2711 pstrcpy(new_path, l + diff + 1, mapping->path);
2712 pstrcpy(new_path + l1, l + diff + 1 - l1,
2713 m->path + l2);
a046433a 2714
d6a7e54e
HP
2715 schedule_rename(s, m->begin, new_path);
2716 }
2717 i++;
2718 } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2719 c = fat_get(s, c);
2720 }
2721 }
de167e41 2722
ce137829 2723 g_free(old_path);
d6a7e54e
HP
2724 array_remove(&(s->commits), i);
2725 continue;
2726 } else if (commit->action == ACTION_MKDIR) {
2727 mapping_t* mapping;
2728 int j, parent_path_len;
a046433a 2729
c2632994 2730 if (g_mkdir(commit->path, 0755)) {
48c2f068 2731 return -5;
c2632994 2732 }
a046433a 2733
d6a7e54e
HP
2734 mapping = insert_mapping(s, commit->param.mkdir.cluster,
2735 commit->param.mkdir.cluster + 1);
2736 if (mapping == NULL)
2737 return -6;
2738
2739 mapping->mode = MODE_DIRECTORY;
2740 mapping->read_only = 0;
2741 mapping->path = commit->path;
2742 j = s->directory.next;
2743 assert(j);
2744 insert_direntries(s, s->directory.next,
2745 0x10 * s->sectors_per_cluster);
2746 mapping->info.dir.first_dir_index = j;
2747
2748 parent_path_len = strlen(commit->path)
2749 - strlen(get_basename(commit->path)) - 1;
2750 for (j = 0; j < s->mapping.next; j++) {
2751 mapping_t* m = array_get(&(s->mapping), j);
2752 if (m->first_mapping_index < 0 && m != mapping &&
2753 !strncmp(m->path, mapping->path, parent_path_len) &&
2754 strlen(m->path) == parent_path_len)
2755 break;
2756 }
2757 assert(j < s->mapping.next);
2758 mapping->info.dir.parent_mapping_index = j;
2759
2760 array_remove(&(s->commits), i);
2761 continue;
2762 }
2763
2764 i++;
a046433a
FB
2765 }
2766 return 0;
2767}
2768
2769/*
2770 * TODO: make sure that the short name is not matching *another* file
2771 */
2772static int handle_commits(BDRVVVFATState* s)
2773{
2774 int i, fail = 0;
2775
2776 vvfat_close_current_file(s);
2777
2778 for (i = 0; !fail && i < s->commits.next; i++) {
d6a7e54e
HP
2779 commit_t* commit = array_get(&(s->commits), i);
2780 switch(commit->action) {
2781 case ACTION_RENAME: case ACTION_MKDIR:
43dc2a64 2782 abort();
d6a7e54e
HP
2783 fail = -2;
2784 break;
2785 case ACTION_WRITEOUT: {
a6c6f76c
BS
2786#ifndef NDEBUG
2787 /* these variables are only used by assert() below */
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);
a6c6f76c 2792#endif
a046433a 2793
d6a7e54e
HP
2794 assert(mapping);
2795 assert(mapping->begin == begin);
2796 assert(commit->path == NULL);
2797
2798 if (commit_one_file(s, commit->param.writeout.dir_index,
2799 commit->param.writeout.modified_offset))
2800 fail = -3;
2801
2802 break;
2803 }
2804 case ACTION_NEW_FILE: {
2805 int begin = commit->param.new_file.first_cluster;
2806 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2807 direntry_t* entry;
2808 int i;
2809
2810 /* find direntry */
2811 for (i = 0; i < s->directory.next; i++) {
2812 entry = array_get(&(s->directory), i);
2813 if (is_file(entry) && begin_of_direntry(entry) == begin)
2814 break;
2815 }
2816
2817 if (i >= s->directory.next) {
2818 fail = -6;
2819 continue;
2820 }
2821
2822 /* make sure there exists an initial mapping */
2823 if (mapping && mapping->begin != begin) {
2824 mapping->end = begin;
2825 mapping = NULL;
2826 }
2827 if (mapping == NULL) {
2828 mapping = insert_mapping(s, begin, begin+1);
2829 }
2830 /* most members will be fixed in commit_mappings() */
2831 assert(commit->path);
2832 mapping->path = commit->path;
2833 mapping->read_only = 0;
2834 mapping->mode = MODE_NORMAL;
2835 mapping->info.file.offset = 0;
2836
2837 if (commit_one_file(s, i, 0))
2838 fail = -7;
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 */
2918static int do_commit(BDRVVVFATState* s)
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
2968static int try_commit(BDRVVVFATState* s)
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
5fafdf24 2977static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
a046433a
FB
2978 const uint8_t *buf, int nb_sectors)
2979{
5fafdf24 2980 BDRVVVFATState *s = bs->opaque;
a046433a 2981 int i, ret;
b9b8860d 2982 int first_cluster, last_cluster;
a046433a
FB
2983
2984DLOG(checkpoint());
2985
ac48e389
KW
2986 /* Check if we're operating in read-only mode */
2987 if (s->qcow == NULL) {
2988 return -EACCES;
2989 }
2990
a046433a
FB
2991 vvfat_close_current_file(s);
2992
d0f95b6c
HP
2993 if (sector_num == s->offset_to_bootsector && nb_sectors == 1) {
2994 /*
2995 * Write on bootsector. Allow only changing the reserved1 field,
2996 * used to mark volume dirtiness
2997 */
2998 unsigned char *bootsector = s->first_sectors
2999 + s->offset_to_bootsector * 0x200;
3000 /*
3001 * LATER TODO: if FAT32, this is wrong (see init_directories(),
3002 * which always creates a FAT16 bootsector)
3003 */
3004 const int reserved1_offset = offsetof(bootsector_t, u.fat16.reserved1);
3005
3006 for (i = 0; i < 0x200; i++) {
3007 if (i != reserved1_offset && bootsector[i] != buf[i]) {
3008 fprintf(stderr, "Tried to write to protected bootsector\n");
3009 return -1;
3010 }
3011 }
3012
3013 /* Update bootsector with the only updatable byte, and return success */
3014 bootsector[reserved1_offset] = buf[reserved1_offset];
3015 return 0;
3016 }
3017
a046433a
FB
3018 /*
3019 * Some sanity checks:
3020 * - do not allow writing to the boot sector
a046433a 3021 */
4dc705dc 3022 if (sector_num < s->offset_to_fat)
d6a7e54e 3023 return -1;
a046433a 3024
b9b8860d
KW
3025 /*
3026 * Values will be negative for writes to the FAT, which is located before
3027 * the root directory.
3028 */
3029 first_cluster = sector2cluster(s, sector_num);
3030 last_cluster = sector2cluster(s, sector_num + nb_sectors - 1);
3031
3032 for (i = first_cluster; i <= last_cluster;) {
3033 mapping_t *mapping = NULL;
3034
3035 if (i >= 0) {
3036 mapping = find_mapping_for_cluster(s, i);
3037 }
3038
d6a7e54e
HP
3039 if (mapping) {
3040 if (mapping->read_only) {
3041 fprintf(stderr, "Tried to write to write-protected file %s\n",
3042 mapping->path);
3043 return -1;
3044 }
3045
3046 if (mapping->mode & MODE_DIRECTORY) {
3047 int begin = cluster2sector(s, i);
3048 int end = begin + s->sectors_per_cluster, k;
3049 int dir_index;
3050 const direntry_t* direntries;
3051 long_file_name lfn;
3052
3053 lfn_init(&lfn);
3054
3055 if (begin < sector_num)
3056 begin = sector_num;
3057 if (end > sector_num + nb_sectors)
3058 end = sector_num + nb_sectors;
3059 dir_index = mapping->dir_index +
3060 0x10 * (begin - mapping->begin * s->sectors_per_cluster);
3061 direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
3062
3063 for (k = 0; k < (end - begin) * 0x10; k++) {
d6a7e54e 3064 /* no access to the direntry of a read-only file */
e03da26b 3065 if (is_short_name(direntries + k) &&
d6a7e54e
HP
3066 (direntries[k].attributes & 1)) {
3067 if (memcmp(direntries + k,
3068 array_get(&(s->directory), dir_index + k),
3069 sizeof(direntry_t))) {
2ab4b135
AF
3070 warn_report("tried to write to write-protected "
3071 "file");
d6a7e54e
HP
3072 return -1;
3073 }
3074 }
3075 }
3076 }
3077 i = mapping->end;
b9b8860d 3078 } else {
d6a7e54e 3079 i++;
b9b8860d 3080 }
a046433a
FB
3081 }
3082
3083 /*
3084 * Use qcow backend. Commit later.
3085 */
3086DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
32cc71de
AF
3087 ret = bdrv_pwrite(s->qcow, sector_num * BDRV_SECTOR_SIZE,
3088 nb_sectors * BDRV_SECTOR_SIZE, buf, 0);
a046433a 3089 if (ret < 0) {
d6a7e54e
HP
3090 fprintf(stderr, "Error writing to qcow backend\n");
3091 return ret;
a046433a
FB
3092 }
3093
b9b8860d
KW
3094 for (i = first_cluster; i <= last_cluster; i++) {
3095 if (i >= 0) {
d6a7e54e 3096 s->used_clusters[i] |= USED_ALLOCATED;
b9b8860d
KW
3097 }
3098 }
a046433a
FB
3099
3100DLOG(checkpoint());
3101 /* TODO: add timeout */
3102 try_commit(s);
3103
3104DLOG(checkpoint());
3105 return 0;
3106}
3107
4575eb49 3108static int coroutine_fn
e75abeda
VSO
3109vvfat_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
3110 QEMUIOVector *qiov, BdrvRequestFlags flags)
e183ef75
PB
3111{
3112 int ret;
3113 BDRVVVFATState *s = bs->opaque;
4575eb49
KW
3114 uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
3115 int nb_sectors = bytes >> BDRV_SECTOR_BITS;
3116 void *buf;
3117
1bbbf32d
NS
3118 assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE));
3119 assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE));
4575eb49
KW
3120
3121 buf = g_try_malloc(bytes);
3122 if (bytes && buf == NULL) {
3123 return -ENOMEM;
3124 }
3125 qemu_iovec_to_buf(qiov, 0, buf, bytes);
3126
e183ef75
PB
3127 qemu_co_mutex_lock(&s->lock);
3128 ret = vvfat_write(bs, sector_num, buf, nb_sectors);
3129 qemu_co_mutex_unlock(&s->lock);
4575eb49
KW
3130
3131 g_free(buf);
3132
e183ef75
PB
3133 return ret;
3134}
3135
fba3998d
EB
3136static int coroutine_fn vvfat_co_block_status(BlockDriverState *bs,
3137 bool want_zero, int64_t offset,
3138 int64_t bytes, int64_t *n,
3139 int64_t *map,
3140 BlockDriverState **file)
a046433a 3141{
fba3998d 3142 *n = bytes;
4bc74be9 3143 return BDRV_BLOCK_DATA;
a046433a
FB
3144}
3145
3cdc69d3 3146static void vvfat_qcow_options(BdrvChildRole role, bool parent_is_format,
272c02ea 3147 int *child_flags, QDict *child_options,
eecc7747 3148 int parent_flags, QDict *parent_options)
a046433a 3149{
f87a0e29 3150 qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off");
e35bdc12 3151 qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off");
4f8e3a1f 3152 qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on");
eecc7747
KW
3153}
3154
8081f064 3155static BdrvChildClass child_vvfat_qcow;
eecc7747
KW
3156
3157static int enable_write_target(BlockDriverState *bs, Error **errp)
3158{
3159 BDRVVVFATState *s = bs->opaque;
facdbb02 3160 BlockDriver *bdrv_qcow = NULL;
facdbb02 3161 QemuOpts *opts = NULL;
a655211a 3162 int ret;
a046433a 3163 int size = sector2cluster(s, s->sector_count);
e6641719
HR
3164 QDict *options;
3165
22c36b75 3166 s->used_clusters = g_malloc0(size);
a046433a 3167
c227f099 3168 array_init(&(s->commits), sizeof(commit_t));
a046433a 3169
69fbfff9
BM
3170 s->qcow_filename = create_tmp_file(errp);
3171 if (!s->qcow_filename) {
3172 ret = -ENOENT;
78f27bd0 3173 goto err;
eba25057 3174 }
91a073a9
KW
3175
3176 bdrv_qcow = bdrv_find_format("qcow");
1bcb15cf
HR
3177 if (!bdrv_qcow) {
3178 error_setg(errp, "Failed to locate qcow driver");
3179 ret = -ENOENT;
3180 goto err;
3181 }
3182
c282e1fd 3183 opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort);
2db9b9e9
KW
3184 qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
3185 bs->total_sectors * BDRV_SECTOR_SIZE, &error_abort);
f43e47db 3186 qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:", &error_abort);
91a073a9 3187
c282e1fd 3188 ret = bdrv_create(bdrv_qcow, s->qcow_filename, opts, errp);
facdbb02 3189 qemu_opts_del(opts);
78f27bd0
FZ
3190 if (ret < 0) {
3191 goto err;
3192 }
a655211a 3193
e6641719 3194 options = qdict_new();
46f5ac20 3195 qdict_put_str(options, "write-target.driver", "qcow");
eecc7747 3196 s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs,
1f38f04e
HR
3197 &child_vvfat_qcow,
3198 BDRV_CHILD_DATA | BDRV_CHILD_METADATA,
3199 false, errp);
cb3e7f08 3200 qobject_unref(options);
5b363937
HR
3201 if (!s->qcow) {
3202 ret = -EINVAL;
78f27bd0 3203 goto err;
d6e9098e 3204 }
a046433a
FB
3205
3206#ifndef _WIN32
3207 unlink(s->qcow_filename);
3208#endif
3209
de167e41 3210 return 0;
78f27bd0
FZ
3211
3212err:
78f27bd0 3213 return ret;
de167e41
FB
3214}
3215
91ef3825 3216static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c,
bf8e925e 3217 BdrvChildRole role,
e0995dc3 3218 BlockReopenQueue *reopen_queue,
91ef3825
KW
3219 uint64_t perm, uint64_t shared,
3220 uint64_t *nperm, uint64_t *nshared)
3221{
6af72274
VSO
3222 assert(role & BDRV_CHILD_DATA);
3223 /* This is a private node, nobody should try to attach to it */
3224 *nperm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE;
3225 *nshared = BLK_PERM_WRITE_UNCHANGED;
91ef3825
KW
3226}
3227
de167e41
FB
3228static void vvfat_close(BlockDriverState *bs)
3229{
3230 BDRVVVFATState *s = bs->opaque;
3231
3232 vvfat_close_current_file(s);
3233 array_free(&(s->fat));
3234 array_free(&(s->directory));
3235 array_free(&(s->mapping));
ce137829 3236 g_free(s->cluster_buffer);
3397f0cb
KW
3237
3238 if (s->qcow) {
3239 migrate_del_blocker(s->migration_blocker);
3240 error_free(s->migration_blocker);
3241 }
de167e41
FB
3242}
3243
2654267c
HR
3244static const char *const vvfat_strong_runtime_opts[] = {
3245 "dir",
3246 "fat-type",
3247 "floppy",
3248 "label",
3249 "rw",
3250
3251 NULL
3252};
3253
5efa9d5a 3254static BlockDriver bdrv_vvfat = {
7ad9be64
KW
3255 .format_name = "vvfat",
3256 .protocol_name = "fat",
3257 .instance_size = sizeof(BDRVVVFATState),
3258
3259 .bdrv_parse_filename = vvfat_parse_filename,
3260 .bdrv_file_open = vvfat_open,
a6506481 3261 .bdrv_refresh_limits = vvfat_refresh_limits,
7ad9be64 3262 .bdrv_close = vvfat_close,
91ef3825 3263 .bdrv_child_perm = vvfat_child_perm,
7ad9be64 3264
4575eb49
KW
3265 .bdrv_co_preadv = vvfat_co_preadv,
3266 .bdrv_co_pwritev = vvfat_co_pwritev,
fba3998d 3267 .bdrv_co_block_status = vvfat_co_block_status,
2654267c
HR
3268
3269 .strong_runtime_opts = vvfat_strong_runtime_opts,
de167e41
FB
3270};
3271
5efa9d5a
AL
3272static void bdrv_vvfat_init(void)
3273{
8081f064
VSO
3274 child_vvfat_qcow = child_of_bds;
3275 child_vvfat_qcow.inherit_options = vvfat_qcow_options;
5efa9d5a
AL
3276 bdrv_register(&bdrv_vvfat);
3277}
3278
3279block_init(bdrv_vvfat_init);
3280
a046433a 3281#ifdef DEBUG
7a6ab45e
TH
3282static void checkpoint(void)
3283{
c227f099 3284 assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
a046433a
FB
3285 check1(vvv);
3286 check2(vvv);
3287 assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
a046433a
FB
3288}
3289#endif