Statistics
| Branch: | Revision:

root / block-vvfat.c @ dfae6487

History | View | Annotate | Download (53.2 kB)

1 de167e41 bellard
/*
2 de167e41 bellard
 * QEMU Block driver for virtual VFAT (shadows a local directory)
3 de167e41 bellard
 * 
4 de167e41 bellard
 * Copyright (c) 2004 Johannes E. Schindelin
5 de167e41 bellard
 * 
6 de167e41 bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 de167e41 bellard
 * of this software and associated documentation files (the "Software"), to deal
8 de167e41 bellard
 * in the Software without restriction, including without limitation the rights
9 de167e41 bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 de167e41 bellard
 * copies of the Software, and to permit persons to whom the Software is
11 de167e41 bellard
 * furnished to do so, subject to the following conditions:
12 de167e41 bellard
 *
13 de167e41 bellard
 * The above copyright notice and this permission notice shall be included in
14 de167e41 bellard
 * all copies or substantial portions of the Software.
15 de167e41 bellard
 *
16 de167e41 bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 de167e41 bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 de167e41 bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 de167e41 bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 de167e41 bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 de167e41 bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 de167e41 bellard
 * THE SOFTWARE.
23 de167e41 bellard
 */
24 de167e41 bellard
#include <sys/stat.h>
25 de167e41 bellard
#include <dirent.h>
26 de167e41 bellard
#include <assert.h>
27 de167e41 bellard
#include "vl.h"
28 de167e41 bellard
#include "block_int.h"
29 de167e41 bellard
30 de167e41 bellard
// TODO: new file
31 de167e41 bellard
// TODO: delete file
32 de167e41 bellard
// TODO: make root directory larger
33 de167e41 bellard
// TODO: make directory clusters connected, so they are reserved anyway... add a member which tells how many clusters are reserved after a directory
34 de167e41 bellard
// TODO: introduce another member in mapping_t which says where the directory resides in s->directory (for mkdir and rmdir) 
35 de167e41 bellard
// in _read and _write, before treating direntries or file contents, get_mapping to know what it is.
36 de167e41 bellard
// TODO: mkdir
37 de167e41 bellard
// TODO: rmdir 
38 de167e41 bellard
39 de167e41 bellard
// TODO: when commit_data'ing a direntry and is_consistent, commit_remove
40 de167e41 bellard
// TODO: reset MODE_MODIFIED when commit_remove'ing
41 de167e41 bellard
42 de167e41 bellard
#define DEBUG
43 de167e41 bellard
44 de167e41 bellard
/* dynamic array functions */
45 de167e41 bellard
typedef struct array_t {
46 de167e41 bellard
    char* pointer;
47 de167e41 bellard
    unsigned int size,next,item_size;
48 de167e41 bellard
} array_t;
49 de167e41 bellard
50 de167e41 bellard
static inline void array_init(array_t* array,unsigned int item_size)
51 de167e41 bellard
{
52 de167e41 bellard
    array->pointer=0;
53 de167e41 bellard
    array->size=0;
54 de167e41 bellard
    array->next=0;
55 de167e41 bellard
    array->item_size=item_size;
56 de167e41 bellard
}
57 de167e41 bellard
58 de167e41 bellard
static inline void array_free(array_t* array)
59 de167e41 bellard
{
60 de167e41 bellard
    if(array->pointer)
61 de167e41 bellard
        free(array->pointer);
62 de167e41 bellard
    array->size=array->next=0;
63 de167e41 bellard
}
64 de167e41 bellard
65 de167e41 bellard
/* make sure that memory is reserved at pointer[index*item_size] */
66 de167e41 bellard
static inline void* array_get(array_t* array,unsigned int index) {
67 de167e41 bellard
    if((index+1)*array->item_size>array->size) {
68 de167e41 bellard
        int new_size=(index+32)*array->item_size;
69 de167e41 bellard
        array->pointer=realloc(array->pointer,new_size);
70 de167e41 bellard
        if(!array->pointer)
71 de167e41 bellard
            return 0;
72 de167e41 bellard
        array->size=new_size;
73 de167e41 bellard
        array->next=index+1;
74 de167e41 bellard
    }
75 de167e41 bellard
    return array->pointer+index*array->item_size;
76 de167e41 bellard
}
77 de167e41 bellard
78 de167e41 bellard
static inline void* array_get_next(array_t* array) {
79 de167e41 bellard
    unsigned int next=array->next;
80 de167e41 bellard
    void* result=array_get(array,next);
81 de167e41 bellard
    array->next=next+1;
82 de167e41 bellard
    return result;
83 de167e41 bellard
}
84 de167e41 bellard
85 de167e41 bellard
static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
86 de167e41 bellard
    if((array->next+count)*array->item_size>array->size) {
87 de167e41 bellard
        int increment=count*array->item_size;
88 de167e41 bellard
        array->pointer=realloc(array->pointer,array->size+increment);
89 de167e41 bellard
        if(!array->pointer)
90 de167e41 bellard
            return 0;
91 de167e41 bellard
        array->size+=increment;
92 de167e41 bellard
    }
93 de167e41 bellard
    memmove(array->pointer+(index+count)*array->item_size,
94 de167e41 bellard
                array->pointer+index*array->item_size,
95 de167e41 bellard
                (array->next-index)*array->item_size);
96 de167e41 bellard
    array->next+=count;
97 de167e41 bellard
    return array->pointer+index*array->item_size;
98 de167e41 bellard
}
99 de167e41 bellard
100 de167e41 bellard
/* this performs a "roll", so that the element which was at index_from becomes
101 de167e41 bellard
 * index_to, but the order of all other elements is preserved. */
102 de167e41 bellard
static inline int array_roll(array_t* array,int index_to,int index_from,int count)
103 de167e41 bellard
{
104 de167e41 bellard
    char* buf;
105 de167e41 bellard
    char* from;
106 de167e41 bellard
    char* to;
107 de167e41 bellard
    int is;
108 de167e41 bellard
109 de167e41 bellard
    if(!array ||
110 de167e41 bellard
            index_to<0 || index_to>=array->next ||
111 de167e41 bellard
            index_from<0 || index_from>=array->next)
112 de167e41 bellard
        return -1;
113 de167e41 bellard
    
114 de167e41 bellard
    if(index_to==index_from)
115 de167e41 bellard
        return 0;
116 de167e41 bellard
117 de167e41 bellard
    is=array->item_size;
118 de167e41 bellard
    from=array->pointer+index_from*is;
119 de167e41 bellard
    to=array->pointer+index_to*is;
120 de167e41 bellard
    buf=malloc(is*count);
121 de167e41 bellard
    memcpy(buf,from,is*count);
122 de167e41 bellard
123 de167e41 bellard
    if(index_to<index_from)
124 de167e41 bellard
        memmove(to+is*count,to,from-to);
125 de167e41 bellard
    else
126 de167e41 bellard
        memmove(from,from+is*count,to-from);
127 de167e41 bellard
    
128 de167e41 bellard
    memcpy(to,buf,is*count);
129 de167e41 bellard
130 de167e41 bellard
    free(buf);
131 de167e41 bellard
132 de167e41 bellard
    return 0;
133 de167e41 bellard
}
134 de167e41 bellard
135 de167e41 bellard
int array_remove(array_t* array,int index)
136 de167e41 bellard
{
137 de167e41 bellard
    if(array_roll(array,array->next-1,index,1))
138 de167e41 bellard
        return -1;
139 de167e41 bellard
    array->next--;
140 de167e41 bellard
    return 0;
141 de167e41 bellard
}
142 de167e41 bellard
143 de167e41 bellard
/* These structures are used to fake a disk and the VFAT filesystem.
144 de167e41 bellard
 * For this reason we need to use __attribute__((packed)). */
145 de167e41 bellard
146 de167e41 bellard
typedef struct bootsector_t {
147 de167e41 bellard
    uint8_t jump[3];
148 de167e41 bellard
    uint8_t name[8];
149 de167e41 bellard
    uint16_t sector_size;
150 de167e41 bellard
    uint8_t sectors_per_cluster;
151 de167e41 bellard
    uint16_t reserved_sectors;
152 de167e41 bellard
    uint8_t number_of_fats;
153 de167e41 bellard
    uint16_t root_entries;
154 de167e41 bellard
    uint16_t zero;
155 de167e41 bellard
    uint8_t media_type;
156 de167e41 bellard
    uint16_t sectors_per_fat;
157 de167e41 bellard
    uint16_t sectors_per_track;
158 de167e41 bellard
    uint16_t number_of_heads;
159 de167e41 bellard
    uint32_t hidden_sectors;
160 de167e41 bellard
    uint32_t total_sectors;
161 de167e41 bellard
    union {
162 de167e41 bellard
        struct {
163 de167e41 bellard
            uint8_t drive_number;
164 de167e41 bellard
            uint8_t current_head;
165 de167e41 bellard
            uint8_t signature;
166 de167e41 bellard
            uint32_t id;
167 de167e41 bellard
            uint8_t volume_label[11];
168 de167e41 bellard
        } __attribute__((packed)) fat16;
169 de167e41 bellard
        struct {
170 de167e41 bellard
            uint32_t sectors_per_fat;
171 de167e41 bellard
            uint16_t flags;
172 de167e41 bellard
            uint8_t major,minor;
173 de167e41 bellard
            uint32_t first_cluster_of_root_directory;
174 de167e41 bellard
            uint16_t info_sector;
175 de167e41 bellard
            uint16_t backup_boot_sector;
176 de167e41 bellard
            uint16_t ignored;
177 de167e41 bellard
        } __attribute__((packed)) fat32;
178 de167e41 bellard
    } u;
179 de167e41 bellard
    uint8_t fat_type[8];
180 de167e41 bellard
    uint8_t ignored[0x1c0];
181 de167e41 bellard
    uint8_t magic[2];
182 de167e41 bellard
} __attribute__((packed)) bootsector_t;
183 de167e41 bellard
184 de167e41 bellard
typedef struct partition_t {
185 de167e41 bellard
    uint8_t attributes; /* 0x80 = bootable */
186 de167e41 bellard
    uint8_t start_head;
187 de167e41 bellard
    uint8_t start_sector;
188 de167e41 bellard
    uint8_t start_cylinder;
189 de167e41 bellard
    uint8_t fs_type; /* 0x6 = FAT16, 0xb = FAT32 */
190 de167e41 bellard
    uint8_t end_head;
191 de167e41 bellard
    uint8_t end_sector;
192 de167e41 bellard
    uint8_t end_cylinder;
193 de167e41 bellard
    uint32_t start_sector_long;
194 de167e41 bellard
    uint32_t end_sector_long;
195 de167e41 bellard
} __attribute__((packed)) partition_t;
196 de167e41 bellard
197 de167e41 bellard
typedef struct mbr_t {
198 de167e41 bellard
    uint8_t ignored[0x1be];
199 de167e41 bellard
    partition_t partition[4];
200 de167e41 bellard
    uint8_t magic[2];
201 de167e41 bellard
} __attribute__((packed)) mbr_t;
202 de167e41 bellard
203 de167e41 bellard
typedef struct direntry_t {
204 de167e41 bellard
    uint8_t name[8];
205 de167e41 bellard
    uint8_t extension[3];
206 de167e41 bellard
    uint8_t attributes;
207 de167e41 bellard
    uint8_t reserved[2];
208 de167e41 bellard
    uint16_t ctime;
209 de167e41 bellard
    uint16_t cdate;
210 de167e41 bellard
    uint16_t adate;
211 de167e41 bellard
    uint16_t begin_hi;
212 de167e41 bellard
    uint16_t mtime;
213 de167e41 bellard
    uint16_t mdate;
214 de167e41 bellard
    uint16_t begin;
215 de167e41 bellard
    uint32_t size;
216 de167e41 bellard
} __attribute__((packed)) direntry_t;
217 de167e41 bellard
218 de167e41 bellard
/* this structure are used to transparently access the files */
219 de167e41 bellard
220 de167e41 bellard
typedef struct mapping_t {
221 de167e41 bellard
    /* begin is the first cluster, end is the last+1,
222 de167e41 bellard
     * offset is the offset in the file in clusters of this slice */
223 de167e41 bellard
    off_t begin,end,offset;
224 de167e41 bellard
    char* filename;
225 de167e41 bellard
226 de167e41 bellard
    /* as s->directory is growable, no pointer may be used here */
227 de167e41 bellard
    unsigned int dir_index;
228 de167e41 bellard
    enum { MODE_NORMAL,MODE_UNDEFINED,MODE_MODIFIED,MODE_DELETED,MODE_DIRECTORY } mode;
229 de167e41 bellard
} mapping_t;
230 de167e41 bellard
231 de167e41 bellard
/* this structure is used to hold sectors which need to be written, but it's
232 de167e41 bellard
 * not known yet where to write them. */
