Statistics
| Branch: | Revision:

root / block-vvfat.c @ 9596ebb7

History | View | Annotate | Download (78.9 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();
57

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

    
67
#else
68

    
69
#define DLOG(a)
70

    
71
#endif
72

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

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

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

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

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

    
112
    return 0;
113
}
114

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

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

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

    
125
    return result;
126
}
127

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

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

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

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

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

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

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

    
173
    free(buf);
174

    
175
    return 0;
176
}
177

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
412
/* direntry functions */
413

    
414
/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
415
static inline int short2long_name(unsigned char* dest,const char* src)
416
{
417
    int i;
418
    for(i=0;i<129 && src[i];i++) {
419
        dest[2*i]=src[i];
420
        dest[2*i+1]=0;
421
    }
422
    dest[2*i]=dest[2*i+1]=0;
423
    for(i=2*i+2;(i%26);i++)
424
        dest[i]=0xff;
425
    return i;
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<length;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]==0 ; */
456
    return direntry->attributes == 0 || direntry->name[0]==0xe5;
457
}
458

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

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

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

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

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

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

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

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

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

    
506
/* fat functions */
507

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

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

    
517
    return chksum;
518
}
519

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

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

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

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

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

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

    
600
}
601

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

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

    
618
    entry_long=create_long_filename(s,filename);
619

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

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

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

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

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

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

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

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

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

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

    
686
    return entry;
687
}
688

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
813
    return 0;
814
}
815

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
951
    s->current_mapping = NULL;
952

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

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

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

    
982
    return 0;
983
}
984

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

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

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

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

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

    
1007
    s->bs = bs;
1008

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

    
1015
    s->current_cluster=0xffffffff;
1016

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1151
    return NULL;
1152
}
1153

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

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

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

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

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

    
1203
        assert(s->current_fd);
1204

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1411
typedef struct {
1412
    unsigned char name[1024];
1413
    int checksum, len;
1414
    int sequence_number;
1415
} long_file_name;
1416

    
1417
static void lfn_init(long_file_name* lfn)
1418
{
1419
   lfn->sequence_number = lfn->len = 0;
1420
   lfn->checksum = 0x100;
1421
}
1422

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

    
1430
    if (!is_long_name(direntry))
1431
        return 1;
1432

    
1433
    if (pointer[0] & 0x40) {
1434
        lfn->sequence_number = pointer[0] & 0x3f;
1435
        lfn->checksum = pointer[13];
1436
        lfn->name[0] = 0;
1437
    } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
1438
        return -1;
1439
    else if (pointer[13] != lfn->checksum)
1440
        return -2;
1441
    else if (pointer[12] || pointer[26] || pointer[27])
1442
        return -3;
1443

    
1444
    offset = 13 * (lfn->sequence_number - 1);
1445
    for (i = 0, j = 1; i < 13; i++, j+=2) {
1446
        if (j == 11)
1447
            j = 14;
1448
        else if (j == 26)
1449
            j = 28;
1450

    
1451
        if (pointer[j+1] == 0)
1452
            lfn->name[offset + i] = pointer[j];
1453
        else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1454
            return -4;
1455
        else
1456
            lfn->name[offset + i] = 0;
1457
    }
1458

    
1459
    if (pointer[0] & 0x40)
1460
        lfn->len = offset + strlen(lfn->name + offset);
1461

    
1462
    return 0;
1463
}
1464

    
1465
/* returns 0 if successful, >0 if no short_name, and <0 on error */
1466
static int parse_short_name(BDRVVVFATState* s,
1467
        long_file_name* lfn, direntry_t* direntry)
1468
{
1469
    int i, j;
1470

    
1471
    if (!is_short_name(direntry))
1472
        return 1;
1473

    
1474
    for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1475
    for (i = 0; i <= j; i++) {
1476
        if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
1477
            return -1;
1478
        else if (s->downcase_short_names)
1479
            lfn->name[i] = tolower(direntry->name[i]);
1480
        else
1481
            lfn->name[i] = direntry->name[i];
1482
    }
1483

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

    
1499
    lfn->len = strlen(lfn->name);
1500

    
1501
    return 0;
1502
}
1503

    
1504
static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1505
        unsigned int cluster)
