Statistics
| Branch: | Revision:

root / block-vvfat.c @ 59fdb018

History | View | Annotate | Download (79.2 kB)

1
/* vim:set shiftwidth=4 ts=8: */
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
#include <sys/stat.h>
26
#include <dirent.h>
27
#include <assert.h>
28
#include "qemu-common.h"
29
#include "block_int.h"
30

    
31
#ifndef S_IWGRP
32
#define S_IWGRP 0
33
#endif
34
#ifndef S_IWOTH
35
#define S_IWOTH 0
36
#endif
37

    
38
/* TODO: add ":bootsector=blabla.img:" */
39
/* LATER TODO: add automatic boot sector generation from
40
    BOOTEASY.ASM and Ranish Partition Manager
41
    Note that DOS assumes the system files to be the first files in the
42
    file system (test if the boot sector still relies on that fact)! */
43
/* MAYBE TODO: write block-visofs.c */
44
/* TODO: call try_commit() only after a timeout */
45

    
46
/* #define DEBUG */
47

    
48
#ifdef DEBUG
49

    
50
#define DLOG(a) a
51

    
52
#undef stderr
53
#define stderr STDERR
54
FILE* stderr = NULL;
55

    
56
static void checkpoint(void);
57

    
58
#ifdef __MINGW32__
59
void nonono(const char* file, int line, const char* msg) {
60
    fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg);
61
    exit(-5);
62
}
63
#undef assert
64
#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
65
#endif
66

    
67
#else
68

    
69
#define DLOG(a)
70

    
71
#endif
72

    
73
/* dynamic array functions */
74
typedef struct array_t {
75
    char* pointer;
76
    unsigned int size,next,item_size;
77
} array_t;
78

    
79
static inline void array_init(array_t* array,unsigned int item_size)
80
{
81
    array->pointer=0;
82
    array->size=0;
83
    array->next=0;
84
    array->item_size=item_size;
85
}
86

    
87
static inline void array_free(array_t* array)
88
{
89
    if(array->pointer)
90
        free(array->pointer);
91
    array->size=array->next=0;
92
}
93

    
94
/* does not automatically grow */
95
static inline void* array_get(array_t* array,unsigned int index) {
96
    assert(index >= 0);
97
    assert(index < array->next);
98
    return array->pointer + index * array->item_size;
99
}
100

    
101
static inline int array_ensure_allocated(array_t* array, int index)
102
{
103
    if((index + 1) * array->item_size > array->size) {
104
        int new_size = (index + 32) * array->item_size;
105
        array->pointer = realloc(array->pointer, new_size);
106
        if (!array->pointer)
107
            return -1;
108
        array->size = new_size;
109
        array->next = index + 1;
110
    }
111

    
112
    return 0;
113
}
114

    
115
static inline void* array_get_next(array_t* array) {
116
    unsigned int next = array->next;
117
    void* result;
118

    
119
    if (array_ensure_allocated(array, next) < 0)
120
        return NULL;
121

    
122
    array->next = next + 1;
123
    result = array_get(array, next);
124

    
125
    return result;
126
}
127

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

    
143
/* this performs a "roll", so that the element which was at index_from becomes
144
 * index_to, but the order of all other elements is preserved. */
145
static inline int array_roll(array_t* array,int index_to,int index_from,int count)
146
{
147
    char* buf;
148
    char* from;
149
    char* to;
150
    int is;
151

    
152
    if(!array ||
153
            index_to<0 || index_to>=array->next ||
154
            index_from<0 || index_from>=array->next)
155
        return -1;
156

    
157
    if(index_to==index_from)
158
        return 0;
159

    
160
    is=array->item_size;
161
    from=array->pointer+index_from*is;
162
    to=array->pointer+index_to*is;
163
    buf=malloc(is*count);
164
    memcpy(buf,from,is*count);
165

    
166
    if(index_to<index_from)
167
        memmove(to+is*count,to,from-to);
168
    else
169
        memmove(from,from+is*count,to-from);
170

    
171
    memcpy(to,buf,is*count);
172

    
173
    free(buf);
174

    
175
    return 0;
176
}
177

    
178
static inline int array_remove_slice(array_t* array,int index, int count)
179
{
180
    assert(index >=0);
181
    assert(count > 0);
182
    assert(index + count <= array->next);
183
    if(array_roll(array,array->next-1,index,count))
184
        return -1;
185
    array->next -= count;
186
    return 0;
187
}
188

    
189
static int array_remove(array_t* array,int index)
190
{
191
    return array_remove_slice(array, index, 1);
192
}
193

    
194
/* return the index for a given member */
195
static int array_index(array_t* array, void* pointer)
196
{
197
    size_t offset = (char*)pointer - array->pointer;
198
    assert(offset >= 0);
199
    assert((offset % array->item_size) == 0);
200
    assert(offset/array->item_size < array->next);
201
    return offset/array->item_size;
202
}
203

    
204
/* These structures are used to fake a disk and the VFAT filesystem.
205
 * For this reason we need to use __attribute__((packed)). */
206

    
207
typedef struct bootsector_t {
208
    uint8_t jump[3];
209
    uint8_t name[8];
210
    uint16_t sector_size;
211
    uint8_t sectors_per_cluster;
212
    uint16_t reserved_sectors;
213
    uint8_t number_of_fats;
214
    uint16_t root_entries;
215
    uint16_t total_sectors16;
216
    uint8_t media_type;
217
    uint16_t sectors_per_fat;
218
    uint16_t sectors_per_track;
219
    uint16_t number_of_heads;
220
    uint32_t hidden_sectors;
221
    uint32_t total_sectors;
222
    union {
223
        struct {
224
            uint8_t drive_number;
225
            uint8_t current_head;
226
            uint8_t signature;
227
            uint32_t id;
228
            uint8_t volume_label[11];
229
        } __attribute__((packed)) fat16;
230
        struct {
231
            uint32_t sectors_per_fat;
232
            uint16_t flags;
233
            uint8_t major,minor;
234
            uint32_t first_cluster_of_root_directory;
235
            uint16_t info_sector;
236
            uint16_t backup_boot_sector;
237
            uint16_t ignored;
238
        } __attribute__((packed)) fat32;
239
    } u;
240
    uint8_t fat_type[8];
241
    uint8_t ignored[0x1c0];
242
    uint8_t magic[2];
243
} __attribute__((packed)) bootsector_t;
244

    
245
typedef struct {
246
    uint8_t head;
247
    uint8_t sector;
248
    uint8_t cylinder;
249
} mbr_chs_t;
250

    
251
typedef struct partition_t {
252
    uint8_t attributes; /* 0x80 = bootable */
253
    mbr_chs_t start_CHS;
254
    uint8_t   fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
255
    mbr_chs_t end_CHS;
256
    uint32_t start_sector_long;
257
    uint32_t length_sector_long;
258
} __attribute__((packed)) partition_t;
259

    
260
typedef struct mbr_t {
261
    uint8_t ignored[0x1b8];
262
    uint32_t nt_id;
263
    uint8_t ignored2[2];
264
    partition_t partition[4];
265
    uint8_t magic[2];
266
} __attribute__((packed)) mbr_t;
267

    
268
typedef struct direntry_t {
269
    uint8_t name[8];
270
    uint8_t extension[3];
271
    uint8_t attributes;
272
    uint8_t reserved[2];
273
    uint16_t ctime;
274
    uint16_t cdate;
275
    uint16_t adate;
276
    uint16_t begin_hi;
277
    uint16_t mtime;
278
    uint16_t mdate;
279
    uint16_t begin;
280
    uint32_t size;
281
} __attribute__((packed)) direntry_t;
282

    
283
/* this structure are used to transparently access the files */
284

    
285
typedef struct mapping_t {
286
    /* begin is the first cluster, end is the last+1 */
287
    uint32_t begin,end;
288
    /* as s->directory is growable, no pointer may be used here */
289
    unsigned int dir_index;
290
    /* the clusters of a file may be in any order; this points to the first */
291
    int first_mapping_index;
292
    union {
293
        /* offset is
294
         * - the offset in the file (in clusters) for a file, or
295
         * - the next cluster of the directory for a directory, and
296
         * - the address of the buffer for a faked entry
297
         */
298
        struct {
299
            uint32_t offset;
300
        } file;
301
        struct {
302
            int parent_mapping_index;
303
            int first_dir_index;
304
        } dir;
305
    } info;
306
    /* path contains the full path, i.e. it always starts with s->path */
307
    char* path;
308

    
309
    enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2,
310
        MODE_DIRECTORY = 4, MODE_FAKED = 8,
311
        MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
312
    int read_only;
313
} mapping_t;
314

    
315
#ifdef DEBUG
316
static void print_direntry(const struct direntry_t*);
317
static void print_mapping(const struct mapping_t* mapping);
318
#endif
319

    
320
/* here begins the real VVFAT driver */
321

    
322
typedef struct BDRVVVFATState {
323
    BlockDriverState* bs; /* pointer to parent */
324
    unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
325
    unsigned char first_sectors[0x40*0x200];
326

    
327
    int fat_type; /* 16 or 32 */
328
    array_t fat,directory,mapping;
329

    
330
    unsigned int cluster_size;
331
    unsigned int sectors_per_cluster;
332
    unsigned int sectors_per_fat;
333
    unsigned int sectors_of_root_directory;
334
    uint32_t last_cluster_of_root_directory;
335
    unsigned int faked_sectors; /* how many sectors are faked before file data */
336
    uint32_t sector_count; /* total number of sectors of the partition */
337
    uint32_t cluster_count; /* total number of clusters of this partition */
338
    uint32_t max_fat_value;
339

    
340
    int current_fd;
341
    mapping_t* current_mapping;
342
    unsigned char* cluster; /* points to current cluster */
343
    unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
344
    unsigned int current_cluster;
345

    
346
    /* write support */
347
    BlockDriverState* write_target;
348
    char* qcow_filename;
349
    BlockDriverState* qcow;
350
    void* fat2;
351
    char* used_clusters;
352
    array_t commits;
353
    const char* path;
354
    int downcase_short_names;
355
} BDRVVVFATState;
356

    
357
/* take the sector position spos and convert it to Cylinder/Head/Sector position
358
 * if the position is outside the specified geometry, fill maximum value for CHS
359
 * and return 1 to signal overflow.
360
 */
