Statistics
| Branch: | Revision:

root / block-vvfat.c @ 5fafdf24

History | View | Annotate | Download (77.6 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 "vl.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
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
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
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 partition_t {
246
    uint8_t attributes; /* 0x80 = bootable */
247
    uint8_t start_head;
248
    uint8_t start_sector;
249
    uint8_t start_cylinder;
250
    uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xb = FAT32 */
251
    uint8_t end_head;
252
    uint8_t end_sector;
253
    uint8_t end_cylinder;
254
    uint32_t start_sector_long;
255
    uint32_t end_sector_long;
256
} __attribute__((packed)) partition_t;
257

    
258
typedef struct mbr_t {
259
    uint8_t ignored[0x1be];
260
    partition_t partition[4];
261
    uint8_t magic[2];
262
} __attribute__((packed)) mbr_t;
263

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

    
279
/* this structure are used to transparently access the files */
280

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

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

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

    
316
/* here begins the real VVFAT driver */
317

    
318
typedef struct BDRVVVFATState {
319
    BlockDriverState* bs; /* pointer to parent */
320
    unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
321
    unsigned char first_sectors[0x40*0x200];
322
   
323
    int fat_type; /* 16 or 32 */
324
    array_t fat,directory,mapping;
325
  
326
    unsigned int cluster_size;
327
    unsigned int sectors_per_cluster;
328
    unsigned int sectors_per_fat;
329
    unsigned int sectors_of_root_directory;
330
    uint32_t last_cluster_of_root_directory;
331
    unsigned int faked_sectors; /* how many sectors are faked before file data */
332
    uint32_t sector_count; /* total number of sectors of the partition */
333
    uint32_t cluster_count; /* total number of clusters of this partition */
334
    uint32_t max_fat_value;
335
  
336
    int current_fd;
337
    mapping_t* current_mapping;
338
    unsigned char* cluster; /* points to current cluster */
339
    unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
340
    unsigned int current_cluster;
341

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

    
353

    
354
static void init_mbr(BDRVVVFATState* s)
355
{
356
    /* TODO: if the files mbr.img and bootsect.img exist, use them */
357
    mbr_t* real_mbr=(mbr_t*)s->first_sectors;
358
    partition_t* partition=&(real_mbr->partition[0]);
359

    
360
    memset(s->first_sectors,0,512);
361
  
362
    partition->attributes=0x80; /* bootable */
363
    partition->start_head=1;
364
    partition->start_sector=1;
365
    partition->start_cylinder=0;
366
    /* FAT12/FAT16/FAT32 */
367
    partition->fs_type=(s->fat_type==12?0x1:s->fat_type==16?0x6:0xb);
368
    partition->end_head=s->bs->heads-1;
369
    partition->end_sector=0xff; /* end sector & upper 2 bits of cylinder */;
370
    partition->end_cylinder=0xff; /* lower 8 bits of end cylinder */;
371
    partition->start_sector_long=cpu_to_le32(s->bs->secs);
372
    partition->end_sector_long=cpu_to_le32(s->sector_count);
373

    
374
    real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
375
}
376

    
377
/* direntry functions */
378

    
379
/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
380
static inline int short2long_name(unsigned char* dest,const char* src)
381
{
382
    int i;
383
    for(i=0;i<129 && src[i];i++) {
384
        dest[2*i]=src[i];
385
        dest[2*i+1]=0;
386
    }
387
    dest[2*i]=dest[2*i+1]=0;
388
    for(i=2*i+2;(i%26);i++)
389
        dest[i]=0xff;
390
    return i;
391
}
392

    
393
static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
394
{
395
    char buffer[258];
396
    int length=short2long_name(buffer,filename),
397
        number_of_entries=(length+25)/26,i;
398
    direntry_t* entry;
399

    
400
    for(i=0;i<number_of_entries;i++) {
401
        entry=array_get_next(&(s->directory));
402
        entry->attributes=0xf;
403
        entry->reserved[0]=0;
404
        entry->begin=0;
405
        entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
406
    }
407
    for(i=0;i<length;i++) {
408
        int offset=(i%26);
409
        if(offset<10) offset=1+offset;
410
        else if(offset<22) offset=14+offset-10;
411
        else offset=28+offset-22;
412
        entry=array_get(&(s->directory),s->directory.next-1-(i/26));
413
        entry->name[offset]=buffer[i];
414
    }
415
    return array_get(&(s->directory),s->directory.next-number_of_entries);
416
}
417

    
418
static char is_free(const direntry_t* direntry)
419
{
420
    /* return direntry->name[0]==0 ; */
421
    return direntry->attributes == 0 || direntry->name[0]==0xe5;
422
}
423

    
424
static char is_volume_label(const direntry_t* direntry)
425
{
426
    return direntry->attributes == 0x28;
427
}
428

    
429
static char is_long_name(const direntry_t* direntry)
430
{
431
    return direntry->attributes == 0xf;
432
}
433

    
434
static char is_short_name(const direntry_t* direntry)
435
{
436
    return !is_volume_label(direntry) && !is_long_name(direntry)
437
        && !is_free(direntry);
438
}
439

    
440
static char is_directory(const direntry_t* direntry)
441
{
442
    return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
443
}
444

    
445
static inline char is_dot(const direntry_t* direntry)
446
{
447
    return is_short_name(direntry) && direntry->name[0] == '.';
448
}
449

    
450
static char is_file(const direntry_t* direntry)
451
{
452
    return is_short_name(direntry) && !is_directory(direntry);
453
}
454

    
455
static inline uint32_t begin_of_direntry(const direntry_t* direntry)
456
{
457
    return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
458
}
459

    
460
static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
461
{
462
    return le32_to_cpu(direntry->size);
463
}
464

    
465
static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
466
{
467
    direntry->begin = cpu_to_le16(begin & 0xffff);
468
    direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
469
}
470

    
471
/* fat functions */
472

    
473
static inline uint8_t fat_chksum(const direntry_t* entry)
474
{
475
    uint8_t chksum=0;
476
    int i;
477

    
478
    for(i=0;i<11;i++)
479
        chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0))
480
            +(unsigned char)entry->name[i];
481
   
482
    return chksum;
483
}
484

    
485
/* if return_time==0, this returns the fat_date, else the fat_time */
486
static uint16_t fat_datetime(time_t time,int return_time) {
487
    struct tm* t;
488
#ifdef _WIN32
489
    t=localtime(&time); /* this is not thread safe */
490
#else
491
    struct tm t1;
492
    t=&t1;
493
    localtime_r(&time,t);
494
#endif
495
    if(return_time)
496
        return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
497
    return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
498
}
499

    
500
static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
501
{
502
    if(s->fat_type==32) {
503
        uint32_t* entry=array_get(&(s->fat),cluster);
504
        *entry=cpu_to_le32(value);
505
    } else if(s->fat_type==16) {
506
        uint16_t* entry=array_get(&(s->fat),cluster);
507
        *entry=cpu_to_le16(value&0xffff);
508
    } else {
509
        int offset = (cluster*3/2);
510
        unsigned char* p = array_get(&(s->fat), offset);
511
        switch (cluster&1) {
512
        case 0:
513
                p[0] = value&0xff;
514
                p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
515
                break;
516
        case 1:
517
                p[0] = (p[0]&0xf) | ((value&0xf)<<4);
518
                p[1] = (value>>4);
519
                break;
520
        }
521
    }
522
}
523

    
524
static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
525
{
526
    if(s->fat_type==32) {
527
        uint32_t* entry=array_get(&(s->fat),cluster);
528
        return le32_to_cpu(*entry);
529
    } else if(s->fat_type==16) {
530
        uint16_t* entry=array_get(&(s->fat),cluster);
531
        return le16_to_cpu(*entry);
532
    } else {
533
        const uint8_t* x=s->fat.pointer+cluster*3/2;
534
        return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
535
    }
536
}
537

    
538
static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
539
{
540
    if(fat_entry>s->max_fat_value-8)
541
        return -1;
542
    return 0;
543
}
544

    
545
static inline void init_fat(BDRVVVFATState* s)
546
{
547
    if (s->fat_type == 12) {
548
        array_init(&(s->fat),1);
549
        array_ensure_allocated(&(s->fat),
550
                s->sectors_per_fat * 0x200 * 3 / 2 - 1);
551
    } else {
552
        array_init(&(s->fat),(s->fat_type==32?4:2));
553
        array_ensure_allocated(&(s->fat),
554
                s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
555
    }
556
    memset(s->fat.pointer,0,s->fat.size);
557
   
558
    switch(s->fat_type) {
559
        case 12: s->max_fat_value=0xfff; break;
560
        case 16: s->max_fat_value=0xffff; break;
561
        case 32: s->max_fat_value=0x0fffffff; break;
562
        default: s->max_fat_value=0; /* error... */
563
    }
564

    
565
}
566

    
567
/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
568
/* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
569
static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
570
        unsigned int directory_start, const char* filename, int is_dot)
571
{
572
    int i,j,long_index=s->directory.next;
573
    direntry_t* entry=0;
574
    direntry_t* entry_long=0;
575

    
576
    if(is_dot) {
577
        entry=array_get_next(&(s->directory));
578
        memset(entry->name,0x20,11);
579
        memcpy(entry->name,filename,strlen(filename));
580
        return entry;
581
    }
582
   
583
    entry_long=create_long_filename(s,filename);
584
 
585
    i = strlen(filename);
586
    for(j = i - 1; j>0  && filename[j]!='.';j--);
587
    if (j > 0)
588
        i = (j > 8 ? 8 : j);
589
    else if (i > 8)
590
        i = 8;
591

    
592
    entry=array_get_next(&(s->directory));
593
    memset(entry->name,0x20,11);
594
    strncpy(entry->name,filename,i);
595
   
596
    if(j > 0)
597
        for (i = 0; i < 3 && filename[j+1+i]; i++)
598
            entry->extension[i] = filename[j+1+i];
599

    
600
    /* upcase & remove unwanted characters */
601
    for(i=10;i>=0;i--) {
602
        if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
603
        if(entry->name[i]<=' ' || entry->name[i]>0x7f
604
                || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
605
            entry->name[i]='_';
606
        else if(entry->name[i]>='a' && entry->name[i]<='z')
607
            entry->name[i]+='A'-'a';
608
    }
609

    
610
    /* mangle duplicates */
611
    while(1) {
612
        direntry_t* entry1=array_get(&(s->directory),directory_start);
613
        int j;
614

    
615
        for(;entry1<entry;entry1++)
616
            if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
617
                break; /* found dupe */
618
        if(entry1==entry) /* no dupe found */
619
            break;
620

    
621
        /* use all 8 characters of name */
622
        if(entry->name[7]==' ') {
623
            int j;
624
            for(j=6;j>0 && entry->name[j]==' ';j--)
625
                entry->name[j]='~';
626
        }
627

    
628
        /* increment number */
629
        for(j=7;j>0 && entry->name[j]=='9';j--)
630
            entry->name[j]='0';
631
        if(j>0) {
632
            if(entry->name[j]<'0' || entry->name[j]>'9')
633
                entry->name[j]='0';
634
            else
635
                entry->name[j]++;
636
        }
637
    }
638

    
639
    /* calculate checksum; propagate to long name */
640
    if(entry_long) {
641
        uint8_t chksum=fat_chksum(entry);
642

    
643
        /* calculate anew, because realloc could have taken place */
644
        entry_long=array_get(&(s->directory),long_index);
645
        while(entry_long<entry && is_long_name(entry_long)) {
646
            entry_long->reserved[1]=chksum;
647
            entry_long++;
648
        }
649
    }
650

    
651
    return entry;
652
}
653

    
654
/*
655
 * Read a directory. (the index of the corresponding mapping must be passed).
656
 */
657
static int read_directory(BDRVVVFATState* s, int mapping_index)
658
{
659
    mapping_t* mapping = array_get(&(s->mapping), mapping_index);
660
    direntry_t* direntry;
661
    const char* dirname = mapping->path;
662
    int first_cluster = mapping->begin;
663
    int parent_index = mapping->info.dir.parent_mapping_index;
664
    mapping_t* parent_mapping = (mapping_t*)
665
        (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : 0);
666
    int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
667

    
668
    DIR* dir=opendir(dirname);
669
    struct dirent* entry;
670
    int i;
671

    
672
    assert(mapping->mode & MODE_DIRECTORY);
673

    
674
    if(!dir) {
675
        mapping->end = mapping->begin;
676
        return -1;
677
    }
678
  
679
    i = mapping->info.dir.first_dir_index =
680
            first_cluster == 0 ? 0 : s->directory.next;
681

    
682
    /* actually read the directory, and allocate the mappings */
683
    while((entry=readdir(dir))) {
684
        unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
685
        char* buffer;
686
        direntry_t* direntry;
687
        struct stat st;
688
        int is_dot=!strcmp(entry->d_name,".");
689
        int is_dotdot=!strcmp(entry->d_name,"..");
690

    
691
        if(first_cluster == 0 && (is_dotdot || is_dot))
692
            continue;
693

    
694
        buffer=(char*)malloc(length);
695
        assert(buffer);
696
        snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
697

    
698
        if(stat(buffer,&st)<0) {
699
            free(buffer);
700
            continue;
701
        }
702

    
703
        /* create directory entry for this file */
704
        direntry=create_short_and_long_name(s, i, entry->d_name,
705
                is_dot || is_dotdot);
706
        direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
707
        direntry->reserved[0]=direntry->reserved[1]=0;
708
        direntry->ctime=fat_datetime(st.st_ctime,1);
709
        direntry->cdate=fat_datetime(st.st_ctime,0);
710
        direntry->adate=fat_datetime(st.st_atime,0);
711
        direntry->begin_hi=0;
712
        direntry->mtime=fat_datetime(st.st_mtime,1);
713
        direntry->mdate=fat_datetime(st.st_mtime,0);
714
        if(is_dotdot)
715
            set_begin_of_direntry(direntry, first_cluster_of_parent);
716
        else if(is_dot)
717
            set_begin_of_direntry(direntry, first_cluster);
718
        else
719
            direntry->begin=0; /* do that later */
720
        if (st.st_size > 0x7fffffff) {
721
            fprintf(stderr, "File %s is larger than 2GB\n", buffer);
722
            free(buffer);
723
            return -2;
724
        }
725
        direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
726

    
727
        /* create mapping for this file */
728
        if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
729
            s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
730
            s->current_mapping->begin=0;
731
            s->current_mapping->end=st.st_size;
732
            /*
733
             * we get the direntry of the most recent direntry, which
734
             * contains the short name and all the relevant information.
735
             */
736
            s->current_mapping->dir_index=s->directory.next-1;
737
            s->current_mapping->first_mapping_index = -1;
738
            if (S_ISDIR(st.st_mode)) {
739
                s->current_mapping->mode = MODE_DIRECTORY;
740
                s->current_mapping->info.dir.parent_mapping_index =
741
                    mapping_index;
742
            } else {
743
                s->current_mapping->mode = MODE_UNDEFINED;
744
                s->current_mapping->info.file.offset = 0;
745
            }
746
            s->current_mapping->path=buffer;
747
            s->current_mapping->read_only =
748
                (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
749
        }
750
    }
751
    closedir(dir);
752

    
753
    /* fill with zeroes up to the end of the cluster */
754
    while(s->directory.next%(0x10*s->sectors_per_cluster)) {
755
        direntry_t* direntry=array_get_next(&(s->directory));
756
        memset(direntry,0,sizeof(direntry_t));
757
    }
758

    
759
/* TODO: if there are more entries, bootsector has to be adjusted! */
760
#define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
761
    if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
762
        /* root directory */
763
        int cur = s->directory.next;
764
        array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
765
        memset(array_get(&(s->directory), cur), 0,
766
                (ROOT_ENTRIES - cur) * sizeof(direntry_t));
767
    }
768

    
769
     /* reget the mapping, since s->mapping was possibly realloc()ed */
770
    mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
771
    first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
772
        * 0x20 / s->cluster_size;
773
    mapping->end = first_cluster;
774

    
775
    direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
776
    set_begin_of_direntry(direntry, mapping->begin);
777
  
778
    return 0;
779
}
780

    
781
static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
782
{
783
    return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
784
}
785

    
786
static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
787
{
788
    return s->faked_sectors + s->sectors_per_cluster * cluster_num;
789
}
790

    
791
static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
792
{
793
    return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
794
}
795

    
796
#ifdef DBG
797
static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
798
{
799
    if(mapping->mode==MODE_UNDEFINED)
800
        return 0;
801
    return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
802
}
803
#endif
804

    
805
static int init_directories(BDRVVVFATState* s,
806
        const char* dirname)
