Statistics
| Branch: | Revision:

root / block-vvfat.c @ da2414e9

History | View | Annotate | Download (77.7 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) if (!(a)) nonono(__FILE__, __LINE__, #a)
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 int vvfat_probe(const uint8_t *buf, int buf_size, const char *filename)
355
{
356
    if (strstart(filename, "fat:", NULL))
357
        return 100;
358
    return 0;
359
}
360

    
361
static void init_mbr(BDRVVVFATState* s)
362
{
363
    /* TODO: if the files mbr.img and bootsect.img exist, use them */
364
    mbr_t* real_mbr=(mbr_t*)s->first_sectors;
365
    partition_t* partition=&(real_mbr->partition[0]);
366

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

    
381
    real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
382
}
383

    
384
/* direntry functions */
385

    
386
/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
387
static inline int short2long_name(unsigned char* dest,const char* src)
388
{
389
    int i;
390
    for(i=0;i<129 && src[i];i++) {
391
        dest[2*i]=src[i];
392
        dest[2*i+1]=0;
393
    }
394
    dest[2*i]=dest[2*i+1]=0;
395
    for(i=2*i+2;(i%26);i++)
396
        dest[i]=0xff;
397
    return i;
398
}
399

    
400
static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
401
{
402
    char buffer[258];
403
    int length=short2long_name(buffer,filename),
404
        number_of_entries=(length+25)/26,i;
405
    direntry_t* entry;
406

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

    
425
static char is_free(const direntry_t* direntry)
426
{
427
    /* return direntry->name[0]==0 ; */
428
    return direntry->attributes == 0 || direntry->name[0]==0xe5;
429
}
430

    
431
static char is_volume_label(const direntry_t* direntry)
432
{
433
    return direntry->attributes == 0x28;
434
}
435

    
436
static char is_long_name(const direntry_t* direntry)
437
{
438
    return direntry->attributes == 0xf;
439
}
440

    
441
static char is_short_name(const direntry_t* direntry)
442
{
443
    return !is_volume_label(direntry) && !is_long_name(direntry)
444
        && !is_free(direntry);
445
}
446

    
447
static char is_directory(const direntry_t* direntry)
448
{
449
    return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
450
}
451

    
452
static inline char is_dot(const direntry_t* direntry)
453
{
454
    return is_short_name(direntry) && direntry->name[0] == '.';
455
}
456

    
457
static char is_file(const direntry_t* direntry)
458
{
459
    return is_short_name(direntry) && !is_directory(direntry);
460
}
461

    
462
static inline uint32_t begin_of_direntry(const direntry_t* direntry)
463
{
464
    return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
465
}
466

    
467
static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
468
{
469
    return le32_to_cpu(direntry->size);
470
}
471

    
472
static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
473
{
474
    direntry->begin = cpu_to_le16(begin & 0xffff);
475
    direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
476
}
477

    
478
/* fat functions */
479

    
480
static inline uint8_t fat_chksum(const direntry_t* entry)
481
{
482
    uint8_t chksum=0;
483
    int i;
484

    
485
    for(i=0;i<11;i++)
486
        chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0))
487
            +(unsigned char)entry->name[i];
488
    
489
    return chksum;
490
}
491

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

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

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

    
545
static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
546
{
547
    if(fat_entry>s->max_fat_value-8)
548
        return -1;
549
    return 0;
550
}
551

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

    
572
}
573

    
574
/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
575
/* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
576
static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
577
        unsigned int directory_start, const char* filename, int is_dot)
578
{
579
    int i,j,long_index=s->directory.next;
580
    direntry_t* entry=0;
581
    direntry_t* entry_long=0;
582

    
583
    if(is_dot) {
584
        entry=array_get_next(&(s->directory));
585
        memset(entry->name,0x20,11);
586
        memcpy(entry->name,filename,strlen(filename));
587
        return entry;
588
    }
589
    
590
    entry_long=create_long_filename(s,filename);
591
  
592
    i = strlen(filename); 
593
    for(j = i - 1; j>0  && filename[j]!='.';j--);
594
    if (j > 0)
595
        i = (j > 8 ? 8 : j);
596
    else if (i > 8)
597
        i = 8;
598

    
599
    entry=array_get_next(&(s->directory));
600
    memset(entry->name,0x20,11);
601
    strncpy(entry->name,filename,i);
602
    
603
    if(j > 0)
604
        for (i = 0; i < 3 && filename[j+1+i]; i++)
605
            entry->extension[i] = filename[j+1+i];
606

    
607
    /* upcase & remove unwanted characters */
