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