Statistics
| Branch: | Revision:

root / block / vvfat.c @ 34b5d2c6

History | View | Annotate | Download (84.7 kB)

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