233 de167e41 bellard
234 de167e41 bellard
typedef struct commit_t {
235 de167e41 bellard
    uint32_t cluster_num;
236 de167e41 bellard
    uint8_t* buf;
237 de167e41 bellard
} commit_t;
238 de167e41 bellard
239 de167e41 bellard
/* write support exists for fat, direntry and file contents */
240 de167e41 bellard
typedef enum {
241 de167e41 bellard
    WRITE_UNDEFINED,WRITE_FAT,WRITE_DIRENTRY,WRITE_DATA
242 de167e41 bellard
} write_action_t;
243 de167e41 bellard
244 de167e41 bellard
/* here begins the real VVFAT driver */
245 de167e41 bellard
246 de167e41 bellard
typedef struct BDRVVVFATState {
247 de167e41 bellard
    unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
248 de167e41 bellard
    unsigned char first_sectors[0x40*0x200];
249 de167e41 bellard
    
250 de167e41 bellard
    int fat_type; /* 16 or 32 */
251 de167e41 bellard
    array_t fat,directory,mapping;
252 de167e41 bellard
   
253 de167e41 bellard
    unsigned int cluster_size;
254 de167e41 bellard
    unsigned int sectors_per_cluster;
255 de167e41 bellard
    unsigned int sectors_per_fat;
256 de167e41 bellard
    unsigned int sectors_of_root_directory;
257 de167e41 bellard
    unsigned int sectors_for_directory;
258 de167e41 bellard
    unsigned int faked_sectors; /* how many sectors are faked before file data */
259 de167e41 bellard
    uint32_t sector_count; /* total number of sectors of the partition */
260 de167e41 bellard
    uint32_t cluster_count; /* total number of clusters of this partition */
261 de167e41 bellard
    unsigned int first_file_mapping; /* index of the first mapping which is not a directory, but a file */
262 de167e41 bellard
    uint32_t max_fat_value;
263 de167e41 bellard
   
264 de167e41 bellard
    int current_fd;
265 de167e41 bellard
    char current_fd_is_writable; /* =0 if read only, !=0 if read/writable */
266 de167e41 bellard
    mapping_t* current_mapping;
267 de167e41 bellard
    unsigned char* cluster;
268 de167e41 bellard
    unsigned int current_cluster;
269 de167e41 bellard
270 de167e41 bellard
    /* write support */
271 de167e41 bellard
    array_t commit;
272 de167e41 bellard
    /* for each file, the file contents, the direntry, and the fat entries are
273 de167e41 bellard
     * written, but not necessarily in that order */
274 de167e41 bellard
    write_action_t action[3];
275 de167e41 bellard
} BDRVVVFATState;
276 de167e41 bellard
277 de167e41 bellard
278 de167e41 bellard
static int vvfat_probe(const uint8_t *buf, int buf_size, const char *filename)
279 de167e41 bellard
{
280 de167e41 bellard
    if (strstart(filename, "fat:", NULL) ||
281 de167e41 bellard
        strstart(filename, "fatrw:", NULL))
282 de167e41 bellard
        return 100;
283 de167e41 bellard
    return 0;
284 de167e41 bellard
}
285 de167e41 bellard
286 de167e41 bellard
static void init_mbr(BDRVVVFATState* s)
287 de167e41 bellard
{
288 de167e41 bellard
    /* TODO: if the files mbr.img and bootsect.img exist, use them */
289 de167e41 bellard
    mbr_t* real_mbr=(mbr_t*)s->first_sectors;
290 de167e41 bellard
    partition_t* partition=&(real_mbr->partition[0]);
291 de167e41 bellard
292 de167e41 bellard
    memset(s->first_sectors,0,512);
293 de167e41 bellard
   
294 de167e41 bellard
    partition->attributes=0x80; /* bootable */
295 de167e41 bellard
    partition->start_head=1;
296 de167e41 bellard
    partition->start_sector=1;
297 de167e41 bellard
    partition->start_cylinder=0;
298 de167e41 bellard
    partition->fs_type=(s->fat_type==16?0x6:0xb); /* FAT16/FAT32 */
299 de167e41 bellard
    partition->end_head=0xf;
300 de167e41 bellard
    partition->end_sector=0xff; /* end sector & upper 2 bits of cylinder */;
301 de167e41 bellard
    partition->end_cylinder=0xff; /* lower 8 bits of end cylinder */;
302 de167e41 bellard
    partition->start_sector_long=cpu_to_le32(0x3f);
303 de167e41 bellard
    partition->end_sector_long=cpu_to_le32(s->sector_count);
304 de167e41 bellard
305 de167e41 bellard
    real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
306 de167e41 bellard
}
307 de167e41 bellard
308 de167e41 bellard
/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
309 de167e41 bellard
static inline int short2long_name(unsigned char* dest,const char* src)
310 de167e41 bellard
{
311 de167e41 bellard
    int i;
312 de167e41 bellard
    for(i=0;i<129 && src[i];i++) {
313 de167e41 bellard
        dest[2*i]=src[i];
314 de167e41 bellard
        dest[2*i+1]=0;
315 de167e41 bellard
    }
316 de167e41 bellard
    dest[2*i]=dest[2*i+1]=0;
317 de167e41 bellard
    for(i=2*i+2;(i%26);i++)
318 de167e41 bellard
        dest[i]=0xff;
319 de167e41 bellard
    return i;
320 de167e41 bellard
}
321 de167e41 bellard
322 de167e41 bellard
static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
323 de167e41 bellard
{
324 de167e41 bellard
    char buffer[258];
325 de167e41 bellard
    int length=short2long_name(buffer,filename),
326 de167e41 bellard
        number_of_entries=(length+25)/26,i;
327 de167e41 bellard
    direntry_t* entry;
328 de167e41 bellard
329 de167e41 bellard
    for(i=0;i<number_of_entries;i++) {
330 de167e41 bellard
        entry=array_get_next(&(s->directory));
331 de167e41 bellard
        entry->attributes=0xf;
332 de167e41 bellard
        entry->reserved[0]=0;
333 de167e41 bellard
        entry->begin=0;
334 de167e41 bellard
        entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
335 de167e41 bellard
    }
336 de167e41 bellard
    for(i=0;i<length;i++) {
337 de167e41 bellard
        int offset=(i%26);
338 de167e41 bellard
        if(offset<10) offset=1+offset;
339 de167e41 bellard
        else if(offset<22) offset=14+offset-10;
340 de167e41 bellard
        else offset=28+offset-22;
341 de167e41 bellard
        entry=array_get(&(s->directory),s->directory.next-1-(i/26));
342 de167e41 bellard
        entry->name[offset]=buffer[i];
343 de167e41 bellard
    }
344 de167e41 bellard
    return array_get(&(s->directory),s->directory.next-number_of_entries);
345 de167e41 bellard
}
346 de167e41 bellard
347 de167e41 bellard
/* fat functions */
348 de167e41 bellard
349 de167e41 bellard
static inline uint8_t fat_chksum(direntry_t* entry)
350 de167e41 bellard
{
351 de167e41 bellard
    uint8_t chksum=0;
352 de167e41 bellard
    int i;
353 de167e41 bellard
354 de167e41 bellard
    for(i=0;i<11;i++)
355 de167e41 bellard
        chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0))
356 de167e41 bellard
            +(unsigned char)entry->name[i];
357 de167e41 bellard
    
358 de167e41 bellard
    return chksum;
359 de167e41 bellard
}
360 de167e41 bellard
361 de167e41 bellard
/* if return_time==0, this returns the fat_date, else the fat_time */
362 de167e41 bellard
static uint16_t fat_datetime(time_t time,int return_time) {
363 de167e41 bellard
    struct tm* t;
364 de167e41 bellard
#ifdef _WIN32
365 de167e41 bellard
    t=localtime(&time); /* this is not thread safe */
366 de167e41 bellard
#else
367 de167e41 bellard
    struct tm t1;
368 de167e41 bellard
    t=&t1;
369 de167e41 bellard
    localtime_r(&time,t);
370 de167e41 bellard
#endif
371 de167e41 bellard
    if(return_time)
372 de167e41 bellard
        return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
373 de167e41 bellard
    return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
374 de167e41 bellard
}
375 de167e41 bellard
376 de167e41 bellard
static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
377 de167e41 bellard
{
378 de167e41 bellard
    if(s->fat_type==12) {
379 de167e41 bellard
        assert(0); /* TODO */
380 de167e41 bellard
    } else if(s->fat_type==16) {
381 de167e41 bellard
        uint16_t* entry=array_get(&(s->fat),cluster);
382 de167e41 bellard
        *entry=cpu_to_le16(value&0xffff);
383 de167e41 bellard
    } else {
384 de167e41 bellard
        uint32_t* entry=array_get(&(s->fat),cluster);
385 de167e41 bellard
        *entry=cpu_to_le32(value);
386 de167e41 bellard
    }
387 de167e41 bellard
}
388 de167e41 bellard
389 de167e41 bellard
static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
390 de167e41 bellard
{
391 de167e41 bellard
    //fprintf(stderr,"want to get fat for cluster %d\n",cluster);
392 de167e41 bellard
    if(s->fat_type==12) {
393 de167e41 bellard
        const uint8_t* x=s->fat.pointer+cluster*3/2;
394 de167e41 bellard
        return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
395 de167e41 bellard
    } else if(s->fat_type==16) {
396 de167e41 bellard
        uint16_t* entry=array_get(&(s->fat),cluster);
397 de167e41 bellard
        return le16_to_cpu(*entry);
398 de167e41 bellard
    } else {
399 de167e41 bellard
        uint32_t* entry=array_get(&(s->fat),cluster);
400 de167e41 bellard
        return le32_to_cpu(*entry);
401 de167e41 bellard
    }
402 de167e41 bellard
}
403 de167e41 bellard
404 de167e41 bellard
static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
405 de167e41 bellard
{
406 de167e41 bellard
    if(fat_entry>s->max_fat_value-8)
407 de167e41 bellard
        return -1;
408 de167e41 bellard
    return 0;
409 de167e41 bellard
}
410 de167e41 bellard
411 de167e41 bellard
static inline void init_fat(BDRVVVFATState* s)
412 de167e41 bellard
{
413 de167e41 bellard
    int i;
414 de167e41 bellard
    
415 de167e41 bellard
    array_init(&(s->fat),(s->fat_type==32?4:2));
416 de167e41 bellard
    array_get(&(s->fat),s->sectors_per_fat*0x200/s->fat.item_size-1);
417 de167e41 bellard
    memset(s->fat.pointer,0,s->fat.size);
418 de167e41 bellard
    fat_set(s,0,0x7ffffff8);
419 de167e41 bellard
    
420 de167e41 bellard
    for(i=1;i<s->sectors_for_directory/s->sectors_per_cluster-1;i++)
421 de167e41 bellard
        fat_set(s,i,i+1);
422 de167e41 bellard
    fat_set(s,i,0x7fffffff);
423 de167e41 bellard
424 de167e41 bellard
    switch(s->fat_type) {
425 de167e41 bellard
        case 12: s->max_fat_value=0xfff; break;
426 de167e41 bellard
        case 16: s->max_fat_value=0xffff; break;
427 de167e41 bellard
        case 32: s->max_fat_value=0xfffffff; break;
428 de167e41 bellard
        default: s->max_fat_value=0; /* error... */
429 de167e41 bellard
    }
430 de167e41 bellard
431 de167e41 bellard
}
432 de167e41 bellard
433 de167e41 bellard
static inline int long2unix_name(unsigned char* dest,int dest_size,direntry_t* direntry_short) {
434 de167e41 bellard
    int i=-1,j;
435 de167e41 bellard
    int chksum=fat_chksum(direntry_short);
436 de167e41 bellard
    while(1) {
437 de167e41 bellard
        char* buf=(char*)(direntry_short+i);
438 de167e41 bellard
        if((buf[0]&0x3f)!=-i || direntry_short[i].reserved[1]!=chksum ||
439 de167e41 bellard
                direntry_short[i].attributes!=0xf) {
440 de167e41 bellard
            if(i<-1)
441 de167e41 bellard
                return -3;
442 de167e41 bellard
            /* take short name */
443 de167e41 bellard
            for(j=7;j>0 && direntry_short->name[j]==' ';j--);
444 de167e41 bellard
            if(j+1>dest_size)
445 de167e41 bellard
                return -1;
446 de167e41 bellard
            strncpy(dest,direntry_short->name,j+1);
447 de167e41 bellard
            dest+=j+1; dest_size-=j+1;
448 de167e41 bellard
            for(j=2;j>=0 && direntry_short->extension[j]==' ';j--);
449 de167e41 bellard
            if(j>=0) {
450 de167e41 bellard
                if(j+2>dest_size)
451 de167e41 bellard
                    return -1;
452 de167e41 bellard
                dest[0]='.';
453 de167e41 bellard
                strncpy(dest+1,direntry_short->extension,j+1);
454 de167e41 bellard
            }
455 de167e41 bellard
            return 0;
456 de167e41 bellard
        }
457 de167e41 bellard
        for(j=0;j<13;j++) {
458 de167e41 bellard
            dest_size--;
459 de167e41 bellard
            if(dest_size<0)
460 de167e41 bellard
                return -2;
461 de167e41 bellard
            dest[0]=buf[2*j+((j<5)?1:(j<11)?4:6)];
462 de167e41 bellard
            if(dest[0]==0 && (buf[0]&0x40)!=0)
463 de167e41 bellard
                return 0;
464 de167e41 bellard
            dest++;
465 de167e41 bellard
        }
466 de167e41 bellard
        /* last entry, but no trailing \0? */
467 de167e41 bellard
        if(buf[0]&0x40)
468 de167e41 bellard
            return -3;
469 de167e41 bellard
        i--;
470 de167e41 bellard
    }
471 de167e41 bellard
}
472 de167e41 bellard
473 de167e41 bellard
static inline direntry_t* create_short_filename(BDRVVVFATState* s,unsigned int directory_start,const char* filename,int is_dot)
474 de167e41 bellard
{
475 de167e41 bellard
    int i,long_index=s->directory.next;
476 de167e41 bellard
    direntry_t* entry=0;
477 de167e41 bellard
    direntry_t* entry_long=0;
478 de167e41 bellard
479 de167e41 bellard
    if(is_dot) {
480 de167e41 bellard
        entry=array_get_next(&(s->directory));
481 de167e41 bellard
        memset(entry->name,0x20,11);
482 de167e41 bellard
        memcpy(entry->name,filename,strlen(filename));
483 de167e41 bellard
        return entry;
484 de167e41 bellard
    }
485 de167e41 bellard
    
486 de167e41 bellard
    for(i=1;i<8 && filename[i] && filename[i]!='.';i++);
487 de167e41 bellard
488 de167e41 bellard
    entry_long=create_long_filename(s,filename);
489 de167e41 bellard
   
490 de167e41 bellard
    entry=array_get_next(&(s->directory));
491 de167e41 bellard
    memset(entry->name,0x20,11);
492 de167e41 bellard
    strncpy(entry->name,filename,i);
493 de167e41 bellard
    
494 de167e41 bellard
    if(filename[i]) {
495 de167e41 bellard
        int len=strlen(filename);
496 de167e41 bellard
        for(i=len;i>0 && filename[i-1]!='.';i--);
497 de167e41 bellard
        if(i>0)
498 de167e41 bellard
            memcpy(entry->extension,filename+i,(len-i>3?3:len-i));
499 de167e41 bellard
    }
500 de167e41 bellard
501 de167e41 bellard
    /* upcase & remove unwanted characters */
502 de167e41 bellard
    for(i=10;i>=0;i--) {
503 de167e41 bellard
        if(i==10 || i==7) for(;i>1 && entry->name[i]==' ';i--);
504 de167e41 bellard
        if(entry->name[i]<=' ' || entry->name[i]>0x7f
505 de167e41 bellard
                || strchr("*?<>|\":/\\[];,+='",entry->name[i]))
506 de167e41 bellard
            entry->name[i]='_';
507 de167e41 bellard
        else if(entry->name[i]>='a' && entry->name[i]<='z')
508 de167e41 bellard
            entry->name[i]+='A'-'a';
509 de167e41 bellard
    }
510 de167e41 bellard
511 de167e41 bellard
    /* mangle duplicates */
512 de167e41 bellard
    while(1) {
513 de167e41 bellard
        direntry_t* entry1=array_get(&(s->directory),directory_start);
514 de167e41 bellard
        int j;
515 de167e41 bellard
516 de167e41 bellard
        for(;entry1<entry;entry1++)
517 de167e41 bellard
            if(!(entry1->attributes&0xf) && !memcmp(entry1->name,entry->name,11))
518 de167e41 bellard
                break; /* found dupe */
519 de167e41 bellard
        if(entry1==entry) /* no dupe found */
520 de167e41 bellard
            break;
521 de167e41 bellard
522 de167e41 bellard
        /* use all 8 characters of name */        
523 de167e41 bellard
        if(entry->name[7]==' ') {
524 de167e41 bellard
            int j;
525 de167e41 bellard
            for(j=6;j>0 && entry->name[j]==' ';j--)
526 de167e41 bellard
                entry->name[j]='~';
527 de167e41 bellard
        }
528 de167e41 bellard
529 de167e41 bellard
        /* increment number */
530 de167e41 bellard
        for(j=7;j>0 && entry->name[j]=='9';j--)
531 de167e41 bellard
            entry->name[j]='0';
532 de167e41 bellard
        if(j>0) {
533 de167e41 bellard
            if(entry->name[j]<'0' || entry->name[j]>'9')
534 de167e41 bellard
                entry->name[j]='0';
535 de167e41 bellard
            else
536 de167e41 bellard
                entry->name[j]++;
537 de167e41 bellard
        }
538 de167e41 bellard
    }
539 de167e41 bellard
540 de167e41 bellard
    /* calculate checksum; propagate to long name */
541 de167e41 bellard
    if(entry_long) {
542 de167e41 bellard
        uint8_t chksum=fat_chksum(entry);
543 de167e41 bellard
544 de167e41 bellard
        /* calculate anew, because realloc could have taken place */
545 de167e41 bellard
        entry_long=array_get(&(s->directory),long_index);
546 de167e41 bellard
        while(entry_long<entry
547 de167e41 bellard
                    && entry_long->attributes==0xf) {
548 de167e41 bellard
            entry_long->reserved[1]=chksum;
549 de167e41 bellard
            entry_long++;
550 de167e41 bellard
        }
551 de167e41 bellard
    }
552 de167e41 bellard
553 de167e41 bellard
    return entry;
554 de167e41 bellard
}
555 de167e41 bellard
556 de167e41 bellard
static int read_directory(BDRVVVFATState* s,const char* dirname,
557 de167e41 bellard
                int first_cluster_of_parent)
