Statistics
| Branch: | Revision:

root / block / vvfat.c @ 1b1ed8dc

History | View | Annotate | Download (81.6 kB)

1 a046433a bellard
/* vim:set shiftwidth=4 ts=8: */
2 de167e41 bellard
/*
3 de167e41 bellard
 * QEMU Block driver for virtual VFAT (shadows a local directory)
4 5fafdf24 ths
 *
5 a046433a bellard
 * Copyright (c) 2004,2005 Johannes E. Schindelin
6 5fafdf24 ths
 *
7 de167e41 bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 de167e41 bellard
 * of this software and associated documentation files (the "Software"), to deal
9 de167e41 bellard
 * in the Software without restriction, including without limitation the rights
10 de167e41 bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 de167e41 bellard
 * copies of the Software, and to permit persons to whom the Software is
12 de167e41 bellard
 * furnished to do so, subject to the following conditions:
13 de167e41 bellard
 *
14 de167e41 bellard
 * The above copyright notice and this permission notice shall be included in
15 de167e41 bellard
 * all copies or substantial portions of the Software.
16 de167e41 bellard
 *
17 de167e41 bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 de167e41 bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 de167e41 bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 de167e41 bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 de167e41 bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 de167e41 bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 de167e41 bellard
 * THE SOFTWARE.
24 de167e41 bellard
 */
25 de167e41 bellard
#include <sys/stat.h>
26 de167e41 bellard
#include <dirent.h>
27 faf07963 pbrook
#include "qemu-common.h"
28 737e150e Paolo Bonzini
#include "block/block_int.h"
29 1de7afc9 Paolo Bonzini
#include "qemu/module.h"
30 caf71f86 Paolo Bonzini
#include "migration/migration.h"
31 de167e41 bellard
32 a046433a bellard
#ifndef S_IWGRP
33 a046433a bellard
#define S_IWGRP 0
34 a046433a bellard
#endif
35 a046433a bellard
#ifndef S_IWOTH
36 a046433a bellard
#define S_IWOTH 0
37 a046433a bellard
#endif
38 a046433a bellard
39 a046433a bellard
/* TODO: add ":bootsector=blabla.img:" */
40 a046433a bellard
/* LATER TODO: add automatic boot sector generation from
41 a046433a bellard
    BOOTEASY.ASM and Ranish Partition Manager
42 5fafdf24 ths
    Note that DOS assumes the system files to be the first files in the
43 a046433a bellard
    file system (test if the boot sector still relies on that fact)! */
44 a046433a bellard
/* MAYBE TODO: write block-visofs.c */
45 a046433a bellard
/* TODO: call try_commit() only after a timeout */
46 a046433a bellard
47 a046433a bellard
/* #define DEBUG */
48 a046433a bellard
49 a046433a bellard
#ifdef DEBUG
50 a046433a bellard
51 a046433a bellard
#define DLOG(a) a
52 a046433a bellard
53 a046433a bellard
#undef stderr
54 a046433a bellard
#define stderr STDERR
55 a046433a bellard
FILE* stderr = NULL;
56 de167e41 bellard
57 3f47aa8c blueswir1
static void checkpoint(void);
58 de167e41 bellard
59 a046433a bellard
#ifdef __MINGW32__
60 a046433a bellard
void nonono(const char* file, int line, const char* msg) {
61 a046433a bellard
    fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg);
62 a046433a bellard
    exit(-5);
63 a046433a bellard
}
64 a046433a bellard
#undef assert
65 6bcb76c3 bellard
#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
66 a046433a bellard
#endif
67 a046433a bellard
68 a046433a bellard
#else
69 a046433a bellard
70 a046433a bellard
#define DLOG(a)
71 a046433a bellard
72 a046433a bellard
#endif
73 de167e41 bellard
74 de167e41 bellard
/* dynamic array functions */
75 c227f099 Anthony Liguori
typedef struct array_t {
76 de167e41 bellard
    char* pointer;
77 de167e41 bellard
    unsigned int size,next,item_size;
78 c227f099 Anthony Liguori
} array_t;
79 de167e41 bellard
80 c227f099 Anthony Liguori
static inline void array_init(array_t* array,unsigned int item_size)
81 de167e41 bellard
{
82 511d2b14 blueswir1
    array->pointer = NULL;
83 de167e41 bellard
    array->size=0;
84 de167e41 bellard
    array->next=0;
85 de167e41 bellard
    array->item_size=item_size;
86 de167e41 bellard
}
87 de167e41 bellard
88 c227f099 Anthony Liguori
static inline void array_free(array_t* array)
89 de167e41 bellard
{
90 ce137829 Stefan Weil
    g_free(array->pointer);
91 de167e41 bellard
    array->size=array->next=0;
92 de167e41 bellard
}
93 de167e41 bellard
94 a046433a bellard
/* does not automatically grow */
95 c227f099 Anthony Liguori
static inline void* array_get(array_t* array,unsigned int index) {
96 a046433a bellard
    assert(index < array->next);
97 a046433a bellard
    return array->pointer + index * array->item_size;
98 a046433a bellard
}
99 a046433a bellard
100 c227f099 Anthony Liguori
static inline int array_ensure_allocated(array_t* array, int index)
101 a046433a bellard
{
102 a046433a bellard
    if((index + 1) * array->item_size > array->size) {
103 a046433a bellard
        int new_size = (index + 32) * array->item_size;
104 7267c094 Anthony Liguori
        array->pointer = g_realloc(array->pointer, new_size);
105 a046433a bellard
        if (!array->pointer)
106 a046433a bellard
            return -1;
107 a046433a bellard
        array->size = new_size;
108 a046433a bellard
        array->next = index + 1;
109 de167e41 bellard
    }
110 a046433a bellard
111 a046433a bellard
    return 0;
112 de167e41 bellard
}
113 de167e41 bellard
114 c227f099 Anthony Liguori
static inline void* array_get_next(array_t* array) {
115 a046433a bellard
    unsigned int next = array->next;
116 a046433a bellard
    void* result;
117 a046433a bellard
118 a046433a bellard
    if (array_ensure_allocated(array, next) < 0)
119 a046433a bellard
        return NULL;
120 a046433a bellard
121 a046433a bellard
    array->next = next + 1;
122 a046433a bellard
    result = array_get(array, next);
123 a046433a bellard
124 de167e41 bellard
    return result;
125 de167e41 bellard
}
126 de167e41 bellard
127 c227f099 Anthony Liguori
static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
128 de167e41 bellard
    if((array->next+count)*array->item_size>array->size) {
129 de167e41 bellard
        int increment=count*array->item_size;
130 7267c094 Anthony Liguori
        array->pointer=g_realloc(array->pointer,array->size+increment);
131 de167e41 bellard
        if(!array->pointer)
132 511d2b14 blueswir1
            return NULL;
133 de167e41 bellard
        array->size+=increment;
134 de167e41 bellard
    }
135 de167e41 bellard
    memmove(array->pointer+(index+count)*array->item_size,
136 de167e41 bellard
                array->pointer+index*array->item_size,
137 de167e41 bellard
                (array->next-index)*array->item_size);
138 de167e41 bellard
    array->next+=count;
139 de167e41 bellard
    return array->pointer+index*array->item_size;
140 de167e41 bellard
}
141 de167e41 bellard
142 de167e41 bellard
/* this performs a "roll", so that the element which was at index_from becomes
143 de167e41 bellard
 * index_to, but the order of all other elements is preserved. */
144 c227f099 Anthony Liguori
static inline int array_roll(array_t* array,int index_to,int index_from,int count)
145 de167e41 bellard
{
146 de167e41 bellard
    char* buf;
147 de167e41 bellard
    char* from;
148 de167e41 bellard
    char* to;
149 de167e41 bellard
    int is;
150 de167e41 bellard
151 de167e41 bellard
    if(!array ||
152 de167e41 bellard
            index_to<0 || index_to>=array->next ||
153 de167e41 bellard
            index_from<0 || index_from>=array->next)
154 de167e41 bellard
        return -1;
155 3b46e624 ths
156 de167e41 bellard
    if(index_to==index_from)
157 de167e41 bellard
        return 0;
158 de167e41 bellard
159 de167e41 bellard
    is=array->item_size;
160 de167e41 bellard
    from=array->pointer+index_from*is;
161 de167e41 bellard
    to=array->pointer+index_to*is;
162 7267c094 Anthony Liguori
    buf=g_malloc(is*count);
163 de167e41 bellard
    memcpy(buf,from,is*count);
164 de167e41 bellard
165 de167e41 bellard
    if(index_to<index_from)
166 de167e41 bellard
        memmove(to+is*count,to,from-to);
167 de167e41 bellard
    else
168 de167e41 bellard
        memmove(from,from+is*count,to-from);
169 3b46e624 ths
170 de167e41 bellard
    memcpy(to,buf,is*count);
171 de167e41 bellard
172 ce137829 Stefan Weil
    g_free(buf);
173 de167e41 bellard
174 de167e41 bellard
    return 0;
175 de167e41 bellard
}
176 de167e41 bellard
177 c227f099 Anthony Liguori
static inline int array_remove_slice(array_t* array,int index, int count)
178 de167e41 bellard
{
179 a046433a bellard
    assert(index >=0);
180 a046433a bellard
    assert(count > 0);
181 a046433a bellard
    assert(index + count <= array->next);
182 a046433a bellard
    if(array_roll(array,array->next-1,index,count))
183 de167e41 bellard
        return -1;
184 a046433a bellard
    array->next -= count;
185 de167e41 bellard
    return 0;
186 de167e41 bellard
}
187 de167e41 bellard
188 c227f099 Anthony Liguori
static int array_remove(array_t* array,int index)
189 a046433a bellard
{
190 a046433a bellard
    return array_remove_slice(array, index, 1);
191 a046433a bellard
}
192 a046433a bellard
193 a046433a bellard
/* return the index for a given member */
194 c227f099 Anthony Liguori
static int array_index(array_t* array, void* pointer)
195 a046433a bellard
{
196 a046433a bellard
    size_t offset = (char*)pointer - array->pointer;
197 a046433a bellard
    assert((offset % array->item_size) == 0);
198 a046433a bellard
    assert(offset/array->item_size < array->next);
199 a046433a bellard
    return offset/array->item_size;
200 a046433a bellard
}
201 a046433a bellard
202 de167e41 bellard
/* These structures are used to fake a disk and the VFAT filesystem.
203 541dc0d4 Stefan Weil
 * For this reason we need to use QEMU_PACKED. */
204 de167e41 bellard
205 c227f099 Anthony Liguori
typedef struct bootsector_t {
206 de167e41 bellard
    uint8_t jump[3];
207 de167e41 bellard
    uint8_t name[8];
208 de167e41 bellard
    uint16_t sector_size;
209 de167e41 bellard
    uint8_t sectors_per_cluster;
210 de167e41 bellard
    uint16_t reserved_sectors;
211 de167e41 bellard
    uint8_t number_of_fats;
212 de167e41 bellard
    uint16_t root_entries;
213 a046433a bellard
    uint16_t total_sectors16;
214 de167e41 bellard
    uint8_t media_type;
215 de167e41 bellard
    uint16_t sectors_per_fat;
216 de167e41 bellard
    uint16_t sectors_per_track;
217 de167e41 bellard
    uint16_t number_of_heads;
218 de167e41 bellard
    uint32_t hidden_sectors;
219 de167e41 bellard
    uint32_t total_sectors;
220 de167e41 bellard
    union {
221 de167e41 bellard
        struct {
222 de167e41 bellard
            uint8_t drive_number;
223 de167e41 bellard
            uint8_t current_head;
224 de167e41 bellard
            uint8_t signature;
225 de167e41 bellard
            uint32_t id;
226 de167e41 bellard
            uint8_t volume_label[11];
227 541dc0d4 Stefan Weil
        } QEMU_PACKED fat16;
228 de167e41 bellard
        struct {
229 de167e41 bellard
            uint32_t sectors_per_fat;
230 de167e41 bellard
            uint16_t flags;
231 de167e41 bellard
            uint8_t major,minor;
232 de167e41 bellard
            uint32_t first_cluster_of_root_directory;
233 de167e41 bellard
            uint16_t info_sector;
234 de167e41 bellard
            uint16_t backup_boot_sector;
235 de167e41 bellard
            uint16_t ignored;
236 541dc0d4 Stefan Weil
        } QEMU_PACKED fat32;
237 de167e41 bellard
    } u;
238 de167e41 bellard
    uint8_t fat_type[8];
239 de167e41 bellard
    uint8_t ignored[0x1c0];
240 de167e41 bellard
    uint8_t magic[2];
241 541dc0d4 Stefan Weil
} QEMU_PACKED bootsector_t;
242 de167e41 bellard
243 b570094d ths
typedef struct {
244 b570094d ths
    uint8_t head;
245 b570094d ths
    uint8_t sector;
246 b570094d ths
    uint8_t cylinder;
247 c227f099 Anthony Liguori
} mbr_chs_t;
248 b570094d ths
249 c227f099 Anthony Liguori
typedef struct partition_t {
250 de167e41 bellard
    uint8_t attributes; /* 0x80 = bootable */
251 c227f099 Anthony Liguori
    mbr_chs_t start_CHS;
252 b570094d ths
    uint8_t   fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
253 c227f099 Anthony Liguori
    mbr_chs_t end_CHS;
254 de167e41 bellard
    uint32_t start_sector_long;
255 b570094d ths
    uint32_t length_sector_long;
256 541dc0d4 Stefan Weil
} QEMU_PACKED partition_t;
257 de167e41 bellard
258 c227f099 Anthony Liguori
typedef struct mbr_t {
259 b570094d ths
    uint8_t ignored[0x1b8];
260 b570094d ths
    uint32_t nt_id;
261 b570094d ths
    uint8_t ignored2[2];
262 c227f099 Anthony Liguori
    partition_t partition[4];
263 de167e41 bellard
    uint8_t magic[2];
264 541dc0d4 Stefan Weil
} QEMU_PACKED mbr_t;
265 de167e41 bellard
266 c227f099 Anthony Liguori
typedef struct direntry_t {
267 de167e41 bellard
    uint8_t name[8];
268 de167e41 bellard
    uint8_t extension[3];
269 de167e41 bellard
    uint8_t attributes;
270 de167e41 bellard
    uint8_t reserved[2];
271 de167e41 bellard
    uint16_t ctime;
272 de167e41 bellard
    uint16_t cdate;
273 de167e41 bellard
    uint16_t adate;
274 de167e41 bellard
    uint16_t begin_hi;
275 de167e41 bellard
    uint16_t mtime;
276 de167e41 bellard
    uint16_t mdate;
277 de167e41 bellard
    uint16_t begin;
278 de167e41 bellard
    uint32_t size;
279 541dc0d4 Stefan Weil
} QEMU_PACKED direntry_t;
280 de167e41 bellard
281 de167e41 bellard
/* this structure are used to transparently access the files */
282 de167e41 bellard
283 c227f099 Anthony Liguori
typedef struct mapping_t {
284 a046433a bellard
    /* begin is the first cluster, end is the last+1 */
285 a046433a bellard
    uint32_t begin,end;
286 de167e41 bellard
    /* as s->directory is growable, no pointer may be used here */
287 de167e41 bellard
    unsigned int dir_index;
288 a046433a bellard
    /* the clusters of a file may be in any order; this points to the first */
289 a046433a bellard
    int first_mapping_index;
290 a046433a bellard
    union {
291 a046433a bellard
        /* offset is
292 a046433a bellard
         * - the offset in the file (in clusters) for a file, or
293 a046433a bellard
         * - the next cluster of the directory for a directory, and
294 a046433a bellard
         * - the address of the buffer for a faked entry
295 a046433a bellard
         */
296 a046433a bellard
        struct {
297 a046433a bellard
            uint32_t offset;
298 a046433a bellard
        } file;
299 a046433a bellard
        struct {
300 a046433a bellard
            int parent_mapping_index;
301 a046433a bellard
            int first_dir_index;
302 a046433a bellard
        } dir;
303 a046433a bellard
    } info;
304 a046433a bellard
    /* path contains the full path, i.e. it always starts with s->path */
305 a046433a bellard
    char* path;
306 a046433a bellard
307 a046433a bellard
    enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2,
308 a046433a bellard
        MODE_DIRECTORY = 4, MODE_FAKED = 8,
309 a046433a bellard
        MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
310 a046433a bellard
    int read_only;
311 c227f099 Anthony Liguori
} mapping_t;
312 de167e41 bellard
313 a046433a bellard
#ifdef DEBUG
314 c227f099 Anthony Liguori
static void print_direntry(const struct direntry_t*);
315 c227f099 Anthony Liguori
static void print_mapping(const struct mapping_t* mapping);
316 a046433a bellard
#endif
317 de167e41 bellard
318 de167e41 bellard
/* here begins the real VVFAT driver */
319 de167e41 bellard
320 de167e41 bellard
typedef struct BDRVVVFATState {
321 848c66e8 Paolo Bonzini
    CoMutex lock;
322 a046433a bellard
    BlockDriverState* bs; /* pointer to parent */
323 de167e41 bellard
    unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
324 de167e41 bellard
    unsigned char first_sectors[0x40*0x200];
325 3b46e624 ths
326 de167e41 bellard
    int fat_type; /* 16 or 32 */
327 c227f099 Anthony Liguori
    array_t fat,directory,mapping;
328 3b46e624 ths
329 de167e41 bellard
    unsigned int cluster_size;
330 de167e41 bellard
    unsigned int sectors_per_cluster;
331 de167e41 bellard
    unsigned int sectors_per_fat;
332 de167e41 bellard
    unsigned int sectors_of_root_directory;
333 a046433a bellard
    uint32_t last_cluster_of_root_directory;
334 de167e41 bellard
    unsigned int faked_sectors; /* how many sectors are faked before file data */
335 de167e41 bellard
    uint32_t sector_count; /* total number of sectors of the partition */
336 de167e41 bellard
    uint32_t cluster_count; /* total number of clusters of this partition */
337 de167e41 bellard
    uint32_t max_fat_value;
338 3b46e624 ths
339 de167e41 bellard
    int current_fd;
340 c227f099 Anthony Liguori
    mapping_t* current_mapping;
341 a046433a bellard
    unsigned char* cluster; /* points to current cluster */
342 a046433a bellard
    unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
343 de167e41 bellard
    unsigned int current_cluster;
344 de167e41 bellard
345 de167e41 bellard
    /* write support */
346 a046433a bellard
    BlockDriverState* write_target;
347 a046433a bellard
    char* qcow_filename;
348 a046433a bellard
    BlockDriverState* qcow;
349 a046433a bellard
    void* fat2;
350 a046433a bellard
    char* used_clusters;
351 c227f099 Anthony Liguori
    array_t commits;
352 a046433a bellard
    const char* path;
353 a046433a bellard
    int downcase_short_names;
354 3397f0cb Kevin Wolf
355 3397f0cb Kevin Wolf
    Error *migration_blocker;
356 de167e41 bellard
} BDRVVVFATState;
357 de167e41 bellard
358 b570094d ths
/* take the sector position spos and convert it to Cylinder/Head/Sector position
359 b570094d ths
 * if the position is outside the specified geometry, fill maximum value for CHS
360 b570094d ths
 * and return 1 to signal overflow.
361 b570094d ths
 */
