qemu

Форк
0
/
vvfat.c 
3289 строк · 102.0 Кб
1
/* vim:set shiftwidth=4 ts=4: */
2
/*
3
 * QEMU Block driver for virtual VFAT (shadows a local directory)
4
 *
5
 * Copyright (c) 2004,2005 Johannes E. Schindelin
6
 *
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
 */
25

26
#include "qemu/osdep.h"
27
#include <dirent.h>
28
#include <glib/gstdio.h>
29
#include "qapi/error.h"
30
#include "block/block-io.h"
31
#include "block/block_int.h"
32
#include "block/qdict.h"
33
#include "qemu/module.h"
34
#include "qemu/option.h"
35
#include "qemu/bswap.h"
36
#include "migration/blocker.h"
37
#include "qapi/qmp/qdict.h"
38
#include "qapi/qmp/qstring.h"
39
#include "qemu/ctype.h"
40
#include "qemu/cutils.h"
41
#include "qemu/error-report.h"
42

43
#ifndef S_IWGRP
44
#define S_IWGRP 0
45
#endif
46
#ifndef S_IWOTH
47
#define S_IWOTH 0
48
#endif
49

50
/* TODO: add ":bootsector=blabla.img:" */
51
/* LATER TODO: add automatic boot sector generation from
52
    BOOTEASY.ASM and Ranish Partition Manager
53
    Note that DOS assumes the system files to be the first files in the
54
    file system (test if the boot sector still relies on that fact)! */
55
/* MAYBE TODO: write block-visofs.c */
56
/* TODO: call try_commit() only after a timeout */
57

58
/* #define DEBUG */
59

60
#ifdef DEBUG
61

62
#define DLOG(a) a
63

64
static void checkpoint(void);
65

66
#else
67

68
#define DLOG(a)
69

70
#endif
71

72
/* bootsector OEM name. see related compatibility problems at:
73
 * https://jdebp.eu/FGA/volume-boot-block-oem-name-field.html
74
 * http://seasip.info/Misc/oemid.html
75
 */
76
#define BOOTSECTOR_OEM_NAME "MSWIN4.1"
77

78
#define DIR_DELETED 0xe5
79
#define DIR_KANJI DIR_DELETED
80
#define DIR_KANJI_FAKE 0x05
81
#define DIR_FREE 0x00
82

83
/* dynamic array functions */
84
typedef struct array_t {
85
    char* pointer;
86
    unsigned int size,next,item_size;
87
} array_t;
88

89
static inline void array_init(array_t* array,unsigned int item_size)
90
{
91
    array->pointer = NULL;
92
    array->size=0;
93
    array->next=0;
94
    array->item_size=item_size;
95
}
96

97
static inline void array_free(array_t* array)
98
{
99
    g_free(array->pointer);
100
    array->size=array->next=0;
101
}
102

103
/* does not automatically grow */
104
static inline void* array_get(array_t* array,unsigned int index) {
105
    assert(index < array->next);
106
    assert(array->pointer);
107
    return array->pointer + index * array->item_size;
108
}
109

110
static inline void array_ensure_allocated(array_t *array, int index)
111
{
112
    if((index + 1) * array->item_size > array->size) {
113
        int new_size = (index + 32) * array->item_size;
114
        array->pointer = g_realloc(array->pointer, new_size);
115
        assert(array->pointer);
116
        memset(array->pointer + array->size, 0, new_size - array->size);
117
        array->size = new_size;
118
        array->next = index + 1;
119
    }
120
}
121

122
static inline void* array_get_next(array_t* array) {
123
    unsigned int next = array->next;
124

125
    array_ensure_allocated(array, next);
126
    array->next = next + 1;
127
    return array_get(array, next);
128
}
129

130
static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
131
    if((array->next+count)*array->item_size>array->size) {
132
        int increment=count*array->item_size;
133
        array->pointer=g_realloc(array->pointer,array->size+increment);
134
        if(!array->pointer)
135
            return NULL;
136
        array->size+=increment;
137
    }
138
    memmove(array->pointer+(index+count)*array->item_size,
139
                array->pointer+index*array->item_size,
140
                (array->next-index)*array->item_size);
141
    array->next+=count;
142
    return array->pointer+index*array->item_size;
143
}
144

145
static inline int array_remove_slice(array_t* array,int index, int count)
146
{
147
    assert(index >=0);
148
    assert(count > 0);
149
    assert(index + count <= array->next);
150

151
    memmove(array->pointer + index * array->item_size,
152
            array->pointer + (index + count) * array->item_size,
153
            (array->next - index - count) * array->item_size);
154

155
    array->next -= count;
156
    return 0;
157
}
158

159
static int array_remove(array_t* array,int index)
160
{
161
    return array_remove_slice(array, index, 1);
162
}
163

164
/* return the index for a given member */
165
static int array_index(array_t* array, void* pointer)
166
{
167
    size_t offset = (char*)pointer - array->pointer;
168
    assert((offset % array->item_size) == 0);
169
    assert(offset/array->item_size < array->next);
170
    return offset/array->item_size;
171
}
172

173
/* These structures are used to fake a disk and the VFAT filesystem.
174
 * For this reason we need to use QEMU_PACKED. */
175

176
typedef struct bootsector_t {
177
    uint8_t jump[3];
178
    uint8_t name[8];
179
    uint16_t sector_size;
180
    uint8_t sectors_per_cluster;
181
    uint16_t reserved_sectors;
182
    uint8_t number_of_fats;
183
    uint16_t root_entries;
184
    uint16_t total_sectors16;
185
    uint8_t media_type;
186
    uint16_t sectors_per_fat;
187
    uint16_t sectors_per_track;
188
    uint16_t number_of_heads;
189
    uint32_t hidden_sectors;
190
    uint32_t total_sectors;
191
    union {
192
        struct {
193
            uint8_t drive_number;
194
            uint8_t reserved1;
195
            uint8_t signature;
196
            uint32_t id;
197
            uint8_t volume_label[11];
198
            uint8_t fat_type[8];
199
            uint8_t ignored[0x1c0];
200
        } QEMU_PACKED fat16;
201
        struct {
202
            uint32_t sectors_per_fat;
203
            uint16_t flags;
204
            uint8_t major,minor;
205
            uint32_t first_cluster_of_root_dir;
206
            uint16_t info_sector;
207
            uint16_t backup_boot_sector;
208
            uint8_t reserved[12];
209
            uint8_t drive_number;
210
            uint8_t reserved1;
211
            uint8_t signature;
212
            uint32_t id;
213
            uint8_t volume_label[11];
214
            uint8_t fat_type[8];
215
            uint8_t ignored[0x1a4];
216
        } QEMU_PACKED fat32;
217
    } u;
218
    uint8_t magic[2];
219
} QEMU_PACKED bootsector_t;
220

221
typedef struct {
222
    uint8_t head;
223
    uint8_t sector;
224
    uint8_t cylinder;
225
} mbr_chs_t;
226

227
typedef struct partition_t {
228
    uint8_t attributes; /* 0x80 = bootable */
229
    mbr_chs_t start_CHS;
230
    uint8_t   fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
231
    mbr_chs_t end_CHS;
232
    uint32_t start_sector_long;
233
    uint32_t length_sector_long;
234
} QEMU_PACKED partition_t;
235

236
typedef struct mbr_t {
237
    uint8_t ignored[0x1b8];
238
    uint32_t nt_id;
239
    uint8_t ignored2[2];
240
    partition_t partition[4];
241
    uint8_t magic[2];
242
} QEMU_PACKED mbr_t;
243

244
typedef struct direntry_t {
245
    uint8_t name[8 + 3];
246
    uint8_t attributes;
247
    uint8_t reserved[2];
248
    uint16_t ctime;
249
    uint16_t cdate;
250
    uint16_t adate;
251
    uint16_t begin_hi;
252
    uint16_t mtime;
253
    uint16_t mdate;
254
    uint16_t begin;
255
    uint32_t size;
256
} QEMU_PACKED direntry_t;
257

258
/* this structure are used to transparently access the files */
259

260
typedef struct mapping_t {
261
    /* begin is the first cluster, end is the last+1 */
262
    uint32_t begin,end;
263
    /* as s->directory is growable, no pointer may be used here */
264
    unsigned int dir_index;
265
    /* the clusters of a file may be in any order; this points to the first */
266
    int first_mapping_index;
267
    union {
268
        /* offset is
269
         * - the offset in the file (in clusters) for a file, or
270
         * - the next cluster of the directory for a directory
271
         */
272
        struct {
273
            uint32_t offset;
274
        } file;
275
        struct {
276
            int parent_mapping_index;
277
            int first_dir_index;
278
        } dir;
279
    } info;
280
    /* path contains the full path, i.e. it always starts with s->path */
281
    char* path;
282

283
    enum {
284
        MODE_UNDEFINED = 0,
285
        MODE_NORMAL = 1,
286
        MODE_MODIFIED = 2,
287
        MODE_DIRECTORY = 4,
288
        MODE_DELETED = 8,
289
    } mode;
290
    int read_only;
291
} mapping_t;
292

293
#ifdef DEBUG
294
static void print_direntry(const struct direntry_t*);
295
static void print_mapping(const struct mapping_t* mapping);
296
#endif
297

298
/* here begins the real VVFAT driver */
299

300
typedef struct BDRVVVFATState {
301
    CoMutex lock;
302
    BlockDriverState* bs; /* pointer to parent */
303
    unsigned char first_sectors[0x40*0x200];
304

305
    int fat_type; /* 16 or 32 */
306
    array_t fat,directory,mapping;
307
    char volume_label[11];
308

309
    uint32_t offset_to_bootsector; /* 0 for floppy, 0x3f for disk */
310

311
    unsigned int cluster_size;
312
    unsigned int sectors_per_cluster;
313
    unsigned int sectors_per_fat;
314
    uint32_t last_cluster_of_root_directory;
315
    /* how many entries are available in root directory (0 for FAT32) */
316
    uint16_t root_entries;
317
    uint32_t sector_count; /* total number of sectors of the partition */
318
    uint32_t cluster_count; /* total number of clusters of this partition */
319
    uint32_t max_fat_value;
320
    uint32_t offset_to_fat;
321
    uint32_t offset_to_root_dir;
322

323
    int current_fd;
324
    mapping_t* current_mapping;
325
    unsigned char* cluster; /* points to current cluster */
326
    unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
327
    unsigned int current_cluster;
328

329
    /* write support */
330
    char* qcow_filename;
331
    BdrvChild* qcow;
332
    void* fat2;
333
    char* used_clusters;
334
    array_t commits;
335
    const char* path;
336
    int downcase_short_names;
337

338
    Error *migration_blocker;
339
} BDRVVVFATState;
340

341
/* take the sector position spos and convert it to Cylinder/Head/Sector position
342
 * if the position is outside the specified geometry, fill maximum value for CHS
343
 * and return 1 to signal overflow.
344
 */