558 de167e41 bellard
{
559 de167e41 bellard
560 de167e41 bellard
    DIR* dir=opendir(dirname);
561 de167e41 bellard
    struct dirent* entry;
562 de167e41 bellard
    struct stat st;
563 de167e41 bellard
    unsigned int start_of_directory=s->directory.next;
564 de167e41 bellard
    /* mappings before first_file_mapping are directories */
565 de167e41 bellard
    unsigned int first_directory_mapping=s->first_file_mapping;
566 de167e41 bellard
    unsigned int first_cluster=(start_of_directory/0x10/s->sectors_per_cluster);
567 de167e41 bellard
    int i;
568 de167e41 bellard
569 de167e41 bellard
    if(!dir)
570 de167e41 bellard
        return -1;
571 de167e41 bellard
    
572 de167e41 bellard
    while((entry=readdir(dir))) {
573 de167e41 bellard
        unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
574 de167e41 bellard
        char* buffer;
575 de167e41 bellard
        direntry_t* direntry;
576 de167e41 bellard
        int is_dot=!strcmp(entry->d_name,".");
577 de167e41 bellard
        int is_dotdot=!strcmp(entry->d_name,"..");
578 de167e41 bellard
579 de167e41 bellard
        if(start_of_directory==1 && (is_dotdot || is_dot))
580 de167e41 bellard
            continue;
581 de167e41 bellard
        
582 de167e41 bellard
        buffer=(char*)malloc(length);
583 de167e41 bellard
        snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
584 de167e41 bellard
585 de167e41 bellard
        if(stat(buffer,&st)<0) {
586 de167e41 bellard
            free(buffer);
587 de167e41 bellard
            continue;
588 de167e41 bellard
        }
589 de167e41 bellard
590 de167e41 bellard
        /* create directory entry for this file */
591 de167e41 bellard
        //fprintf(stderr,"create direntry at %d (cluster %d) for %s\n",s->directory.next,s->directory.next/0x10/s->sectors_per_cluster,entry->d_name);
592 de167e41 bellard
        direntry=create_short_filename(s,start_of_directory,entry->d_name,is_dot||is_dotdot);
593 de167e41 bellard
        direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
594 de167e41 bellard
        direntry->reserved[0]=direntry->reserved[1]=0;
595 de167e41 bellard
        direntry->ctime=fat_datetime(st.st_ctime,1);
596 de167e41 bellard
        direntry->cdate=fat_datetime(st.st_ctime,0);
597 de167e41 bellard
        direntry->adate=fat_datetime(st.st_atime,0);
598 de167e41 bellard
        direntry->begin_hi=0;
599 de167e41 bellard
        direntry->mtime=fat_datetime(st.st_mtime,1);
600 de167e41 bellard
        direntry->mdate=fat_datetime(st.st_mtime,0);
601 de167e41 bellard
        if(is_dotdot)
602 de167e41 bellard
            direntry->begin=cpu_to_le16(first_cluster_of_parent);
603 de167e41 bellard
        else if(is_dot)
604 de167e41 bellard
            direntry->begin=cpu_to_le16(first_cluster);
605 de167e41 bellard
        else
606 de167e41 bellard
            direntry->begin=cpu_to_le16(0); /* do that later */
607 de167e41 bellard
        direntry->size=cpu_to_le32(st.st_size);
608 de167e41 bellard
609 de167e41 bellard
        /* create mapping for this file */
610 de167e41 bellard
        if(!is_dot && !is_dotdot) {
611 de167e41 bellard
            if(S_ISDIR(st.st_mode))
612 de167e41 bellard
                s->current_mapping=(mapping_t*)array_insert(&(s->mapping),s->first_file_mapping++,1);
613 de167e41 bellard
            else
614 de167e41 bellard
                s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
615 de167e41 bellard
            s->current_mapping->begin=0;
616 de167e41 bellard
            s->current_mapping->end=st.st_size;
617 de167e41 bellard
            s->current_mapping->offset=0;
618 de167e41 bellard
            s->current_mapping->filename=buffer;
619 de167e41 bellard
            s->current_mapping->dir_index=s->directory.next-1;
620 de167e41 bellard
            s->current_mapping->mode=(S_ISDIR(st.st_mode)?MODE_DIRECTORY:MODE_UNDEFINED);
621 de167e41 bellard
        }
622 de167e41 bellard
    }
623 de167e41 bellard
    closedir(dir);
624 de167e41 bellard
625 de167e41 bellard
    /* fill with zeroes up to the end of the cluster */
626 de167e41 bellard
    while(s->directory.next%(0x10*s->sectors_per_cluster)) {
627 de167e41 bellard
        direntry_t* direntry=array_get_next(&(s->directory));
628 de167e41 bellard
        memset(direntry,0,sizeof(direntry_t));
629 de167e41 bellard
    }
630 de167e41 bellard
631 de167e41 bellard
    /* reserve next cluster also (for new files) */
632 de167e41 bellard
    for(i=0;i<0x10*s->sectors_per_cluster;i++) {
633 de167e41 bellard
        direntry_t* direntry=array_get_next(&(s->directory));
634 de167e41 bellard
        memset(direntry,0,sizeof(direntry_t));
635 de167e41 bellard
    }
636 de167e41 bellard
637 de167e41 bellard
    /* was it the first directory? */
638 de167e41 bellard
    if(start_of_directory==1) {
639 de167e41 bellard
        mapping_t* mapping=array_insert(&(s->mapping),0,1);
640 de167e41 bellard
        mapping->filename=strdup(dirname);
641 de167e41 bellard
        mapping->mode=MODE_DIRECTORY;
642 de167e41 bellard
        mapping->begin=0;
643 de167e41 bellard
        mapping->end=1;
644 de167e41 bellard
        mapping->offset=0;
645 de167e41 bellard
        mapping->dir_index=0xffffffff;
646 de167e41 bellard
        s->sectors_of_root_directory=s->directory.next/0x10;
647 de167e41 bellard
    }
648 de167e41 bellard
649 de167e41 bellard
    /* recurse directories */
650 de167e41 bellard
    {
651 de167e41 bellard
        int i;
652 de167e41 bellard
653 de167e41 bellard
        //fprintf(stderr,"iterating subdirectories of %s (first cluster %d): %d to %d\n",dirname,first_cluster,first_directory_mapping,last_directory_mapping);
654 de167e41 bellard
        for(i=first_directory_mapping;i<s->first_file_mapping;i++) {
655 de167e41 bellard
            mapping_t* mapping=array_get(&(s->mapping),i);
656 de167e41 bellard
            direntry_t* direntry=array_get(&(s->directory),mapping->dir_index);
657 de167e41 bellard
            /* the directory to be read can add more subdirectories */
658 de167e41 bellard
            int last_dir_mapping=s->first_file_mapping;
659 de167e41 bellard
            
660 de167e41 bellard
            assert(mapping->mode==MODE_DIRECTORY);
661 de167e41 bellard
            /* first, tell the mapping where the directory will start */
662 de167e41 bellard
            mapping->begin=s->directory.next/0x10/s->sectors_per_cluster;
663 de167e41 bellard
            if(i>0) {
664 de167e41 bellard
                mapping[-1].end=mapping->begin;
665 de167e41 bellard
                assert(mapping[-1].begin<mapping->begin);
666 de167e41 bellard
            }
667 de167e41 bellard
            /* then tell the direntry */
668 de167e41 bellard
            direntry->begin=cpu_to_le16(mapping->begin);
669 de167e41 bellard
            //fprintf(stderr,"read directory %s (begin %d)\n",mapping->filename,(int)mapping->begin);
670 de167e41 bellard
            /* then read it */
671 de167e41 bellard
            if(read_directory(s,mapping->filename,first_cluster))
672 de167e41 bellard
                return -1;
673 de167e41 bellard
674 de167e41 bellard
            if(last_dir_mapping!=s->first_file_mapping) {
675 de167e41 bellard
                int diff=s->first_file_mapping-last_dir_mapping;
676 de167e41 bellard
                assert(diff>0);
677 de167e41 bellard
678 de167e41 bellard
                if(last_dir_mapping!=i+1) {
679 de167e41 bellard
                    int count=last_dir_mapping-i-1;
680 de167e41 bellard
                    int to=s->first_file_mapping-count;
681 de167e41 bellard
682 de167e41 bellard
                    assert(count>0);
683 de167e41 bellard
                    assert(to>i+1);
684 de167e41 bellard
                    array_roll(&(s->mapping),to,i+1,count);
685 de167e41 bellard
                    /* could have changed due to realloc */
686 de167e41 bellard
                    mapping=array_get(&(s->mapping),i);
687 de167e41 bellard
                    mapping->end=mapping[1].begin;
688 de167e41 bellard
                }
689 de167e41 bellard
                i+=diff;
690 de167e41 bellard
            }
691 de167e41 bellard
        }
692 de167e41 bellard
    }
693 de167e41 bellard
694 de167e41 bellard
    return 0;
695 de167e41 bellard
}
696 de167e41 bellard
697 de167e41 bellard
static int init_directory(BDRVVVFATState* s,const char* dirname)
698 de167e41 bellard
{
699 de167e41 bellard
    bootsector_t* bootsector=(bootsector_t*)&(s->first_sectors[(s->first_sectors_number-1)*0x200]);
700 de167e41 bellard
    unsigned int i;
701 de167e41 bellard
    unsigned int cluster;
702 de167e41 bellard
703 de167e41 bellard
    memset(&(s->first_sectors[0]),0,0x40*0x200);
704 de167e41 bellard
705 de167e41 bellard
    /* TODO: if FAT32, this is probably wrong */
706 de167e41 bellard
    s->sectors_per_fat=0xfc;
707 de167e41 bellard
    s->sectors_per_cluster=0x10;
708 de167e41 bellard
    s->cluster_size=s->sectors_per_cluster*0x200;
709 de167e41 bellard
    s->cluster=malloc(s->cluster_size);
710 de167e41 bellard
    
711 de167e41 bellard
    array_init(&(s->mapping),sizeof(mapping_t));
712 de167e41 bellard
    array_init(&(s->directory),sizeof(direntry_t));
713 de167e41 bellard
    array_init(&(s->commit),sizeof(commit_t));
714 de167e41 bellard
715 de167e41 bellard
    /* add volume label */
716 de167e41 bellard
    {
717 de167e41 bellard
        direntry_t* entry=array_get_next(&(s->directory));
718 de167e41 bellard
        entry->attributes=0x28; /* archive | volume label */
719 de167e41 bellard
        snprintf(entry->name,11,"QEMU VVFAT");
720 de167e41 bellard
    }
721 de167e41 bellard
722 de167e41 bellard
    if(read_directory(s,dirname,0))
723 de167e41 bellard
        return -1;
724 de167e41 bellard
725 de167e41 bellard
    /* make sure that the number of directory entries is multiple of 0x200/0x20 (to fit the last sector exactly) */
726 de167e41 bellard
    s->sectors_for_directory=s->directory.next/0x10;
727 de167e41 bellard
728 de167e41 bellard
    s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2+s->sectors_for_directory;
729 de167e41 bellard
    s->cluster_count=(s->sector_count-s->faked_sectors)/s->sectors_per_cluster;
730 de167e41 bellard
731 de167e41 bellard
    /* Now build FAT, and write back information into directory */
732 de167e41 bellard
    init_fat(s);
733 de167e41 bellard
734 de167e41 bellard
    cluster=s->sectors_for_directory/s->sectors_per_cluster;
735 de167e41 bellard
    assert(s->sectors_for_directory%s->sectors_per_cluster==0);
736 de167e41 bellard
737 de167e41 bellard
    /* set the end of the last read directory */
738 de167e41 bellard
    if(s->first_file_mapping>0) {
739 de167e41 bellard
        mapping_t* mapping=array_get(&(s->mapping),s->first_file_mapping-1);
740 de167e41 bellard
        mapping->end=cluster;
741 de167e41 bellard
    }
742 de167e41 bellard
743 de167e41 bellard
    for(i=1;i<s->mapping.next;i++) {
744 de167e41 bellard
        mapping_t* mapping=array_get(&(s->mapping),i);
745 de167e41 bellard
        direntry_t* direntry=array_get(&(s->directory),mapping->dir_index);
746 de167e41 bellard
        if(mapping->mode==MODE_DIRECTORY) {
747 de167e41 bellard
            /* directory */
748 de167e41 bellard
            int i;
749 de167e41 bellard
#ifdef DEBUG
750 de167e41 bellard
            fprintf(stderr,"assert: %s %d < %d\n",mapping->filename,(int)mapping->begin,(int)mapping->end);
751 de167e41 bellard
#endif
752 de167e41 bellard
            assert(mapping->begin<mapping->end);
753 de167e41 bellard
            for(i=mapping->begin;i<mapping->end-1;i++)
754 de167e41 bellard
                fat_set(s,i,i+1);
755 de167e41 bellard
            fat_set(s,i,0x7fffffff);
756 de167e41 bellard
        } else {
757 de167e41 bellard
            /* as the space is virtual, we can be sloppy about it */
758 de167e41 bellard
            unsigned int end_cluster=cluster+mapping->end/s->cluster_size;
759 de167e41 bellard
760 de167e41 bellard
            if(end_cluster>=s->cluster_count) {
761 de167e41 bellard
                fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type);
762 de167e41 bellard
                return -1;
763 de167e41 bellard
            }
764 de167e41 bellard
            mapping->begin=cluster;
765 de167e41 bellard
            mapping->mode=MODE_NORMAL;
766 de167e41 bellard
            mapping->offset=0;
767 de167e41 bellard
            direntry->size=cpu_to_le32(mapping->end);
768 de167e41 bellard
            if(direntry->size==0) {
769 de167e41 bellard
                direntry->begin=0;
770 de167e41 bellard
                mapping->end=cluster;
771 de167e41 bellard
                continue;
772 de167e41 bellard
            }
773 de167e41 bellard
774 de167e41 bellard
            direntry->begin=cpu_to_le16(cluster);
775 de167e41 bellard
            mapping->end=end_cluster+1;
776 de167e41 bellard
            for(;cluster<end_cluster;cluster++)
777 de167e41 bellard
                fat_set(s,cluster,cluster+1);
778 de167e41 bellard
            fat_set(s,cluster,0x7fffffff);
779 de167e41 bellard
            cluster++;
780 de167e41 bellard
        }
781 de167e41 bellard
    }