362 4480e0f9 Markus Armbruster
static int sector2CHS(mbr_chs_t *chs, int spos, int cyls, int heads, int secs)
363 4480e0f9 Markus Armbruster
{
364 b570094d ths
    int head,sector;
365 4480e0f9 Markus Armbruster
    sector   = spos % secs;  spos /= secs;
366 4480e0f9 Markus Armbruster
    head     = spos % heads; spos /= heads;
367 4480e0f9 Markus Armbruster
    if (spos >= cyls) {
368 b570094d ths
        /* Overflow,
369 b570094d ths
        it happens if 32bit sector positions are used, while CHS is only 24bit.
370 b570094d ths
        Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
371 b570094d ths
        chs->head     = 0xFF;
372 b570094d ths
        chs->sector   = 0xFF;
373 b570094d ths
        chs->cylinder = 0xFF;
374 b570094d ths
        return 1;
375 b570094d ths
    }
376 b570094d ths
    chs->head     = (uint8_t)head;
377 b570094d ths
    chs->sector   = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
378 b570094d ths
    chs->cylinder = (uint8_t)spos;
379 b570094d ths
    return 0;
380 b570094d ths
}
381 de167e41 bellard
382 4480e0f9 Markus Armbruster
static void init_mbr(BDRVVVFATState *s, int cyls, int heads, int secs)
383 de167e41 bellard
{
384 de167e41 bellard
    /* TODO: if the files mbr.img and bootsect.img exist, use them */
385 c227f099 Anthony Liguori
    mbr_t* real_mbr=(mbr_t*)s->first_sectors;
386 c227f099 Anthony Liguori
    partition_t* partition = &(real_mbr->partition[0]);
387 b570094d ths
    int lba;
388 de167e41 bellard
389 de167e41 bellard
    memset(s->first_sectors,0,512);
390 3b46e624 ths
391 b570094d ths
    /* Win NT Disk Signature */
392 b570094d ths
    real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
393 b570094d ths
394 de167e41 bellard
    partition->attributes=0x80; /* bootable */
395 b570094d ths
396 b570094d ths
    /* LBA is used when partition is outside the CHS geometry */
397 4480e0f9 Markus Armbruster
    lba  = sector2CHS(&partition->start_CHS, s->first_sectors_number - 1,
398 4480e0f9 Markus Armbruster
                     cyls, heads, secs);
399 4480e0f9 Markus Armbruster
    lba |= sector2CHS(&partition->end_CHS,   s->bs->total_sectors - 1,
400 4480e0f9 Markus Armbruster
                     cyls, heads, secs);
401 b570094d ths
402 b570094d ths
    /*LBA partitions are identified only by start/length_sector_long not by CHS*/
403 f91cbefe Markus Armbruster
    partition->start_sector_long  = cpu_to_le32(s->first_sectors_number - 1);
404 f91cbefe Markus Armbruster
    partition->length_sector_long = cpu_to_le32(s->bs->total_sectors
405 f91cbefe Markus Armbruster
                                                - s->first_sectors_number + 1);
406 b570094d ths
407 a046433a bellard
    /* FAT12/FAT16/FAT32 */
408 b570094d ths
    /* DOS uses different types when partition is LBA,
409 b570094d ths
       probably to prevent older versions from using CHS on them */
410 b570094d ths
    partition->fs_type= s->fat_type==12 ? 0x1:
411 b570094d ths
                        s->fat_type==16 ? (lba?0xe:0x06):
412 b570094d ths
                         /*fat_tyoe==32*/ (lba?0xc:0x0b);
413 de167e41 bellard
414 de167e41 bellard
    real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
415 de167e41 bellard
}
416 de167e41 bellard
417 a046433a bellard
/* direntry functions */
418 a046433a bellard
419 de167e41 bellard
/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
420 60fe76f3 ths
static inline int short2long_name(char* dest,const char* src)
421 de167e41 bellard
{
422 de167e41 bellard
    int i;
423 1e080d5d balrog
    int len;
424 de167e41 bellard
    for(i=0;i<129 && src[i];i++) {
425 de167e41 bellard
        dest[2*i]=src[i];
426 de167e41 bellard
        dest[2*i+1]=0;
427 de167e41 bellard
    }
428 1e080d5d balrog
    len=2*i;
429 de167e41 bellard
    dest[2*i]=dest[2*i+1]=0;
430 de167e41 bellard
    for(i=2*i+2;(i%26);i++)
431 de167e41 bellard
        dest[i]=0xff;
432 1e080d5d balrog
    return len;
433 de167e41 bellard
}
434 de167e41 bellard
435 c227f099 Anthony Liguori
static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
436 de167e41 bellard
{
437 de167e41 bellard
    char buffer[258];
438 de167e41 bellard
    int length=short2long_name(buffer,filename),
439 de167e41 bellard
        number_of_entries=(length+25)/26,i;
440 c227f099 Anthony Liguori
    direntry_t* entry;
441 de167e41 bellard
442 de167e41 bellard
    for(i=0;i<number_of_entries;i++) {
443 de167e41 bellard
        entry=array_get_next(&(s->directory));
444 de167e41 bellard
        entry->attributes=0xf;
445 de167e41 bellard
        entry->reserved[0]=0;
446 de167e41 bellard
        entry->begin=0;
447 de167e41 bellard
        entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
448 de167e41 bellard
    }
449 1e080d5d balrog
    for(i=0;i<26*number_of_entries;i++) {
450 de167e41 bellard
        int offset=(i%26);
451 de167e41 bellard
        if(offset<10) offset=1+offset;
452 de167e41 bellard
        else if(offset<22) offset=14+offset-10;
453 de167e41 bellard
        else offset=28+offset-22;
454 de167e41 bellard
        entry=array_get(&(s->directory),s->directory.next-1-(i/26));
455 de167e41 bellard
        entry->name[offset]=buffer[i];
456 de167e41 bellard
    }
457 de167e41 bellard
    return array_get(&(s->directory),s->directory.next-number_of_entries);
458 de167e41 bellard
}
459 de167e41 bellard
460 c227f099 Anthony Liguori
static char is_free(const direntry_t* direntry)
461 a046433a bellard
{
462 ad1a897e ths
    return direntry->name[0]==0xe5 || direntry->name[0]==0x00;
463 a046433a bellard
}
464 a046433a bellard
465 c227f099 Anthony Liguori
static char is_volume_label(const direntry_t* direntry)
466 a046433a bellard
{
467 a046433a bellard
    return direntry->attributes == 0x28;
468 a046433a bellard
}
469 a046433a bellard
470 c227f099 Anthony Liguori
static char is_long_name(const direntry_t* direntry)
471 a046433a bellard
{
472 a046433a bellard
    return direntry->attributes == 0xf;
473 a046433a bellard
}
474 a046433a bellard
475 c227f099 Anthony Liguori
static char is_short_name(const direntry_t* direntry)
476 a046433a bellard
{
477 a046433a bellard
    return !is_volume_label(direntry) && !is_long_name(direntry)
478 a046433a bellard
        && !is_free(direntry);
479 a046433a bellard
}
480 a046433a bellard
481 c227f099 Anthony Liguori
static char is_directory(const direntry_t* direntry)
482 a046433a bellard
{
483 a046433a bellard
    return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
484 a046433a bellard
}
485 a046433a bellard
486 c227f099 Anthony Liguori
static inline char is_dot(const direntry_t* direntry)
487 a046433a bellard
{
488 a046433a bellard
    return is_short_name(direntry) && direntry->name[0] == '.';
489 a046433a bellard
}
490 a046433a bellard
491 c227f099 Anthony Liguori
static char is_file(const direntry_t* direntry)
492 a046433a bellard
{
493 a046433a bellard
    return is_short_name(direntry) && !is_directory(direntry);
494 a046433a bellard
}
495 a046433a bellard
496 c227f099 Anthony Liguori
static inline uint32_t begin_of_direntry(const direntry_t* direntry)
497 a046433a bellard
{
498 a046433a bellard
    return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
499 a046433a bellard
}
500 a046433a bellard
501 c227f099 Anthony Liguori
static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
502 a046433a bellard
{
503 a046433a bellard
    return le32_to_cpu(direntry->size);
504 a046433a bellard
}
505 a046433a bellard
506 c227f099 Anthony Liguori
static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
507 a046433a bellard
{
508 a046433a bellard
    direntry->begin = cpu_to_le16(begin & 0xffff);
509 a046433a bellard
    direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
510 a046433a bellard
}
511 a046433a bellard
512 de167e41 bellard
/* fat functions */
513 de167e41 bellard
514 c227f099 Anthony Liguori
static inline uint8_t fat_chksum(const direntry_t* entry)
515 de167e41 bellard
{
516 de167e41 bellard
    uint8_t chksum=0;
517 de167e41 bellard
    int i;
518 de167e41 bellard
519 5606c220 Aurelien Jarno
    for(i=0;i<11;i++) {
520 5606c220 Aurelien Jarno
        unsigned char c;
521 5606c220 Aurelien Jarno
522 2aa326be Loรฏc Minier
        c = (i < 8) ? entry->name[i] : entry->extension[i-8];
523 5606c220 Aurelien Jarno
        chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0)) + c;
524 5606c220 Aurelien Jarno
    }
525 3b46e624 ths
526 de167e41 bellard
    return chksum;
527 de167e41 bellard
}
528 de167e41 bellard
529 de167e41 bellard
/* if return_time==0, this returns the fat_date, else the fat_time */
530 de167e41 bellard
static uint16_t fat_datetime(time_t time,int return_time) {
531 de167e41 bellard
    struct tm* t;
532 de167e41 bellard
    struct tm t1;
533 6ab00cee Michael S. Tsirkin
    t = &t1;
534 de167e41 bellard
    localtime_r(&time,t);
535 de167e41 bellard
    if(return_time)
536 de167e41 bellard
        return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
537 de167e41 bellard
    return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
538 de167e41 bellard
}
539 de167e41 bellard
540 de167e41 bellard
static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
541 de167e41 bellard
{
542 a046433a bellard
    if(s->fat_type==32) {
543 a046433a bellard
        uint32_t* entry=array_get(&(s->fat),cluster);
544 a046433a bellard
        *entry=cpu_to_le32(value);
545 de167e41 bellard
    } else if(s->fat_type==16) {
546 de167e41 bellard
        uint16_t* entry=array_get(&(s->fat),cluster);
547 de167e41 bellard
        *entry=cpu_to_le16(value&0xffff);
548 de167e41 bellard
    } else {
549 a046433a bellard
        int offset = (cluster*3/2);
550 a046433a bellard
        unsigned char* p = array_get(&(s->fat), offset);
551 a046433a bellard
        switch (cluster&1) {
552 a046433a bellard
        case 0:
553 a046433a bellard
                p[0] = value&0xff;
554 a046433a bellard
                p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
555 a046433a bellard
                break;
556 a046433a bellard
        case 1:
557 a046433a bellard
                p[0] = (p[0]&0xf) | ((value&0xf)<<4);
558 a046433a bellard
                p[1] = (value>>4);
559 a046433a bellard
                break;
560 a046433a bellard
        }
561 de167e41 bellard
    }
562 de167e41 bellard
}
563 de167e41 bellard
564 de167e41 bellard
static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
565 de167e41 bellard
{
566 a046433a bellard
    if(s->fat_type==32) {
567 a046433a bellard
        uint32_t* entry=array_get(&(s->fat),cluster);
568 a046433a bellard
        return le32_to_cpu(*entry);
569 de167e41 bellard
    } else if(s->fat_type==16) {
570 de167e41 bellard
        uint16_t* entry=array_get(&(s->fat),cluster);
571 de167e41 bellard
        return le16_to_cpu(*entry);
572 de167e41 bellard
    } else {
573 ffe8ab83 ths
        const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
574 a046433a bellard
        return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
575 de167e41 bellard
    }
576 de167e41 bellard
}
577 de167e41 bellard
578 de167e41 bellard
static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
579 de167e41 bellard
{
580 de167e41 bellard
    if(fat_entry>s->max_fat_value-8)
581 de167e41 bellard
        return -1;
582 de167e41 bellard
    return 0;
583 de167e41 bellard
}
584 de167e41 bellard
585 de167e41 bellard
static inline void init_fat(BDRVVVFATState* s)
586 de167e41 bellard
{
587 a046433a bellard
    if (s->fat_type == 12) {
588 a046433a bellard
        array_init(&(s->fat),1);
589 a046433a bellard
        array_ensure_allocated(&(s->fat),
590 a046433a bellard
                s->sectors_per_fat * 0x200 * 3 / 2 - 1);
591 a046433a bellard
    } else {
592 a046433a bellard
        array_init(&(s->fat),(s->fat_type==32?4:2));
593 a046433a bellard
        array_ensure_allocated(&(s->fat),
594 a046433a bellard
                s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
595 a046433a bellard
    }
596 de167e41 bellard
    memset(s->fat.pointer,0,s->fat.size);
597 3b46e624 ths
598 de167e41 bellard
    switch(s->fat_type) {
599 de167e41 bellard
        case 12: s->max_fat_value=0xfff; break;
600 de167e41 bellard
        case 16: s->max_fat_value=0xffff; break;
601 a046433a bellard
        case 32: s->max_fat_value=0x0fffffff; break;
602 de167e41 bellard
        default: s->max_fat_value=0; /* error... */
603 de167e41 bellard
    }
604 de167e41 bellard
605 de167e41 bellard
}
606 de167e41 bellard
607 a046433a bellard
/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
608 a046433a bellard
/* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
609 c227f099 Anthony Liguori
static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
610 a046433a bellard
        unsigned int directory_start, const char* filename, int is_dot)
611 de167e41 bellard
{
612 a046433a bellard
    int i,j,long_index=s->directory.next;
613 c227f099 Anthony Liguori
    direntry_t* entry = NULL;
614 c227f099 Anthony Liguori
    direntry_t* entry_long = NULL;
615 de167e41 bellard
616 de167e41 bellard
    if(is_dot) {
617 de167e41 bellard
        entry=array_get_next(&(s->directory));
618 de167e41 bellard
        memset(entry->name,0x20,11);
619 de167e41 bellard
        memcpy(entry->name,filename,strlen(filename));
620 de167e41 bellard
        return entry;
621 de167e41 bellard
    }
622 3b46e624 ths
623 de167e41 bellard
    entry_long=create_long_filename(s,filename);
624 3b46e624 ths
625 5fafdf24 ths
    i = strlen(filename);
626 a046433a bellard
    for(j = i - 1; j>0  && filename[j]!='.';j--);
627 a046433a bellard
    if (j > 0)
628 a046433a bellard
        i = (j > 8 ? 8 : j);
629 a046433a bellard
    else if (i > 8)
630 a046433a bellard
        i = 8;
631 a046433a bellard
632 de167e41 bellard
    entry=array_get_next(&(s->directory));
633 de167e41 bellard
    memset(entry->name,0x20,11);
634 51a0f568 blueswir1
    memcpy(entry->name, filename, i);
635 3b46e624 ths
636 a046433a bellard
    if(j > 0)
637 a046433a bellard
        for (i = 0; i < 3 && filename[j+1+i]; i++)
638 a046433a bellard
            entry->extension[i] = filename[j+1+i];
639 de167e41 bellard
640 de167e41 bellard
    /* upcase & remove unwanted characters */
641 de167e41 bellard
    for(i=10;i>=0;i--) {
642 a046433a bellard
        if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
643 de167e41 bellard
        if(entry->name[i]<=' ' || entry->name[i]>0x7f
644 a046433a bellard
                || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
645 de167e41 bellard
            entry->name[i]='_';
646 de167e41 bellard
        else if(entry->name[i]>='a' && entry->name[i]<='z')
647 de167e41 bellard
            entry->name[i]+='A'-'a';
648 de167e41 bellard
    }
649 de167e41 bellard
650 de167e41 bellard
    /* mangle duplicates */
651 de167e41 bellard
    while(1) {
652 c227f099 Anthony Liguori
        direntry_t* entry1=array_get(&(s->directory),directory_start);
653 de167e41 bellard
        int j;
654 de167e41 bellard
655 de167e41 bellard
        for(;entry1<entry;entry1++)
656 a046433a bellard
            if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
657 de167e41 bellard
                break; /* found dupe */
658 de167e41 bellard
        if(entry1==entry) /* no dupe found */
659 de167e41 bellard
            break;
660 de167e41 bellard
661 5fafdf24 ths
        /* use all 8 characters of name */
662 de167e41 bellard
        if(entry->name[7]==' ') {
663 de167e41 bellard
            int j;
664 de167e41 bellard
            for(j=6;j>0 && entry->name[j]==' ';j--)
665 de167e41 bellard
                entry->name[j]='~';
666 de167e41 bellard
        }
667 de167e41 bellard
668 de167e41 bellard
        /* increment number */
669 de167e41 bellard
        for(j=7;j>0 && entry->name[j]=='9';j--)
670 de167e41 bellard
            entry->name[j]='0';
671 de167e41 bellard
        if(j>0) {
672 de167e41 bellard
            if(entry->name[j]<'0' || entry->name[j]>'9')
673 de167e41 bellard
                entry->name[j]='0';
674 de167e41 bellard
            else
675 de167e41 bellard
                entry->name[j]++;
676 de167e41 bellard
        }
677 de167e41 bellard
    }
678 de167e41 bellard
679 de167e41 bellard
    /* calculate checksum; propagate to long name */
680 de167e41 bellard
    if(entry_long) {
681 de167e41 bellard
        uint8_t chksum=fat_chksum(entry);
682 de167e41 bellard
683 de167e41 bellard
        /* calculate anew, because realloc could have taken place */
684 de167e41 bellard
        entry_long=array_get(&(s->directory),long_index);
685 a046433a bellard
        while(entry_long<entry && is_long_name(entry_long)) {
686 de167e41 bellard
            entry_long->reserved[1]=chksum;
687 de167e41 bellard
            entry_long++;
688 de167e41 bellard
        }
689 de167e41 bellard
    }
690 de167e41 bellard
691 de167e41 bellard
    return entry;
692 de167e41 bellard
}
693 de167e41 bellard
694 a046433a bellard
/*
695 a046433a bellard
 * Read a directory. (the index of the corresponding mapping must be passed).
696 a046433a bellard
 */
697 a046433a bellard
static int read_directory(BDRVVVFATState* s, int mapping_index)
698 de167e41 bellard
{
699 c227f099 Anthony Liguori
    mapping_t* mapping = array_get(&(s->mapping), mapping_index);
700 c227f099 Anthony Liguori
    direntry_t* direntry;
701 a046433a bellard
    const char* dirname = mapping->path;
702 a046433a bellard
    int first_cluster = mapping->begin;
703 a046433a bellard
    int parent_index = mapping->info.dir.parent_mapping_index;
704 c227f099 Anthony Liguori
    mapping_t* parent_mapping = (mapping_t*)
705 511d2b14 blueswir1
        (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL);
706 a046433a bellard
    int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
707 de167e41 bellard
708 de167e41 bellard
    DIR* dir=opendir(dirname);
709 de167e41 bellard
    struct dirent* entry;
710 de167e41 bellard
    int i;
711 de167e41 bellard
712 a046433a bellard
    assert(mapping->mode & MODE_DIRECTORY);
713 a046433a bellard
714 a046433a bellard
    if(!dir) {
715 a046433a bellard
        mapping->end = mapping->begin;
716 de167e41 bellard
        return -1;
717 a046433a bellard
    }
718 3b46e624 ths
719 a046433a bellard
    i = mapping->info.dir.first_dir_index =
720 a046433a bellard
            first_cluster == 0 ? 0 : s->directory.next;
721 a046433a bellard
722 5fafdf24 ths
    /* actually read the directory, and allocate the mappings */
723 de167e41 bellard
    while((entry=readdir(dir))) {
724 de167e41 bellard
        unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
725 de167e41 bellard
        char* buffer;
726 c227f099 Anthony Liguori
        direntry_t* direntry;
727 a046433a bellard
        struct stat st;
728 de167e41 bellard
        int is_dot=!strcmp(entry->d_name,".");
729 de167e41 bellard
        int is_dotdot=!strcmp(entry->d_name,"..");
730 de167e41 bellard
731 a046433a bellard
        if(first_cluster == 0 && (is_dotdot || is_dot))
732 de167e41 bellard
            continue;
733 5fafdf24 ths
734 7267c094 Anthony Liguori
        buffer=(char*)g_malloc(length);
735 de167e41 bellard
        snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
736 de167e41 bellard
737 de167e41 bellard
        if(stat(buffer,&st)<0) {
738 ce137829 Stefan Weil
            g_free(buffer);
739 de167e41 bellard
            continue;
740 de167e41 bellard
        }
741 de167e41 bellard
742 de167e41 bellard
        /* create directory entry for this file */
743 a046433a bellard
        direntry=create_short_and_long_name(s, i, entry->d_name,
744 a046433a bellard
                is_dot || is_dotdot);
745 de167e41 bellard
        direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
746 de167e41 bellard
        direntry->reserved[0]=direntry->reserved[1]=0;
747 de167e41 bellard
        direntry->ctime=fat_datetime(st.st_ctime,1);
748 de167e41 bellard
        direntry->cdate=fat_datetime(st.st_ctime,0);
749 de167e41 bellard
        direntry->adate=fat_datetime(st.st_atime,0);
750 de167e41 bellard
        direntry->begin_hi=0;
751 de167e41 bellard
        direntry->mtime=fat_datetime(st.st_mtime,1);
752 de167e41 bellard
        direntry->mdate=fat_datetime(st.st_mtime,0);
753 de167e41 bellard
        if(is_dotdot)
754 a046433a bellard
            set_begin_of_direntry(direntry, first_cluster_of_parent);
755 de167e41 bellard
        else if(is_dot)
756 a046433a bellard
            set_begin_of_direntry(direntry, first_cluster);
757 de167e41 bellard
        else
758 a046433a bellard
            direntry->begin=0; /* do that later */
759 a046433a bellard
        if (st.st_size > 0x7fffffff) {
760 a046433a bellard
            fprintf(stderr, "File %s is larger than 2GB\n", buffer);
761 ce137829 Stefan Weil
            g_free(buffer);
762 08089edc Blue Swirl
            closedir(dir);
763 a046433a bellard
            return -2;
764 a046433a bellard
        }
765 a046433a bellard
        direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
766 de167e41 bellard
767 de167e41 bellard
        /* create mapping for this file */
768 a046433a bellard
        if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
769 c227f099 Anthony Liguori
            s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
770 de167e41 bellard
            s->current_mapping->begin=0;
771 de167e41 bellard
            s->current_mapping->end=st.st_size;
772 a046433a bellard
            /*
773 a046433a bellard
             * we get the direntry of the most recent direntry, which
774 a046433a bellard
             * contains the short name and all the relevant information.
775 a046433a bellard
             */
776 de167e41 bellard
            s->current_mapping->dir_index=s->directory.next-1;
777 a046433a bellard
            s->current_mapping->first_mapping_index = -1;
778 a046433a bellard
            if (S_ISDIR(st.st_mode)) {
779 a046433a bellard
                s->current_mapping->mode = MODE_DIRECTORY;
780 a046433a bellard
                s->current_mapping->info.dir.parent_mapping_index =
781 a046433a bellard
                    mapping_index;
782 a046433a bellard
            } else {
783 a046433a bellard
                s->current_mapping->mode = MODE_UNDEFINED;
784 a046433a bellard
                s->current_mapping->info.file.offset = 0;
785 a046433a bellard
            }
786 a046433a bellard
            s->current_mapping->path=buffer;
787 a046433a bellard
            s->current_mapping->read_only =
788 a046433a bellard
                (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
789 de167e41 bellard
        }
790 de167e41 bellard
    }
791 de167e41 bellard
    closedir(dir);
792 de167e41 bellard
793 de167e41 bellard
    /* fill with zeroes up to the end of the cluster */
794 de167e41 bellard
    while(s->directory.next%(0x10*s->sectors_per_cluster)) {
795 c227f099 Anthony Liguori
        direntry_t* direntry=array_get_next(&(s->directory));
796 c227f099 Anthony Liguori
        memset(direntry,0,sizeof(direntry_t));
797 de167e41 bellard
    }
798 de167e41 bellard
799 a046433a bellard
/* TODO: if there are more entries, bootsector has to be adjusted! */
800 a046433a bellard
#define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
801 a046433a bellard
    if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
802 a046433a bellard
        /* root directory */
803 a046433a bellard
        int cur = s->directory.next;
804 a046433a bellard
        array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
805 2b6a43a8 Paolo Bonzini
        s->directory.next = ROOT_ENTRIES;
806 a046433a bellard
        memset(array_get(&(s->directory), cur), 0,
807 c227f099 Anthony Liguori
                (ROOT_ENTRIES - cur) * sizeof(direntry_t));
808 de167e41 bellard
    }
809 5fafdf24 ths
810 a046433a bellard
     /* reget the mapping, since s->mapping was possibly realloc()ed */
811 c227f099 Anthony Liguori
    mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
812 a046433a bellard
    first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
813 a046433a bellard
        * 0x20 / s->cluster_size;
814 a046433a bellard
    mapping->end = first_cluster;
815 a046433a bellard
816 c227f099 Anthony Liguori
    direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
817 a046433a bellard
    set_begin_of_direntry(direntry, mapping->begin);
818 3b46e624 ths
819 a046433a bellard
    return 0;
820 a046433a bellard
}
821 de167e41 bellard
822 a046433a bellard
static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
823 a046433a bellard
{
824 a046433a bellard
    return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
825 a046433a bellard
}
826 de167e41 bellard
827 a046433a bellard
static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
828 a046433a bellard
{
829 a046433a bellard
    return s->faked_sectors + s->sectors_per_cluster * cluster_num;
830 a046433a bellard
}
831 de167e41 bellard
832 a046433a bellard
static int init_directories(BDRVVVFATState* s,
833 4480e0f9 Markus Armbruster
                            const char *dirname, int heads, int secs)