807
{
808
    bootsector_t* bootsector;
809
    mapping_t* mapping;
810
    unsigned int i;
811
    unsigned int cluster;
812

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

    
815
    s->cluster_size=s->sectors_per_cluster*0x200;
816
    s->cluster_buffer=malloc(s->cluster_size);
817
    assert(s->cluster_buffer);
818

    
819
    /*
820
     * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
821
     * where sc is sector_count,
822
     * spf is sectors_per_fat,
823
     * spc is sectors_per_clusters, and
824
     * fat_type = 12, 16 or 32.
825
     */
826
    i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
827
    s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
828
   
829
    array_init(&(s->mapping),sizeof(mapping_t));
830
    array_init(&(s->directory),sizeof(direntry_t));
831

    
832
    /* add volume label */
833
    {
834
        direntry_t* entry=array_get_next(&(s->directory));
835
        entry->attributes=0x28; /* archive | volume label */
836
        snprintf(entry->name,11,"QEMU VVFAT");
837
    }
838

    
839
    /* Now build FAT, and write back information into directory */
840
    init_fat(s);
841

    
842
    s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
843
    s->cluster_count=sector2cluster(s, s->sector_count);
844

    
845
    mapping = array_get_next(&(s->mapping));
846
    mapping->begin = 0;
847
    mapping->dir_index = 0;
848
    mapping->info.dir.parent_mapping_index = -1;
849
    mapping->first_mapping_index = -1;
850
    mapping->path = strdup(dirname);
851
    i = strlen(mapping->path);
852
    if (i > 0 && mapping->path[i - 1] == '/')
853
        mapping->path[i - 1] = '\0';
854
    mapping->mode = MODE_DIRECTORY;
855
    mapping->read_only = 0;
856
    s->path = mapping->path;
857

    
858
    for (i = 0, cluster = 0; i < s->mapping.next; i++) {
859
        int j;
860
        /* MS-DOS expects the FAT to be 0 for the root directory
861
         * (except for the media byte). */
862
        /* LATER TODO: still true for FAT32? */
863
        int fix_fat = (i != 0);
864
        mapping = array_get(&(s->mapping), i);
865

    
866
        if (mapping->mode & MODE_DIRECTORY) {
867
            mapping->begin = cluster;
868
            if(read_directory(s, i)) {
869
                fprintf(stderr, "Could not read directory %s\n",
870
                        mapping->path);
871
                return -1;
872
            }
873
            mapping = array_get(&(s->mapping), i);
874
        } else {
875
            assert(mapping->mode == MODE_UNDEFINED);
876
            mapping->mode=MODE_NORMAL;
877
            mapping->begin = cluster;
878
            if (mapping->end > 0) {
879
                direntry_t* direntry = array_get(&(s->directory),
880
                        mapping->dir_index);
881

    
882
                mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
883
                set_begin_of_direntry(direntry, mapping->begin);
884
            } else {
885
                mapping->end = cluster + 1;
886
                fix_fat = 0;
887
            }
888
        }
889

    
890
        assert(mapping->begin < mapping->end);
891

    
892
        /* fix fat for entry */
893
        if (fix_fat) {
894
            for(j = mapping->begin; j < mapping->end - 1; j++)
895
                fat_set(s, j, j+1);
896
            fat_set(s, mapping->end - 1, s->max_fat_value);
897
        }
898

    
899
        /* next free cluster */
900
        cluster = mapping->end;
901

    
902
        if(cluster > s->cluster_count) {
903
            fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type);
904
            return -1;
905
        }
906
    }
907

    
908
    mapping = array_get(&(s->mapping), 0);
909
    s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
910
    s->last_cluster_of_root_directory = mapping->end;
911

    
912
    /* the FAT signature */
913
    fat_set(s,0,s->max_fat_value);
914
    fat_set(s,1,s->max_fat_value);
915

    
916
    s->current_mapping = NULL;
917

    
918
    bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
919
    bootsector->jump[0]=0xeb;
920
    bootsector->jump[1]=0x3e;
921
    bootsector->jump[2]=0x90;
922
    memcpy(bootsector->name,"QEMU    ",8);
923
    bootsector->sector_size=cpu_to_le16(0x200);
924
    bootsector->sectors_per_cluster=s->sectors_per_cluster;
925
    bootsector->reserved_sectors=cpu_to_le16(1);
926
    bootsector->number_of_fats=0x2; /* number of FATs */
927
    bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
928
    bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
929
    bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
930
    s->fat.pointer[0] = bootsector->media_type;
931
    bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
932
    bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
933
    bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
934
    bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
935
    bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
936

    
937
    /* LATER TODO: if FAT32, this is wrong */
938
    bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
939
    bootsector->u.fat16.current_head=0;
940
    bootsector->u.fat16.signature=0x29;
941
    bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
942

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

    
947
    return 0;