782 de167e41 bellard
783 de167e41 bellard
    s->current_mapping=0;
784 de167e41 bellard
785 de167e41 bellard
    bootsector->jump[0]=0xeb;
786 de167e41 bellard
    bootsector->jump[1]=0x3e;
787 de167e41 bellard
    bootsector->jump[2]=0x90;
788 de167e41 bellard
    memcpy(bootsector->name,"QEMU    ",8);
789 de167e41 bellard
    bootsector->sector_size=cpu_to_le16(0x200);
790 de167e41 bellard
    bootsector->sectors_per_cluster=s->sectors_per_cluster;
791 de167e41 bellard
    bootsector->reserved_sectors=cpu_to_le16(1);
792 de167e41 bellard
    bootsector->number_of_fats=0x2; /* number of FATs */
793 de167e41 bellard
    bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
794 de167e41 bellard
    bootsector->zero=0;
795 de167e41 bellard
    bootsector->media_type=(s->first_sectors_number==1?0xf0:0xf8); /* media descriptor */
796 de167e41 bellard
    bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
797 de167e41 bellard
    bootsector->sectors_per_track=cpu_to_le16(0x3f);
798 de167e41 bellard
    bootsector->number_of_heads=cpu_to_le16(0x10);
799 de167e41 bellard
    bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
800 de167e41 bellard
    /* TODO: if FAT32, adjust */
801 de167e41 bellard
    bootsector->total_sectors=cpu_to_le32(s->sector_count);
802 de167e41 bellard
803 de167e41 bellard
    /* TODO: if FAT32, this is wrong */
804 de167e41 bellard
    bootsector->u.fat16.drive_number=0x80; /* assume this is hda (TODO) */
805 de167e41 bellard
    bootsector->u.fat16.current_head=0;
806 de167e41 bellard
    bootsector->u.fat16.signature=0x29;
807 de167e41 bellard
    bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
808 de167e41 bellard
809 de167e41 bellard
    memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
810 de167e41 bellard
    memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12   ":s->fat_type==16?"FAT16   ":"FAT32   "),8);
811 de167e41 bellard
    bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
812 de167e41 bellard
813 de167e41 bellard
    return 0;
814 de167e41 bellard
}
815 de167e41 bellard
816 de167e41 bellard
static int vvfat_open(BlockDriverState *bs, const char* dirname)
817 de167e41 bellard
{
818 de167e41 bellard
    BDRVVVFATState *s = bs->opaque;
819 de167e41 bellard
    int i;
820 de167e41 bellard
821 de167e41 bellard
    /* TODO: automatically determine which FAT type */
822 de167e41 bellard
    s->fat_type=16;
823 de167e41 bellard
    s->sector_count=0xec04f;
824 de167e41 bellard
825 de167e41 bellard
    s->current_cluster=0xffffffff;
826 de167e41 bellard
    s->first_file_mapping=0;
827 de167e41 bellard
828 de167e41 bellard
    /* TODO: if simulating a floppy, this is 1, because there is no partition table */
829 de167e41 bellard
    s->first_sectors_number=0x40;
830 de167e41 bellard
    
831 de167e41 bellard
    if (strstart(dirname, "fat:", &dirname)) {
832 de167e41 bellard
        /* read only is the default for safety */
833 de167e41 bellard
        bs->read_only = 1;
834 de167e41 bellard
    } else if (strstart(dirname, "fatrw:", &dirname)) {
835 de167e41 bellard
        /* development only for now */
836 de167e41 bellard
        bs->read_only = 0;
837 de167e41 bellard
    } else {
838 de167e41 bellard
        return -1;
839 de167e41 bellard
    }
840 de167e41 bellard
    if(init_directory(s,dirname))
841 de167e41 bellard
        return -1;
842 de167e41 bellard
843 de167e41 bellard
    if(s->first_sectors_number==0x40)
844 de167e41 bellard
        init_mbr(s);
845 de167e41 bellard
846 de167e41 bellard
    /* TODO: this could be wrong for FAT32 */
847 de167e41 bellard
    bs->cyls=1023; bs->heads=15; bs->secs=63;
848 de167e41 bellard
    bs->total_sectors=bs->cyls*bs->heads*bs->secs;
849 de167e41 bellard
850 de167e41 bellard
    /* write support */
851 de167e41 bellard
    for(i=0;i<3;i++)
852 de167e41 bellard
        s->action[i]=WRITE_UNDEFINED;
853 de167e41 bellard
    return 0;
854 de167e41 bellard
}
855 de167e41 bellard
856 de167e41 bellard
static inline void vvfat_close_current_file(BDRVVVFATState *s)
857 de167e41 bellard
{
858 de167e41 bellard
    if(s->current_mapping) {
859 de167e41 bellard
        s->current_mapping = 0;
860 de167e41 bellard
        close(s->current_fd);
861 de167e41 bellard
    }
862 de167e41 bellard
}
863 de167e41 bellard
864 de167e41 bellard
/* mappings between index1 and index2-1 are supposed to be ordered
865 de167e41 bellard
 * return value is the index of the last mapping for which end>cluster_num
866 de167e41 bellard
 */
867 de167e41 bellard
static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
868 de167e41 bellard
{
869 de167e41 bellard
    int index3=index1+1;
870 de167e41 bellard
    //fprintf(stderr,"find_aux: cluster_num=%d, index1=%d,index2=%d\n",cluster_num,index1,index2);
871 de167e41 bellard
    while(1) {
872 de167e41 bellard
        mapping_t* mapping;
873 de167e41 bellard
        index3=(index1+index2)/2;
874 de167e41 bellard
        mapping=array_get(&(s->mapping),index3);
875 de167e41 bellard
        //fprintf(stderr,"index3: %d = (%d+%d)/2, end: %d\n",index3,index1,index2,(int)mapping->end);
876 de167e41 bellard
        if(mapping->end>cluster_num) {
877 de167e41 bellard
            assert(index2!=index3 || index2==0);
878 de167e41 bellard
            if(index2==index3)
879 de167e41 bellard
                return index2;
880 de167e41 bellard
            index2=index3;
881 de167e41 bellard
        } else {
882 de167e41 bellard
            if(index1==index3)
883 de167e41 bellard
                return index2;
884 de167e41 bellard
            index1=index3;
885 de167e41 bellard
        }
886 de167e41 bellard
        assert(index1<=index2);
887 de167e41 bellard
    }
888 de167e41 bellard
}
889 de167e41 bellard
890 de167e41 bellard
static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
891 de167e41 bellard
{
892 de167e41 bellard
    int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
893 de167e41 bellard
    mapping_t* mapping;
894 de167e41 bellard
    if(index>=s->mapping.next)
895 de167e41 bellard
        return 0;
896 de167e41 bellard
    mapping=array_get(&(s->mapping),index);
897 de167e41 bellard
    if(mapping->begin>cluster_num)
898 de167e41 bellard
        return 0;
899 de167e41 bellard
    return mapping;
900 de167e41 bellard
}
901 de167e41 bellard
902 de167e41 bellard
static int open_file(BDRVVVFATState* s,mapping_t* mapping,int flags)
903 de167e41 bellard
{
904 de167e41 bellard
    if(!mapping)
905 de167e41 bellard
        return -1;
906 de167e41 bellard
    assert(flags==O_RDONLY || flags==O_RDWR);
907 de167e41 bellard
    if(!s->current_mapping ||
908 de167e41 bellard
            strcmp(s->current_mapping->filename,mapping->filename) ||
909 de167e41 bellard
            (flags==O_RDWR && !s->current_fd_is_writable)) {
910 de167e41 bellard
        /* open file */
911 de167e41 bellard
        int fd = open(mapping->filename, flags | O_BINARY | O_LARGEFILE);
912 de167e41 bellard
        if(fd<0)
913 de167e41 bellard
            return -1;
914 de167e41 bellard
        vvfat_close_current_file(s);
915 de167e41 bellard
        s->current_fd = fd;
916 de167e41 bellard
        s->current_fd_is_writable = (flags==O_RDWR?-1:0);
917 de167e41 bellard
        s->current_mapping = mapping;
918 de167e41 bellard
    }
919 de167e41 bellard
    return 0;
920 de167e41 bellard
}
921 de167e41 bellard
922 de167e41 bellard
static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
923 de167e41 bellard
{
924 de167e41 bellard
    if(s->current_cluster != cluster_num) {
925 de167e41 bellard
        int result=0;
926 de167e41 bellard
        off_t offset;
927 de167e41 bellard
        if(!s->current_mapping
928 de167e41 bellard
                || s->current_mapping->begin>cluster_num
929 de167e41 bellard
                || s->current_mapping->end<=cluster_num) {
930 de167e41 bellard
            /* binary search of mappings for file */
931 de167e41 bellard
            mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
932 de167e41 bellard
            if(open_file(s,mapping,O_RDONLY))
933 de167e41 bellard
                return -2;
934 de167e41 bellard
        }
935 de167e41 bellard
936 de167e41 bellard
        offset=s->cluster_size*(cluster_num-s->current_mapping->begin+s->current_mapping->offset);
937 de167e41 bellard
        if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
938 de167e41 bellard
            return -3;
939 de167e41 bellard
        result=read(s->current_fd,s->cluster,s->cluster_size);
940 de167e41 bellard
        if(result<0) {
941 de167e41 bellard
            s->current_cluster = -1;
942 de167e41 bellard
            return -1;
943 de167e41 bellard
        }
944 de167e41 bellard
        s->current_cluster = cluster_num;
945 de167e41 bellard
    }
946 de167e41 bellard
    return 0;
947 de167e41 bellard
}
948 de167e41 bellard
949 de167e41 bellard
static int vvfat_read(BlockDriverState *bs, int64_t sector_num, 
950 de167e41 bellard
                    uint8_t *buf, int nb_sectors)