608
    for(i=10;i>=0;i--) {
609
        if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
610
        if(entry->name[i]<=' ' || entry->name[i]>0x7f
611
                || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
612
            entry->name[i]='_';
613
        else if(entry->name[i]>='a' && entry->name[i]<='z')
614
            entry->name[i]+='A'-'a';
615
    }
616

    
617
    /* mangle duplicates */
618
    while(1) {
619
        direntry_t* entry1=array_get(&(s->directory),directory_start);
620
        int j;
621

    
622
        for(;entry1<entry;entry1++)
623
            if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
624
                break; /* found dupe */
625
        if(entry1==entry) /* no dupe found */
626
            break;
627

    
628
        /* use all 8 characters of name */        
629
        if(entry->name[7]==' ') {
630
            int j;
631
            for(j=6;j>0 && entry->name[j]==' ';j--)
632
                entry->name[j]='~';
633
        }
634

    
635
        /* increment number */
636
        for(j=7;j>0 && entry->name[j]=='9';j--)
637
            entry->name[j]='0';
638
        if(j>0) {
639
            if(entry->name[j]<'0' || entry->name[j]>'9')
640
                entry->name[j]='0';
641
            else
642
                entry->name[j]++;
643
        }
644
    }
645

    
646
    /* calculate checksum; propagate to long name */
647
    if(entry_long) {
648
        uint8_t chksum=fat_chksum(entry);
649

    
650
        /* calculate anew, because realloc could have taken place */
651
        entry_long=array_get(&(s->directory),long_index);
652
        while(entry_long<entry && is_long_name(entry_long)) {
653
            entry_long->reserved[1]=chksum;
654
            entry_long++;
655
        }
656
    }
657

    
658
    return entry;
659
}
660

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

    
675
    DIR* dir=opendir(dirname);
676
    struct dirent* entry;
677
    int i;
678

    
679
    assert(mapping->mode & MODE_DIRECTORY);
680

    
681
    if(!dir) {
682
        mapping->end = mapping->begin;
683
        return -1;
684
    }
685
   
686
    i = mapping->info.dir.first_dir_index =
687
            first_cluster == 0 ? 0 : s->directory.next;
688

    
689
    /* actually read the directory, and allocate the mappings */ 
690
    while((entry=readdir(dir))) {
691
        unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
692
        char* buffer;
693
        direntry_t* direntry;
694
        struct stat st;
695
        int is_dot=!strcmp(entry->d_name,".");
696
        int is_dotdot=!strcmp(entry->d_name,"..");
697

    
698
        if(first_cluster == 0 && (is_dotdot || is_dot))
699
            continue;
700
        
701
        buffer=(char*)malloc(length);
702
        assert(buffer);
703
        snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
704

    
705
        if(stat(buffer,&st)<0) {
706
            free(buffer);
707
            continue;
708
        }
709

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

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

    
760
    /* fill with zeroes up to the end of the cluster */
761
    while(s->directory.next%(0x10*s->sectors_per_cluster)) {
762
        direntry_t* direntry=array_get_next(&(s->directory));
763
        memset(direntry,0,sizeof(direntry_t));
764
    }
765

    
766
/* TODO: if there are more entries, bootsector has to be adjusted! */
767
#define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
768
    if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
769
        /* root directory */
770
        int cur = s->directory.next;
771
        array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
772
        memset(array_get(&(s->directory), cur), 0,
773
                (ROOT_ENTRIES - cur) * sizeof(direntry_t));
774
    }
775
        
776
     /* reget the mapping, since s->mapping was possibly realloc()ed */
777
    mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
778
    first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
779
        * 0x20 / s->cluster_size;
780
    mapping->end = first_cluster;
781

    
782
    direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
783
    set_begin_of_direntry(direntry, mapping->begin);
784
   
785
    return 0;
786
}
787

    
788
static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
789
{
790
    return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
791
}
792

    
793
static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
794
{
795
    return s->faked_sectors + s->sectors_per_cluster * cluster_num;
796
}
797

    
798
static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
799
{
800
    return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
801
}
802

    
803
#ifdef DBG
804
static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
805
{
806
    if(mapping->mode==MODE_UNDEFINED)
807
        return 0;
808
    return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
809
}
810
#endif
811

    
812
static int init_directories(BDRVVVFATState* s,
813
        const char* dirname)