345
static int sector2CHS(mbr_chs_t *chs, int spos, int cyls, int heads, int secs)
346
{
347
    int head,sector;
348
    sector   = spos % secs;  spos /= secs;
349
    head     = spos % heads; spos /= heads;
350
    if (spos >= cyls) {
351
        /* Overflow,
352
        it happens if 32bit sector positions are used, while CHS is only 24bit.
353
        Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
354
        chs->head     = 0xFF;
355
        chs->sector   = 0xFF;
356
        chs->cylinder = 0xFF;
357
        return 1;
358
    }
359
    chs->head     = (uint8_t)head;
360
    chs->sector   = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
361
    chs->cylinder = (uint8_t)spos;
362
    return 0;
363
}
364

365
static void init_mbr(BDRVVVFATState *s, int cyls, int heads, int secs)
366
{
367
    /* TODO: if the files mbr.img and bootsect.img exist, use them */
368
    mbr_t* real_mbr=(mbr_t*)s->first_sectors;
369
    partition_t* partition = &(real_mbr->partition[0]);
370
    int lba;
371

372
    memset(s->first_sectors,0,512);
373

374
    /* Win NT Disk Signature */
375
    real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
376

377
    partition->attributes=0x80; /* bootable */
378

379
    /* LBA is used when partition is outside the CHS geometry */
380
    lba  = sector2CHS(&partition->start_CHS, s->offset_to_bootsector,
381
                     cyls, heads, secs);
382
    lba |= sector2CHS(&partition->end_CHS,   s->bs->total_sectors - 1,
383
                     cyls, heads, secs);
384

385
    /*LBA partitions are identified only by start/length_sector_long not by CHS*/
386
    partition->start_sector_long  = cpu_to_le32(s->offset_to_bootsector);
387
    partition->length_sector_long = cpu_to_le32(s->bs->total_sectors
388
                                                - s->offset_to_bootsector);
389

390
    /* FAT12/FAT16/FAT32 */
391
    /* DOS uses different types when partition is LBA,
392
       probably to prevent older versions from using CHS on them */
393
    partition->fs_type = s->fat_type == 12 ? 0x1 :
394
                         s->fat_type == 16 ? (lba ? 0xe : 0x06) :
395
                       /*s->fat_type == 32*/ (lba ? 0xc : 0x0b);
396

397
    real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
398
}
399

400
/* direntry functions */
401

402
static direntry_t *create_long_filename(BDRVVVFATState *s, const char *filename)
403
{
404
    int number_of_entries, i;
405
    glong length;
406
    direntry_t *entry;
407

408
    gunichar2 *longname = g_utf8_to_utf16(filename, -1, NULL, &length, NULL);
409
    if (!longname) {
410
        fprintf(stderr, "vvfat: invalid UTF-8 name: %s\n", filename);
411
        return NULL;
412
    }
413

414
    number_of_entries = DIV_ROUND_UP(length * 2, 26);
415

416
    for(i=0;i<number_of_entries;i++) {
417
        entry=array_get_next(&(s->directory));
418
        entry->attributes=0xf;
419
        entry->reserved[0]=0;
420
        entry->begin=0;
421
        entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
422
    }
423
    for(i=0;i<26*number_of_entries;i++) {
424
        int offset=(i%26);
425
        if(offset<10) offset=1+offset;
426
        else if(offset<22) offset=14+offset-10;
427
        else offset=28+offset-22;
428
        entry=array_get(&(s->directory),s->directory.next-1-(i/26));
429
        if (i >= 2 * length + 2) {
430
            entry->name[offset] = 0xff;
431
        } else if (i % 2 == 0) {
432
            entry->name[offset] = longname[i / 2] & 0xff;
433
        } else {
434
            entry->name[offset] = longname[i / 2] >> 8;
435
        }
436
    }
437
    g_free(longname);
438
    return array_get(&(s->directory),s->directory.next-number_of_entries);
439
}
440

441
static char is_free(const direntry_t* direntry)
442
{
443
    return direntry->name[0] == DIR_DELETED || direntry->name[0] == DIR_FREE;
444
}
445

446
static char is_volume_label(const direntry_t* direntry)
447
{
448
    return direntry->attributes == 0x28;
449
}
450

451
static char is_long_name(const direntry_t* direntry)
452
{
453
    return direntry->attributes == 0xf;
454
}
455

456
static char is_short_name(const direntry_t* direntry)
457
{
458
    return !is_volume_label(direntry) && !is_long_name(direntry)
459
        && !is_free(direntry);
460
}
461

462
static char is_directory(const direntry_t* direntry)
463
{
464
    return direntry->attributes & 0x10 && direntry->name[0] != DIR_DELETED;
465
}
466

467
static inline char is_dot(const direntry_t* direntry)
468
{
469
    return is_short_name(direntry) && direntry->name[0] == '.';
470
}
471

472
static char is_file(const direntry_t* direntry)
473
{
474
    return is_short_name(direntry) && !is_directory(direntry);
475
}
476

477
static inline uint32_t begin_of_direntry(const direntry_t* direntry)
478
{
479
    return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
480
}
481

482
static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
483
{
484
    return le32_to_cpu(direntry->size);
485
}
486

487
static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
488
{
489
    direntry->begin = cpu_to_le16(begin & 0xffff);
490
    direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
491
}
492

493
static bool valid_filename(const unsigned char *name)
494
{
495
    unsigned char c;
496
    if (!strcmp((const char*)name, ".") || !strcmp((const char*)name, "..")) {
497
        return false;
498
    }
499
    for (; (c = *name); name++) {
500
        if (!((c >= '0' && c <= '9') ||
501
              (c >= 'A' && c <= 'Z') ||
502
              (c >= 'a' && c <= 'z') ||
503
              c > 127 ||
504
              strchr(" $%'-_@~`!(){}^#&.+,;=[]", c) != NULL))
505
        {
506
            return false;
507
        }
508
    }
509
    return true;
510
}
511

512
static uint8_t to_valid_short_char(gunichar c)
513
{
514
    c = g_unichar_toupper(c);
515
    if ((c >= '0' && c <= '9') ||
516
        (c >= 'A' && c <= 'Z') ||
517
        strchr("$%'-_@~`!(){}^#&", c) != NULL) {
518
        return c;
519
    } else {
520
        return 0;
521
    }
522
}
523

524
static direntry_t *create_short_filename(BDRVVVFATState *s,
525
                                         const char *filename,
526
                                         unsigned int directory_start)
527
{
528
    int i, j = 0;
529
    direntry_t *entry = array_get_next(&(s->directory));
530
    const gchar *p, *last_dot = NULL;
531
    gunichar c;
532
    bool lossy_conversion = false;
533
    char tail[8];
534

535
    if (!entry) {
536
        return NULL;
537
    }
538
    memset(entry->name, 0x20, sizeof(entry->name));
539

540
    /* copy filename and search last dot */
541
    for (p = filename; ; p = g_utf8_next_char(p)) {
542
        c = g_utf8_get_char(p);
543
        if (c == '\0') {
544
            break;
545
        } else if (c == '.') {
546
            if (j == 0) {
547
                /* '.' at start of filename */
548
                lossy_conversion = true;
549
            } else {
550
                if (last_dot) {
551
                    lossy_conversion = true;
552
                }
553
                last_dot = p;
554
            }
555
        } else if (!last_dot) {
556
            /* first part of the name; copy it */
557
            uint8_t v = to_valid_short_char(c);
558
            if (j < 8 && v) {
559
                entry->name[j++] = v;
560
            } else {
561
                lossy_conversion = true;
562
            }
563
        }
564
    }
565

566
    /* copy extension (if any) */
567
    if (last_dot) {
568
        j = 0;
569
        for (p = g_utf8_next_char(last_dot); ; p = g_utf8_next_char(p)) {
570
            c = g_utf8_get_char(p);
571
            if (c == '\0') {
572
                break;
573
            } else {
574
                /* extension; copy it */
575
                uint8_t v = to_valid_short_char(c);
576
                if (j < 3 && v) {
577
                    entry->name[8 + (j++)] = v;
578
                } else {
579
                    lossy_conversion = true;
580
                }
581
            }
582
        }
583
    }
584

585
    if (entry->name[0] == DIR_KANJI) {
586
        entry->name[0] = DIR_KANJI_FAKE;
587
    }
588

589
    /* numeric-tail generation */
590
    for (j = 0; j < 8; j++) {
591
        if (entry->name[j] == ' ') {
592
            break;
593
        }
594
    }
595
    for (i = lossy_conversion ? 1 : 0; i < 999999; i++) {
596
        direntry_t *entry1;
597
        if (i > 0) {
598
            int len = snprintf(tail, sizeof(tail), "~%u", (unsigned)i);
599
            assert(len <= 7);
600
            memcpy(entry->name + MIN(j, 8 - len), tail, len);
601
        }
602
        for (entry1 = array_get(&(s->directory), directory_start);
603
             entry1 < entry; entry1++) {
604
            if (!is_long_name(entry1) &&
605
                !memcmp(entry1->name, entry->name, 11)) {
606
                break; /* found dupe */
607
            }
608
        }
609
        if (entry1 == entry) {
610
            /* no dupe found */
611
            return entry;
612
        }
613
    }
614
    return NULL;
615
}
616

617
/* fat functions */
618

619
static inline uint8_t fat_chksum(const direntry_t* entry)
620
{
621
    uint8_t chksum=0;
622
    int i;
623

624
    for (i = 0; i < ARRAY_SIZE(entry->name); i++) {
625
        chksum = (((chksum & 0xfe) >> 1) |
626
                  ((chksum & 0x01) ? 0x80 : 0)) + entry->name[i];
627
    }
628

629
    return chksum;
630
}
631

632
/* if return_time==0, this returns the fat_date, else the fat_time */
633
static uint16_t fat_datetime(time_t time,int return_time) {
634
    struct tm* t;
635
    struct tm t1;
636
    t = &t1;
637
    localtime_r(&time,t);
638
    if(return_time)
639
        return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
640
    return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
641
}
642

643
static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
644
{
645
    if(s->fat_type==32) {
646
        uint32_t* entry=array_get(&(s->fat),cluster);
647
        *entry=cpu_to_le32(value);
648
    } else if(s->fat_type==16) {
649
        uint16_t* entry=array_get(&(s->fat),cluster);
650
        *entry=cpu_to_le16(value&0xffff);
651
    } else {
652
        int offset = (cluster*3/2);
653
        unsigned char* p = array_get(&(s->fat), offset);
654
        switch (cluster&1) {
655
        case 0:
656
                p[0] = value&0xff;
657
                p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
658
                break;
659
        case 1:
660
                p[0] = (p[0]&0xf) | ((value&0xf)<<4);
661
                p[1] = (value>>4);
662
                break;
663
        }
664
    }
665
}
666

667
static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
668
{
669
    if(s->fat_type==32) {
670
        uint32_t* entry=array_get(&(s->fat),cluster);
671
        return le32_to_cpu(*entry);
672
    } else if(s->fat_type==16) {
673
        uint16_t* entry=array_get(&(s->fat),cluster);
674
        return le16_to_cpu(*entry);
675
    } else {
676
        const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
677
        return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
678
    }
679
}
680

681
static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
682
{
683
    if(fat_entry>s->max_fat_value-8)
684
        return -1;
685
    return 0;
686
}
687

688
static inline void init_fat(BDRVVVFATState* s)
689
{
690
    if (s->fat_type == 12) {
691
        array_init(&(s->fat),1);
692
        array_ensure_allocated(&(s->fat),
693
                s->sectors_per_fat * 0x200 * 3 / 2 - 1);
694
    } else {
695
        array_init(&(s->fat),(s->fat_type==32?4:2));
696
        array_ensure_allocated(&(s->fat),
697
                s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
698
    }
699
    memset(s->fat.pointer,0,s->fat.size);
700

701
    switch(s->fat_type) {
702
        case 12: s->max_fat_value=0xfff; break;
703
        case 16: s->max_fat_value=0xffff; break;
704
        case 32: s->max_fat_value=0x0fffffff; break;
705
        default: s->max_fat_value=0; /* error... */
706
    }
707

708
}
709

710
static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
711
        unsigned int directory_start, const char* filename, int is_dot)
712
{
713
    int long_index = s->directory.next;
714
    direntry_t* entry = NULL;
715
    direntry_t* entry_long = NULL;
716

717
    if(is_dot) {
718
        entry=array_get_next(&(s->directory));
719
        memset(entry->name, 0x20, sizeof(entry->name));
720
        memcpy(entry->name,filename,strlen(filename));
721
        return entry;
722
    }
723

724
    entry_long=create_long_filename(s,filename);
725
    entry = create_short_filename(s, filename, directory_start);
726

727
    /* calculate checksum; propagate to long name */
728
    if(entry_long) {
729
        uint8_t chksum=fat_chksum(entry);
730

731
        /* calculate anew, because realloc could have taken place */
732
        entry_long=array_get(&(s->directory),long_index);
733
        while(entry_long<entry && is_long_name(entry_long)) {
734
            entry_long->reserved[1]=chksum;
735
            entry_long++;
736
        }
737
    }
738

739
    return entry;
740
}
741

742
/*
743
 * Read a directory. (the index of the corresponding mapping must be passed).
744
 */
745
static int read_directory(BDRVVVFATState* s, int mapping_index)
746
{
747
    mapping_t* mapping = array_get(&(s->mapping), mapping_index);
748
    direntry_t* direntry;
749
    const char* dirname = mapping->path;
750
    int first_cluster = mapping->begin;
751
    int parent_index = mapping->info.dir.parent_mapping_index;
752
    mapping_t* parent_mapping = (mapping_t*)
753
        (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL);
754
    int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
755

756
    DIR* dir=opendir(dirname);
757
    struct dirent* entry;
758
    int i;
759

760
    assert(mapping->mode & MODE_DIRECTORY);
761

762
    if(!dir) {
763
        mapping->end = mapping->begin;
764
        return -1;
765
    }
766

767
    i = mapping->info.dir.first_dir_index =
768
            first_cluster == 0 ? 0 : s->directory.next;
769

770
    if (first_cluster != 0) {
771
        /* create the top entries of a subdirectory */
772
        (void)create_short_and_long_name(s, i, ".", 1);
773
        (void)create_short_and_long_name(s, i, "..", 1);
774
    }
775

776
    /* actually read the directory, and allocate the mappings */
777
    while((entry=readdir(dir))) {
778
        unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
779
        char* buffer;
780
        struct stat st;
781
        int is_dot=!strcmp(entry->d_name,".");
782
        int is_dotdot=!strcmp(entry->d_name,"..");
783

784
        if (first_cluster == 0 && s->directory.next >= s->root_entries - 1) {
785
            fprintf(stderr, "Too many entries in root directory\n");
786
            closedir(dir);
787
            return -2;
788
        }
789

790
        if(first_cluster == 0 && (is_dotdot || is_dot))
791
            continue;
792

793
        buffer = g_malloc(length);
794
        snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
795

796
        if(stat(buffer,&st)<0) {
797
            g_free(buffer);
798
            continue;
799
        }
800

801
        /* create directory entry for this file */
802
        if (!is_dot && !is_dotdot) {
803
            direntry = create_short_and_long_name(s, i, entry->d_name, 0);
804
        } else {
805
            direntry = array_get(&(s->directory), is_dot ? i : i + 1);
806
        }
807
        direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
808
        direntry->reserved[0]=direntry->reserved[1]=0;
809
        direntry->ctime=fat_datetime(st.st_ctime,1);
810
        direntry->cdate=fat_datetime(st.st_ctime,0);
811
        direntry->adate=fat_datetime(st.st_atime,0);
812
        direntry->begin_hi=0;
813
        direntry->mtime=fat_datetime(st.st_mtime,1);
814
        direntry->mdate=fat_datetime(st.st_mtime,0);
815
        if(is_dotdot)
816
            set_begin_of_direntry(direntry, first_cluster_of_parent);
817
        else if(is_dot)
818
            set_begin_of_direntry(direntry, first_cluster);
819
        else
820
            direntry->begin=0; /* do that later */
821
        if (st.st_size > 0x7fffffff) {
822
            fprintf(stderr, "File %s is larger than 2GB\n", buffer);
823
            g_free(buffer);
824
            closedir(dir);
825
            return -2;
826
        }
827
        direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
828

829
        /* create mapping for this file */
830
        if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
831
            s->current_mapping = array_get_next(&(s->mapping));
832
            s->current_mapping->begin=0;
833
            s->current_mapping->end=st.st_size;
834
            /*
835
             * we get the direntry of the most recent direntry, which
836
             * contains the short name and all the relevant information.
837
             */
838
            s->current_mapping->dir_index=s->directory.next-1;
839
            s->current_mapping->first_mapping_index = -1;
840
            if (S_ISDIR(st.st_mode)) {
841
                s->current_mapping->mode = MODE_DIRECTORY;
842
                s->current_mapping->info.dir.parent_mapping_index =
843
                    mapping_index;
844
            } else {
845
                s->current_mapping->mode = MODE_UNDEFINED;
846
                s->current_mapping->info.file.offset = 0;
847
            }
848
            s->current_mapping->path=buffer;
849
            s->current_mapping->read_only =
850
                (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
851
        } else {
852
            g_free(buffer);
853
        }
854
    }
855
    closedir(dir);
856

857
    /* fill with zeroes up to the end of the cluster */
858
    while(s->directory.next%(0x10*s->sectors_per_cluster)) {
859
        direntry = array_get_next(&(s->directory));
860
        memset(direntry,0,sizeof(direntry_t));
861
    }
862

863
    if (s->fat_type != 32 &&
864
        mapping_index == 0 &&
865
        s->directory.next < s->root_entries) {
866
        /* root directory */
867
        int cur = s->directory.next;
868
        array_ensure_allocated(&(s->directory), s->root_entries - 1);
869
        s->directory.next = s->root_entries;
870
        memset(array_get(&(s->directory), cur), 0,
871
                (s->root_entries - cur) * sizeof(direntry_t));
872
    }
873

874
    /* re-get the mapping, since s->mapping was possibly realloc()ed */
875
    mapping = array_get(&(s->mapping), mapping_index);
876
    first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
877
        * 0x20 / s->cluster_size;
878
    mapping->end = first_cluster;
879

880
    direntry = array_get(&(s->directory), mapping->dir_index);
881
    set_begin_of_direntry(direntry, mapping->begin);
882

883
    return 0;
884
}
885

886
static inline int32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
887
{
888
    return (sector_num - s->offset_to_root_dir) / s->sectors_per_cluster;
889
}
890

891
static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
892
{
893
    return s->offset_to_root_dir + s->sectors_per_cluster * cluster_num;
894
}
895

896
static int init_directories(BDRVVVFATState* s,
897
                            const char *dirname, int heads, int secs,
898
                            Error **errp)
899
{
900
    bootsector_t* bootsector;
901
    mapping_t* mapping;
902
    unsigned int i;
903
    unsigned int cluster;
904

905
    memset(&(s->first_sectors[0]),0,0x40*0x200);
906

907
    s->cluster_size=s->sectors_per_cluster*0x200;
908
    s->cluster_buffer=g_malloc(s->cluster_size);
909

910
    /*
911
     * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
912
     * where sc is sector_count,
913
     * spf is sectors_per_fat,
914
     * spc is sectors_per_clusters, and
915
     * fat_type = 12, 16 or 32.
916
     */
917
    i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
918
    s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
919

920
    s->offset_to_fat = s->offset_to_bootsector + 1;
921
    s->offset_to_root_dir = s->offset_to_fat + s->sectors_per_fat * 2;
922

923
    array_init(&(s->mapping),sizeof(mapping_t));
924
    array_init(&(s->directory),sizeof(direntry_t));
925

926
    /* add volume label */
927
    {
928
        direntry_t* entry=array_get_next(&(s->directory));
929
        entry->attributes=0x28; /* archive | volume label */
930
        memcpy(entry->name, s->volume_label, sizeof(entry->name));
931
    }
932

933
    /* Now build FAT, and write back information into directory */
934
    init_fat(s);
935

936
    /* TODO: if there are more entries, bootsector has to be adjusted! */
937
    s->root_entries = 0x02 * 0x10 * s->sectors_per_cluster;
938
    s->cluster_count=sector2cluster(s, s->sector_count);
939

940
    mapping = array_get_next(&(s->mapping));
941
    mapping->begin = 0;
942
    mapping->dir_index = 0;
943
    mapping->info.dir.parent_mapping_index = -1;
944
    mapping->first_mapping_index = -1;
945
    mapping->path = g_strdup(dirname);
946
    i = strlen(mapping->path);
947
    if (i > 0 && mapping->path[i - 1] == '/')
948
        mapping->path[i - 1] = '\0';
949
    mapping->mode = MODE_DIRECTORY;
950
    mapping->read_only = 0;
951
    s->path = mapping->path;
952

953
    for (i = 0, cluster = 0; i < s->mapping.next; i++) {
954
        /* MS-DOS expects the FAT to be 0 for the root directory
955
         * (except for the media byte). */
956
        /* LATER TODO: still true for FAT32? */
957
        int fix_fat = (i != 0);
958
        mapping = array_get(&(s->mapping), i);
959

960
        if (mapping->mode & MODE_DIRECTORY) {
961
            char *path = mapping->path;
962
            mapping->begin = cluster;
963
            if(read_directory(s, i)) {
964
                error_setg(errp, "Could not read directory %s", path);
965
                return -1;
966
            }
967
            mapping = array_get(&(s->mapping), i);
968
        } else {
969
            assert(mapping->mode == MODE_UNDEFINED);
970
            mapping->mode=MODE_NORMAL;
971
            mapping->begin = cluster;
972
            if (mapping->end > 0) {
973
                direntry_t* direntry = array_get(&(s->directory),
974
                        mapping->dir_index);
975

976
                mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
977
                set_begin_of_direntry(direntry, mapping->begin);
978
            } else {
979
                mapping->end = cluster + 1;
980
                fix_fat = 0;
981
            }
982
        }
983

984
        assert(mapping->begin < mapping->end);
985

986
        /* next free cluster */
987
        cluster = mapping->end;
988

989
        if(cluster > s->cluster_count) {
990
            error_setg(errp,
991
                       "Directory does not fit in FAT%d (capacity %.2f MB)",
992
                       s->fat_type, s->sector_count / 2000.0);
993
            return -1;
994
        }
995

996
        /* fix fat for entry */
997
        if (fix_fat) {
998
            int j;
999
            for(j = mapping->begin; j < mapping->end - 1; j++)
1000
                fat_set(s, j, j+1);
1001
            fat_set(s, mapping->end - 1, s->max_fat_value);
1002
        }
1003
    }
1004

1005
    mapping = array_get(&(s->mapping), 0);
1006
    s->last_cluster_of_root_directory = mapping->end;
1007

1008
    /* the FAT signature */
1009
    fat_set(s,0,s->max_fat_value);
1010
    fat_set(s,1,s->max_fat_value);
1011

1012
    s->current_mapping = NULL;
1013

1014
    bootsector = (bootsector_t *)(s->first_sectors
1015
                                  + s->offset_to_bootsector * 0x200);
1016
    bootsector->jump[0]=0xeb;
1017
    bootsector->jump[1]=0x3e;
1018
    bootsector->jump[2]=0x90;
1019
    memcpy(bootsector->name, BOOTSECTOR_OEM_NAME, 8);
1020
    bootsector->sector_size=cpu_to_le16(0x200);
1021
    bootsector->sectors_per_cluster=s->sectors_per_cluster;
1022
    bootsector->reserved_sectors=cpu_to_le16(1);
1023
    bootsector->number_of_fats=0x2; /* number of FATs */
1024
    bootsector->root_entries = cpu_to_le16(s->root_entries);
1025
    bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
1026
    /* media descriptor: hard disk=0xf8, floppy=0xf0 */
1027
    bootsector->media_type = (s->offset_to_bootsector > 0 ? 0xf8 : 0xf0);
1028
    s->fat.pointer[0] = bootsector->media_type;
1029
    bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
1030
    bootsector->sectors_per_track = cpu_to_le16(secs);
1031
    bootsector->number_of_heads = cpu_to_le16(heads);
1032
    bootsector->hidden_sectors = cpu_to_le32(s->offset_to_bootsector);
1033
    bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
1034

1035
    /* LATER TODO: if FAT32, this is wrong */
1036
    /* drive_number: fda=0, hda=0x80 */
1037
    bootsector->u.fat16.drive_number = s->offset_to_bootsector == 0 ? 0 : 0x80;
1038
    bootsector->u.fat16.signature=0x29;
1039
    bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
1040

1041
    memcpy(bootsector->u.fat16.volume_label, s->volume_label,
1042
           sizeof(bootsector->u.fat16.volume_label));
1043
    memcpy(bootsector->u.fat16.fat_type,
1044
           s->fat_type == 12 ? "FAT12   " : "FAT16   ", 8);
1045
    bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
1046

1047
    return 0;
1048
}
1049

1050
#ifdef DEBUG
1051
static BDRVVVFATState *vvv = NULL;
1052
#endif
1053

1054
static int enable_write_target(BlockDriverState *bs, Error **errp);
1055
static int coroutine_fn is_consistent(BDRVVVFATState *s);
1056

1057
static QemuOptsList runtime_opts = {
1058
    .name = "vvfat",
1059
    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
1060
    .desc = {
1061
        {
1062
            .name = "dir",
1063
            .type = QEMU_OPT_STRING,
1064
            .help = "Host directory to map to the vvfat device",
1065
        },
1066
        {
1067
            .name = "fat-type",
1068
            .type = QEMU_OPT_NUMBER,
1069
            .help = "FAT type (12, 16 or 32)",
1070
        },
1071
        {
1072
            .name = "floppy",
1073
            .type = QEMU_OPT_BOOL,
1074
            .help = "Create a floppy rather than a hard disk image",
1075
        },
1076
        {
1077
            .name = "label",
1078
            .type = QEMU_OPT_STRING,
1079
            .help = "Use a volume label other than QEMU VVFAT",
1080
        },
1081
        {
1082
            .name = "rw",
1083
            .type = QEMU_OPT_BOOL,
1084
            .help = "Make the image writable",
1085
        },
1086
        { /* end of list */ }
1087
    },
1088
};
1089

1090
static void vvfat_parse_filename(const char *filename, QDict *options,
1091
                                 Error **errp)
1092
{
1093
    int fat_type = 0;
1094
    bool floppy = false;
1095
    bool rw = false;
1096
    int i;
1097

1098
    if (!strstart(filename, "fat:", NULL)) {
1099
        error_setg(errp, "File name string must start with 'fat:'");
1100
        return;
1101
    }
1102

1103
    /* Parse options */
1104
    if (strstr(filename, ":32:")) {
1105
        fat_type = 32;
1106
    } else if (strstr(filename, ":16:")) {
1107
        fat_type = 16;
1108
    } else if (strstr(filename, ":12:")) {
1109
        fat_type = 12;
1110
    }
1111

1112
    if (strstr(filename, ":floppy:")) {
1113
        floppy = true;
1114
    }
1115

1116
    if (strstr(filename, ":rw:")) {
1117
        rw = true;
1118
    }
1119

1120
    /* Get the directory name without options */
1121
    i = strrchr(filename, ':') - filename;
1122
    assert(i >= 3);
1123
    if (filename[i - 2] == ':' && qemu_isalpha(filename[i - 1])) {
1124
        /* workaround for DOS drive names */
1125
        filename += i - 1;
1126
    } else {
1127
        filename += i + 1;
1128
    }
1129

1130
    /* Fill in the options QDict */
1131
    qdict_put_str(options, "dir", filename);
1132
    qdict_put_int(options, "fat-type", fat_type);
1133
    qdict_put_bool(options, "floppy", floppy);
1134
    qdict_put_bool(options, "rw", rw);
1135
}
1136

1137
static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
1138
                      Error **errp)