834 de167e41 bellard
{
835 c227f099 Anthony Liguori
    bootsector_t* bootsector;
836 c227f099 Anthony Liguori
    mapping_t* mapping;
837 de167e41 bellard
    unsigned int i;
838 de167e41 bellard
    unsigned int cluster;
839 de167e41 bellard
840 de167e41 bellard
    memset(&(s->first_sectors[0]),0,0x40*0x200);
841 de167e41 bellard
842 de167e41 bellard
    s->cluster_size=s->sectors_per_cluster*0x200;
843 7267c094 Anthony Liguori
    s->cluster_buffer=g_malloc(s->cluster_size);
844 a046433a bellard
845 a046433a bellard
    /*
846 a046433a bellard
     * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
847 a046433a bellard
     * where sc is sector_count,
848 a046433a bellard
     * spf is sectors_per_fat,
849 a046433a bellard
     * spc is sectors_per_clusters, and
850 a046433a bellard
     * fat_type = 12, 16 or 32.
851 a046433a bellard
     */
852 a046433a bellard
    i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
853 a046433a bellard
    s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
854 3b46e624 ths
855 c227f099 Anthony Liguori
    array_init(&(s->mapping),sizeof(mapping_t));
856 c227f099 Anthony Liguori
    array_init(&(s->directory),sizeof(direntry_t));
857 de167e41 bellard
858 de167e41 bellard
    /* add volume label */
859 de167e41 bellard
    {
860 c227f099 Anthony Liguori
        direntry_t* entry=array_get_next(&(s->directory));
861 de167e41 bellard
        entry->attributes=0x28; /* archive | volume label */
862 2dedf83e Kirill A. Shutemov
        memcpy(entry->name,"QEMU VVF",8);
863 2dedf83e Kirill A. Shutemov
        memcpy(entry->extension,"AT ",3);
864 de167e41 bellard
    }
865 de167e41 bellard
866 de167e41 bellard
    /* Now build FAT, and write back information into directory */
867 de167e41 bellard
    init_fat(s);
868 de167e41 bellard
869 a046433a bellard
    s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
870 a046433a bellard
    s->cluster_count=sector2cluster(s, s->sector_count);
871 a046433a bellard
872 a046433a bellard
    mapping = array_get_next(&(s->mapping));
873 a046433a bellard
    mapping->begin = 0;
874 a046433a bellard
    mapping->dir_index = 0;
875 a046433a bellard
    mapping->info.dir.parent_mapping_index = -1;
876 a046433a bellard
    mapping->first_mapping_index = -1;
877 7267c094 Anthony Liguori
    mapping->path = g_strdup(dirname);
878 a046433a bellard
    i = strlen(mapping->path);
879 a046433a bellard
    if (i > 0 && mapping->path[i - 1] == '/')
880 a046433a bellard
        mapping->path[i - 1] = '\0';
881 a046433a bellard
    mapping->mode = MODE_DIRECTORY;
882 a046433a bellard
    mapping->read_only = 0;
883 a046433a bellard
    s->path = mapping->path;
884 a046433a bellard
885 a046433a bellard
    for (i = 0, cluster = 0; i < s->mapping.next; i++) {
886 5fafdf24 ths
        /* MS-DOS expects the FAT to be 0 for the root directory
887 a046433a bellard
         * (except for the media byte). */
888 a046433a bellard
        /* LATER TODO: still true for FAT32? */
889 a046433a bellard
        int fix_fat = (i != 0);
890 a046433a bellard
        mapping = array_get(&(s->mapping), i);
891 a046433a bellard
892 a046433a bellard
        if (mapping->mode & MODE_DIRECTORY) {
893 a046433a bellard
            mapping->begin = cluster;
894 a046433a bellard
            if(read_directory(s, i)) {
895 a046433a bellard
                fprintf(stderr, "Could not read directory %s\n",
896 a046433a bellard
                        mapping->path);
897 de167e41 bellard
                return -1;
898 de167e41 bellard
            }
899 a046433a bellard
            mapping = array_get(&(s->mapping), i);
900 a046433a bellard
        } else {
901 a046433a bellard
            assert(mapping->mode == MODE_UNDEFINED);
902 de167e41 bellard
            mapping->mode=MODE_NORMAL;
903 a046433a bellard
            mapping->begin = cluster;
904 a046433a bellard
            if (mapping->end > 0) {
905 c227f099 Anthony Liguori
                direntry_t* direntry = array_get(&(s->directory),
906 a046433a bellard
                        mapping->dir_index);
907 a046433a bellard
908 a046433a bellard
                mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
909 a046433a bellard
                set_begin_of_direntry(direntry, mapping->begin);
910 a046433a bellard
            } else {
911 a046433a bellard
                mapping->end = cluster + 1;
912 a046433a bellard
                fix_fat = 0;
913 de167e41 bellard
            }
914 a046433a bellard
        }
915 a046433a bellard
916 a046433a bellard
        assert(mapping->begin < mapping->end);
917 a046433a bellard
918 8ce0f869 balrog
        /* next free cluster */
919 8ce0f869 balrog
        cluster = mapping->end;
920 8ce0f869 balrog
921 8ce0f869 balrog
        if(cluster > s->cluster_count) {
922 d71cff42 Paolo Bonzini
            fprintf(stderr,"Directory does not fit in FAT%d (capacity %.2f MB)\n",
923 d71cff42 Paolo Bonzini
                    s->fat_type, s->sector_count / 2000.0);
924 8ce0f869 balrog
            return -EINVAL;
925 8ce0f869 balrog
        }
926 8ce0f869 balrog
927 a046433a bellard
        /* fix fat for entry */
928 a046433a bellard
        if (fix_fat) {
929 8ce0f869 balrog
            int j;
930 a046433a bellard
            for(j = mapping->begin; j < mapping->end - 1; j++)
931 a046433a bellard
                fat_set(s, j, j+1);
932 a046433a bellard
            fat_set(s, mapping->end - 1, s->max_fat_value);
933 a046433a bellard
        }
934 de167e41 bellard
    }
935 de167e41 bellard
936 a046433a bellard
    mapping = array_get(&(s->mapping), 0);
937 a046433a bellard
    s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
938 a046433a bellard
    s->last_cluster_of_root_directory = mapping->end;
939 a046433a bellard
940 a046433a bellard
    /* the FAT signature */
941 a046433a bellard
    fat_set(s,0,s->max_fat_value);
942 a046433a bellard
    fat_set(s,1,s->max_fat_value);
943 de167e41 bellard
944 a046433a bellard
    s->current_mapping = NULL;
945 a046433a bellard
946 c227f099 Anthony Liguori
    bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
947 de167e41 bellard
    bootsector->jump[0]=0xeb;
948 de167e41 bellard
    bootsector->jump[1]=0x3e;
949 de167e41 bellard
    bootsector->jump[2]=0x90;
950 de167e41 bellard
    memcpy(bootsector->name,"QEMU    ",8);
951 de167e41 bellard
    bootsector->sector_size=cpu_to_le16(0x200);
952 de167e41 bellard
    bootsector->sectors_per_cluster=s->sectors_per_cluster;
953 de167e41 bellard
    bootsector->reserved_sectors=cpu_to_le16(1);
954 de167e41 bellard
    bootsector->number_of_fats=0x2; /* number of FATs */
955 de167e41 bellard
    bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
956 a046433a bellard
    bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
957 aad37c06 Paolo Bonzini
    bootsector->media_type=(s->first_sectors_number>1?0xf8:0xf0); /* media descriptor (f8=hd, f0=3.5 fd)*/
958 a046433a bellard
    s->fat.pointer[0] = bootsector->media_type;
959 de167e41 bellard
    bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
960 4480e0f9 Markus Armbruster
    bootsector->sectors_per_track = cpu_to_le16(secs);
961 4480e0f9 Markus Armbruster
    bootsector->number_of_heads = cpu_to_le16(heads);
962 de167e41 bellard
    bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
963 a046433a bellard
    bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
964 de167e41 bellard
965 a046433a bellard
    /* LATER TODO: if FAT32, this is wrong */
966 aad37c06 Paolo Bonzini
    bootsector->u.fat16.drive_number=s->first_sectors_number==1?0:0x80; /* fda=0, hda=0x80 */
967 de167e41 bellard
    bootsector->u.fat16.current_head=0;
968 de167e41 bellard
    bootsector->u.fat16.signature=0x29;
969 de167e41 bellard
    bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
970 de167e41 bellard
971 de167e41 bellard
    memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
972 de167e41 bellard
    memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12   ":s->fat_type==16?"FAT16   ":"FAT32   "),8);
973 de167e41 bellard
    bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
974 de167e41 bellard
975 de167e41 bellard
    return 0;
976 de167e41 bellard
}
977 de167e41 bellard
978 83f64091 bellard
#ifdef DEBUG
979 a046433a bellard
static BDRVVVFATState *vvv = NULL;
980 83f64091 bellard
#endif
981 a046433a bellard
982 a046433a bellard
static int enable_write_target(BDRVVVFATState *s);
983 a046433a bellard
static int is_consistent(BDRVVVFATState *s);
984 a046433a bellard
985 e023b2e2 Paolo Bonzini
static void vvfat_rebind(BlockDriverState *bs)
986 e023b2e2 Paolo Bonzini
{
987 e023b2e2 Paolo Bonzini
    BDRVVVFATState *s = bs->opaque;
988 e023b2e2 Paolo Bonzini
    s->bs = bs;
989 e023b2e2 Paolo Bonzini
}
990 e023b2e2 Paolo Bonzini
991 83f64091 bellard
static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
992 de167e41 bellard
{
993 de167e41 bellard
    BDRVVVFATState *s = bs->opaque;
994 4480e0f9 Markus Armbruster
    int i, cyls, heads, secs;
995 de167e41 bellard
996 83f64091 bellard
#ifdef DEBUG
997 a046433a bellard
    vvv = s;
998 83f64091 bellard
#endif
999 a046433a bellard
1000 a046433a bellard
DLOG(if (stderr == NULL) {
1001 a046433a bellard
    stderr = fopen("vvfat.log", "a");
1002 a046433a bellard
    setbuf(stderr, NULL);
1003 a046433a bellard
})
1004 a046433a bellard
1005 a046433a bellard
    s->bs = bs;
1006 a046433a bellard
1007 a046433a bellard
    /* LATER TODO: if FAT32, adjust */
1008 a046433a bellard
    s->sectors_per_cluster=0x10;
1009 de167e41 bellard
1010 de167e41 bellard
    s->current_cluster=0xffffffff;
1011 de167e41 bellard
1012 de167e41 bellard
    s->first_sectors_number=0x40;
1013 a046433a bellard
    /* read only is the default for safety */
1014 a046433a bellard
    bs->read_only = 1;
1015 a046433a bellard
    s->qcow = s->write_target = NULL;
1016 a046433a bellard
    s->qcow_filename = NULL;
1017 a046433a bellard
    s->fat2 = NULL;
1018 a046433a bellard
    s->downcase_short_names = 1;
1019 3b46e624 ths
1020 a046433a bellard
    if (!strstart(dirname, "fat:", NULL))
1021 a046433a bellard
        return -1;
1022 a046433a bellard
1023 a046433a bellard
    if (strstr(dirname, ":32:")) {
1024 a046433a bellard
        fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1025 a046433a bellard
        s->fat_type = 32;
1026 a046433a bellard
    } else if (strstr(dirname, ":16:")) {
1027 a046433a bellard
        s->fat_type = 16;
1028 a046433a bellard
    } else if (strstr(dirname, ":12:")) {
1029 a046433a bellard
        s->fat_type = 12;
1030 273e4e03 Paolo Bonzini
    }
1031 273e4e03 Paolo Bonzini
1032 273e4e03 Paolo Bonzini
    if (strstr(dirname, ":floppy:")) {
1033 273e4e03 Paolo Bonzini
        /* 1.44MB or 2.88MB floppy.  2.88MB can be FAT12 (default) or FAT16. */
1034 273e4e03 Paolo Bonzini
        if (!s->fat_type) {
1035 273e4e03 Paolo Bonzini
            s->fat_type = 12;
1036 4480e0f9 Markus Armbruster
            secs = 36;
1037 273e4e03 Paolo Bonzini
            s->sectors_per_cluster=2;
1038 273e4e03 Paolo Bonzini
        } else {
1039 4480e0f9 Markus Armbruster
            secs = s->fat_type == 12 ? 18 : 36;
1040 273e4e03 Paolo Bonzini
            s->sectors_per_cluster=1;
1041 273e4e03 Paolo Bonzini
        }
1042 273e4e03 Paolo Bonzini
        s->first_sectors_number = 1;
1043 4480e0f9 Markus Armbruster
        cyls = 80;
1044 4480e0f9 Markus Armbruster
        heads = 2;
1045 273e4e03 Paolo Bonzini
    } else {
1046 273e4e03 Paolo Bonzini
        /* 32MB or 504MB disk*/
1047 273e4e03 Paolo Bonzini
        if (!s->fat_type) {
1048 273e4e03 Paolo Bonzini
            s->fat_type = 16;
1049 273e4e03 Paolo Bonzini
        }
1050 4480e0f9 Markus Armbruster
        cyls = s->fat_type == 12 ? 64 : 1024;
1051 4480e0f9 Markus Armbruster
        heads = 16;
1052 4480e0f9 Markus Armbruster
        secs = 63;
1053 de167e41 bellard
    }
1054 4480e0f9 Markus Armbruster
    fprintf(stderr, "vvfat %s chs %d,%d,%d\n",
1055 4480e0f9 Markus Armbruster
            dirname, cyls, heads, secs);
1056 a046433a bellard
1057 4480e0f9 Markus Armbruster
    s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
1058 5a742b55 Paolo Bonzini
1059 b570094d ths
    if (strstr(dirname, ":rw:")) {
1060 b570094d ths
        if (enable_write_target(s))
1061 b570094d ths
            return -1;
1062 b570094d ths
        bs->read_only = 0;
1063 b570094d ths
    }
1064 b570094d ths
1065 a046433a bellard
    i = strrchr(dirname, ':') - dirname;
1066 a046433a bellard
    assert(i >= 3);
1067 cd390083 blueswir1
    if (dirname[i-2] == ':' && qemu_isalpha(dirname[i-1]))
1068 a046433a bellard
        /* workaround for DOS drive names */
1069 a046433a bellard
        dirname += i-1;
1070 a046433a bellard
    else
1071 a046433a bellard
        dirname += i+1;
1072 a046433a bellard
1073 4480e0f9 Markus Armbruster
    bs->total_sectors = cyls * heads * secs;
1074 b570094d ths
1075 4480e0f9 Markus Armbruster
    if (init_directories(s, dirname, heads, secs)) {
1076 de167e41 bellard
        return -1;
1077 4480e0f9 Markus Armbruster
    }
1078 de167e41 bellard
1079 b570094d ths
    s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
1080 b570094d ths
1081 4480e0f9 Markus Armbruster
    if (s->first_sectors_number == 0x40) {
1082 4480e0f9 Markus Armbruster
        init_mbr(s, cyls, heads, secs);
1083 273e4e03 Paolo Bonzini
    }
1084 a046433a bellard
1085 a046433a bellard
    //    assert(is_consistent(s));
1086 848c66e8 Paolo Bonzini
    qemu_co_mutex_init(&s->lock);
1087 3397f0cb Kevin Wolf
1088 3397f0cb Kevin Wolf
    /* Disable migration when vvfat is used rw */
1089 3397f0cb Kevin Wolf
    if (s->qcow) {
1090 3397f0cb Kevin Wolf
        error_set(&s->migration_blocker,
1091 3397f0cb Kevin Wolf
                  QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
1092 3397f0cb Kevin Wolf
                  "vvfat (rw)", bs->device_name, "live migration");
1093 3397f0cb Kevin Wolf
        migrate_add_blocker(s->migration_blocker);
1094 3397f0cb Kevin Wolf
    }
1095 3397f0cb Kevin Wolf
1096 de167e41 bellard
    return 0;
1097 de167e41 bellard
}
1098 de167e41 bellard
1099 de167e41 bellard
static inline void vvfat_close_current_file(BDRVVVFATState *s)
1100 de167e41 bellard
{
1101 de167e41 bellard
    if(s->current_mapping) {
1102 a046433a bellard
        s->current_mapping = NULL;
1103 a046433a bellard
        if (s->current_fd) {
1104 2e1e79da Corey Bryant
                qemu_close(s->current_fd);
1105 a046433a bellard
                s->current_fd = 0;
1106 a046433a bellard
        }
1107 de167e41 bellard
    }
1108 a046433a bellard
    s->current_cluster = -1;
1109 de167e41 bellard
}
1110 de167e41 bellard
1111 de167e41 bellard
/* mappings between index1 and index2-1 are supposed to be ordered
1112 de167e41 bellard
 * return value is the index of the last mapping for which end>cluster_num
1113 de167e41 bellard
 */