814
{
815
    bootsector_t* bootsector;
816
    mapping_t* mapping;
817
    unsigned int i;
818
    unsigned int cluster;
819

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

    
822
    s->cluster_size=s->sectors_per_cluster*0x200;
823
    s->cluster_buffer=malloc(s->cluster_size);
824
    assert(s->cluster_buffer);
825

    
826
    /*
827
     * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
828
     * where sc is sector_count,
829
     * spf is sectors_per_fat,
830
     * spc is sectors_per_clusters, and
831
     * fat_type = 12, 16 or 32.
832
     */
833
    i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
834
    s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
835
    
836
    array_init(&(s->mapping),sizeof(mapping_t));
837
    array_init(&(s->directory),sizeof(direntry_t));
838

    
839
    /* add volume label */
840
    {
841
        direntry_t* entry=array_get_next(&(s->directory));
842
        entry->attributes=0x28; /* archive | volume label */
843
        snprintf(entry->name,11,"QEMU VVFAT");
844
    }
845

    
846
    /* Now build FAT, and write back information into directory */
847
    init_fat(s);
848

    
849
    s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
850
    s->cluster_count=sector2cluster(s, s->sector_count);
851

    
852
    mapping = array_get_next(&(s->mapping));
853
    mapping->begin = 0;
854
    mapping->dir_index = 0;
855
    mapping->info.dir.parent_mapping_index = -1;
856
    mapping->first_mapping_index = -1;
857
    mapping->path = strdup(dirname);
858
    i = strlen(mapping->path);
859
    if (i > 0 && mapping->path[i - 1] == '/')
860
        mapping->path[i - 1] = '\0';
861
    mapping->mode = MODE_DIRECTORY;
862
    mapping->read_only = 0;
863
    s->path = mapping->path;
864

    
865
    for (i = 0, cluster = 0; i < s->mapping.next; i++) {
866
        int j;
867
        /* MS-DOS expects the FAT to be 0 for the root directory 
868
         * (except for the media byte). */
869
        /* LATER TODO: still true for FAT32? */
870
        int fix_fat = (i != 0);
871
        mapping = array_get(&(s->mapping), i);
872

    
873
        if (mapping->mode & MODE_DIRECTORY) {
874
            mapping->begin = cluster;
875
            if(read_directory(s, i)) {
876
                fprintf(stderr, "Could not read directory %s\n",
877
                        mapping->path);
878
                return -1;
879
            }
880
            mapping = array_get(&(s->mapping), i);
881
        } else {
882
            assert(mapping->mode == MODE_UNDEFINED);
883
            mapping->mode=MODE_NORMAL;
884
            mapping->begin = cluster;
885
            if (mapping->end > 0) {
886
                direntry_t* direntry = array_get(&(s->directory),
887
                        mapping->dir_index);
888

    
889
                mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
890
                set_begin_of_direntry(direntry, mapping->begin);
891
            } else {
892
                mapping->end = cluster + 1;
893
                fix_fat = 0;
894
            }
895
        }
896

    
897
        assert(mapping->begin < mapping->end);
898

    
899
        /* fix fat for entry */
900
        if (fix_fat) {
901
            for(j = mapping->begin; j < mapping->end - 1; j++)
902
                fat_set(s, j, j+1);
903
            fat_set(s, mapping->end - 1, s->max_fat_value);
904
        }
905

    
906
        /* next free cluster */
907
        cluster = mapping->end;
908

    
909
        if(cluster > s->cluster_count) {
910
            fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type);
911
            return -1;
912
        }
913
    }
914

    
915
    mapping = array_get(&(s->mapping), 0);
916
    s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
917
    s->last_cluster_of_root_directory = mapping->end;
918

    
919
    /* the FAT signature */
920
    fat_set(s,0,s->max_fat_value);
921
    fat_set(s,1,s->max_fat_value);
922

    
923
    s->current_mapping = NULL;
924

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

    
944
    /* LATER TODO: if FAT32, this is wrong */
945
    bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
946
    bootsector->u.fat16.current_head=0;
947
    bootsector->u.fat16.signature=0x29;
948
    bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
949

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

    
954
    return 0;
955
}
956

    
957
static BDRVVVFATState *vvv = NULL;
958

    
959
static int enable_write_target(BDRVVVFATState *s);
960
static int is_consistent(BDRVVVFATState *s);
961

    
962
static int vvfat_open(BlockDriverState *bs, const char* dirname)
963
{
964
    BDRVVVFATState *s = bs->opaque;
965
    int floppy = 0;
966
    int i;
967

    
968
    vvv = s;
969

    
970
DLOG(if (stderr == NULL) {
971
    stderr = fopen("vvfat.log", "a");
972
    setbuf(stderr, NULL);
973
})
974

    
975
    s->bs = bs;
976

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

    
984
    s->current_cluster=0xffffffff;
985

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

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

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

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

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

    
1029
    bs->total_sectors=bs->cyls*bs->heads*bs->secs;
1030
    if (s->sector_count > bs->total_sectors)
1031
        s->sector_count = bs->total_sectors;
1032
    if(init_directories(s, dirname))
1033
        return -1;
1034

    
1035
    if(s->first_sectors_number==0x40)
1036
        init_mbr(s);
1037

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

    
1042
    //    assert(is_consistent(s));
1043

    
1044
    return 0;
1045
}
1046

    
1047
static inline void vvfat_close_current_file(BDRVVVFATState *s)
1048
{
1049
    if(s->current_mapping) {
1050
        s->current_mapping = NULL;
1051
        if (s->current_fd) {
1052
                close(s->current_fd);
1053
                s->current_fd = 0;
1054
        }
1055
    }
1056
    s->current_cluster = -1;
1057
}
1058

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

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

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

    
1111
    for (i = 0; i < s->mapping.next; i++) {
1112
        mapping_t* mapping = array_get(&(s->mapping), i);
1113
        if (mapping->first_mapping_index < 0 &&
1114
                !strcmp(path, mapping->path))
1115
            return mapping;
1116
    }
