Statistics
| Branch: | Revision:

root / block / vvfat.c @ e685b4eb

History | View | Annotate | Download (80.6 kB)

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