1139
{
1140
    BDRVVVFATState *s = bs->opaque;
1141
    int cyls, heads, secs;
1142
    bool floppy;
1143
    const char *dirname, *label;
1144
    QemuOpts *opts;
1145
    int ret;
1146

1147
    GRAPH_RDLOCK_GUARD_MAINLOOP();
1148

1149
#ifdef DEBUG
1150
    vvv = s;
1151
#endif
1152

1153
    opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
1154
    if (!qemu_opts_absorb_qdict(opts, options, errp)) {
1155
        ret = -EINVAL;
1156
        goto fail;
1157
    }
1158

1159
    dirname = qemu_opt_get(opts, "dir");
1160
    if (!dirname) {
1161
        error_setg(errp, "vvfat block driver requires a 'dir' option");
1162
        ret = -EINVAL;
1163
        goto fail;
1164
    }
1165

1166
    s->fat_type = qemu_opt_get_number(opts, "fat-type", 0);
1167
    floppy = qemu_opt_get_bool(opts, "floppy", false);
1168

1169
    memset(s->volume_label, ' ', sizeof(s->volume_label));
1170
    label = qemu_opt_get(opts, "label");
1171
    if (label) {
1172
        size_t label_length = strlen(label);
1173
        if (label_length > 11) {
1174
            error_setg(errp, "vvfat label cannot be longer than 11 bytes");
1175
            ret = -EINVAL;
1176
            goto fail;
1177
        }
1178
        memcpy(s->volume_label, label, label_length);
1179
    } else {
1180
        memcpy(s->volume_label, "QEMU VVFAT", 10);
1181
    }
1182

1183
    if (floppy) {
1184
        /* 1.44MB or 2.88MB floppy.  2.88MB can be FAT12 (default) or FAT16. */
1185
        if (!s->fat_type) {
1186
            s->fat_type = 12;
1187
            secs = 36;
1188
            s->sectors_per_cluster = 2;
1189
        } else {
1190
            secs = s->fat_type == 12 ? 18 : 36;
1191
            s->sectors_per_cluster = 1;
1192
        }
1193
        cyls = 80;
1194
        heads = 2;
1195
    } else {
1196
        /* 32MB or 504MB disk*/
1197
        if (!s->fat_type) {
1198
            s->fat_type = 16;
1199
        }
1200
        s->offset_to_bootsector = 0x3f;
1201
        cyls = s->fat_type == 12 ? 64 : 1024;
1202
        heads = 16;
1203
        secs = 63;
1204
    }
1205

1206
    switch (s->fat_type) {
1207
    case 32:
1208
        warn_report("FAT32 has not been tested. You are welcome to do so!");
1209
        break;
1210
    case 16:
1211
    case 12:
1212
        break;
1213
    default:
1214
        error_setg(errp, "Valid FAT types are only 12, 16 and 32");
1215
        ret = -EINVAL;
1216
        goto fail;
1217
    }
1218

1219

1220
    s->bs = bs;
1221

1222
    /* LATER TODO: if FAT32, adjust */
1223
    s->sectors_per_cluster=0x10;
1224

1225
    s->current_cluster=0xffffffff;
1226

1227
    s->qcow = NULL;
1228
    s->qcow_filename = NULL;
1229
    s->fat2 = NULL;
1230
    s->downcase_short_names = 1;
1231

1232
    DLOG(fprintf(stderr, "vvfat %s chs %d,%d,%d\n",
1233
                 dirname, cyls, heads, secs));
1234

1235
    s->sector_count = cyls * heads * secs - s->offset_to_bootsector;
1236
    bs->total_sectors = cyls * heads * secs;
1237

1238
    if (qemu_opt_get_bool(opts, "rw", false)) {
1239
        if (!bdrv_is_read_only(bs)) {
1240
            ret = enable_write_target(bs, errp);
1241
            if (ret < 0) {
1242
                goto fail;
1243
            }
1244
        } else {
1245
            ret = -EPERM;
1246
            error_setg(errp,
1247
                       "Unable to set VVFAT to 'rw' when drive is read-only");
1248
            goto fail;
1249
        }
1250
    } else {
1251
        ret = bdrv_apply_auto_read_only(bs, NULL, errp);
1252
        if (ret < 0) {
1253
            goto fail;
1254
        }
1255
    }
1256

1257
    if (init_directories(s, dirname, heads, secs, errp)) {
1258
        ret = -EIO;
1259
        goto fail;
1260
    }
1261

1262
    s->sector_count = s->offset_to_root_dir
1263
                    + s->sectors_per_cluster * s->cluster_count;
1264

1265
    /* Disable migration when vvfat is used rw */
1266
    if (s->qcow) {
1267
        error_setg(&s->migration_blocker,
1268
                   "The vvfat (rw) format used by node '%s' "
1269
                   "does not support live migration",
1270
                   bdrv_get_device_or_node_name(bs));
1271
        ret = migrate_add_blocker_normal(&s->migration_blocker, errp);
1272
        if (ret < 0) {
1273
            goto fail;
1274
        }
1275
    }
1276

1277
    if (s->offset_to_bootsector > 0) {
1278
        init_mbr(s, cyls, heads, secs);
1279
    }
1280

1281
    qemu_co_mutex_init(&s->lock);
1282

1283
    qemu_opts_del(opts);
1284

1285
    return 0;
1286

1287
fail:
1288
    g_free(s->qcow_filename);
1289
    s->qcow_filename = NULL;
1290
    g_free(s->cluster_buffer);
1291
    s->cluster_buffer = NULL;
1292
    g_free(s->used_clusters);
1293
    s->used_clusters = NULL;
1294

1295
    qemu_opts_del(opts);
1296
    return ret;
1297
}
1298

