Statistics
| Branch: | Revision:

root / block-vvfat.c @ bd7d9a6d

History | View | Annotate | Download (79.3 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 < array->next);
97
    return array->pointer + index * array->item_size;
98
}
99

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

    
111
    return 0;
112
}
113

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

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

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

    
124
    return result;
125
}
126

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

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

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

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

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

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

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

    
172
    free(buf);
173

    
174
    return 0;
175
}
176

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

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

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

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

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

    
243
typedef struct {
244
    uint8_t head;
245
    uint8_t sector;
246
    uint8_t cylinder;
247
} mbr_chs_t;
248

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

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

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

    
281
/* this structure are used to transparently access the files */
282

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

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

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

    
318
/* here begins the real VVFAT driver */
319

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

    
325
    int fat_type; /* 16 or 32 */
326
    array_t fat,directory,mapping;
327

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

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

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

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

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

    
385
    memset(s->first_sectors,0,512);
386

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

    
390
    partition->attributes=0x80; /* bootable */
391

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

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

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

    
407
    real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
408
}
409

    
410
/* direntry functions */
411

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

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

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

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

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

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

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

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

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

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

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

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

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

    
505
/* fat functions */
506

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

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

    
516
    return chksum;
517
}
518

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

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

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

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

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

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

    
599
}
600

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

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

    
617
    entry_long=create_long_filename(s,filename);
618

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

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

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

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

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

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

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

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

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

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

    
685
    return entry;
686
}
687

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

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

    
706
    assert(mapping->mode & MODE_DIRECTORY);
707

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

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

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

    
725
        if(first_cluster == 0 && (is_dotdot || is_dot))
726
            continue;
727

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

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

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

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

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

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

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

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

    
812
    return 0;
813
}
814

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

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

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

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

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

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

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

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

    
863
    array_init(&(s->mapping),sizeof(mapping_t));
864
    array_init(&(s->directory),sizeof(direntry_t));
865

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

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

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

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

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

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

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

    
924
        assert(mapping->begin < mapping->end);
925

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

    
933
        /* next free cluster */
934
        cluster = mapping->end;
935

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

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

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

    
950
    s->current_mapping = NULL;
951

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

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

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

    
981
    return 0;
982
}
983

    
984
#ifdef DEBUG
985
static BDRVVVFATState *vvv = NULL;
986
#endif
987

    
988
static int enable_write_target(BDRVVVFATState *s);
989
static int is_consistent(BDRVVVFATState *s);
990

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

    
997
#ifdef DEBUG
998
    vvv = s;
999
#endif
1000

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

    
1006
    s->bs = bs;
1007

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

    
1014
    s->current_cluster=0xffffffff;
1015

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

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

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

    
1035
    s->sector_count=bs->cyls*bs->heads*bs->secs;
1036

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

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

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

    
1061
    bs->total_sectors=bs->cyls*bs->heads*bs->secs;
1062

    
1063
    if(init_directories(s, dirname))
1064
        return -1;
1065

    
1066
    s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
1067

    
1068
    if(s->first_sectors_number==0x40)
1069
        init_mbr(s);
1070

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

    
1075
    //    assert(is_consistent(s));
1076
    return 0;
1077
}
1078

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

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

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

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

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

    
1150
    return NULL;
1151
}
1152

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

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

    
1182
            assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1183

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

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

    
1202
        assert(s->current_fd);
1203

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

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

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

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

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

    
1268
static void print_mapping(const mapping_t* mapping)
1269
{
1270
    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);
1271
    if (mapping->mode & MODE_DIRECTORY)
1272
        fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1273
    else
1274
        fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
1275
}
1276
#endif
1277

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

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

    
1322
/* LATER TODO: statify all functions */
1323

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

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

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

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

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

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

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

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

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

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

    
1434
    if (!is_long_name(direntry))
1435
        return 1;
1436

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

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

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

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

    
1467
    return 0;
