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