1506
{
1507
    if (cluster < s->last_cluster_of_root_directory) {
1508
        if (cluster + 1 == s->last_cluster_of_root_directory)
1509
            return s->max_fat_value;
1510
        else
1511
            return cluster + 1;
1512
    }
1513

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

    
1526
static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1527
{
1528
    int was_modified = 0;
1529
    int i, dummy;
1530

    
1531
    if (s->qcow == NULL)
1532
        return 0;
1533

    
1534
    for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
1535
        was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
1536
                cluster2sector(s, cluster_num) + i, 1, &dummy);
1537

    
1538
    return was_modified;
1539
}
1540

    
1541
static const char* get_basename(const char* path)
1542
{
1543
    char* basename = strrchr(path, '/');
1544
    if (basename == NULL)
1545
        return path;
1546
    else
1547
        return basename + 1; /* strip '/' */
1548
}
1549

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

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

    
1595
    uint32_t cluster_num = begin_of_direntry(direntry);
1596
    uint32_t offset = 0;
1597
    int first_mapping_index = -1;
1598
    mapping_t* mapping = NULL;
1599
    const char* basename2 = NULL;
1600

    
1601
    vvfat_close_current_file(s);
1602

    
1603
    /* the root directory */
1604
    if (cluster_num == 0)
1605
        return 0;
1606

    
1607
    /* write support */
1608
    if (s->qcow) {
1609
        basename2 = get_basename(path);
1610

    
1611
        mapping = find_mapping_for_cluster(s, cluster_num);
1612

    
1613
        if (mapping) {
1614
            const char* basename;
1615

    
1616
            assert(mapping->mode & MODE_DELETED);
1617
            mapping->mode &= ~MODE_DELETED;
1618

    
1619
            basename = get_basename(mapping->path);
1620

    
1621
            assert(mapping->mode & MODE_NORMAL);
1622

    
1623
            /* rename */
1624
            if (strcmp(basename, basename2))
1625
                schedule_rename(s, cluster_num, strdup(path));
1626
        } else if (is_file(direntry))
1627
            /* new file */
1628
            schedule_new_file(s, strdup(path), cluster_num);
1629
        else {
1630
            assert(0);
1631
            return 0;
1632
        }
1633
    }
1634

    
1635
    while(1) {
1636
        if (s->qcow) {
1637
            if (!copy_it && cluster_was_modified(s, cluster_num)) {
1638
                if (mapping == NULL ||
1639
                        mapping->begin > cluster_num ||
1640
                        mapping->end <= cluster_num)
1641
                mapping = find_mapping_for_cluster(s, cluster_num);
1642

    
1643

    
1644
                if (mapping &&
1645
                        (mapping->mode & MODE_DIRECTORY) == 0) {
1646

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

    
1656
                        if (strcmp(basename, basename2))
1657
                            copy_it = 1;
1658
                        first_mapping_index = array_index(&(s->mapping), mapping);
1659
                    }
1660

    
1661
                    if (mapping->first_mapping_index != first_mapping_index
1662
                            && mapping->info.file.offset > 0) {
1663
                        assert(0);
1664
                        copy_it = 1;
1665
                    }
1666

    
1667
                    /* need to write out? */
1668
                    if (!was_modified && is_file(direntry)) {
1669
                        was_modified = 1;
1670
                        schedule_writeout(s, mapping->dir_index, offset);
1671
                    }
1672
                }
1673
            }
1674

    
1675
            if (copy_it) {
1676
                int i, dummy;
1677
                /*
1678
                 * This is horribly inefficient, but that is okay, since
1679
                 * it is rarely executed, if at all.
1680
                 */
1681
                int64_t offset = cluster2sector(s, cluster_num);
1682

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

    
1697
        ret++;
1698
        if (s->used_clusters[cluster_num] & USED_ANY)
1699
            return 0;
1700
        s->used_clusters[cluster_num] = USED_FILE;
1701

    
1702
        cluster_num = modified_fat_get(s, cluster_num);
1703

    
1704
        if (fat_eof(s, cluster_num))
1705
            return ret;
1706
        else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
1707
            return -1;
1708

    
1709
        offset += s->cluster_size;
1710
    }
1711
}
1712

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

    
1726
    long_file_name lfn;
1727
    int path_len = strlen(path);
1728
    char path2[PATH_MAX];
1729

    
1730
    assert(path_len < PATH_MAX); /* len was tested before! */
1731
    strcpy(path2, path);
1732
    path2[path_len] = '/';
1733
    path2[path_len + 1] = '\0';
1734

    
1735
    if (mapping) {
1736
        const char* basename = get_basename(mapping->path);
1737
        const char* basename2 = get_basename(path);
1738

    
1739
        assert(mapping->mode & MODE_DIRECTORY);
1740

    
1741
        assert(mapping->mode & MODE_DELETED);
1742
        mapping->mode &= ~MODE_DELETED;
1743

    
1744
        if (strcmp(basename, basename2))
1745
            schedule_rename(s, cluster_num, strdup(path));
1746
    } else
1747
        /* new directory */
1748
        schedule_mkdir(s, cluster_num, strdup(path));