1114 de167e41 bellard
static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1115 de167e41 bellard
{
1116 de167e41 bellard
    while(1) {
1117 88bf7950 Blue Swirl
        int index3;
1118 c227f099 Anthony Liguori
        mapping_t* mapping;
1119 de167e41 bellard
        index3=(index1+index2)/2;
1120 de167e41 bellard
        mapping=array_get(&(s->mapping),index3);
1121 a046433a bellard
        assert(mapping->begin < mapping->end);
1122 a046433a bellard
        if(mapping->begin>=cluster_num) {
1123 de167e41 bellard
            assert(index2!=index3 || index2==0);
1124 de167e41 bellard
            if(index2==index3)
1125 a046433a bellard
                return index1;
1126 de167e41 bellard
            index2=index3;
1127 de167e41 bellard
        } else {
1128 de167e41 bellard
            if(index1==index3)
1129 a046433a bellard
                return mapping->end<=cluster_num ? index2 : index1;
1130 de167e41 bellard
            index1=index3;
1131 de167e41 bellard
        }
1132 de167e41 bellard
        assert(index1<=index2);
1133 a046433a bellard
        DLOG(mapping=array_get(&(s->mapping),index1);
1134 a046433a bellard
        assert(mapping->begin<=cluster_num);
1135 5fafdf24 ths
        assert(index2 >= s->mapping.next ||
1136 a046433a bellard
                ((mapping = array_get(&(s->mapping),index2)) &&
1137 a046433a bellard
                mapping->end>cluster_num)));
1138 de167e41 bellard
    }
1139 de167e41 bellard
}
1140 de167e41 bellard
1141 c227f099 Anthony Liguori
static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
1142 de167e41 bellard
{
1143 de167e41 bellard
    int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
1144 c227f099 Anthony Liguori
    mapping_t* mapping;
1145 de167e41 bellard
    if(index>=s->mapping.next)
1146 511d2b14 blueswir1
        return NULL;
1147 de167e41 bellard
    mapping=array_get(&(s->mapping),index);
1148 de167e41 bellard
    if(mapping->begin>cluster_num)
1149 511d2b14 blueswir1
        return NULL;
1150 a046433a bellard
    assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
1151 de167e41 bellard
    return mapping;
1152 de167e41 bellard
}
1153 de167e41 bellard
1154 c227f099 Anthony Liguori
static int open_file(BDRVVVFATState* s,mapping_t* mapping)
1155 de167e41 bellard
{
1156 de167e41 bellard
    if(!mapping)
1157 de167e41 bellard
        return -1;
1158 de167e41 bellard
    if(!s->current_mapping ||
1159 a046433a bellard
            strcmp(s->current_mapping->path,mapping->path)) {
1160 de167e41 bellard
        /* open file */
1161 6165f4d8 Corey Bryant
        int fd = qemu_open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
1162 de167e41 bellard
        if(fd<0)
1163 de167e41 bellard
            return -1;
1164 de167e41 bellard
        vvfat_close_current_file(s);
1165 de167e41 bellard
        s->current_fd = fd;
1166 de167e41 bellard
        s->current_mapping = mapping;
1167 de167e41 bellard
    }
1168 de167e41 bellard
    return 0;
1169 de167e41 bellard
}
1170 de167e41 bellard
1171 de167e41 bellard
static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1172 de167e41 bellard
{
1173 de167e41 bellard
    if(s->current_cluster != cluster_num) {
1174 de167e41 bellard
        int result=0;
1175 de167e41 bellard
        off_t offset;
1176 a046433a bellard
        assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
1177 de167e41 bellard
        if(!s->current_mapping
1178 de167e41 bellard
                || s->current_mapping->begin>cluster_num
1179 de167e41 bellard
                || s->current_mapping->end<=cluster_num) {
1180 de167e41 bellard
            /* binary search of mappings for file */
1181 c227f099 Anthony Liguori
            mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
1182 a046433a bellard
1183 a046433a bellard
            assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1184 a046433a bellard
1185 a046433a bellard
            if (mapping && mapping->mode & MODE_DIRECTORY) {
1186 a046433a bellard
                vvfat_close_current_file(s);
1187 a046433a bellard
                s->current_mapping = mapping;
1188 a046433a bellard
read_cluster_directory:
1189 a046433a bellard
                offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
1190 ffe8ab83 ths
                s->cluster = (unsigned char*)s->directory.pointer+offset
1191 a046433a bellard
                        + 0x20*s->current_mapping->info.dir.first_dir_index;
1192 a046433a bellard
                assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1193 a046433a bellard
                assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1194 a046433a bellard
                s->current_cluster = cluster_num;
1195 a046433a bellard
                return 0;
1196 a046433a bellard
            }
1197 a046433a bellard
1198 a046433a bellard
            if(open_file(s,mapping))
1199 de167e41 bellard
                return -2;
1200 a046433a bellard
        } else if (s->current_mapping->mode & MODE_DIRECTORY)
1201 a046433a bellard
            goto read_cluster_directory;
1202 de167e41 bellard
1203 a046433a bellard
        assert(s->current_fd);
1204 a046433a bellard
1205 a046433a bellard
        offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
1206 de167e41 bellard
        if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1207 de167e41 bellard
            return -3;
1208 a046433a bellard
        s->cluster=s->cluster_buffer;
1209 de167e41 bellard
        result=read(s->current_fd,s->cluster,s->cluster_size);
1210 de167e41 bellard
        if(result<0) {
1211 de167e41 bellard
            s->current_cluster = -1;
1212 de167e41 bellard
            return -1;
1213 de167e41 bellard
        }
1214 de167e41 bellard
        s->current_cluster = cluster_num;
1215 de167e41 bellard
    }
1216 de167e41 bellard
    return 0;
1217 de167e41 bellard
}
1218 de167e41 bellard
1219 a046433a bellard
#ifdef DEBUG
1220 c227f099 Anthony Liguori
static void print_direntry(const direntry_t* direntry)
1221 de167e41 bellard
{
1222 a046433a bellard
    int j = 0;
1223 a046433a bellard
    char buffer[1024];
1224 a046433a bellard
1225 3e89cb04 Kevin Wolf
    fprintf(stderr, "direntry %p: ", direntry);
1226 de167e41 bellard
    if(!direntry)
1227 de167e41 bellard
        return;
1228 a046433a bellard
    if(is_long_name(direntry)) {
1229 de167e41 bellard
        unsigned char* c=(unsigned char*)direntry;
1230 de167e41 bellard
        int i;
1231 de167e41 bellard
        for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
1232 3891b370 blueswir1
#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
1233 a046433a bellard
            ADD_CHAR(c[i]);
1234 de167e41 bellard
        for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
1235 a046433a bellard
            ADD_CHAR(c[i]);
1236 de167e41 bellard
        for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
1237 a046433a bellard
            ADD_CHAR(c[i]);
1238 a046433a bellard
        buffer[j] = 0;
1239 a046433a bellard
        fprintf(stderr, "%s\n", buffer);
1240 de167e41 bellard
    } else {
1241 de167e41 bellard
        int i;
1242 de167e41 bellard
        for(i=0;i<11;i++)
1243 a046433a bellard
            ADD_CHAR(direntry->name[i]);
1244 a046433a bellard
        buffer[j] = 0;
1245 a046433a bellard
        fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1246 a046433a bellard
                buffer,
1247 de167e41 bellard
                direntry->attributes,
1248 a046433a bellard
                begin_of_direntry(direntry),le32_to_cpu(direntry->size));
1249 de167e41 bellard
    }
1250 de167e41 bellard
}
1251 de167e41 bellard
1252 c227f099 Anthony Liguori
static void print_mapping(const mapping_t* mapping)
1253 de167e41 bellard
{
1254 3e89cb04 Kevin Wolf
    fprintf(stderr, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1255 3e89cb04 Kevin Wolf
        "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1256 3e89cb04 Kevin Wolf
        mapping, mapping->begin, mapping->end, mapping->dir_index,
1257 3e89cb04 Kevin Wolf
        mapping->first_mapping_index, mapping->path, mapping->mode);
1258 3e89cb04 Kevin Wolf
1259 a046433a bellard
    if (mapping->mode & MODE_DIRECTORY)
1260 a046433a bellard
        fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1261 a046433a bellard
    else
1262 a046433a bellard
        fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
1263 de167e41 bellard
}
1264 a046433a bellard
#endif
1265 de167e41 bellard
1266 5fafdf24 ths
static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
1267 a046433a bellard
                    uint8_t *buf, int nb_sectors)
1268 de167e41 bellard
{
1269 a046433a bellard
    BDRVVVFATState *s = bs->opaque;
1270 de167e41 bellard
    int i;
1271 de167e41 bellard
1272 a046433a bellard
    for(i=0;i<nb_sectors;i++,sector_num++) {
1273 e654bfe4 Paolo Bonzini
        if (sector_num >= bs->total_sectors)
1274 a046433a bellard
           return -1;
1275 a046433a bellard
        if (s->qcow) {
1276 a046433a bellard
            int n;
1277 7704df98 Kevin Wolf
            if (bdrv_is_allocated(s->qcow, sector_num, nb_sectors-i, &n)) {
1278 a046433a bellard
DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
1279 7704df98 Kevin Wolf
                if (bdrv_read(s->qcow, sector_num, buf + i*0x200, n)) {
1280 7704df98 Kevin Wolf
                    return -1;
1281 7704df98 Kevin Wolf
                }
1282 7704df98 Kevin Wolf
                i += n - 1;
1283 7704df98 Kevin Wolf
                sector_num += n - 1;
1284 7704df98 Kevin Wolf
                continue;
1285 7704df98 Kevin Wolf
            }
1286 a046433a bellard
DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
1287 de167e41 bellard
        }
1288 a046433a bellard
        if(sector_num<s->faked_sectors) {
1289 a046433a bellard
            if(sector_num<s->first_sectors_number)
1290 a046433a bellard
                memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
1291 a046433a bellard
            else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
1292 a046433a bellard
                memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
1293 a046433a bellard
            else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
1294 a046433a bellard
                memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
1295 a046433a bellard
        } else {
1296 a046433a bellard
            uint32_t sector=sector_num-s->faked_sectors,
1297 a046433a bellard
            sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1298 a046433a bellard
            cluster_num=sector/s->sectors_per_cluster;
1299 e654bfe4 Paolo Bonzini
            if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) {
1300 a046433a bellard
                /* LATER TODO: strict: return -1; */
1301 a046433a bellard
                memset(buf+i*0x200,0,0x200);
1302 a046433a bellard
                continue;
1303 de167e41 bellard
            }
1304 a046433a bellard
            memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
1305 de167e41 bellard
        }
1306 de167e41 bellard
    }
1307 de167e41 bellard
    return 0;
1308 de167e41 bellard
}
1309 de167e41 bellard
1310 2914caa0 Paolo Bonzini
static coroutine_fn int vvfat_co_read(BlockDriverState *bs, int64_t sector_num,
1311 2914caa0 Paolo Bonzini
                                      uint8_t *buf, int nb_sectors)
1312 2914caa0 Paolo Bonzini
{
1313 2914caa0 Paolo Bonzini
    int ret;
1314 2914caa0 Paolo Bonzini
    BDRVVVFATState *s = bs->opaque;
1315 2914caa0 Paolo Bonzini
    qemu_co_mutex_lock(&s->lock);
1316 2914caa0 Paolo Bonzini
    ret = vvfat_read(bs, sector_num, buf, nb_sectors);
1317 2914caa0 Paolo Bonzini
    qemu_co_mutex_unlock(&s->lock);
1318 2914caa0 Paolo Bonzini
    return ret;
1319 2914caa0 Paolo Bonzini
}
1320 2914caa0 Paolo Bonzini
1321 a046433a bellard
/* LATER TODO: statify all functions */
1322 de167e41 bellard
1323 a046433a bellard
/*
1324 a046433a bellard
 * Idea of the write support (use snapshot):
1325 de167e41 bellard
 *
1326 a046433a bellard
 * 1. check if all data is consistent, recording renames, modifications,
1327 a046433a bellard
 *    new files and directories (in s->commits).
1328 de167e41 bellard
 *
1329 a046433a bellard
 * 2. if the data is not consistent, stop committing
1330 de167e41 bellard
 *
1331 a046433a bellard
 * 3. handle renames, and create new files and directories (do not yet
1332 a046433a bellard
 *    write their contents)
1333 de167e41 bellard
 *
1334 a046433a bellard
 * 4. walk the directories, fixing the mapping and direntries, and marking
1335 a046433a bellard
 *    the handled mappings as not deleted
1336 de167e41 bellard
 *
1337 a046433a bellard
 * 5. commit the contents of the files
1338 de167e41 bellard
 *
1339 a046433a bellard
 * 6. handle deleted files and directories
1340 de167e41 bellard
 *
1341 de167e41 bellard
 */
1342 de167e41 bellard
1343 c227f099 Anthony Liguori
typedef struct commit_t {
1344 a046433a bellard
    char* path;
1345 a046433a bellard
    union {
1346 a046433a bellard
        struct { uint32_t cluster; } rename;
1347 a046433a bellard
        struct { int dir_index; uint32_t modified_offset; } writeout;
1348 a046433a bellard
        struct { uint32_t first_cluster; } new_file;
1349 a046433a bellard
        struct { uint32_t cluster; } mkdir;
1350 a046433a bellard
    } param;
1351 a046433a bellard
    /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1352 a046433a bellard
    enum {
1353 a046433a bellard
        ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1354 a046433a bellard
    } action;
1355 c227f099 Anthony Liguori
} commit_t;
1356 de167e41 bellard
1357 a046433a bellard
static void clear_commits(BDRVVVFATState* s)
1358 de167e41 bellard
{
1359 de167e41 bellard
    int i;
1360 a046433a bellard
DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1361 a046433a bellard
    for (i = 0; i < s->commits.next; i++) {
1362 c227f099 Anthony Liguori
        commit_t* commit = array_get(&(s->commits), i);
1363 a046433a bellard
        assert(commit->path || commit->action == ACTION_WRITEOUT);
1364 a046433a bellard
        if (commit->action != ACTION_WRITEOUT) {
1365 a046433a bellard
            assert(commit->path);
1366 ce137829 Stefan Weil
            g_free(commit->path);
1367 a046433a bellard
        } else
1368 a046433a bellard
            assert(commit->path == NULL);
1369 de167e41 bellard
    }
1370 a046433a bellard
    s->commits.next = 0;
1371 de167e41 bellard
}
1372 de167e41 bellard
1373 a046433a bellard
static void schedule_rename(BDRVVVFATState* s,
1374 a046433a bellard
        uint32_t cluster, char* new_path)
1375 de167e41 bellard
{
1376 c227f099 Anthony Liguori
    commit_t* commit = array_get_next(&(s->commits));
1377 a046433a bellard
    commit->path = new_path;
1378 a046433a bellard
    commit->param.rename.cluster = cluster;
1379 a046433a bellard
    commit->action = ACTION_RENAME;
1380 de167e41 bellard
}
1381 de167e41 bellard
1382 a046433a bellard
static void schedule_writeout(BDRVVVFATState* s,
1383 a046433a bellard
        int dir_index, uint32_t modified_offset)
1384 de167e41 bellard
{
1385 c227f099 Anthony Liguori
    commit_t* commit = array_get_next(&(s->commits));
1386 a046433a bellard
    commit->path = NULL;
1387 a046433a bellard
    commit->param.writeout.dir_index = dir_index;
1388 a046433a bellard
    commit->param.writeout.modified_offset = modified_offset;
1389 a046433a bellard
    commit->action = ACTION_WRITEOUT;
1390 de167e41 bellard
}
1391 de167e41 bellard
1392 a046433a bellard
static void schedule_new_file(BDRVVVFATState* s,
1393 a046433a bellard
        char* path, uint32_t first_cluster)
1394 de167e41 bellard
{
1395 c227f099 Anthony Liguori
    commit_t* commit = array_get_next(&(s->commits));
1396 a046433a bellard
    commit->path = path;
1397 a046433a bellard
    commit->param.new_file.first_cluster = first_cluster;
1398 a046433a bellard
    commit->action = ACTION_NEW_FILE;
1399 a046433a bellard
}
1400 a046433a bellard
1401 a046433a bellard
static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1402 a046433a bellard
{
1403 c227f099 Anthony Liguori
    commit_t* commit = array_get_next(&(s->commits));
1404 a046433a bellard
    commit->path = path;
1405 a046433a bellard
    commit->param.mkdir.cluster = cluster;
1406 a046433a bellard
    commit->action = ACTION_MKDIR;
1407 a046433a bellard
}
1408 a046433a bellard
1409 a046433a bellard
typedef struct {
1410 64eaabda ths
    /*
1411 64eaabda ths
     * Since the sequence number is at most 0x3f, and the filename
1412 64eaabda ths
     * length is at most 13 times the sequence number, the maximal
1413 64eaabda ths
     * filename length is 0x3f * 13 bytes.
1414 64eaabda ths
     */
1415 64eaabda ths
    unsigned char name[0x3f * 13 + 1];
1416 a046433a bellard
    int checksum, len;
1417 a046433a bellard
    int sequence_number;
1418 a046433a bellard
} long_file_name;
1419 a046433a bellard
1420 a046433a bellard
static void lfn_init(long_file_name* lfn)
1421 a046433a bellard
{
1422 a046433a bellard
   lfn->sequence_number = lfn->len = 0;
1423 a046433a bellard
   lfn->checksum = 0x100;
1424 a046433a bellard
}
1425 a046433a bellard
1426 a046433a bellard
/* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1427 a046433a bellard
static int parse_long_name(long_file_name* lfn,
1428 c227f099 Anthony Liguori
        const direntry_t* direntry)
1429 a046433a bellard
{
1430 a046433a bellard
    int i, j, offset;
1431 a046433a bellard
    const unsigned char* pointer = (const unsigned char*)direntry;
1432 a046433a bellard
1433 a046433a bellard
    if (!is_long_name(direntry))
1434 a046433a bellard
        return 1;
1435 a046433a bellard
1436 a046433a bellard
    if (pointer[0] & 0x40) {
1437 a046433a bellard
        lfn->sequence_number = pointer[0] & 0x3f;
1438 a046433a bellard
        lfn->checksum = pointer[13];
1439 a046433a bellard
        lfn->name[0] = 0;
1440 59fdb018 ths
        lfn->name[lfn->sequence_number * 13] = 0;
1441 a046433a bellard
    } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
1442 a046433a bellard
        return -1;
1443 a046433a bellard
    else if (pointer[13] != lfn->checksum)
1444 a046433a bellard
        return -2;
1445 a046433a bellard
    else if (pointer[12] || pointer[26] || pointer[27])
1446 a046433a bellard
        return -3;
1447 a046433a bellard
1448 a046433a bellard
    offset = 13 * (lfn->sequence_number - 1);
1449 a046433a bellard
    for (i = 0, j = 1; i < 13; i++, j+=2) {
1450 a046433a bellard
        if (j == 11)
1451 a046433a bellard
            j = 14;
1452 a046433a bellard
        else if (j == 26)
1453 a046433a bellard
            j = 28;
1454 a046433a bellard
1455 a046433a bellard
        if (pointer[j+1] == 0)
1456 a046433a bellard
            lfn->name[offset + i] = pointer[j];
1457 a046433a bellard
        else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1458 a046433a bellard
            return -4;
1459 a046433a bellard
        else
1460 a046433a bellard
            lfn->name[offset + i] = 0;
1461 de167e41 bellard
    }
1462 a046433a bellard
1463 a046433a bellard
    if (pointer[0] & 0x40)
1464 ffe8ab83 ths
        lfn->len = offset + strlen((char*)lfn->name + offset);
1465 a046433a bellard
1466 de167e41 bellard
    return 0;
1467 de167e41 bellard
}
1468 de167e41 bellard
1469 a046433a bellard
/* returns 0 if successful, >0 if no short_name, and <0 on error */
1470 a046433a bellard
static int parse_short_name(BDRVVVFATState* s,
1471 c227f099 Anthony Liguori
        long_file_name* lfn, direntry_t* direntry)