1117

    
1118
    return NULL;
1119
}
1120

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

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

    
1150
            assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1151

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

    
1165
            if(open_file(s,mapping))
1166
                return -2;
1167
        } else if (s->current_mapping->mode & MODE_DIRECTORY)
1168
            goto read_cluster_directory;
1169

    
1170
        assert(s->current_fd);
1171

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

    
1186
#ifdef DEBUG
1187
static void hexdump(const void* address, uint32_t len)
1188
{
1189
    const unsigned char* p = address;
1190
    int i, j;
1191

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

    
1204
static void print_direntry(const direntry_t* direntry)
1205
{
1206
    int j = 0;
1207
    char buffer[1024];
1208

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

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

    
1246
static int vvfat_read(BlockDriverState *bs, int64_t sector_num, 
1247
                    uint8_t *buf, int nb_sectors)
1248
{
1249
    BDRVVVFATState *s = bs->opaque;
1250
    int i;
1251

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

    
1290
/* LATER TODO: statify all functions */
1291

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

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

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

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

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

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

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

    
1378
typedef struct {
1379
    unsigned char name[1024];
1380
    int checksum, len;
1381
    int sequence_number;
1382
} long_file_name;
1383

    
1384
static void lfn_init(long_file_name* lfn)
1385
{
1386
   lfn->sequence_number = lfn->len = 0;
1387
   lfn->checksum = 0x100;
1388
}
1389

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

    
1397
    if (!is_long_name(direntry))
1398
        return 1;
1399

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

    
1411
    offset = 13 * (lfn->sequence_number - 1);
1412
    for (i = 0, j = 1; i < 13; i++, j+=2) {
1413
        if (j == 11)
1414
            j = 14;
1415
        else if (j == 26)
1416
            j = 28;
1417

    
1418
        if (pointer[j+1] == 0)
1419
            lfn->name[offset + i] = pointer[j];
1420
        else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1421
            return -4;
1422
        else
1423
            lfn->name[offset + i] = 0;
1424
    }
1425

    
1426
    if (pointer[0] & 0x40)
1427
        lfn->len = offset + strlen(lfn->name + offset);
1428

    
1429
    return 0;
1430
}
1431

    
1432
/* returns 0 if successful, >0 if no short_name, and <0 on error */
1433
static int parse_short_name(BDRVVVFATState* s,
1434
        long_file_name* lfn, direntry_t* direntry)
1435
{
1436
    int i, j;
1437

    
1438
    if (!is_short_name(direntry))
1439
        return 1;
1440

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

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

    
1466
    lfn->len = strlen(lfn->name);
1467

    
1468
    return 0;
1469
}
1470

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

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

    
1493
static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1494
{
1495
    int was_modified = 0;
1496
    int i, dummy;
1497

    
1498
    if (s->qcow == NULL)
1499
        return 0;
1500

    
1501
    for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
1502
        was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
1503
                cluster2sector(s, cluster_num) + i, 1, &dummy);
1504

    
1505
    return was_modified;
1506
}
1507

    
1508
static const char* get_basename(const char* path)
1509
{
1510
    char* basename = strrchr(path, '/');
1511
    if (basename == NULL)
1512
        return path;
1513
    else
1514
        return basename + 1; /* strip '/' */
1515
}
1516

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

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

    
1562
    uint32_t cluster_num = begin_of_direntry(direntry);
1563
    uint32_t offset = 0;
1564
    int first_mapping_index = -1;
1565
    mapping_t* mapping = NULL;
1566
    const char* basename2 = NULL;
1567

    
1568
    vvfat_close_current_file(s);
1569

    
1570
    /* the root directory */
1571
    if (cluster_num == 0)
1572
        return 0;
1573

    
1574
    /* write support */
1575
    if (s->qcow) {
1576
        basename2 = get_basename(path);
1577

    
1578
        mapping = find_mapping_for_cluster(s, cluster_num);
1579

    
1580
        if (mapping) {
1581
            const char* basename;
1582

    
1583
            assert(mapping->mode & MODE_DELETED);
1584
            mapping->mode &= ~MODE_DELETED;
1585

    
1586
            basename = get_basename(mapping->path);
1587

    
1588
            assert(mapping->mode & MODE_NORMAL);
1589

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

    
1602
    while(1) {
1603
        if (s->qcow) {
1604
            if (!copy_it && cluster_was_modified(s, cluster_num)) {
1605
                if (mapping == NULL ||
1606
                        mapping->begin > cluster_num ||
1607
                        mapping->end <= cluster_num)
1608
                mapping = find_mapping_for_cluster(s, cluster_num);
1609

    
1610

    
1611
                if (mapping &&
1612
                        (mapping->mode & MODE_DIRECTORY) == 0) {
1613

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

    
1623
                        if (strcmp(basename, basename2))
1624
                            copy_it = 1;
1625
                        first_mapping_index = array_index(&(s->mapping), mapping);
1626
                    }
1627

    
1628
                    if (mapping->first_mapping_index != first_mapping_index
1629
                            && mapping->info.file.offset > 0) {
1630
                        assert(0);
1631
                        copy_it = 1;
1632
                    }
1633

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

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

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

    
1664
        ret++;
1665
        if (s->used_clusters[cluster_num] & USED_ANY)
1666
            return 0;
1667
        s->used_clusters[cluster_num] = USED_FILE;
1668

    
1669
        cluster_num = modified_fat_get(s, cluster_num);
1670

    
1671
        if (fat_eof(s, cluster_num))
1672
            return ret;
1673
        else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
1674
            return -1;
1675

    
1676
        offset += s->cluster_size;
1677
    }
1678
}
1679

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

    
1693
    long_file_name lfn;
1694
    int path_len = strlen(path);
1695
    char path2[PATH_MAX];
1696

    
1697
    assert(path_len < PATH_MAX); /* len was tested before! */
1698
    strcpy(path2, path);
1699
    path2[path_len] = '/';
1700
    path2[path_len + 1] = '\0';
1701

    
1702
    if (mapping) {
1703
        const char* basename = get_basename(mapping->path);
1704
        const char* basename2 = get_basename(path);
1705

    
1706
        assert(mapping->mode & MODE_DIRECTORY);
1707

    
1708
        assert(mapping->mode & MODE_DELETED);
1709
        mapping->mode &= ~MODE_DELETED;
1710

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

    
1722
        ret++;
1723

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

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

    
1740
        for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
1741
            int cluster_count;
1742

    
1743
DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
1744
            if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
1745
                    is_free(direntries + i))
1746
                continue;
1747

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

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

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

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

    
1797
            ret += cluster_count;
1798
        }
1799

    
1800
        cluster_num = modified_fat_get(s, cluster_num);
1801
    } while(!fat_eof(s, cluster_num));
1802

    
1803
    free(cluster);
1804
    return ret;
1805
}
1806

    
1807
/* returns 1 on success */
1808
static int is_consistent(BDRVVVFATState* s)
1809
{
1810
    int i, check;
1811
    int used_clusters_count = 0;
1812

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

    
1842
    clear_commits(s);
1843

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

    
1853
    used_clusters_count = check_directory_consistency(s, 0, s->path);
1854
    if (used_clusters_count <= 0) {
1855
        DLOG(fprintf(stderr, "problem in directory\n"));
1856
        return 0;
1857
    }
1858

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

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

    
1876
    if (check != used_clusters_count)
1877
        return 0;
1878

    
1879
    return used_clusters_count;
1880
}
1881

    
1882
static inline void adjust_mapping_indices(BDRVVVFATState* s,
1883
        int offset, int adjust)
1884
{
1885
    int i;
1886

    
1887
    for (i = 0; i < s->mapping.next; i++) {
1888
        mapping_t* mapping = array_get(&(s->mapping), i);
1889

    
1890
#define ADJUST_MAPPING_INDEX(name) \
1891
        if (mapping->name >= offset) \
1892
            mapping->name += adjust
1893

    
1894
        ADJUST_MAPPING_INDEX(first_mapping_index);
1895
        if (mapping->mode & MODE_DIRECTORY)
1896
            ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
1897
    }
1898
}
1899

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

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

    
1927
    mapping->begin = begin;
1928
    mapping->end = end;
1929

    
1930
DLOG(mapping_t* next_mapping;
1931
assert(index + 1 >= s->mapping.next ||
1932
((next_mapping = array_get(&(s->mapping), index + 1)) &&
1933
 next_mapping->begin >= end)));
1934

    
1935
    if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1936
        s->current_mapping = array_get(&(s->mapping),
1937
                s->current_mapping - first_mapping);
1938

    
1939
    return mapping;
1940
}
1941

    
1942
static int remove_mapping(BDRVVVFATState* s, int mapping_index)
1943
{
1944
    mapping_t* mapping = array_get(&(s->mapping), mapping_index);
1945
    mapping_t* first_mapping = array_get(&(s->mapping), 0);
1946

    
1947
    /* free mapping */
1948
    if (mapping->first_mapping_index < 0)
1949
        free(mapping->path);
1950

    
1951
    /* remove from s->mapping */
1952
    array_remove(&(s->mapping), mapping_index);
1953

    
1954
    /* adjust all references to mappings */
1955
    adjust_mapping_indices(s, mapping_index, -1);
1956

    
1957
    if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1958
        s->current_mapping = array_get(&(s->mapping),
1959
                s->current_mapping - first_mapping);
1960

    
1961
    return 0;
1962
}
1963

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

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

    
1991
static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
1992
{
1993
    int ret = array_remove_slice(&(s->directory), dir_index, count);
1994
    if (ret)
1995
        return ret;
1996
    adjust_dirindices(s, dir_index, -count);
1997
    return 0;
1998
}
1999

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

    
2013
    vvfat_close_current_file(s);