1749

    
1750
    lfn_init(&lfn);
1751
    do {
1752
        int i;
1753
        int subret = 0;
1754

    
1755
        ret++;
1756

    
1757
        if (s->used_clusters[cluster_num] & USED_ANY) {
1758
            fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
1759
            return 0;
1760
        }
1761
        s->used_clusters[cluster_num] = USED_DIRECTORY;
1762

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

    
1773
        for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
1774
            int cluster_count;
1775

    
1776
DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
1777
            if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
1778
                    is_free(direntries + i))
1779
                continue;
1780

    
1781
            subret = parse_long_name(&lfn, direntries + i);
1782
            if (subret < 0) {
1783
                fprintf(stderr, "Error in long name\n");
1784
                goto fail;
1785
            }
1786
            if (subret == 0 || is_free(direntries + i))
1787
                continue;
1788

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

    
1801
            if (path_len + 1 + lfn.len >= PATH_MAX) {
1802
                fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
1803
                goto fail;
1804
            }
1805
            strcpy(path2 + path_len + 1, lfn.name);
1806

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

    
1830
            ret += cluster_count;
1831
        }
1832

    
1833
        cluster_num = modified_fat_get(s, cluster_num);
1834
    } while(!fat_eof(s, cluster_num));
1835

    
1836
    free(cluster);
1837
    return ret;
1838
}
1839

    
1840
/* returns 1 on success */
1841
static int is_consistent(BDRVVVFATState* s)
1842
{
1843
    int i, check;
1844
    int used_clusters_count = 0;
1845

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

    
1875
    clear_commits(s);
1876

    
1877
    /* mark every mapped file/directory as deleted.
1878
     * (check_directory_consistency() will unmark those still present). */
1879
    if (s->qcow)
1880
        for (i = 0; i < s->mapping.next; i++) {
1881
            mapping_t* mapping = array_get(&(s->mapping), i);
1882
            if (mapping->first_mapping_index < 0)
1883
                mapping->mode |= MODE_DELETED;
1884
        }
1885

    
1886
    used_clusters_count = check_directory_consistency(s, 0, s->path);
1887
    if (used_clusters_count <= 0) {
1888
        DLOG(fprintf(stderr, "problem in directory\n"));
1889
        return 0;
1890
    }
1891

    
1892
    check = s->last_cluster_of_root_directory;
1893
    for (i = check; i < sector2cluster(s, s->sector_count); i++) {
1894
        if (modified_fat_get(s, i)) {
1895
            if(!s->used_clusters[i]) {
1896
                DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
1897
                return 0;
1898
            }
1899
            check++;
1900
        }
1901

    
1902
        if (s->used_clusters[i] == USED_ALLOCATED) {
1903
            /* allocated, but not used... */
1904
            DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
1905
            return 0;
1906
        }
1907
    }
1908

    
1909
    if (check != used_clusters_count)
1910
        return 0;
1911

    
1912
    return used_clusters_count;
1913
}
1914

    
1915
static inline void adjust_mapping_indices(BDRVVVFATState* s,
1916
        int offset, int adjust)
1917
{
1918
    int i;
1919

    
1920
    for (i = 0; i < s->mapping.next; i++) {
1921
        mapping_t* mapping = array_get(&(s->mapping), i);
1922

    
1923
#define ADJUST_MAPPING_INDEX(name) \
1924
        if (mapping->name >= offset) \
1925
            mapping->name += adjust
1926

    
1927
        ADJUST_MAPPING_INDEX(first_mapping_index);
1928
        if (mapping->mode & MODE_DIRECTORY)
1929
            ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
1930
    }
1931
}
1932

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

    
1948
    if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
1949
            && mapping->begin < begin) {
1950
        mapping->end = begin;
1951
        index++;
1952
        mapping = array_get(&(s->mapping), index);
1953
    }
1954
    if (index >= s->mapping.next || mapping->begin > begin) {
1955
        mapping = array_insert(&(s->mapping), index, 1);
1956
        mapping->path = NULL;
1957
        adjust_mapping_indices(s, index, +1);
1958
    }
1959

    
1960
    mapping->begin = begin;
1961
    mapping->end = end;
1962

    
1963
DLOG(mapping_t* next_mapping;
1964
assert(index + 1 >= s->mapping.next ||
1965
((next_mapping = array_get(&(s->mapping), index + 1)) &&
1966
 next_mapping->begin >= end)));
1967

    
1968
    if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1969
        s->current_mapping = array_get(&(s->mapping),
1970
                s->current_mapping - first_mapping);
1971

    
1972
    return mapping;
