Statistics
| Branch: | Revision:

root / block-vvfat.c @ 83f64091

History | View | Annotate | Download (77.6 kB)

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