vvfat.c 84.8 KB
Newer Older
1
/* vim:set shiftwidth=4 ts=4: */
2
3
/*
 * QEMU Block driver for virtual VFAT (shadows a local directory)
4
 *
5
 * Copyright (c) 2004,2005 Johannes E. Schindelin
6
 *
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include <sys/stat.h>
#include <dirent.h>
pbrook's avatar
pbrook committed
27
#include "qemu-common.h"
28
#include "block/block_int.h"
29
#include "qemu/module.h"
30
#include "migration/migration.h"
31
32
#include "qapi/qmp/qint.h"
#include "qapi/qmp/qbool.h"
33

34
35
36
37
38
39
40
41
42
43
#ifndef S_IWGRP
#define S_IWGRP 0
#endif
#ifndef S_IWOTH
#define S_IWOTH 0
#endif

/* TODO: add ":bootsector=blabla.img:" */
/* LATER TODO: add automatic boot sector generation from
    BOOTEASY.ASM and Ranish Partition Manager
44
    Note that DOS assumes the system files to be the first files in the
45
46
47
48
49
50
51
52
53
54
55
56
57
    file system (test if the boot sector still relies on that fact)! */
/* MAYBE TODO: write block-visofs.c */
/* TODO: call try_commit() only after a timeout */

/* #define DEBUG */

#ifdef DEBUG

#define DLOG(a) a

#undef stderr
#define stderr STDERR
FILE* stderr = NULL;
58

59
static void checkpoint(void);
60

61
62
63
64
65
66
#ifdef __MINGW32__
void nonono(const char* file, int line, const char* msg) {
    fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg);
    exit(-5);
}
#undef assert
bellard's avatar
bellard committed
67
#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
68
69
70
71
72
73
74
#endif

#else

#define DLOG(a)

#endif
75
76

/* dynamic array functions */
77
typedef struct array_t {
78
79
    char* pointer;
    unsigned int size,next,item_size;
80
} array_t;
81

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

90
static inline void array_free(array_t* array)
91
{
92
    g_free(array->pointer);
93
94
95
    array->size=array->next=0;
}

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

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

    return 0;
114
115
}

116
static inline void* array_get_next(array_t* array) {
117
118
119
120
121
122
123
124
125
    unsigned int next = array->next;
    void* result;

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

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

126
127
128
    return result;
}

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

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

    if(!array ||
	    index_to<0 || index_to>=array->next ||
	    index_from<0 || index_from>=array->next)
	return -1;
157

158
159
160
161
162
163
    if(index_to==index_from)
	return 0;

    is=array->item_size;
    from=array->pointer+index_from*is;
    to=array->pointer+index_to*is;
164
    buf=g_malloc(is*count);
165
166
167
168
169
170
    memcpy(buf,from,is*count);

    if(index_to<index_from)
	memmove(to+is*count,to,from-to);
    else
	memmove(from,from+is*count,to-from);
171

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

174
    g_free(buf);
175
176
177
178

    return 0;
}

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

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

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

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

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

ths's avatar
ths committed
245
246
247
248
typedef struct {
    uint8_t head;
    uint8_t sector;
    uint8_t cylinder;
249
} mbr_chs_t;
ths's avatar
ths committed
250

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

260
typedef struct mbr_t {
ths's avatar
ths committed
261
262
263
    uint8_t ignored[0x1b8];
    uint32_t nt_id;
    uint8_t ignored2[2];
264
    partition_t partition[4];
265
    uint8_t magic[2];
266
} QEMU_PACKED mbr_t;
267

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

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

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

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

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

/* here begins the real VVFAT driver */

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

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

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

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

    /* write support */
347
348
349
350
351
    BlockDriverState* write_target;
    char* qcow_filename;
    BlockDriverState* qcow;
    void* fat2;
    char* used_clusters;
352
    array_t commits;
353
354
    const char* path;
    int downcase_short_names;
Kevin Wolf's avatar
Kevin Wolf committed
355
356

    Error *migration_blocker;
357
358
} BDRVVVFATState;

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

383
static void init_mbr(BDRVVVFATState *s, int cyls, int heads, int secs)
384
385
{
    /* TODO: if the files mbr.img and bootsect.img exist, use them */
386
387
    mbr_t* real_mbr=(mbr_t*)s->first_sectors;
    partition_t* partition = &(real_mbr->partition[0]);
ths's avatar
ths committed
388
    int lba;
389
390

    memset(s->first_sectors,0,512);
391

ths's avatar
ths committed
392
393
394
    /* Win NT Disk Signature */
    real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);

395
    partition->attributes=0x80; /* bootable */
ths's avatar
ths committed
396
397

    /* LBA is used when partition is outside the CHS geometry */