951 de167e41 bellard
{
952 de167e41 bellard
    BDRVVVFATState *s = bs->opaque;
953 de167e41 bellard
    int i;
954 de167e41 bellard
955 de167e41 bellard
    //    fprintf(stderr,"vvfat_read: sector %d+%d\n",(int)sector_num,nb_sectors);
956 de167e41 bellard
957 de167e41 bellard
    for(i=0;i<nb_sectors;i++,sector_num++) {
958 de167e41 bellard
        if(sector_num<s->faked_sectors) {
959 de167e41 bellard
                if(sector_num<s->first_sectors_number)
960 de167e41 bellard
                    memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
961 de167e41 bellard
                else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
962 de167e41 bellard
                        memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
963 de167e41 bellard
                else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
964 de167e41 bellard
                        memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
965 de167e41 bellard
                else if(sector_num-s->first_sectors_number-s->sectors_per_fat*2<s->sectors_for_directory)
966 de167e41 bellard
                        memcpy(buf+i*0x200,&(s->directory.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat*2)*0x200]),0x200);
967 de167e41 bellard
        } else {
968 de167e41 bellard
            uint32_t sector=sector_num-s->first_sectors_number-s->sectors_per_fat*2,
969 de167e41 bellard
                sector_offset_in_cluster=(sector%s->sectors_per_cluster),
970 de167e41 bellard
                cluster_num=sector/s->sectors_per_cluster;
971 de167e41 bellard
                if(read_cluster(s, cluster_num) != 0) {
972 de167e41 bellard
                        //fprintf(stderr,"failed to read cluster %d\n",(int)cluster_num);
973 de167e41 bellard
                        // TODO: strict: return -1;
974 de167e41 bellard
                        memset(buf+i*0x200,0,0x200);
975 de167e41 bellard
                        continue;
976 de167e41 bellard
                }
977 de167e41 bellard
                memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
978 de167e41 bellard
        }
979 de167e41 bellard
    }
980 de167e41 bellard
    return 0;
981 de167e41 bellard
}
982 de167e41 bellard
983 de167e41 bellard
static void print_direntry(direntry_t* direntry)
984 de167e41 bellard
{
985 de167e41 bellard
    if(!direntry)
986 de167e41 bellard
        return;
987 de167e41 bellard
    if(direntry->attributes==0xf) {
988 de167e41 bellard
        unsigned char* c=(unsigned char*)direntry;
989 de167e41 bellard
        int i;
990 de167e41 bellard
        for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
991 de167e41 bellard
            fputc(c[i],stderr);
992 de167e41 bellard
        for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
993 de167e41 bellard
            fputc(c[i],stderr);
994 de167e41 bellard
        for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
995 de167e41 bellard
            fputc(c[i],stderr);
996 de167e41 bellard
        fputc('\n',stderr);
997 de167e41 bellard
    } else {
998 de167e41 bellard
        int i;
999 de167e41 bellard
        for(i=0;i<11;i++)
1000 de167e41 bellard
            fputc(direntry->name[i],stderr);
1001 de167e41 bellard
        fprintf(stderr,"attributes=0x%02x begin=%d size=%d\n",
1002 de167e41 bellard
                direntry->attributes,
1003 de167e41 bellard
                direntry->begin,direntry->size);
1004 de167e41 bellard
    }
1005 de167e41 bellard
}
1006 de167e41 bellard
1007 de167e41 bellard
static void print_changed_sector(BlockDriverState *bs,int64_t sector_num,const uint8_t *buf)
1008 de167e41 bellard
{
1009 de167e41 bellard
    BDRVVVFATState *s = bs->opaque;
1010 de167e41 bellard
1011 de167e41 bellard
    if(sector_num<s->first_sectors_number)
1012 de167e41 bellard
        return;
1013 de167e41 bellard
    if(sector_num<s->first_sectors_number+s->sectors_per_fat*2) {
1014 de167e41 bellard
        int first=((sector_num-s->first_sectors_number)%s->sectors_per_fat);
1015 de167e41 bellard
        int first_fat_entry=first*0x200/2;
1016 de167e41 bellard
        int i;
1017 de167e41 bellard
1018 de167e41 bellard
        fprintf(stderr, "fat:\n");
1019 de167e41 bellard
        for(i=0;i<0x200;i+=2) {
1020 de167e41 bellard
            uint16_t* f=array_get(&(s->fat),first_fat_entry+i/2);
1021 de167e41 bellard
            if(memcmp(buf+i,f,2))
1022 de167e41 bellard
                fprintf(stderr,"%d(%d->%d) ",first_fat_entry+i/2,*f,*(uint16_t*)(buf+i));
1023 de167e41 bellard
        }
1024 de167e41 bellard
        fprintf(stderr, "\n");
1025 de167e41 bellard
    } else if(sector_num<s->faked_sectors) {
1026 de167e41 bellard
        direntry_t* d=(direntry_t*)buf;
1027 de167e41 bellard
        int i;
1028 de167e41 bellard
        fprintf(stderr, "directory:\n");
1029 de167e41 bellard
        for(i=0;i<0x200/sizeof(direntry_t);i++) {
1030 de167e41 bellard
            direntry_t* d_old=(direntry_t*)(s->directory.pointer+0x200*(sector_num-s->first_sectors_number-s->sectors_per_fat*2)+i*sizeof(direntry_t));
1031 de167e41 bellard
            if(memcmp(d+i,d_old,sizeof(direntry_t))) {
1032 de167e41 bellard
                fprintf(stderr, "old: "); print_direntry(d_old);
1033 de167e41 bellard
                fprintf(stderr, "new: "); print_direntry(d+i);
1034 de167e41 bellard
                fprintf(stderr, "\n");
1035 de167e41 bellard
            }
1036 de167e41 bellard
        }
1037 de167e41 bellard
    } else {
1038 de167e41 bellard
        int sec=(sector_num-s->first_sectors_number-2*s->sectors_per_fat);
1039 de167e41 bellard
        fprintf(stderr, "\tcluster: %d(+%d sectors)\n",sec/s->sectors_per_cluster,sec%s->sectors_per_cluster);
1040 de167e41 bellard
    }
1041 de167e41 bellard
}
1042 de167e41 bellard
1043 de167e41 bellard
char direntry_is_free(const direntry_t* direntry)
1044 de167e41 bellard
{
1045 de167e41 bellard
    return direntry->name[0]==0 || direntry->name[0]==0xe5;
1046 de167e41 bellard
}
1047 de167e41 bellard
1048 de167e41 bellard
/* TODO: use this everywhere */
1049 de167e41 bellard
static inline uint32_t begin_of_direntry(direntry_t* direntry)
1050 de167e41 bellard
{
1051 de167e41 bellard
    return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
1052 de167e41 bellard
}
1053 de167e41 bellard
1054 de167e41 bellard
int consistency_check1(BDRVVVFATState *s) {
1055 de167e41 bellard
    /* check all mappings */
1056 de167e41 bellard
    int i;
1057 de167e41 bellard
    for(i=0;i<s->mapping.next;i++) {
1058 de167e41 bellard
        mapping_t* mapping=array_get(&(s->mapping),i);
1059 de167e41 bellard
        int j;
1060 de167e41 bellard
        for(j=mapping->begin;j<mapping->end-1;j++)
1061 de167e41 bellard
            assert(fat_get(s,j)==j+1);
1062 de167e41 bellard
        assert(fat_get(s,j)==(0x7fffffff&s->max_fat_value));
1063 de167e41 bellard
    }
1064 de167e41 bellard
    return 0;
1065 de167e41 bellard
}
1066 de167e41 bellard
1067 de167e41 bellard
int consistency_check2(BDRVVVFATState *s) {
1068 de167e41 bellard
    /* check fat entries: consecutive fat entries should be mapped in one mapping */
1069 de167e41 bellard
    int i;
1070 de167e41 bellard
    /* TODO: i=0 (mappings for direntries have to be sorted) */
1071 de167e41 bellard
    for(i=s->sectors_for_directory/s->sectors_per_cluster;i<s->fat.next-1;i++) {
1072 de167e41 bellard
        uint32_t j=fat_get(s,i);
1073 de167e41 bellard
        if(j!=i+1 && j!=0 && !fat_eof(s,j)) {
1074 de167e41 bellard
            mapping_t* mapping=find_mapping_for_cluster(s,i+1);
1075 de167e41 bellard
            assert(mapping->begin==i+1);
1076 de167e41 bellard
        }
1077 de167e41 bellard
    }
1078 de167e41 bellard
    return 0;
1079 de167e41 bellard
}
1080 de167e41 bellard
1081 de167e41 bellard
int consistency_check3(BDRVVVFATState *s) {
1082 de167e41 bellard
    /* check that for each file there is exactly one mapping per cluster */
1083 de167e41 bellard
    int i,count_non_next=0;
1084 de167e41 bellard
    for(i=0;i<s->mapping.next;i++) {
1085 de167e41 bellard
        mapping_t* mapping=array_get(&(s->mapping),i);
1086 de167e41 bellard
        /* TODO: when directories are correctly adapted, add them here */
1087 de167e41 bellard
        assert(mapping->begin<mapping->end);
1088 de167e41 bellard
        if(mapping->mode==MODE_NORMAL) {
1089 de167e41 bellard
            int j,count=0,count_next=0;
1090 de167e41 bellard
            for(j=0;j<s->mapping.next;j++) {
1091 de167e41 bellard
                mapping_t* other=array_get(&(s->mapping),j);
1092 de167e41 bellard
                if(mapping->begin<other->end&&mapping->end>other->begin)
1093 de167e41 bellard
                    count++;
1094 de167e41 bellard
                if(mapping->end==other->begin)
1095 de167e41 bellard
                    count_next++;
1096 de167e41 bellard
            }
1097 de167e41 bellard
            assert(count==1); /* no overlapping mappings */
1098 de167e41 bellard
            assert(count_next==1 || count_next==0); /* every mapping except the last one has a successor */
1099 de167e41 bellard
            if(!count_next)
1100 de167e41 bellard
                count_non_next++;
1101 de167e41 bellard
        }
1102 de167e41 bellard
    }
1103 de167e41 bellard
    assert(count_non_next==1); /* only one last mapping */
1104 de167e41 bellard
    return 0;
1105 de167e41 bellard
}
1106 de167e41 bellard
1107 de167e41 bellard
static inline commit_t* commit_get_next(BDRVVVFATState* s)
1108 de167e41 bellard
{
1109 de167e41 bellard
    commit_t* commit=array_get_next(&(s->commit));
1110 de167e41 bellard
    if((commit->buf=malloc(s->cluster_size))==0) {
1111 de167e41 bellard
        /* out of memory */
1112 de167e41 bellard
        s->commit.next--;
1113 de167e41 bellard
        return 0;
1114 de167e41 bellard
    }
1115 de167e41 bellard
    return commit;
1116 de167e41 bellard
}
1117 de167e41 bellard
1118 de167e41 bellard
int commit_remove(BDRVVVFATState* s,commit_t* commit)
1119 de167e41 bellard
{
1120 de167e41 bellard
    int index=commit-(commit_t*)s->commit.pointer;
1121 de167e41 bellard
    free(commit->buf);
1122 de167e41 bellard
    if(array_roll(&(s->commit),s->commit.next-1,index,1))
1123 de167e41 bellard
        return -1;
1124 de167e41 bellard
    s->commit.next--;
1125 de167e41 bellard
    return 0;
1126 de167e41 bellard
}
1127 de167e41 bellard
1128 de167e41 bellard
/* TODO: the plan for write support:
1129 de167e41 bellard
 *
1130 de167e41 bellard
 * it seems that the direntries are written first, then the data is committed
1131 de167e41 bellard
 * to the free sectors, then fat 1 is updated, then fat2.
1132 de167e41 bellard
 *
1133 de167e41 bellard
 * Plan: when sectors are written, do the following:
1134 de167e41 bellard
 *
1135 de167e41 bellard
 * - if they are in a directory, check if the entry has changed. if yes,
1136 de167e41 bellard
 *   look what has changed (different strategies for name, begin & size).
1137 de167e41 bellard
 *
1138 de167e41 bellard
 *   if it is new (old entry is only 0's or has E5 at the start), create it,
1139 de167e41 bellard
 *   and also create mapping, but in a special mode "undefined" (TODO),
1140 de167e41 bellard
 *   because we cannot know which clusters belong to it yet.
1141 de167e41 bellard
 *
1142 de167e41 bellard
 *   if it is zeroed, or has E5 at the start, look if has just moved. If yes,
1143 de167e41 bellard
 *   copy the entry to the new position. If no, delete the file.
1144 de167e41 bellard
 *
1145 de167e41 bellard
 * - if they are in data, and the cluster is undefined, add it to the commit
1146 de167e41 bellard
 *   list. if the cluster is defined (find_mapping), then write it into the
1147 de167e41 bellard
 *   corresponding file.
1148 de167e41 bellard
 *
1149 de167e41 bellard
 *   If it is the last cluster (TODO: add a function
1150 de167e41 bellard
 *   fat_get(s,cluster); ), make sure not to write a complete cluster_size.
1151 de167e41 bellard
 *
1152 de167e41 bellard
 *   If the data is in current_cluster, update s->cluster.
1153 de167e41 bellard
 *
1154 de167e41 bellard
 * - if they are in fat 1, update mappings, look in the commit list
1155 de167e41 bellard
 *   (assertions!) and if the cluster is now known (or changed from undefined
1156 de167e41 bellard
 *   state to defined state, like when begin or size changed in a direntry),
1157 de167e41 bellard
 *   write it.
1158 de167e41 bellard
 *
1159 de167e41 bellard
 * - if they are in fat 2, make sure they match with current fat.
1160 de167e41 bellard
 *
1161 de167e41 bellard
 */