361
static int sector2CHS(BlockDriverState* bs, mbr_chs_t * chs, int spos){
362
    int head,sector;
363
    sector   = spos % (bs->secs);  spos/= bs->secs;
364
    head     = spos % (bs->heads); spos/= bs->heads;
365
    if(spos >= bs->cyls){
366
        /* Overflow,
367
        it happens if 32bit sector positions are used, while CHS is only 24bit.
368
        Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
369
        chs->head     = 0xFF;
370
        chs->sector   = 0xFF;
371
        chs->cylinder = 0xFF;
372
        return 1;
373
    }
374
    chs->head     = (uint8_t)head;
375
    chs->sector   = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
376
    chs->cylinder = (uint8_t)spos;
377
    return 0;
378
}
379

    
380
static void init_mbr(BDRVVVFATState* s)
381
{
382
    /* TODO: if the files mbr.img and bootsect.img exist, use them */
383
    mbr_t* real_mbr=(mbr_t*)s->first_sectors;
384
    partition_t* partition=&(real_mbr->partition[0]);
385
    int lba;
386

    
387
    memset(s->first_sectors,0,512);
388

    
389
    /* Win NT Disk Signature */
390
    real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
391

    
392
    partition->attributes=0x80; /* bootable */
393

    
394
    /* LBA is used when partition is outside the CHS geometry */
395
    lba = sector2CHS(s->bs, &partition->start_CHS, s->first_sectors_number-1);
396
    lba|= sector2CHS(s->bs, &partition->end_CHS,   s->sector_count);
397

    
398
    /*LBA partitions are identified only by start/length_sector_long not by CHS*/
399
    partition->start_sector_long =cpu_to_le32(s->first_sectors_number-1);
400
    partition->length_sector_long=cpu_to_le32(s->sector_count - s->first_sectors_number+1);
401

    
402
    /* FAT12/FAT16/FAT32 */
403
    /* DOS uses different types when partition is LBA,
404
       probably to prevent older versions from using CHS on them */
405
    partition->fs_type= s->fat_type==12 ? 0x1:
406
                        s->fat_type==16 ? (lba?0xe:0x06):
407
                         /*fat_tyoe==32*/ (lba?0xc:0x0b);
408

    
409
    real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
410
}
411

    
412
/* direntry functions */
413

    
414
/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
415
static inline int short2long_name(char* dest,const char* src)
416
{
417
    int i;
418
    int len;
419
    for(i=0;i<129 && src[i];i++) {
420
        dest[2*i]=src[i];
421
        dest[2*i+1]=0;
422
    }
423
    len=2*i;
424
    dest[2*i]=dest[2*i+1]=0;
425
    for(i=2*i+2;(i%26);i++)
426
        dest[i]=0xff;
427
    return len;
428
}
429

    
430
static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
431
{
432
    char buffer[258];
433
    int length=short2long_name(buffer,filename),
434
        number_of_entries=(length+25)/26,i;
435
    direntry_t* entry;
436

    
437
    for(i=0;i<number_of_entries;i++) {
438
        entry=array_get_next(&(s->directory));
439
        entry->attributes=0xf;
440
        entry->reserved[0]=0;
441
        entry->begin=0;
442
        entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
443
    }
444
    for(i=0;i<26*number_of_entries;i++) {
445
        int offset=(i%26);
446
        if(offset<10) offset=1+offset;
447
        else if(offset<22) offset=14+offset-10;
448
        else offset=28+offset-22;
449
        entry=array_get(&(s->directory),s->directory.next-1-(i/26));
450
        entry->name[offset]=buffer[i];
451
    }
452
    return array_get(&(s->directory),s->directory.next-number_of_entries);
453
}
454

    
455
static char is_free(const direntry_t* direntry)
456
{
457
    return direntry->name[0]==0xe5 || direntry->name[0]==0x00;
458
}
459

    
460
static char is_volume_label(const direntry_t* direntry)
461
{
462
    return direntry->attributes == 0x28;
463
}
464

    
465
static char is_long_name(const direntry_t* direntry)
466
{
467
    return direntry->attributes == 0xf;
468
}
469

    
470
static char is_short_name(const direntry_t* direntry)
471
{
472
    return !is_volume_label(direntry) && !is_long_name(direntry)
473
        && !is_free(direntry);
474
}
475

    
476
static char is_directory(const direntry_t* direntry)
477
{
478
    return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
479
}
480

    
481
static inline char is_dot(const direntry_t* direntry)
482
{
483
    return is_short_name(direntry) && direntry->name[0] == '.';
484
}
485

    
486
static char is_file(const direntry_t* direntry)
487
{
488
    return is_short_name(direntry) && !is_directory(direntry);
489
}
490

    
491
static inline uint32_t begin_of_direntry(const direntry_t* direntry)
492
{
493
    return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
494
}
495

    
496
static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
497
{
498
    return le32_to_cpu(direntry->size);
499
}
500

    
501
static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
502
{
503
    direntry->begin = cpu_to_le16(begin & 0xffff);
504
    direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
505
}
506

    
507
/* fat functions */
508

    
509
static inline uint8_t fat_chksum(const direntry_t* entry)
510
{
511
    uint8_t chksum=0;
512
    int i;
513

    
514
    for(i=0;i<11;i++)
515
        chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0))
516
            +(unsigned char)entry->name[i];
517

    
518
    return chksum;
519
}
520

    
521
/* if return_time==0, this returns the fat_date, else the fat_time */
522
static uint16_t fat_datetime(time_t time,int return_time) {
523
    struct tm* t;
524
#ifdef _WIN32
525
    t=localtime(&time); /* this is not thread safe */
526
#else
527
    struct tm t1;
528
    t=&t1;
529
    localtime_r(&time,t);
530
#endif
531
    if(return_time)
532
        return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
533
    return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
534
}
535

    
536
static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
537
{
538
    if(s->fat_type==32) {
539
        uint32_t* entry=array_get(&(s->fat),cluster);
540
        *entry=cpu_to_le32(value);
541
    } else if(s->fat_type==16) {
542
        uint16_t* entry=array_get(&(s->fat),cluster);
543
        *entry=cpu_to_le16(value&0xffff);
544
    } else {
545
        int offset = (cluster*3/2);
546
        unsigned char* p = array_get(&(s->fat), offset);
547
        switch (cluster&1) {
548
        case 0:
549
                p[0] = value&0xff;
550
                p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
551
                break;
552
        case 1:
553
                p[0] = (p[0]&0xf) | ((value&0xf)<<4);
554
                p[1] = (value>>4);
555
                break;
556
        }
557
    }
558
}
559

    
560
static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
561
{
562
    if(s->fat_type==32) {
563
        uint32_t* entry=array_get(&(s->fat),cluster);
564
        return le32_to_cpu(*entry);
565
    } else if(s->fat_type==16) {
566
        uint16_t* entry=array_get(&(s->fat),cluster);
567
        return le16_to_cpu(*entry);
568
    } else {
569
        const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
570
        return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
571
    }
572
}
573

    
574
static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
575
{
576
    if(fat_entry>s->max_fat_value-8)
577
        return -1;
578
    return 0;
579
}
580

    
581
static inline void init_fat(BDRVVVFATState* s)
582
{
583
    if (s->fat_type == 12) {
584
        array_init(&(s->fat),1);
585
        array_ensure_allocated(&(s->fat),
586
                s->sectors_per_fat * 0x200 * 3 / 2 - 1);
587
    } else {
588
        array_init(&(s->fat),(s->fat_type==32?4:2));
589
        array_ensure_allocated(&(s->fat),
590
                s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
591
    }
592
    memset(s->fat.pointer,0,s->fat.size);
593

    
594
    switch(s->fat_type) {
595
        case 12: s->max_fat_value=0xfff; break;
596
        case 16: s->max_fat_value=0xffff; break;
597
        case 32: s->max_fat_value=0x0fffffff; break;
598
        default: s->max_fat_value=0; /* error... */
599
    }
600

    
601
}
602

    
603
/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
604
/* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
605
static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
606
        unsigned int directory_start, const char* filename, int is_dot)
607
{
608
    int i,j,long_index=s->directory.next;
609
    direntry_t* entry=0;
610
    direntry_t* entry_long=0;
611

    
612
    if(is_dot) {
613
        entry=array_get_next(&(s->directory));
614
        memset(entry->name,0x20,11);
615
        memcpy(entry->name,filename,strlen(filename));
616
        return entry;
617
    }
618

    
619
    entry_long=create_long_filename(s,filename);
620

    
621
    i = strlen(filename);
622
    for(j = i - 1; j>0  && filename[j]!='.';j--);
623
    if (j > 0)
624
        i = (j > 8 ? 8 : j);
625
    else if (i > 8)
626
        i = 8;
627

    
628
    entry=array_get_next(&(s->directory));
629
    memset(entry->name,0x20,11);
630
    strncpy((char*)entry->name,filename,i);
631

    
632
    if(j > 0)
633
        for (i = 0; i < 3 && filename[j+1+i]; i++)
634
            entry->extension[i] = filename[j+1+i];
635

    
636
    /* upcase & remove unwanted characters */
637
    for(i=10;i>=0;i--) {
638
        if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
639
        if(entry->name[i]<=' ' || entry->name[i]>0x7f
640
                || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
641
            entry->name[i]='_';
642
        else if(entry->name[i]>='a' && entry->name[i]<='z')
643
            entry->name[i]+='A'-'a';
644
    }
645

    
646
    /* mangle duplicates */
647
    while(1) {
648
        direntry_t* entry1=array_get(&(s->directory),directory_start);
649
        int j;
650

    
651
        for(;entry1<entry;entry1++)
652
            if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
653
                break; /* found dupe */
654
        if(entry1==entry) /* no dupe found */
655
            break;
656

    
657
        /* use all 8 characters of name */
658
        if(entry->name[7]==' ') {
659
            int j;
660
            for(j=6;j>0 && entry->name[j]==' ';j--)
661
                entry->name[j]='~';
662
        }
663

    
664
        /* increment number */
665
        for(j=7;j>0 && entry->name[j]=='9';j--)
666
            entry->name[j]='0';
667
        if(j>0) {
668
            if(entry->name[j]<'0' || entry->name[j]>'9')
669
                entry->name[j]='0';
670
            else
671
                entry->name[j]++;
672
        }
673
    }
674

    
675
    /* calculate checksum; propagate to long name */
676
    if(entry_long) {
677
        uint8_t chksum=fat_chksum(entry);
678

    
679
        /* calculate anew, because realloc could have taken place */
680
        entry_long=array_get(&(s->directory),long_index);
681
        while(entry_long<entry && is_long_name(entry_long)) {
682
            entry_long->reserved[1]=chksum;
683
            entry_long++;
684
        }
685
    }
686

    
687
    return entry;
688
}
689

    
690
/*
691
 * Read a directory. (the index of the corresponding mapping must be passed).
692
 */
693
static int read_directory(BDRVVVFATState* s, int mapping_index)
694
{
695
    mapping_t* mapping = array_get(&(s->mapping), mapping_index);
696
    direntry_t* direntry;
697
    const char* dirname = mapping->path;
698
    int first_cluster = mapping->begin;
699
    int parent_index = mapping->info.dir.parent_mapping_index;
700
    mapping_t* parent_mapping = (mapping_t*)
701
        (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : 0);
702
    int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
703

    
704
    DIR* dir=opendir(dirname);
705
    struct dirent* entry;
706
    int i;
707

    
708
    assert(mapping->mode & MODE_DIRECTORY);
709

    
710
    if(!dir) {
711
        mapping->end = mapping->begin;
712
        return -1;
713
    }
714

    
715
    i = mapping->info.dir.first_dir_index =
716
            first_cluster == 0 ? 0 : s->directory.next;
717

    
718
    /* actually read the directory, and allocate the mappings */
719
    while((entry=readdir(dir))) {
720
        unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
721
        char* buffer;
722
        direntry_t* direntry;
723
        struct stat st;
724
        int is_dot=!strcmp(entry->d_name,".");
725
        int is_dotdot=!strcmp(entry->d_name,"..");
726

    
727
        if(first_cluster == 0 && (is_dotdot || is_dot))
728
            continue;
729

    
730
        buffer=(char*)malloc(length);
731
        assert(buffer);
732
        snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
733

    
734
        if(stat(buffer,&st)<0) {
735
            free(buffer);
736
            continue;
737
        }
738

    
739
        /* create directory entry for this file */
740
        direntry=create_short_and_long_name(s, i, entry->d_name,
741
                is_dot || is_dotdot);
742
        direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
743
        direntry->reserved[0]=direntry->reserved[1]=0;
744
        direntry->ctime=fat_datetime(st.st_ctime,1);
745
        direntry->cdate=fat_datetime(st.st_ctime,0);
746
        direntry->adate=fat_datetime(st.st_atime,0);
747
        direntry->begin_hi=0;
748
        direntry->mtime=fat_datetime(st.st_mtime,1);
749
        direntry->mdate=fat_datetime(st.st_mtime,0);
750
        if(is_dotdot)
751
            set_begin_of_direntry(direntry, first_cluster_of_parent);
752
        else if(is_dot)
753
            set_begin_of_direntry(direntry, first_cluster);
754
        else
755
            direntry->begin=0; /* do that later */
756
        if (st.st_size > 0x7fffffff) {
757
            fprintf(stderr, "File %s is larger than 2GB\n", buffer);
758
            free(buffer);
759
            return -2;
760
        }
761
        direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
762

    
763
        /* create mapping for this file */
764
        if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
765
            s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
766
            s->current_mapping->begin=0;
767
            s->current_mapping->end=st.st_size;
768
            /*
769
             * we get the direntry of the most recent direntry, which
770
             * contains the short name and all the relevant information.
771
             */
772
            s->current_mapping->dir_index=s->directory.next-1;
773
            s->current_mapping->first_mapping_index = -1;
774
            if (S_ISDIR(st.st_mode)) {
775
                s->current_mapping->mode = MODE_DIRECTORY;
776
                s->current_mapping->info.dir.parent_mapping_index =
777
                    mapping_index;
778
            } else {
779
                s->current_mapping->mode = MODE_UNDEFINED;
780
                s->current_mapping->info.file.offset = 0;
781
            }
782
            s->current_mapping->path=buffer;
783
            s->current_mapping->read_only =
784
                (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
785
        }
786
    }
787
    closedir(dir);
788

    
789
    /* fill with zeroes up to the end of the cluster */
790
    while(s->directory.next%(0x10*s->sectors_per_cluster)) {
791
        direntry_t* direntry=array_get_next(&(s->directory));
792
        memset(direntry,0,sizeof(direntry_t));
793
    }
794

    
795
/* TODO: if there are more entries, bootsector has to be adjusted! */
796
#define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
797
    if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
798
        /* root directory */
799
        int cur = s->directory.next;
800
        array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
801
        memset(array_get(&(s->directory), cur), 0,
802
                (ROOT_ENTRIES - cur) * sizeof(direntry_t));
803
    }
804

    
805
     /* reget the mapping, since s->mapping was possibly realloc()ed */
806
    mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
807
    first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
808
        * 0x20 / s->cluster_size;
809
    mapping->end = first_cluster;
810

    
811
    direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
812
    set_begin_of_direntry(direntry, mapping->begin);
813

    
814
    return 0;
815
}
816

    
817
static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
818
{
819
    return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
820
}
821

    
822
static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
823
{
824
    return s->faked_sectors + s->sectors_per_cluster * cluster_num;
825
}
826

    
827
static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
828
{
829
    return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
830
}
831

    
832
#ifdef DBG
833
static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
834
{
835
    if(mapping->mode==MODE_UNDEFINED)
836
        return 0;
837
    return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
838
}
839
#endif
840

    
841
static int init_directories(BDRVVVFATState* s,
842
        const char* dirname)