398
399
400
401
    lba  = sector2CHS(&partition->start_CHS, s->first_sectors_number - 1,
                     cyls, heads, secs);
    lba |= sector2CHS(&partition->end_CHS,   s->bs->total_sectors - 1,
                     cyls, heads, secs);
ths's avatar
ths committed
402
403

    /*LBA partitions are identified only by start/length_sector_long not by CHS*/
Markus Armbruster's avatar
Markus Armbruster committed
404
405
406
    partition->start_sector_long  = cpu_to_le32(s->first_sectors_number - 1);
    partition->length_sector_long = cpu_to_le32(s->bs->total_sectors
                                                - s->first_sectors_number + 1);
ths's avatar
ths committed
407

408
    /* FAT12/FAT16/FAT32 */
ths's avatar
ths committed
409
410
411
412
413
    /* DOS uses different types when partition is LBA,
       probably to prevent older versions from using CHS on them */
    partition->fs_type= s->fat_type==12 ? 0x1:
                        s->fat_type==16 ? (lba?0xe:0x06):
                         /*fat_tyoe==32*/ (lba?0xc:0x0b);
414
415
416
417

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

418
419
/* direntry functions */

420
/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
ths's avatar
ths committed
421
static inline int short2long_name(char* dest,const char* src)
422
423
{
    int i;
424
    int len;
425
426
427
428
    for(i=0;i<129 && src[i];i++) {
        dest[2*i]=src[i];
	dest[2*i+1]=0;
    }
429
    len=2*i;
430
431
432
    dest[2*i]=dest[2*i+1]=0;
    for(i=2*i+2;(i%26);i++)
	dest[i]=0xff;
433
    return len;
434
435
}

436
static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
437
438
439
440
{
    char buffer[258];
    int length=short2long_name(buffer,filename),
        number_of_entries=(length+25)/26,i;
441
    direntry_t* entry;
442
443
444
445
446
447
448
449

    for(i=0;i<number_of_entries;i++) {
	entry=array_get_next(&(s->directory));
	entry->attributes=0xf;
	entry->reserved[0]=0;
	entry->begin=0;
	entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
    }
450
    for(i=0;i<26*number_of_entries;i++) {
451
452
453
454
455
456
457
458
459
460
	int offset=(i%26);
	if(offset<10) offset=1+offset;
	else if(offset<22) offset=14+offset-10;
	else offset=28+offset-22;
	entry=array_get(&(s->directory),s->directory.next-1-(i/26));
	entry->name[offset]=buffer[i];
    }
    return array_get(&(s->directory),s->directory.next-number_of_entries);
}

461
static char is_free(const direntry_t* direntry)
462
{
463
    return direntry->name[0]==0xe5 || direntry->name[0]==0x00;
464
465
}

466
static char is_volume_label(const direntry_t* direntry)
467
468
469
470
{
    return direntry->attributes == 0x28;
}

471
static char is_long_name(const direntry_t* direntry)
472
473
474
475
{
    return direntry->attributes == 0xf;
}

476
static char is_short_name(const direntry_t* direntry)
477
478
479
480
481
{
    return !is_volume_label(direntry) && !is_long_name(direntry)
	&& !is_free(direntry);
}

482
static char is_directory(const direntry_t* direntry)
483
484
485
486
{
    return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
}

487
static inline char is_dot(const direntry_t* direntry)
488
489
490
491
{
    return is_short_name(direntry) && direntry->name[0] == '.';
}

492
static char is_file(const direntry_t* direntry)
493
494
495
496
{
    return is_short_name(direntry) && !is_directory(direntry);
}

497
static inline uint32_t begin_of_direntry(const direntry_t* direntry)
498
499
500
501
{
    return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
}

502
static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
503
504
505
506
{
    return le32_to_cpu(direntry->size);
}

507
static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
508
509
510
511
512
{
    direntry->begin = cpu_to_le16(begin & 0xffff);
    direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
}

513
514
/* fat functions */

515
static inline uint8_t fat_chksum(const direntry_t* entry)
516
517
518
519
{
    uint8_t chksum=0;
    int i;

520
521
522
    for (i = 0; i < ARRAY_SIZE(entry->name); i++) {
        chksum = (((chksum & 0xfe) >> 1) |
                  ((chksum & 0x01) ? 0x80 : 0)) + entry->name[i];
Aurelien Jarno's avatar
Aurelien Jarno committed
523
    }
524

525
526
527
528
529
530
531
    return chksum;
}

/* if return_time==0, this returns the fat_date, else the fat_time */
static uint16_t fat_datetime(time_t time,int return_time) {
    struct tm* t;
    struct tm t1;
532
    t = &t1;
533
534
535
536
537
538
539
540
    localtime_r(&time,t);
    if(return_time)
	return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
    return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
}

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