1973
}
1974

    
1975
static int remove_mapping(BDRVVVFATState* s, int mapping_index)
1976
{
1977
    mapping_t* mapping = array_get(&(s->mapping), mapping_index);
1978
    mapping_t* first_mapping = array_get(&(s->mapping), 0);
1979

    
1980
    /* free mapping */
1981
    if (mapping->first_mapping_index < 0)
1982
        free(mapping->path);
1983

    
1984
    /* remove from s->mapping */
1985
    array_remove(&(s->mapping), mapping_index);
1986

    
1987
    /* adjust all references to mappings */
1988
    adjust_mapping_indices(s, mapping_index, -1);
1989

    
1990
    if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1991
        s->current_mapping = array_get(&(s->mapping),
1992
                s->current_mapping - first_mapping);
1993

    
1994
    return 0;
1995
}
1996

    
1997
static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
1998
{
1999
    int i;
2000
    for (i = 0; i < s->mapping.next; i++) {
2001
        mapping_t* mapping = array_get(&(s->mapping), i);
2002
        if (mapping->dir_index >= offset)
2003
            mapping->dir_index += adjust;
2004
        if ((mapping->mode & MODE_DIRECTORY) &&
2005
                mapping->info.dir.first_dir_index >= offset)
2006
            mapping->info.dir.first_dir_index += adjust;
2007
    }
2008
}
2009

    
2010
static direntry_t* insert_direntries(BDRVVVFATState* s,
2011
        int dir_index, int count)
2012
{
2013
    /*
2014
     * make room in s->directory,
2015
     * adjust_dirindices
2016
     */
2017
    direntry_t* result = array_insert(&(s->directory), dir_index, count);
2018
    if (result == NULL)
2019
        return NULL;
2020
    adjust_dirindices(s, dir_index, count);
2021
    return result;
2022
}
2023

    
2024
static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
2025
{
2026
    int ret = array_remove_slice(&(s->directory), dir_index, count);
2027
    if (ret)
2028
        return ret;
2029
    adjust_dirindices(s, dir_index, -count);
2030
    return 0;
2031
}
2032

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

    
2046
    vvfat_close_current_file(s);
2047

    
2048
    assert(mapping);
2049
    assert(mapping->begin == first_cluster);
2050
    mapping->first_mapping_index = -1;
2051
    mapping->dir_index = dir_index;
2052
    mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2053
        MODE_DIRECTORY : MODE_NORMAL;
2054

    
2055
    while (!fat_eof(s, cluster)) {
2056
        uint32_t c, c1;
2057

    
2058
        for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2059
                c = c1, c1 = modified_fat_get(s, c1));
2060

    
2061
        c++;
2062
        if (c > mapping->end) {
2063
            int index = array_index(&(s->mapping), mapping);
2064
            int i, max_i = s->mapping.next - index;
2065
            for (i = 1; i < max_i && mapping[i].begin < c; i++);
2066
            while (--i > 0)
2067
                remove_mapping(s, index + 1);
2068
        }
2069
        assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2070
                || mapping[1].begin >= c);
2071
        mapping->end = c;
2072

    
2073
        if (!fat_eof(s, c1)) {
2074
            int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2075
            mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2076
                array_get(&(s->mapping), i);
2077

    
2078
            if (next_mapping == NULL || next_mapping->begin > c1) {
2079
                int i1 = array_index(&(s->mapping), mapping);
2080

    
2081
                next_mapping = insert_mapping(s, c1, c1+1);
2082

    
2083
                if (c1 < c)
2084
                    i1++;
2085
                mapping = array_get(&(s->mapping), i1);
2086
            }
2087

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

    
2107
            mapping = next_mapping;
2108
        }
2109

    
2110
        cluster = c1;
2111
    }
2112

    
2113
    return 0;
2114
}
2115

    
2116
static int commit_direntries(BDRVVVFATState* s,
2117
        int dir_index, int parent_mapping_index)
2118
{
2119
    direntry_t* direntry = array_get(&(s->directory), dir_index);
2120
    uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
2121
    mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2122

    
2123
    int factor = 0x10 * s->sectors_per_cluster;
2124
    int old_cluster_count, new_cluster_count;
2125
    int current_dir_index = mapping->info.dir.first_dir_index;
2126
    int first_dir_index = current_dir_index;
2127
    int ret, i;
2128
    uint32_t c;
2129

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

    
2132
    assert(direntry);
2133
    assert(mapping);
2134
    assert(mapping->begin == first_cluster);
2135
    assert(mapping->info.dir.first_dir_index < s->directory.next);
2136
    assert(mapping->mode & MODE_DIRECTORY);
2137
    assert(dir_index == 0 || is_directory(direntry));
2138

    
2139
    mapping->info.dir.parent_mapping_index = parent_mapping_index;
2140

    
2141
    if (first_cluster == 0) {
2142
        old_cluster_count = new_cluster_count =
2143
            s->last_cluster_of_root_directory;
2144
    } else {
2145
        for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2146
                c = fat_get(s, c))
2147
            old_cluster_count++;
2148

    
2149
        for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2150
                c = modified_fat_get(s, c))