843
{
844
    bootsector_t* bootsector;
845
    mapping_t* mapping;
846
    unsigned int i;
847
    unsigned int cluster;
848

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

    
851
    s->cluster_size=s->sectors_per_cluster*0x200;
852
    s->cluster_buffer=malloc(s->cluster_size);
853
    assert(s->cluster_buffer);
854

    
855
    /*
856
     * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
857
     * where sc is sector_count,
858
     * spf is sectors_per_fat,
859
     * spc is sectors_per_clusters, and
860
     * fat_type = 12, 16 or 32.
861
     */
862
    i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
863
    s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
864

    
865
    array_init(&(s->mapping),sizeof(mapping_t));
866
    array_init(&(s->directory),sizeof(direntry_t));
867

    
868
    /* add volume label */
869
    {
870
        direntry_t* entry=array_get_next(&(s->directory));
871
        entry->attributes=0x28; /* archive | volume label */
872
        snprintf((char*)entry->name,11,"QEMU VVFAT");
873
    }
874

    
875
    /* Now build FAT, and write back information into directory */
876
    init_fat(s);
877

    
878
    s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
879
    s->cluster_count=sector2cluster(s, s->sector_count);
880

    
881
    mapping = array_get_next(&(s->mapping));
882
    mapping->begin = 0;
883
    mapping->dir_index = 0;
884
    mapping->info.dir.parent_mapping_index = -1;
885
    mapping->first_mapping_index = -1;
886
    mapping->path = strdup(dirname);
887
    i = strlen(mapping->path);
888
    if (i > 0 && mapping->path[i - 1] == '/')
889
        mapping->path[i - 1] = '\0';
890
    mapping->mode = MODE_DIRECTORY;
891
    mapping->read_only = 0;
892
    s->path = mapping->path;
893

    
894
    for (i = 0, cluster = 0; i < s->mapping.next; i++) {
895
        int j;
896
        /* MS-DOS expects the FAT to be 0 for the root directory
897
         * (except for the media byte). */
898
        /* LATER TODO: still true for FAT32? */
899
        int fix_fat = (i != 0);
900
        mapping = array_get(&(s->mapping), i);
901

    
902
        if (mapping->mode & MODE_DIRECTORY) {
903
            mapping->begin = cluster;
904
            if(read_directory(s, i)) {
905
                fprintf(stderr, "Could not read directory %s\n",
906
                        mapping->path);
907
                return -1;
908
            }
909
            mapping = array_get(&(s->mapping), i);
910
        } else {
911
            assert(mapping->mode == MODE_UNDEFINED);
912
            mapping->mode=MODE_NORMAL;
913
            mapping->begin = cluster;
914
            if (mapping->end > 0) {
915
                direntry_t* direntry = array_get(&(s->directory),
916
                        mapping->dir_index);
917

    
918
                mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
919
                set_begin_of_direntry(direntry, mapping->begin);
920
            } else {
921
                mapping->end = cluster + 1;
922
                fix_fat = 0;
923
            }
924
        }
925

    
926
        assert(mapping->begin < mapping->end);
927

    
928
        /* fix fat for entry */
929
        if (fix_fat) {
930
            for(j = mapping->begin; j < mapping->end - 1; j++)
931
                fat_set(s, j, j+1);
932
            fat_set(s, mapping->end - 1, s->max_fat_value);
933
        }
934

    
935
        /* next free cluster */
936
        cluster = mapping->end;
937

    
938
        if(cluster > s->cluster_count) {
939
            fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type);
940
            return -1;
941
        }
942
    }
943

    
944
    mapping = array_get(&(s->mapping), 0);
945
    s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
946
    s->last_cluster_of_root_directory = mapping->end;
947

    
948
    /* the FAT signature */
949
    fat_set(s,0,s->max_fat_value);
950
    fat_set(s,1,s->max_fat_value);
951

    
952
    s->current_mapping = NULL;
953

    
954
    bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
955
    bootsector->jump[0]=0xeb;
956
    bootsector->jump[1]=0x3e;
957
    bootsector->jump[2]=0x90;
958
    memcpy(bootsector->name,"QEMU    ",8);
959
    bootsector->sector_size=cpu_to_le16(0x200);
960
    bootsector->sectors_per_cluster=s->sectors_per_cluster;
961
    bootsector->reserved_sectors=cpu_to_le16(1);
962
    bootsector->number_of_fats=0x2; /* number of FATs */
963
    bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
964
    bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
965
    bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
966
    s->fat.pointer[0] = bootsector->media_type;
967
    bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
968
    bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
969
    bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
970
    bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
971
    bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
972

    
973
    /* LATER TODO: if FAT32, this is wrong */
974
    bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
975
    bootsector->u.fat16.current_head=0;
976
    bootsector->u.fat16.signature=0x29;
977
    bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
978

    
979
    memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
980
    memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12   ":s->fat_type==16?"FAT16   ":"FAT32   "),8);
981
    bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
982

    
983
    return 0;
984
}
985

    
986
#ifdef DEBUG
987
static BDRVVVFATState *vvv = NULL;
988
#endif
989

    
990
static int enable_write_target(BDRVVVFATState *s);
991
static int is_consistent(BDRVVVFATState *s);
992

    
993
static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
994
{
995
    BDRVVVFATState *s = bs->opaque;
996
    int floppy = 0;
997
    int i;
998

    
999
#ifdef DEBUG
1000
    vvv = s;
1001
#endif
1002

    
1003
DLOG(if (stderr == NULL) {
1004
    stderr = fopen("vvfat.log", "a");
1005
    setbuf(stderr, NULL);
1006
})
1007

    
1008
    s->bs = bs;
1009

    
1010
    s->fat_type=16;
1011
    /* LATER TODO: if FAT32, adjust */
1012
    s->sectors_per_cluster=0x10;
1013
    /* 504MB disk*/
1014
    bs->cyls=1024; bs->heads=16; bs->secs=63;
1015

    
1016
    s->current_cluster=0xffffffff;
1017

    
1018
    s->first_sectors_number=0x40;
1019
    /* read only is the default for safety */
1020
    bs->read_only = 1;
1021
    s->qcow = s->write_target = NULL;
1022
    s->qcow_filename = NULL;
1023
    s->fat2 = NULL;
1024
    s->downcase_short_names = 1;
1025

    
1026
    if (!strstart(dirname, "fat:", NULL))
1027
        return -1;
1028

    
1029
    if (strstr(dirname, ":floppy:")) {
1030
        floppy = 1;
1031
        s->fat_type = 12;
1032
        s->first_sectors_number = 1;
1033
        s->sectors_per_cluster=2;
1034
        bs->cyls = 80; bs->heads = 2; bs->secs = 36;
1035
    }
1036

    
1037
    s->sector_count=bs->cyls*bs->heads*bs->secs;
1038

    
1039
    if (strstr(dirname, ":32:")) {
1040
        fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1041
        s->fat_type = 32;
1042
    } else if (strstr(dirname, ":16:")) {
1043
        s->fat_type = 16;
1044
    } else if (strstr(dirname, ":12:")) {
1045
        s->fat_type = 12;
1046
        s->sector_count=2880;
1047
    }
1048

    
1049
    if (strstr(dirname, ":rw:")) {
1050
        if (enable_write_target(s))
1051
            return -1;
1052
        bs->read_only = 0;
1053
    }
1054

    
1055
    i = strrchr(dirname, ':') - dirname;
1056
    assert(i >= 3);
1057
    if (dirname[i-2] == ':' && isalpha(dirname[i-1]))
1058
        /* workaround for DOS drive names */
1059
        dirname += i-1;
1060
    else
1061
        dirname += i+1;
1062

    
1063
    bs->total_sectors=bs->cyls*bs->heads*bs->secs;
1064

    
1065
    if(init_directories(s, dirname))
1066
        return -1;
1067

    
1068
    s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
1069

    
1070
    if(s->first_sectors_number==0x40)
1071
        init_mbr(s);
1072

    
1073
    /* for some reason or other, MS-DOS does not like to know about CHS... */
1074
    if (floppy)
1075
        bs->heads = bs->cyls = bs->secs = 0;
1076

    
1077
    //    assert(is_consistent(s));
1078
    return 0;
1079
}
1080

    
1081
static inline void vvfat_close_current_file(BDRVVVFATState *s)
1082
{
1083
    if(s->current_mapping) {
1084
        s->current_mapping = NULL;
1085
        if (s->current_fd) {
1086
                close(s->current_fd);
1087
                s->current_fd = 0;
1088
        }
1089
    }
1090
    s->current_cluster = -1;
1091
}
1092

    
1093
/* mappings between index1 and index2-1 are supposed to be ordered
1094
 * return value is the index of the last mapping for which end>cluster_num
1095
 */
1096
static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1097
{
1098
    int index3=index1+1;
1099
    while(1) {
1100
        mapping_t* mapping;
1101
        index3=(index1+index2)/2;
1102
        mapping=array_get(&(s->mapping),index3);
1103
        assert(mapping->begin < mapping->end);
1104
        if(mapping->begin>=cluster_num) {
1105
            assert(index2!=index3 || index2==0);
1106
            if(index2==index3)
1107
                return index1;
1108
            index2=index3;
1109
        } else {
1110
            if(index1==index3)
1111
                return mapping->end<=cluster_num ? index2 : index1;
1112
            index1=index3;
1113
        }
1114
        assert(index1<=index2);
1115
        DLOG(mapping=array_get(&(s->mapping),index1);
1116
        assert(mapping->begin<=cluster_num);
1117
        assert(index2 >= s->mapping.next ||
1118
                ((mapping = array_get(&(s->mapping),index2)) &&
1119
                mapping->end>cluster_num)));
1120
    }
1121
}
1122

    
1123
static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
1124
{
1125
    int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
1126
    mapping_t* mapping;
1127
    if(index>=s->mapping.next)
1128
        return 0;
1129
    mapping=array_get(&(s->mapping),index);
1130
    if(mapping->begin>cluster_num)
1131
        return 0;
1132
    assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
1133
    return mapping;
1134
}
1135

    
1136
/*
1137
 * This function simply compares path == mapping->path. Since the mappings
1138
 * are sorted by cluster, this is expensive: O(n).
1139
 */
