Statistics
| Branch: | Revision:

root / block-vvfat.c @ d796321b

History | View | Annotate | Download (77.7 kB)

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