2151
            new_cluster_count++;
2152
    }
2153

    
2154
    if (new_cluster_count > old_cluster_count) {
2155
        if (insert_direntries(s,
2156
                current_dir_index + factor * old_cluster_count,
2157
                factor * (new_cluster_count - old_cluster_count)) == NULL)
2158
            return -1;
2159
    } else if (new_cluster_count < old_cluster_count)
2160
        remove_direntries(s,
2161
                current_dir_index + factor * new_cluster_count,
2162
                factor * (old_cluster_count - new_cluster_count));
2163

    
2164
    for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
2165
        void* direntry = array_get(&(s->directory), current_dir_index);
2166
        int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2167
                s->sectors_per_cluster);
2168
        if (ret)
2169
            return ret;
2170
        assert(!strncmp(s->directory.pointer, "QEMU", 4));
2171
        current_dir_index += factor;
2172
    }
2173

    
2174
    ret = commit_mappings(s, first_cluster, dir_index);
2175
    if (ret)
2176
        return ret;
2177

    
2178
    /* recurse */
2179
    for (i = 0; i < factor * new_cluster_count; i++) {
2180
        direntry = array_get(&(s->directory), first_dir_index + i);
2181
        if (is_directory(direntry) && !is_dot(direntry)) {
2182
            mapping = find_mapping_for_cluster(s, first_cluster);
2183
            assert(mapping->mode & MODE_DIRECTORY);
2184
            ret = commit_direntries(s, first_dir_index + i,
2185
                array_index(&(s->mapping), mapping));
2186
            if (ret)
2187
                return ret;
2188
        }
2189
    }
2190

    
2191
    return 0;
2192
}
2193

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

    
2208
    assert(offset < size);
2209
    assert((offset % s->cluster_size) == 0);
2210

    
2211
    for (i = s->cluster_size; i < offset; i += s->cluster_size)
2212
        c = modified_fat_get(s, c);
2213

    
2214
    fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
2215
    if (fd < 0) {
2216
        fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2217
                strerror(errno), errno);
2218
        return fd;
2219
    }
2220
    if (offset > 0)
2221
        if (lseek(fd, offset, SEEK_SET) != offset)
2222
            return -3;
2223

    
2224
    while (offset < size) {
2225
        uint32_t c1;
2226
        int rest_size = (size - offset > s->cluster_size ?
2227
                s->cluster_size : size - offset);
2228
        int ret;
2229

    
2230
        c1 = modified_fat_get(s, c);
2231

    
2232
        assert((size - offset == 0 && fat_eof(s, c)) ||
2233
                (size > offset && c >=2 && !fat_eof(s, c)));
2234
        assert(size >= 0);
2235

    
2236
        ret = vvfat_read(s->bs, cluster2sector(s, c),
2237
            cluster, (rest_size + 0x1ff) / 0x200);
2238

    
2239
        if (ret < 0)
2240
            return ret;
2241

    
2242
        if (write(fd, cluster, rest_size) < 0)
2243
            return -2;
2244

    
2245
        offset += rest_size;
2246
        c = c1;
2247
    }
2248

    
2249
    ftruncate(fd, size);
2250
    close(fd);
2251

    
2252
    return commit_mappings(s, first_cluster, dir_index);