1140
static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
1141
        const char* path)
1142
{
1143
    int i;
1144

    
1145
    for (i = 0; i < s->mapping.next; i++) {
1146
        mapping_t* mapping = array_get(&(s->mapping), i);
1147
        if (mapping->first_mapping_index < 0 &&
1148
                !strcmp(path, mapping->path))
1149
            return mapping;
1150
    }
1151

    
1152
    return NULL;
1153
}
1154

    
1155
static int open_file(BDRVVVFATState* s,mapping_t* mapping)
1156
{
1157
    if(!mapping)
1158
        return -1;
1159
    if(!s->current_mapping ||
1160
            strcmp(s->current_mapping->path,mapping->path)) {
1161
        /* open file */
1162
        int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
1163
        if(fd<0)
1164
            return -1;
1165
        vvfat_close_current_file(s);
1166
        s->current_fd = fd;
1167
        s->current_mapping = mapping;
1168
    }
1169
    return 0;
1170
}
1171

    
1172
static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1173
{
1174
    if(s->current_cluster != cluster_num) {
1175
        int result=0;
1176
        off_t offset;
1177
        assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
1178
        if(!s->current_mapping
1179
                || s->current_mapping->begin>cluster_num
1180
                || s->current_mapping->end<=cluster_num) {
1181
            /* binary search of mappings for file */
1182
            mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
1183

    
1184
            assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1185

    
1186
            if (mapping && mapping->mode & MODE_DIRECTORY) {
1187
                vvfat_close_current_file(s);
1188
                s->current_mapping = mapping;
1189
read_cluster_directory:
1190
                offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
1191
                s->cluster = (unsigned char*)s->directory.pointer+offset
1192
                        + 0x20*s->current_mapping->info.dir.first_dir_index;
1193
                assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1194
                assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1195
                s->current_cluster = cluster_num;
1196
                return 0;
1197
            }
1198

    
1199
            if(open_file(s,mapping))
1200
                return -2;
1201
        } else if (s->current_mapping->mode & MODE_DIRECTORY)
1202
            goto read_cluster_directory;
1203

    
1204
        assert(s->current_fd);
1205

    
1206
        offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
1207
        if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1208
            return -3;
1209
        s->cluster=s->cluster_buffer;
1210
        result=read(s->current_fd,s->cluster,s->cluster_size);
1211
        if(result<0) {
1212
            s->current_cluster = -1;
1213
            return -1;
1214
        }
1215
        s->current_cluster = cluster_num;
1216
    }
1217
    return 0;
1218
}
1219

    
1220
#ifdef DEBUG
1221
static void hexdump(const void* address, uint32_t len)
1222
{
1223
    const unsigned char* p = address;
1224
    int i, j;
1225

    
1226
    for (i = 0; i < len; i += 16) {
1227
        for (j = 0; j < 16 && i + j < len; j++)
1228
            fprintf(stderr, "%02x ", p[i + j]);
1229
        for (; j < 16; j++)
1230
            fprintf(stderr, "   ");
1231
        fprintf(stderr, " ");
1232
        for (j = 0; j < 16 && i + j < len; j++)
1233
            fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
1234
        fprintf(stderr, "\n");
1235
    }
1236
}
1237

    
1238
static void print_direntry(const direntry_t* direntry)
1239
{
1240
    int j = 0;
1241
    char buffer[1024];
1242

    
1243
    fprintf(stderr, "direntry 0x%x: ", (int)direntry);
1244
    if(!direntry)
1245
        return;
1246
    if(is_long_name(direntry)) {
1247
        unsigned char* c=(unsigned char*)direntry;
1248
        int i;
1249
        for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
1250
#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = '?'; j++;}
1251
            ADD_CHAR(c[i]);
1252
        for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
1253
            ADD_CHAR(c[i]);
1254
        for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
1255
            ADD_CHAR(c[i]);
1256
        buffer[j] = 0;
1257
        fprintf(stderr, "%s\n", buffer);
1258
    } else {
1259
        int i;
1260
        for(i=0;i<11;i++)
1261
            ADD_CHAR(direntry->name[i]);
1262
        buffer[j] = 0;
1263
        fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1264
                buffer,
1265
                direntry->attributes,
1266
                begin_of_direntry(direntry),le32_to_cpu(direntry->size));
1267
    }
1268
}
1269

    
1270
static void print_mapping(const mapping_t* mapping)
1271
{
1272
    fprintf(stderr, "mapping (0x%x): begin, end = %d, %d, dir_index = %d, first_mapping_index = %d, name = %s, mode = 0x%x, " , (int)mapping, mapping->begin, mapping->end, mapping->dir_index, mapping->first_mapping_index, mapping->path, mapping->mode);
1273
    if (mapping->mode & MODE_DIRECTORY)
1274
        fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1275
    else
1276
        fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
1277
}
1278
#endif
1279

    
1280
static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
1281
                    uint8_t *buf, int nb_sectors)
1282
{
1283
    BDRVVVFATState *s = bs->opaque;
1284
    int i;
1285

    
1286
    for(i=0;i<nb_sectors;i++,sector_num++) {
1287
        if (sector_num >= s->sector_count)
1288
           return -1;
1289
        if (s->qcow) {
1290
            int n;
1291
            if (s->qcow->drv->bdrv_is_allocated(s->qcow,
1292
                        sector_num, nb_sectors-i, &n)) {
1293
DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
1294
                if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
1295
                    return -1;
1296
                i += n - 1;
1297
                sector_num += n - 1;
1298
                continue;
1299
            }
1300
DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
1301
        }
1302
        if(sector_num<s->faked_sectors) {
1303
            if(sector_num<s->first_sectors_number)
1304
                memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
1305
            else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
1306
                memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
1307
            else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
1308
                memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
1309
        } else {
1310
            uint32_t sector=sector_num-s->faked_sectors,
1311
            sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1312
            cluster_num=sector/s->sectors_per_cluster;
1313
            if(read_cluster(s, cluster_num) != 0) {
1314
                /* LATER TODO: strict: return -1; */
1315
                memset(buf+i*0x200,0,0x200);
1316
                continue;
1317
            }
1318
            memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
1319
        }
1320
    }
1321
    return 0;
1322
}
1323

    
1324
/* LATER TODO: statify all functions */
1325

    
1326
/*
1327
 * Idea of the write support (use snapshot):
1328
 *
1329
 * 1. check if all data is consistent, recording renames, modifications,
1330
 *    new files and directories (in s->commits).
1331
 *
1332
 * 2. if the data is not consistent, stop committing
1333
 *
1334
 * 3. handle renames, and create new files and directories (do not yet
1335
 *    write their contents)
1336
 *
1337
 * 4. walk the directories, fixing the mapping and direntries, and marking
1338
 *    the handled mappings as not deleted
1339
 *
1340
 * 5. commit the contents of the files
1341
 *
1342
 * 6. handle deleted files and directories
1343
 *
1344
 */
1345

    
1346
typedef struct commit_t {
1347
    char* path;
1348
    union {
1349
        struct { uint32_t cluster; } rename;
1350
        struct { int dir_index; uint32_t modified_offset; } writeout;
1351
        struct { uint32_t first_cluster; } new_file;
1352
        struct { uint32_t cluster; } mkdir;
1353
    } param;
1354
    /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1355
    enum {
1356
        ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1357
    } action;
1358
} commit_t;
1359

    
1360
static void clear_commits(BDRVVVFATState* s)
1361
{
1362
    int i;
1363
DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1364
    for (i = 0; i < s->commits.next; i++) {
1365
        commit_t* commit = array_get(&(s->commits), i);
1366
        assert(commit->path || commit->action == ACTION_WRITEOUT);
1367
        if (commit->action != ACTION_WRITEOUT) {
1368
            assert(commit->path);
1369
            free(commit->path);
1370
        } else
1371
            assert(commit->path == NULL);
1372
    }
1373
    s->commits.next = 0;
1374
}
1375

    
1376
static void schedule_rename(BDRVVVFATState* s,
1377
        uint32_t cluster, char* new_path)
1378
{
1379
    commit_t* commit = array_get_next(&(s->commits));
1380
    commit->path = new_path;
1381
    commit->param.rename.cluster = cluster;
1382
    commit->action = ACTION_RENAME;
1383
}
1384

    
1385
static void schedule_writeout(BDRVVVFATState* s,
1386
        int dir_index, uint32_t modified_offset)
1387
{
1388
    commit_t* commit = array_get_next(&(s->commits));
1389
    commit->path = NULL;
1390
    commit->param.writeout.dir_index = dir_index;
1391
    commit->param.writeout.modified_offset = modified_offset;
1392
    commit->action = ACTION_WRITEOUT;
1393
}
1394

    
1395
static void schedule_new_file(BDRVVVFATState* s,
1396
        char* path, uint32_t first_cluster)
1397
{
1398
    commit_t* commit = array_get_next(&(s->commits));
1399
    commit->path = path;
1400
    commit->param.new_file.first_cluster = first_cluster;
1401
    commit->action = ACTION_NEW_FILE;
1402
}
1403

    
1404
static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1405
{
1406
    commit_t* commit = array_get_next(&(s->commits));
1407
    commit->path = path;
1408
    commit->param.mkdir.cluster = cluster;
1409
    commit->action = ACTION_MKDIR;
1410
}
1411

    
1412
typedef struct {
1413
    /*
1414
     * Since the sequence number is at most 0x3f, and the filename
1415
     * length is at most 13 times the sequence number, the maximal
1416
     * filename length is 0x3f * 13 bytes.
1417
     */
1418
    unsigned char name[0x3f * 13 + 1];
1419
    int checksum, len;
1420
    int sequence_number;
1421
} long_file_name;
1422

    
1423
static void lfn_init(long_file_name* lfn)
1424
{
1425
   lfn->sequence_number = lfn->len = 0;
1426
   lfn->checksum = 0x100;
1427
}
1428

    
1429
/* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1430
static int parse_long_name(long_file_name* lfn,
1431
        const direntry_t* direntry)
1432
{
1433
    int i, j, offset;
1434
    const unsigned char* pointer = (const unsigned char*)direntry;
1435

    
1436
    if (!is_long_name(direntry))
1437
        return 1;
1438

    
1439
    if (pointer[0] & 0x40) {
1440
        lfn->sequence_number = pointer[0] & 0x3f;
1441
        lfn->checksum = pointer[13];
1442
        lfn->name[0] = 0;
1443
        lfn->name[lfn->sequence_number * 13] = 0;
1444
    } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
1445
        return -1;
1446
    else if (pointer[13] != lfn->checksum)
1447
        return -2;
1448
    else if (pointer[12] || pointer[26] || pointer[27])
1449
        return -3;
1450

    
1451
    offset = 13 * (lfn->sequence_number - 1);
1452
    for (i = 0, j = 1; i < 13; i++, j+=2) {
1453
        if (j == 11)
1454
            j = 14;
1455
        else if (j == 26)
1456
            j = 28;
1457

    
1458
        if (pointer[j+1] == 0)
1459
            lfn->name[offset + i] = pointer[j];
1460
        else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1461
            return -4;
1462
        else
1463
            lfn->name[offset + i] = 0;
1464
    }
1465

    
1466
    if (pointer[0] & 0x40)
1467
        lfn->len = offset + strlen((char*)lfn->name + offset);
1468

    
1469
    return 0;
1470
}
1471

    
1472
/* returns 0 if successful, >0 if no short_name, and <0 on error */
1473
static int parse_short_name(BDRVVVFATState* s,
1474
        long_file_name* lfn, direntry_t* direntry)