2014

    
2015
    assert(mapping);
2016
    assert(mapping->begin == first_cluster);
2017
    mapping->first_mapping_index = -1;
2018
    mapping->dir_index = dir_index;
2019
    mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2020
        MODE_DIRECTORY : MODE_NORMAL;
2021

    
2022
    while (!fat_eof(s, cluster)) {
2023
        uint32_t c, c1;
2024

    
2025
        for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2026
                c = c1, c1 = modified_fat_get(s, c1));
2027

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

    
2040
        if (!fat_eof(s, c1)) {
2041
            int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2042
            mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2043
                array_get(&(s->mapping), i);
2044

    
2045
            if (next_mapping == NULL || next_mapping->begin > c1) {
2046
                int i1 = array_index(&(s->mapping), mapping);
2047

    
2048
                next_mapping = insert_mapping(s, c1, c1+1);
2049

    
2050
                if (c1 < c)
2051
                    i1++;
2052
                mapping = array_get(&(s->mapping), i1);
2053
            }
2054

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

    
2074
            mapping = next_mapping;
2075
        }
2076
                
2077
        cluster = c1;
2078
    }
2079

    
2080
    return 0;
2081
}
2082

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

    
2090
    int factor = 0x10 * s->sectors_per_cluster;
2091
    int old_cluster_count, new_cluster_count;
