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