1162 de167e41 bellard
1163 de167e41 bellard
void mapping_modify_from_direntry(BDRVVVFATState* s,mapping_t* mapping,direntry_t* direntry)
1164 de167e41 bellard
{
1165 de167e41 bellard
    int begin=le16_to_cpu(direntry->begin),
1166 de167e41 bellard
        end=begin+le32_to_cpu(direntry->size)/s->cluster_size+1,
1167 de167e41 bellard
        i;
1168 de167e41 bellard
    mapping->mode = MODE_MODIFIED;
1169 de167e41 bellard
    /* TODO: what if begin==0 (size==0)? */
1170 de167e41 bellard
    mapping->begin = begin;
1171 de167e41 bellard
    /* TODO: why not just mapping->end = begin+1 ? */
1172 de167e41 bellard
    for(i=begin+1;i<end && (fat_get(s,i)==0 || fat_get(s,i)==i+1);i++);
1173 de167e41 bellard
    mapping->end = i;
1174 de167e41 bellard
}
1175 de167e41 bellard
1176 de167e41 bellard
mapping_t* find_mapping_for_direntry(BDRVVVFATState* s,direntry_t* direntry)
1177 de167e41 bellard
{
1178 de167e41 bellard
    int i;
1179 de167e41 bellard
    int dir_index=direntry-((direntry_t*)s->directory.pointer);
1180 de167e41 bellard
    
1181 de167e41 bellard
    /* TODO: support allocation for new clusters for directories (new/larger directory */
1182 de167e41 bellard
    assert(dir_index<0x200/0x20*s->sectors_for_directory);
1183 de167e41 bellard
    
1184 de167e41 bellard
    for(i=0;i<s->mapping.next;i++) {
1185 de167e41 bellard
        mapping_t* mapping=array_get(&(s->mapping),i);
1186 de167e41 bellard
        if(mapping->dir_index==dir_index && mapping->offset==0 &&
1187 de167e41 bellard
                mapping->mode!=MODE_UNDEFINED)
1188 de167e41 bellard
            return mapping;
1189 de167e41 bellard
    }
1190 de167e41 bellard
    return 0;
1191 de167e41 bellard
}
1192 de167e41 bellard
1193 de167e41 bellard
static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
1194 de167e41 bellard
{
1195 de167e41 bellard
    return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)/s->sectors_per_cluster;
1196 de167e41 bellard
}
1197 de167e41 bellard
1198 de167e41 bellard
static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
1199 de167e41 bellard
{
1200 de167e41 bellard
    return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
1201 de167e41 bellard
}
1202 de167e41 bellard
1203 de167e41 bellard
static commit_t* get_commit_for_cluster(BDRVVVFATState* s,uint32_t cluster_num)
1204 de167e41 bellard
{
1205 de167e41 bellard
    int i;
1206 de167e41 bellard
    for(i=0;i<s->commit.next;i++) {
1207 de167e41 bellard
        commit_t* commit=array_get(&(s->commit),i);
1208 de167e41 bellard
        if(commit->cluster_num==cluster_num)
1209 de167e41 bellard
            return commit;
1210 de167e41 bellard
    }
1211 de167e41 bellard
    return 0;
1212 de167e41 bellard
}
1213 de167e41 bellard
1214 de167e41 bellard
static inline commit_t* create_or_get_commit_for_sector(BDRVVVFATState* s,off_t sector_num)
1215 de167e41 bellard
{
1216 de167e41 bellard
    int i;
1217 de167e41 bellard
    commit_t* commit;
1218 de167e41 bellard
    uint32_t cluster_num=sector2cluster(s,sector_num);
1219 de167e41 bellard
1220 de167e41 bellard
    for(i=0;i<s->commit.next;i++) {
1221 de167e41 bellard
        commit=array_get(&(s->commit),i);
1222 de167e41 bellard
        if(commit->cluster_num==cluster_num)
1223 de167e41 bellard
            return commit;
1224 de167e41 bellard
    }
1225 de167e41 bellard
1226 de167e41 bellard
    commit=commit_get_next(s);
1227 de167e41 bellard
    commit->cluster_num=cluster_num;
1228 de167e41 bellard
    /* we can ignore read errors here */
1229 de167e41 bellard
    read_cluster(s,cluster_num);
1230 de167e41 bellard
    memcpy(commit->buf,s->cluster,s->cluster_size);
1231 de167e41 bellard
    return commit;
1232 de167e41 bellard
}
1233 de167e41 bellard
1234 de167e41 bellard
static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
1235 de167e41 bellard
{
1236 de167e41 bellard
    if(mapping->mode==MODE_UNDEFINED)
1237 de167e41 bellard
        return 0;
1238 de167e41 bellard
    if(mapping->dir_index>=0x200/0x20*s->sectors_for_directory)
1239 de167e41 bellard
        return 0;
1240 de167e41 bellard
    return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
1241 de167e41 bellard
}
1242 de167e41 bellard
1243 de167e41 bellard
static void print_mappings(BDRVVVFATState* s)
1244 de167e41 bellard
{
1245 de167e41 bellard
    int i;
1246 de167e41 bellard
    fprintf(stderr,"mapping:\n");
1247 de167e41 bellard
    for(i=0;i<s->mapping.next;i++) {
1248 de167e41 bellard
        mapping_t* m=array_get(&(s->mapping),i);
1249 de167e41 bellard
        direntry_t* d=get_direntry_for_mapping(s,m);
1250 de167e41 bellard
        fprintf(stderr,"%02d %d-%d (%d) %s (dir: %d)",i,(int)m->begin,(int)m->end,(int)m->offset,m->filename,m->dir_index);
1251 de167e41 bellard
        print_direntry(d);
1252 de167e41 bellard
        fprintf(stderr,"\n");
1253 de167e41 bellard
    }
1254 de167e41 bellard
    fprintf(stderr,"mappings end.\n");
1255 de167e41 bellard
}
1256 de167e41 bellard
1257 de167e41 bellard
/* TODO: statify all functions */
1258 de167e41 bellard
1259 de167e41 bellard
/* This function is only meant for file contents.
1260 de167e41 bellard
 * It will return an error if used for other sectors. */
1261 de167e41 bellard
static int write_cluster(BDRVVVFATState* s,uint32_t cluster_num,const uint8_t* buf)
1262 de167e41 bellard
{
1263 de167e41 bellard
    /* sector_offset is the sector_num relative to the first cluster */
1264 de167e41 bellard
    mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
1265 de167e41 bellard
    direntry_t* direntry;
1266 de167e41 bellard
    int next_cluster,write_size,last_cluster;
1267 de167e41 bellard
    off_t offset;
1268 de167e41 bellard
1269 de167e41 bellard
    /* if this cluster is free, return error */
1270 de167e41 bellard
    next_cluster=fat_get(s,cluster_num);
1271 de167e41 bellard
    if(next_cluster<2)
1272 de167e41 bellard
        return -1;
1273 de167e41 bellard
    
1274 de167e41 bellard
    /* TODO: MODE_DIRECTORY */
1275 de167e41 bellard
    if(!mapping || mapping->mode==MODE_UNDEFINED || mapping->mode==MODE_DIRECTORY)
1276 de167e41 bellard
        return -1;
1277 de167e41 bellard
    direntry=get_direntry_for_mapping(s,mapping);
1278 de167e41 bellard
    if(!direntry)
1279 de167e41 bellard
        return -2;
1280 de167e41 bellard
1281 de167e41 bellard
    /* get size to write */
1282 de167e41 bellard
    last_cluster=fat_eof(s,next_cluster);
1283 de167e41 bellard
    write_size=!last_cluster?s->cluster_size:
1284 de167e41 bellard
        (le32_to_cpu(direntry->size)%s->cluster_size);
1285 de167e41 bellard
    if(write_size<=0)
1286 de167e41 bellard
        return 0;
1287 de167e41 bellard
    //fprintf(stderr,"next_cluster: %d (%d), write_size: %d, %d, %d\n",next_cluster,s->max_fat_value-8,write_size,direntry->size,s->cluster_size);
1288 de167e41 bellard
1289 de167e41 bellard
    if(open_file(s,mapping,O_RDWR))
1290 de167e41 bellard
        return -4;
1291 de167e41 bellard
   
1292 de167e41 bellard
    offset=(cluster_num-mapping->begin+mapping->offset)*s->cluster_size;
1293 de167e41 bellard
    if(lseek(s->current_fd,offset,SEEK_SET)!=offset)
1294 de167e41 bellard
        return -3;
1295 de167e41 bellard
    if(write(s->current_fd,buf,write_size)!=write_size) {
1296 de167e41 bellard
        lseek(s->current_fd,0,SEEK_END);
1297 de167e41 bellard
        vvfat_close_current_file(s);
1298 de167e41 bellard
        return -2;
1299 de167e41 bellard
    }
1300 de167e41 bellard
1301 de167e41 bellard
    /* seek to end of file, so it doesn't get truncated */
1302 de167e41 bellard
    if(!last_cluster)
1303 de167e41 bellard
        lseek(s->current_fd,0,SEEK_END);
1304 de167e41 bellard
    else {
1305 de167e41 bellard
        ftruncate(s->current_fd,le32_to_cpu(direntry->size));
1306 de167e41 bellard
        vvfat_close_current_file(s);
1307 de167e41 bellard
    }
1308 de167e41 bellard
1309 de167e41 bellard
    /* update s->cluster if necessary */
1310 de167e41 bellard
    if(cluster_num==s->current_cluster && s->cluster!=buf)
1311 de167e41 bellard
        memcpy(s->cluster,buf,s->cluster_size);
1312 de167e41 bellard
1313 de167e41 bellard
    return 0;
1314 de167e41 bellard
}
1315 de167e41 bellard
1316 de167e41 bellard
/* this function returns !=0 on error */
1317 de167e41 bellard
int mapping_is_consistent(BDRVVVFATState* s,mapping_t* mapping)
1318 de167e41 bellard
{
1319 de167e41 bellard
    direntry_t* direntry=get_direntry_for_mapping(s,mapping);
1320 de167e41 bellard
    uint32_t cluster_count=0;
1321 de167e41 bellard
    int commit_count=0; /* number of commits for this file (we also write incomplete files; think "append") */
1322 de167e41 bellard
    //fprintf(stderr,"check direntry for %s\n",mapping->filename);
1323 de167e41 bellard
    while(mapping) {
1324 de167e41 bellard
        int i;
1325 de167e41 bellard
        assert(mapping->begin<mapping->end);
1326 de167e41 bellard
        for(i=mapping->begin;i<mapping->end-1;i++) {
1327 de167e41 bellard
            if(i<=0 || fat_get(s,i)!=i+1) {
1328 de167e41 bellard
                /*fprintf(stderr,"the fat mapping of %d is not %d, but %d\n",
1329 de167e41 bellard
                        i,i+1,fat_get(s,i));*/
1330 de167e41 bellard
                return -1;
1331 de167e41 bellard
            }
1332 de167e41 bellard
            if(get_commit_for_cluster(s,i))
1333 de167e41 bellard
                commit_count++;
1334 de167e41 bellard
        }
1335 de167e41 bellard
        if(get_commit_for_cluster(s,i))
1336 de167e41 bellard
            commit_count++;
1337 de167e41 bellard
1338 de167e41 bellard
        cluster_count+=mapping->end-mapping->begin;
1339 de167e41 bellard
        
1340 de167e41 bellard
        i=fat_get(s,mapping->end-1);
1341 de167e41 bellard
        if(fat_eof(s,i))
1342 de167e41 bellard
            break;
1343 de167e41 bellard
1344 de167e41 bellard
        mapping=find_mapping_for_cluster(s,i);
1345 de167e41 bellard
        if(!mapping) {
1346 de167e41 bellard
            //fprintf(stderr,"No mapping found for %d\n",i);
1347 de167e41 bellard
            print_mappings(s);
1348 de167e41 bellard
            return -2;
1349 de167e41 bellard
        }
1350 de167e41 bellard
    }
1351 de167e41 bellard
1352 de167e41 bellard
    if(cluster_count!=(le32_to_cpu(direntry->size)+s->cluster_size-1)/s->cluster_size) {
1353 de167e41 bellard
        //fprintf(stderr,"cluster_count is %d, but size is %d\n",cluster_count,le32_to_cpu(direntry->size));
1354 de167e41 bellard
        return -3;
1355 de167e41 bellard
    }
1356 de167e41 bellard
1357 de167e41 bellard
    if(commit_count==0)
1358 de167e41 bellard
        return -4;
1359 de167e41 bellard
1360 de167e41 bellard
    //fprintf(stderr,"okay\n");
1361 de167e41 bellard
    return 0;
1362 de167e41 bellard
}
1363 de167e41 bellard
1364 de167e41 bellard
/* TODO: remember what comes third, and what's first in this OS:
1365 de167e41 bellard
 * FAT, direntry or data.
1366 de167e41 bellard
 * If the last written sector is either last in cluster or sector_num+nb_sectors-1,
1367 de167e41 bellard
 *         - commit every cluster for this file if mapping_is_consistent()==0
1368 de167e41 bellard
 *         - if the last written sector is first_action, and last_action=third_action, clear commit
1369 de167e41 bellard
 */