1299
static void vvfat_refresh_limits(BlockDriverState *bs, Error **errp)
1300
{
1301
    bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */
1302
}
1303

1304
static inline void vvfat_close_current_file(BDRVVVFATState *s)
1305
{
1306
    if(s->current_mapping) {
1307
        s->current_mapping = NULL;
1308
        if (s->current_fd) {
1309
                qemu_close(s->current_fd);
1310
                s->current_fd = 0;
1311
        }
1312
    }
1313
    s->current_cluster = -1;
1314
}
1315

1316
/* mappings between index1 and index2-1 are supposed to be ordered
1317
 * return value is the index of the last mapping for which end>cluster_num
1318
 */
1319
static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1320
{
1321
    while(1) {
1322
        int index3;
1323
        mapping_t* mapping;
1324
        index3=(index1+index2)/2;
1325
        mapping=array_get(&(s->mapping),index3);
1326
        assert(mapping->begin < mapping->end);
1327
        if(mapping->begin>=cluster_num) {
1328
            assert(index2!=index3 || index2==0);
1329
            if(index2==index3)
1330
                return index1;
1331
            index2=index3;
1332
        } else {
1333
            if(index1==index3)
1334
                return mapping->end<=cluster_num ? index2 : index1;
1335
            index1=index3;
1336
        }
1337
        assert(index1<=index2);
1338
        DLOG(mapping=array_get(&(s->mapping),index1);
1339
        assert(mapping->begin<=cluster_num);
1340
        assert(index2 >= s->mapping.next ||
1341
                ((mapping = array_get(&(s->mapping),index2)) &&
1342
                mapping->end>cluster_num)));
1343
    }
1344
}
1345

1346
static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
1347
{
1348
    int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
1349
    mapping_t* mapping;
1350
    if(index>=s->mapping.next)
1351
        return NULL;
1352
    mapping=array_get(&(s->mapping),index);
1353
    if(mapping->begin>cluster_num)
1354
        return NULL;
1355
    assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
1356
    return mapping;
1357
}
1358

1359
static int open_file(BDRVVVFATState* s,mapping_t* mapping)
1360
{
1361
    if(!mapping)
1362
        return -1;
1363
    if(!s->current_mapping ||
1364
            strcmp(s->current_mapping->path,mapping->path)) {
1365
        /* open file */
1366
        int fd = qemu_open_old(mapping->path,
1367
                               O_RDONLY | O_BINARY | O_LARGEFILE);
1368
        if(fd<0)
1369
            return -1;
1370
        vvfat_close_current_file(s);
1371
        s->current_fd = fd;
1372
    }
1373

1374
    s->current_mapping = mapping;
1375
    return 0;
1376
}
1377

1378
static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1379
{
1380
    if(s->current_cluster != cluster_num) {
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;
1395
read_cluster_directory:
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 *
1413
            ((cluster_num - s->current_mapping->begin)
1414
            + s->current_mapping->info.file.offset);
1415
        if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1416
            return -3;
1417
        s->cluster=s->cluster_buffer;
1418
        result=read(s->current_fd,s->cluster,s->cluster_size);
1419
        if(result<0) {
1420
            s->current_cluster = -1;
1421
            return -1;
1422
        }
1423
        s->current_cluster = cluster_num;
1424
    }
1425
    return 0;
1426
}
1427

1428
#ifdef DEBUG
1429
static void print_direntry(const direntry_t* direntry)
1430
{
1431
    int j = 0;
1432
    char buffer[1024];
1433

1434
    fprintf(stderr, "direntry %p: ", direntry);
1435
    if(!direntry)
1436
        return;
1437
    if(is_long_name(direntry)) {
1438
        unsigned char* c=(unsigned char*)direntry;
1439
        int i;
1440
        for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
1441
#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
1442
            ADD_CHAR(c[i]);
1443
        for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
1444
            ADD_CHAR(c[i]);
1445
        for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
1446
            ADD_CHAR(c[i]);
1447
        buffer[j] = 0;
1448
        fprintf(stderr, "%s\n", buffer);
1449
    } else {
1450
        int i;
1451
        for(i=0;i<11;i++)
1452
            ADD_CHAR(direntry->name[i]);
1453
        buffer[j] = 0;
1454
        fprintf(stderr, "%s attributes=0x%02x begin=%u size=%u\n",
1455
                buffer,
1456
                direntry->attributes,
1457
                begin_of_direntry(direntry),le32_to_cpu(direntry->size));
1458
    }
1459
}
1460

1461
static void print_mapping(const mapping_t* mapping)
1462
{
1463
    fprintf(stderr, "mapping (%p): begin, end = %u, %u, dir_index = %u, "
1464
        "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1465
        mapping, mapping->begin, mapping->end, mapping->dir_index,
1466
        mapping->first_mapping_index, mapping->path, mapping->mode);
1467

1468
    if (mapping->mode & MODE_DIRECTORY)
1469
        fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1470
    else
1471
        fprintf(stderr, "offset = %u\n", mapping->info.file.offset);
1472
}
1473
#endif
1474

1475
static int coroutine_fn GRAPH_RDLOCK
1476
vvfat_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors)
1477
{
1478
    BDRVVVFATState *s = bs->opaque;
1479
    int i;
1480

1481
    for(i=0;i<nb_sectors;i++,sector_num++) {
1482
        if (sector_num >= bs->total_sectors)
1483
           return -1;
1484
        if (s->qcow) {
1485
            int64_t n;
1486
            int ret;
1487
            ret = bdrv_co_is_allocated(s->qcow->bs, sector_num * BDRV_SECTOR_SIZE,
1488
                                       (nb_sectors - i) * BDRV_SECTOR_SIZE, &n);
1489
            if (ret < 0) {
1490
                return ret;
1491
            }
1492
            if (ret) {
1493
                DLOG(fprintf(stderr, "sectors %" PRId64 "+%" PRId64
1494
                             " allocated\n", sector_num,
1495
                             n >> BDRV_SECTOR_BITS));
1496
                if (bdrv_co_pread(s->qcow, sector_num * BDRV_SECTOR_SIZE, n,
1497
                                  buf + i * 0x200, 0) < 0) {
1498
                    return -1;
1499
                }
1500
                i += (n >> BDRV_SECTOR_BITS) - 1;
1501
                sector_num += (n >> BDRV_SECTOR_BITS) - 1;
1502
                continue;
1503
            }
1504
            DLOG(fprintf(stderr, "sector %" PRId64 " not allocated\n",
1505
                         sector_num));
1506
        }
1507
        if (sector_num < s->offset_to_root_dir) {
1508
            if (sector_num < s->offset_to_fat) {
1509
                memcpy(buf + i * 0x200,
1510
                       &(s->first_sectors[sector_num * 0x200]),
1511
                       0x200);
1512
            } else if (sector_num < s->offset_to_fat + s->sectors_per_fat) {
1513
                memcpy(buf + i * 0x200,
1514
                       &(s->fat.pointer[(sector_num
1515
                                       - s->offset_to_fat) * 0x200]),
1516
                       0x200);
1517
            } else if (sector_num < s->offset_to_root_dir) {
1518
                memcpy(buf + i * 0x200,
1519
                       &(s->fat.pointer[(sector_num - s->offset_to_fat
1520
                                       - s->sectors_per_fat) * 0x200]),
1521
                       0x200);
1522
            }
1523
        } else {
1524
            uint32_t sector = sector_num - s->offset_to_root_dir,
1525
            sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1526
            cluster_num=sector/s->sectors_per_cluster;
1527
            if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) {
1528
                /* LATER TODO: strict: return -1; */
1529
                memset(buf+i*0x200,0,0x200);
1530
                continue;
1531
            }
1532
            memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
1533
        }
1534
    }
1535
    return 0;
1536
}
1537

1538
static int coroutine_fn GRAPH_RDLOCK
1539
vvfat_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
1540
                QEMUIOVector *qiov, BdrvRequestFlags flags)
1541
{
1542
    int ret;
1543
    BDRVVVFATState *s = bs->opaque;
1544
    uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
1545
    int nb_sectors = bytes >> BDRV_SECTOR_BITS;
1546
    void *buf;
1547

1548
    assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE));
1549
    assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE));
1550

1551
    buf = g_try_malloc(bytes);
1552
    if (bytes && buf == NULL) {
1553
        return -ENOMEM;
1554
    }
1555

1556
    qemu_co_mutex_lock(&s->lock);
1557
    ret = vvfat_read(bs, sector_num, buf, nb_sectors);
1558
    qemu_co_mutex_unlock(&s->lock);
1559

1560
    qemu_iovec_from_buf(qiov, 0, buf, bytes);
1561
    g_free(buf);
1562

1563
    return ret;
1564
}
1565

1566
/* LATER TODO: statify all functions */
1567

1568
/*
1569
 * Idea of the write support (use snapshot):
1570
 *
1571
 * 1. check if all data is consistent, recording renames, modifications,
1572
 *    new files and directories (in s->commits).
1573
 *
1574
 * 2. if the data is not consistent, stop committing
1575
 *
1576
 * 3. handle renames, and create new files and directories (do not yet
1577
 *    write their contents)
1578
 *
1579
 * 4. walk the directories, fixing the mapping and direntries, and marking
1580
 *    the handled mappings as not deleted
1581
 *
1582
 * 5. commit the contents of the files
1583
 *
1584
 * 6. handle deleted files and directories
1585
 *
1586
 */
1587

1588
typedef struct commit_t {
1589
    char* path;
1590
    union {
1591
        struct { uint32_t cluster; } rename;
1592
        struct { int dir_index; uint32_t modified_offset; } writeout;
1593
        struct { uint32_t first_cluster; } new_file;
1594
        struct { uint32_t cluster; } mkdir;
1595
    } param;
1596
    /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1597
    enum {
1598
        ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1599
    } action;
1600
} commit_t;
1601

1602
static void clear_commits(BDRVVVFATState* s)
1603
{
1604
    int i;
1605
DLOG(fprintf(stderr, "clear_commits (%u commits)\n", s->commits.next));
1606
    for (i = 0; i < s->commits.next; i++) {
1607
        commit_t* commit = array_get(&(s->commits), i);
1608
        assert(commit->path || commit->action == ACTION_WRITEOUT);
1609
        if (commit->action != ACTION_WRITEOUT) {
1610
            assert(commit->path);
1611
            g_free(commit->path);
1612
        } else
1613
            assert(commit->path == NULL);
1614
    }
1615
    s->commits.next = 0;
1616
}
1617

1618
static void schedule_rename(BDRVVVFATState* s,
1619
        uint32_t cluster, char* new_path)
1620
{
1621
    commit_t* commit = array_get_next(&(s->commits));
1622
    commit->path = new_path;
1623
    commit->param.rename.cluster = cluster;
1624
    commit->action = ACTION_RENAME;
1625
}
1626

1627
static void schedule_writeout(BDRVVVFATState* s,
1628
        int dir_index, uint32_t modified_offset)
1629
{
1630
    commit_t* commit = array_get_next(&(s->commits));
1631
    commit->path = NULL;
1632
    commit->param.writeout.dir_index = dir_index;
1633
    commit->param.writeout.modified_offset = modified_offset;
1634
    commit->action = ACTION_WRITEOUT;
1635
}
1636

1637
static void schedule_new_file(BDRVVVFATState* s,
1638
        char* path, uint32_t first_cluster)
1639
{
1640
    commit_t* commit = array_get_next(&(s->commits));
1641
    commit->path = path;
1642
    commit->param.new_file.first_cluster = first_cluster;
1643
    commit->action = ACTION_NEW_FILE;
1644
}
1645

1646
static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1647
{
1648
    commit_t* commit = array_get_next(&(s->commits));
1649
    commit->path = path;
1650
    commit->param.mkdir.cluster = cluster;
1651
    commit->action = ACTION_MKDIR;
1652
}
1653

1654
typedef struct {
1655
    /*
1656
     * Since the sequence number is at most 0x3f, and the filename
1657
     * length is at most 13 times the sequence number, the maximal
1658
     * filename length is 0x3f * 13 bytes.
1659
     */
1660
    unsigned char name[0x3f * 13 + 1];
1661
    gunichar2 name2[0x3f * 13 + 1];
1662
    int checksum, len;
1663
    int sequence_number;
1664
} long_file_name;
1665

1666
static void lfn_init(long_file_name* lfn)
1667
{
1668
   lfn->sequence_number = lfn->len = 0;
1669
   lfn->checksum = 0x100;
1670
}
1671