1472 de167e41 bellard
{
1473 a046433a bellard
    int i, j;
1474 de167e41 bellard
1475 a046433a bellard
    if (!is_short_name(direntry))
1476 a046433a bellard
        return 1;
1477 a046433a bellard
1478 a046433a bellard
    for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1479 a046433a bellard
    for (i = 0; i <= j; i++) {
1480 a046433a bellard
        if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
1481 a046433a bellard
            return -1;
1482 a046433a bellard
        else if (s->downcase_short_names)
1483 47398b9c blueswir1
            lfn->name[i] = qemu_tolower(direntry->name[i]);
1484 a046433a bellard
        else
1485 a046433a bellard
            lfn->name[i] = direntry->name[i];
1486 de167e41 bellard
    }
1487 de167e41 bellard
1488 a046433a bellard
    for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
1489 a046433a bellard
    if (j >= 0) {
1490 a046433a bellard
        lfn->name[i++] = '.';
1491 a046433a bellard
        lfn->name[i + j + 1] = '\0';
1492 a046433a bellard
        for (;j >= 0; j--) {
1493 a046433a bellard
            if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
1494 a046433a bellard
                return -2;
1495 a046433a bellard
            else if (s->downcase_short_names)
1496 47398b9c blueswir1
                lfn->name[i + j] = qemu_tolower(direntry->extension[j]);
1497 a046433a bellard
            else
1498 a046433a bellard
                lfn->name[i + j] = direntry->extension[j];
1499 a046433a bellard
        }
1500 a046433a bellard
    } else
1501 a046433a bellard
        lfn->name[i + j + 1] = '\0';
1502 a046433a bellard
1503 ffe8ab83 ths
    lfn->len = strlen((char*)lfn->name);
1504 a046433a bellard
1505 a046433a bellard
    return 0;
1506 de167e41 bellard
}
1507 de167e41 bellard
1508 a046433a bellard
static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1509 a046433a bellard
        unsigned int cluster)
1510 de167e41 bellard
{
1511 a046433a bellard
    if (cluster < s->last_cluster_of_root_directory) {
1512 a046433a bellard
        if (cluster + 1 == s->last_cluster_of_root_directory)
1513 a046433a bellard
            return s->max_fat_value;
1514 a046433a bellard
        else
1515 a046433a bellard
            return cluster + 1;
1516 a046433a bellard
    }
1517 a046433a bellard
1518 a046433a bellard
    if (s->fat_type==32) {
1519 a046433a bellard
        uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1520 a046433a bellard
        return le32_to_cpu(*entry);
1521 a046433a bellard
    } else if (s->fat_type==16) {
1522 a046433a bellard
        uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1523 a046433a bellard
        return le16_to_cpu(*entry);
1524 a046433a bellard
    } else {
1525 a046433a bellard
        const uint8_t* x=s->fat2+cluster*3/2;
1526 a046433a bellard
        return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1527 a046433a bellard
    }
1528 a046433a bellard
}
1529 a046433a bellard
1530 a046433a bellard
static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1531 a046433a bellard
{
1532 a046433a bellard
    int was_modified = 0;
1533 a046433a bellard
    int i, dummy;
1534 a046433a bellard
1535 a046433a bellard
    if (s->qcow == NULL)
1536 de167e41 bellard
        return 0;
1537 a046433a bellard
1538 a046433a bellard
    for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
1539 7704df98 Kevin Wolf
        was_modified = bdrv_is_allocated(s->qcow,
1540 a046433a bellard
                cluster2sector(s, cluster_num) + i, 1, &dummy);
1541 a046433a bellard
1542 a046433a bellard
    return was_modified;
1543 de167e41 bellard
}
1544 de167e41 bellard
1545 a046433a bellard
static const char* get_basename(const char* path)
1546 de167e41 bellard
{
1547 a046433a bellard
    char* basename = strrchr(path, '/');
1548 a046433a bellard
    if (basename == NULL)
1549 a046433a bellard
        return path;
1550 a046433a bellard
    else
1551 a046433a bellard
        return basename + 1; /* strip '/' */
1552 de167e41 bellard
}
1553 de167e41 bellard
1554 a046433a bellard
/*
1555 a046433a bellard
 * The array s->used_clusters holds the states of the clusters. If it is
1556 a046433a bellard
 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1557 a046433a bellard
 * was modified, bit 3 is set.
1558 a046433a bellard
 * If any cluster is allocated, but not part of a file or directory, this
1559 a046433a bellard
 * driver refuses to commit.
1560 a046433a bellard
 */
1561 a046433a bellard
typedef enum {
1562 a046433a bellard
     USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
1563 c227f099 Anthony Liguori
} used_t;
1564 de167e41 bellard
1565 a046433a bellard
/*
1566 a046433a bellard
 * get_cluster_count_for_direntry() not only determines how many clusters
1567 a046433a bellard
 * are occupied by direntry, but also if it was renamed or modified.
1568 a046433a bellard
 *
1569 a046433a bellard
 * A file is thought to be renamed *only* if there already was a file with
1570 a046433a bellard
 * exactly the same first cluster, but a different name.
1571 a046433a bellard
 *
1572 a046433a bellard
 * Further, the files/directories handled by this function are
1573 a046433a bellard
 * assumed to be *not* deleted (and *only* those).
1574 a046433a bellard
 */
1575 a046433a bellard
static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
1576 c227f099 Anthony Liguori
        direntry_t* direntry, const char* path)
1577 de167e41 bellard
{
1578 a046433a bellard
    /*
1579 a046433a bellard
     * This is a little bit tricky:
1580 a046433a bellard
     * IF the guest OS just inserts a cluster into the file chain,
1581 a046433a bellard
     * and leaves the rest alone, (i.e. the original file had clusters
1582 a046433a bellard
     * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1583 a046433a bellard
     *
1584 a046433a bellard
     * - do_commit will write the cluster into the file at the given
1585 a046433a bellard
     *   offset, but
1586 a046433a bellard
     *
1587 a046433a bellard
     * - the cluster which is overwritten should be moved to a later
1588 a046433a bellard
     *   position in the file.
1589 a046433a bellard
     *
1590 a046433a bellard
     * I am not aware that any OS does something as braindead, but this
1591 a046433a bellard
     * situation could happen anyway when not committing for a long time.
1592 a046433a bellard
     * Just to be sure that this does not bite us, detect it, and copy the
1593 a046433a bellard
     * contents of the clusters to-be-overwritten into the qcow.
1594 a046433a bellard
     */
1595 a046433a bellard
    int copy_it = 0;
1596 a046433a bellard
    int was_modified = 0;
1597 a046433a bellard
    int32_t ret = 0;
1598 a046433a bellard
1599 a046433a bellard
    uint32_t cluster_num = begin_of_direntry(direntry);
1600 a046433a bellard
    uint32_t offset = 0;
1601 a046433a bellard
    int first_mapping_index = -1;
1602 c227f099 Anthony Liguori
    mapping_t* mapping = NULL;
1603 a046433a bellard
    const char* basename2 = NULL;
1604 de167e41 bellard
1605 a046433a bellard
    vvfat_close_current_file(s);
1606 de167e41 bellard
1607 a046433a bellard
    /* the root directory */
1608 a046433a bellard
    if (cluster_num == 0)
1609 de167e41 bellard
        return 0;
1610 de167e41 bellard
1611 a046433a bellard
    /* write support */
1612 a046433a bellard
    if (s->qcow) {
1613 a046433a bellard
        basename2 = get_basename(path);
1614 de167e41 bellard
1615 a046433a bellard
        mapping = find_mapping_for_cluster(s, cluster_num);
1616 a046433a bellard
1617 a046433a bellard
        if (mapping) {
1618 da2414e9 bellard
            const char* basename;
1619 da2414e9 bellard
1620 a046433a bellard
            assert(mapping->mode & MODE_DELETED);
1621 a046433a bellard
            mapping->mode &= ~MODE_DELETED;
1622 a046433a bellard
1623 da2414e9 bellard
            basename = get_basename(mapping->path);
1624 a046433a bellard
1625 a046433a bellard
            assert(mapping->mode & MODE_NORMAL);
1626 a046433a bellard
1627 a046433a bellard
            /* rename */
1628 a046433a bellard
            if (strcmp(basename, basename2))
1629 7267c094 Anthony Liguori
                schedule_rename(s, cluster_num, g_strdup(path));
1630 a046433a bellard
        } else if (is_file(direntry))
1631 a046433a bellard
            /* new file */
1632 7267c094 Anthony Liguori
            schedule_new_file(s, g_strdup(path), cluster_num);
1633 a046433a bellard
        else {
1634 43dc2a64 Blue Swirl
            abort();
1635 a046433a bellard
            return 0;
1636 a046433a bellard
        }
1637 de167e41 bellard
    }
1638 de167e41 bellard
1639 a046433a bellard
    while(1) {
1640 a046433a bellard
        if (s->qcow) {
1641 a046433a bellard
            if (!copy_it && cluster_was_modified(s, cluster_num)) {
1642 a046433a bellard
                if (mapping == NULL ||
1643 a046433a bellard
                        mapping->begin > cluster_num ||
1644 a046433a bellard
                        mapping->end <= cluster_num)
1645 a046433a bellard
                mapping = find_mapping_for_cluster(s, cluster_num);
1646 de167e41 bellard
1647 a046433a bellard
1648 a046433a bellard
                if (mapping &&
1649 a046433a bellard
                        (mapping->mode & MODE_DIRECTORY) == 0) {
1650 a046433a bellard
1651 a046433a bellard
                    /* was modified in qcow */
1652 a046433a bellard
                    if (offset != mapping->info.file.offset + s->cluster_size
1653 a046433a bellard
                            * (cluster_num - mapping->begin)) {
1654 a046433a bellard
                        /* offset of this cluster in file chain has changed */
1655 43dc2a64 Blue Swirl
                        abort();
1656 a046433a bellard
                        copy_it = 1;
1657 a046433a bellard
                    } else if (offset == 0) {
1658 a046433a bellard
                        const char* basename = get_basename(mapping->path);
1659 a046433a bellard
1660 a046433a bellard
                        if (strcmp(basename, basename2))
1661 a046433a bellard
                            copy_it = 1;
1662 a046433a bellard
                        first_mapping_index = array_index(&(s->mapping), mapping);
1663 a046433a bellard
                    }
1664 a046433a bellard
1665 a046433a bellard
                    if (mapping->first_mapping_index != first_mapping_index
1666 a046433a bellard
                            && mapping->info.file.offset > 0) {
1667 43dc2a64 Blue Swirl
                        abort();
1668 a046433a bellard
                        copy_it = 1;
1669 a046433a bellard
                    }
1670 a046433a bellard
1671 a046433a bellard
                    /* need to write out? */
1672 a046433a bellard
                    if (!was_modified && is_file(direntry)) {
1673 a046433a bellard
                        was_modified = 1;
1674 a046433a bellard
                        schedule_writeout(s, mapping->dir_index, offset);
1675 a046433a bellard
                    }
1676 a046433a bellard
                }
1677 a046433a bellard
            }
1678 a046433a bellard
1679 a046433a bellard
            if (copy_it) {
1680 a046433a bellard
                int i, dummy;
1681 a046433a bellard
                /*
1682 a046433a bellard
                 * This is horribly inefficient, but that is okay, since
1683 a046433a bellard
                 * it is rarely executed, if at all.
1684 a046433a bellard
                 */
1685 a046433a bellard
                int64_t offset = cluster2sector(s, cluster_num);
1686 a046433a bellard
1687 a046433a bellard
                vvfat_close_current_file(s);
1688 7704df98 Kevin Wolf
                for (i = 0; i < s->sectors_per_cluster; i++) {
1689 7704df98 Kevin Wolf
                    if (!bdrv_is_allocated(s->qcow, offset + i, 1, &dummy)) {
1690 7704df98 Kevin Wolf
                        if (vvfat_read(s->bs, offset, s->cluster_buffer, 1)) {
1691 7704df98 Kevin Wolf
                            return -1;
1692 7704df98 Kevin Wolf
                        }
1693 7704df98 Kevin Wolf
                        if (bdrv_write(s->qcow, offset, s->cluster_buffer, 1)) {
1694 7704df98 Kevin Wolf
                            return -2;
1695 7704df98 Kevin Wolf
                        }
1696 7704df98 Kevin Wolf
                    }
1697 7704df98 Kevin Wolf
                }
1698 a046433a bellard
            }
1699 a046433a bellard
        }
1700 a046433a bellard
1701 a046433a bellard
        ret++;
1702 a046433a bellard
        if (s->used_clusters[cluster_num] & USED_ANY)
1703 a046433a bellard
            return 0;
1704 a046433a bellard
        s->used_clusters[cluster_num] = USED_FILE;
1705 a046433a bellard
1706 a046433a bellard
        cluster_num = modified_fat_get(s, cluster_num);
1707 a046433a bellard
1708 a046433a bellard
        if (fat_eof(s, cluster_num))
1709 a046433a bellard
            return ret;
1710 a046433a bellard
        else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
1711 a046433a bellard
            return -1;
1712 a046433a bellard
1713 a046433a bellard
        offset += s->cluster_size;
1714 a046433a bellard
    }
1715 de167e41 bellard
}
1716 de167e41 bellard
1717 a046433a bellard
/*
1718 5fafdf24 ths
 * This function looks at the modified data (qcow).
1719 a046433a bellard
 * It returns 0 upon inconsistency or error, and the number of clusters
1720 a046433a bellard
 * used by the directory, its subdirectories and their files.
1721 a046433a bellard
 */
1722 a046433a bellard
static int check_directory_consistency(BDRVVVFATState *s,
1723 a046433a bellard
        int cluster_num, const char* path)
1724 de167e41 bellard
{
1725 a046433a bellard
    int ret = 0;
1726 7267c094 Anthony Liguori
    unsigned char* cluster = g_malloc(s->cluster_size);
1727 c227f099 Anthony Liguori
    direntry_t* direntries = (direntry_t*)cluster;
1728 c227f099 Anthony Liguori
    mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
1729 a046433a bellard
1730 a046433a bellard
    long_file_name lfn;
1731 a046433a bellard
    int path_len = strlen(path);
1732 0d460d6f Kevin Wolf
    char path2[PATH_MAX + 1];
1733 a046433a bellard
1734 a046433a bellard
    assert(path_len < PATH_MAX); /* len was tested before! */
1735 363a37d5 blueswir1
    pstrcpy(path2, sizeof(path2), path);
1736 a046433a bellard
    path2[path_len] = '/';
1737 a046433a bellard
    path2[path_len + 1] = '\0';
1738 a046433a bellard
1739 a046433a bellard
    if (mapping) {
1740 a046433a bellard
        const char* basename = get_basename(mapping->path);
1741 a046433a bellard
        const char* basename2 = get_basename(path);
1742 a046433a bellard
1743 a046433a bellard
        assert(mapping->mode & MODE_DIRECTORY);
1744 a046433a bellard
1745 a046433a bellard
        assert(mapping->mode & MODE_DELETED);
1746 a046433a bellard
        mapping->mode &= ~MODE_DELETED;
1747 a046433a bellard
1748 a046433a bellard
        if (strcmp(basename, basename2))
1749 7267c094 Anthony Liguori
            schedule_rename(s, cluster_num, g_strdup(path));
1750 a046433a bellard
    } else
1751 a046433a bellard
        /* new directory */
1752 7267c094 Anthony Liguori
        schedule_mkdir(s, cluster_num, g_strdup(path));
1753 3b46e624 ths
1754 a046433a bellard
    lfn_init(&lfn);
1755 a046433a bellard
    do {
1756 de167e41 bellard
        int i;
1757 a046433a bellard
        int subret = 0;
1758 a046433a bellard
1759 a046433a bellard
        ret++;
1760 a046433a bellard
1761 a046433a bellard
        if (s->used_clusters[cluster_num] & USED_ANY) {
1762 a046433a bellard
            fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
1763 a046433a bellard
            return 0;
1764 a046433a bellard
        }
1765 a046433a bellard
        s->used_clusters[cluster_num] = USED_DIRECTORY;
1766 a046433a bellard
1767 a046433a bellard
DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
1768 a046433a bellard
        subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
1769 a046433a bellard
                s->sectors_per_cluster);
1770 a046433a bellard
        if (subret) {
1771 a046433a bellard
            fprintf(stderr, "Error fetching direntries\n");
1772 a046433a bellard
        fail:
1773 ce137829 Stefan Weil
            g_free(cluster);
1774 a046433a bellard
            return 0;
1775 a046433a bellard
        }
1776 a046433a bellard
1777 a046433a bellard
        for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
1778 3f4cb3d3 blueswir1
            int cluster_count = 0;
1779 a046433a bellard
1780 b2bedb21 Stefan Weil
DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i));
1781 a046433a bellard
            if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
1782 a046433a bellard
                    is_free(direntries + i))
1783 a046433a bellard
                continue;
1784 a046433a bellard
1785 a046433a bellard
            subret = parse_long_name(&lfn, direntries + i);
1786 a046433a bellard
            if (subret < 0) {
1787 a046433a bellard
                fprintf(stderr, "Error in long name\n");
1788 a046433a bellard
                goto fail;
1789 de167e41 bellard
            }
1790 a046433a bellard
            if (subret == 0 || is_free(direntries + i))
1791 a046433a bellard
                continue;
1792 a046433a bellard
1793 a046433a bellard
            if (fat_chksum(direntries+i) != lfn.checksum) {
1794 a046433a bellard
                subret = parse_short_name(s, &lfn, direntries + i);
1795 a046433a bellard
                if (subret < 0) {
1796 a046433a bellard
                    fprintf(stderr, "Error in short name (%d)\n", subret);
1797 a046433a bellard
                    goto fail;
1798 a046433a bellard
                }
1799 ffe8ab83 ths
                if (subret > 0 || !strcmp((char*)lfn.name, ".")
1800 ffe8ab83 ths
                        || !strcmp((char*)lfn.name, ".."))
1801 a046433a bellard
                    continue;
1802 a046433a bellard
            }
1803 a046433a bellard
            lfn.checksum = 0x100; /* cannot use long name twice */
1804 a046433a bellard
1805 a046433a bellard
            if (path_len + 1 + lfn.len >= PATH_MAX) {
1806 a046433a bellard
                fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
1807 a046433a bellard
                goto fail;
1808 a046433a bellard
            }
1809 363a37d5 blueswir1
            pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
1810 363a37d5 blueswir1
                    (char*)lfn.name);
1811 a046433a bellard
1812 a046433a bellard
            if (is_directory(direntries + i)) {
1813 a046433a bellard
                if (begin_of_direntry(direntries + i) == 0) {
1814 a046433a bellard
                    DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
1815 a046433a bellard
                    goto fail;
1816 a046433a bellard
                }
1817 a046433a bellard
                cluster_count = check_directory_consistency(s,
1818 a046433a bellard
                        begin_of_direntry(direntries + i), path2);
1819 a046433a bellard
                if (cluster_count == 0) {
1820 a046433a bellard
                    DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
1821 a046433a bellard
                    goto fail;
1822 a046433a bellard
                }
1823 a046433a bellard
            } else if (is_file(direntries + i)) {
1824 a046433a bellard
                /* check file size with FAT */
1825 a046433a bellard
                cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
1826 a046433a bellard
                if (cluster_count !=
1827 a046433a bellard
                        (le32_to_cpu(direntries[i].size) + s->cluster_size
1828 a046433a bellard
                         - 1) / s->cluster_size) {
1829 a046433a bellard
                    DLOG(fprintf(stderr, "Cluster count mismatch\n"));
1830 a046433a bellard
                    goto fail;
1831 a046433a bellard
                }
1832 a046433a bellard
            } else
1833 43dc2a64 Blue Swirl
                abort(); /* cluster_count = 0; */