2092
    int current_dir_index = mapping->info.dir.first_dir_index;
2093
    int first_dir_index = current_dir_index;
2094
    int ret, i;
2095
    uint32_t c;
2096

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

    
2099
    assert(direntry);
2100
    assert(mapping);
2101
    assert(mapping->begin == first_cluster);
2102
    assert(mapping->info.dir.first_dir_index < s->directory.next);
2103
    assert(mapping->mode & MODE_DIRECTORY);
2104
    assert(dir_index == 0 || is_directory(direntry));
2105

    
2106
    mapping->info.dir.parent_mapping_index = parent_mapping_index;
2107

    
2108
    if (first_cluster == 0) {
2109
        old_cluster_count = new_cluster_count =
2110
            s->last_cluster_of_root_directory;
2111
    } else {
2112
        for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2113
                c = fat_get(s, c))
2114
            old_cluster_count++;
2115

    
2116
        for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2117
                c = modified_fat_get(s, c))
2118
            new_cluster_count++;
2119
    }
2120

    
2121
    if (new_cluster_count > old_cluster_count) {
2122
        if (insert_direntries(s,
2123
                current_dir_index + factor * old_cluster_count,
2124
                factor * (new_cluster_count - old_cluster_count)) == NULL)
2125
            return -1;
2126
    } else if (new_cluster_count < old_cluster_count)
2127
        remove_direntries(s,
2128
                current_dir_index + factor * new_cluster_count,
2129
                factor * (old_cluster_count - new_cluster_count));
2130

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

    
2141
    ret = commit_mappings(s, first_cluster, dir_index);
2142
    if (ret)
2143
        return ret;
2144

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

    
2158
    return 0;
2159
}
2160

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

    
2175
    assert(offset < size);
2176
    assert((offset % s->cluster_size) == 0);
2177

    
2178
    for (i = s->cluster_size; i < offset; i += s->cluster_size)
2179
        c = modified_fat_get(s, c);
2180

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

    
2191
    while (offset < size) {
2192
        uint32_t c1;
2193
        int rest_size = (size - offset > s->cluster_size ?
2194
                s->cluster_size : size - offset);
2195
        int ret;
2196

    
2197
        c1 = modified_fat_get(s, c);
2198

    
2199
        assert((size - offset == 0 && fat_eof(s, c)) ||
2200
                (size > offset && c >=2 && !fat_eof(s, c)));
2201
        assert(size >= 0);
2202

    
2203
        ret = vvfat_read(s->bs, cluster2sector(s, c),
2204
            cluster, (rest_size + 0x1ff) / 0x200);
2205

    
2206
        if (ret < 0)
2207
            return ret;
2208

    
2209
        if (write(fd, cluster, rest_size) < 0)
2210
            return -2;
2211

    
2212
        offset += rest_size;
2213
        c = c1;
2214
    }
2215

    
2216
    ftruncate(fd, size);
2217
    close(fd);
2218

    
2219
    return commit_mappings(s, first_cluster, dir_index);
