Statistics
| Branch: | Revision:

root / block-vvfat.c @ abf28337

History | View | Annotate | Download (78.8 kB)

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