1834 a046433a bellard
1835 a046433a bellard
            ret += cluster_count;
1836 de167e41 bellard
        }
1837 de167e41 bellard
1838 a046433a bellard
        cluster_num = modified_fat_get(s, cluster_num);
1839 a046433a bellard
    } while(!fat_eof(s, cluster_num));
1840 de167e41 bellard
1841 ce137829 Stefan Weil
    g_free(cluster);
1842 a046433a bellard
    return ret;
1843 a046433a bellard
}
1844 a046433a bellard
1845 a046433a bellard
/* returns 1 on success */
1846 a046433a bellard
static int is_consistent(BDRVVVFATState* s)
1847 a046433a bellard
{
1848 a046433a bellard
    int i, check;
1849 a046433a bellard
    int used_clusters_count = 0;
1850 a046433a bellard
1851 a046433a bellard
DLOG(checkpoint());
1852 a046433a bellard
    /*
1853 a046433a bellard
     * - get modified FAT
1854 a046433a bellard
     * - compare the two FATs (TODO)
1855 a046433a bellard
     * - get buffer for marking used clusters
1856 a046433a bellard
     * - recurse direntries from root (using bs->bdrv_read to make
1857 a046433a bellard
     *    sure to get the new data)
1858 a046433a bellard
     *   - check that the FAT agrees with the size
1859 a046433a bellard
     *   - count the number of clusters occupied by this directory and
1860 a046433a bellard
     *     its files
1861 a046433a bellard
     * - check that the cumulative used cluster count agrees with the
1862 a046433a bellard
     *   FAT
1863 a046433a bellard
     * - if all is fine, return number of used clusters
1864 a046433a bellard
     */
1865 a046433a bellard
    if (s->fat2 == NULL) {
1866 a046433a bellard
        int size = 0x200 * s->sectors_per_fat;
1867 7267c094 Anthony Liguori
        s->fat2 = g_malloc(size);
1868 a046433a bellard
        memcpy(s->fat2, s->fat.pointer, size);
1869 a046433a bellard
    }
1870 a046433a bellard
    check = vvfat_read(s->bs,
1871 a046433a bellard
            s->first_sectors_number, s->fat2, s->sectors_per_fat);
1872 a046433a bellard
    if (check) {
1873 a046433a bellard
        fprintf(stderr, "Could not copy fat\n");
1874 a046433a bellard
        return 0;
1875 a046433a bellard
    }
1876 a046433a bellard
    assert (s->used_clusters);
1877 a046433a bellard
    for (i = 0; i < sector2cluster(s, s->sector_count); i++)
1878 a046433a bellard
        s->used_clusters[i] &= ~USED_ANY;
1879 a046433a bellard
1880 a046433a bellard
    clear_commits(s);
1881 a046433a bellard
1882 a046433a bellard
    /* mark every mapped file/directory as deleted.
1883 a046433a bellard
     * (check_directory_consistency() will unmark those still present). */
1884 a046433a bellard
    if (s->qcow)
1885 a046433a bellard
        for (i = 0; i < s->mapping.next; i++) {
1886 c227f099 Anthony Liguori
            mapping_t* mapping = array_get(&(s->mapping), i);
1887 a046433a bellard
            if (mapping->first_mapping_index < 0)
1888 a046433a bellard
                mapping->mode |= MODE_DELETED;
1889 de167e41 bellard
        }
1890 a046433a bellard
1891 a046433a bellard
    used_clusters_count = check_directory_consistency(s, 0, s->path);
1892 a046433a bellard
    if (used_clusters_count <= 0) {
1893 a046433a bellard
        DLOG(fprintf(stderr, "problem in directory\n"));
1894 a046433a bellard
        return 0;
1895 de167e41 bellard
    }
1896 de167e41 bellard
1897 a046433a bellard
    check = s->last_cluster_of_root_directory;
1898 a046433a bellard
    for (i = check; i < sector2cluster(s, s->sector_count); i++) {
1899 a046433a bellard
        if (modified_fat_get(s, i)) {
1900 a046433a bellard
            if(!s->used_clusters[i]) {
1901 a046433a bellard
                DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
1902 a046433a bellard
                return 0;
1903 a046433a bellard
            }
1904 a046433a bellard
            check++;
1905 a046433a bellard
        }
1906 a046433a bellard
1907 a046433a bellard
        if (s->used_clusters[i] == USED_ALLOCATED) {
1908 a046433a bellard
            /* allocated, but not used... */
1909 a046433a bellard
            DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
1910 a046433a bellard
            return 0;
1911 a046433a bellard
        }
1912 a046433a bellard
    }
1913 a046433a bellard
1914 a046433a bellard
    if (check != used_clusters_count)
1915 a046433a bellard
        return 0;
1916 a046433a bellard
1917 a046433a bellard
    return used_clusters_count;
1918 a046433a bellard
}
1919 a046433a bellard
1920 a046433a bellard
static inline void adjust_mapping_indices(BDRVVVFATState* s,
1921 a046433a bellard
        int offset, int adjust)
1922 a046433a bellard
{
1923 a046433a bellard
    int i;
1924 a046433a bellard
1925 a046433a bellard
    for (i = 0; i < s->mapping.next; i++) {
1926 c227f099 Anthony Liguori
        mapping_t* mapping = array_get(&(s->mapping), i);
1927 a046433a bellard
1928 a046433a bellard
#define ADJUST_MAPPING_INDEX(name) \
1929 a046433a bellard
        if (mapping->name >= offset) \
1930 a046433a bellard
            mapping->name += adjust
1931 a046433a bellard
1932 a046433a bellard
        ADJUST_MAPPING_INDEX(first_mapping_index);
1933 a046433a bellard
        if (mapping->mode & MODE_DIRECTORY)
1934 a046433a bellard
            ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
1935 de167e41 bellard
    }
1936 a046433a bellard
}
1937 a046433a bellard
1938 a046433a bellard
/* insert or update mapping */
1939 c227f099 Anthony Liguori
static mapping_t* insert_mapping(BDRVVVFATState* s,
1940 a046433a bellard
        uint32_t begin, uint32_t end)
1941 a046433a bellard
{
1942 a046433a bellard
    /*
1943 a046433a bellard
     * - find mapping where mapping->begin >= begin,
1944 a046433a bellard
     * - if mapping->begin > begin: insert
1945 a046433a bellard
     *   - adjust all references to mappings!
1946 a046433a bellard
     * - else: adjust
1947 a046433a bellard
     * - replace name
1948 a046433a bellard
     */
1949 a046433a bellard
    int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
1950 c227f099 Anthony Liguori
    mapping_t* mapping = NULL;
1951 c227f099 Anthony Liguori
    mapping_t* first_mapping = array_get(&(s->mapping), 0);
1952 a046433a bellard
1953 a046433a bellard
    if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
1954 a046433a bellard
            && mapping->begin < begin) {
1955 a046433a bellard
        mapping->end = begin;
1956 a046433a bellard
        index++;
1957 a046433a bellard
        mapping = array_get(&(s->mapping), index);
1958 a046433a bellard
    }
1959 a046433a bellard
    if (index >= s->mapping.next || mapping->begin > begin) {
1960 a046433a bellard
        mapping = array_insert(&(s->mapping), index, 1);
1961 a046433a bellard
        mapping->path = NULL;
1962 a046433a bellard
        adjust_mapping_indices(s, index, +1);
1963 a046433a bellard
    }
1964 a046433a bellard
1965 a046433a bellard
    mapping->begin = begin;
1966 a046433a bellard
    mapping->end = end;
1967 de167e41 bellard
1968 c227f099 Anthony Liguori
DLOG(mapping_t* next_mapping;
1969 a046433a bellard
assert(index + 1 >= s->mapping.next ||
1970 a046433a bellard
((next_mapping = array_get(&(s->mapping), index + 1)) &&
1971 a046433a bellard
 next_mapping->begin >= end)));
1972 a046433a bellard
1973 c227f099 Anthony Liguori
    if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1974 a046433a bellard
        s->current_mapping = array_get(&(s->mapping),
1975 a046433a bellard
                s->current_mapping - first_mapping);
1976 a046433a bellard
1977 a046433a bellard
    return mapping;
1978 a046433a bellard
}
1979 a046433a bellard
1980 a046433a bellard
static int remove_mapping(BDRVVVFATState* s, int mapping_index)
1981 a046433a bellard
{
1982 c227f099 Anthony Liguori
    mapping_t* mapping = array_get(&(s->mapping), mapping_index);
1983 c227f099 Anthony Liguori
    mapping_t* first_mapping = array_get(&(s->mapping), 0);
1984 a046433a bellard
1985 a046433a bellard
    /* free mapping */
1986 ce137829 Stefan Weil
    if (mapping->first_mapping_index < 0) {
1987 ce137829 Stefan Weil
        g_free(mapping->path);
1988 ce137829 Stefan Weil
    }
1989 a046433a bellard
1990 a046433a bellard
    /* remove from s->mapping */
1991 a046433a bellard
    array_remove(&(s->mapping), mapping_index);
1992 a046433a bellard
1993 a046433a bellard
    /* adjust all references to mappings */
1994 a046433a bellard
    adjust_mapping_indices(s, mapping_index, -1);
1995 a046433a bellard
1996 c227f099 Anthony Liguori
    if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1997 a046433a bellard
        s->current_mapping = array_get(&(s->mapping),
1998 a046433a bellard
                s->current_mapping - first_mapping);
1999 de167e41 bellard
2000 de167e41 bellard
    return 0;
2001 de167e41 bellard
}
2002 de167e41 bellard
2003 a046433a bellard
static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
2004 a046433a bellard
{
2005 a046433a bellard
    int i;
2006 a046433a bellard
    for (i = 0; i < s->mapping.next; i++) {
2007 c227f099 Anthony Liguori
        mapping_t* mapping = array_get(&(s->mapping), i);
2008 a046433a bellard
        if (mapping->dir_index >= offset)
2009 a046433a bellard
            mapping->dir_index += adjust;
2010 a046433a bellard
        if ((mapping->mode & MODE_DIRECTORY) &&
2011 a046433a bellard
                mapping->info.dir.first_dir_index >= offset)
2012 a046433a bellard
            mapping->info.dir.first_dir_index += adjust;
2013 a046433a bellard
    }
2014 a046433a bellard
}
2015 de167e41 bellard
2016 c227f099 Anthony Liguori
static direntry_t* insert_direntries(BDRVVVFATState* s,
2017 a046433a bellard
        int dir_index, int count)
2018 de167e41 bellard
{
2019 a046433a bellard
    /*
2020 a046433a bellard
     * make room in s->directory,
2021 a046433a bellard
     * adjust_dirindices
2022 a046433a bellard
     */
2023 c227f099 Anthony Liguori
    direntry_t* result = array_insert(&(s->directory), dir_index, count);
2024 a046433a bellard
    if (result == NULL)
2025 a046433a bellard
        return NULL;
2026 a046433a bellard
    adjust_dirindices(s, dir_index, count);
2027 de167e41 bellard
    return result;
2028 de167e41 bellard
}
2029 de167e41 bellard
2030 a046433a bellard
static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
2031 a046433a bellard
{
2032 a046433a bellard
    int ret = array_remove_slice(&(s->directory), dir_index, count);
2033 a046433a bellard
    if (ret)
2034 a046433a bellard
        return ret;
2035 a046433a bellard
    adjust_dirindices(s, dir_index, -count);
2036 a046433a bellard
    return 0;
2037 a046433a bellard
}
2038 de167e41 bellard
2039 a046433a bellard
/*
2040 a046433a bellard
 * Adapt the mappings of the cluster chain starting at first cluster
2041 a046433a bellard
 * (i.e. if a file starts at first_cluster, the chain is followed according
2042 a046433a bellard
 * to the modified fat, and the corresponding entries in s->mapping are
2043 a046433a bellard
 * adjusted)
2044 a046433a bellard
 */
2045 a046433a bellard
static int commit_mappings(BDRVVVFATState* s,
2046 a046433a bellard
        uint32_t first_cluster, int dir_index)
2047 de167e41 bellard
{
2048 c227f099 Anthony Liguori
    mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2049 c227f099 Anthony Liguori
    direntry_t* direntry = array_get(&(s->directory), dir_index);
2050 a046433a bellard
    uint32_t cluster = first_cluster;
2051 a046433a bellard
2052 a046433a bellard
    vvfat_close_current_file(s);
2053 a046433a bellard
2054 a046433a bellard
    assert(mapping);
2055 a046433a bellard
    assert(mapping->begin == first_cluster);
2056 a046433a bellard
    mapping->first_mapping_index = -1;
2057 a046433a bellard
    mapping->dir_index = dir_index;
2058 a046433a bellard
    mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2059 a046433a bellard
        MODE_DIRECTORY : MODE_NORMAL;
2060 a046433a bellard
2061 a046433a bellard
    while (!fat_eof(s, cluster)) {
2062 a046433a bellard
        uint32_t c, c1;
2063 a046433a bellard
2064 a046433a bellard
        for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2065 a046433a bellard
                c = c1, c1 = modified_fat_get(s, c1));
2066 a046433a bellard
2067 a046433a bellard
        c++;
2068 a046433a bellard
        if (c > mapping->end) {
2069 a046433a bellard
            int index = array_index(&(s->mapping), mapping);
2070 a046433a bellard
            int i, max_i = s->mapping.next - index;
2071 a046433a bellard
            for (i = 1; i < max_i && mapping[i].begin < c; i++);
2072 a046433a bellard
            while (--i > 0)
2073 a046433a bellard
                remove_mapping(s, index + 1);
2074 a046433a bellard
        }
2075 a046433a bellard
        assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2076 a046433a bellard
                || mapping[1].begin >= c);
2077 a046433a bellard
        mapping->end = c;
2078 a046433a bellard
2079 a046433a bellard
        if (!fat_eof(s, c1)) {
2080 a046433a bellard
            int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2081 c227f099 Anthony Liguori
            mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2082 a046433a bellard
                array_get(&(s->mapping), i);
2083 a046433a bellard
2084 a046433a bellard
            if (next_mapping == NULL || next_mapping->begin > c1) {
2085 a046433a bellard
                int i1 = array_index(&(s->mapping), mapping);
2086 a046433a bellard
2087 a046433a bellard
                next_mapping = insert_mapping(s, c1, c1+1);
2088 a046433a bellard
2089 a046433a bellard
                if (c1 < c)
2090 a046433a bellard
                    i1++;
2091 a046433a bellard
                mapping = array_get(&(s->mapping), i1);
2092 a046433a bellard
            }
2093 a046433a bellard
2094 a046433a bellard
            next_mapping->dir_index = mapping->dir_index;
2095 5fafdf24 ths
            next_mapping->first_mapping_index =
2096 a046433a bellard
                mapping->first_mapping_index < 0 ?
2097 a046433a bellard
                array_index(&(s->mapping), mapping) :
2098 a046433a bellard
                mapping->first_mapping_index;
2099 a046433a bellard
            next_mapping->path = mapping->path;
2100 a046433a bellard
            next_mapping->mode = mapping->mode;
2101 a046433a bellard
            next_mapping->read_only = mapping->read_only;
2102 a046433a bellard
            if (mapping->mode & MODE_DIRECTORY) {
2103 a046433a bellard
                next_mapping->info.dir.parent_mapping_index =
2104 a046433a bellard
                        mapping->info.dir.parent_mapping_index;
2105 a046433a bellard
                next_mapping->info.dir.first_dir_index =
2106 a046433a bellard
                        mapping->info.dir.first_dir_index +
2107 a046433a bellard
                        0x10 * s->sectors_per_cluster *
2108 a046433a bellard
                        (mapping->end - mapping->begin);
2109 a046433a bellard
            } else
2110 a046433a bellard
                next_mapping->info.file.offset = mapping->info.file.offset +
2111 a046433a bellard
                        mapping->end - mapping->begin;
2112 a046433a bellard
2113 a046433a bellard
            mapping = next_mapping;
2114 a046433a bellard
        }
2115 3b46e624 ths
2116 a046433a bellard
        cluster = c1;
2117 a046433a bellard
    }
2118 de167e41 bellard
2119 de167e41 bellard
    return 0;
2120 de167e41 bellard
}
2121 de167e41 bellard
2122 a046433a bellard
static int commit_direntries(BDRVVVFATState* s,
2123 a046433a bellard
        int dir_index, int parent_mapping_index)
2124 de167e41 bellard
{
2125 c227f099 Anthony Liguori
    direntry_t* direntry = array_get(&(s->directory), dir_index);
2126 a046433a bellard
    uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
2127 c227f099 Anthony Liguori
    mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2128 a046433a bellard
2129 a046433a bellard
    int factor = 0x10 * s->sectors_per_cluster;
2130 a046433a bellard
    int old_cluster_count, new_cluster_count;
2131 a046433a bellard
    int current_dir_index = mapping->info.dir.first_dir_index;
2132 a046433a bellard
    int first_dir_index = current_dir_index;
2133 a046433a bellard
    int ret, i;
2134 a046433a bellard
    uint32_t c;
2135 a046433a bellard
2136 a046433a bellard
DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
2137 a046433a bellard
2138 a046433a bellard
    assert(direntry);
2139 a046433a bellard
    assert(mapping);
2140 a046433a bellard
    assert(mapping->begin == first_cluster);
2141 a046433a bellard
    assert(mapping->info.dir.first_dir_index < s->directory.next);
2142 a046433a bellard
    assert(mapping->mode & MODE_DIRECTORY);
2143 a046433a bellard
    assert(dir_index == 0 || is_directory(direntry));
2144 a046433a bellard
2145 a046433a bellard
    mapping->info.dir.parent_mapping_index = parent_mapping_index;
2146 a046433a bellard
2147 a046433a bellard
    if (first_cluster == 0) {
2148 a046433a bellard
        old_cluster_count = new_cluster_count =
2149 a046433a bellard
            s->last_cluster_of_root_directory;
2150 a046433a bellard
    } else {
2151 a046433a bellard
        for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2152 a046433a bellard
                c = fat_get(s, c))
2153 a046433a bellard
            old_cluster_count++;
2154 de167e41 bellard
2155 a046433a bellard
        for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2156 a046433a bellard
                c = modified_fat_get(s, c))
2157 a046433a bellard
            new_cluster_count++;
2158 a046433a bellard
    }
2159 de167e41 bellard
2160 a046433a bellard
    if (new_cluster_count > old_cluster_count) {
2161 a046433a bellard
        if (insert_direntries(s,
2162 a046433a bellard
                current_dir_index + factor * old_cluster_count,
2163 a046433a bellard
                factor * (new_cluster_count - old_cluster_count)) == NULL)
2164 a046433a bellard
            return -1;
2165 a046433a bellard
    } else if (new_cluster_count < old_cluster_count)
2166 a046433a bellard
        remove_direntries(s,
2167 a046433a bellard
                current_dir_index + factor * new_cluster_count,
2168 a046433a bellard
                factor * (old_cluster_count - new_cluster_count));
2169 a046433a bellard
2170 a046433a bellard
    for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
2171 a046433a bellard
        void* direntry = array_get(&(s->directory), current_dir_index);
2172 a046433a bellard
        int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2173 a046433a bellard
                s->sectors_per_cluster);
2174 a046433a bellard
        if (ret)
2175 a046433a bellard
            return ret;
2176 a046433a bellard
        assert(!strncmp(s->directory.pointer, "QEMU", 4));
2177 a046433a bellard
        current_dir_index += factor;
2178 a046433a bellard
    }
2179 de167e41 bellard
2180 a046433a bellard
    ret = commit_mappings(s, first_cluster, dir_index);
2181 a046433a bellard
    if (ret)
2182 a046433a bellard
        return ret;
2183 a046433a bellard
2184 a046433a bellard
    /* recurse */
2185 a046433a bellard
    for (i = 0; i < factor * new_cluster_count; i++) {
2186 a046433a bellard
        direntry = array_get(&(s->directory), first_dir_index + i);
2187 a046433a bellard
        if (is_directory(direntry) && !is_dot(direntry)) {
2188 a046433a bellard
            mapping = find_mapping_for_cluster(s, first_cluster);
2189 a046433a bellard
            assert(mapping->mode & MODE_DIRECTORY);
2190 a046433a bellard
            ret = commit_direntries(s, first_dir_index + i,
2191 a046433a bellard
                array_index(&(s->mapping), mapping));
2192 a046433a bellard
            if (ret)
2193 a046433a bellard
                return ret;
2194 a046433a bellard
        }
2195 a046433a bellard
    }