2220
}
2221

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

    
2244
/* test, if all direntries have mappings */
2245
static void check2(BDRVVVFATState* s)
2246
{
2247
    int i;
2248
    int first_mapping = -1;
2249

    
2250
    for (i = 0; i < s->directory.next; i++) {
2251
        direntry_t* direntry = array_get(&(s->directory), i);
2252

    
2253
        if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2254
            mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2255
            assert(mapping);
2256
            assert(mapping->dir_index == i || is_dot(direntry));
2257
            assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2258
        }
2259

    
2260
        if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2261
            /* cluster start */
2262
            int j, count = 0;
2263

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

    
2292
static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2293
{
2294
    int i;
2295

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

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

    
2311
            assert(commit->path);
2312
            mapping->path = commit->path;
2313
            if (rename(old_path, mapping->path))
2314
                return -2;
2315

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

    
2325
                /* recurse */
2326
                while (!fat_eof(s, c)) {
2327
                    do {
2328
                        direntry_t* d = direntry + i;
2329

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

    
2336
                            assert(!strncmp(m->path, mapping->path, l2));
2337

    
2338
                            strcpy(new_path, mapping->path);
2339
                            strcpy(new_path + l1, m->path + l2);
2340

    
2341
                            schedule_rename(s, m->begin, new_path);
2342
                        }
2343
                        i++;
2344
                    } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2345
                    c = fat_get(s, c);
2346
                }
2347
            }
2348

    
2349
            free(old_path);
2350
            array_remove(&(s->commits), i);
2351
            continue;
2352
        } else if (commit->action == ACTION_MKDIR) {
2353
            mapping_t* mapping;
2354
            int j, parent_path_len;
2355

    
2356
#ifdef __MINGW32__
2357
            if (mkdir(commit->path))
2358
                return -5;
2359
#else
2360
            if (mkdir(commit->path, 0755))
2361
                return -5;
2362
#endif
2363

    
2364
            mapping = insert_mapping(s, commit->param.mkdir.cluster,
2365
                    commit->param.mkdir.cluster + 1);
2366
            if (mapping == NULL)
2367
                return -6;
2368

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

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

    
2390
            array_remove(&(s->commits), i);
2391
            continue;
2392
        }
2393

    
2394
        i++;
2395
    }
2396
    return 0;
2397
}
2398

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

    
2406
    vvfat_close_current_file(s);
2407

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

    
2421
            assert(mapping);
2422
            assert(mapping->begin == begin);
2423
            assert(commit->path == NULL);
2424

    
2425
            if (commit_one_file(s, commit->param.writeout.dir_index,
2426
                        commit->param.writeout.modified_offset))
2427
                fail = -3;
2428

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

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

    
2444
            if (i >= s->directory.next) {
2445
                fail = -6;
2446
                continue;
2447
            }
2448

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

    
2464
            if (commit_one_file(s, i, 0))
2465
                fail = -7;
2466

    
2467
            break;
2468
        }
2469
        default:
2470
            assert(0);
2471
        }
2472
    }
2473
    if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2474
        return -1;
2475
    return fail;