948
}
949

    
950
#ifdef DEBUG
951
static BDRVVVFATState *vvv = NULL;
952
#endif
953

    
954
static int enable_write_target(BDRVVVFATState *s);
955
static int is_consistent(BDRVVVFATState *s);
956

    
957
static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
958
{
959
    BDRVVVFATState *s = bs->opaque;
960
    int floppy = 0;
961
    int i;
962

    
963
#ifdef DEBUG
964
    vvv = s;
965
#endif
966

    
967
DLOG(if (stderr == NULL) {
968
    stderr = fopen("vvfat.log", "a");
969
    setbuf(stderr, NULL);
970
})
971

    
972
    s->bs = bs;
973

    
974
    s->fat_type=16;
975
    /* LATER TODO: if FAT32, adjust */
976
    s->sector_count=0xec04f;
977
    s->sectors_per_cluster=0x10;
978
    /* LATER TODO: this could be wrong for FAT32 */
979
    bs->cyls=1023; bs->heads=15; bs->secs=63;
980

    
981
    s->current_cluster=0xffffffff;
982

    
983
    s->first_sectors_number=0x40;
984
    /* read only is the default for safety */
985
    bs->read_only = 1;
986
    s->qcow = s->write_target = NULL;
987
    s->qcow_filename = NULL;
988
    s->fat2 = NULL;
989
    s->downcase_short_names = 1;
990
   
991
    if (!strstart(dirname, "fat:", NULL))
992
        return -1;
993

    
994
    if (strstr(dirname, ":rw:")) {
995
        if (enable_write_target(s))
996
            return -1;
997
        bs->read_only = 0;
998
    }
999

    
1000
    if (strstr(dirname, ":floppy:")) {
1001
        floppy = 1;
1002
        s->fat_type = 12;
1003
        s->first_sectors_number = 1;
1004
        s->sectors_per_cluster=2;
1005
        bs->cyls = 80; bs->heads = 2; bs->secs = 36;
1006
    }
1007

    
1008
    if (strstr(dirname, ":32:")) {
1009
        fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1010
        s->fat_type = 32;
1011
    } else if (strstr(dirname, ":16:")) {
1012
        s->fat_type = 16;
1013
    } else if (strstr(dirname, ":12:")) {
1014
        s->fat_type = 12;
1015
        s->sector_count=2880;
1016
    }
1017

    
1018
    i = strrchr(dirname, ':') - dirname;
1019
    assert(i >= 3);
1020
    if (dirname[i-2] == ':' && isalpha(dirname[i-1]))
1021
        /* workaround for DOS drive names */
1022
        dirname += i-1;
1023
    else
1024
        dirname += i+1;
1025

    
1026
    bs->total_sectors=bs->cyls*bs->heads*bs->secs;
1027
    if (s->sector_count > bs->total_sectors)
1028
        s->sector_count = bs->total_sectors;
1029
    if(init_directories(s, dirname))
1030
        return -1;
1031

    
1032
    if(s->first_sectors_number==0x40)
1033
        init_mbr(s);
1034

    
1035
    /* for some reason or other, MS-DOS does not like to know about CHS... */
1036
    if (floppy)
1037
        bs->heads = bs->cyls = bs->secs = 0;
1038

    
1039
    //    assert(is_consistent(s));
1040
    return 0;
1041
}
1042

    
1043
static inline void vvfat_close_current_file(BDRVVVFATState *s)
1044
{
1045
    if(s->current_mapping) {
1046
        s->current_mapping = NULL;
1047
        if (s->current_fd) {
1048
                close(s->current_fd);
1049
                s->current_fd = 0;
1050
        }
1051
    }
1052
    s->current_cluster = -1;
1053
}
1054

    
1055
/* mappings between index1 and index2-1 are supposed to be ordered
1056
 * return value is the index of the last mapping for which end>cluster_num
1057
 */
1058
static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1059
{
1060
    int index3=index1+1;
1061
    while(1) {
1062
        mapping_t* mapping;
1063
        index3=(index1+index2)/2;
1064
        mapping=array_get(&(s->mapping),index3);
1065
        assert(mapping->begin < mapping->end);
1066
        if(mapping->begin>=cluster_num) {
1067
            assert(index2!=index3 || index2==0);
1068
            if(index2==index3)
1069
                return index1;
1070
            index2=index3;
1071
        } else {
1072
            if(index1==index3)
1073
                return mapping->end<=cluster_num ? index2 : index1;
1074
            index1=index3;
1075
        }
1076
        assert(index1<=index2);
1077
        DLOG(mapping=array_get(&(s->mapping),index1);
1078
        assert(mapping->begin<=cluster_num);
1079
        assert(index2 >= s->mapping.next ||
1080
                ((mapping = array_get(&(s->mapping),index2)) &&
1081
                mapping->end>cluster_num)));
1082
    }
1083
}
1084

    
1085
static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
1086
{
1087
    int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
1088
    mapping_t* mapping;
1089
    if(index>=s->mapping.next)
1090
        return 0;
1091
    mapping=array_get(&(s->mapping),index);
1092
    if(mapping->begin>cluster_num)
1093
        return 0;
1094
    assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
1095
    return mapping;
1096
}
1097

    
1098
/*
1099
 * This function simply compares path == mapping->path. Since the mappings
1100
 * are sorted by cluster, this is expensive: O(n).
1101
 */
1102
static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
1103
        const char* path)
1104
{
1105
    int i;
1106

    
1107
    for (i = 0; i < s->mapping.next; i++) {
1108
        mapping_t* mapping = array_get(&(s->mapping), i);
1109
        if (mapping->first_mapping_index < 0 &&
1110
                !strcmp(path, mapping->path))
1111
            return mapping;
1112
    }
1113

    
1114
    return NULL;
1115
}
1116

    
1117
static int open_file(BDRVVVFATState* s,mapping_t* mapping)
1118
{
1119
    if(!mapping)
1120
        return -1;
1121
    if(!s->current_mapping ||
1122
            strcmp(s->current_mapping->path,mapping->path)) {
1123
        /* open file */
1124
        int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
1125
        if(fd<0)
1126
            return -1;
1127
        vvfat_close_current_file(s);
1128
        s->current_fd = fd;
1129
        s->current_mapping = mapping;
1130
    }
1131
    return 0;
1132
}
1133

    
1134
static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1135
{
1136
    if(s->current_cluster != cluster_num) {
1137
        int result=0;
1138
        off_t offset;
1139
        assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
1140
        if(!s->current_mapping
1141
                || s->current_mapping->begin>cluster_num
1142
                || s->current_mapping->end<=cluster_num) {
1143
            /* binary search of mappings for file */
1144
            mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
1145

    
1146
            assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1147

    
1148
            if (mapping && mapping->mode & MODE_DIRECTORY) {
1149
                vvfat_close_current_file(s);
1150
                s->current_mapping = mapping;
1151
read_cluster_directory:
1152
                offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
1153
                s->cluster = s->directory.pointer+offset
1154
                        + 0x20*s->current_mapping->info.dir.first_dir_index;
1155
                assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1156
                assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1157
                s->current_cluster = cluster_num;
1158
                return 0;
1159
            }
1160

    
1161
            if(open_file(s,mapping))
1162
                return -2;
1163
        } else if (s->current_mapping->mode & MODE_DIRECTORY)
1164
            goto read_cluster_directory;
1165

    
1166
        assert(s->current_fd);
1167

    
1168
        offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
1169
        if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1170
            return -3;
1171
        s->cluster=s->cluster_buffer;
1172
        result=read(s->current_fd,s->cluster,s->cluster_size);
1173
        if(result<0) {
1174
            s->current_cluster = -1;
1175
            return -1;
1176
        }
1177
        s->current_cluster = cluster_num;
1178
    }
1179
    return 0;
1180
}
1181

    
1182
#ifdef DEBUG
1183
static void hexdump(const void* address, uint32_t len)
1184
{
1185
    const unsigned char* p = address;
1186
    int i, j;
1187

    
1188
    for (i = 0; i < len; i += 16) {
1189
        for (j = 0; j < 16 && i + j < len; j++)
1190
            fprintf(stderr, "%02x ", p[i + j]);
1191
        for (; j < 16; j++)
1192
            fprintf(stderr, "   ");
1193
        fprintf(stderr, " ");
1194
        for (j = 0; j < 16 && i + j < len; j++)
1195
            fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
1196
        fprintf(stderr, "\n");
1197
    }
1198
}
1199

    
1200
static void print_direntry(const direntry_t* direntry)
1201
{
1202
    int j = 0;
1203
    char buffer[1024];
1204

    
1205
    fprintf(stderr, "direntry 0x%x: ", (int)direntry);
1206
    if(!direntry)
1207
        return;
1208
    if(is_long_name(direntry)) {
1209
        unsigned char* c=(unsigned char*)direntry;
1210
        int i;
1211
        for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
1212
#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = '?'; j++;}
1213
            ADD_CHAR(c[i]);
1214
        for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
1215
            ADD_CHAR(c[i]);
1216
        for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
1217
            ADD_CHAR(c[i]);
1218
        buffer[j] = 0;
1219
        fprintf(stderr, "%s\n", buffer);
1220
    } else {
1221
        int i;
1222
        for(i=0;i<11;i++)
1223
            ADD_CHAR(direntry->name[i]);
1224
        buffer[j] = 0;
1225
        fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1226
                buffer,
1227
                direntry->attributes,
1228
                begin_of_direntry(direntry),le32_to_cpu(direntry->size));
1229
    }
1230
}
1231

    
1232
static void print_mapping(const mapping_t* mapping)
1233
{
1234
    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);
1235
    if (mapping->mode & MODE_DIRECTORY)
1236
        fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1237
    else
1238
        fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
1239
}
1240
#endif
1241

    
1242
static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
1243
                    uint8_t *buf, int nb_sectors)