1672
/* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1673
static int parse_long_name(long_file_name* lfn,
1674
        const direntry_t* direntry)
1675
{
1676
    int i, j, offset;
1677
    const unsigned char* pointer = (const unsigned char*)direntry;
1678

1679
    if (!is_long_name(direntry))
1680
        return 1;
1681

1682
    if (pointer[0] & 0x40) {
1683
        /* first entry; do some initialization */
1684
        lfn->sequence_number = pointer[0] & 0x3f;
1685
        lfn->checksum = pointer[13];
1686
        lfn->name[0] = 0;
1687
        lfn->name[lfn->sequence_number * 13] = 0;
1688
    } else if ((pointer[0] & 0x3f) != --lfn->sequence_number) {
1689
        /* not the expected sequence number */
1690
        return -1;
1691
    } else if (pointer[13] != lfn->checksum) {
1692
        /* not the expected checksum */
1693
        return -2;
1694
    } else if (pointer[12] || pointer[26] || pointer[27]) {
1695
        /* invalid zero fields */
1696
        return -3;
1697
    }
1698

1699
    offset = 13 * (lfn->sequence_number - 1);
1700
    for (i = 0, j = 1; i < 13; i++, j+=2) {
1701
        if (j == 11)
1702
            j = 14;
1703
        else if (j == 26)
1704
            j = 28;
1705

1706
        if (pointer[j] == 0 && pointer[j + 1] == 0) {
1707
            /* end of long file name */
1708
            break;
1709
        }
1710
        gunichar2 c = (pointer[j + 1] << 8) + pointer[j];
1711
        lfn->name2[offset + i] = c;
1712
    }
1713

1714
    if (pointer[0] & 0x40) {
1715
        /* first entry; set len */
1716
        lfn->len = offset + i;
1717
    }
1718
    if ((pointer[0] & 0x3f) == 0x01) {
1719
        /* last entry; finalize entry */
1720
        glong olen;
1721
        gchar *utf8 = g_utf16_to_utf8(lfn->name2, lfn->len, NULL, &olen, NULL);
1722
        if (!utf8) {
1723
            return -4;
1724
        }
1725
        lfn->len = olen;
1726
        memcpy(lfn->name, utf8, olen + 1);
1727
        g_free(utf8);
1728
    }
1729

1730
    return 0;
1731
}
1732

1733
/* returns 0 if successful, >0 if no short_name, and <0 on error */
1734
static int parse_short_name(BDRVVVFATState* s,
1735
        long_file_name* lfn, direntry_t* direntry)
1736
{
1737
    int i, j;
1738

1739
    if (!is_short_name(direntry))
1740
        return 1;
1741

1742
    for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1743
    for (i = 0; i <= j; i++) {
1744
        uint8_t c = direntry->name[i];
1745
        if (c != to_valid_short_char(c)) {
1746
            return -1;
1747
        } else if (s->downcase_short_names) {
1748
            lfn->name[i] = qemu_tolower(direntry->name[i]);
1749
        } else {
1750
            lfn->name[i] = direntry->name[i];
1751
        }
1752
    }
1753

1754
    for (j = 2; j >= 0 && direntry->name[8 + j] == ' '; j--) {
1755
    }
1756
    if (j >= 0) {
1757
        lfn->name[i++] = '.';
1758
        lfn->name[i + j + 1] = '\0';
1759
        for (;j >= 0; j--) {
1760
            uint8_t c = direntry->name[8 + j];
1761
            if (c != to_valid_short_char(c)) {
1762
                return -2;
1763
            } else if (s->downcase_short_names) {
1764
                lfn->name[i + j] = qemu_tolower(c);
1765
            } else {
1766
                lfn->name[i + j] = c;
1767
            }
1768
        }
1769
    } else
1770
        lfn->name[i + j + 1] = '\0';
1771

1772
    if (lfn->name[0] == DIR_KANJI_FAKE) {
1773
        lfn->name[0] = DIR_KANJI;
1774
    }
1775
    lfn->len = strlen((char*)lfn->name);
1776

1777
    return 0;
1778
}
1779

1780
static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1781
        unsigned int cluster)
1782
{
1783
    if (cluster < s->last_cluster_of_root_directory) {
1784
        if (cluster + 1 == s->last_cluster_of_root_directory)
1785
            return s->max_fat_value;
1786
        else
1787
            return cluster + 1;
1788
    }
1789

1790
    if (s->fat_type==32) {
1791
        uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1792
        return le32_to_cpu(*entry);
1793
    } else if (s->fat_type==16) {
1794
        uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1795
        return le16_to_cpu(*entry);
1796
    } else {
1797
        const uint8_t* x=s->fat2+cluster*3/2;
1798
        return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1799
    }
1800
}
1801

1802
static inline bool coroutine_fn GRAPH_RDLOCK
1803
cluster_was_modified(BDRVVVFATState *s, uint32_t cluster_num)
1804
{
1805
    int was_modified = 0;
1806
    int i;
1807

1808
    if (s->qcow == NULL) {
1809
        return 0;
1810
    }
1811

1812
    for (i = 0; !was_modified && i < s->sectors_per_cluster; i++) {
1813
        was_modified = bdrv_co_is_allocated(s->qcow->bs,
1814
                                            (cluster2sector(s, cluster_num) +
1815
                                             i) * BDRV_SECTOR_SIZE,
1816
                                            BDRV_SECTOR_SIZE, NULL);
1817
    }
1818

1819
    /*
1820
     * Note that this treats failures to learn allocation status the
1821
     * same as if an allocation has occurred.  It's as safe as
1822
     * anything else, given that a failure to learn allocation status
1823
     * will probably result in more failures.
1824
     */
1825
    return !!was_modified;
1826
}
1827

1828
static const char* get_basename(const char* path)
1829
{
1830
    char* basename = strrchr(path, '/');
1831
    if (basename == NULL)
1832
        return path;
1833
    else
1834
        return basename + 1; /* strip '/' */
1835
}
1836

1837
/*
1838
 * The array s->used_clusters holds the states of the clusters. If it is
1839
 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1840
 * was modified, bit 3 is set.
1841
 * If any cluster is allocated, but not part of a file or directory, this
1842
 * driver refuses to commit.
1843
 */
1844
typedef enum {
1845
     USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
1846
} used_t;
1847

1848
/*
1849
 * get_cluster_count_for_direntry() not only determines how many clusters
1850
 * are occupied by direntry, but also if it was renamed or modified.
1851
 *
1852
 * A file is thought to be renamed *only* if there already was a file with
1853
 * exactly the same first cluster, but a different name.
1854
 *
1855
 * Further, the files/directories handled by this function are
1856
 * assumed to be *not* deleted (and *only* those).
1857
 */
1858
static uint32_t coroutine_fn GRAPH_RDLOCK
1859
get_cluster_count_for_direntry(BDRVVVFATState* s, direntry_t* direntry, const char* path)
1860
{
1861
    /*
1862
     * This is a little bit tricky:
1863
     * IF the guest OS just inserts a cluster into the file chain,
1864
     * and leaves the rest alone, (i.e. the original file had clusters
1865
     * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1866
     *
1867
     * - do_commit will write the cluster into the file at the given
1868
     *   offset, but
1869
     *
1870
     * - the cluster which is overwritten should be moved to a later
1871
     *   position in the file.
1872
     *
1873
     * I am not aware that any OS does something as braindead, but this
1874
     * situation could happen anyway when not committing for a long time.
1875
     * Just to be sure that this does not bite us, detect it, and copy the
1876
     * contents of the clusters to-be-overwritten into the qcow.
1877
     */
1878
    int copy_it = 0;
1879
    int was_modified = 0;
1880
    int32_t ret = 0;
1881

1882
    uint32_t cluster_num = begin_of_direntry(direntry);
1883
    uint32_t offset = 0;
1884
    mapping_t* mapping = NULL;
1885
    const char* basename2 = NULL;
1886

1887
    vvfat_close_current_file(s);
1888

1889
    /* the root directory */
1890
    if (cluster_num == 0)
1891
        return 0;
1892

1893
    /* write support */
1894
    if (s->qcow) {
1895
        basename2 = get_basename(path);
1896

1897
        mapping = find_mapping_for_cluster(s, cluster_num);
1898

1899
        if (mapping) {
1900
            const char* basename;
1901

1902
            assert(mapping->mode & MODE_DELETED);
1903
            mapping->mode &= ~MODE_DELETED;
1904

1905
            basename = get_basename(mapping->path);
1906

1907
            assert(mapping->mode & MODE_NORMAL);
1908

1909
            /* rename */
1910
            if (strcmp(basename, basename2))
1911
                schedule_rename(s, cluster_num, g_strdup(path));
1912
        } else if (is_file(direntry))
1913
            /* new file */
1914
            schedule_new_file(s, g_strdup(path), cluster_num);
1915
        else {
1916
            abort();
1917
            return 0;
1918
        }
1919
    }
1920

1921
    while(1) {
1922
        if (s->qcow) {
1923
            if (!copy_it && cluster_was_modified(s, cluster_num)) {
1924
                if (mapping == NULL ||
1925
                        mapping->begin > cluster_num ||
1926
                        mapping->end <= cluster_num)
1927
                mapping = find_mapping_for_cluster(s, cluster_num);
1928

1929

1930
                if (mapping &&
1931
                        (mapping->mode & MODE_DIRECTORY) == 0) {
1932

1933
                    /* was modified in qcow */
1934
                    if (offset != s->cluster_size
1935
                            * ((cluster_num - mapping->begin)
1936
                            + mapping->info.file.offset)) {
1937
                        /* offset of this cluster in file chain has changed */
1938
                        abort();
1939
                        copy_it = 1;
1940
                    } else if (offset == 0) {
1941
                        const char* basename = get_basename(mapping->path);
1942

1943
                        if (strcmp(basename, basename2))
1944
                            copy_it = 1;
1945
                    }
1946
                    assert(mapping->first_mapping_index == -1
1947
                            || mapping->info.file.offset > 0);
1948

1949
                    /* need to write out? */
1950
                    if (!was_modified && is_file(direntry)) {
1951
                        was_modified = 1;
1952
                        schedule_writeout(s, mapping->dir_index, offset);
1953
                    }
1954
                }
1955
            }
1956

1957
            if (copy_it) {
1958
                int i;
1959
                /*
1960
                 * This is horribly inefficient, but that is okay, since
1961
                 * it is rarely executed, if at all.
1962
                 */
1963
                int64_t offs = cluster2sector(s, cluster_num);
1964

1965
                vvfat_close_current_file(s);
1966
                for (i = 0; i < s->sectors_per_cluster; i++) {
1967
                    int res;
1968

1969
                    res = bdrv_co_is_allocated(s->qcow->bs,
1970
                                               (offs + i) * BDRV_SECTOR_SIZE,
1971
                                               BDRV_SECTOR_SIZE, NULL);
1972
                    if (res < 0) {
1973
                        return -1;
1974
                    }
1975
                    if (!res) {
1976
                        res = vvfat_read(s->bs, offs, s->cluster_buffer, 1);
1977
                        if (res) {
1978
                            return -1;
1979
                        }
1980
                        res = bdrv_co_pwrite(s->qcow, offs * BDRV_SECTOR_SIZE,
1981
                                             BDRV_SECTOR_SIZE, s->cluster_buffer,
1982
                                             0);
1983
                        if (res < 0) {
1984
                            return -2;
1985
                        }
1986
                    }
1987
                }
1988
            }
1989
        }
1990

1991
        ret++;
1992
        if (s->used_clusters[cluster_num] & USED_ANY)
1993
            return 0;
1994
        s->used_clusters[cluster_num] = USED_FILE;
1995

1996
        cluster_num = modified_fat_get(s, cluster_num);
1997

1998
        if (fat_eof(s, cluster_num))
1999
            return ret;
2000
        else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
2001
            return -1;
2002

2003
        offset += s->cluster_size;
2004
    }
2005
}
2006

2007
/*
2008
 * This function looks at the modified data (qcow).
2009
 * It returns 0 upon inconsistency or error, and the number of clusters
2010
 * used by the directory, its subdirectories and their files.
2011
 */
2012
static int coroutine_fn GRAPH_RDLOCK
2013
check_directory_consistency(BDRVVVFATState *s, int cluster_num, const char* path)
2014
{
2015
    int ret = 0;
2016
    unsigned char* cluster = g_malloc(s->cluster_size);
2017
    direntry_t* direntries = (direntry_t*)cluster;
2018
    mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
2019

2020
    long_file_name lfn;
2021
    int path_len = strlen(path);
2022
    char path2[PATH_MAX + 1];
2023

2024
    assert(path_len < PATH_MAX); /* len was tested before! */
2025
    pstrcpy(path2, sizeof(path2), path);
2026
    path2[path_len] = '/';
2027
    path2[path_len + 1] = '\0';
2028

2029
    if (mapping) {
2030
        const char* basename = get_basename(mapping->path);
2031
        const char* basename2 = get_basename(path);
2032

2033
        assert(mapping->mode & MODE_DIRECTORY);
2034

2035
        assert(mapping->mode & MODE_DELETED);
2036
        mapping->mode &= ~MODE_DELETED;
2037

2038
        if (strcmp(basename, basename2))
2039
            schedule_rename(s, cluster_num, g_strdup(path));
2040
    } else
2041
        /* new directory */
2042
        schedule_mkdir(s, cluster_num, g_strdup(path));
2043

2044
    lfn_init(&lfn);
2045
    do {
2046
        int i;
2047
        int subret = 0;
2048

2049
        ret++;
2050

2051
        if (s->used_clusters[cluster_num] & USED_ANY) {
2052
            fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
2053
            goto fail;
2054
        }
2055
        s->used_clusters[cluster_num] = USED_DIRECTORY;
2056

2057
DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
2058
        subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
2059
                s->sectors_per_cluster);
2060
        if (subret) {
2061
            fprintf(stderr, "Error fetching direntries\n");
2062
        fail:
2063
            g_free(cluster);
2064
            return 0;
2065
        }
2066

2067
        for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
2068
            int cluster_count = 0;
2069

2070
DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i));
2071
            if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
2072
                    is_free(direntries + i))
2073
                continue;
2074

2075
            subret = parse_long_name(&lfn, direntries + i);