2253
}
2254

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

    
2277
/* test, if all direntries have mappings */
2278
static void check2(BDRVVVFATState* s)
2279
{
2280
    int i;
2281
    int first_mapping = -1;
2282

    
2283
    for (i = 0; i < s->directory.next; i++) {
2284
        direntry_t* direntry = array_get(&(s->directory), i);
2285

    
2286
        if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2287
            mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2288
            assert(mapping);
2289
            assert(mapping->dir_index == i || is_dot(direntry));
2290
            assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2291
        }
2292

    
2293
        if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2294
            /* cluster start */
2295
            int j, count = 0;
2296

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

    
2325
static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2326
{
2327
    int i;
2328

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

    
2337
    for (i = 0; i < s->commits.next;) {
2338
        commit_t* commit = array_get(&(s->commits), i);
2339
        if (commit->action == ACTION_RENAME) {
2340
            mapping_t* mapping = find_mapping_for_cluster(s,
2341
                    commit->param.rename.cluster);
2342
            char* old_path = mapping->path;
2343

    
2344
            assert(commit->path);
2345
            mapping->path = commit->path;
2346
            if (rename(old_path, mapping->path))
2347
                return -2;
2348

    
2349
            if (mapping->mode & MODE_DIRECTORY) {
2350
                int l1 = strlen(mapping->path);
2351
                int l2 = strlen(old_path);
2352
                int diff = l1 - l2;
2353
                direntry_t* direntry = array_get(&(s->directory),
2354
                        mapping->info.dir.first_dir_index);
2355
                uint32_t c = mapping->begin;
2356
                int i = 0;
2357

    
2358
                /* recurse */
2359
                while (!fat_eof(s, c)) {
2360
                    do {
2361
                        direntry_t* d = direntry + i;
2362

    
2363
                        if (is_file(d) || (is_directory(d) && !is_dot(d))) {
2364
                            mapping_t* m = find_mapping_for_cluster(s,
2365
                                    begin_of_direntry(d));
2366
                            int l = strlen(m->path);
2367
                            char* new_path = malloc(l + diff + 1);
2368

    
2369
                            assert(!strncmp(m->path, mapping->path, l2));
2370

    
2371
                            strcpy(new_path, mapping->path);
2372
                            strcpy(new_path + l1, m->path + l2);
2373

    
2374
                            schedule_rename(s, m->begin, new_path);
2375
                        }
2376
                        i++;
2377
                    } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2378
                    c = fat_get(s, c);
2379
                }
2380
            }
2381

    
2382
            free(old_path);
2383
            array_remove(&(s->commits), i);
2384
            continue;
2385
        } else if (commit->action == ACTION_MKDIR) {
2386
            mapping_t* mapping;
2387
            int j, parent_path_len;
2388

    
2389
#ifdef __MINGW32__
2390
            if (mkdir(commit->path))
2391
                return -5;
2392
#else
2393
            if (mkdir(commit->path, 0755))
2394
                return -5;
2395
#endif
2396

    
2397
            mapping = insert_mapping(s, commit->param.mkdir.cluster,
2398
                    commit->param.mkdir.cluster + 1);
2399
            if (mapping == NULL)
2400
                return -6;
2401

    
2402
            mapping->mode = MODE_DIRECTORY;
2403
            mapping->read_only = 0;
2404
            mapping->path = commit->path;
2405
            j = s->directory.next;
2406
            assert(j);
2407
            insert_direntries(s, s->directory.next,
2408
                    0x10 * s->sectors_per_cluster);
2409
            mapping->info.dir.first_dir_index = j;
2410

    
2411
            parent_path_len = strlen(commit->path)
2412
                - strlen(get_basename(commit->path)) - 1;
2413
            for (j = 0; j < s->mapping.next; j++) {
2414
                mapping_t* m = array_get(&(s->mapping), j);
2415
                if (m->first_mapping_index < 0 && m != mapping &&
2416
                        !strncmp(m->path, mapping->path, parent_path_len) &&
2417
                        strlen(m->path) == parent_path_len)
2418
                    break;
2419
            }
2420
            assert(j < s->mapping.next);
2421
            mapping->info.dir.parent_mapping_index = j;
2422

    
2423
            array_remove(&(s->commits), i);
2424
            continue;
2425
        }
2426

    
2427
        i++;
2428
    }
2429
    return 0;
2430
}
2431

    
2432
/*
2433
 * TODO: make sure that the short name is not matching *another* file
2434
 */
2435
static int handle_commits(BDRVVVFATState* s)
2436
{
2437
    int i, fail = 0;
2438

    
2439
    vvfat_close_current_file(s);
2440

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

    
2454
            assert(mapping);
2455
            assert(mapping->begin == begin);
2456
            assert(commit->path == NULL);
2457

    
2458
            if (commit_one_file(s, commit->param.writeout.dir_index,
2459
                        commit->param.writeout.modified_offset))
2460
                fail = -3;
2461

    
2462
            break;
2463
        }
2464
        case ACTION_NEW_FILE: {
2465
            int begin = commit->param.new_file.first_cluster;
2466
            mapping_t* mapping = find_mapping_for_cluster(s, begin);
2467
            direntry_t* entry;
2468
            int i;
2469

    
2470
            /* find direntry */
2471
            for (i = 0; i < s->directory.next; i++) {
2472
                entry = array_get(&(s->directory), i);
2473
                if (is_file(entry) && begin_of_direntry(entry) == begin)
2474
                    break;
2475
            }
2476

    
2477
            if (i >= s->directory.next) {
2478
                fail = -6;
2479
                continue;
2480
            }
2481

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

    
2497
            if (commit_one_file(s, i, 0))
2498
                fail = -7;
2499

    
2500
            break;
2501
        }
2502
        default:
2503
            assert(0);
2504
        }