1244
{
1245
    BDRVVVFATState *s = bs->opaque;
1246
    int i;
1247

    
1248
    for(i=0;i<nb_sectors;i++,sector_num++) {
1249
        if (sector_num >= s->sector_count)
1250
           return -1;
1251
        if (s->qcow) {
1252
            int n;
1253
            if (s->qcow->drv->bdrv_is_allocated(s->qcow,
1254
                        sector_num, nb_sectors-i, &n)) {
1255
DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
1256
                if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
1257
                    return -1;
1258
                i += n - 1;
1259
                sector_num += n - 1;
1260
                continue;
1261
            }
1262
DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
1263
        }
1264
        if(sector_num<s->faked_sectors) {
1265
            if(sector_num<s->first_sectors_number)
1266
                memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
1267
            else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
1268
                memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
1269
            else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
1270
                memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
1271
        } else {
1272
            uint32_t sector=sector_num-s->faked_sectors,
1273
            sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1274
            cluster_num=sector/s->sectors_per_cluster;
1275
            if(read_cluster(s, cluster_num) != 0) {
1276
                /* LATER TODO: strict: return -1; */
1277
                memset(buf+i*0x200,0,0x200);
1278
                continue;
1279
            }
1280
            memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
1281
        }
1282
    }
1283
    return 0;
1284
}
1285

    
1286
/* LATER TODO: statify all functions */
1287

    
1288
/*
1289
 * Idea of the write support (use snapshot):
1290
 *
1291
 * 1. check if all data is consistent, recording renames, modifications,
1292
 *    new files and directories (in s->commits).
1293
 *
1294
 * 2. if the data is not consistent, stop committing
1295
 *
1296
 * 3. handle renames, and create new files and directories (do not yet
1297
 *    write their contents)
1298
 *
1299
 * 4. walk the directories, fixing the mapping and direntries, and marking
1300
 *    the handled mappings as not deleted
1301
 *
1302
 * 5. commit the contents of the files
1303
 *
1304
 * 6. handle deleted files and directories
1305
 *
1306
 */
1307

    
1308
typedef struct commit_t {
1309
    char* path;
1310
    union {
1311
        struct { uint32_t cluster; } rename;
1312
        struct { int dir_index; uint32_t modified_offset; } writeout;
1313
        struct { uint32_t first_cluster; } new_file;
1314
        struct { uint32_t cluster; } mkdir;
1315
    } param;
1316
    /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1317
    enum {
1318
        ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1319
    } action;
1320
} commit_t;
1321

    
1322
static void clear_commits(BDRVVVFATState* s)
1323
{
1324
    int i;
1325
DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1326
    for (i = 0; i < s->commits.next; i++) {
1327
        commit_t* commit = array_get(&(s->commits), i);
1328
        assert(commit->path || commit->action == ACTION_WRITEOUT);
1329
        if (commit->action != ACTION_WRITEOUT) {
1330
            assert(commit->path);
1331
            free(commit->path);
1332
        } else
1333
            assert(commit->path == NULL);
1334
    }
1335
    s->commits.next = 0;
1336
}
1337

    
1338
static void schedule_rename(BDRVVVFATState* s,
1339
        uint32_t cluster, char* new_path)
1340
{
1341
    commit_t* commit = array_get_next(&(s->commits));
1342
    commit->path = new_path;
1343
    commit->param.rename.cluster = cluster;
1344
    commit->action = ACTION_RENAME;
1345
}
1346

    
1347
static void schedule_writeout(BDRVVVFATState* s,
1348
        int dir_index, uint32_t modified_offset)
1349
{
1350
    commit_t* commit = array_get_next(&(s->commits));
1351
    commit->path = NULL;
1352
    commit->param.writeout.dir_index = dir_index;
1353
    commit->param.writeout.modified_offset = modified_offset;
1354
    commit->action = ACTION_WRITEOUT;
1355
}
1356

    
1357
static void schedule_new_file(BDRVVVFATState* s,
1358
        char* path, uint32_t first_cluster)
1359
{
1360
    commit_t* commit = array_get_next(&(s->commits));
1361
    commit->path = path;
1362
    commit->param.new_file.first_cluster = first_cluster;
1363
    commit->action = ACTION_NEW_FILE;
1364
}
1365

    
1366
static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1367
{
1368
    commit_t* commit = array_get_next(&(s->commits));
1369
    commit->path = path;
1370
    commit->param.mkdir.cluster = cluster;
1371
    commit->action = ACTION_MKDIR;
1372
}
1373

    
1374
typedef struct {
1375
    unsigned char name[1024];
1376
    int checksum, len;
1377
    int sequence_number;
1378
} long_file_name;
1379

    
1380
static void lfn_init(long_file_name* lfn)
1381
{
1382
   lfn->sequence_number = lfn->len = 0;
1383
   lfn->checksum = 0x100;
1384
}
1385

    
1386
/* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1387
static int parse_long_name(long_file_name* lfn,
1388
        const direntry_t* direntry)
1389
{
1390
    int i, j, offset;
1391
    const unsigned char* pointer = (const unsigned char*)direntry;
1392

    
1393
    if (!is_long_name(direntry))
1394
        return 1;
1395

    
1396
    if (pointer[0] & 0x40) {
1397
        lfn->sequence_number = pointer[0] & 0x3f;
1398
        lfn->checksum = pointer[13];
1399
        lfn->name[0] = 0;
1400
    } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
1401
        return -1;
1402
    else if (pointer[13] != lfn->checksum)
1403
        return -2;
1404
    else if (pointer[12] || pointer[26] || pointer[27])
1405
        return -3;
1406

    
1407
    offset = 13 * (lfn->sequence_number - 1);
1408
    for (i = 0, j = 1; i < 13; i++, j+=2) {
1409
        if (j == 11)
1410
            j = 14;
1411
        else if (j == 26)
1412
            j = 28;
1413

    
1414
        if (pointer[j+1] == 0)
1415
            lfn->name[offset + i] = pointer[j];
1416
        else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1417
            return -4;
1418
        else
1419
            lfn->name[offset + i] = 0;
1420
    }
1421

    
1422
    if (pointer[0] & 0x40)
1423
        lfn->len = offset + strlen(lfn->name + offset);
1424

    
1425
    return 0;
1426
}
1427

    
1428
/* returns 0 if successful, >0 if no short_name, and <0 on error */
1429
static int parse_short_name(BDRVVVFATState* s,
1430
        long_file_name* lfn, direntry_t* direntry)
1431
{
1432
    int i, j;
1433

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

    
1437
    for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1438
    for (i = 0; i <= j; i++) {
1439
        if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
1440
            return -1;
1441
        else if (s->downcase_short_names)
1442
            lfn->name[i] = tolower(direntry->name[i]);
1443
        else
1444
            lfn->name[i] = direntry->name[i];
1445
    }
1446

    
1447
    for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
1448
    if (j >= 0) {
1449
        lfn->name[i++] = '.';
1450
        lfn->name[i + j + 1] = '\0';
1451
        for (;j >= 0; j--) {
1452
            if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
1453
                return -2;
1454
            else if (s->downcase_short_names)
1455
                lfn->name[i + j] = tolower(direntry->extension[j]);
1456
            else
1457
                lfn->name[i + j] = direntry->extension[j];
1458
        }
1459
    } else
1460
        lfn->name[i + j + 1] = '\0';
1461

    
1462
    lfn->len = strlen(lfn->name);
1463

    
1464
    return 0;
1465
}
1466

    
1467
static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1468
        unsigned int cluster)
1469
{
1470
    if (cluster < s->last_cluster_of_root_directory) {
1471
        if (cluster + 1 == s->last_cluster_of_root_directory)
1472
            return s->max_fat_value;
1473
        else
1474
            return cluster + 1;
1475
    }
1476

    
1477
    if (s->fat_type==32) {
1478
        uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1479
        return le32_to_cpu(*entry);
1480
    } else if (s->fat_type==16) {
1481
        uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1482
        return le16_to_cpu(*entry);
1483
    } else {
1484
        const uint8_t* x=s->fat2+cluster*3/2;
1485
        return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1486
    }
1487
}
1488

    
1489
static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1490
{
1491
    int was_modified = 0;
1492
    int i, dummy;
1493

    
1494
    if (s->qcow == NULL)
1495
        return 0;
1496

    
1497
    for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
1498
        was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
1499
                cluster2sector(s, cluster_num) + i, 1, &dummy);
1500

    
1501
    return was_modified;
1502
}
1503

    
1504
static const char* get_basename(const char* path)
1505
{
1506
    char* basename = strrchr(path, '/');
1507
    if (basename == NULL)
1508
        return path;
1509
    else
1510
        return basename + 1; /* strip '/' */
1511
}
1512

    
1513
/*
1514
 * The array s->used_clusters holds the states of the clusters. If it is
1515
 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1516
 * was modified, bit 3 is set.
1517
 * If any cluster is allocated, but not part of a file or directory, this
1518
 * driver refuses to commit.
1519
 */
1520
typedef enum {
1521
     USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
1522
} used_t;
1523

    
1524
/*
1525
 * get_cluster_count_for_direntry() not only determines how many clusters
1526
 * are occupied by direntry, but also if it was renamed or modified.
1527
 *
1528
 * A file is thought to be renamed *only* if there already was a file with
1529
 * exactly the same first cluster, but a different name.
1530
 *
1531
 * Further, the files/directories handled by this function are
1532
 * assumed to be *not* deleted (and *only* those).
1533
 */
1534
static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
1535
        direntry_t* direntry, const char* path)
