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