1475
{
1476
    int i, j;
1477

    
1478
    if (!is_short_name(direntry))
1479
        return 1;
1480

    
1481
    for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1482
    for (i = 0; i <= j; i++) {
1483
        if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
1484
            return -1;
1485
        else if (s->downcase_short_names)
1486
            lfn->name[i] = tolower(direntry->name[i]);
1487
        else
1488
            lfn->name[i] = direntry->name[i];
1489
    }
1490

    
1491
    for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
1492
    if (j >= 0) {
1493
        lfn->name[i++] = '.';
1494
        lfn->name[i + j + 1] = '\0';
1495
        for (;j >= 0; j--) {
1496
            if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
1497
                return -2;
1498
            else if (s->downcase_short_names)
1499
                lfn->name[i + j] = tolower(direntry->extension[j]);
1500
            else
1501
                lfn->name[i + j] = direntry->extension[j];
1502
        }
1503
    } else
1504
        lfn->name[i + j + 1] = '\0';
1505

    
1506
    lfn->len = strlen((char*)lfn->name);
1507

    
1508
    return 0;
1509
}
1510

    
1511
static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1512
        unsigned int cluster)
1513
{
1514
    if (cluster < s->last_cluster_of_root_directory) {
1515
        if (cluster + 1 == s->last_cluster_of_root_directory)
1516
            return s->max_fat_value;
1517
        else
1518
            return cluster + 1;
1519
    }
1520

    
1521
    if (s->fat_type==32) {
1522
        uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1523
        return le32_to_cpu(*entry);
1524
    } else if (s->fat_type==16) {
1525
        uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1526
        return le16_to_cpu(*entry);
1527
    } else {
1528
        const uint8_t* x=s->fat2+cluster*3/2;
1529
        return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1530
    }
1531
}
1532

    
1533
static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1534
{
1535
    int was_modified = 0;
1536
    int i, dummy;
1537

    
1538
    if (s->qcow == NULL)
1539
        return 0;
1540

    
1541
    for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
1542
        was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
1543
                cluster2sector(s, cluster_num) + i, 1, &dummy);
1544

    
1545
    return was_modified;
1546
}
1547

    
1548
static const char* get_basename(const char* path)
1549
{
1550
    char* basename = strrchr(path, '/');
1551
    if (basename == NULL)
1552
        return path;
1553
    else
1554
        return basename + 1; /* strip '/' */
1555
}
1556

    
1557
/*
1558
 * The array s->used_clusters holds the states of the clusters. If it is
1559
 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1560
 * was modified, bit 3 is set.
1561
 * If any cluster is allocated, but not part of a file or directory, this
1562
 * driver refuses to commit.
1563
 */
1564
typedef enum {
1565
     USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
1566
} used_t;
1567

    
1568
/*
1569
 * get_cluster_count_for_direntry() not only determines how many clusters
1570
 * are occupied by direntry, but also if it was renamed or modified.
1571
 *
1572
 * A file is thought to be renamed *only* if there already was a file with
1573
 * exactly the same first cluster, but a different name.
1574
 *
1575
 * Further, the files/directories handled by this function are
1576
 * assumed to be *not* deleted (and *only* those).
1577
 */
1578
static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
1579
        direntry_t* direntry, const char* path)
1580
{
1581
    /*
1582
     * This is a little bit tricky:
1583
     * IF the guest OS just inserts a cluster into the file chain,
1584
     * and leaves the rest alone, (i.e. the original file had clusters
1585
     * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1586
     *
1587
     * - do_commit will write the cluster into the file at the given
1588
     *   offset, but
1589
     *
1590
     * - the cluster which is overwritten should be moved to a later
1591
     *   position in the file.
1592
     *
1593
     * I am not aware that any OS does something as braindead, but this
1594
     * situation could happen anyway when not committing for a long time.
1595
     * Just to be sure that this does not bite us, detect it, and copy the
1596
     * contents of the clusters to-be-overwritten into the qcow.
1597
     */
1598
    int copy_it = 0;
1599
    int was_modified = 0;
1600
    int32_t ret = 0;
1601

    
1602
    uint32_t cluster_num = begin_of_direntry(direntry);
1603
    uint32_t offset = 0;
1604
    int first_mapping_index = -1;
1605
    mapping_t* mapping = NULL;
1606
    const char* basename2 = NULL;
1607

    
1608
    vvfat_close_current_file(s);
1609

    
1610
    /* the root directory */
1611
    if (cluster_num == 0)
1612
        return 0;
1613

    
1614
    /* write support */
1615
    if (s->qcow) {
1616
        basename2 = get_basename(path);
1617

    
1618
        mapping = find_mapping_for_cluster(s, cluster_num);
1619

    
1620
        if (mapping) {
1621
            const char* basename;
1622

    
1623
            assert(mapping->mode & MODE_DELETED);
1624
            mapping->mode &= ~MODE_DELETED;
1625

    
1626
            basename = get_basename(mapping->path);
1627

    
1628
            assert(mapping->mode & MODE_NORMAL);
1629

    
1630
            /* rename */
1631
            if (strcmp(basename, basename2))
1632
                schedule_rename(s, cluster_num, strdup(path));
1633
        } else if (is_file(direntry))
1634
            /* new file */
1635
            schedule_new_file(s, strdup(path), cluster_num);
1636
        else {
1637
            assert(0);
1638
            return 0;
1639
        }
1640
    }
1641

    
1642
    while(1) {
1643
        if (s->qcow) {
1644
            if (!copy_it && cluster_was_modified(s, cluster_num)) {
1645
                if (mapping == NULL ||
1646
                        mapping->begin > cluster_num ||
1647
                        mapping->end <= cluster_num)
1648
                mapping = find_mapping_for_cluster(s, cluster_num);
1649

    
1650

    
1651
                if (mapping &&
1652
                        (mapping->mode & MODE_DIRECTORY) == 0) {
1653

    
1654
                    /* was modified in qcow */
1655
                    if (offset != mapping->info.file.offset + s->cluster_size
1656
                            * (cluster_num - mapping->begin)) {
1657
                        /* offset of this cluster in file chain has changed */
1658
                        assert(0);
1659
                        copy_it = 1;
1660
                    } else if (offset == 0) {
1661
                        const char* basename = get_basename(mapping->path);
1662

    
1663
                        if (strcmp(basename, basename2))
1664
                            copy_it = 1;
1665
                        first_mapping_index = array_index(&(s->mapping), mapping);
1666
                    }
1667

    
1668
                    if (mapping->first_mapping_index != first_mapping_index
1669
                            && mapping->info.file.offset > 0) {
1670
                        assert(0);
1671
                        copy_it = 1;
1672
                    }
1673

    
1674
                    /* need to write out? */
1675
                    if (!was_modified && is_file(direntry)) {
1676
                        was_modified = 1;
1677
                        schedule_writeout(s, mapping->dir_index, offset);
1678
                    }
1679
                }
1680
            }
1681

    
1682
            if (copy_it) {
1683
                int i, dummy;
1684
                /*
1685
                 * This is horribly inefficient, but that is okay, since
1686
                 * it is rarely executed, if at all.
1687
                 */
1688
                int64_t offset = cluster2sector(s, cluster_num);
1689

    
1690
                vvfat_close_current_file(s);
1691
                for (i = 0; i < s->sectors_per_cluster; i++)
1692
                    if (!s->qcow->drv->bdrv_is_allocated(s->qcow,
1693
                                offset + i, 1, &dummy)) {
1694
                        if (vvfat_read(s->bs,
1695
                                    offset, s->cluster_buffer, 1))
1696
                            return -1;
1697
                        if (s->qcow->drv->bdrv_write(s->qcow,
1698
                                    offset, s->cluster_buffer, 1))
1699
                            return -2;
1700
                    }
1701
            }
1702
        }
1703

    
1704
        ret++;
1705
        if (s->used_clusters[cluster_num] & USED_ANY)
1706
            return 0;
1707
        s->used_clusters[cluster_num] = USED_FILE;
1708

    
1709
        cluster_num = modified_fat_get(s, cluster_num);
1710

    
1711
        if (fat_eof(s, cluster_num))
1712
            return ret;
1713
        else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
1714
            return -1;
1715

    
1716
        offset += s->cluster_size;
1717
    }
1718
}
1719

    
1720
/*
1721
 * This function looks at the modified data (qcow).
1722
 * It returns 0 upon inconsistency or error, and the number of clusters
1723
 * used by the directory, its subdirectories and their files.
1724
 */
1725
static int check_directory_consistency(BDRVVVFATState *s,
1726
        int cluster_num, const char* path)
1727
{
1728
    int ret = 0;
1729
    unsigned char* cluster = malloc(s->cluster_size);
1730
    direntry_t* direntries = (direntry_t*)cluster;
1731
    mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
1732

    
1733
    long_file_name lfn;
1734
    int path_len = strlen(path);
1735
    char path2[PATH_MAX];
1736

    
1737
    assert(path_len < PATH_MAX); /* len was tested before! */
1738
    strcpy(path2, path);
1739
    path2[path_len] = '/';
1740
    path2[path_len + 1] = '\0';
1741

    
1742
    if (mapping) {
1743
        const char* basename = get_basename(mapping->path);
1744
        const char* basename2 = get_basename(path);
1745

    
1746
        assert(mapping->mode & MODE_DIRECTORY);
1747

    
1748
        assert(mapping->mode & MODE_DELETED);
1749
        mapping->mode &= ~MODE_DELETED;
1750

    
1751
        if (strcmp(basename, basename2))
1752
            schedule_rename(s, cluster_num, strdup(path));
1753
    } else
1754
        /* new directory */
1755
        schedule_mkdir(s, cluster_num, strdup(path));
1756

    
1757
    lfn_init(&lfn);
1758
    do {
1759
        int i;
1760
        int subret = 0;
1761

    
1762
        ret++;
1763

    
1764
        if (s->used_clusters[cluster_num] & USED_ANY) {
1765
            fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
1766
            return 0;
1767
        }
1768
        s->used_clusters[cluster_num] = USED_DIRECTORY;
1769

    
1770
DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
1771
        subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
1772
                s->sectors_per_cluster);
1773
        if (subret) {
1774
            fprintf(stderr, "Error fetching direntries\n");
1775
        fail:
1776
            free(cluster);
1777
            return 0;
1778
        }
1779

    
1780
        for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
1781
            int cluster_count;
1782

    
1783
DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
1784
            if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
1785
                    is_free(direntries + i))
1786
                continue;
1787

    
1788
            subret = parse_long_name(&lfn, direntries + i);
1789
            if (subret < 0) {
1790
                fprintf(stderr, "Error in long name\n");
1791
                goto fail;
1792
            }
1793
            if (subret == 0 || is_free(direntries + i))
1794
                continue;
1795

    
1796
            if (fat_chksum(direntries+i) != lfn.checksum) {
1797
                subret = parse_short_name(s, &lfn, direntries + i);
1798
                if (subret < 0) {
1799
                    fprintf(stderr, "Error in short name (%d)\n", subret);
1800
                    goto fail;
1801
                }
1802
                if (subret > 0 || !strcmp((char*)lfn.name, ".")
1803
                        || !strcmp((char*)lfn.name, ".."))
1804
                    continue;
1805
            }
1806
            lfn.checksum = 0x100; /* cannot use long name twice */
1807

    
1808
            if (path_len + 1 + lfn.len >= PATH_MAX) {
1809
                fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
1810
                goto fail;
1811
            }
1812
            strcpy(path2 + path_len + 1, (char*)lfn.name);
1813

    
1814
            if (is_directory(direntries + i)) {
1815
                if (begin_of_direntry(direntries + i) == 0) {
1816
                    DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
1817
                    goto fail;
1818
                }
1819
                cluster_count = check_directory_consistency(s,
1820
                        begin_of_direntry(direntries + i), path2);
1821
                if (cluster_count == 0) {
1822
                    DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
1823
                    goto fail;
1824
                }
1825
            } else if (is_file(direntries + i)) {
1826
                /* check file size with FAT */
1827
                cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
1828
                if (cluster_count !=
1829
                        (le32_to_cpu(direntries[i].size) + s->cluster_size
1830
                         - 1) / s->cluster_size) {
1831
                    DLOG(fprintf(stderr, "Cluster count mismatch\n"));
1832
                    goto fail;
1833
                }
1834
            } else