1536
{
1537
    /*
1538
     * This is a little bit tricky:
1539
     * IF the guest OS just inserts a cluster into the file chain,
1540
     * and leaves the rest alone, (i.e. the original file had clusters
1541
     * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1542
     *
1543
     * - do_commit will write the cluster into the file at the given
1544
     *   offset, but
1545
     *
1546
     * - the cluster which is overwritten should be moved to a later
1547
     *   position in the file.
1548
     *
1549
     * I am not aware that any OS does something as braindead, but this
1550
     * situation could happen anyway when not committing for a long time.
1551
     * Just to be sure that this does not bite us, detect it, and copy the
1552
     * contents of the clusters to-be-overwritten into the qcow.
1553
     */
1554
    int copy_it = 0;
1555
    int was_modified = 0;
1556
    int32_t ret = 0;
1557

    
1558
    uint32_t cluster_num = begin_of_direntry(direntry);
1559
    uint32_t offset = 0;
1560
    int first_mapping_index = -1;
1561
    mapping_t* mapping = NULL;
1562
    const char* basename2 = NULL;
1563

    
1564
    vvfat_close_current_file(s);
1565

    
1566
    /* the root directory */
1567
    if (cluster_num == 0)
1568
        return 0;
1569

    
1570
    /* write support */
1571
    if (s->qcow) {
1572
        basename2 = get_basename(path);
1573

    
1574
        mapping = find_mapping_for_cluster(s, cluster_num);
1575

    
1576
        if (mapping) {
1577
            const char* basename;
1578

    
1579
            assert(mapping->mode & MODE_DELETED);
1580
            mapping->mode &= ~MODE_DELETED;
1581

    
1582
            basename = get_basename(mapping->path);
1583

    
1584
            assert(mapping->mode & MODE_NORMAL);
1585

    
1586
            /* rename */
1587
            if (strcmp(basename, basename2))
1588
                schedule_rename(s, cluster_num, strdup(path));
1589
        } else if (is_file(direntry))
1590
            /* new file */
1591
            schedule_new_file(s, strdup(path), cluster_num);
1592
        else {
1593
            assert(0);
1594
            return 0;
1595
        }
1596
    }
1597

    
1598
    while(1) {
1599
        if (s->qcow) {
1600
            if (!copy_it && cluster_was_modified(s, cluster_num)) {
1601
                if (mapping == NULL ||
1602
                        mapping->begin > cluster_num ||
1603
                        mapping->end <= cluster_num)
1604
                mapping = find_mapping_for_cluster(s, cluster_num);
1605

    
1606

    
1607
                if (mapping &&
1608
                        (mapping->mode & MODE_DIRECTORY) == 0) {
1609

    
1610
                    /* was modified in qcow */
1611
                    if (offset != mapping->info.file.offset + s->cluster_size
1612
                            * (cluster_num - mapping->begin)) {
1613
                        /* offset of this cluster in file chain has changed */
1614
                        assert(0);
1615
                        copy_it = 1;
1616
                    } else if (offset == 0) {
1617
                        const char* basename = get_basename(mapping->path);
1618

    
1619
                        if (strcmp(basename, basename2))
1620
                            copy_it = 1;
1621
                        first_mapping_index = array_index(&(s->mapping), mapping);
1622
                    }
1623

    
1624
                    if (mapping->first_mapping_index != first_mapping_index
1625
                            && mapping->info.file.offset > 0) {
1626
                        assert(0);
1627
                        copy_it = 1;
1628
                    }
1629

    
1630
                    /* need to write out? */
1631
                    if (!was_modified && is_file(direntry)) {
1632
                        was_modified = 1;
1633
                        schedule_writeout(s, mapping->dir_index, offset);
1634
                    }
1635
                }
1636
            }
1637

    
1638
            if (copy_it) {
1639
                int i, dummy;
1640
                /*
1641
                 * This is horribly inefficient, but that is okay, since
1642
                 * it is rarely executed, if at all.
1643
                 */
1644
                int64_t offset = cluster2sector(s, cluster_num);
1645

    
1646
                vvfat_close_current_file(s);
1647
                for (i = 0; i < s->sectors_per_cluster; i++)
1648
                    if (!s->qcow->drv->bdrv_is_allocated(s->qcow,
1649
                                offset + i, 1, &dummy)) {
1650
                        if (vvfat_read(s->bs,
1651
                                    offset, s->cluster_buffer, 1))
1652
                            return -1;
1653
                        if (s->qcow->drv->bdrv_write(s->qcow,
1654
                                    offset, s->cluster_buffer, 1))
1655
                            return -2;
1656
                    }
1657
            }
1658
        }
1659

    
1660
        ret++;
1661
        if (s->used_clusters[cluster_num] & USED_ANY)
1662
            return 0;
1663
        s->used_clusters[cluster_num] = USED_FILE;
1664

    
1665
        cluster_num = modified_fat_get(s, cluster_num);
1666

    
1667
        if (fat_eof(s, cluster_num))
1668
            return ret;
1669
        else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
1670
            return -1;
1671

    
1672
        offset += s->cluster_size;
1673
    }
1674
}
1675

    
1676
/*
1677
 * This function looks at the modified data (qcow).
1678
 * It returns 0 upon inconsistency or error, and the number of clusters
1679
 * used by the directory, its subdirectories and their files.
1680
 */
1681
static int check_directory_consistency(BDRVVVFATState *s,
1682
        int cluster_num, const char* path)
1683
{
1684
    int ret = 0;
1685
    unsigned char* cluster = malloc(s->cluster_size);
1686
    direntry_t* direntries = (direntry_t*)cluster;
1687
    mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
1688

    
1689
    long_file_name lfn;
1690
    int path_len = strlen(path);
1691
    char path2[PATH_MAX];
1692

    
1693
    assert(path_len < PATH_MAX); /* len was tested before! */
1694
    strcpy(path2, path);
1695
    path2[path_len] = '/';
1696
    path2[path_len + 1] = '\0';
1697

    
1698
    if (mapping) {
1699
        const char* basename = get_basename(mapping->path);
1700
        const char* basename2 = get_basename(path);
1701

    
1702
        assert(mapping->mode & MODE_DIRECTORY);
1703

    
1704
        assert(mapping->mode & MODE_DELETED);
1705
        mapping->mode &= ~MODE_DELETED;
1706

    
1707
        if (strcmp(basename, basename2))
1708
            schedule_rename(s, cluster_num, strdup(path));
1709
    } else
1710
        /* new directory */
1711
        schedule_mkdir(s, cluster_num, strdup(path));
1712
        
1713
    lfn_init(&lfn);
1714
    do {
1715
        int i;
1716
        int subret = 0;
1717

    
1718
        ret++;
1719

    
1720
        if (s->used_clusters[cluster_num] & USED_ANY) {
1721
            fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
1722
            return 0;
1723
        }
1724
        s->used_clusters[cluster_num] = USED_DIRECTORY;
1725

    
1726
DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
1727
        subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
1728
                s->sectors_per_cluster);
1729
        if (subret) {
1730
            fprintf(stderr, "Error fetching direntries\n");
1731
        fail:
1732
            free(cluster);
1733
            return 0;
1734
        }
1735

    
1736
        for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
1737
            int cluster_count;
1738

    
1739
DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
1740
            if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
1741
                    is_free(direntries + i))
1742
                continue;
1743

    
1744
            subret = parse_long_name(&lfn, direntries + i);
1745
            if (subret < 0) {
1746
                fprintf(stderr, "Error in long name\n");
1747
                goto fail;
1748
            }
1749
            if (subret == 0 || is_free(direntries + i))
1750
                continue;
1751

    
1752
            if (fat_chksum(direntries+i) != lfn.checksum) {
1753
                subret = parse_short_name(s, &lfn, direntries + i);
1754
                if (subret < 0) {
1755
                    fprintf(stderr, "Error in short name (%d)\n", subret);
1756
                    goto fail;
1757
                }
1758
                if (subret > 0 || !strcmp(lfn.name, ".")
1759
                        || !strcmp(lfn.name, ".."))
1760
                    continue;
1761
            }
1762
            lfn.checksum = 0x100; /* cannot use long name twice */
1763

    
1764
            if (path_len + 1 + lfn.len >= PATH_MAX) {
1765
                fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
1766
                goto fail;
1767
            }
1768
            strcpy(path2 + path_len + 1, lfn.name);
1769

    
1770
            if (is_directory(direntries + i)) {
1771
                if (begin_of_direntry(direntries + i) == 0) {
1772
                    DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
1773
                    goto fail;
1774
                }
1775
                cluster_count = check_directory_consistency(s,
1776
                        begin_of_direntry(direntries + i), path2);
1777
                if (cluster_count == 0) {
1778
                    DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
1779
                    goto fail;
1780
                }
1781
            } else if (is_file(direntries + i)) {
1782
                /* check file size with FAT */
1783
                cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
1784
                if (cluster_count !=
1785
                        (le32_to_cpu(direntries[i].size) + s->cluster_size
1786
                         - 1) / s->cluster_size) {
1787
                    DLOG(fprintf(stderr, "Cluster count mismatch\n"));
1788
                    goto fail;
1789
                }
1790
            } else
1791
                assert(0); /* cluster_count = 0; */
1792

    
1793
            ret += cluster_count;
1794
        }
1795

    
1796
        cluster_num = modified_fat_get(s, cluster_num);
1797
    } while(!fat_eof(s, cluster_num));
1798

    
1799
    free(cluster);
1800
    return ret;
1801
}
1802

    
1803
/* returns 1 on success */
1804
static int is_consistent(BDRVVVFATState* s)
1805
{
1806
    int i, check;
1807
    int used_clusters_count = 0;
1808

    
1809
DLOG(checkpoint());
1810
    /*
1811
     * - get modified FAT
1812
     * - compare the two FATs (TODO)
1813
     * - get buffer for marking used clusters
1814
     * - recurse direntries from root (using bs->bdrv_read to make
1815
     *    sure to get the new data)
1816
     *   - check that the FAT agrees with the size
1817
     *   - count the number of clusters occupied by this directory and
1818
     *     its files
1819
     * - check that the cumulative used cluster count agrees with the
1820
     *   FAT
1821
     * - if all is fine, return number of used clusters
1822
     */
1823
    if (s->fat2 == NULL) {
1824
        int size = 0x200 * s->sectors_per_fat;
1825
        s->fat2 = malloc(size);
1826
        memcpy(s->fat2, s->fat.pointer, size);
1827
    }
1828
    check = vvfat_read(s->bs,
1829
            s->first_sectors_number, s->fat2, s->sectors_per_fat);
1830
    if (check) {
1831
        fprintf(stderr, "Could not copy fat\n");
1832
        return 0;
1833
    }
1834
    assert (s->used_clusters);
1835
    for (i = 0; i < sector2cluster(s, s->sector_count); i++)
1836
        s->used_clusters[i] &= ~USED_ANY;
1837

    
1838
    clear_commits(s);
1839

    
1840
    /* mark every mapped file/directory as deleted.
1841
     * (check_directory_consistency() will unmark those still present). */
1842
    if (s->qcow)
1843
        for (i = 0; i < s->mapping.next; i++) {
1844
            mapping_t* mapping = array_get(&(s->mapping), i);
1845
            if (mapping->first_mapping_index < 0)
1846
                mapping->mode |= MODE_DELETED;
1847
        }
1848

    
1849
    used_clusters_count = check_directory_consistency(s, 0, s->path);
1850
    if (used_clusters_count <= 0) {
1851
        DLOG(fprintf(stderr, "problem in directory\n"));
1852
        return 0;
1853
    }
1854

    
1855
    check = s->last_cluster_of_root_directory;
1856
    for (i = check; i < sector2cluster(s, s->sector_count); i++) {
1857
        if (modified_fat_get(s, i)) {
1858
            if(!s->used_clusters[i]) {
1859
                DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
1860
                return 0;
1861
            }
1862
            check++;
1863
        }
1864

    
1865
        if (s->used_clusters[i] == USED_ALLOCATED) {
1866
            /* allocated, but not used... */
1867
            DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
1868
            return 0;
1869
        }
1870
    }
1871

    
1872
    if (check != used_clusters_count)
1873
        return 0;
1874

    
1875
    return used_clusters_count;
1876
}
1877

    
1878
static inline void adjust_mapping_indices(BDRVVVFATState* s,
1879
        int offset, int adjust)
1880
{
1881
    int i;
1882

    
1883
    for (i = 0; i < s->mapping.next; i++) {
1884
        mapping_t* mapping = array_get(&(s->mapping), i);
1885

    
1886
#define ADJUST_MAPPING_INDEX(name) \
1887
        if (mapping->name >= offset) \
1888
            mapping->name += adjust
1889

    
1890
        ADJUST_MAPPING_INDEX(first_mapping_index);
1891
        if (mapping->mode & MODE_DIRECTORY)
1892
            ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
1893
    }
1894
}
1895

    
1896
/* insert or update mapping */
1897
static mapping_t* insert_mapping(BDRVVVFATState* s,
1898
        uint32_t begin, uint32_t end)