2196 de167e41 bellard
2197 a046433a bellard
    return 0;
2198 a046433a bellard
}
2199 de167e41 bellard
2200 a046433a bellard
/* commit one file (adjust contents, adjust mapping),
2201 a046433a bellard
   return first_mapping_index */
2202 a046433a bellard
static int commit_one_file(BDRVVVFATState* s,
2203 a046433a bellard
        int dir_index, uint32_t offset)
2204 a046433a bellard
{
2205 c227f099 Anthony Liguori
    direntry_t* direntry = array_get(&(s->directory), dir_index);
2206 a046433a bellard
    uint32_t c = begin_of_direntry(direntry);
2207 a046433a bellard
    uint32_t first_cluster = c;
2208 c227f099 Anthony Liguori
    mapping_t* mapping = find_mapping_for_cluster(s, c);
2209 a046433a bellard
    uint32_t size = filesize_of_direntry(direntry);
2210 7267c094 Anthony Liguori
    char* cluster = g_malloc(s->cluster_size);
2211 a046433a bellard
    uint32_t i;
2212 a046433a bellard
    int fd = 0;
2213 a046433a bellard
2214 a046433a bellard
    assert(offset < size);
2215 a046433a bellard
    assert((offset % s->cluster_size) == 0);
2216 a046433a bellard
2217 a046433a bellard
    for (i = s->cluster_size; i < offset; i += s->cluster_size)
2218 a046433a bellard
        c = modified_fat_get(s, c);
2219 a046433a bellard
2220 6165f4d8 Corey Bryant
    fd = qemu_open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
2221 a046433a bellard
    if (fd < 0) {
2222 a046433a bellard
        fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2223 a046433a bellard
                strerror(errno), errno);
2224 ce137829 Stefan Weil
        g_free(cluster);
2225 a046433a bellard
        return fd;
2226 de167e41 bellard
    }
2227 ce137829 Stefan Weil
    if (offset > 0) {
2228 ce137829 Stefan Weil
        if (lseek(fd, offset, SEEK_SET) != offset) {
2229 2e1e79da Corey Bryant
            qemu_close(fd);
2230 ce137829 Stefan Weil
            g_free(cluster);
2231 ce137829 Stefan Weil
            return -3;
2232 ce137829 Stefan Weil
        }
2233 ce137829 Stefan Weil
    }
2234 a046433a bellard
2235 a046433a bellard
    while (offset < size) {
2236 a046433a bellard
        uint32_t c1;
2237 a046433a bellard
        int rest_size = (size - offset > s->cluster_size ?
2238 a046433a bellard
                s->cluster_size : size - offset);
2239 a046433a bellard
        int ret;
2240 a046433a bellard
2241 a046433a bellard
        c1 = modified_fat_get(s, c);
2242 a046433a bellard
2243 a046433a bellard
        assert((size - offset == 0 && fat_eof(s, c)) ||
2244 a046433a bellard
                (size > offset && c >=2 && !fat_eof(s, c)));
2245 a046433a bellard
2246 a046433a bellard
        ret = vvfat_read(s->bs, cluster2sector(s, c),
2247 ffe8ab83 ths
            (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
2248 a046433a bellard
2249 ce137829 Stefan Weil
        if (ret < 0) {
2250 2e1e79da Corey Bryant
            qemu_close(fd);
2251 ce137829 Stefan Weil
            g_free(cluster);
2252 ce137829 Stefan Weil
            return ret;
2253 ce137829 Stefan Weil
        }
2254 a046433a bellard
2255 ce137829 Stefan Weil
        if (write(fd, cluster, rest_size) < 0) {
2256 2e1e79da Corey Bryant
            qemu_close(fd);
2257 ce137829 Stefan Weil
            g_free(cluster);
2258 ce137829 Stefan Weil
            return -2;
2259 ce137829 Stefan Weil
        }
2260 a046433a bellard
2261 a046433a bellard
        offset += rest_size;
2262 a046433a bellard
        c = c1;
2263 a046433a bellard
    }
2264 a046433a bellard
2265 2dedf83e Kirill A. Shutemov
    if (ftruncate(fd, size)) {
2266 2dedf83e Kirill A. Shutemov
        perror("ftruncate()");
2267 2e1e79da Corey Bryant
        qemu_close(fd);
2268 ce137829 Stefan Weil
        g_free(cluster);
2269 2dedf83e Kirill A. Shutemov
        return -4;
2270 2dedf83e Kirill A. Shutemov
    }
2271 2e1e79da Corey Bryant
    qemu_close(fd);
2272 ce137829 Stefan Weil
    g_free(cluster);
2273 a046433a bellard
2274 a046433a bellard
    return commit_mappings(s, first_cluster, dir_index);
2275 a046433a bellard
}
2276 a046433a bellard
2277 a046433a bellard
#ifdef DEBUG
2278 a046433a bellard
/* test, if all mappings point to valid direntries */
2279 a046433a bellard
static void check1(BDRVVVFATState* s)
2280 a046433a bellard
{
2281 a046433a bellard
    int i;
2282 a046433a bellard
    for (i = 0; i < s->mapping.next; i++) {
2283 c227f099 Anthony Liguori
        mapping_t* mapping = array_get(&(s->mapping), i);
2284 a046433a bellard
        if (mapping->mode & MODE_DELETED) {
2285 a046433a bellard
            fprintf(stderr, "deleted\n");
2286 a046433a bellard
            continue;
2287 a046433a bellard
        }
2288 a046433a bellard
        assert(mapping->dir_index < s->directory.next);
2289 c227f099 Anthony Liguori
        direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2290 a046433a bellard
        assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2291 a046433a bellard
        if (mapping->mode & MODE_DIRECTORY) {
2292 a046433a bellard
            assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2293 a046433a bellard
            assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2294 de167e41 bellard
        }
2295 de167e41 bellard
    }
2296 de167e41 bellard
}
2297 de167e41 bellard
2298 a046433a bellard
/* test, if all direntries have mappings */
2299 a046433a bellard
static void check2(BDRVVVFATState* s)
2300 de167e41 bellard
{
2301 de167e41 bellard
    int i;
2302 a046433a bellard
    int first_mapping = -1;
2303 de167e41 bellard
2304 a046433a bellard
    for (i = 0; i < s->directory.next; i++) {
2305 c227f099 Anthony Liguori
        direntry_t* direntry = array_get(&(s->directory), i);
2306 de167e41 bellard
2307 a046433a bellard
        if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2308 c227f099 Anthony Liguori
            mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2309 a046433a bellard
            assert(mapping);
2310 a046433a bellard
            assert(mapping->dir_index == i || is_dot(direntry));
2311 a046433a bellard
            assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2312 a046433a bellard
        }
2313 de167e41 bellard
2314 a046433a bellard
        if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2315 a046433a bellard
            /* cluster start */
2316 a046433a bellard
            int j, count = 0;
2317 de167e41 bellard
2318 a046433a bellard
            for (j = 0; j < s->mapping.next; j++) {
2319 c227f099 Anthony Liguori
                mapping_t* mapping = array_get(&(s->mapping), j);
2320 a046433a bellard
                if (mapping->mode & MODE_DELETED)
2321 de167e41 bellard
                    continue;
2322 a046433a bellard
                if (mapping->mode & MODE_DIRECTORY) {
2323 a046433a bellard
                    if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2324 a046433a bellard
                        assert(++count == 1);
2325 a046433a bellard
                        if (mapping->first_mapping_index == -1)
2326 a046433a bellard
                            first_mapping = array_index(&(s->mapping), mapping);
2327 a046433a bellard
                        else
2328 a046433a bellard
                            assert(first_mapping == mapping->first_mapping_index);
2329 a046433a bellard
                        if (mapping->info.dir.parent_mapping_index < 0)
2330 a046433a bellard
                            assert(j == 0);
2331 a046433a bellard
                        else {
2332 c227f099 Anthony Liguori
                            mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2333 a046433a bellard
                            assert(parent->mode & MODE_DIRECTORY);
2334 a046433a bellard
                            assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2335 a046433a bellard
                        }
2336 a046433a bellard
                    }
2337 de167e41 bellard
                }
2338 a046433a bellard
            }
2339 a046433a bellard
            if (count == 0)
2340 a046433a bellard
                first_mapping = -1;
2341 a046433a bellard
        }
2342 a046433a bellard
    }
2343 a046433a bellard
}
2344 a046433a bellard
#endif
2345 de167e41 bellard
2346 a046433a bellard
static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2347 a046433a bellard
{
2348 a046433a bellard
    int i;
2349 de167e41 bellard
2350 a046433a bellard
#ifdef DEBUG
2351 a046433a bellard
    fprintf(stderr, "handle_renames\n");
2352 a046433a bellard
    for (i = 0; i < s->commits.next; i++) {
2353 c227f099 Anthony Liguori
        commit_t* commit = array_get(&(s->commits), i);
2354 a046433a bellard
        fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
2355 a046433a bellard
    }
2356 a046433a bellard
#endif
2357 a046433a bellard
2358 a046433a bellard
    for (i = 0; i < s->commits.next;) {
2359 c227f099 Anthony Liguori
        commit_t* commit = array_get(&(s->commits), i);
2360 a046433a bellard
        if (commit->action == ACTION_RENAME) {
2361 c227f099 Anthony Liguori
            mapping_t* mapping = find_mapping_for_cluster(s,
2362 a046433a bellard
                    commit->param.rename.cluster);
2363 a046433a bellard
            char* old_path = mapping->path;
2364 a046433a bellard
2365 a046433a bellard
            assert(commit->path);
2366 a046433a bellard
            mapping->path = commit->path;
2367 a046433a bellard
            if (rename(old_path, mapping->path))
2368 a046433a bellard
                return -2;
2369 a046433a bellard
2370 a046433a bellard
            if (mapping->mode & MODE_DIRECTORY) {
2371 a046433a bellard
                int l1 = strlen(mapping->path);
2372 a046433a bellard
                int l2 = strlen(old_path);
2373 a046433a bellard
                int diff = l1 - l2;
2374 c227f099 Anthony Liguori
                direntry_t* direntry = array_get(&(s->directory),
2375 a046433a bellard
                        mapping->info.dir.first_dir_index);
2376 a046433a bellard
                uint32_t c = mapping->begin;
2377 a046433a bellard
                int i = 0;
2378 a046433a bellard
2379 a046433a bellard
                /* recurse */
2380 a046433a bellard
                while (!fat_eof(s, c)) {
2381 a046433a bellard
                    do {
2382 c227f099 Anthony Liguori
                        direntry_t* d = direntry + i;
2383 a046433a bellard
2384 a046433a bellard
                        if (is_file(d) || (is_directory(d) && !is_dot(d))) {
2385 c227f099 Anthony Liguori
                            mapping_t* m = find_mapping_for_cluster(s,
2386 a046433a bellard
                                    begin_of_direntry(d));
2387 a046433a bellard
                            int l = strlen(m->path);
2388 7267c094 Anthony Liguori
                            char* new_path = g_malloc(l + diff + 1);
2389 a046433a bellard
2390 a046433a bellard
                            assert(!strncmp(m->path, mapping->path, l2));
2391 a046433a bellard
2392 363a37d5 blueswir1
                            pstrcpy(new_path, l + diff + 1, mapping->path);
2393 363a37d5 blueswir1
                            pstrcpy(new_path + l1, l + diff + 1 - l1,
2394 363a37d5 blueswir1
                                    m->path + l2);
2395 a046433a bellard
2396 a046433a bellard
                            schedule_rename(s, m->begin, new_path);
2397 de167e41 bellard
                        }
2398 a046433a bellard
                        i++;
2399 a046433a bellard
                    } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2400 a046433a bellard
                    c = fat_get(s, c);
2401 de167e41 bellard
                }
2402 de167e41 bellard
            }
2403 de167e41 bellard
2404 ce137829 Stefan Weil
            g_free(old_path);
2405 a046433a bellard
            array_remove(&(s->commits), i);
2406 a046433a bellard
            continue;
2407 a046433a bellard
        } else if (commit->action == ACTION_MKDIR) {
2408 c227f099 Anthony Liguori
            mapping_t* mapping;
2409 a046433a bellard
            int j, parent_path_len;
2410 a046433a bellard
2411 48c2f068 bellard
#ifdef __MINGW32__
2412 48c2f068 bellard
            if (mkdir(commit->path))
2413 48c2f068 bellard
                return -5;
2414 48c2f068 bellard
#else
2415 48c2f068 bellard
            if (mkdir(commit->path, 0755))
2416 48c2f068 bellard
                return -5;
2417 48c2f068 bellard
#endif
2418 a046433a bellard
2419 a046433a bellard
            mapping = insert_mapping(s, commit->param.mkdir.cluster,
2420 a046433a bellard
                    commit->param.mkdir.cluster + 1);
2421 a046433a bellard
            if (mapping == NULL)
2422 a046433a bellard
                return -6;
2423 a046433a bellard
2424 a046433a bellard
            mapping->mode = MODE_DIRECTORY;
2425 a046433a bellard
            mapping->read_only = 0;
2426 a046433a bellard
            mapping->path = commit->path;
2427 a046433a bellard
            j = s->directory.next;
2428 a046433a bellard
            assert(j);
2429 a046433a bellard
            insert_direntries(s, s->directory.next,
2430 a046433a bellard
                    0x10 * s->sectors_per_cluster);
2431 a046433a bellard
            mapping->info.dir.first_dir_index = j;
2432 a046433a bellard
2433 a046433a bellard
            parent_path_len = strlen(commit->path)
2434 a046433a bellard
                - strlen(get_basename(commit->path)) - 1;
2435 a046433a bellard
            for (j = 0; j < s->mapping.next; j++) {
2436 c227f099 Anthony Liguori
                mapping_t* m = array_get(&(s->mapping), j);
2437 a046433a bellard
                if (m->first_mapping_index < 0 && m != mapping &&
2438 a046433a bellard
                        !strncmp(m->path, mapping->path, parent_path_len) &&
2439 a046433a bellard
                        strlen(m->path) == parent_path_len)
2440 a046433a bellard
                    break;
2441 a046433a bellard
            }
2442 a046433a bellard
            assert(j < s->mapping.next);
2443 a046433a bellard
            mapping->info.dir.parent_mapping_index = j;
2444 a046433a bellard
2445 a046433a bellard
            array_remove(&(s->commits), i);
2446 a046433a bellard
            continue;
2447 a046433a bellard
        }
2448 a046433a bellard
2449 a046433a bellard
        i++;
2450 a046433a bellard
    }
2451 a046433a bellard
    return 0;
2452 a046433a bellard
}
2453 a046433a bellard
2454 a046433a bellard
/*
2455 a046433a bellard
 * TODO: make sure that the short name is not matching *another* file
2456 a046433a bellard
 */
2457 a046433a bellard
static int handle_commits(BDRVVVFATState* s)
2458 a046433a bellard
{
2459 a046433a bellard
    int i, fail = 0;
2460 a046433a bellard
2461 a046433a bellard
    vvfat_close_current_file(s);
2462 a046433a bellard
2463 a046433a bellard
    for (i = 0; !fail && i < s->commits.next; i++) {
2464 c227f099 Anthony Liguori
        commit_t* commit = array_get(&(s->commits), i);
2465 a046433a bellard
        switch(commit->action) {
2466 a046433a bellard
        case ACTION_RENAME: case ACTION_MKDIR:
2467 43dc2a64 Blue Swirl
            abort();
2468 a046433a bellard
            fail = -2;
2469 a046433a bellard
            break;
2470 a046433a bellard
        case ACTION_WRITEOUT: {
2471 a6c6f76c Blue Swirl
#ifndef NDEBUG
2472 a6c6f76c Blue Swirl
            /* these variables are only used by assert() below */
2473 c227f099 Anthony Liguori
            direntry_t* entry = array_get(&(s->directory),
2474 a046433a bellard
                    commit->param.writeout.dir_index);
2475 a046433a bellard
            uint32_t begin = begin_of_direntry(entry);
2476 c227f099 Anthony Liguori
            mapping_t* mapping = find_mapping_for_cluster(s, begin);
2477 a6c6f76c Blue Swirl
#endif
2478 a046433a bellard
2479 a046433a bellard
            assert(mapping);
2480 a046433a bellard
            assert(mapping->begin == begin);
2481 a046433a bellard
            assert(commit->path == NULL);
2482 a046433a bellard
2483 a046433a bellard
            if (commit_one_file(s, commit->param.writeout.dir_index,
2484 a046433a bellard
                        commit->param.writeout.modified_offset))
2485 a046433a bellard
                fail = -3;
2486 a046433a bellard
2487 a046433a bellard
            break;
2488 a046433a bellard
        }
2489 a046433a bellard
        case ACTION_NEW_FILE: {
2490 a046433a bellard
            int begin = commit->param.new_file.first_cluster;
2491 c227f099 Anthony Liguori
            mapping_t* mapping = find_mapping_for_cluster(s, begin);
2492 c227f099 Anthony Liguori
            direntry_t* entry;
2493 a046433a bellard
            int i;
2494 de167e41 bellard
2495 a046433a bellard
            /* find direntry */
2496 a046433a bellard
            for (i = 0; i < s->directory.next; i++) {
2497 a046433a bellard
                entry = array_get(&(s->directory), i);
2498 a046433a bellard
                if (is_file(entry) && begin_of_direntry(entry) == begin)
2499 a046433a bellard
                    break;
2500 de167e41 bellard
            }
2501 de167e41 bellard
2502 a046433a bellard
            if (i >= s->directory.next) {
2503 a046433a bellard
                fail = -6;
2504 a046433a bellard
                continue;
2505 a046433a bellard
            }
2506 de167e41 bellard
2507 a046433a bellard
            /* make sure there exists an initial mapping */
2508 a046433a bellard
            if (mapping && mapping->begin != begin) {
2509 a046433a bellard
                mapping->end = begin;
2510 a046433a bellard
                mapping = NULL;
2511 a046433a bellard
            }
2512 a046433a bellard
            if (mapping == NULL) {
2513 a046433a bellard
                mapping = insert_mapping(s, begin, begin+1);
2514 a046433a bellard
            }
2515 a046433a bellard
            /* most members will be fixed in commit_mappings() */
2516 a046433a bellard
            assert(commit->path);
2517 a046433a bellard
            mapping->path = commit->path;
2518 a046433a bellard
            mapping->read_only = 0;
2519 a046433a bellard
            mapping->mode = MODE_NORMAL;
2520 a046433a bellard
            mapping->info.file.offset = 0;
2521 a046433a bellard
2522 a046433a bellard
            if (commit_one_file(s, i, 0))
2523 a046433a bellard
                fail = -7;
2524 a046433a bellard
2525 a046433a bellard
            break;
2526 a046433a bellard
        }
2527 a046433a bellard
        default:
2528 43dc2a64 Blue Swirl
            abort();
2529 a046433a bellard
        }
2530 a046433a bellard
    }
2531 a046433a bellard
    if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2532 a046433a bellard
        return -1;
2533 a046433a bellard
    return fail;
2534 a046433a bellard
}
2535 a046433a bellard
2536 a046433a bellard
static int handle_deletes(BDRVVVFATState* s)
2537 a046433a bellard
{
2538 a046433a bellard
    int i, deferred = 1, deleted = 1;
2539 a046433a bellard
2540 a046433a bellard
    /* delete files corresponding to mappings marked as deleted */
2541 a046433a bellard
    /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2542 a046433a bellard
    while (deferred && deleted) {
2543 a046433a bellard
        deferred = 0;
2544 a046433a bellard
        deleted = 0;
2545 a046433a bellard
2546 a046433a bellard
        for (i = 1; i < s->mapping.next; i++) {
2547 c227f099 Anthony Liguori
            mapping_t* mapping = array_get(&(s->mapping), i);
2548 a046433a bellard
            if (mapping->mode & MODE_DELETED) {
2549 c227f099 Anthony Liguori
                direntry_t* entry = array_get(&(s->directory),
2550 a046433a bellard
                        mapping->dir_index);
2551 a046433a bellard
2552 a046433a bellard
                if (is_free(entry)) {
2553 a046433a bellard
                    /* remove file/directory */
2554 a046433a bellard
                    if (mapping->mode & MODE_DIRECTORY) {
2555 a046433a bellard
                        int j, next_dir_index = s->directory.next,
2556 a046433a bellard
                        first_dir_index = mapping->info.dir.first_dir_index;
2557 a046433a bellard
2558 a046433a bellard
                        if (rmdir(mapping->path) < 0) {
2559 a046433a bellard
                            if (errno == ENOTEMPTY) {
2560 a046433a bellard
                                deferred++;
2561 a046433a bellard
                                continue;
2562 a046433a bellard
                            } else
2563 a046433a bellard
                                return -5;
2564 de167e41 bellard
                        }
2565 a046433a bellard
2566 a046433a bellard
                        for (j = 1; j < s->mapping.next; j++) {
2567 c227f099 Anthony Liguori
                            mapping_t* m = array_get(&(s->mapping), j);
2568 a046433a bellard
                            if (m->mode & MODE_DIRECTORY &&
2569 a046433a bellard
                                    m->info.dir.first_dir_index >
2570 a046433a bellard
                                    first_dir_index &&
2571 a046433a bellard
                                    m->info.dir.first_dir_index <
2572 a046433a bellard
                                    next_dir_index)
2573 a046433a bellard
                                next_dir_index =
2574 a046433a bellard
                                    m->info.dir.first_dir_index;
2575 de167e41 bellard
                        }
2576 a046433a bellard
                        remove_direntries(s, first_dir_index,
2577 a046433a bellard
                                next_dir_index - first_dir_index);
2578 de167e41 bellard
2579 a046433a bellard
                        deleted++;
2580 de167e41 bellard
                    }
2581 a046433a bellard
                } else {
2582 a046433a bellard
                    if (unlink(mapping->path))
2583 a046433a bellard
                        return -4;
2584 a046433a bellard
                    deleted++;
2585 de167e41 bellard
                }
2586 a046433a bellard
                DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2587 a046433a bellard
                remove_mapping(s, i);
2588 de167e41 bellard
            }
2589 de167e41 bellard
        }
2590 de167e41 bellard
    }
2591 a046433a bellard
2592 a046433a bellard
    return 0;
2593 a046433a bellard
}
2594 a046433a bellard
2595 a046433a bellard
/*
2596 a046433a bellard
 * synchronize mapping with new state:
2597 a046433a bellard
 *
2598 a046433a bellard
 * - copy FAT (with bdrv_read)
2599 a046433a bellard
 * - mark all filenames corresponding to mappings as deleted
2600 a046433a bellard
 * - recurse direntries from root (using bs->bdrv_read)
2601 a046433a bellard
 * - delete files corresponding to mappings marked as deleted
2602 a046433a bellard
 */