2505
    }
2506
    if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2507
        return -1;
2508
    return fail;
2509
}
2510

    
2511
static int handle_deletes(BDRVVVFATState* s)
2512
{
2513
    int i, deferred = 1, deleted = 1;
2514

    
2515
    /* delete files corresponding to mappings marked as deleted */
2516
    /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2517
    while (deferred && deleted) {
2518
        deferred = 0;
2519
        deleted = 0;
2520

    
2521
        for (i = 1; i < s->mapping.next; i++) {
2522
            mapping_t* mapping = array_get(&(s->mapping), i);
2523
            if (mapping->mode & MODE_DELETED) {
2524
                direntry_t* entry = array_get(&(s->directory),
2525
                        mapping->dir_index);
2526

    
2527
                if (is_free(entry)) {
2528
                    /* remove file/directory */
2529
                    if (mapping->mode & MODE_DIRECTORY) {
2530
                        int j, next_dir_index = s->directory.next,
2531
                        first_dir_index = mapping->info.dir.first_dir_index;
2532

    
2533
                        if (rmdir(mapping->path) < 0) {
2534
                            if (errno == ENOTEMPTY) {
2535
                                deferred++;
2536
                                continue;
2537
                            } else
2538
                                return -5;
2539
                        }
2540

    
2541
                        for (j = 1; j < s->mapping.next; j++) {
2542
                            mapping_t* m = array_get(&(s->mapping), j);
2543
                            if (m->mode & MODE_DIRECTORY &&
2544
                                    m->info.dir.first_dir_index >
2545
                                    first_dir_index &&
2546
                                    m->info.dir.first_dir_index <
2547
                                    next_dir_index)
2548
                                next_dir_index =
2549
                                    m->info.dir.first_dir_index;
2550
                        }
2551
                        remove_direntries(s, first_dir_index,
2552
                                next_dir_index - first_dir_index);
2553

    
2554
                        deleted++;
2555
                    }
2556
                } else {
2557
                    if (unlink(mapping->path))
2558
                        return -4;
2559
                    deleted++;
2560
                }
2561
                DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2562
                remove_mapping(s, i);
2563
            }
2564
        }
2565
    }
2566

    
2567
    return 0;
2568
}
2569

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

    
2582
    /* the real meat are the commits. Nothing to do? Move along! */
2583
    if (s->commits.next == 0)
2584
        return 0;
2585

    
2586
    vvfat_close_current_file(s);
2587

    
2588
    ret = handle_renames_and_mkdirs(s);
2589
    if (ret) {
2590
        fprintf(stderr, "Error handling renames (%d)\n", ret);
2591
        assert(0);
2592
        return ret;
2593
    }
2594

    
2595
    /* copy FAT (with bdrv_read) */
2596
    memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2597

    
2598
    /* recurse direntries from root (using bs->bdrv_read) */
2599
    ret = commit_direntries(s, 0, -1);
2600
    if (ret) {
2601
        fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
2602
        assert(0);
2603
        return ret;
2604
    }
2605

    
2606
    ret = handle_commits(s);
2607
    if (ret) {
2608
        fprintf(stderr, "Error handling commits (%d)\n", ret);
2609
        assert(0);
2610
        return ret;
2611
    }
2612

    
2613
    ret = handle_deletes(s);
2614
    if (ret) {
2615
        fprintf(stderr, "Error deleting\n");
2616
        assert(0);
2617
        return ret;
2618
    }
2619

    
2620
    s->qcow->drv->bdrv_make_empty(s->qcow);
2621

    
2622
    memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2623

    
2624
DLOG(checkpoint());
2625
    return 0;
2626
}
2627

    
2628
static int try_commit(BDRVVVFATState* s)
2629
{
2630
    vvfat_close_current_file(s);
2631
DLOG(checkpoint());
2632
    if(!is_consistent(s))
2633
        return -1;
2634
    return do_commit(s);
2635
}
2636

    
2637
static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
2638
                    const uint8_t *buf, int nb_sectors)