1899
{
1900
    /*
1901
     * - find mapping where mapping->begin >= begin,
1902
     * - if mapping->begin > begin: insert
1903
     *   - adjust all references to mappings!
1904
     * - else: adjust
1905
     * - replace name
1906
     */
1907
    int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
1908
    mapping_t* mapping = NULL;
1909
    mapping_t* first_mapping = array_get(&(s->mapping), 0);
1910

    
1911
    if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
1912
            && mapping->begin < begin) {
1913
        mapping->end = begin;
1914
        index++;
1915
        mapping = array_get(&(s->mapping), index);
1916
    }
1917
    if (index >= s->mapping.next || mapping->begin > begin) {
1918
        mapping = array_insert(&(s->mapping), index, 1);
1919
        mapping->path = NULL;
1920
        adjust_mapping_indices(s, index, +1);
1921
    }
1922

    
1923
    mapping->begin = begin;
1924
    mapping->end = end;
1925

    
1926
DLOG(mapping_t* next_mapping;
1927
assert(index + 1 >= s->mapping.next ||
1928
((next_mapping = array_get(&(s->mapping), index + 1)) &&
1929
 next_mapping->begin >= end)));
1930

    
1931
    if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1932
        s->current_mapping = array_get(&(s->mapping),
1933
                s->current_mapping - first_mapping);
1934

    
1935
    return mapping;
1936
}
1937

    
1938
static int remove_mapping(BDRVVVFATState* s, int mapping_index)
1939
{
1940
    mapping_t* mapping = array_get(&(s->mapping), mapping_index);
1941
    mapping_t* first_mapping = array_get(&(s->mapping), 0);
1942

    
1943
    /* free mapping */
1944
    if (mapping->first_mapping_index < 0)
1945
        free(mapping->path);
1946

    
1947
    /* remove from s->mapping */
1948
    array_remove(&(s->mapping), mapping_index);
1949

    
1950
    /* adjust all references to mappings */
1951
    adjust_mapping_indices(s, mapping_index, -1);
1952

    
1953
    if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1954
        s->current_mapping = array_get(&(s->mapping),
1955
                s->current_mapping - first_mapping);
1956

    
1957
    return 0;
1958
}
1959

    
1960
static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
1961
{
1962
    int i;
1963
    for (i = 0; i < s->mapping.next; i++) {
1964
        mapping_t* mapping = array_get(&(s->mapping), i);
1965
        if (mapping->dir_index >= offset)
1966
            mapping->dir_index += adjust;
1967
        if ((mapping->mode & MODE_DIRECTORY) &&
1968
                mapping->info.dir.first_dir_index >= offset)
1969
            mapping->info.dir.first_dir_index += adjust;
1970
    }
1971
}
1972

    
1973
static direntry_t* insert_direntries(BDRVVVFATState* s,
1974
        int dir_index, int count)
1975
{
1976
    /*
1977
     * make room in s->directory,
1978
     * adjust_dirindices
1979
     */
1980
    direntry_t* result = array_insert(&(s->directory), dir_index, count);
1981
    if (result == NULL)
1982
        return NULL;
1983
    adjust_dirindices(s, dir_index, count);
1984
    return result;
1985
}
1986

    
1987
static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
1988
{
1989
    int ret = array_remove_slice(&(s->directory), dir_index, count);
1990
    if (ret)
1991
        return ret;
1992
    adjust_dirindices(s, dir_index, -count);
1993
    return 0;
1994
}
1995

    
1996
/*
1997
 * Adapt the mappings of the cluster chain starting at first cluster
1998
 * (i.e. if a file starts at first_cluster, the chain is followed according
1999
 * to the modified fat, and the corresponding entries in s->mapping are
2000
 * adjusted)
2001
 */
2002
static int commit_mappings(BDRVVVFATState* s,
2003
        uint32_t first_cluster, int dir_index)
2004
{
2005
    mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2006
    direntry_t* direntry = array_get(&(s->directory), dir_index);
2007
    uint32_t cluster = first_cluster;
2008

    
2009
    vvfat_close_current_file(s);
2010

    
2011
    assert(mapping);
2012
    assert(mapping->begin == first_cluster);
2013
    mapping->first_mapping_index = -1;
2014
    mapping->dir_index = dir_index;
2015
    mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2016
        MODE_DIRECTORY : MODE_NORMAL;
2017

    
2018
    while (!fat_eof(s, cluster)) {
2019
        uint32_t c, c1;
2020

    
2021
        for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2022
                c = c1, c1 = modified_fat_get(s, c1));
2023

    
2024
        c++;
2025
        if (c > mapping->end) {
2026
            int index = array_index(&(s->mapping), mapping);
2027
            int i, max_i = s->mapping.next - index;
2028
            for (i = 1; i < max_i && mapping[i].begin < c; i++);
2029
            while (--i > 0)
2030
                remove_mapping(s, index + 1);
2031
        }
2032
        assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2033
                || mapping[1].begin >= c);
2034
        mapping->end = c;
2035

    
2036
        if (!fat_eof(s, c1)) {
2037
            int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2038
            mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2039
                array_get(&(s->mapping), i);
2040

    
2041
            if (next_mapping == NULL || next_mapping->begin > c1) {
2042
                int i1 = array_index(&(s->mapping), mapping);
2043

    
2044
                next_mapping = insert_mapping(s, c1, c1+1);
2045

    
2046
                if (c1 < c)
2047
                    i1++;
2048
                mapping = array_get(&(s->mapping), i1);
2049
            }
2050

    
2051
            next_mapping->dir_index = mapping->dir_index;
2052
            next_mapping->first_mapping_index =
2053
                mapping->first_mapping_index < 0 ?
2054
                array_index(&(s->mapping), mapping) :
2055
                mapping->first_mapping_index;
2056
            next_mapping->path = mapping->path;
2057
            next_mapping->mode = mapping->mode;
2058
            next_mapping->read_only = mapping->read_only;
2059
            if (mapping->mode & MODE_DIRECTORY) {
2060
                next_mapping->info.dir.parent_mapping_index =
2061
                        mapping->info.dir.parent_mapping_index;
2062
                next_mapping->info.dir.first_dir_index =
2063
                        mapping->info.dir.first_dir_index +
2064
                        0x10 * s->sectors_per_cluster *
2065
                        (mapping->end - mapping->begin);
2066
            } else
2067
                next_mapping->info.file.offset = mapping->info.file.offset +
2068
                        mapping->end - mapping->begin;
2069

    
2070
            mapping = next_mapping;
2071
        }
2072
        
2073
        cluster = c1;
2074
    }
2075

    
2076
    return 0;
2077
}
2078

    
2079
static int commit_direntries(BDRVVVFATState* s,
2080
        int dir_index, int parent_mapping_index)
2081
{
2082
    direntry_t* direntry = array_get(&(s->directory), dir_index);
2083
    uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
2084
    mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2085

    
2086
    int factor = 0x10 * s->sectors_per_cluster;
2087
    int old_cluster_count, new_cluster_count;
2088
    int current_dir_index = mapping->info.dir.first_dir_index;
2089
    int first_dir_index = current_dir_index;
2090
    int ret, i;
2091
    uint32_t c;
2092

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

    
2095
    assert(direntry);
2096
    assert(mapping);
2097
    assert(mapping->begin == first_cluster);
2098
    assert(mapping->info.dir.first_dir_index < s->directory.next);
2099
    assert(mapping->mode & MODE_DIRECTORY);
2100
    assert(dir_index == 0 || is_directory(direntry));
2101

    
2102
    mapping->info.dir.parent_mapping_index = parent_mapping_index;
2103

    
2104
    if (first_cluster == 0) {
2105
        old_cluster_count = new_cluster_count =
2106
            s->last_cluster_of_root_directory;
2107
    } else {
2108
        for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2109
                c = fat_get(s, c))
2110
            old_cluster_count++;
2111

    
2112
        for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2113
                c = modified_fat_get(s, c))
2114
            new_cluster_count++;
2115
    }
2116

    
2117
    if (new_cluster_count > old_cluster_count) {
2118
        if (insert_direntries(s,
2119
                current_dir_index + factor * old_cluster_count,
2120
                factor * (new_cluster_count - old_cluster_count)) == NULL)
2121
            return -1;
2122
    } else if (new_cluster_count < old_cluster_count)
2123
        remove_direntries(s,
2124
                current_dir_index + factor * new_cluster_count,
2125
                factor * (old_cluster_count - new_cluster_count));
2126

    
2127
    for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
2128
        void* direntry = array_get(&(s->directory), current_dir_index);
2129
        int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2130
                s->sectors_per_cluster);
2131
        if (ret)
2132
            return ret;
2133
        assert(!strncmp(s->directory.pointer, "QEMU", 4));
2134
        current_dir_index += factor;
2135
    }
2136

    
2137
    ret = commit_mappings(s, first_cluster, dir_index);
2138
    if (ret)
2139
        return ret;
2140

    
2141
    /* recurse */
2142
    for (i = 0; i < factor * new_cluster_count; i++) {
2143
        direntry = array_get(&(s->directory), first_dir_index + i);
2144
        if (is_directory(direntry) && !is_dot(direntry)) {
2145
            mapping = find_mapping_for_cluster(s, first_cluster);
2146
            assert(mapping->mode & MODE_DIRECTORY);
2147
            ret = commit_direntries(s, first_dir_index + i,
2148
                array_index(&(s->mapping), mapping));
2149
            if (ret)
2150
                return ret;
2151
        }
2152
    }
2153

    
2154
    return 0;
2155
}
2156

    
2157
/* commit one file (adjust contents, adjust mapping),
2158
   return first_mapping_index */
2159
static int commit_one_file(BDRVVVFATState* s,
2160
        int dir_index, uint32_t offset)
2161
{
2162
    direntry_t* direntry = array_get(&(s->directory), dir_index);
2163
    uint32_t c = begin_of_direntry(direntry);
2164
    uint32_t first_cluster = c;
2165
    mapping_t* mapping = find_mapping_for_cluster(s, c);
2166
    uint32_t size = filesize_of_direntry(direntry);
2167
    char* cluster = malloc(s->cluster_size);
2168
    uint32_t i;
2169
    int fd = 0;
2170

    
2171
    assert(offset < size);
2172
    assert((offset % s->cluster_size) == 0);
2173

    
2174
    for (i = s->cluster_size; i < offset; i += s->cluster_size)
2175
        c = modified_fat_get(s, c);
2176

    
2177
    fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
2178
    if (fd < 0) {
2179
        fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2180
                strerror(errno), errno);
2181
        return fd;
2182
    }
2183
    if (offset > 0)