static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
{
565
566
567
    if(s->fat_type==32) {
	uint32_t* entry=array_get(&(s->fat),cluster);
	return le32_to_cpu(*entry);
568
569
570
571
    } else if(s->fat_type==16) {
	uint16_t* entry=array_get(&(s->fat),cluster);
	return le16_to_cpu(*entry);
    } else {
ths's avatar
ths committed
572
	const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
573
	return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
574
575
576
577
578
579
580
581
582
583
584
585
    }
}

static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
{
    if(fat_entry>s->max_fat_value-8)
	return -1;
    return 0;
}

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

597
598
599
    switch(s->fat_type) {
	case 12: s->max_fat_value=0xfff; break;
	case 16: s->max_fat_value=0xffff; break;
600
	case 32: s->max_fat_value=0x0fffffff; break;
601
602
603
604
605
	default: s->max_fat_value=0; /* error... */
    }

}

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

    if(is_dot) {
	entry=array_get_next(&(s->directory));
617
        memset(entry->name, 0x20, sizeof(entry->name));
618
619
620
	memcpy(entry->name,filename,strlen(filename));
	return entry;
    }
621

622
    entry_long=create_long_filename(s,filename);
623

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

631
    entry=array_get_next(&(s->directory));
632
    memset(entry->name, 0x20, sizeof(entry->name));
633
    memcpy(entry->name, filename, i);
634

635
636
637
638
639
    if (j > 0) {
        for (i = 0; i < 3 && filename[j + 1 + i]; i++) {
            entry->name[8 + i] = filename[j + 1 + i];
        }
    }
640
641
642

    /* upcase & remove unwanted characters */
    for(i=10;i>=0;i--) {
643
	if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
644
	if(entry->name[i]<=' ' || entry->name[i]>0x7f
645
		|| strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
646
647
648
649
650
651
652
	    entry->name[i]='_';
        else if(entry->name[i]>='a' && entry->name[i]<='z')
            entry->name[i]+='A'-'a';
    }

    /* mangle duplicates */
    while(1) {
653
	direntry_t* entry1=array_get(&(s->directory),directory_start);
654
655
656
	int j;

	for(;entry1<entry;entry1++)
657
	    if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
658
659
660
661
		break; /* found dupe */
	if(entry1==entry) /* no dupe found */
	    break;

662
	/* use all 8 characters of name */
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
	if(entry->name[7]==' ') {
	    int j;
	    for(j=6;j>0 && entry->name[j]==' ';j--)
		entry->name[j]='~';
	}

	/* increment number */
	for(j=7;j>0 && entry->name[j]=='9';j--)
	    entry->name[j]='0';
	if(j>0) {
	    if(entry->name[j]<'0' || entry->name[j]>'9')
	        entry->name[j]='0';
	    else
	        entry->name[j]++;
	}
    }

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

	/* calculate anew, because realloc could have taken place */
	entry_long=array_get(&(s->directory),long_index);
686
	while(entry_long<entry && is_long_name(entry_long)) {
687
688
689
690
691
692
693
694
	    entry_long->reserved[1]=chksum;
	    entry_long++;
	}
    }

    return entry;
}

695
696
697
698
/*
 * Read a directory. (the index of the corresponding mapping must be passed).
 */
static int read_directory(BDRVVVFATState* s, int mapping_index)
699
{
700
701
    mapping_t* mapping = array_get(&(s->mapping), mapping_index);
    direntry_t* direntry;
702
703
704
    const char* dirname = mapping->path;
    int first_cluster = mapping->begin;
    int parent_index = mapping->info.dir.parent_mapping_index;
705
    mapping_t* parent_mapping = (mapping_t*)
706
        (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL);
707
    int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
708
709
710
711
712

    DIR* dir=opendir(dirname);
    struct dirent* entry;
    int i;

713
714
715
716
    assert(mapping->mode & MODE_DIRECTORY);

    if(!dir) {
	mapping->end = mapping->begin;
717
	return -1;
718
    }
719

720
721
722
    i = mapping->info.dir.first_dir_index =
	    first_cluster == 0 ? 0 : s->directory.next;

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

732
	if(first_cluster == 0 && (is_dotdot || is_dot))
733
	    continue;
734

735
	buffer=(char*)g_malloc(length);
736
737
738
	snprintf(buffer,length,"%s/%s",dirname,entry->d_name);

	if(stat(buffer,&st)<0) {
739
            g_free(buffer);
740
741
742
743
            continue;
	}

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

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

    /* fill with zeroes up to the end of the cluster */
    while(s->directory.next%(0x10*s->sectors_per_cluster)) {
796
797
	direntry_t* direntry=array_get_next(&(s->directory));
	memset(direntry,0,sizeof(direntry_t));
798
799
    }

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

811
     /* reget the mapping, since s->mapping was possibly realloc()ed */
812
    mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
813
814
815
816
    first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
	* 0x20 / s->cluster_size;
    mapping->end = first_cluster;

817
    direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
818
    set_begin_of_direntry(direntry, mapping->begin);
819

820
821
    return 0;
}
822

