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