1835
                assert(0); /* cluster_count = 0; */
1836

    
1837
            ret += cluster_count;
1838
        }
1839

    
1840
        cluster_num = modified_fat_get(s, cluster_num);
1841
    } while(!fat_eof(s, cluster_num));
1842

    
1843
    free(cluster);
1844
    return ret;
1845
}
1846

    
1847
/* returns 1 on success */
1848
static int is_consistent(BDRVVVFATState* s)
1849
{
1850
    int i, check;
1851
    int used_clusters_count = 0;
1852

    
1853
DLOG(checkpoint());
1854
    /*
1855
     * - get modified FAT
1856
     * - compare the two FATs (TODO)
1857
     * - get buffer for marking used clusters
1858
     * - recurse direntries from root (using bs->bdrv_read to make
1859
     *    sure to get the new data)
1860
     *   - check that the FAT agrees with the size
1861
     *   - count the number of clusters occupied by this directory and
1862
     *     its files
1863
     * - check that the cumulative used cluster count agrees with the
1864
     *   FAT
1865
     * - if all is fine, return number of used clusters
1866
     */
1867
    if (s->fat2 == NULL) {
1868
        int size = 0x200 * s->sectors_per_fat;
1869
        s->fat2 = malloc(size);
1870
        memcpy(s->fat2, s->fat.pointer, size);
1871
    }
1872
    check = vvfat_read(s->bs,
1873
            s->first_sectors_number, s->fat2, s->sectors_per_fat);
1874
    if (check) {
1875
        fprintf(stderr, "Could not copy fat\n");
1876
        return 0;
1877
    }
1878
    assert (s->used_clusters);
1879
    for (i = 0; i < sector2cluster(s, s->sector_count); i++)
1880
        s->used_clusters[i] &= ~USED_ANY;
1881

    
1882
    clear_commits(s);
1883

    
1884
    /* mark every mapped file/directory as deleted.
1885
     * (check_directory_consistency() will unmark those still present). */
1886
    if (s->qcow)
1887
        for (i = 0; i < s->mapping.next; i++) {
1888
            mapping_t* mapping = array_get(&(s->mapping), i);
1889
            if (mapping->first_mapping_index < 0)
1890
                mapping->mode |= MODE_DELETED;
1891
        }
1892

    
1893
    used_clusters_count = check_directory_consistency(s, 0, s->path);
1894
    if (used_clusters_count <= 0) {
1895
        DLOG(fprintf(stderr, "problem in directory\n"));
1896
        return 0;
1897
    }
1898

    
1899
    check = s->last_cluster_of_root_directory;
1900
    for (i = check; i < sector2cluster(s, s->sector_count); i++) {
1901
        if (modified_fat_get(s, i)) {
1902
            if(!s->used_clusters[i]) {
1903
                DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
1904
                return 0;
1905
            }
1906
            check++;
1907
        }
1908

    
1909
        if (s->used_clusters[i] == USED_ALLOCATED) {
1910
            /* allocated, but not used... */
1911
            DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
1912
            return 0;
1913
        }
1914
    }
1915

    
1916
    if (check != used_clusters_count)
1917
        return 0;
1918

    
1919
    return used_clusters_count;
1920
}
1921

    
1922
static inline void adjust_mapping_indices(BDRVVVFATState* s,
1923
        int offset, int adjust)
1924
{
1925
    int i;
1926

    
1927
    for (i = 0; i < s->mapping.next; i++) {
1928
        mapping_t* mapping = array_get(&(s->mapping), i);
1929

    
1930
#define ADJUST_MAPPING_INDEX(name) \
1931
        if (mapping->name >= offset) \
1932
            mapping->name += adjust
1933

    
1934
        ADJUST_MAPPING_INDEX(first_mapping_index);
1935
        if (mapping->mode & MODE_DIRECTORY)
1936
            ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
1937
    }
1938
}
1939

    
1940
/* insert or update mapping */
1941
static mapping_t* insert_mapping(BDRVVVFATState* s,
1942
        uint32_t begin, uint32_t end)
1943
{
1944
    /*
1945
     * - find mapping where mapping->begin >= begin,
1946
     * - if mapping->begin > begin: insert
1947
     *   - adjust all references to mappings!
1948
     * - else: adjust
1949
     * - replace name
1950
     */
1951
    int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
1952
    mapping_t* mapping = NULL;
1953
    mapping_t* first_mapping = array_get(&(s->mapping), 0);
1954

    
1955
    if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
1956
            && mapping->begin < begin) {
1957
        mapping->end = begin;
1958
        index++;
1959
        mapping = array_get(&(s->mapping), index);
1960
    }
1961
    if (index >= s->mapping.next || mapping->begin > begin) {
1962
        mapping = array_insert(&(s->mapping), index, 1);
1963
        mapping->path = NULL;
1964
        adjust_mapping_indices(s, index, +1);
1965
    }
1966

    
1967
    mapping->begin = begin;
1968
    mapping->end = end;
1969

    
1970
DLOG(mapping_t* next_mapping;
1971
assert(index + 1 >= s->mapping.next ||
1972
((next_mapping = array_get(&(s->mapping), index + 1)) &&
1973
 next_mapping->begin >= end)));
1974

    
1975
    if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1976
        s->current_mapping = array_get(&(s->mapping),
1977
                s->current_mapping - first_mapping);
1978

    
1979
    return mapping;
1980
}
1981

    
1982
static int remove_mapping(BDRVVVFATState* s, int mapping_index)
1983
{
1984
    mapping_t* mapping = array_get(&(s->mapping), mapping_index);
1985
    mapping_t* first_mapping = array_get(&(s->mapping), 0);
1986

    
1987
    /* free mapping */
1988
    if (mapping->first_mapping_index < 0)
1989
        free(mapping->path);
1990

    
1991
    /* remove from s->mapping */
1992
    array_remove(&(s->mapping), mapping_index);
1993

    
1994
    /* adjust all references to mappings */
1995
    adjust_mapping_indices(s, mapping_index, -1);
1996

    
1997
    if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1998
        s->current_mapping = array_get(&(s->mapping),
1999
                s->current_mapping - first_mapping);
2000

    
2001
    return 0;
2002
}
2003

    
2004
static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
2005
{
2006
    int i;
2007
    for (i = 0; i < s->mapping.next; i++) {
2008
        mapping_t* mapping = array_get(&(s->mapping), i);
2009
        if (mapping->dir_index >= offset)
2010
            mapping->dir_index += adjust;
2011
        if ((mapping->mode & MODE_DIRECTORY) &&
2012
                mapping->info.dir.first_dir_index >= offset)
2013
            mapping->info.dir.first_dir_index += adjust;
2014
    }
2015
}
2016

    
2017
static direntry_t* insert_direntries(BDRVVVFATState* s,
2018
        int dir_index, int count)
2019
{
2020
    /*
2021
     * make room in s->directory,
2022
     * adjust_dirindices
2023
     */
2024
    direntry_t* result = array_insert(&(s->directory), dir_index, count);
2025
    if (result == NULL)
2026
        return NULL;
2027
    adjust_dirindices(s, dir_index, count);
2028
    return result;
2029
}
2030

    
2031
static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
2032
{
2033
    int ret = array_remove_slice(&(s->directory), dir_index, count);
2034
    if (ret)
2035
        return ret;
2036
    adjust_dirindices(s, dir_index, -count);
2037
    return 0;
2038
}
2039

    
2040
/*
2041
 * Adapt the mappings of the cluster chain starting at first cluster
2042
 * (i.e. if a file starts at first_cluster, the chain is followed according
2043
 * to the modified fat, and the corresponding entries in s->mapping are
2044
 * adjusted)
2045
 */
2046
static int commit_mappings(BDRVVVFATState* s,
2047
        uint32_t first_cluster, int dir_index)
2048
{
2049
    mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2050
    direntry_t* direntry = array_get(&(s->directory), dir_index);
2051
    uint32_t cluster = first_cluster;
2052

    
2053
    vvfat_close_current_file(s);
2054

    
2055
    assert(mapping);
2056
    assert(mapping->begin == first_cluster);
2057
    mapping->first_mapping_index = -1;
2058
    mapping->dir_index = dir_index;
2059
    mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2060
        MODE_DIRECTORY : MODE_NORMAL;
2061

    
2062
    while (!fat_eof(s, cluster)) {
2063
        uint32_t c, c1;
2064

    
2065
        for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2066
                c = c1, c1 = modified_fat_get(s, c1));
2067

    
2068
        c++;
2069
        if (c > mapping->end) {
2070
            int index = array_index(&(s->mapping), mapping);
2071
            int i, max_i = s->mapping.next - index;
2072
            for (i = 1; i < max_i && mapping[i].begin < c; i++);
2073
            while (--i > 0)
2074
                remove_mapping(s, index + 1);
2075
        }
2076
        assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2077
                || mapping[1].begin >= c);
2078
        mapping->end = c;
2079

    
2080
        if (!fat_eof(s, c1)) {
2081
            int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2082
            mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2083
                array_get(&(s->mapping), i);
2084

    
2085
            if (next_mapping == NULL || next_mapping->begin > c1) {
2086
                int i1 = array_index(&(s->mapping), mapping);
2087

    
2088
                next_mapping = insert_mapping(s, c1, c1+1);
2089

    
2090
                if (c1 < c)
2091
                    i1++;
2092
                mapping = array_get(&(s->mapping), i1);
2093
            }
2094

    
2095
            next_mapping->dir_index = mapping->dir_index;
2096
            next_mapping->first_mapping_index =
2097
                mapping->first_mapping_index < 0 ?
2098
                array_index(&(s->mapping), mapping) :
2099
                mapping->first_mapping_index;
2100
            next_mapping->path = mapping->path;
2101
            next_mapping->mode = mapping->mode;
2102
            next_mapping->read_only = mapping->read_only;
2103
            if (mapping->mode & MODE_DIRECTORY) {
2104
                next_mapping->info.dir.parent_mapping_index =
2105
                        mapping->info.dir.parent_mapping_index;
2106
                next_mapping->info.dir.first_dir_index =
2107
                        mapping->info.dir.first_dir_index +
2108
                        0x10 * s->sectors_per_cluster *
2109
                        (mapping->end - mapping->begin);
2110
            } else
2111
                next_mapping->info.file.offset = mapping->info.file.offset +
2112
                        mapping->end - mapping->begin;
2113

    
2114
            mapping = next_mapping;
2115
        }
2116

    
2117
        cluster = c1;
2118
    }
2119

    
2120
    return 0;
2121
}
2122

    
2123
static int commit_direntries(BDRVVVFATState* s,
2124
        int dir_index, int parent_mapping_index)
2125
{
2126
    direntry_t* direntry = array_get(&(s->directory), dir_index);
2127
    uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
2128
    mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2129

    
2130
    int factor = 0x10 * s->sectors_per_cluster;
2131
    int old_cluster_count, new_cluster_count;
2132
    int current_dir_index = mapping->info.dir.first_dir_index;
2133
    int first_dir_index = current_dir_index;
2134
    int ret, i;
2135
    uint32_t c;
2136

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

    
2139
    assert(direntry);
2140
    assert(mapping);
2141
    assert(mapping->begin == first_cluster);
2142
    assert(mapping->info.dir.first_dir_index < s->directory.next);
2143
    assert(mapping->mode & MODE_DIRECTORY);
2144
    assert(dir_index == 0 || is_directory(direntry));
2145

    
2146
    mapping->info.dir.parent_mapping_index = parent_mapping_index;
2147

    
2148
    if (first_cluster == 0) {
2149
        old_cluster_count = new_cluster_count =
2150
            s->last_cluster_of_root_directory;
2151
    } else {
2152
        for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2153
                c = fat_get(s, c))
2154
            old_cluster_count++;
2155

    
2156
        for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2157
                c = modified_fat_get(s, c))
2158
            new_cluster_count++;
2159
    }