2184
        if (lseek(fd, offset, SEEK_SET) != offset)
2185
            return -3;
2186

    
2187
    while (offset < size) {
2188
        uint32_t c1;
2189
        int rest_size = (size - offset > s->cluster_size ?
2190
                s->cluster_size : size - offset);
2191
        int ret;
2192

    
2193
        c1 = modified_fat_get(s, c);
2194

    
2195
        assert((size - offset == 0 && fat_eof(s, c)) ||
2196
                (size > offset && c >=2 && !fat_eof(s, c)));
2197
        assert(size >= 0);
2198

    
2199
        ret = vvfat_read(s->bs, cluster2sector(s, c),
2200
            cluster, (rest_size + 0x1ff) / 0x200);
2201

    
2202
        if (ret < 0)
2203
            return ret;
2204

    
2205
        if (write(fd, cluster, rest_size) < 0)
2206
            return -2;
2207

    
2208
        offset += rest_size;
2209
        c = c1;
2210
    }
2211

    
2212
    ftruncate(fd, size);
2213
    close(fd);
2214

    
2215
    return commit_mappings(s, first_cluster, dir_index);
2216
}
2217

    
2218
#ifdef DEBUG
2219
/* test, if all mappings point to valid direntries */
2220
static void check1(BDRVVVFATState* s)
2221
{
2222
    int i;
2223
    for (i = 0; i < s->mapping.next; i++) {
2224
        mapping_t* mapping = array_get(&(s->mapping), i);
2225
        if (mapping->mode & MODE_DELETED) {
2226
            fprintf(stderr, "deleted\n");
2227
            continue;
2228
        }
2229
        assert(mapping->dir_index >= 0);
2230
        assert(mapping->dir_index < s->directory.next);
2231
        direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2232
        assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2233
        if (mapping->mode & MODE_DIRECTORY) {
2234
            assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2235
            assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2236
        }
2237
    }
2238
}
2239

    
2240
/* test, if all direntries have mappings */
2241
static void check2(BDRVVVFATState* s)
2242
{
2243
    int i;
2244
    int first_mapping = -1;
2245

    
2246
    for (i = 0; i < s->directory.next; i++) {
2247
        direntry_t* direntry = array_get(&(s->directory), i);
2248

    
2249
        if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2250
            mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2251
            assert(mapping);
2252
            assert(mapping->dir_index == i || is_dot(direntry));
2253
            assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2254
        }
2255

    
2256
        if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2257
            /* cluster start */
2258
            int j, count = 0;
2259

    
2260
            for (j = 0; j < s->mapping.next; j++) {
2261
                mapping_t* mapping = array_get(&(s->mapping), j);
2262
                if (mapping->mode & MODE_DELETED)
2263
                    continue;
2264
                if (mapping->mode & MODE_DIRECTORY) {
2265
                    if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2266
                        assert(++count == 1);
2267
                        if (mapping->first_mapping_index == -1)
2268
                            first_mapping = array_index(&(s->mapping), mapping);
2269
                        else
2270
                            assert(first_mapping == mapping->first_mapping_index);
2271
                        if (mapping->info.dir.parent_mapping_index < 0)
2272
                            assert(j == 0);
2273
                        else {
2274
                            mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2275
                            assert(parent->mode & MODE_DIRECTORY);
2276
                            assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2277
                        }
2278
                    }
2279
                }
2280
            }
2281
            if (count == 0)
2282
                first_mapping = -1;
2283
        }
2284
    }
2285
}
2286
#endif
2287

    
2288
static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2289
{
2290
    int i;
2291

    
2292
#ifdef DEBUG
2293
    fprintf(stderr, "handle_renames\n");
2294
    for (i = 0; i < s->commits.next; i++) {
2295
        commit_t* commit = array_get(&(s->commits), i);
2296
        fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
2297
    }
2298
#endif
2299

    
2300
    for (i = 0; i < s->commits.next;) {
2301
        commit_t* commit = array_get(&(s->commits), i);
2302
        if (commit->action == ACTION_RENAME) {
2303
            mapping_t* mapping = find_mapping_for_cluster(s,
2304
                    commit->param.rename.cluster);
2305
            char* old_path = mapping->path;
2306

    
2307
            assert(commit->path);
2308
            mapping->path = commit->path;
2309
            if (rename(old_path, mapping->path))
2310
                return -2;
2311

    
2312
            if (mapping->mode & MODE_DIRECTORY) {
2313
                int l1 = strlen(mapping->path);
2314
                int l2 = strlen(old_path);
2315
                int diff = l1 - l2;
2316
                direntry_t* direntry = array_get(&(s->directory),
2317
                        mapping->info.dir.first_dir_index);
2318
                uint32_t c = mapping->begin;
2319
                int i = 0;
2320

    
2321
                /* recurse */
2322
                while (!fat_eof(s, c)) {
2323
                    do {
2324
                        direntry_t* d = direntry + i;
2325

    
2326
                        if (is_file(d) || (is_directory(d) && !is_dot(d))) {
2327
                            mapping_t* m = find_mapping_for_cluster(s,
2328
                                    begin_of_direntry(d));
2329
                            int l = strlen(m->path);
2330
                            char* new_path = malloc(l + diff + 1);
2331

    
2332
                            assert(!strncmp(m->path, mapping->path, l2));
2333

    
2334
                            strcpy(new_path, mapping->path);
2335
                            strcpy(new_path + l1, m->path + l2);
2336

    
2337
                            schedule_rename(s, m->begin, new_path);
2338
                        }
2339
                        i++;
2340
                    } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2341
                    c = fat_get(s, c);
2342
                }
2343
            }
2344

    
2345
            free(old_path);
2346
            array_remove(&(s->commits), i);
2347
            continue;
2348
        } else if (commit->action == ACTION_MKDIR) {
2349
            mapping_t* mapping;
2350
            int j, parent_path_len;
2351

    
2352
#ifdef __MINGW32__
2353
            if (mkdir(commit->path))
2354
                return -5;
2355
#else
2356
            if (mkdir(commit->path, 0755))
2357
                return -5;
2358
#endif
2359

    
2360
            mapping = insert_mapping(s, commit->param.mkdir.cluster,
2361
                    commit->param.mkdir.cluster + 1);
2362
            if (mapping == NULL)
2363
                return -6;
2364

    
2365
            mapping->mode = MODE_DIRECTORY;
2366
            mapping->read_only = 0;
2367
            mapping->path = commit->path;
2368
            j = s->directory.next;
2369
            assert(j);
2370
            insert_direntries(s, s->directory.next,
2371
                    0x10 * s->sectors_per_cluster);
2372
            mapping->info.dir.first_dir_index = j;
2373

    
2374
            parent_path_len = strlen(commit->path)
2375
                - strlen(get_basename(commit->path)) - 1;
2376
            for (j = 0; j < s->mapping.next; j++) {
2377
                mapping_t* m = array_get(&(s->mapping), j);
2378
                if (m->first_mapping_index < 0 && m != mapping &&
2379
                        !strncmp(m->path, mapping->path, parent_path_len) &&
2380
                        strlen(m->path) == parent_path_len)
2381
                    break;
2382
            }
2383
            assert(j < s->mapping.next);
2384
            mapping->info.dir.parent_mapping_index = j;
2385

    
2386
            array_remove(&(s->commits), i);
2387
            continue;
2388
        }
2389

    
2390
        i++;
2391
    }
2392
    return 0;
2393
}
2394

    
2395
/*
2396
 * TODO: make sure that the short name is not matching *another* file
2397
 */
2398
static int handle_commits(BDRVVVFATState* s)
2399
{
2400
    int i, fail = 0;
2401

    
2402
    vvfat_close_current_file(s);
2403

    
2404
    for (i = 0; !fail && i < s->commits.next; i++) {
2405
        commit_t* commit = array_get(&(s->commits), i);
2406
        switch(commit->action) {
2407
        case ACTION_RENAME: case ACTION_MKDIR:
2408
            assert(0);
2409
            fail = -2;
2410
            break;
2411
        case ACTION_WRITEOUT: {
2412
            direntry_t* entry = array_get(&(s->directory),
2413
                    commit->param.writeout.dir_index);
2414
            uint32_t begin = begin_of_direntry(entry);
2415
            mapping_t* mapping = find_mapping_for_cluster(s, begin);
2416

    
2417
            assert(mapping);
2418
            assert(mapping->begin == begin);
2419
            assert(commit->path == NULL);
2420

    
2421
            if (commit_one_file(s, commit->param.writeout.dir_index,
2422
                        commit->param.writeout.modified_offset))
2423
                fail = -3;
2424

    
2425
            break;
2426
        }
2427
        case ACTION_NEW_FILE: {
2428
            int begin = commit->param.new_file.first_cluster;
2429
            mapping_t* mapping = find_mapping_for_cluster(s, begin);
2430
            direntry_t* entry;
2431
            int i;
2432

    
2433
            /* find direntry */
2434
            for (i = 0; i < s->directory.next; i++) {
2435
                entry = array_get(&(s->directory), i);
2436
                if (is_file(entry) && begin_of_direntry(entry) == begin)
2437
                    break;
2438
            }
2439

    
2440
            if (i >= s->directory.next) {
2441
                fail = -6;
2442
                continue;
2443
            }
2444

    
2445
            /* make sure there exists an initial mapping */
2446
            if (mapping && mapping->begin != begin) {
2447
                mapping->end = begin;
2448
                mapping = NULL;
2449
            }
2450
            if (mapping == NULL) {
2451
                mapping = insert_mapping(s, begin, begin+1);
2452
            }
2453
            /* most members will be fixed in commit_mappings() */
2454
            assert(commit->path);
2455
            mapping->path = commit->path;
2456
            mapping->read_only = 0;
2457
            mapping->mode = MODE_NORMAL;
2458
            mapping->info.file.offset = 0;
2459

    
2460
            if (commit_one_file(s, i, 0))
2461
                fail = -7;
2462

    
2463
            break;
2464
        }
2465
        default:
2466
            assert(0);
2467
        }
2468
    }
2469
    if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2470
        return -1;
2471
    return fail;
2472
}
2473

    
2474
static int handle_deletes(BDRVVVFATState* s)
2475
{
2476
    int i, deferred = 1, deleted = 1;
2477

    
2478
    /* delete files corresponding to mappings marked as deleted */
2479
    /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2480
    while (deferred && deleted) {
2481
        deferred = 0;
2482
        deleted = 0;
2483

    
2484
        for (i = 1; i < s->mapping.next; i++) {
2485
            mapping_t* mapping = array_get(&(s->mapping), i);
2486
            if (mapping->mode & MODE_DELETED) {
2487
                direntry_t* entry = array_get(&(s->directory),
2488
                        mapping->dir_index);
2489

    
2490
                if (is_free(entry)) {
2491
                    /* remove file/directory */
2492
                    if (mapping->mode & MODE_DIRECTORY) {
2493
                        int j, next_dir_index = s->directory.next,
2494
                        first_dir_index = mapping->info.dir.first_dir_index;
2495

    
2496
                        if (rmdir(mapping->path) < 0) {
2497
                            if (errno == ENOTEMPTY) {
2498
                                deferred++;
2499
                                continue;
2500
                            } else
2501
                                return -5;
2502
                        }
2503

    
2504
                        for (j = 1; j < s->mapping.next; j++) {
2505
                            mapping_t* m = array_get(&(s->mapping), j);
2506
                            if (m->mode & MODE_DIRECTORY &&
2507
                                    m->info.dir.first_dir_index >
2508
                                    first_dir_index &&
2509
                                    m->info.dir.first_dir_index <
2510
                                    next_dir_index)
2511
                                next_dir_index =
2512
                                    m->info.dir.first_dir_index;
2513
                        }
2514
                        remove_direntries(s, first_dir_index,
2515
                                next_dir_index - first_dir_index);
2516

    
2517
                        deleted++;
2518
                    }
2519
                } else {
2520
                    if (unlink(mapping->path))
2521
                        return -4;
2522
                    deleted++;
2523
                }
2524
                DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2525
                remove_mapping(s, i);
2526
            }
2527
        }
2528
    }
2529

    
2530
    return 0;
2531
}
2532

    
2533
/*
2534
 * synchronize mapping with new state:
2535
 *
2536
 * - copy FAT (with bdrv_read)
2537
 * - mark all filenames corresponding to mappings as deleted
2538
 * - recurse direntries from root (using bs->bdrv_read)
2539
 * - delete files corresponding to mappings marked as deleted
2540
 */