2076
            if (subret < 0) {
2077
                fprintf(stderr, "Error in long name\n");
2078
                goto fail;
2079
            }
2080
            if (subret == 0 || is_free(direntries + i))
2081
                continue;
2082

2083
            if (fat_chksum(direntries+i) != lfn.checksum) {
2084
                subret = parse_short_name(s, &lfn, direntries + i);
2085
                if (subret < 0) {
2086
                    fprintf(stderr, "Error in short name (%d)\n", subret);
2087
                    goto fail;
2088
                }
2089
                if (subret > 0 || !strcmp((char*)lfn.name, ".")
2090
                        || !strcmp((char*)lfn.name, ".."))
2091
                    continue;
2092
            }
2093
            lfn.checksum = 0x100; /* cannot use long name twice */
2094

2095
            if (!valid_filename(lfn.name)) {
2096
                fprintf(stderr, "Invalid file name\n");
2097
                goto fail;
2098
            }
2099
            if (path_len + 1 + lfn.len >= PATH_MAX) {
2100
                fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
2101
                goto fail;
2102
            }
2103
            pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
2104
                    (char*)lfn.name);
2105

2106
            if (is_directory(direntries + i)) {
2107
                if (begin_of_direntry(direntries + i) == 0) {
2108
                    DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
2109
                    goto fail;
2110
                }
2111
                cluster_count = check_directory_consistency(s,
2112
                        begin_of_direntry(direntries + i), path2);
2113
                if (cluster_count == 0) {
2114
                    DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
2115
                    goto fail;
2116
                }
2117
            } else if (is_file(direntries + i)) {
2118
                /* check file size with FAT */
2119
                cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
2120
                if (cluster_count !=
2121
            DIV_ROUND_UP(le32_to_cpu(direntries[i].size), s->cluster_size)) {
2122
                    DLOG(fprintf(stderr, "Cluster count mismatch\n"));
2123
                    goto fail;
2124
                }
2125
            } else
2126
                abort(); /* cluster_count = 0; */
2127

2128
            ret += cluster_count;
2129
        }
2130

2131
        cluster_num = modified_fat_get(s, cluster_num);
2132
    } while(!fat_eof(s, cluster_num));
2133

2134
    g_free(cluster);
2135
    return ret;
2136
}
2137

2138
/* returns 1 on success */
2139
static int coroutine_fn GRAPH_RDLOCK
2140
is_consistent(BDRVVVFATState* s)
2141
{
2142
    int i, check;
2143
    int used_clusters_count = 0;
2144

2145
DLOG(checkpoint());
2146
    /*
2147
     * - get modified FAT
2148
     * - compare the two FATs (TODO)
2149
     * - get buffer for marking used clusters
2150
     * - recurse direntries from root (using bs->bdrv_pread to make
2151
     *    sure to get the new data)
2152
     *   - check that the FAT agrees with the size
2153
     *   - count the number of clusters occupied by this directory and
2154
     *     its files
2155
     * - check that the cumulative used cluster count agrees with the
2156
     *   FAT
2157
     * - if all is fine, return number of used clusters
2158
     */
2159
    if (s->fat2 == NULL) {
2160
        int size = 0x200 * s->sectors_per_fat;
2161
        s->fat2 = g_malloc(size);
2162
        memcpy(s->fat2, s->fat.pointer, size);
2163
    }
2164
    check = vvfat_read(s->bs,
2165
            s->offset_to_fat, s->fat2, s->sectors_per_fat);
2166
    if (check) {
2167
        fprintf(stderr, "Could not copy fat\n");
2168
        return 0;
2169
    }
2170
    assert (s->used_clusters);
2171
    for (i = 0; i < sector2cluster(s, s->sector_count); i++)
2172
        s->used_clusters[i] &= ~USED_ANY;
2173

2174
    clear_commits(s);
2175

2176
    /* mark every mapped file/directory as deleted.
2177
     * (check_directory_consistency() will unmark those still present). */
2178
    if (s->qcow)
2179
        for (i = 0; i < s->mapping.next; i++) {
2180
            mapping_t* mapping = array_get(&(s->mapping), i);
2181
            if (mapping->first_mapping_index < 0)
2182
                mapping->mode |= MODE_DELETED;
2183
        }
2184

2185
    used_clusters_count = check_directory_consistency(s, 0, s->path);
2186
    if (used_clusters_count <= 0) {
2187
        DLOG(fprintf(stderr, "problem in directory\n"));
2188
        return 0;
2189
    }
2190

2191
    check = s->last_cluster_of_root_directory;
2192
    for (i = check; i < sector2cluster(s, s->sector_count); i++) {
2193
        if (modified_fat_get(s, i)) {
2194
            if(!s->used_clusters[i]) {
2195
                DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
2196
                return 0;
2197
            }
2198
            check++;
2199
        }
2200

2201
        if (s->used_clusters[i] == USED_ALLOCATED) {
2202
            /* allocated, but not used... */
2203
            DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
2204
            return 0;
2205
        }
2206
    }
2207

2208
    if (check != used_clusters_count)
2209
        return 0;
2210

2211
    return used_clusters_count;
2212
}
2213

2214
static inline void adjust_mapping_indices(BDRVVVFATState* s,
2215
        int offset, int adjust)
2216
{
2217
    int i;
2218

2219
    for (i = 0; i < s->mapping.next; i++) {
2220
        mapping_t* mapping = array_get(&(s->mapping), i);
2221

2222
#define ADJUST_MAPPING_INDEX(name) \
2223
        if (mapping->name >= offset) \
2224
            mapping->name += adjust
2225

2226
        ADJUST_MAPPING_INDEX(first_mapping_index);
2227
        if (mapping->mode & MODE_DIRECTORY)
2228
            ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
2229
    }
2230
}
2231

2232
/* insert or update mapping */
2233
static mapping_t* insert_mapping(BDRVVVFATState* s,
2234
        uint32_t begin, uint32_t end)
2235
{
2236
    /*
2237
     * - find mapping where mapping->begin >= begin,
2238
     * - if mapping->begin > begin: insert
2239
     *   - adjust all references to mappings!
2240
     * - else: adjust
2241
     * - replace name
2242
     */
2243
    int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
2244
    mapping_t* mapping = NULL;
2245
    mapping_t* first_mapping = array_get(&(s->mapping), 0);
2246

2247
    if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
2248
            && mapping->begin < begin) {
2249
        mapping->end = begin;
2250
        index++;
2251
        mapping = array_get(&(s->mapping), index);
2252
    }
2253
    if (index >= s->mapping.next || mapping->begin > begin) {
2254
        mapping = array_insert(&(s->mapping), index, 1);
2255
        mapping->path = NULL;
2256
        adjust_mapping_indices(s, index, +1);
2257
    }
2258

2259
    mapping->begin = begin;
2260
    mapping->end = end;
2261

2262
DLOG(mapping_t* next_mapping;
2263
assert(index + 1 >= s->mapping.next ||
2264
((next_mapping = array_get(&(s->mapping), index + 1)) &&
2265
 next_mapping->begin >= end)));
2266

2267
    if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
2268
        s->current_mapping = array_get(&(s->mapping),
2269
                s->current_mapping - first_mapping);
2270

2271
    return mapping;
2272
}
2273

2274
static int remove_mapping(BDRVVVFATState* s, int mapping_index)
2275
{
2276
    mapping_t* mapping = array_get(&(s->mapping), mapping_index);
2277
    mapping_t* first_mapping = array_get(&(s->mapping), 0);
2278

2279
    /* free mapping */
2280
    if (mapping->first_mapping_index < 0) {
2281
        g_free(mapping->path);
2282
    }
2283

2284
    /* remove from s->mapping */
2285
    array_remove(&(s->mapping), mapping_index);
2286

2287
    /* adjust all references to mappings */
2288
    adjust_mapping_indices(s, mapping_index, -1);
2289

2290
    if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
2291
        s->current_mapping = array_get(&(s->mapping),
2292
                s->current_mapping - first_mapping);
2293

2294
    return 0;
2295
}
2296

2297
static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
2298
{
2299
    int i;
2300
    for (i = 0; i < s->mapping.next; i++) {
2301
        mapping_t* mapping = array_get(&(s->mapping), i);
2302
        if (mapping->dir_index >= offset)
2303
            mapping->dir_index += adjust;
2304
        if ((mapping->mode & MODE_DIRECTORY) &&
2305
                mapping->info.dir.first_dir_index >= offset)
2306
            mapping->info.dir.first_dir_index += adjust;
2307
    }
2308
}
2309

2310
static direntry_t* insert_direntries(BDRVVVFATState* s,
2311
        int dir_index, int count)
2312
{
2313
    /*
2314
     * make room in s->directory,
2315
     * adjust_dirindices
2316
     */
2317
    direntry_t* result = array_insert(&(s->directory), dir_index, count);
2318
    if (result == NULL)
2319
        return NULL;
2320
    adjust_dirindices(s, dir_index, count);
2321
    return result;
2322
}
2323

2324
static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
2325
{
2326
    int ret = array_remove_slice(&(s->directory), dir_index, count);
2327
    if (ret)
2328
        return ret;
2329
    adjust_dirindices(s, dir_index, -count);
2330
    return 0;
2331
}
2332

2333
/*
2334
 * Adapt the mappings of the cluster chain starting at first cluster
2335
 * (i.e. if a file starts at first_cluster, the chain is followed according
2336
 * to the modified fat, and the corresponding entries in s->mapping are
2337
 * adjusted)
2338
 */
2339
static int commit_mappings(BDRVVVFATState* s,
2340
        uint32_t first_cluster, int dir_index)
2341
{
2342
    mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2343
    direntry_t* direntry = array_get(&(s->directory), dir_index);
2344
    uint32_t cluster = first_cluster;
2345

2346
    vvfat_close_current_file(s);
2347

2348
    assert(mapping);
2349
    assert(mapping->begin == first_cluster);
2350
    mapping->first_mapping_index = -1;
2351
    mapping->dir_index = dir_index;
2352
    mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2353
        MODE_DIRECTORY : MODE_NORMAL;
2354

2355
    while (!fat_eof(s, cluster)) {
2356
        uint32_t c, c1;
2357

2358
        for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2359
                c = c1, c1 = modified_fat_get(s, c1));
2360

2361
        c++;
2362
        if (c > mapping->end) {
2363
            int index = array_index(&(s->mapping), mapping);
2364
            int i, max_i = s->mapping.next - index;
2365
            for (i = 1; i < max_i && mapping[i].begin < c; i++);
2366
            while (--i > 0)
2367
                remove_mapping(s, index + 1);
2368
        }
2369
        assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2370
                || mapping[1].begin >= c);
2371
        mapping->end = c;
2372

2373
        if (!fat_eof(s, c1)) {
2374
            int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2375
            mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2376
                array_get(&(s->mapping), i);
2377

2378
            if (next_mapping == NULL || next_mapping->begin > c1) {
2379
                int i1 = array_index(&(s->mapping), mapping);
2380

2381
                next_mapping = insert_mapping(s, c1, c1+1);
2382

2383
                if (c1 < c)
2384
                    i1++;
2385
                mapping = array_get(&(s->mapping), i1);
2386
            }
2387

2388
            next_mapping->dir_index = mapping->dir_index;
2389
            next_mapping->first_mapping_index =
2390
                mapping->first_mapping_index < 0 ?
2391
                array_index(&(s->mapping), mapping) :
2392
                mapping->first_mapping_index;
2393
            next_mapping->path = mapping->path;
2394
            next_mapping->mode = mapping->mode;
2395
            next_mapping->read_only = mapping->read_only;
2396
            if (mapping->mode & MODE_DIRECTORY) {
2397
                next_mapping->info.dir.parent_mapping_index =
2398
                        mapping->info.dir.parent_mapping_index;
2399
                next_mapping->info.dir.first_dir_index =
2400
                        mapping->info.dir.first_dir_index +
2401
                        0x10 * s->sectors_per_cluster *
2402
                        (mapping->end - mapping->begin);
2403
            } else
2404
                next_mapping->info.file.offset = mapping->info.file.offset +
2405
                        (mapping->end - mapping->begin);
2406

2407
            mapping = next_mapping;
2408
        }
2409

2410
        cluster = c1;
2411
    }
2412

2413
    return 0;
2414
}
2415

2416
static int coroutine_fn GRAPH_RDLOCK
2417
commit_direntries(BDRVVVFATState* s, int dir_index, int parent_mapping_index)
2418
{
2419
    direntry_t* direntry = array_get(&(s->directory), dir_index);
2420
    uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
2421
    mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2422
    int factor = 0x10 * s->sectors_per_cluster;
2423
    int old_cluster_count, new_cluster_count;
2424
    int current_dir_index;
2425
    int first_dir_index;
2426
    int ret, i;
2427
    uint32_t c;
2428

2429
    assert(direntry);
2430
    assert(mapping);
2431
    assert(mapping->begin == first_cluster);
2432
    assert(mapping->info.dir.first_dir_index < s->directory.next);
2433
    assert(mapping->mode & MODE_DIRECTORY);
2434
    assert(dir_index == 0 || is_directory(direntry));
2435

2436
    DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n",
2437
                 mapping->path, parent_mapping_index));
2438

2439
    current_dir_index = mapping->info.dir.first_dir_index;
2440
    first_dir_index = current_dir_index;
2441
    mapping->info.dir.parent_mapping_index = parent_mapping_index;
2442

2443
    if (first_cluster == 0) {
2444
        old_cluster_count = new_cluster_count =
2445
            s->last_cluster_of_root_directory;
2446
    } else {
2447
        for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2448
                c = fat_get(s, c))
2449
            old_cluster_count++;
2450

2451
        for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2452
                c = modified_fat_get(s, c))
2453
            new_cluster_count++;
2454
    }
2455

2456
    if (new_cluster_count > old_cluster_count) {
2457
        if (insert_direntries(s,
2458
                current_dir_index + factor * old_cluster_count,
2459
                factor * (new_cluster_count - old_cluster_count)) == NULL)
2460
            return -1;
2461
    } else if (new_cluster_count < old_cluster_count)
2462
        remove_direntries(s,
2463
                current_dir_index + factor * new_cluster_count,
2464
                factor * (old_cluster_count - new_cluster_count));
2465

2466
    for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
2467
        direntry_t *first_direntry;