2160

    
2161
    if (new_cluster_count > old_cluster_count) {
2162
        if (insert_direntries(s,
2163
                current_dir_index + factor * old_cluster_count,
2164
                factor * (new_cluster_count - old_cluster_count)) == NULL)
2165
            return -1;
2166
    } else if (new_cluster_count < old_cluster_count)
2167
        remove_direntries(s,
2168
                current_dir_index + factor * new_cluster_count,
2169
                factor * (old_cluster_count - new_cluster_count));
2170

    
2171
    for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
2172
        void* direntry = array_get(&(s->directory), current_dir_index);
2173
        int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2174
                s->sectors_per_cluster);
2175
        if (ret)
2176
            return ret;
2177
        assert(!strncmp(s->directory.pointer, "QEMU", 4));
2178
        current_dir_index += factor;
2179
    }
2180

    
2181
    ret = commit_mappings(s, first_cluster, dir_index);
2182
    if (ret)
2183
        return ret;
2184

    
2185
    /* recurse */
2186
    for (i = 0; i < factor * new_cluster_count; i++) {
2187
        direntry = array_get(&(s->directory), first_dir_index + i);
2188
        if (is_directory(direntry) && !is_dot(direntry)) {
2189
            mapping = find_mapping_for_cluster(s, first_cluster);
2190
            assert(mapping->mode & MODE_DIRECTORY);
2191
            ret = commit_direntries(s, first_dir_index + i,
2192
                array_index(&(s->mapping), mapping));
2193
            if (ret)
2194
                return ret;
2195
        }
2196
    }
2197

    
2198
    return 0;
2199
}
2200

    
2201
/* commit one file (adjust contents, adjust mapping),
2202
   return first_mapping_index */
2203
static int commit_one_file(BDRVVVFATState* s,
2204
        int dir_index, uint32_t offset)
2205
{
2206
    direntry_t* direntry = array_get(&(s->directory), dir_index);
2207
    uint32_t c = begin_of_direntry(direntry);
2208
    uint32_t first_cluster = c;
2209
    mapping_t* mapping = find_mapping_for_cluster(s, c);
2210
    uint32_t size = filesize_of_direntry(direntry);
2211
    char* cluster = malloc(s->cluster_size);
2212
    uint32_t i;
2213
    int fd = 0;
2214

    
2215
    assert(offset < size);
2216
    assert((offset % s->cluster_size) == 0);
2217

    
2218
    for (i = s->cluster_size; i < offset; i += s->cluster_size)
2219
        c = modified_fat_get(s, c);
2220

    
2221
    fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
2222
    if (fd < 0) {
2223
        fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2224
                strerror(errno), errno);
2225
        return fd;
2226
    }
2227
    if (offset > 0)
2228
        if (lseek(fd, offset, SEEK_SET) != offset)
2229
            return -3;
2230

    
2231
    while (offset < size) {
2232
        uint32_t c1;
2233
        int rest_size = (size - offset > s->cluster_size ?
2234
                s->cluster_size : size - offset);
2235
        int ret;
2236

    
2237
        c1 = modified_fat_get(s, c);
2238

    
2239
        assert((size - offset == 0 && fat_eof(s, c)) ||
2240
                (size > offset && c >=2 && !fat_eof(s, c)));
2241
        assert(size >= 0);
2242

    
2243
        ret = vvfat_read(s->bs, cluster2sector(s, c),
2244
            (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
2245

    
2246
        if (ret < 0)
2247
            return ret;
2248

    
2249
        if (write(fd, cluster, rest_size) < 0)
2250
            return -2;
2251

    
2252
        offset += rest_size;
2253
        c = c1;
2254
    }
2255

    
2256
    ftruncate(fd, size);
2257
    close(fd);
2258

    
2259
    return commit_mappings(s, first_cluster, dir_index);
2260
}
2261

    
2262
#ifdef DEBUG
2263
/* test, if all mappings point to valid direntries */
2264
static void check1(BDRVVVFATState* s)
2265
{
2266
    int i;
2267
    for (i = 0; i < s->mapping.next; i++) {
2268
        mapping_t* mapping = array_get(&(s->mapping), i);
2269
        if (mapping->mode & MODE_DELETED) {
2270
            fprintf(stderr, "deleted\n");
2271
            continue;
2272
        }
2273
        assert(mapping->dir_index >= 0);
2274
        assert(mapping->dir_index < s->directory.next);
2275
        direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2276
        assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2277
        if (mapping->mode & MODE_DIRECTORY) {
2278
            assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2279
            assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2280
        }
2281
    }
2282
}
2283

    
2284
/* test, if all direntries have mappings */
2285
static void check2(BDRVVVFATState* s)
2286
{
2287
    int i;
2288
    int first_mapping = -1;
2289

    
2290
    for (i = 0; i < s->directory.next; i++) {
2291
        direntry_t* direntry = array_get(&(s->directory), i);
2292

    
2293
        if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2294
            mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2295
            assert(mapping);
2296
            assert(mapping->dir_index == i || is_dot(direntry));
2297
            assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2298
        }
2299

    
2300
        if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2301
            /* cluster start */
2302
            int j, count = 0;
2303

    
2304
            for (j = 0; j < s->mapping.next; j++) {
2305
                mapping_t* mapping = array_get(&(s->mapping), j);
2306
                if (mapping->mode & MODE_DELETED)
2307
                    continue;
2308
                if (mapping->mode & MODE_DIRECTORY) {
2309
                    if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2310
                        assert(++count == 1);
2311
                        if (mapping->first_mapping_index == -1)
2312
                            first_mapping = array_index(&(s->mapping), mapping);
2313
                        else
2314
                            assert(first_mapping == mapping->first_mapping_index);
2315
                        if (mapping->info.dir.parent_mapping_index < 0)
2316
                            assert(j == 0);
2317
                        else {
2318
                            mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2319
                            assert(parent->mode & MODE_DIRECTORY);
2320
                            assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2321
                        }
2322
                    }
2323
                }
2324
            }
2325
            if (count == 0)
2326
                first_mapping = -1;
2327
        }
2328
    }
2329
}
2330
#endif
2331

    
2332
static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2333
{
2334
    int i;
2335

    
2336
#ifdef DEBUG
2337
    fprintf(stderr, "handle_renames\n");
2338
    for (i = 0; i < s->commits.next; i++) {
2339
        commit_t* commit = array_get(&(s->commits), i);
2340
        fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
2341
    }
2342
#endif
2343

    
2344
    for (i = 0; i < s->commits.next;) {
2345
        commit_t* commit = array_get(&(s->commits), i);
2346
        if (commit->action == ACTION_RENAME) {
2347
            mapping_t* mapping = find_mapping_for_cluster(s,
2348
                    commit->param.rename.cluster);
2349
            char* old_path = mapping->path;
2350

    
2351
            assert(commit->path);
2352
            mapping->path = commit->path;
2353
            if (rename(old_path, mapping->path))
2354
                return -2;
2355

    
2356
            if (mapping->mode & MODE_DIRECTORY) {
2357
                int l1 = strlen(mapping->path);
2358
                int l2 = strlen(old_path);
2359
                int diff = l1 - l2;
2360
                direntry_t* direntry = array_get(&(s->directory),
2361
                        mapping->info.dir.first_dir_index);
2362
                uint32_t c = mapping->begin;
2363
                int i = 0;
2364

    
2365
                /* recurse */
2366
                while (!fat_eof(s, c)) {
2367
                    do {
2368
                        direntry_t* d = direntry + i;
2369

    
2370
                        if (is_file(d) || (is_directory(d) && !is_dot(d))) {
2371
                            mapping_t* m = find_mapping_for_cluster(s,
2372
                                    begin_of_direntry(d));
2373
                            int l = strlen(m->path);
2374
                            char* new_path = malloc(l + diff + 1);
2375

    
2376
                            assert(!strncmp(m->path, mapping->path, l2));
2377

    
2378
                            strcpy(new_path, mapping->path);
2379
                            strcpy(new_path + l1, m->path + l2);
2380

    
2381
                            schedule_rename(s, m->begin, new_path);
2382
                        }
2383
                        i++;
2384
                    } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2385
                    c = fat_get(s, c);
2386
                }
2387
            }
2388

    
2389
            free(old_path);
2390
            array_remove(&(s->commits), i);
2391
            continue;
2392
        } else if (commit->action == ACTION_MKDIR) {
2393
            mapping_t* mapping;
2394
            int j, parent_path_len;
2395

    
2396
#ifdef __MINGW32__
2397
            if (mkdir(commit->path))
2398
                return -5;
2399
#else
2400
            if (mkdir(commit->path, 0755))
2401
                return -5;
2402
#endif
2403

    
2404
            mapping = insert_mapping(s, commit->param.mkdir.cluster,
2405
                    commit->param.mkdir.cluster + 1);
2406
            if (mapping == NULL)
2407
                return -6;
2408

    
2409
            mapping->mode = MODE_DIRECTORY;
2410
            mapping->read_only = 0;
2411
            mapping->path = commit->path;
2412
            j = s->directory.next;
2413
            assert(j);
2414
            insert_direntries(s, s->directory.next,
2415
                    0x10 * s->sectors_per_cluster);
2416
            mapping->info.dir.first_dir_index = j;
2417

    
2418
            parent_path_len = strlen(commit->path)
2419
                - strlen(get_basename(commit->path)) - 1;
2420
            for (j = 0; j < s->mapping.next; j++) {
2421
                mapping_t* m = array_get(&(s->mapping), j);
2422
                if (m->first_mapping_index < 0 && m != mapping &&
2423
                        !strncmp(m->path, mapping->path, parent_path_len) &&
2424
                        strlen(m->path) == parent_path_len)
2425
                    break;
2426
            }
2427
            assert(j < s->mapping.next);
2428
            mapping->info.dir.parent_mapping_index = j;
2429

    
2430
            array_remove(&(s->commits), i);
2431
            continue;
2432
        }
2433

    
2434
        i++;
2435
    }
2436
    return 0;
2437
}
2438

    
2439
/*
2440
 * TODO: make sure that the short name is not matching *another* file
2441
 */