1370 de167e41 bellard
1371 de167e41 bellard
static int commit_cluster_aux(BDRVVVFATState* s,commit_t* commit)
1372 de167e41 bellard
{
1373 de167e41 bellard
    int result=write_cluster(s,commit->cluster_num,commit->buf);
1374 de167e41 bellard
    return result;
1375 de167e41 bellard
}
1376 de167e41 bellard
1377 de167e41 bellard
1378 de167e41 bellard
static int commit_cluster(BDRVVVFATState* s,uint32_t cluster_num)
1379 de167e41 bellard
{
1380 de167e41 bellard
    commit_t* commit;
1381 de167e41 bellard
1382 de167e41 bellard
    /* commit the sectors of this cluster */
1383 de167e41 bellard
    commit=get_commit_for_cluster(s,cluster_num);
1384 de167e41 bellard
    if(commit)
1385 de167e41 bellard
        return commit_cluster_aux(s,commit);
1386 de167e41 bellard
    return 0;
1387 de167e41 bellard
}
1388 de167e41 bellard
1389 de167e41 bellard
/* this function checks the consistency for the direntry which belongs to
1390 de167e41 bellard
 * the mapping. if everything is found consistent, the data is committed.
1391 de167e41 bellard
 * this returns 0 if no error occurred (even if inconsistencies were found) */
1392 de167e41 bellard
static inline int commit_data_if_consistent(BDRVVVFATState* s,mapping_t* mapping,write_action_t action)
1393 de167e41 bellard
{
1394 de167e41 bellard
    direntry_t* direntry;
1395 de167e41 bellard
    
1396 de167e41 bellard
    if(!mapping)
1397 de167e41 bellard
        return 0;
1398 de167e41 bellard
1399 de167e41 bellard
    //fprintf(stderr,"7\n");
1400 de167e41 bellard
#define d(x) fprintf(stderr,#x "\n")
1401 de167e41 bellard
    direntry=get_direntry_for_mapping(s,mapping);
1402 de167e41 bellard
1403 de167e41 bellard
    //d(8);
1404 de167e41 bellard
1405 de167e41 bellard
    assert(action==WRITE_FAT || action==WRITE_DIRENTRY || action==WRITE_DATA);
1406 de167e41 bellard
1407 de167e41 bellard
    //d(9);
1408 de167e41 bellard
    //fprintf(stderr,"mapping: 0x%x s=0x%x\n",(uint32_t)mapping,(uint32_t)s);
1409 de167e41 bellard
    /*fprintf(stderr,"commit? file=%s, action=%s\n",
1410 de167e41 bellard
            mapping->filename,action==WRITE_FAT?"fat":action==WRITE_DIRENTRY?"direntry":"data");*/
1411 de167e41 bellard
1412 de167e41 bellard
    //d(10);
1413 de167e41 bellard
    if(s->action[2]==WRITE_UNDEFINED) {
1414 de167e41 bellard
        int i;
1415 de167e41 bellard
        for(i=2;i>0 && s->action[i-1]==WRITE_UNDEFINED;i--);
1416 de167e41 bellard
        if(i>0 && action!=s->action[i-1])
1417 de167e41 bellard
            s->action[i]=action;
1418 de167e41 bellard
        assert(i<2 || s->action[0]!=s->action[2]);
1419 de167e41 bellard
    }
1420 de167e41 bellard
    //d(11);
1421 de167e41 bellard
    
1422 de167e41 bellard
    if(mapping_is_consistent(s,mapping)==0) {
1423 de167e41 bellard
        uint32_t cluster_num=begin_of_direntry(direntry);
1424 de167e41 bellard
        off_t remaining_bytes=le32_to_cpu(direntry->size);
1425 de167e41 bellard
        //fprintf(stderr,"the data for %s was found consistent\n",mapping->filename);
1426 de167e41 bellard
        while(remaining_bytes>0) {
1427 de167e41 bellard
            commit_t* commit=get_commit_for_cluster(s,cluster_num);
1428 de167e41 bellard
            if(!commit)
1429 de167e41 bellard
                continue;
1430 de167e41 bellard
                
1431 de167e41 bellard
            //fprintf(stderr,"commit_cluster %d (%d), remaining: %d\n",cluster_num,s->max_fat_value-15,(int)remaining_bytes);
1432 de167e41 bellard
            assert(cluster_num>1);
1433 de167e41 bellard
            assert(cluster_num<s->max_fat_value-15);
1434 de167e41 bellard
            if(commit_cluster(s,cluster_num)) {
1435 de167e41 bellard
                fprintf(stderr,"error committing cluster %d\n",cluster_num);
1436 de167e41 bellard
                return -1;
1437 de167e41 bellard
            }
1438 de167e41 bellard
            cluster_num=fat_get(s,cluster_num);
1439 de167e41 bellard
            remaining_bytes-=s->cluster_size;
1440 de167e41 bellard
            /* TODO: if(action==s->action[2]) {
1441 de167e41 bellard
                commit_t* commit=get_commit_for_cluster(s,cluster_num);
1442 de167e41 bellard
                commit_remove(s,commit);
1443 de167e41 bellard
            } */
1444 de167e41 bellard
        }
1445 de167e41 bellard
    }
1446 de167e41 bellard
    //print_mappings(s);
1447 de167e41 bellard
    //fprintf(stderr,"finish vvfat_write\n");
1448 de167e41 bellard
    return 0;
1449 de167e41 bellard
}
1450 de167e41 bellard
1451 de167e41 bellard
static int vvfat_write(BlockDriverState *bs, int64_t sector_num, 
1452 de167e41 bellard
                    const uint8_t *buf, int nb_sectors)