1468
}
1469

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

    
1476
    if (!is_short_name(direntry))
1477
        return 1;
1478

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

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

    
1504
    lfn->len = strlen((char*)lfn->name);
1505

    
1506
    return 0;
1507
}
1508

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

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

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

    
1536
    if (s->qcow == NULL)
1537
        return 0;
1538

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

    
1543
    return was_modified;
1544
}
1545

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

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

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

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

    
1606
    vvfat_close_current_file(s);
1607

    
1608
    /* the root directory */
1609
    if (cluster_num == 0)
1610
        return 0;
1611

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

    
1616
        mapping = find_mapping_for_cluster(s, cluster_num);
1617

    
1618
        if (mapping) {
1619
            const char* basename;
1620

    
1621
            assert(mapping->mode & MODE_DELETED);
1622
            mapping->mode &= ~MODE_DELETED;
1623

    
1624
            basename = get_basename(mapping->path);
1625

    
1626
            assert(mapping->mode & MODE_NORMAL);
1627

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

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

    
1648

    
1649
                if (mapping &&
1650
                        (mapping->mode & MODE_DIRECTORY) == 0) {
1651

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

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

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

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

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

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

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

    
1707
        cluster_num = modified_fat_get(s, cluster_num);
1708

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

    
1714
        offset += s->cluster_size;
1715
    }
1716
}
1717

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

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

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

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

    
1744
        assert(mapping->mode & MODE_DIRECTORY);
1745

    
1746
        assert(mapping->mode & MODE_DELETED);
1747
        mapping->mode &= ~MODE_DELETED;
1748

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

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

    
1760
        ret++;
1761

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

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

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

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

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

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

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

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

    
1836
            ret += cluster_count;
1837
        }
1838

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

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

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

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

    
1881
    clear_commits(s);
1882

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

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

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

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

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

    
1918
    return used_clusters_count;
1919
}
1920

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

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

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

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

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

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

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

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

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

    
1978
    return mapping;
1979
}
1980

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

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

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

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

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

    
2000
    return 0;
2001
}
2002

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

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

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

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

    
2052
    vvfat_close_current_file(s);
2053

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

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

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

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

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

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

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

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

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

    
2113
            mapping = next_mapping;
2114
        }
2115

    
2116
        cluster = c1;
2117
    }
2118

    
2119
    return 0;
2120
}
2121

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

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

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

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

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

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

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

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

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

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

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

    
2197
    return 0;
2198
}
2199

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

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

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

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

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

    
2236
        c1 = modified_fat_get(s, c);
2237

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

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

    
2244
        if (ret < 0)
2245
            return ret;
2246

    
2247
        if (write(fd, cluster, rest_size) < 0)
2248
            return -2;
2249

    
2250
        offset += rest_size;
2251
        c = c1;
2252
    }
2253

    
2254
    ftruncate(fd, size);
2255
    close(fd);
2256

    
2257
    return commit_mappings(s, first_cluster, dir_index);
2258
}
2259

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

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

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

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

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

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

    
2330
static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2331
{
2332
    int i;
2333

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

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

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

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

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

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

    
2374
                            assert(!strncmp(m->path, mapping->path, l2));
2375

    
2376
                            pstrcpy(new_path, l + diff + 1, mapping->path);
2377
                            pstrcpy(new_path + l1, l + diff + 1 - l1,
2378
                                    m->path + l2);
2379

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

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

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

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

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

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

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

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

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

    
2445
    vvfat_close_current_file(s);
2446

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2573
    return 0;
2574
}
2575

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

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

    
2592
    vvfat_close_current_file(s);
2593

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

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

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

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

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

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

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

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

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

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

    
2649
DLOG(checkpoint());
2650

    
2651
    vvfat_close_current_file(s);
2652

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

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

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

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

    
2679
                lfn_init(&lfn);
2680

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2790
    return 0;
2791
}
2792

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

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

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

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