2442
static int handle_commits(BDRVVVFATState* s)
2443
{
2444
    int i, fail = 0;
2445

    
2446
    vvfat_close_current_file(s);
2447

    
2448
    for (i = 0; !fail && i < s->commits.next; i++) {
2449
        commit_t* commit = array_get(&(s->commits), i);
2450
        switch(commit->action) {
2451
        case ACTION_RENAME: case ACTION_MKDIR:
2452
            assert(0);
2453
            fail = -2;
2454
            break;
2455
        case ACTION_WRITEOUT: {
2456
            direntry_t* entry = array_get(&(s->directory),
2457
                    commit->param.writeout.dir_index);
2458
            uint32_t begin = begin_of_direntry(entry);
2459
            mapping_t* mapping = find_mapping_for_cluster(s, begin);
2460

    
2461
            assert(mapping);
2462
            assert(mapping->begin == begin);
2463
            assert(commit->path == NULL);
2464

    
2465
            if (commit_one_file(s, commit->param.writeout.dir_index,
2466
                        commit->param.writeout.modified_offset))
2467
                fail = -3;
2468

    
2469
            break;
2470
        }
2471
        case ACTION_NEW_FILE: {
2472
            int begin = commit->param.new_file.first_cluster;
2473
            mapping_t* mapping = find_mapping_for_cluster(s, begin);
2474
            direntry_t* entry;
2475
            int i;
2476

    
2477
            /* find direntry */
2478
            for (i = 0; i < s->directory.next; i++) {
2479
                entry = array_get(&(s->directory), i);
2480
                if (is_file(entry) && begin_of_direntry(entry) == begin)
2481
                    break;
2482
            }
2483

    
2484
            if (i >= s->directory.next) {
2485
                fail = -6;
2486
                continue;
2487
            }
2488

    
2489
            /* make sure there exists an initial mapping */
2490
            if (mapping && mapping->begin != begin) {
2491
                mapping->end = begin;
2492
                mapping = NULL;
2493
            }
2494
            if (mapping == NULL) {
2495
                mapping = insert_mapping(s, begin, begin+1);
2496
            }
2497
            /* most members will be fixed in commit_mappings() */
2498
            assert(commit->path);
2499
            mapping->path = commit->path;
2500
            mapping->read_only = 0;
2501
            mapping->mode = MODE_NORMAL;
2502
            mapping->info.file.offset = 0;
2503

    
2504
            if (commit_one_file(s, i, 0))
2505
                fail = -7;
2506

    
2507
            break;
2508
        }
2509
        default:
2510
            assert(0);
2511
        }
2512
    }
2513
    if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2514
        return -1;
2515
    return fail;
2516
}
2517

    
2518
static int handle_deletes(BDRVVVFATState* s)
2519
{
2520
    int i, deferred = 1, deleted = 1;
2521

    
2522
    /* delete files corresponding to mappings marked as deleted */
2523
    /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2524
    while (deferred && deleted) {
2525
        deferred = 0;
2526
        deleted = 0;
2527

    
2528
        for (i = 1; i < s->mapping.next; i++) {
2529
            mapping_t* mapping = array_get(&(s->mapping), i);
2530
            if (mapping->mode & MODE_DELETED) {
2531
                direntry_t* entry = array_get(&(s->directory),
2532
                        mapping->dir_index);
2533

    
2534
                if (is_free(entry)) {
2535
                    /* remove file/directory */
2536
                    if (mapping->mode & MODE_DIRECTORY) {
2537
                        int j, next_dir_index = s->directory.next,
2538
                        first_dir_index = mapping->info.dir.first_dir_index;
2539

    
2540
                        if (rmdir(mapping->path) < 0) {
2541
                            if (errno == ENOTEMPTY) {
2542
                                deferred++;
2543
                                continue;
2544
                            } else
2545
                                return -5;
2546
                        }
2547

    
2548
                        for (j = 1; j < s->mapping.next; j++) {
2549
                            mapping_t* m = array_get(&(s->mapping), j);
2550
                            if (m->mode & MODE_DIRECTORY &&
2551
                                    m->info.dir.first_dir_index >
2552
                                    first_dir_index &&
2553
                                    m->info.dir.first_dir_index <
2554
                                    next_dir_index)
2555
                                next_dir_index =
2556
                                    m->info.dir.first_dir_index;
2557
                        }
2558
                        remove_direntries(s, first_dir_index,
2559
                                next_dir_index - first_dir_index);
2560

    
2561
                        deleted++;
2562
                    }
2563
                } else {
2564
                    if (unlink(mapping->path))
2565
                        return -4;
2566
                    deleted++;
2567
                }
2568
                DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2569
                remove_mapping(s, i);
2570
            }
2571
        }
2572
    }
2573

    
2574
    return 0;
2575
}
2576

    
2577
/*
2578
 * synchronize mapping with new state:
2579
 *
2580
 * - copy FAT (with bdrv_read)
2581
 * - mark all filenames corresponding to mappings as deleted
2582
 * - recurse direntries from root (using bs->bdrv_read)
2583
 * - delete files corresponding to mappings marked as deleted
2584
 */
2585
static int do_commit(BDRVVVFATState* s)
2586
{
2587
    int ret = 0;
2588

    
2589
    /* the real meat are the commits. Nothing to do? Move along! */
2590
    if (s->commits.next == 0)
2591
        return 0;
2592

    
2593
    vvfat_close_current_file(s);
2594

    
2595
    ret = handle_renames_and_mkdirs(s);
2596
    if (ret) {
2597
        fprintf(stderr, "Error handling renames (%d)\n", ret);
2598
        assert(0);
2599
        return ret;
2600
    }
2601

    
2602
    /* copy FAT (with bdrv_read) */
2603
    memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2604

    
2605
    /* recurse direntries from root (using bs->bdrv_read) */
2606
    ret = commit_direntries(s, 0, -1);
2607
    if (ret) {
2608
        fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
2609
        assert(0);
2610
        return ret;
2611
    }
2612

    
2613
    ret = handle_commits(s);
2614
    if (ret) {
2615
        fprintf(stderr, "Error handling commits (%d)\n", ret);
2616
        assert(0);
2617
        return ret;
2618
    }
2619

    
2620
    ret = handle_deletes(s);
2621
    if (ret) {
2622
        fprintf(stderr, "Error deleting\n");
2623
        assert(0);
2624
        return ret;
2625
    }
2626

    
2627
    s->qcow->drv->bdrv_make_empty(s->qcow);
2628

    
2629
    memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2630

    
2631
DLOG(checkpoint());
2632
    return 0;
2633
}
2634

    
2635
static int try_commit(BDRVVVFATState* s)
2636
{
2637
    vvfat_close_current_file(s);
2638
DLOG(checkpoint());
2639
    if(!is_consistent(s))
2640
        return -1;
2641
    return do_commit(s);
2642
}
2643

    
2644
static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
2645
                    const uint8_t *buf, int nb_sectors)
2646
{
2647
    BDRVVVFATState *s = bs->opaque;
2648
    int i, ret;
2649

    
2650
DLOG(checkpoint());
2651

    
2652
    vvfat_close_current_file(s);
2653

    
2654
    /*
2655
     * Some sanity checks:
2656
     * - do not allow writing to the boot sector
2657
     * - do not allow to write non-ASCII filenames
2658
     */
2659

    
2660
    if (sector_num < s->first_sectors_number)
2661
        return -1;
2662

    
2663
    for (i = sector2cluster(s, sector_num);
2664
            i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
2665
        mapping_t* mapping = find_mapping_for_cluster(s, i);
2666
        if (mapping) {
2667
            if (mapping->read_only) {
2668
                fprintf(stderr, "Tried to write to write-protected file %s\n",
2669
                        mapping->path);
2670
                return -1;
2671
            }
2672

    
2673
            if (mapping->mode & MODE_DIRECTORY) {
2674
                int begin = cluster2sector(s, i);
2675
                int end = begin + s->sectors_per_cluster, k;
2676
                int dir_index;
2677
                const direntry_t* direntries;
2678
                long_file_name lfn;
2679

    
2680
                lfn_init(&lfn);
2681

    
2682
                if (begin < sector_num)
2683
                    begin = sector_num;
2684
                if (end > sector_num + nb_sectors)
2685
                    end = sector_num + nb_sectors;
2686
                dir_index  = mapping->dir_index +
2687
                    0x10 * (begin - mapping->begin * s->sectors_per_cluster);
2688
                direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
2689

    
2690
                for (k = 0; k < (end - begin) * 0x10; k++) {
2691
                    /* do not allow non-ASCII filenames */
2692
                    if (parse_long_name(&lfn, direntries + k) < 0) {
2693
                        fprintf(stderr, "Warning: non-ASCII filename\n");
2694
                        return -1;
2695
                    }
2696
                    /* no access to the direntry of a read-only file */
2697
                    else if (is_short_name(direntries+k) &&
2698
                            (direntries[k].attributes & 1)) {
2699
                        if (memcmp(direntries + k,
2700
                                    array_get(&(s->directory), dir_index + k),
2701
                                    sizeof(direntry_t))) {
2702
                            fprintf(stderr, "Warning: tried to write to write-protected file\n");
2703
                            return -1;
2704
                        }
2705
                    }
2706
                }
2707
            }
2708
            i = mapping->end;
2709
        } else
2710
            i++;
2711
    }
2712

    
2713
    /*
2714
     * Use qcow backend. Commit later.
2715
     */
2716
DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
2717
    ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
2718
    if (ret < 0) {
2719
        fprintf(stderr, "Error writing to qcow backend\n");
2720
        return ret;
2721
    }
2722

    
2723
    for (i = sector2cluster(s, sector_num);
2724
            i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
2725
        if (i >= 0)
2726
            s->used_clusters[i] |= USED_ALLOCATED;
2727

    
2728
DLOG(checkpoint());
2729
    /* TODO: add timeout */
2730
    try_commit(s);
2731

    
2732
DLOG(checkpoint());
2733
    return 0;
2734
}
2735

    
2736
static int vvfat_is_allocated(BlockDriverState *bs,
2737
        int64_t sector_num, int nb_sectors, int* n)
2738
{
2739
    BDRVVVFATState* s = bs->opaque;
2740
    *n = s->sector_count - sector_num;
2741
    if (*n > nb_sectors)
2742
        *n = nb_sectors;
2743
    else if (*n < 0)
2744
        return 0;
2745
    return 1;
2746
}
2747

    
2748
static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
2749
        const uint8_t* buffer, int nb_sectors) {
2750
    BDRVVVFATState* s = bs->opaque;
2751
    return try_commit(s);
2752
}
2753

    
2754
static void write_target_close(BlockDriverState *bs) {
2755
    BDRVVVFATState* s = bs->opaque;
2756
    bdrv_delete(s->qcow);
2757
    free(s->qcow_filename);
2758
}
2759

    
2760
static BlockDriver vvfat_write_target = {
2761
    "vvfat_write_target", 0, NULL, NULL, NULL,
2762
    write_target_commit,
2763
    write_target_close,
2764
    NULL, NULL, NULL
2765
};
2766

    
2767
static int enable_write_target(BDRVVVFATState *s)
2768
{
2769
    int size = sector2cluster(s, s->sector_count);
2770
    s->used_clusters = calloc(size, 1);
2771

    
2772
    array_init(&(s->commits), sizeof(commit_t));
2773

    
2774
    s->qcow_filename = malloc(1024);
2775
    get_tmp_filename(s->qcow_filename, 1024);
2776
    if (bdrv_create(&bdrv_qcow,
2777
                s->qcow_filename, s->sector_count, "fat:", 0) < 0)
2778
        return -1;
2779
    s->qcow = bdrv_new("");
2780
    if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
2781
        return -1;
2782

    
2783
#ifndef _WIN32
2784
    unlink(s->qcow_filename);
2785
#endif
2786

    
2787
    s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
2788
    s->bs->backing_hd->drv = &vvfat_write_target;
2789
    s->bs->backing_hd->opaque = s;
2790

    
2791
    return 0;
2792
}
2793

    
2794
static void vvfat_close(BlockDriverState *bs)
2795
{
2796
    BDRVVVFATState *s = bs->opaque;
2797

    
2798
    vvfat_close_current_file(s);
2799
    array_free(&(s->fat));
2800
    array_free(&(s->directory));
2801
    array_free(&(s->mapping));
2802
    if(s->cluster_buffer)
2803
        free(s->cluster_buffer);
2804
}
2805

    
2806
BlockDriver bdrv_vvfat = {
2807
    "vvfat",
2808
    sizeof(BDRVVVFATState),
2809
    NULL, /* no probe for protocols */
2810
    vvfat_open,
2811
    vvfat_read,
2812
    vvfat_write,
2813
    vvfat_close,
2814
    NULL, /* ??? Not sure if we can do any meaningful flushing.  */
2815
    NULL,
2816
    vvfat_is_allocated,
2817
    .protocol_name = "fat",
2818
};
2819

    
2820
#ifdef DEBUG
2821
static void checkpoint(void) {
2822
    assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
2823
    check1(vvv);
2824
    check2(vvv);
2825
    assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
2826
#if 0
2827
    if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
2828
        fprintf(stderr, "Nonono!\n");
2829
    mapping_t* mapping;
2830
    direntry_t* direntry;
2831
    assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
2832
    assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
2833
    if (vvv->mapping.next<47)
2834
        return;
2835
    assert((mapping = array_get(&(vvv->mapping), 47)));
2836
    assert(mapping->dir_index < vvv->directory.next);
2837
    direntry = array_get(&(vvv->directory), mapping->dir_index);
2838
    assert(!memcmp(direntry->name, "USB     H  ", 11) || direntry->name[0]==0);
2839
#endif
2840
    return;
2841
    /* avoid compiler warnings: */
2842
    hexdump(NULL, 100);
2843
    remove_mapping(vvv, NULL);
2844
    print_mapping(NULL);
2845
    print_direntry(NULL);
2846
}
2847
#endif
2848