1453 de167e41 bellard
{
1454 de167e41 bellard
    BDRVVVFATState *s = bs->opaque;
1455 de167e41 bellard
    int i;
1456 de167e41 bellard
1457 de167e41 bellard
    /* fprintf(stderr,"vvfat_write %d+%d (%s)\n",(int)sector_num,nb_sectors,
1458 de167e41 bellard
                    (sector_num>=s->faked_sectors?"data":
1459 de167e41 bellard
                     (sector_num>=s->first_sectors_number+2*s->sectors_per_fat?"directory":
1460 de167e41 bellard
                      (sector_num>=s->first_sectors_number+s->sectors_per_fat?"fat 2":
1461 de167e41 bellard
                       (sector_num>=s->first_sectors_number?"fat 1":"boot sector"))))); */
1462 de167e41 bellard
1463 de167e41 bellard
    for(i=0;i<nb_sectors;i++,sector_num++,buf+=0x200) {
1464 de167e41 bellard
        print_changed_sector(bs,sector_num,buf);
1465 de167e41 bellard
1466 de167e41 bellard
        if(sector_num<s->first_sectors_number) {
1467 de167e41 bellard
            /* change the bootsector or partition table? no! */
1468 de167e41 bellard
            return -1;
1469 de167e41 bellard
        } else if(sector_num<s->first_sectors_number+s->sectors_per_fat) {
1470 de167e41 bellard
            /* FAT 1 */
1471 de167e41 bellard
            int fat_entries_per_cluster=s->cluster_size*8/s->fat_type;
1472 de167e41 bellard
            int first_cluster=(sector_num-s->first_sectors_number)*fat_entries_per_cluster,i;
1473 de167e41 bellard
            mapping_t* mapping=0;
1474 de167e41 bellard
1475 de167e41 bellard
            /* write back */
1476 de167e41 bellard
            memcpy(s->fat.pointer+0x200*(sector_num-s->first_sectors_number),
1477 de167e41 bellard
                    buf,0x200);
1478 de167e41 bellard
1479 de167e41 bellard
            /* for each changed FAT entry, */
1480 de167e41 bellard
            for(i=0;i<fat_entries_per_cluster;i++) {
1481 de167e41 bellard
                int new_value;
1482 de167e41 bellard
                
1483 de167e41 bellard
                /* TODO: MODE_DIRENTRY */
1484 de167e41 bellard
                if(first_cluster+i<s->sectors_for_directory/s->sectors_per_cluster)
1485 de167e41 bellard
                    continue;
1486 de167e41 bellard
1487 de167e41 bellard
                new_value=fat_get(s,first_cluster+i);
1488 de167e41 bellard
1489 de167e41 bellard
                /* check the current fat entry */
1490 de167e41 bellard
                if(new_value<2 || (new_value>=s->max_fat_value-0xf && !fat_eof(s,new_value))) {
1491 de167e41 bellard
                    /* free, reserved or bad cluster */
1492 de167e41 bellard
                    mapping=find_mapping_for_cluster(s,first_cluster+i);
1493 de167e41 bellard
                    //assert(!mapping || mapping->mode==MODE_DELETED);
1494 de167e41 bellard
                    if(mapping && mapping->mode==MODE_DELETED &&
1495 de167e41 bellard
                            first_cluster+i+1==mapping->end)
1496 de167e41 bellard
                        array_remove(&(s->mapping),mapping-(mapping_t*)s->mapping.pointer);
1497 de167e41 bellard
                    mapping=0;
1498 de167e41 bellard
                    continue;
1499 de167e41 bellard
                }
1500 de167e41 bellard
1501 de167e41 bellard
                /* get the mapping for the current entry */
1502 de167e41 bellard
                if(!mapping || mapping->begin>new_value || mapping->end<=new_value) {
1503 de167e41 bellard
                    mapping=find_mapping_for_cluster(s,first_cluster+i);
1504 de167e41 bellard
                }
1505 de167e41 bellard
1506 de167e41 bellard
                print_mappings(s);
1507 de167e41 bellard
                fprintf(stderr,"fat_get(%d)=%d\n",first_cluster+i,new_value);
1508 de167e41 bellard
                /* TODO: what if there's no mapping? this is valid. */
1509 de167e41 bellard
                /* TODO: refactor the rest of this clause so it can be called when the direntry changes, too */
1510 de167e41 bellard
                assert(mapping);
1511 de167e41 bellard
1512 de167e41 bellard
                if(new_value>1 && new_value<s->max_fat_value-0xf) {
1513 de167e41 bellard
                    /* the cluster new_value points to is valid */
1514 de167e41 bellard
1515 de167e41 bellard
                    if(first_cluster+i+1==new_value) {
1516 de167e41 bellard
                        /* consecutive cluster */
1517 de167e41 bellard
                        if(mapping->end<=new_value)
1518 de167e41 bellard
                            mapping->end=new_value+1;
1519 de167e41 bellard
                    } else {
1520 de167e41 bellard
                        mapping_t* next_mapping;
1521 de167e41 bellard
                        
1522 de167e41 bellard
                        /* the current mapping ends here */
1523 de167e41 bellard
                        mapping->end=first_cluster+i+1;
1524 de167e41 bellard
                        
1525 de167e41 bellard
                        /* the next mapping */
1526 de167e41 bellard
                        next_mapping=find_mapping_for_cluster(s,new_value);
1527 de167e41 bellard
                        if(next_mapping) {
1528 de167e41 bellard
                            assert(mapping!=next_mapping);
1529 de167e41 bellard
                            /* assert next mapping's filename is the same */
1530 de167e41 bellard
                            assert(next_mapping->filename==mapping->filename);
1531 de167e41 bellard
                            assert(next_mapping->dir_index==mapping->dir_index);
1532 de167e41 bellard
                            /* assert next mapping is MODIFIED or UNDEFINED */
1533 de167e41 bellard
                            assert(next_mapping->mode==MODE_MODIFIED || next_mapping->mode==MODE_UNDEFINED);
1534 de167e41 bellard
                        } else {
1535 de167e41 bellard
                            int index=find_mapping_for_cluster_aux(s,new_value,0,s->mapping.next);
1536 de167e41 bellard
                            next_mapping=array_insert(&(s->mapping),index,1);
1537 de167e41 bellard
                            next_mapping->filename=mapping->filename;
1538 de167e41 bellard
                            next_mapping->dir_index=mapping->dir_index;
1539 de167e41 bellard
                            next_mapping->mode=MODE_MODIFIED;
1540 de167e41 bellard
                            next_mapping->begin=0;
1541 de167e41 bellard
                        }
1542 de167e41 bellard
                        /* adjust offset of next mapping */
1543 de167e41 bellard
                        next_mapping->offset=mapping->offset+mapping->end-mapping->begin;
1544 de167e41 bellard
                        /* set begin and possible end */
1545 de167e41 bellard
                        if(next_mapping->begin!=new_value) {
1546 de167e41 bellard
                            next_mapping->begin=new_value;
1547 de167e41 bellard
                            next_mapping->end=new_value+1;
1548 de167e41 bellard
                        }
1549 de167e41 bellard
                        if(commit_data_if_consistent(s,mapping,WRITE_FAT))
1550 de167e41 bellard
                            return -4;
1551 de167e41 bellard
                        mapping=0;
1552 de167e41 bellard
                    }
1553 de167e41 bellard
                } else if(fat_eof(s,new_value)) {
1554 de167e41 bellard
                    /* the last cluster of the file */
1555 de167e41 bellard
                    mapping->end=first_cluster+i+1;
1556 de167e41 bellard
                    if(commit_data_if_consistent(s,mapping,WRITE_FAT))
1557 de167e41 bellard
                        return -4;
1558 de167e41 bellard
                    mapping=0;
1559 de167e41 bellard
                }
1560 de167e41 bellard
            }
1561 de167e41 bellard
        } else if(sector_num<s->first_sectors_number+2*s->sectors_per_fat) {
1562 de167e41 bellard
            /* FAT 2: check if it is the same as FAT 1 */
1563 de167e41 bellard
            if(memcmp(array_get(&(s->fat),sector_num-s->first_sectors_number),buf,0x200))
1564 de167e41 bellard
                return -1; /* mismatch */
1565 de167e41 bellard
        } else if(sector_num<s->faked_sectors) {
1566 de167e41 bellard
            /* direntry */
1567 de167e41 bellard
            /* - if they are in a directory, check if the entry has changed.
1568 de167e41 bellard
             *   if yes, look what has changed (different strategies for name,
1569 de167e41 bellard
             *   begin & size).
1570 de167e41 bellard
             *
1571 de167e41 bellard
             *   if it is new (old entry is only 0's or has E5 at the start),
1572 de167e41 bellard
             *   create it, and also create mapping, but in a special mode
1573 de167e41 bellard
             *   "undefined", because we cannot know which clusters belong
1574 de167e41 bellard
             *   to it yet.
1575 de167e41 bellard
             *
1576 de167e41 bellard
             *   if it is zeroed, or has E5 at the start, look if has just
1577 de167e41 bellard
             *   moved. If yes, copy the entry to the new position. If no,
1578 de167e41 bellard
             *   delete the file.
1579 de167e41 bellard
             */
1580 de167e41 bellard
            mapping_t* dir_mapping=find_mapping_for_cluster(s,sector2cluster(s,sector_num));
1581 de167e41 bellard
            direntry_t *original=array_get(&(s->directory),sector_num-s->first_sectors_number-2*s->sectors_per_fat);
1582 de167e41 bellard
            direntry_t *new_=(direntry_t*)buf;
1583 de167e41 bellard
            int first_dir_index=(sector_num-s->first_sectors_number-2*s->sectors_per_fat)*0x200/0x20;
1584 de167e41 bellard
            int j;
1585 de167e41 bellard
1586 de167e41 bellard
#if 0
1587 de167e41 bellard
            fprintf(stderr,"direntry: consistency check\n");
1588 de167e41 bellard

1589 de167e41 bellard
            if(s->commit.next==0) {
1590 de167e41 bellard
                consistency_check1(s);
1591 de167e41 bellard
                consistency_check2(s);
1592 de167e41 bellard
                consistency_check3(s);
1593 de167e41 bellard
            }
1594 de167e41 bellard
#endif
1595 de167e41 bellard
1596 de167e41 bellard
            assert(sizeof(direntry_t)==0x20);
1597 de167e41 bellard
1598 de167e41 bellard
            for(j=0;j<0x200/0x20;j++) {
1599 de167e41 bellard
                //fprintf(stderr,"compare direntry %d: 0x%x,0x%x\n",j,(uint32_t)original+j,(uint32_t)new_+j);
1600 de167e41 bellard
                if(memcmp(original+j,new_+j,sizeof(direntry_t))) {
1601 de167e41 bellard
                    //fprintf(stderr,"different\n");
1602 de167e41 bellard
                    /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
1603 de167e41 bellard
                    if(direntry_is_free(original+j)) {
1604 de167e41 bellard
                        mapping_t* mapping;
1605 de167e41 bellard
                        char buffer[4096];
1606 de167e41 bellard
                        int fd,i;
1607 de167e41 bellard
1608 de167e41 bellard
                        if(new_[j].attributes==0xf)
1609 de167e41 bellard
                            continue; /* long entry */
1610 de167e41 bellard
1611 de167e41 bellard
                        print_mappings(s);
1612 de167e41 bellard
                        //fprintf(stderr,"sector: %d cluster: %d\n",(int)sector_num,(int)sector2cluster(s,sector_num));
1613 de167e41 bellard
1614 de167e41 bellard
                        /* construct absolute path */
1615 de167e41 bellard
                        strncpy(buffer,dir_mapping->filename,4096);
1616 de167e41 bellard
                        i=strlen(buffer);
1617 de167e41 bellard
                        if(i+2>=4096)
1618 de167e41 bellard
                                return -1;
1619 de167e41 bellard
                        buffer[i]='/';
1620 de167e41 bellard
                        if(long2unix_name(buffer+i+1,4096-i-1,new_+j))
1621 de167e41 bellard
                                return -2;
1622 de167e41 bellard
1623 de167e41 bellard
                        /* new file/directory */
1624 de167e41 bellard
                        if(new_[j].attributes&0x10) {
1625 de167e41 bellard
#ifdef _WIN32
1626 de167e41 bellard
#define SEVENFIVEFIVE
1627 de167e41 bellard
#else
1628 de167e41 bellard
#define SEVENFIVEFIVE ,0755
1629 de167e41 bellard
#endif
1630 de167e41 bellard
                            if(mkdir(buffer SEVENFIVEFIVE))
1631 de167e41 bellard
                                return -3;
1632 de167e41 bellard
                            /* TODO: map direntry.begin as directory, together with new array_t direntries */
1633 de167e41 bellard
                            assert(0);
1634 de167e41 bellard
                        } else {
1635 de167e41 bellard
                            fd=open(buffer,O_CREAT|O_EXCL,0644);
1636 de167e41 bellard
                            if(!fd)
1637 de167e41 bellard
                                return -3;
1638 de167e41 bellard
                            close(fd);
1639 de167e41 bellard
                        }
1640 de167e41 bellard
1641 de167e41 bellard
                        /* create mapping */
1642 de167e41 bellard
                        i=find_mapping_for_cluster_aux(s,begin_of_direntry(new_+j),0,s->mapping.next);
1643 de167e41 bellard
                        mapping=array_insert(&(s->mapping),i,1);
1644 de167e41 bellard
                        mapping->filename=strdup(buffer);
1645 de167e41 bellard
                        mapping->offset=0;
1646 de167e41 bellard
                        /* back pointer to direntry */
1647 de167e41 bellard
                        mapping->dir_index=first_dir_index+j;
1648 de167e41 bellard
                        /* set mode to modified */
1649 de167e41 bellard
                        mapping->mode=MODE_MODIFIED;
1650 de167e41 bellard
                        /* set begin to direntry.begin */
1651 de167e41 bellard
                        mapping->begin=begin_of_direntry(new_+j);
1652 de167e41 bellard
                        /* set end to begin+1 */
1653 de167e41 bellard
                        mapping->end=mapping->begin+1;
1654 de167e41 bellard
                        /* commit file contents */
1655 de167e41 bellard
                        if(commit_data_if_consistent(s,mapping,WRITE_DIRENTRY)) {
1656 de167e41 bellard
                            fprintf(stderr,"error committing file contents for new file %s!\n",buffer);
1657 de167e41 bellard
                            return -4;
1658 de167e41 bellard
                        }
1659 de167e41 bellard
                    } else if(direntry_is_free(new_+j)) {
1660 de167e41 bellard
                        assert(0);
1661 de167e41 bellard
                        /* TODO: delete file */
1662 de167e41 bellard
                        /* TODO: write direntry */
1663 de167e41 bellard
                        /* TODO: modify mapping: set mode=deleted */
1664 de167e41 bellard
                    } else {
1665 de167e41 bellard
                        /* modified file */
1666 de167e41 bellard
                        mapping_t* mapping=0;
1667 de167e41 bellard
                        /* if direntry.begin has changed,
1668 de167e41 bellard
                         * set mode to modified,
1669 de167e41 bellard
                         * adapt begin,
1670 de167e41 bellard
                         * adapt end */
1671 de167e41 bellard
                        /* TODO: handle rename */
1672 de167e41 bellard
                        assert(!memcmp(new_[j].name,original[j].name,11));
1673 de167e41 bellard
                        //fprintf(stderr,"1\n");
1674 de167e41 bellard
                        if(new_[j].begin!=original[j].begin || new_[j].size/s->cluster_size!=original[j].size/s->cluster_size) {
1675 de167e41 bellard
                        //fprintf(stderr,"2\n");
1676 de167e41 bellard
                            mapping = find_mapping_for_direntry(s,original+j);
1677 de167e41 bellard
                        //fprintf(stderr,"3\n");
1678 de167e41 bellard
                            if(!mapping) /* this should never happen! */
1679 de167e41 bellard
                                return -2;
1680 de167e41 bellard
                            mapping_modify_from_direntry(s,mapping,new_+j);
1681 de167e41 bellard
                            //fprintf(stderr,"4\n");
1682 de167e41 bellard
                            if(commit_data_if_consistent(s,mapping,WRITE_DIRENTRY)) {
1683 de167e41 bellard
                                fprintf(stderr,"big error\n");
1684 de167e41 bellard
                                return -4;
1685 de167e41 bellard
                            }
1686 de167e41 bellard
                        }
1687 de167e41 bellard
                        /* TODO: handle modified times and other attributes */
1688 de167e41 bellard
1689 de167e41 bellard
                        //fprintf(stderr,"5: mapping=0x%x, s=0x%x, s->mapping.pointer=0x%x\n",(uint32_t)mapping,(uint32_t)s,(uint32_t)s->mapping.pointer);
1690 de167e41 bellard
                        //fprintf(stderr,"6\n");
1691 de167e41 bellard
                    }
1692 de167e41 bellard
                }
1693 de167e41 bellard
            }
1694 de167e41 bellard
            /* write back direntries */
1695 de167e41 bellard
            memcpy(original,new_,0x200);
1696 de167e41 bellard
        } else {
1697 de167e41 bellard
            /* data */
1698 de167e41 bellard
            off_t sector=sector_num-s->first_sectors_number-2*s->sectors_per_fat;
1699 de167e41 bellard
            off_t cluster=sector/s->sectors_per_cluster;
1700 de167e41 bellard
            mapping_t* mapping=find_mapping_for_cluster(s,cluster);
1701 de167e41 bellard
            if(mapping && mapping->mode==MODE_DELETED)
1702 de167e41 bellard
                return -3; /* this is an error: no writes to these clusters before committed */
1703 de167e41 bellard
            {
1704 de167e41 bellard
                /* as of yet, undefined: put into commits */
1705 de167e41 bellard
                commit_t* commit=create_or_get_commit_for_sector(s,sector_num);
1706 de167e41 bellard
1707 de167e41 bellard
                if(!commit)
1708 de167e41 bellard
                    return -1; /* out of memory */
1709 de167e41 bellard
                memcpy(commit->buf+0x200*sector_offset_in_cluster(s,sector_num),buf,0x200);
1710 de167e41 bellard
1711 de167e41 bellard
                //fprintf(stderr,"mapping: 0x%x\n",(uint32_t)mapping);
1712 de167e41 bellard
                if(commit_data_if_consistent(s,mapping,WRITE_DATA))
1713 de167e41 bellard
                    return -4;
1714 de167e41 bellard
            }
1715 de167e41 bellard
        }
1716 de167e41 bellard
    }
1717 de167e41 bellard
    return 0;
1718 de167e41 bellard
}
1719 de167e41 bellard
1720 de167e41 bellard
static void vvfat_close(BlockDriverState *bs)
1721 de167e41 bellard
{
1722 de167e41 bellard
    BDRVVVFATState *s = bs->opaque;
1723 de167e41 bellard
1724 de167e41 bellard
    vvfat_close_current_file(s);
1725 de167e41 bellard
    array_free(&(s->fat));
1726 de167e41 bellard
    array_free(&(s->directory));
1727 de167e41 bellard
    array_free(&(s->mapping));
1728 de167e41 bellard
    if(s->cluster)
1729 de167e41 bellard
        free(s->cluster);
1730 de167e41 bellard
}
1731 de167e41 bellard
1732 de167e41 bellard
BlockDriver bdrv_vvfat = {
1733 de167e41 bellard
    "vvfat",
1734 de167e41 bellard
    sizeof(BDRVVVFATState),
1735 de167e41 bellard
    vvfat_probe,
1736 de167e41 bellard
    vvfat_open,
1737 de167e41 bellard
    vvfat_read,
1738 de167e41 bellard
    vvfat_write,
1739 de167e41 bellard
    vvfat_close,
1740 de167e41 bellard
};
1741 de167e41 bellard