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