2468

2469
        direntry = array_get(&(s->directory), current_dir_index);
2470
        ret = vvfat_read(s->bs, cluster2sector(s, c), (uint8_t *)direntry,
2471
                s->sectors_per_cluster);
2472
        if (ret)
2473
            return ret;
2474

2475
        /* The first directory entry on the filesystem is the volume name */
2476
        first_direntry = (direntry_t*) s->directory.pointer;
2477
        assert(!memcmp(first_direntry->name, s->volume_label, 11));
2478

2479
        current_dir_index += factor;
2480
    }
2481

2482
    ret = commit_mappings(s, first_cluster, dir_index);
2483
    if (ret)
2484
        return ret;
2485

2486
    /* recurse */
2487
    for (i = 0; i < factor * new_cluster_count; i++) {
2488
        direntry = array_get(&(s->directory), first_dir_index + i);
2489
        if (is_directory(direntry) && !is_dot(direntry)) {
2490
            mapping = find_mapping_for_cluster(s, first_cluster);
2491
            if (mapping == NULL) {
2492
                return -1;
2493
            }
2494
            assert(mapping->mode & MODE_DIRECTORY);
2495
            ret = commit_direntries(s, first_dir_index + i,
2496
                array_index(&(s->mapping), mapping));
2497
            if (ret)
2498
                return ret;
2499
        }
2500
    }
2501

2502
    return 0;
2503
}
2504

2505
/* commit one file (adjust contents, adjust mapping),
2506
   return first_mapping_index */
2507
static int coroutine_fn GRAPH_RDLOCK
2508
commit_one_file(BDRVVVFATState* s, int dir_index, uint32_t offset)
2509
{
2510
    direntry_t* direntry = array_get(&(s->directory), dir_index);
2511
    uint32_t c = begin_of_direntry(direntry);
2512
    uint32_t first_cluster = c;
2513
    mapping_t* mapping = find_mapping_for_cluster(s, c);
2514
    uint32_t size = filesize_of_direntry(direntry);
2515
    char *cluster;
2516
    uint32_t i;
2517
    int fd = 0;
2518

2519
    assert(offset < size);
2520
    assert((offset % s->cluster_size) == 0);
2521

2522
    if (mapping == NULL) {
2523
        return -1;
2524
    }
2525

2526
    for (i = 0; i < offset; i += s->cluster_size) {
2527
        c = modified_fat_get(s, c);
2528
    }
2529

2530
    fd = qemu_open_old(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
2531
    if (fd < 0) {
2532
        fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2533
                strerror(errno), errno);
2534
        return fd;
2535
    }
2536
    if (offset > 0) {
2537
        if (lseek(fd, offset, SEEK_SET) != offset) {
2538
            qemu_close(fd);
2539
            return -3;
2540
        }
2541
    }
2542

2543
    cluster = g_malloc(s->cluster_size);
2544

2545
    while (offset < size) {
2546
        uint32_t c1;
2547
        int rest_size = (size - offset > s->cluster_size ?
2548
                s->cluster_size : size - offset);
2549
        int ret;
2550

2551
        c1 = modified_fat_get(s, c);
2552

2553
        assert((size - offset == 0 && fat_eof(s, c)) ||
2554
                (size > offset && c >=2 && !fat_eof(s, c)));
2555

2556
        ret = vvfat_read(s->bs, cluster2sector(s, c),
2557
            (uint8_t*)cluster, DIV_ROUND_UP(rest_size, 0x200));
2558

2559
        if (ret < 0) {
2560
            qemu_close(fd);
2561
            g_free(cluster);
2562
            return ret;
2563
        }
2564

2565
        if (write(fd, cluster, rest_size) < 0) {
2566
            qemu_close(fd);
2567
            g_free(cluster);
2568
            return -2;
2569
        }
2570

2571
        offset += rest_size;
2572
        c = c1;
2573
    }
2574

2575
    if (ftruncate(fd, size)) {
2576
        perror("ftruncate()");
2577
        qemu_close(fd);
2578
        g_free(cluster);
2579
        return -4;
2580
    }
2581
    qemu_close(fd);
2582
    g_free(cluster);
2583

2584
    return commit_mappings(s, first_cluster, dir_index);
2585
}
2586

2587
#ifdef DEBUG
2588
/* test, if all mappings point to valid direntries */
2589
static void check1(BDRVVVFATState* s)
2590
{
2591
    int i;
2592
    for (i = 0; i < s->mapping.next; i++) {
2593
        mapping_t* mapping = array_get(&(s->mapping), i);
2594
        if (mapping->mode & MODE_DELETED) {
2595
            fprintf(stderr, "deleted\n");
2596
            continue;
2597
        }
2598
        assert(mapping->dir_index < s->directory.next);
2599
        direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2600
        assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2601
        if (mapping->mode & MODE_DIRECTORY) {
2602
            assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2603
            assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2604
        }
2605
    }
2606
}
2607

2608
/* test, if all direntries have mappings */
2609
static void check2(BDRVVVFATState* s)
2610
{
2611
    int i;
2612
    int first_mapping = -1;
2613

2614
    for (i = 0; i < s->directory.next; i++) {
2615
        direntry_t* direntry = array_get(&(s->directory), i);
2616

2617
        if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2618
            mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2619
            assert(mapping);
2620
            assert(mapping->dir_index == i || is_dot(direntry));
2621
            assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2622
        }
2623

2624
        if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2625
            /* cluster start */
2626
            int j, count = 0;
2627

2628
            for (j = 0; j < s->mapping.next; j++) {
2629
                mapping_t* mapping = array_get(&(s->mapping), j);
2630
                if (mapping->mode & MODE_DELETED)
2631
                    continue;
2632
                if (mapping->mode & MODE_DIRECTORY) {
2633
                    if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2634
                        assert(++count == 1);
2635
                        if (mapping->first_mapping_index == -1)
2636
                            first_mapping = array_index(&(s->mapping), mapping);
2637
                        else
2638
                            assert(first_mapping == mapping->first_mapping_index);
2639
                        if (mapping->info.dir.parent_mapping_index < 0)
2640
                            assert(j == 0);
2641
                        else {
2642
                            mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2643
                            assert(parent->mode & MODE_DIRECTORY);
2644
                            assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2645
                        }
2646
                    }
2647
                }
2648
            }
2649
            if (count == 0)
2650
                first_mapping = -1;
2651
        }
2652
    }
2653
}
2654
#endif
2655

2656
static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2657
{
2658
    int i;
2659

2660
#ifdef DEBUG
2661
    fprintf(stderr, "handle_renames\n");
2662
    for (i = 0; i < s->commits.next; i++) {
2663
        commit_t* commit = array_get(&(s->commits), i);
2664
        fprintf(stderr, "%d, %s (%u, %d)\n", i,
2665
                commit->path ? commit->path : "(null)",
2666
                commit->param.rename.cluster, commit->action);
2667
    }
2668
#endif
2669

2670
    for (i = 0; i < s->commits.next;) {
2671
        commit_t* commit = array_get(&(s->commits), i);
2672
        if (commit->action == ACTION_RENAME) {
2673
            mapping_t* mapping = find_mapping_for_cluster(s,
2674
                    commit->param.rename.cluster);
2675
            char *old_path;
2676

2677
            if (mapping == NULL) {
2678
                return -1;
2679
            }
2680
            old_path = mapping->path;
2681
            assert(commit->path);
2682
            mapping->path = commit->path;
2683
            if (rename(old_path, mapping->path))
2684
                return -2;
2685

2686
            if (mapping->mode & MODE_DIRECTORY) {
2687
                int l1 = strlen(mapping->path);
2688
                int l2 = strlen(old_path);
2689
                int diff = l1 - l2;
2690
                direntry_t* direntry = array_get(&(s->directory),
2691
                        mapping->info.dir.first_dir_index);
2692
                uint32_t c = mapping->begin;
2693
                int j = 0;
2694

2695
                /* recurse */
2696
                while (!fat_eof(s, c)) {
2697
                    do {
2698
                        direntry_t *d = direntry + j;
2699

2700
                        if (is_file(d) || (is_directory(d) && !is_dot(d))) {
2701
                            int l;
2702
                            char *new_path;
2703
                            mapping_t* m = find_mapping_for_cluster(s,
2704
                                    begin_of_direntry(d));
2705
                            if (m == NULL) {
2706
                                return -1;
2707
                            }
2708
                            l = strlen(m->path);
2709
                            new_path = g_malloc(l + diff + 1);
2710

2711
                            assert(!strncmp(m->path, mapping->path, l2));
2712

2713
                            pstrcpy(new_path, l + diff + 1, mapping->path);
2714
                            pstrcpy(new_path + l1, l + diff + 1 - l1,
2715
                                    m->path + l2);
2716

2717
                            schedule_rename(s, m->begin, new_path);
2718
                        }
2719
                        j++;
2720
                    } while (j % (0x10 * s->sectors_per_cluster) != 0);
2721
                    c = fat_get(s, c);
2722
                }
2723
            }
2724

2725
            g_free(old_path);
2726
            array_remove(&(s->commits), i);
2727
            continue;
2728
        } else if (commit->action == ACTION_MKDIR) {
2729
            mapping_t* mapping;
2730
            int j, parent_path_len;
2731

2732
            if (g_mkdir(commit->path, 0755)) {
2733
                return -5;
2734
            }
2735

2736
            mapping = insert_mapping(s, commit->param.mkdir.cluster,
2737
                    commit->param.mkdir.cluster + 1);
2738
            if (mapping == NULL)
2739
                return -6;
2740

2741
            mapping->mode = MODE_DIRECTORY;
2742
            mapping->read_only = 0;
2743
            mapping->path = commit->path;
2744
            j = s->directory.next;
2745
            assert(j);
2746
            insert_direntries(s, s->directory.next,
2747
                    0x10 * s->sectors_per_cluster);
2748
            mapping->info.dir.first_dir_index = j;
2749

2750
            parent_path_len = strlen(commit->path)
2751
                - strlen(get_basename(commit->path)) - 1;
2752
            for (j = 0; j < s->mapping.next; j++) {
2753
                mapping_t* m = array_get(&(s->mapping), j);
2754
                if (m->first_mapping_index < 0 && m != mapping &&
2755
                        !strncmp(m->path, mapping->path, parent_path_len) &&
2756
                        strlen(m->path) == parent_path_len)
2757
                    break;
2758
            }
2759
            assert(j < s->mapping.next);
2760
            mapping->info.dir.parent_mapping_index = j;
2761

2762
            array_remove(&(s->commits), i);
2763
            continue;
2764
        }
2765

2766
        i++;
2767
    }
2768
    return 0;
2769
}
2770

2771
/*
2772
 * TODO: make sure that the short name is not matching *another* file
2773
 */
2774
static int coroutine_fn GRAPH_RDLOCK handle_commits(BDRVVVFATState* s)
2775
{
2776
    int i, fail = 0;
2777

2778
    vvfat_close_current_file(s);
2779

2780
    for (i = 0; !fail && i < s->commits.next; i++) {
2781
        commit_t* commit = array_get(&(s->commits), i);
2782
        switch(commit->action) {
2783
        case ACTION_RENAME: case ACTION_MKDIR:
2784
            abort();
2785
            fail = -2;
2786
            break;
2787
        case ACTION_WRITEOUT: {
2788
            direntry_t* entry = array_get(&(s->directory),
2789
                    commit->param.writeout.dir_index);
2790
            uint32_t begin = begin_of_direntry(entry);
2791
            mapping_t* mapping = find_mapping_for_cluster(s, begin);
2792

2793
            assert(mapping);
2794
            assert(mapping->begin == begin);
2795
            assert(commit->path == NULL);
2796

2797
            if (commit_one_file(s, commit->param.writeout.dir_index,
2798
                        commit->param.writeout.modified_offset))
2799
                fail = -3;
2800

2801
            break;
2802
        }
2803
        case ACTION_NEW_FILE: {
2804
            int begin = commit->param.new_file.first_cluster;
2805
            mapping_t* mapping = find_mapping_for_cluster(s, begin);
2806
            direntry_t* entry;
2807
            int j;
2808

2809
            /* find direntry */
2810
            for (j = 0; j < s->directory.next; j++) {
2811
                entry = array_get(&(s->directory), j);
2812
                if (is_file(entry) && begin_of_direntry(entry) == begin)
2813
                    break;
2814
            }
2815

2816
            if (j >= s->directory.next) {
2817
                fail = -6;
2818
                continue;
2819
            }
2820

2821
            /* make sure there exists an initial mapping */
2822
            if (mapping && mapping->begin != begin) {
2823
                mapping->end = begin;
2824
                mapping = NULL;
2825
            }
2826
            if (mapping == NULL) {
2827
                mapping = insert_mapping(s, begin, begin+1);
2828
            }
2829
            /* most members will be fixed in commit_mappings() */
2830
            assert(commit->path);
2831
            mapping->path = commit->path;
2832
            mapping->read_only = 0;
2833
            mapping->mode = MODE_NORMAL;
2834
            mapping->info.file.offset = 0;
2835

2836
            if (commit_one_file(s, j, 0)) {
2837
                fail = -7;
2838
            }
2839

2840
            break;
2841
        }
2842
        default:
2843
            abort();
2844
        }
2845
    }
2846
    if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2847
        return -1;
2848
    return fail;
2849
}
2850