2639
{
2640
    BDRVVVFATState *s = bs->opaque;
2641
    int i, ret;
2642

    
2643
DLOG(checkpoint());
2644

    
2645
    vvfat_close_current_file(s);
2646

    
2647
    /*
2648
     * Some sanity checks:
2649
     * - do not allow writing to the boot sector
2650
     * - do not allow to write non-ASCII filenames
2651
     */
2652

    
2653
    if (sector_num < s->first_sectors_number)
2654
        return -1;
2655

    
2656
    for (i = sector2cluster(s, sector_num);
2657
            i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
2658
        mapping_t* mapping = find_mapping_for_cluster(s, i);
2659
        if (mapping) {
2660
            if (mapping->read_only) {
2661
                fprintf(stderr, "Tried to write to write-protected file %s\n",
2662
                        mapping->path);
2663
                return -1;
2664
            }
2665

    
2666
            if (mapping->mode & MODE_DIRECTORY) {
2667
                int begin = cluster2sector(s, i);
2668
                int end = begin + s->sectors_per_cluster, k;
2669
                int dir_index;
2670
                const direntry_t* direntries;
2671
                long_file_name lfn;
2672

    
2673
                lfn_init(&lfn);
2674

    
2675
                if (begin < sector_num)
2676
                    begin = sector_num;
2677
                if (end > sector_num + nb_sectors)
2678
                    end = sector_num + nb_sectors;
2679
                dir_index  = mapping->dir_index +
2680
                    0x10 * (begin - mapping->begin * s->sectors_per_cluster);
2681
                direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
2682

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

    
2706
    /*
2707
     * Use qcow backend. Commit later.
2708
     */
2709
DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
2710
    ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
2711
    if (ret < 0) {
2712
        fprintf(stderr, "Error writing to qcow backend\n");
2713
        return ret;
2714
    }
2715

    
2716
    for (i = sector2cluster(s, sector_num);
2717
            i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
2718
        if (i >= 0)
2719
            s->used_clusters[i] |= USED_ALLOCATED;
2720

    
2721
DLOG(checkpoint());
2722
    /* TODO: add timeout */
2723
    try_commit(s);
2724

    
2725
DLOG(checkpoint());
2726
    return 0;
2727
}
2728

    
2729
static int vvfat_is_allocated(BlockDriverState *bs,
2730
        int64_t sector_num, int nb_sectors, int* n)
2731
{
2732
    BDRVVVFATState* s = bs->opaque;
2733
    *n = s->sector_count - sector_num;
2734
    if (*n > nb_sectors)
2735
        *n = nb_sectors;
2736
    else if (*n < 0)
2737
        return 0;
2738
    return 1;
2739
}
2740

    
2741
static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
2742
        const uint8_t* buffer, int nb_sectors) {
2743
    BDRVVVFATState* s = bs->opaque;
2744
    return try_commit(s);
2745
}
2746

    
2747
static void write_target_close(BlockDriverState *bs) {
2748
    BDRVVVFATState* s = bs->opaque;
2749
    bdrv_delete(s->qcow);
2750
    free(s->qcow_filename);
2751
}
2752

    
2753
static BlockDriver vvfat_write_target = {
2754
    "vvfat_write_target", 0, NULL, NULL, NULL,
2755
    write_target_commit,
2756
    write_target_close,
2757
    NULL, NULL, NULL
2758
};
2759

    
2760
static int enable_write_target(BDRVVVFATState *s)
2761
{
2762
    int size = sector2cluster(s, s->sector_count);
2763
    s->used_clusters = calloc(size, 1);
2764

    
2765
    array_init(&(s->commits), sizeof(commit_t));
2766

    
2767
    s->qcow_filename = malloc(1024);
2768
    get_tmp_filename(s->qcow_filename, 1024);
2769
    if (bdrv_create(&bdrv_qcow,
2770
                s->qcow_filename, s->sector_count, "fat:", 0) < 0)
2771
        return -1;
2772
    s->qcow = bdrv_new("");
2773
    if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
2774
        return -1;
2775

    
2776
#ifndef _WIN32
2777
    unlink(s->qcow_filename);
2778
#endif
2779

    
2780
    s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
2781
    s->bs->backing_hd->drv = &vvfat_write_target;
2782
    s->bs->backing_hd->opaque = s;
2783

    
2784
    return 0;
2785
}
2786

    
2787
static void vvfat_close(BlockDriverState *bs)
2788
{
2789
    BDRVVVFATState *s = bs->opaque;
2790

    
2791
    vvfat_close_current_file(s);
2792
    array_free(&(s->fat));
2793
    array_free(&(s->directory));
2794
    array_free(&(s->mapping));
2795
    if(s->cluster_buffer)
2796
        free(s->cluster_buffer);
2797
}
2798

    
2799
BlockDriver bdrv_vvfat = {
2800
    "vvfat",
2801
    sizeof(BDRVVVFATState),
2802
    NULL, /* no probe for protocols */
2803
    vvfat_open,
2804
    vvfat_read,
2805
    vvfat_write,
2806
    vvfat_close,
2807
    NULL, /* ??? Not sure if we can do any meaningful flushing.  */
2808
    NULL,
2809
    vvfat_is_allocated,
2810
    .protocol_name = "fat",
2811
};
2812

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