823
824
825
826
static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
{
    return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
}
827

828
829
830
831
static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
{
    return s->faked_sectors + s->sectors_per_cluster * cluster_num;
}
832

833
static int init_directories(BDRVVVFATState* s,
834
835
                            const char *dirname, int heads, int secs,
                            Error **errp)
836
{
837
838
    bootsector_t* bootsector;
    mapping_t* mapping;
839
840
841
842
843
844
    unsigned int i;
    unsigned int cluster;

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

    s->cluster_size=s->sectors_per_cluster*0x200;
845
    s->cluster_buffer=g_malloc(s->cluster_size);
846
847
848
849
850
851
852
853
854
855

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

857
858
    array_init(&(s->mapping),sizeof(mapping_t));
    array_init(&(s->directory),sizeof(direntry_t));
859
860
861

    /* add volume label */
    {
862
	direntry_t* entry=array_get_next(&(s->directory));
863
	entry->attributes=0x28; /* archive | volume label */
864
        memcpy(entry->name, "QEMU VVFAT ", sizeof(entry->name));
865
866
867
868
869
    }

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

870
871
872
873
874
875
876
877
    s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
    s->cluster_count=sector2cluster(s, s->sector_count);

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

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

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

		mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
		set_begin_of_direntry(direntry, mapping->begin);
	    } else {
		mapping->end = cluster + 1;
		fix_fat = 0;
914
	    }
915
916
917
918
	}

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

919
920
921
922
	/* next free cluster */
	cluster = mapping->end;

	if(cluster > s->cluster_count) {
923
924
925
926
            error_setg(errp,
                       "Directory does not fit in FAT%d (capacity %.2f MB)",
                       s->fat_type, s->sector_count / 2000.0);
            return -1;
927
928
	}

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

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

    /* the FAT signature */
    fat_set(s,0,s->max_fat_value);
    fat_set(s,1,s->max_fat_value);
945

946
947
    s->current_mapping = NULL;

948
    bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
949
950
951
952
953
954
955
956
957
    bootsector->jump[0]=0xeb;
    bootsector->jump[1]=0x3e;
    bootsector->jump[2]=0x90;
    memcpy(bootsector->name,"QEMU    ",8);
    bootsector->sector_size=cpu_to_le16(0x200);
    bootsector->sectors_per_cluster=s->sectors_per_cluster;
    bootsector->reserved_sectors=cpu_to_le16(1);
    bootsector->number_of_fats=0x2; /* number of FATs */
    bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
958
    bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
959
    bootsector->media_type=(s->first_sectors_number>1?0xf8:0xf0); /* media descriptor (f8=hd, f0=3.5 fd)*/
960
    s->fat.pointer[0] = bootsector->media_type;
961
    bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
962
963
    bootsector->sectors_per_track = cpu_to_le16(secs);
    bootsector->number_of_heads = cpu_to_le16(heads);
964
    bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
965
    bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
966

967
    /* LATER TODO: if FAT32, this is wrong */
968
    bootsector->u.fat16.drive_number=s->first_sectors_number==1?0:0x80; /* fda=0, hda=0x80 */
969
970
971
972
973
974
975
976
977
978
979
    bootsector->u.fat16.current_head=0;
    bootsector->u.fat16.signature=0x29;
    bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);

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

    return 0;
}

bellard's avatar
bellard committed
980
#ifdef DEBUG
981
static BDRVVVFATState *vvv = NULL;
bellard's avatar
bellard committed
982
#endif
983

984
static int enable_write_target(BDRVVVFATState *s, Error **errp);
985
986
static int is_consistent(BDRVVVFATState *s);

Paolo Bonzini's avatar
Paolo Bonzini committed
987
988
989
990
991
992
static void vvfat_rebind(BlockDriverState *bs)
{
    BDRVVVFATState *s = bs->opaque;
    s->bs = bs;
}

993
994
995
996
997
998
999
1000
static QemuOptsList runtime_opts = {
    .name = "vvfat",
    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
    .desc = {
        {
            .name = "dir",
            .type = QEMU_OPT_STRING,
            .help = "Host directory to map to the vvfat device",
For faster browsing, not all history is shown. View entire blame