2851
static int handle_deletes(BDRVVVFATState* s)
2852
{
2853
    int i, deferred = 1, deleted = 1;
2854

2855
    /* delete files corresponding to mappings marked as deleted */
2856
    /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2857
    while (deferred && deleted) {
2858
        deferred = 0;
2859
        deleted = 0;
2860

2861
        for (i = 1; i < s->mapping.next; i++) {
2862
            mapping_t* mapping = array_get(&(s->mapping), i);
2863
            if (mapping->mode & MODE_DELETED) {
2864
                direntry_t* entry = array_get(&(s->directory),
2865
                        mapping->dir_index);
2866

2867
                if (is_free(entry)) {
2868
                    /* remove file/directory */
2869
                    if (mapping->mode & MODE_DIRECTORY) {
2870
                        int j, next_dir_index = s->directory.next,
2871
                        first_dir_index = mapping->info.dir.first_dir_index;
2872

2873
                        if (rmdir(mapping->path) < 0) {
2874
                            if (errno == ENOTEMPTY) {
2875
                                deferred++;
2876
                                continue;
2877
                            } else
2878
                                return -5;
2879
                        }
2880

2881
                        for (j = 1; j < s->mapping.next; j++) {
2882
                            mapping_t* m = array_get(&(s->mapping), j);
2883
                            if (m->mode & MODE_DIRECTORY &&
2884
                                    m->info.dir.first_dir_index >
2885
                                    first_dir_index &&
2886
                                    m->info.dir.first_dir_index <
2887
                                    next_dir_index)
2888
                                next_dir_index =
2889
                                    m->info.dir.first_dir_index;
2890
                        }
2891
                        remove_direntries(s, first_dir_index,
2892
                                next_dir_index - first_dir_index);
2893

2894
                        deleted++;
2895
                    }
2896
                } else {
2897
                    if (unlink(mapping->path))
2898
                        return -4;
2899
                    deleted++;
2900
                }
2901
                DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2902
                remove_mapping(s, i);
2903
            }
2904
        }
2905
    }
2906

2907
    return 0;
2908
}
2909

2910
/*
2911
 * synchronize mapping with new state:
2912
 *
2913
 * - copy FAT (with bdrv_pread)
2914
 * - mark all filenames corresponding to mappings as deleted
2915
 * - recurse direntries from root (using bs->bdrv_pread)
2916
 * - delete files corresponding to mappings marked as deleted
2917
 */
2918
static int coroutine_fn GRAPH_RDLOCK do_commit(BDRVVVFATState* s)
2919
{
2920
    int ret = 0;
2921

2922
    /* the real meat are the commits. Nothing to do? Move along! */
2923
    if (s->commits.next == 0)
2924
        return 0;
2925

2926
    vvfat_close_current_file(s);
2927

2928
    ret = handle_renames_and_mkdirs(s);
2929
    if (ret) {
2930
        fprintf(stderr, "Error handling renames (%d)\n", ret);
2931
        abort();
2932
        return ret;
2933
    }
2934

2935
    /* copy FAT (with bdrv_pread) */
2936
    memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2937

2938
    /* recurse direntries from root (using bs->bdrv_pread) */
2939
    ret = commit_direntries(s, 0, -1);
2940
    if (ret) {
2941
        fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
2942
        abort();
2943
        return ret;
2944
    }
2945

2946
    ret = handle_commits(s);
2947
    if (ret) {
2948
        fprintf(stderr, "Error handling commits (%d)\n", ret);
2949
        abort();
2950
        return ret;
2951
    }
2952

2953
    ret = handle_deletes(s);
2954
    if (ret) {
2955
        fprintf(stderr, "Error deleting\n");
2956
        abort();
2957
        return ret;
2958
    }
2959

2960
    bdrv_make_empty(s->qcow, NULL);
2961

2962
    memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2963

2964
DLOG(checkpoint());
2965
    return 0;
2966
}
2967

2968
static int coroutine_fn GRAPH_RDLOCK try_commit(BDRVVVFATState* s)
2969
{
2970
    vvfat_close_current_file(s);
2971
DLOG(checkpoint());
2972
    if(!is_consistent(s))
2973
        return -1;
2974
    return do_commit(s);
2975
}
2976

2977
static int coroutine_fn GRAPH_RDLOCK
2978
vvfat_write(BlockDriverState *bs, int64_t sector_num,
2979
            const uint8_t *buf, int nb_sectors)
2980
{
2981
    BDRVVVFATState *s = bs->opaque;
2982
    int i, ret;
2983
    int first_cluster, last_cluster;
2984

2985
DLOG(checkpoint());
2986

2987
    /* Check if we're operating in read-only mode */
2988
    if (s->qcow == NULL) {
2989
        return -EACCES;
2990
    }
2991

2992
    vvfat_close_current_file(s);
2993

2994
    if (sector_num == s->offset_to_bootsector && nb_sectors == 1) {
2995
        /*
2996
         * Write on bootsector. Allow only changing the reserved1 field,
2997
         * used to mark volume dirtiness
2998
         */
2999
        unsigned char *bootsector = s->first_sectors
3000
                                    + s->offset_to_bootsector * 0x200;
3001
        /*
3002
         * LATER TODO: if FAT32, this is wrong (see init_directories(),
3003
         * which always creates a FAT16 bootsector)
3004
         */
3005
        const int reserved1_offset = offsetof(bootsector_t, u.fat16.reserved1);
3006

3007
        for (i = 0; i < 0x200; i++) {
3008
            if (i != reserved1_offset && bootsector[i] != buf[i]) {
3009
                fprintf(stderr, "Tried to write to protected bootsector\n");
3010
                return -1;
3011
            }
3012
        }
3013

3014
        /* Update bootsector with the only updatable byte, and return success */
3015
        bootsector[reserved1_offset] = buf[reserved1_offset];
3016
        return 0;
3017
    }
3018

3019
    /*
3020
     * Some sanity checks:
3021
     * - do not allow writing to the boot sector
3022
     */
3023
    if (sector_num < s->offset_to_fat)
3024
        return -1;
3025

3026
    /*
3027
     * Values will be negative for writes to the FAT, which is located before
3028
     * the root directory.
3029
     */
3030
    first_cluster = sector2cluster(s, sector_num);
3031
    last_cluster = sector2cluster(s, sector_num + nb_sectors - 1);
3032

3033
    for (i = first_cluster; i <= last_cluster;) {
3034
        mapping_t *mapping = NULL;
3035

3036
        if (i >= 0) {
3037
            mapping = find_mapping_for_cluster(s, i);
3038
        }
3039

3040
        if (mapping) {
3041
            if (mapping->read_only) {
3042
                fprintf(stderr, "Tried to write to write-protected file %s\n",
3043
                        mapping->path);
3044
                return -1;
3045
            }
3046

3047
            if (mapping->mode & MODE_DIRECTORY) {
3048
                int begin = cluster2sector(s, i);
3049
                int end = begin + s->sectors_per_cluster, k;
3050
                int dir_index;
3051
                const direntry_t* direntries;
3052
                long_file_name lfn;
3053

3054
                lfn_init(&lfn);
3055

3056
                if (begin < sector_num)
3057
                    begin = sector_num;
3058
                if (end > sector_num + nb_sectors)
3059
                    end = sector_num + nb_sectors;
3060
                dir_index  = mapping->dir_index +
3061
                    0x10 * (begin - mapping->begin * s->sectors_per_cluster);
3062
                direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
3063

3064
                for (k = 0; k < (end - begin) * 0x10; k++) {
3065
                    /* no access to the direntry of a read-only file */
3066
                    if (is_short_name(direntries + k) &&
3067
                            (direntries[k].attributes & 1)) {
3068
                        if (memcmp(direntries + k,
3069
                                    array_get(&(s->directory), dir_index + k),
3070
                                    sizeof(direntry_t))) {
3071
                            warn_report("tried to write to write-protected "
3072
                                        "file");
3073
                            return -1;
3074
                        }
3075
                    }
3076
                }
3077
            }
3078
            i = mapping->end;
3079
        } else {
3080
            i++;
3081
        }
3082
    }
3083

3084
    /*
3085
     * Use qcow backend. Commit later.
3086
     */
3087
DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
3088
    ret = bdrv_co_pwrite(s->qcow, sector_num * BDRV_SECTOR_SIZE,
3089
                         nb_sectors * BDRV_SECTOR_SIZE, buf, 0);
3090
    if (ret < 0) {
3091
        fprintf(stderr, "Error writing to qcow backend\n");
3092
        return ret;
3093
    }
3094

3095
    for (i = first_cluster; i <= last_cluster; i++) {
3096
        if (i >= 0) {
3097
            s->used_clusters[i] |= USED_ALLOCATED;
3098
        }
3099
    }
3100

3101
DLOG(checkpoint());
3102
    /* TODO: add timeout */
3103
    try_commit(s);
3104

3105
DLOG(checkpoint());
3106
    return 0;
3107
}
3108

3109
static int coroutine_fn GRAPH_RDLOCK
3110
vvfat_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
3111
                 QEMUIOVector *qiov, BdrvRequestFlags flags)
3112
{
3113
    int ret;
3114
    BDRVVVFATState *s = bs->opaque;
3115
    uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
3116
    int nb_sectors = bytes >> BDRV_SECTOR_BITS;
3117
    void *buf;
3118

3119
    assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE));
3120
    assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE));
3121

3122
    buf = g_try_malloc(bytes);
3123
    if (bytes && buf == NULL) {
3124
        return -ENOMEM;
3125
    }
3126
    qemu_iovec_to_buf(qiov, 0, buf, bytes);
3127

3128
    qemu_co_mutex_lock(&s->lock);
3129
    ret = vvfat_write(bs, sector_num, buf, nb_sectors);
3130
    qemu_co_mutex_unlock(&s->lock);
3131

3132
    g_free(buf);
3133

3134
    return ret;
3135
}
3136

3137
static int coroutine_fn vvfat_co_block_status(BlockDriverState *bs,
3138
                                              bool want_zero, int64_t offset,
3139
                                              int64_t bytes, int64_t *n,
3140
                                              int64_t *map,
3141
                                              BlockDriverState **file)
3142
{
3143
    *n = bytes;
3144
    return BDRV_BLOCK_DATA;
3145
}
3146

3147
static void vvfat_qcow_options(BdrvChildRole role, bool parent_is_format,
3148
                               int *child_flags, QDict *child_options,
3149
                               int parent_flags, QDict *parent_options)
3150
{
3151
    qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off");
3152
    qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off");
3153
    qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on");
3154
}
3155

3156
static BdrvChildClass child_vvfat_qcow;
3157

3158
static int enable_write_target(BlockDriverState *bs, Error **errp)
3159
{
3160
    BDRVVVFATState *s = bs->opaque;
3161
    BlockDriver *bdrv_qcow = NULL;
3162
    QemuOpts *opts = NULL;
3163
    int ret;
3164
    int size = sector2cluster(s, s->sector_count);
3165
    QDict *options;
3166

3167
    s->used_clusters = g_malloc0(size);
3168

3169
    array_init(&(s->commits), sizeof(commit_t));
3170

3171
    s->qcow_filename = create_tmp_file(errp);
3172
    if (!s->qcow_filename) {
3173
        ret = -ENOENT;
3174
        goto err;
3175
    }
3176

3177
    bdrv_qcow = bdrv_find_format("qcow");
3178
    if (!bdrv_qcow) {
3179
        error_setg(errp, "Failed to locate qcow driver");
3180
        ret = -ENOENT;
3181
        goto err;
3182
    }
3183

3184
    opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort);
3185
    qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
3186
                        bs->total_sectors * BDRV_SECTOR_SIZE, &error_abort);
3187
    qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:", &error_abort);
3188

3189
    ret = bdrv_create(bdrv_qcow, s->qcow_filename, opts, errp);
3190
    qemu_opts_del(opts);
3191
    if (ret < 0) {
3192
        goto err;
3193
    }
3194

3195
    options = qdict_new();
3196
    qdict_put_str(options, "write-target.driver", "qcow");
3197
    s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs,
3198
                              &child_vvfat_qcow,
3199
                              BDRV_CHILD_DATA | BDRV_CHILD_METADATA,
3200
                              false, errp);
3201
    qobject_unref(options);
3202
    if (!s->qcow) {
3203
        ret = -EINVAL;
3204
        goto err;
3205
    }
3206

3207
#ifndef _WIN32
3208
    unlink(s->qcow_filename);
3209
#endif
3210

3211
    return 0;
3212

3213
err:
3214
    return ret;
3215
}
3216

3217
static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c,
3218
                             BdrvChildRole role,
3219
                             BlockReopenQueue *reopen_queue,
3220
                             uint64_t perm, uint64_t shared,
3221
                             uint64_t *nperm, uint64_t *nshared)
3222
{
3223
    assert(role & BDRV_CHILD_DATA);
3224
    /* This is a private node, nobody should try to attach to it */
3225
    *nperm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE;
3226
    *nshared = BLK_PERM_WRITE_UNCHANGED;
3227
}
3228

3229
static void vvfat_close(BlockDriverState *bs)
3230
{
3231
    BDRVVVFATState *s = bs->opaque;
3232

3233
    vvfat_close_current_file(s);
3234
    array_free(&(s->fat));
3235
    array_free(&(s->directory));
3236
    array_free(&(s->mapping));
3237
    g_free(s->cluster_buffer);
3238

3239
    if (s->qcow) {
3240
        migrate_del_blocker(&s->migration_blocker);
3241
    }
3242
}
3243

3244
static const char *const vvfat_strong_runtime_opts[] = {
3245
    "dir",
3246
    "fat-type",
3247
    "floppy",
3248
    "label",
3249
    "rw",
3250

3251
    NULL
3252
};
3253

3254
static BlockDriver bdrv_vvfat = {
3255
    .format_name            = "vvfat",
3256
    .protocol_name          = "fat",
3257
    .instance_size          = sizeof(BDRVVVFATState),
3258

3259
    .bdrv_parse_filename    = vvfat_parse_filename,
3260
    .bdrv_open              = vvfat_open,
3261
    .bdrv_refresh_limits    = vvfat_refresh_limits,
3262
    .bdrv_close             = vvfat_close,
3263
    .bdrv_child_perm        = vvfat_child_perm,
3264

3265
    .bdrv_co_preadv         = vvfat_co_preadv,
3266
    .bdrv_co_pwritev        = vvfat_co_pwritev,
3267
    .bdrv_co_block_status   = vvfat_co_block_status,
3268

3269
    .strong_runtime_opts    = vvfat_strong_runtime_opts,
3270
};
3271

3272
static void bdrv_vvfat_init(void)
3273
{
3274
    child_vvfat_qcow = child_of_bds;
3275
    child_vvfat_qcow.inherit_options = vvfat_qcow_options;
3276
    bdrv_register(&bdrv_vvfat);
3277
}
3278

3279
block_init(bdrv_vvfat_init);
3280

3281
#ifdef DEBUG
3282
static void checkpoint(void)
3283
{
3284
    assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
3285
    check1(vvv);
3286
    check2(vvv);
3287
    assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
3288
}
3289
#endif
3290

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.