2541
static int do_commit(BDRVVVFATState* s)
2542
{
2543
    int ret = 0;
2544

    
2545
    /* the real meat are the commits. Nothing to do? Move along! */
2546
    if (s->commits.next == 0)
2547
        return 0;
2548

    
2549
    vvfat_close_current_file(s);
2550

    
2551
    ret = handle_renames_and_mkdirs(s);
2552
    if (ret) {
2553
        fprintf(stderr, "Error handling renames (%d)\n", ret);
2554
        assert(0);
2555
        return ret;
2556
    }
2557

    
2558
    /* copy FAT (with bdrv_read) */
2559
    memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2560

    
2561
    /* recurse direntries from root (using bs->bdrv_read) */
2562
    ret = commit_direntries(s, 0, -1);
2563
    if (ret) {
2564
        fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
2565
        assert(0);
2566
        return ret;
2567
    }
2568

    
2569
    ret = handle_commits(s);
2570
    if (ret) {
2571
        fprintf(stderr, "Error handling commits (%d)\n", ret);
2572
        assert(0);
2573
        return ret;
2574
    }
2575

    
2576
    ret = handle_deletes(s);
2577
    if (ret) {
2578
        fprintf(stderr, "Error deleting\n");
2579
        assert(0);
2580
        return ret;
2581
    }
2582

    
2583
    s->qcow->drv->bdrv_make_empty(s->qcow);
2584

    
2585
    memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2586

    
2587
DLOG(checkpoint());
2588
    return 0;
2589
}
2590

    
2591
static int try_commit(BDRVVVFATState* s)
2592
{
2593
    vvfat_close_current_file(s);
2594
DLOG(checkpoint());
2595
    if(!is_consistent(s))
2596
        return -1;
2597
    return do_commit(s);
2598
}
2599

    
2600
static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
2601
                    const uint8_t *buf, int nb_sectors)
2602
{
2603
    BDRVVVFATState *s = bs->opaque;
2604
    int i, ret;
2605

    
2606
DLOG(checkpoint());
2607

    
2608
    vvfat_close_current_file(s);
2609

    
2610
    /*
2611
     * Some sanity checks:
2612
     * - do not allow writing to the boot sector
2613
     * - do not allow to write non-ASCII filenames
2614
     */
2615

    
2616
    if (sector_num < s->first_sectors_number)
2617
        return -1;
2618

    
2619
    for (i = sector2cluster(s, sector_num);
2620
            i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
2621
        mapping_t* mapping = find_mapping_for_cluster(s, i);
2622
        if (mapping) {
2623
            if (mapping->read_only) {
2624
                fprintf(stderr, "Tried to write to write-protected file %s\n",
2625
                        mapping->path);
2626
                return -1;
2627
            }
2628

    
2629
            if (mapping->mode & MODE_DIRECTORY) {
2630
                int begin = cluster2sector(s, i);
2631
                int end = begin + s->sectors_per_cluster, k;
2632
                int dir_index;
2633
                const direntry_t* direntries;
2634
                long_file_name lfn;
2635

    
2636
                lfn_init(&lfn);
2637

    
2638
                if (begin < sector_num)
2639
                    begin = sector_num;
2640
                if (end > sector_num + nb_sectors)
2641
                    end = sector_num + nb_sectors;
2642
                dir_index  = mapping->dir_index +
2643
                    0x10 * (begin - mapping->begin * s->sectors_per_cluster);
2644
                direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
2645

    
2646
                for (k = 0; k < (end - begin) * 0x10; k++) {
2647
                    /* do not allow non-ASCII filenames */
2648
                    if (parse_long_name(&lfn, direntries + k) < 0) {
2649
                        fprintf(stderr, "Warning: non-ASCII filename\n");
2650
                        return -1;
2651
                    }
2652
                    /* no access to the direntry of a read-only file */
2653
                    else if (is_short_name(direntries+k) &&
2654
                            (direntries[k].attributes & 1)) {
2655
                        if (memcmp(direntries + k,
2656
                                    array_get(&(s->directory), dir_index + k),
2657
                                    sizeof(direntry_t))) {
2658
                            fprintf(stderr, "Warning: tried to write to write-protected file\n");
2659
                            return -1;
2660
                        }
2661
                    }
2662
                }
2663
            }
2664
            i = mapping->end;
2665
        } else
2666
            i++;
2667
    }
2668

    
2669
    /*
2670
     * Use qcow backend. Commit later.
2671
     */
2672
DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
2673
    ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
2674
    if (ret < 0) {
2675
        fprintf(stderr, "Error writing to qcow backend\n");
2676
        return ret;
2677
    }
2678

    
2679
    for (i = sector2cluster(s, sector_num);
2680
            i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
2681
        if (i >= 0)
2682
            s->used_clusters[i] |= USED_ALLOCATED;
2683

    
2684
DLOG(checkpoint());
2685
    /* TODO: add timeout */
2686
    try_commit(s);
2687

    
2688
DLOG(checkpoint());
2689
    return 0;
2690
}
2691

    
2692
static int vvfat_is_allocated(BlockDriverState *bs,
2693
        int64_t sector_num, int nb_sectors, int* n)
2694
{
2695
    BDRVVVFATState* s = bs->opaque;
2696
    *n = s->sector_count - sector_num;
2697
    if (*n > nb_sectors)
2698
        *n = nb_sectors;
2699
    else if (*n < 0)
2700
        return 0;
2701
    return 1;
2702
}
2703

    
2704
static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
2705
        const uint8_t* buffer, int nb_sectors) {
2706
    BDRVVVFATState* s = bs->opaque;
2707
    return try_commit(s);
2708
}
2709

    
2710
static void write_target_close(BlockDriverState *bs) {
2711
    BDRVVVFATState* s = bs->opaque;
2712
    bdrv_delete(s->qcow);
2713
    free(s->qcow_filename);
2714
}
2715

    
2716
static BlockDriver vvfat_write_target = {
2717
    "vvfat_write_target", 0, NULL, NULL, NULL,
2718
    write_target_commit,
2719
    write_target_close,
2720
    NULL, NULL, NULL
2721
};
2722

    
2723
static int enable_write_target(BDRVVVFATState *s)
2724
{
2725
    int size = sector2cluster(s, s->sector_count);
2726
    s->used_clusters = calloc(size, 1);
2727

    
2728
    array_init(&(s->commits), sizeof(commit_t));
2729

    
2730
    s->qcow_filename = malloc(1024);
2731
    get_tmp_filename(s->qcow_filename, 1024);
2732
    if (bdrv_create(&bdrv_qcow,
2733
                s->qcow_filename, s->sector_count, "fat:", 0) < 0)
2734
        return -1;
2735
    s->qcow = bdrv_new("");
2736
    if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
2737
        return -1;
2738

    
2739
#ifndef _WIN32
2740
    unlink(s->qcow_filename);
2741
#endif
2742

    
2743
    s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
2744
    s->bs->backing_hd->drv = &vvfat_write_target;
2745
    s->bs->backing_hd->opaque = s;
2746

    
2747
    return 0;
2748
}
2749

    
2750
static void vvfat_close(BlockDriverState *bs)
2751
{
2752
    BDRVVVFATState *s = bs->opaque;
2753

    
2754
    vvfat_close_current_file(s);
2755
    array_free(&(s->fat));
2756
    array_free(&(s->directory));
2757
    array_free(&(s->mapping));
2758
    if(s->cluster_buffer)
2759
        free(s->cluster_buffer);
2760
}
2761

    
2762
BlockDriver bdrv_vvfat = {
2763
    "vvfat",
2764
    sizeof(BDRVVVFATState),
2765
    NULL, /* no probe for protocols */
2766
    vvfat_open,
2767
    vvfat_read,
2768
    vvfat_write,
2769
    vvfat_close,
2770
    NULL, /* ??? Not sure if we can do any meaningful flushing.  */
2771
    NULL,
2772
    vvfat_is_allocated,
2773
    .protocol_name = "fat",
2774
};
2775

    
2776
#ifdef DEBUG
2777
static void checkpoint() {
2778
    assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
2779
    check1(vvv);
2780
    check2(vvv);
2781
    assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
2782
#if 0
2783
    if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
2784
        fprintf(stderr, "Nonono!\n");
2785
    mapping_t* mapping;
2786
    direntry_t* direntry;
2787
    assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
2788
    assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
2789
    if (vvv->mapping.next<47)
2790
        return;
2791
    assert((mapping = array_get(&(vvv->mapping), 47)));
2792
    assert(mapping->dir_index < vvv->directory.next);
2793
    direntry = array_get(&(vvv->directory), mapping->dir_index);
2794
    assert(!memcmp(direntry->name, "USB     H  ", 11) || direntry->name[0]==0);
2795
#endif
2796
    return;
2797
    /* avoid compiler warnings: */
2798
    hexdump(NULL, 100);
2799
    remove_mapping(vvv, NULL);
2800
    print_mapping(NULL);
2801
    print_direntry(NULL);
2802
}
2803
#endif
2804