2603 a046433a bellard
static int do_commit(BDRVVVFATState* s)
2604 a046433a bellard
{
2605 a046433a bellard
    int ret = 0;
2606 a046433a bellard
2607 a046433a bellard
    /* the real meat are the commits. Nothing to do? Move along! */
2608 a046433a bellard
    if (s->commits.next == 0)
2609 a046433a bellard
        return 0;
2610 a046433a bellard
2611 a046433a bellard
    vvfat_close_current_file(s);
2612 a046433a bellard
2613 a046433a bellard
    ret = handle_renames_and_mkdirs(s);
2614 a046433a bellard
    if (ret) {
2615 a046433a bellard
        fprintf(stderr, "Error handling renames (%d)\n", ret);
2616 43dc2a64 Blue Swirl
        abort();
2617 a046433a bellard
        return ret;
2618 a046433a bellard
    }
2619 a046433a bellard
2620 5fafdf24 ths
    /* copy FAT (with bdrv_read) */
2621 a046433a bellard
    memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2622 a046433a bellard
2623 a046433a bellard
    /* recurse direntries from root (using bs->bdrv_read) */
2624 a046433a bellard
    ret = commit_direntries(s, 0, -1);
2625 a046433a bellard
    if (ret) {
2626 a046433a bellard
        fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
2627 43dc2a64 Blue Swirl
        abort();
2628 a046433a bellard
        return ret;
2629 a046433a bellard
    }
2630 a046433a bellard
2631 a046433a bellard
    ret = handle_commits(s);
2632 a046433a bellard
    if (ret) {
2633 a046433a bellard
        fprintf(stderr, "Error handling commits (%d)\n", ret);
2634 43dc2a64 Blue Swirl
        abort();
2635 a046433a bellard
        return ret;
2636 a046433a bellard
    }
2637 a046433a bellard
2638 a046433a bellard
    ret = handle_deletes(s);
2639 a046433a bellard
    if (ret) {
2640 a046433a bellard
        fprintf(stderr, "Error deleting\n");
2641 43dc2a64 Blue Swirl
        abort();
2642 a046433a bellard
        return ret;
2643 a046433a bellard
    }
2644 a046433a bellard
2645 7704df98 Kevin Wolf
    if (s->qcow->drv->bdrv_make_empty) {
2646 7704df98 Kevin Wolf
        s->qcow->drv->bdrv_make_empty(s->qcow);
2647 7704df98 Kevin Wolf
    }
2648 a046433a bellard
2649 a046433a bellard
    memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2650 a046433a bellard
2651 a046433a bellard
DLOG(checkpoint());
2652 a046433a bellard
    return 0;
2653 a046433a bellard
}
2654 a046433a bellard
2655 a046433a bellard
static int try_commit(BDRVVVFATState* s)
2656 a046433a bellard
{
2657 a046433a bellard
    vvfat_close_current_file(s);
2658 a046433a bellard
DLOG(checkpoint());
2659 a046433a bellard
    if(!is_consistent(s))
2660 a046433a bellard
        return -1;
2661 a046433a bellard
    return do_commit(s);
2662 a046433a bellard
}
2663 a046433a bellard
2664 5fafdf24 ths
static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
2665 a046433a bellard
                    const uint8_t *buf, int nb_sectors)
2666 a046433a bellard
{
2667 5fafdf24 ths
    BDRVVVFATState *s = bs->opaque;
2668 a046433a bellard
    int i, ret;
2669 a046433a bellard
2670 a046433a bellard
DLOG(checkpoint());
2671 a046433a bellard
2672 ac48e389 Kevin Wolf
    /* Check if we're operating in read-only mode */
2673 ac48e389 Kevin Wolf
    if (s->qcow == NULL) {
2674 ac48e389 Kevin Wolf
        return -EACCES;
2675 ac48e389 Kevin Wolf
    }
2676 ac48e389 Kevin Wolf
2677 a046433a bellard
    vvfat_close_current_file(s);
2678 a046433a bellard
2679 a046433a bellard
    /*
2680 a046433a bellard
     * Some sanity checks:
2681 a046433a bellard
     * - do not allow writing to the boot sector
2682 a046433a bellard
     * - do not allow to write non-ASCII filenames
2683 a046433a bellard
     */
2684 a046433a bellard
2685 a046433a bellard
    if (sector_num < s->first_sectors_number)
2686 a046433a bellard
        return -1;
2687 a046433a bellard
2688 a046433a bellard
    for (i = sector2cluster(s, sector_num);
2689 a046433a bellard
            i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
2690 c227f099 Anthony Liguori
        mapping_t* mapping = find_mapping_for_cluster(s, i);
2691 a046433a bellard
        if (mapping) {
2692 a046433a bellard
            if (mapping->read_only) {
2693 a046433a bellard
                fprintf(stderr, "Tried to write to write-protected file %s\n",
2694 a046433a bellard
                        mapping->path);
2695 a046433a bellard
                return -1;
2696 a046433a bellard
            }
2697 a046433a bellard
2698 a046433a bellard
            if (mapping->mode & MODE_DIRECTORY) {
2699 a046433a bellard
                int begin = cluster2sector(s, i);
2700 a046433a bellard
                int end = begin + s->sectors_per_cluster, k;
2701 a046433a bellard
                int dir_index;
2702 c227f099 Anthony Liguori
                const direntry_t* direntries;
2703 a046433a bellard
                long_file_name lfn;
2704 a046433a bellard
2705 a046433a bellard
                lfn_init(&lfn);
2706 a046433a bellard
2707 a046433a bellard
                if (begin < sector_num)
2708 a046433a bellard
                    begin = sector_num;
2709 a046433a bellard
                if (end > sector_num + nb_sectors)
2710 a046433a bellard
                    end = sector_num + nb_sectors;
2711 5fafdf24 ths
                dir_index  = mapping->dir_index +
2712 a046433a bellard
                    0x10 * (begin - mapping->begin * s->sectors_per_cluster);
2713 c227f099 Anthony Liguori
                direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
2714 a046433a bellard
2715 a046433a bellard
                for (k = 0; k < (end - begin) * 0x10; k++) {
2716 a046433a bellard
                    /* do not allow non-ASCII filenames */
2717 a046433a bellard
                    if (parse_long_name(&lfn, direntries + k) < 0) {
2718 a046433a bellard
                        fprintf(stderr, "Warning: non-ASCII filename\n");
2719 a046433a bellard
                        return -1;
2720 a046433a bellard
                    }
2721 a046433a bellard
                    /* no access to the direntry of a read-only file */
2722 a046433a bellard
                    else if (is_short_name(direntries+k) &&
2723 a046433a bellard
                            (direntries[k].attributes & 1)) {
2724 a046433a bellard
                        if (memcmp(direntries + k,
2725 a046433a bellard
                                    array_get(&(s->directory), dir_index + k),
2726 c227f099 Anthony Liguori
                                    sizeof(direntry_t))) {
2727 a046433a bellard
                            fprintf(stderr, "Warning: tried to write to write-protected file\n");
2728 a046433a bellard
                            return -1;
2729 a046433a bellard
                        }
2730 a046433a bellard
                    }
2731 a046433a bellard
                }
2732 a046433a bellard
            }
2733 a046433a bellard
            i = mapping->end;
2734 a046433a bellard
        } else
2735 a046433a bellard
            i++;
2736 a046433a bellard
    }
2737 a046433a bellard
2738 a046433a bellard
    /*
2739 a046433a bellard
     * Use qcow backend. Commit later.
2740 a046433a bellard
     */
2741 a046433a bellard
DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
2742 7704df98 Kevin Wolf
    ret = bdrv_write(s->qcow, sector_num, buf, nb_sectors);
2743 a046433a bellard
    if (ret < 0) {
2744 a046433a bellard
        fprintf(stderr, "Error writing to qcow backend\n");
2745 a046433a bellard
        return ret;
2746 a046433a bellard
    }
2747 a046433a bellard
2748 a046433a bellard
    for (i = sector2cluster(s, sector_num);
2749 a046433a bellard
            i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
2750 a046433a bellard
        if (i >= 0)
2751 a046433a bellard
            s->used_clusters[i] |= USED_ALLOCATED;
2752 a046433a bellard
2753 a046433a bellard
DLOG(checkpoint());
2754 a046433a bellard
    /* TODO: add timeout */
2755 a046433a bellard
    try_commit(s);
2756 a046433a bellard
2757 a046433a bellard
DLOG(checkpoint());
2758 a046433a bellard
    return 0;
2759 a046433a bellard
}
2760 a046433a bellard
2761 e183ef75 Paolo Bonzini
static coroutine_fn int vvfat_co_write(BlockDriverState *bs, int64_t sector_num,
2762 e183ef75 Paolo Bonzini
                                       const uint8_t *buf, int nb_sectors)
2763 e183ef75 Paolo Bonzini
{
2764 e183ef75 Paolo Bonzini
    int ret;
2765 e183ef75 Paolo Bonzini
    BDRVVVFATState *s = bs->opaque;
2766 e183ef75 Paolo Bonzini
    qemu_co_mutex_lock(&s->lock);
2767 e183ef75 Paolo Bonzini
    ret = vvfat_write(bs, sector_num, buf, nb_sectors);
2768 e183ef75 Paolo Bonzini
    qemu_co_mutex_unlock(&s->lock);
2769 e183ef75 Paolo Bonzini
    return ret;
2770 e183ef75 Paolo Bonzini
}
2771 e183ef75 Paolo Bonzini
2772 73f703ca Stefan Hajnoczi
static int coroutine_fn vvfat_co_is_allocated(BlockDriverState *bs,
2773 a046433a bellard
        int64_t sector_num, int nb_sectors, int* n)
2774 a046433a bellard
{
2775 a046433a bellard
    BDRVVVFATState* s = bs->opaque;
2776 a046433a bellard
    *n = s->sector_count - sector_num;
2777 a046433a bellard
    if (*n > nb_sectors)
2778 a046433a bellard
        *n = nb_sectors;
2779 a046433a bellard
    else if (*n < 0)
2780 a046433a bellard
        return 0;
2781 5fafdf24 ths
    return 1;
2782 a046433a bellard
}
2783 a046433a bellard
2784 a046433a bellard
static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
2785 a046433a bellard
        const uint8_t* buffer, int nb_sectors) {
2786 9217e26f Kevin Wolf
    BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
2787 a046433a bellard
    return try_commit(s);
2788 a046433a bellard
}
2789 a046433a bellard
2790 a046433a bellard
static void write_target_close(BlockDriverState *bs) {
2791 9217e26f Kevin Wolf
    BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
2792 a046433a bellard
    bdrv_delete(s->qcow);
2793 ce137829 Stefan Weil
    g_free(s->qcow_filename);
2794 a046433a bellard
}
2795 a046433a bellard
2796 a046433a bellard
static BlockDriver vvfat_write_target = {
2797 f9e96436 Christoph Hellwig
    .format_name        = "vvfat_write_target",
2798 f9e96436 Christoph Hellwig
    .bdrv_write         = write_target_commit,
2799 f9e96436 Christoph Hellwig
    .bdrv_close         = write_target_close,
2800 a046433a bellard
};
2801 a046433a bellard
2802 a046433a bellard
static int enable_write_target(BDRVVVFATState *s)
2803 a046433a bellard
{
2804 91a073a9 Kevin Wolf
    BlockDriver *bdrv_qcow;
2805 91a073a9 Kevin Wolf
    QEMUOptionParameter *options;
2806 a655211a Kevin Wolf
    int ret;
2807 a046433a bellard
    int size = sector2cluster(s, s->sector_count);
2808 a046433a bellard
    s->used_clusters = calloc(size, 1);
2809 a046433a bellard
2810 c227f099 Anthony Liguori
    array_init(&(s->commits), sizeof(commit_t));
2811 a046433a bellard
2812 7267c094 Anthony Liguori
    s->qcow_filename = g_malloc(1024);
2813 eba25057 Jim Meyering
    ret = get_tmp_filename(s->qcow_filename, 1024);
2814 eba25057 Jim Meyering
    if (ret < 0) {
2815 eba25057 Jim Meyering
        g_free(s->qcow_filename);
2816 eba25057 Jim Meyering
        s->qcow_filename = NULL;
2817 eba25057 Jim Meyering
        return ret;
2818 eba25057 Jim Meyering
    }
2819 91a073a9 Kevin Wolf
2820 91a073a9 Kevin Wolf
    bdrv_qcow = bdrv_find_format("qcow");
2821 91a073a9 Kevin Wolf
    options = parse_option_parameters("", bdrv_qcow->create_options, NULL);
2822 91a073a9 Kevin Wolf
    set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512);
2823 91a073a9 Kevin Wolf
    set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:");
2824 91a073a9 Kevin Wolf
2825 91a073a9 Kevin Wolf
    if (bdrv_create(bdrv_qcow, s->qcow_filename, options) < 0)
2826 a046433a bellard
        return -1;
2827 a655211a Kevin Wolf
2828 a046433a bellard
    s->qcow = bdrv_new("");
2829 a655211a Kevin Wolf
    if (s->qcow == NULL) {
2830 a655211a Kevin Wolf
        return -1;
2831 a655211a Kevin Wolf
    }
2832 a655211a Kevin Wolf
2833 a655211a Kevin Wolf
    ret = bdrv_open(s->qcow, s->qcow_filename,
2834 a655211a Kevin Wolf
            BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, bdrv_qcow);
2835 a655211a Kevin Wolf
    if (ret < 0) {
2836 a655211a Kevin Wolf
        return ret;
2837 d6e9098e Kevin Wolf
    }
2838 a046433a bellard
2839 a046433a bellard
#ifndef _WIN32
2840 a046433a bellard
    unlink(s->qcow_filename);
2841 a046433a bellard
#endif
2842 a046433a bellard
2843 a046433a bellard
    s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
2844 a046433a bellard
    s->bs->backing_hd->drv = &vvfat_write_target;
2845 7267c094 Anthony Liguori
    s->bs->backing_hd->opaque = g_malloc(sizeof(void*));
2846 9217e26f Kevin Wolf
    *(void**)s->bs->backing_hd->opaque = s;
2847 a046433a bellard
2848 de167e41 bellard
    return 0;
2849 de167e41 bellard
}
2850 de167e41 bellard
2851 de167e41 bellard
static void vvfat_close(BlockDriverState *bs)
2852 de167e41 bellard
{
2853 de167e41 bellard
    BDRVVVFATState *s = bs->opaque;
2854 de167e41 bellard
2855 de167e41 bellard
    vvfat_close_current_file(s);
2856 de167e41 bellard
    array_free(&(s->fat));
2857 de167e41 bellard
    array_free(&(s->directory));
2858 de167e41 bellard
    array_free(&(s->mapping));
2859 ce137829 Stefan Weil
    g_free(s->cluster_buffer);
2860 3397f0cb Kevin Wolf
2861 3397f0cb Kevin Wolf
    if (s->qcow) {
2862 3397f0cb Kevin Wolf
        migrate_del_blocker(s->migration_blocker);
2863 3397f0cb Kevin Wolf
        error_free(s->migration_blocker);
2864 3397f0cb Kevin Wolf
    }
2865 de167e41 bellard
}
2866 de167e41 bellard
2867 5efa9d5a Anthony Liguori
static BlockDriver bdrv_vvfat = {
2868 e60f469c aurel32
    .format_name        = "vvfat",
2869 e60f469c aurel32
    .instance_size        = sizeof(BDRVVVFATState),
2870 66f82cee Kevin Wolf
    .bdrv_file_open        = vvfat_open,
2871 e023b2e2 Paolo Bonzini
    .bdrv_rebind        = vvfat_rebind,
2872 2914caa0 Paolo Bonzini
    .bdrv_read          = vvfat_co_read,
2873 e183ef75 Paolo Bonzini
    .bdrv_write         = vvfat_co_write,
2874 e60f469c aurel32
    .bdrv_close                = vvfat_close,
2875 73f703ca Stefan Hajnoczi
    .bdrv_co_is_allocated = vvfat_co_is_allocated,
2876 e60f469c aurel32
    .protocol_name        = "fat",
2877 de167e41 bellard
};
2878 de167e41 bellard
2879 5efa9d5a Anthony Liguori
static void bdrv_vvfat_init(void)
2880 5efa9d5a Anthony Liguori
{
2881 5efa9d5a Anthony Liguori
    bdrv_register(&bdrv_vvfat);
2882 5efa9d5a Anthony Liguori
}
2883 5efa9d5a Anthony Liguori
2884 5efa9d5a Anthony Liguori
block_init(bdrv_vvfat_init);
2885 5efa9d5a Anthony Liguori
2886 a046433a bellard
#ifdef DEBUG
2887 3f47aa8c blueswir1
static void checkpoint(void) {
2888 c227f099 Anthony Liguori
    assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
2889 a046433a bellard
    check1(vvv);
2890 a046433a bellard
    check2(vvv);
2891 a046433a bellard
    assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
2892 a046433a bellard
#if 0
2893 c227f099 Anthony Liguori
    if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
2894 a046433a bellard
        fprintf(stderr, "Nonono!\n");
2895 c227f099 Anthony Liguori
    mapping_t* mapping;
2896 c227f099 Anthony Liguori
    direntry_t* direntry;
2897 a046433a bellard
    assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
2898 a046433a bellard
    assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
2899 a046433a bellard
    if (vvv->mapping.next<47)
2900 a046433a bellard
        return;
2901 a046433a bellard
    assert((mapping = array_get(&(vvv->mapping), 47)));
2902 a046433a bellard
    assert(mapping->dir_index < vvv->directory.next);
2903 a046433a bellard
    direntry = array_get(&(vvv->directory), mapping->dir_index);
2904 a046433a bellard
    assert(!memcmp(direntry->name, "USB     H  ", 11) || direntry->name[0]==0);
2905 a046433a bellard
#endif
2906 a046433a bellard
}
2907 a046433a bellard
#endif