2476
}
2477

    
2478
static int handle_deletes(BDRVVVFATState* s)
2479
{
2480
    int i, deferred = 1, deleted = 1;
2481

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

    
2488
        for (i = 1; i < s->mapping.next; i++) {
2489
            mapping_t* mapping = array_get(&(s->mapping), i);
2490
            if (mapping->mode & MODE_DELETED) {
2491
                direntry_t* entry = array_get(&(s->directory),
2492
                        mapping->dir_index);
2493

    
2494
                if (is_free(entry)) {
2495
                    /* remove file/directory */
2496
                    if (mapping->mode & MODE_DIRECTORY) {
2497
                        int j, next_dir_index = s->directory.next,
2498
                        first_dir_index = mapping->info.dir.first_dir_index;
2499

    
2500
                        if (rmdir(mapping->path) < 0) {
2501
                            if (errno == ENOTEMPTY) {
2502
                                deferred++;
2503
                                continue;
2504
                            } else
2505
                                return -5;
2506
                        }
2507

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

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

    
2534
    return 0;
2535
}
2536

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

    
2549
    /* the real meat are the commits. Nothing to do? Move along! */
2550
    if (s->commits.next == 0)
2551
        return 0;
2552

    
2553
    vvfat_close_current_file(s);
2554

    
2555
    ret = handle_renames_and_mkdirs(s);
2556
    if (ret) {
2557
        fprintf(stderr, "Error handling renames (%d)\n", ret);
2558
        assert(0);
2559
        return ret;
2560
    }
2561

    
2562
    /* copy FAT (with bdrv_read) */ 
2563
    memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2564

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

    
2573
    ret = handle_commits(s);
2574
    if (ret) {
2575
        fprintf(stderr, "Error handling commits (%d)\n", ret);
2576
        assert(0);
2577
        return ret;
2578
    }
2579

    
2580
    ret = handle_deletes(s);
2581
    if (ret) {
2582
        fprintf(stderr, "Error deleting\n");
2583
        assert(0);
2584
        return ret;
2585
    }
2586

    
2587
    s->qcow->drv->bdrv_make_empty(s->qcow);
2588

    
2589
    memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2590

    
2591
DLOG(checkpoint());
2592
    return 0;
2593
}
2594

    
2595
static int try_commit(BDRVVVFATState* s)
2596
{
2597
    vvfat_close_current_file(s);
2598
DLOG(checkpoint());
2599
    if(!is_consistent(s))
2600
        return -1;
2601
    return do_commit(s);
2602
}
2603

    
2604
static int vvfat_write(BlockDriverState *bs, int64_t sector_num, 
2605
                    const uint8_t *buf, int nb_sectors)
2606
{
2607
    BDRVVVFATState *s = bs->opaque; 
2608
    int i, ret;
2609

    
2610
DLOG(checkpoint());
2611

    
2612
    vvfat_close_current_file(s);
2613

    
2614
    /*
2615
     * Some sanity checks:
2616
     * - do not allow writing to the boot sector
2617
     * - do not allow to write non-ASCII filenames
2618
     */
2619

    
2620
    if (sector_num < s->first_sectors_number)
2621
        return -1;
2622

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

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

    
2640
                lfn_init(&lfn);
2641

    
2642
                if (begin < sector_num)
2643
                    begin = sector_num;
2644
                if (end > sector_num + nb_sectors)
2645
                    end = sector_num + nb_sectors;
2646
                dir_index  = mapping->dir_index + 
2647
                    0x10 * (begin - mapping->begin * s->sectors_per_cluster);
2648
                direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
2649

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

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

    
2683
    for (i = sector2cluster(s, sector_num);
2684
            i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
2685
        if (i >= 0)
2686
            s->used_clusters[i] |= USED_ALLOCATED;
2687

    
2688
DLOG(checkpoint());
2689
    /* TODO: add timeout */
2690
    try_commit(s);
2691

    
2692
DLOG(checkpoint());
2693
    return 0;
2694
}
2695

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

    
2708
static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
2709
        const uint8_t* buffer, int nb_sectors) {
2710
    BDRVVVFATState* s = bs->opaque;
2711
    return try_commit(s);
2712
}
2713

    
2714
static void write_target_close(BlockDriverState *bs) {
2715
    BDRVVVFATState* s = bs->opaque;
2716
    bdrv_delete(s->qcow);
2717
    free(s->qcow_filename);
2718
}
2719

    
2720
static BlockDriver vvfat_write_target = {
2721
    "vvfat_write_target", 0, NULL, NULL, NULL,
2722
    write_target_commit,
2723
    write_target_close,
2724
    NULL, NULL, NULL
2725
};
2726

    
2727
static int enable_write_target(BDRVVVFATState *s)
2728
{
2729
    int size = sector2cluster(s, s->sector_count);
2730
    s->used_clusters = calloc(size, 1);
2731

    
2732
    array_init(&(s->commits), sizeof(commit_t));
2733

    
2734
    s->qcow_filename = malloc(1024);
2735
    strcpy(s->qcow_filename, "/tmp/vl.XXXXXX");
2736
    get_tmp_filename(s->qcow_filename, strlen(s->qcow_filename) + 1);
2737
    if (bdrv_create(&bdrv_qcow,
2738
                s->qcow_filename, s->sector_count, "fat:", 0) < 0)
2739
        return -1;
2740
    s->qcow = bdrv_new("");
2741
    if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
2742
        return -1;
2743

    
2744
#ifndef _WIN32
2745
    unlink(s->qcow_filename);
2746
#endif
2747

    
2748
    s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
2749
    s->bs->backing_hd->drv = &vvfat_write_target;
2750
    s->bs->backing_hd->opaque = s;
2751

    
2752
    return 0;
2753
}
2754

    
2755
static void vvfat_close(BlockDriverState *bs)
2756
{
2757
    BDRVVVFATState *s = bs->opaque;
2758

    
2759
    vvfat_close_current_file(s);
2760
    array_free(&(s->fat));
2761
    array_free(&(s->directory));
2762
    array_free(&(s->mapping));
2763
    if(s->cluster_buffer)
2764
        free(s->cluster_buffer);
2765
}
2766

    
2767
BlockDriver bdrv_vvfat = {
2768
    "vvfat",
2769
    sizeof(BDRVVVFATState),
2770
    vvfat_probe,
2771
    vvfat_open,
2772
    vvfat_read,
2773
    vvfat_write,
2774
    vvfat_close,
2775
    NULL,
2776
    vvfat_is_allocated
2777
};
2778

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