blob: b8fa72981bfd05d3530ab8ef7c5674d0063c3714 [file] [log] [blame]
bellarda0464332005-12-18 18:29:50 +00001/* vim:set shiftwidth=4 ts=8: */
bellardde167e42005-04-28 21:15:08 +00002/*
3 * QEMU Block driver for virtual VFAT (shadows a local directory)
ths5fafdf22007-09-16 21:08:06 +00004 *
bellarda0464332005-12-18 18:29:50 +00005 * Copyright (c) 2004,2005 Johannes E. Schindelin
ths5fafdf22007-09-16 21:08:06 +00006 *
bellardde167e42005-04-28 21:15:08 +00007 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25#include <sys/stat.h>
26#include <dirent.h>
27#include <assert.h>
pbrookfaf07962007-11-11 02:51:17 +000028#include "qemu-common.h"
bellardde167e42005-04-28 21:15:08 +000029#include "block_int.h"
30
bellarda0464332005-12-18 18:29:50 +000031#ifndef S_IWGRP
32#define S_IWGRP 0
33#endif
34#ifndef S_IWOTH
35#define S_IWOTH 0
36#endif
bellardde167e42005-04-28 21:15:08 +000037
bellarda0464332005-12-18 18:29:50 +000038/* TODO: add ":bootsector=blabla.img:" */
39/* LATER TODO: add automatic boot sector generation from
40 BOOTEASY.ASM and Ranish Partition Manager
ths5fafdf22007-09-16 21:08:06 +000041 Note that DOS assumes the system files to be the first files in the
bellarda0464332005-12-18 18:29:50 +000042 file system (test if the boot sector still relies on that fact)! */
43/* MAYBE TODO: write block-visofs.c */
44/* TODO: call try_commit() only after a timeout */
bellardde167e42005-04-28 21:15:08 +000045
bellarda0464332005-12-18 18:29:50 +000046/* #define DEBUG */
47
48#ifdef DEBUG
49
50#define DLOG(a) a
51
52#undef stderr
53#define stderr STDERR
54FILE* stderr = NULL;
55
blueswir13f47aa82008-03-09 06:59:01 +000056static void checkpoint(void);
bellarda0464332005-12-18 18:29:50 +000057
58#ifdef __MINGW32__
59void nonono(const char* file, int line, const char* msg) {
60 fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg);
61 exit(-5);
62}
63#undef assert
bellard6bcb76c2006-09-09 12:03:20 +000064#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
bellarda0464332005-12-18 18:29:50 +000065#endif
66
67#else
68
69#define DLOG(a)
70
71#endif
bellardde167e42005-04-28 21:15:08 +000072
73/* dynamic array functions */
74typedef struct array_t {
75 char* pointer;
76 unsigned int size,next,item_size;
77} array_t;
78
79static inline void array_init(array_t* array,unsigned int item_size)
80{
81 array->pointer=0;
82 array->size=0;
83 array->next=0;
84 array->item_size=item_size;
85}
86
87static inline void array_free(array_t* array)
88{
89 if(array->pointer)
90 free(array->pointer);
91 array->size=array->next=0;
92}
93
bellarda0464332005-12-18 18:29:50 +000094/* does not automatically grow */
bellardde167e42005-04-28 21:15:08 +000095static inline void* array_get(array_t* array,unsigned int index) {
bellarda0464332005-12-18 18:29:50 +000096 assert(index < array->next);
97 return array->pointer + index * array->item_size;
98}
99
100static inline int array_ensure_allocated(array_t* array, int index)
101{
102 if((index + 1) * array->item_size > array->size) {
103 int new_size = (index + 32) * array->item_size;
ths2137b4c2008-08-06 08:37:17 +0000104 array->pointer = qemu_realloc(array->pointer, new_size);
bellarda0464332005-12-18 18:29:50 +0000105 if (!array->pointer)
106 return -1;
107 array->size = new_size;
108 array->next = index + 1;
bellardde167e42005-04-28 21:15:08 +0000109 }
bellarda0464332005-12-18 18:29:50 +0000110
111 return 0;
bellardde167e42005-04-28 21:15:08 +0000112}
113
114static inline void* array_get_next(array_t* array) {
bellarda0464332005-12-18 18:29:50 +0000115 unsigned int next = array->next;
116 void* result;
117
118 if (array_ensure_allocated(array, next) < 0)
119 return NULL;
120
121 array->next = next + 1;
122 result = array_get(array, next);
123
bellardde167e42005-04-28 21:15:08 +0000124 return result;
125}
126
127static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
128 if((array->next+count)*array->item_size>array->size) {
129 int increment=count*array->item_size;
ths2137b4c2008-08-06 08:37:17 +0000130 array->pointer=qemu_realloc(array->pointer,array->size+increment);
bellardde167e42005-04-28 21:15:08 +0000131 if(!array->pointer)
132 return 0;
133 array->size+=increment;
134 }
135 memmove(array->pointer+(index+count)*array->item_size,
136 array->pointer+index*array->item_size,
137 (array->next-index)*array->item_size);
138 array->next+=count;
139 return array->pointer+index*array->item_size;
140}
141
142/* this performs a "roll", so that the element which was at index_from becomes
143 * index_to, but the order of all other elements is preserved. */
144static inline int array_roll(array_t* array,int index_to,int index_from,int count)
145{
146 char* buf;
147 char* from;
148 char* to;
149 int is;
150
151 if(!array ||
152 index_to<0 || index_to>=array->next ||
153 index_from<0 || index_from>=array->next)
154 return -1;
ths3b46e622007-09-17 08:09:54 +0000155
bellardde167e42005-04-28 21:15:08 +0000156 if(index_to==index_from)
157 return 0;
158
159 is=array->item_size;
160 from=array->pointer+index_from*is;
161 to=array->pointer+index_to*is;
162 buf=malloc(is*count);
163 memcpy(buf,from,is*count);
164
165 if(index_to<index_from)
166 memmove(to+is*count,to,from-to);
167 else
168 memmove(from,from+is*count,to-from);
ths3b46e622007-09-17 08:09:54 +0000169
bellardde167e42005-04-28 21:15:08 +0000170 memcpy(to,buf,is*count);
171
172 free(buf);
173
174 return 0;
175}
176
pbrook9596ebb2007-11-18 01:44:38 +0000177static inline int array_remove_slice(array_t* array,int index, int count)
bellarda0464332005-12-18 18:29:50 +0000178{
179 assert(index >=0);
180 assert(count > 0);
181 assert(index + count <= array->next);
182 if(array_roll(array,array->next-1,index,count))
183 return -1;
184 array->next -= count;
185 return 0;
186}
187
pbrook9596ebb2007-11-18 01:44:38 +0000188static int array_remove(array_t* array,int index)
bellardde167e42005-04-28 21:15:08 +0000189{
bellarda0464332005-12-18 18:29:50 +0000190 return array_remove_slice(array, index, 1);
191}
192
193/* return the index for a given member */
pbrook9596ebb2007-11-18 01:44:38 +0000194static int array_index(array_t* array, void* pointer)
bellarda0464332005-12-18 18:29:50 +0000195{
196 size_t offset = (char*)pointer - array->pointer;
bellarda0464332005-12-18 18:29:50 +0000197 assert((offset % array->item_size) == 0);
198 assert(offset/array->item_size < array->next);
199 return offset/array->item_size;
bellardde167e42005-04-28 21:15:08 +0000200}
201
202/* These structures are used to fake a disk and the VFAT filesystem.
203 * For this reason we need to use __attribute__((packed)). */
204
205typedef struct bootsector_t {
206 uint8_t jump[3];
207 uint8_t name[8];
208 uint16_t sector_size;
209 uint8_t sectors_per_cluster;
210 uint16_t reserved_sectors;
211 uint8_t number_of_fats;
212 uint16_t root_entries;
bellarda0464332005-12-18 18:29:50 +0000213 uint16_t total_sectors16;
bellardde167e42005-04-28 21:15:08 +0000214 uint8_t media_type;
215 uint16_t sectors_per_fat;
216 uint16_t sectors_per_track;
217 uint16_t number_of_heads;
218 uint32_t hidden_sectors;
219 uint32_t total_sectors;
220 union {
221 struct {
222 uint8_t drive_number;
223 uint8_t current_head;
224 uint8_t signature;
225 uint32_t id;
226 uint8_t volume_label[11];
227 } __attribute__((packed)) fat16;
228 struct {
229 uint32_t sectors_per_fat;
230 uint16_t flags;
231 uint8_t major,minor;
232 uint32_t first_cluster_of_root_directory;
233 uint16_t info_sector;
234 uint16_t backup_boot_sector;
235 uint16_t ignored;
236 } __attribute__((packed)) fat32;
237 } u;
238 uint8_t fat_type[8];
239 uint8_t ignored[0x1c0];
240 uint8_t magic[2];
241} __attribute__((packed)) bootsector_t;
242
thsb5700942007-09-25 14:47:03 +0000243typedef struct {
244 uint8_t head;
245 uint8_t sector;
246 uint8_t cylinder;
247} mbr_chs_t;
248
bellardde167e42005-04-28 21:15:08 +0000249typedef struct partition_t {
250 uint8_t attributes; /* 0x80 = bootable */
thsb5700942007-09-25 14:47:03 +0000251 mbr_chs_t start_CHS;
252 uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
253 mbr_chs_t end_CHS;
bellardde167e42005-04-28 21:15:08 +0000254 uint32_t start_sector_long;
thsb5700942007-09-25 14:47:03 +0000255 uint32_t length_sector_long;
bellardde167e42005-04-28 21:15:08 +0000256} __attribute__((packed)) partition_t;
257
258typedef struct mbr_t {
thsb5700942007-09-25 14:47:03 +0000259 uint8_t ignored[0x1b8];
260 uint32_t nt_id;
261 uint8_t ignored2[2];
bellardde167e42005-04-28 21:15:08 +0000262 partition_t partition[4];
263 uint8_t magic[2];
264} __attribute__((packed)) mbr_t;
265
266typedef struct direntry_t {
267 uint8_t name[8];
268 uint8_t extension[3];
269 uint8_t attributes;
270 uint8_t reserved[2];
271 uint16_t ctime;
272 uint16_t cdate;
273 uint16_t adate;
274 uint16_t begin_hi;
275 uint16_t mtime;
276 uint16_t mdate;
277 uint16_t begin;
278 uint32_t size;
279} __attribute__((packed)) direntry_t;
280
281/* this structure are used to transparently access the files */
282
283typedef struct mapping_t {
bellarda0464332005-12-18 18:29:50 +0000284 /* begin is the first cluster, end is the last+1 */
285 uint32_t begin,end;
bellardde167e42005-04-28 21:15:08 +0000286 /* as s->directory is growable, no pointer may be used here */
287 unsigned int dir_index;
bellarda0464332005-12-18 18:29:50 +0000288 /* the clusters of a file may be in any order; this points to the first */
289 int first_mapping_index;
290 union {
291 /* offset is
292 * - the offset in the file (in clusters) for a file, or
293 * - the next cluster of the directory for a directory, and
294 * - the address of the buffer for a faked entry
295 */
296 struct {
297 uint32_t offset;
298 } file;
299 struct {
300 int parent_mapping_index;
301 int first_dir_index;
302 } dir;
303 } info;
304 /* path contains the full path, i.e. it always starts with s->path */
305 char* path;
306
307 enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2,
308 MODE_DIRECTORY = 4, MODE_FAKED = 8,
309 MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
310 int read_only;
bellardde167e42005-04-28 21:15:08 +0000311} mapping_t;
312
bellarda0464332005-12-18 18:29:50 +0000313#ifdef DEBUG
314static void print_direntry(const struct direntry_t*);
315static void print_mapping(const struct mapping_t* mapping);
316#endif
bellardde167e42005-04-28 21:15:08 +0000317
318/* here begins the real VVFAT driver */
319
320typedef struct BDRVVVFATState {
bellarda0464332005-12-18 18:29:50 +0000321 BlockDriverState* bs; /* pointer to parent */
bellardde167e42005-04-28 21:15:08 +0000322 unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
323 unsigned char first_sectors[0x40*0x200];
ths3b46e622007-09-17 08:09:54 +0000324
bellardde167e42005-04-28 21:15:08 +0000325 int fat_type; /* 16 or 32 */
326 array_t fat,directory,mapping;
ths3b46e622007-09-17 08:09:54 +0000327
bellardde167e42005-04-28 21:15:08 +0000328 unsigned int cluster_size;
329 unsigned int sectors_per_cluster;
330 unsigned int sectors_per_fat;
331 unsigned int sectors_of_root_directory;
bellarda0464332005-12-18 18:29:50 +0000332 uint32_t last_cluster_of_root_directory;
bellardde167e42005-04-28 21:15:08 +0000333 unsigned int faked_sectors; /* how many sectors are faked before file data */
334 uint32_t sector_count; /* total number of sectors of the partition */
335 uint32_t cluster_count; /* total number of clusters of this partition */
bellardde167e42005-04-28 21:15:08 +0000336 uint32_t max_fat_value;
ths3b46e622007-09-17 08:09:54 +0000337
bellardde167e42005-04-28 21:15:08 +0000338 int current_fd;
bellardde167e42005-04-28 21:15:08 +0000339 mapping_t* current_mapping;
bellarda0464332005-12-18 18:29:50 +0000340 unsigned char* cluster; /* points to current cluster */
341 unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
bellardde167e42005-04-28 21:15:08 +0000342 unsigned int current_cluster;
343
344 /* write support */
bellarda0464332005-12-18 18:29:50 +0000345 BlockDriverState* write_target;
346 char* qcow_filename;
347 BlockDriverState* qcow;
348 void* fat2;
349 char* used_clusters;
350 array_t commits;
351 const char* path;
352 int downcase_short_names;
bellardde167e42005-04-28 21:15:08 +0000353} BDRVVVFATState;
354
thsb5700942007-09-25 14:47:03 +0000355/* take the sector position spos and convert it to Cylinder/Head/Sector position
356 * if the position is outside the specified geometry, fill maximum value for CHS
357 * and return 1 to signal overflow.
358 */
359static int sector2CHS(BlockDriverState* bs, mbr_chs_t * chs, int spos){
360 int head,sector;
361 sector = spos % (bs->secs); spos/= bs->secs;
362 head = spos % (bs->heads); spos/= bs->heads;
363 if(spos >= bs->cyls){
364 /* Overflow,
365 it happens if 32bit sector positions are used, while CHS is only 24bit.
366 Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
367 chs->head = 0xFF;
368 chs->sector = 0xFF;
369 chs->cylinder = 0xFF;
370 return 1;
371 }
372 chs->head = (uint8_t)head;
373 chs->sector = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
374 chs->cylinder = (uint8_t)spos;
375 return 0;
376}
bellardde167e42005-04-28 21:15:08 +0000377
bellardde167e42005-04-28 21:15:08 +0000378static void init_mbr(BDRVVVFATState* s)
379{
380 /* TODO: if the files mbr.img and bootsect.img exist, use them */
381 mbr_t* real_mbr=(mbr_t*)s->first_sectors;
382 partition_t* partition=&(real_mbr->partition[0]);
thsb5700942007-09-25 14:47:03 +0000383 int lba;
bellardde167e42005-04-28 21:15:08 +0000384
385 memset(s->first_sectors,0,512);
ths3b46e622007-09-17 08:09:54 +0000386
thsb5700942007-09-25 14:47:03 +0000387 /* Win NT Disk Signature */
388 real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
389
bellardde167e42005-04-28 21:15:08 +0000390 partition->attributes=0x80; /* bootable */
thsb5700942007-09-25 14:47:03 +0000391
392 /* LBA is used when partition is outside the CHS geometry */
393 lba = sector2CHS(s->bs, &partition->start_CHS, s->first_sectors_number-1);
394 lba|= sector2CHS(s->bs, &partition->end_CHS, s->sector_count);
395
396 /*LBA partitions are identified only by start/length_sector_long not by CHS*/
397 partition->start_sector_long =cpu_to_le32(s->first_sectors_number-1);
398 partition->length_sector_long=cpu_to_le32(s->sector_count - s->first_sectors_number+1);
399
bellarda0464332005-12-18 18:29:50 +0000400 /* FAT12/FAT16/FAT32 */
thsb5700942007-09-25 14:47:03 +0000401 /* DOS uses different types when partition is LBA,
402 probably to prevent older versions from using CHS on them */
403 partition->fs_type= s->fat_type==12 ? 0x1:
404 s->fat_type==16 ? (lba?0xe:0x06):
405 /*fat_tyoe==32*/ (lba?0xc:0x0b);
bellardde167e42005-04-28 21:15:08 +0000406
407 real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
408}
409
bellarda0464332005-12-18 18:29:50 +0000410/* direntry functions */
411
bellardde167e42005-04-28 21:15:08 +0000412/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
ths60fe76f2007-12-16 03:02:09 +0000413static inline int short2long_name(char* dest,const char* src)
bellardde167e42005-04-28 21:15:08 +0000414{
415 int i;
balrog1e080d52007-12-24 13:26:04 +0000416 int len;
bellardde167e42005-04-28 21:15:08 +0000417 for(i=0;i<129 && src[i];i++) {
418 dest[2*i]=src[i];
419 dest[2*i+1]=0;
420 }
balrog1e080d52007-12-24 13:26:04 +0000421 len=2*i;
bellardde167e42005-04-28 21:15:08 +0000422 dest[2*i]=dest[2*i+1]=0;
423 for(i=2*i+2;(i%26);i++)
424 dest[i]=0xff;
balrog1e080d52007-12-24 13:26:04 +0000425 return len;
bellardde167e42005-04-28 21:15:08 +0000426}
427
428static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
429{
430 char buffer[258];
431 int length=short2long_name(buffer,filename),
432 number_of_entries=(length+25)/26,i;
433 direntry_t* entry;
434
435 for(i=0;i<number_of_entries;i++) {
436 entry=array_get_next(&(s->directory));
437 entry->attributes=0xf;
438 entry->reserved[0]=0;
439 entry->begin=0;
440 entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
441 }
balrog1e080d52007-12-24 13:26:04 +0000442 for(i=0;i<26*number_of_entries;i++) {
bellardde167e42005-04-28 21:15:08 +0000443 int offset=(i%26);
444 if(offset<10) offset=1+offset;
445 else if(offset<22) offset=14+offset-10;
446 else offset=28+offset-22;
447 entry=array_get(&(s->directory),s->directory.next-1-(i/26));
448 entry->name[offset]=buffer[i];
449 }
450 return array_get(&(s->directory),s->directory.next-number_of_entries);
451}
452
bellarda0464332005-12-18 18:29:50 +0000453static char is_free(const direntry_t* direntry)
454{
thsad1a8972008-07-01 16:44:58 +0000455 return direntry->name[0]==0xe5 || direntry->name[0]==0x00;
bellarda0464332005-12-18 18:29:50 +0000456}
457
458static char is_volume_label(const direntry_t* direntry)
459{
460 return direntry->attributes == 0x28;
461}
462
463static char is_long_name(const direntry_t* direntry)
464{
465 return direntry->attributes == 0xf;
466}
467
468static char is_short_name(const direntry_t* direntry)
469{
470 return !is_volume_label(direntry) && !is_long_name(direntry)
471 && !is_free(direntry);
472}
473
474static char is_directory(const direntry_t* direntry)
475{
476 return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
477}
478
479static inline char is_dot(const direntry_t* direntry)
480{
481 return is_short_name(direntry) && direntry->name[0] == '.';
482}
483
484static char is_file(const direntry_t* direntry)
485{
486 return is_short_name(direntry) && !is_directory(direntry);
487}
488
489static inline uint32_t begin_of_direntry(const direntry_t* direntry)
490{
491 return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
492}
493
494static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
495{
496 return le32_to_cpu(direntry->size);
497}
498
499static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
500{
501 direntry->begin = cpu_to_le16(begin & 0xffff);
502 direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
503}
504
bellardde167e42005-04-28 21:15:08 +0000505/* fat functions */
506
bellarda0464332005-12-18 18:29:50 +0000507static inline uint8_t fat_chksum(const direntry_t* entry)
bellardde167e42005-04-28 21:15:08 +0000508{
509 uint8_t chksum=0;
510 int i;
511
512 for(i=0;i<11;i++)
513 chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0))
514 +(unsigned char)entry->name[i];
ths3b46e622007-09-17 08:09:54 +0000515
bellardde167e42005-04-28 21:15:08 +0000516 return chksum;
517}
518
519/* if return_time==0, this returns the fat_date, else the fat_time */
520static uint16_t fat_datetime(time_t time,int return_time) {
521 struct tm* t;
522#ifdef _WIN32
523 t=localtime(&time); /* this is not thread safe */
524#else
525 struct tm t1;
526 t=&t1;
527 localtime_r(&time,t);
528#endif
529 if(return_time)
530 return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
531 return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
532}
533
534static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
535{
bellarda0464332005-12-18 18:29:50 +0000536 if(s->fat_type==32) {
537 uint32_t* entry=array_get(&(s->fat),cluster);
538 *entry=cpu_to_le32(value);
bellardde167e42005-04-28 21:15:08 +0000539 } else if(s->fat_type==16) {
540 uint16_t* entry=array_get(&(s->fat),cluster);
541 *entry=cpu_to_le16(value&0xffff);
542 } else {
bellarda0464332005-12-18 18:29:50 +0000543 int offset = (cluster*3/2);
544 unsigned char* p = array_get(&(s->fat), offset);
545 switch (cluster&1) {
546 case 0:
547 p[0] = value&0xff;
548 p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
549 break;
550 case 1:
551 p[0] = (p[0]&0xf) | ((value&0xf)<<4);
552 p[1] = (value>>4);
553 break;
554 }
bellardde167e42005-04-28 21:15:08 +0000555 }
556}
557
558static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
559{
bellarda0464332005-12-18 18:29:50 +0000560 if(s->fat_type==32) {
561 uint32_t* entry=array_get(&(s->fat),cluster);
562 return le32_to_cpu(*entry);
bellardde167e42005-04-28 21:15:08 +0000563 } else if(s->fat_type==16) {
564 uint16_t* entry=array_get(&(s->fat),cluster);
565 return le16_to_cpu(*entry);
566 } else {
thsffe8ab82007-12-16 03:16:05 +0000567 const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
bellarda0464332005-12-18 18:29:50 +0000568 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
bellardde167e42005-04-28 21:15:08 +0000569 }
570}
571
572static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
573{
574 if(fat_entry>s->max_fat_value-8)
575 return -1;
576 return 0;
577}
578
579static inline void init_fat(BDRVVVFATState* s)
580{
bellarda0464332005-12-18 18:29:50 +0000581 if (s->fat_type == 12) {
582 array_init(&(s->fat),1);
583 array_ensure_allocated(&(s->fat),
584 s->sectors_per_fat * 0x200 * 3 / 2 - 1);
585 } else {
586 array_init(&(s->fat),(s->fat_type==32?4:2));
587 array_ensure_allocated(&(s->fat),
588 s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
589 }
bellardde167e42005-04-28 21:15:08 +0000590 memset(s->fat.pointer,0,s->fat.size);
ths3b46e622007-09-17 08:09:54 +0000591
bellardde167e42005-04-28 21:15:08 +0000592 switch(s->fat_type) {
593 case 12: s->max_fat_value=0xfff; break;
594 case 16: s->max_fat_value=0xffff; break;
bellarda0464332005-12-18 18:29:50 +0000595 case 32: s->max_fat_value=0x0fffffff; break;
bellardde167e42005-04-28 21:15:08 +0000596 default: s->max_fat_value=0; /* error... */
597 }
598
599}
600
bellarda0464332005-12-18 18:29:50 +0000601/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
602/* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
603static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
604 unsigned int directory_start, const char* filename, int is_dot)
bellardde167e42005-04-28 21:15:08 +0000605{
bellarda0464332005-12-18 18:29:50 +0000606 int i,j,long_index=s->directory.next;
bellardde167e42005-04-28 21:15:08 +0000607 direntry_t* entry=0;
608 direntry_t* entry_long=0;
609
610 if(is_dot) {
611 entry=array_get_next(&(s->directory));
612 memset(entry->name,0x20,11);
613 memcpy(entry->name,filename,strlen(filename));
614 return entry;
615 }
ths3b46e622007-09-17 08:09:54 +0000616
bellardde167e42005-04-28 21:15:08 +0000617 entry_long=create_long_filename(s,filename);
ths3b46e622007-09-17 08:09:54 +0000618
ths5fafdf22007-09-16 21:08:06 +0000619 i = strlen(filename);
bellarda0464332005-12-18 18:29:50 +0000620 for(j = i - 1; j>0 && filename[j]!='.';j--);
621 if (j > 0)
622 i = (j > 8 ? 8 : j);
623 else if (i > 8)
624 i = 8;
625
bellardde167e42005-04-28 21:15:08 +0000626 entry=array_get_next(&(s->directory));
627 memset(entry->name,0x20,11);
blueswir151a0f562008-10-26 10:22:11 +0000628 memcpy(entry->name, filename, i);
ths3b46e622007-09-17 08:09:54 +0000629
bellarda0464332005-12-18 18:29:50 +0000630 if(j > 0)
631 for (i = 0; i < 3 && filename[j+1+i]; i++)
632 entry->extension[i] = filename[j+1+i];
bellardde167e42005-04-28 21:15:08 +0000633
634 /* upcase & remove unwanted characters */
635 for(i=10;i>=0;i--) {
bellarda0464332005-12-18 18:29:50 +0000636 if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
bellardde167e42005-04-28 21:15:08 +0000637 if(entry->name[i]<=' ' || entry->name[i]>0x7f
bellarda0464332005-12-18 18:29:50 +0000638 || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
bellardde167e42005-04-28 21:15:08 +0000639 entry->name[i]='_';
640 else if(entry->name[i]>='a' && entry->name[i]<='z')
641 entry->name[i]+='A'-'a';
642 }
643
644 /* mangle duplicates */
645 while(1) {
646 direntry_t* entry1=array_get(&(s->directory),directory_start);
647 int j;
648
649 for(;entry1<entry;entry1++)
bellarda0464332005-12-18 18:29:50 +0000650 if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
bellardde167e42005-04-28 21:15:08 +0000651 break; /* found dupe */
652 if(entry1==entry) /* no dupe found */
653 break;
654
ths5fafdf22007-09-16 21:08:06 +0000655 /* use all 8 characters of name */
bellardde167e42005-04-28 21:15:08 +0000656 if(entry->name[7]==' ') {
657 int j;
658 for(j=6;j>0 && entry->name[j]==' ';j--)
659 entry->name[j]='~';
660 }
661
662 /* increment number */
663 for(j=7;j>0 && entry->name[j]=='9';j--)
664 entry->name[j]='0';
665 if(j>0) {
666 if(entry->name[j]<'0' || entry->name[j]>'9')
667 entry->name[j]='0';
668 else
669 entry->name[j]++;
670 }
671 }
672
673 /* calculate checksum; propagate to long name */
674 if(entry_long) {
675 uint8_t chksum=fat_chksum(entry);
676
677 /* calculate anew, because realloc could have taken place */
678 entry_long=array_get(&(s->directory),long_index);
bellarda0464332005-12-18 18:29:50 +0000679 while(entry_long<entry && is_long_name(entry_long)) {
bellardde167e42005-04-28 21:15:08 +0000680 entry_long->reserved[1]=chksum;
681 entry_long++;
682 }
683 }
684
685 return entry;
686}
687
bellarda0464332005-12-18 18:29:50 +0000688/*
689 * Read a directory. (the index of the corresponding mapping must be passed).
690 */
691static int read_directory(BDRVVVFATState* s, int mapping_index)
bellardde167e42005-04-28 21:15:08 +0000692{
bellarda0464332005-12-18 18:29:50 +0000693 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
694 direntry_t* direntry;
695 const char* dirname = mapping->path;
696 int first_cluster = mapping->begin;
697 int parent_index = mapping->info.dir.parent_mapping_index;
698 mapping_t* parent_mapping = (mapping_t*)
699 (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : 0);
700 int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
bellardde167e42005-04-28 21:15:08 +0000701
702 DIR* dir=opendir(dirname);
703 struct dirent* entry;
bellardde167e42005-04-28 21:15:08 +0000704 int i;
705
bellarda0464332005-12-18 18:29:50 +0000706 assert(mapping->mode & MODE_DIRECTORY);
707
708 if(!dir) {
709 mapping->end = mapping->begin;
bellardde167e42005-04-28 21:15:08 +0000710 return -1;
bellarda0464332005-12-18 18:29:50 +0000711 }
ths3b46e622007-09-17 08:09:54 +0000712
bellarda0464332005-12-18 18:29:50 +0000713 i = mapping->info.dir.first_dir_index =
714 first_cluster == 0 ? 0 : s->directory.next;
715
ths5fafdf22007-09-16 21:08:06 +0000716 /* actually read the directory, and allocate the mappings */
bellardde167e42005-04-28 21:15:08 +0000717 while((entry=readdir(dir))) {
718 unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
719 char* buffer;
720 direntry_t* direntry;
bellarda0464332005-12-18 18:29:50 +0000721 struct stat st;
bellardde167e42005-04-28 21:15:08 +0000722 int is_dot=!strcmp(entry->d_name,".");
723 int is_dotdot=!strcmp(entry->d_name,"..");
724
bellarda0464332005-12-18 18:29:50 +0000725 if(first_cluster == 0 && (is_dotdot || is_dot))
bellardde167e42005-04-28 21:15:08 +0000726 continue;
ths5fafdf22007-09-16 21:08:06 +0000727
bellardde167e42005-04-28 21:15:08 +0000728 buffer=(char*)malloc(length);
bellarda0464332005-12-18 18:29:50 +0000729 assert(buffer);
bellardde167e42005-04-28 21:15:08 +0000730 snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
731
732 if(stat(buffer,&st)<0) {
733 free(buffer);
734 continue;
735 }
736
737 /* create directory entry for this file */
bellarda0464332005-12-18 18:29:50 +0000738 direntry=create_short_and_long_name(s, i, entry->d_name,
739 is_dot || is_dotdot);
bellardde167e42005-04-28 21:15:08 +0000740 direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
741 direntry->reserved[0]=direntry->reserved[1]=0;
742 direntry->ctime=fat_datetime(st.st_ctime,1);
743 direntry->cdate=fat_datetime(st.st_ctime,0);
744 direntry->adate=fat_datetime(st.st_atime,0);
745 direntry->begin_hi=0;
746 direntry->mtime=fat_datetime(st.st_mtime,1);
747 direntry->mdate=fat_datetime(st.st_mtime,0);
748 if(is_dotdot)
bellarda0464332005-12-18 18:29:50 +0000749 set_begin_of_direntry(direntry, first_cluster_of_parent);
bellardde167e42005-04-28 21:15:08 +0000750 else if(is_dot)
bellarda0464332005-12-18 18:29:50 +0000751 set_begin_of_direntry(direntry, first_cluster);
bellardde167e42005-04-28 21:15:08 +0000752 else
bellarda0464332005-12-18 18:29:50 +0000753 direntry->begin=0; /* do that later */
754 if (st.st_size > 0x7fffffff) {
755 fprintf(stderr, "File %s is larger than 2GB\n", buffer);
756 free(buffer);
757 return -2;
758 }
759 direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
bellardde167e42005-04-28 21:15:08 +0000760
761 /* create mapping for this file */
bellarda0464332005-12-18 18:29:50 +0000762 if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
763 s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
bellardde167e42005-04-28 21:15:08 +0000764 s->current_mapping->begin=0;
765 s->current_mapping->end=st.st_size;
bellarda0464332005-12-18 18:29:50 +0000766 /*
767 * we get the direntry of the most recent direntry, which
768 * contains the short name and all the relevant information.
769 */
bellardde167e42005-04-28 21:15:08 +0000770 s->current_mapping->dir_index=s->directory.next-1;
bellarda0464332005-12-18 18:29:50 +0000771 s->current_mapping->first_mapping_index = -1;
772 if (S_ISDIR(st.st_mode)) {
773 s->current_mapping->mode = MODE_DIRECTORY;
774 s->current_mapping->info.dir.parent_mapping_index =
775 mapping_index;
776 } else {
777 s->current_mapping->mode = MODE_UNDEFINED;
778 s->current_mapping->info.file.offset = 0;
779 }
780 s->current_mapping->path=buffer;
781 s->current_mapping->read_only =
782 (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
bellardde167e42005-04-28 21:15:08 +0000783 }
784 }
785 closedir(dir);
786
787 /* fill with zeroes up to the end of the cluster */
788 while(s->directory.next%(0x10*s->sectors_per_cluster)) {
789 direntry_t* direntry=array_get_next(&(s->directory));
790 memset(direntry,0,sizeof(direntry_t));
791 }
792
bellarda0464332005-12-18 18:29:50 +0000793/* TODO: if there are more entries, bootsector has to be adjusted! */
794#define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
795 if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
796 /* root directory */
797 int cur = s->directory.next;
798 array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
799 memset(array_get(&(s->directory), cur), 0,
800 (ROOT_ENTRIES - cur) * sizeof(direntry_t));
bellardde167e42005-04-28 21:15:08 +0000801 }
ths5fafdf22007-09-16 21:08:06 +0000802
bellarda0464332005-12-18 18:29:50 +0000803 /* reget the mapping, since s->mapping was possibly realloc()ed */
804 mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
805 first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
806 * 0x20 / s->cluster_size;
807 mapping->end = first_cluster;
bellardde167e42005-04-28 21:15:08 +0000808
bellarda0464332005-12-18 18:29:50 +0000809 direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
810 set_begin_of_direntry(direntry, mapping->begin);
ths3b46e622007-09-17 08:09:54 +0000811
bellardde167e42005-04-28 21:15:08 +0000812 return 0;
813}
814
bellarda0464332005-12-18 18:29:50 +0000815static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
bellardde167e42005-04-28 21:15:08 +0000816{
bellarda0464332005-12-18 18:29:50 +0000817 return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
818}
819
820static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
821{
822 return s->faked_sectors + s->sectors_per_cluster * cluster_num;
823}
824
825static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
826{
827 return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
828}
829
830#ifdef DBG
831static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
832{
833 if(mapping->mode==MODE_UNDEFINED)
834 return 0;
835 return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
836}
837#endif
838
839static int init_directories(BDRVVVFATState* s,
840 const char* dirname)
841{
842 bootsector_t* bootsector;
843 mapping_t* mapping;
bellardde167e42005-04-28 21:15:08 +0000844 unsigned int i;
845 unsigned int cluster;
846
847 memset(&(s->first_sectors[0]),0,0x40*0x200);
848
bellardde167e42005-04-28 21:15:08 +0000849 s->cluster_size=s->sectors_per_cluster*0x200;
bellarda0464332005-12-18 18:29:50 +0000850 s->cluster_buffer=malloc(s->cluster_size);
851 assert(s->cluster_buffer);
852
853 /*
854 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
855 * where sc is sector_count,
856 * spf is sectors_per_fat,
857 * spc is sectors_per_clusters, and
858 * fat_type = 12, 16 or 32.
859 */
860 i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
861 s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
ths3b46e622007-09-17 08:09:54 +0000862
bellardde167e42005-04-28 21:15:08 +0000863 array_init(&(s->mapping),sizeof(mapping_t));
864 array_init(&(s->directory),sizeof(direntry_t));
bellardde167e42005-04-28 21:15:08 +0000865
866 /* add volume label */
867 {
868 direntry_t* entry=array_get_next(&(s->directory));
869 entry->attributes=0x28; /* archive | volume label */
thsffe8ab82007-12-16 03:16:05 +0000870 snprintf((char*)entry->name,11,"QEMU VVFAT");
bellardde167e42005-04-28 21:15:08 +0000871 }
872
bellardde167e42005-04-28 21:15:08 +0000873 /* Now build FAT, and write back information into directory */
874 init_fat(s);
875
bellarda0464332005-12-18 18:29:50 +0000876 s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
877 s->cluster_count=sector2cluster(s, s->sector_count);
bellardde167e42005-04-28 21:15:08 +0000878
bellarda0464332005-12-18 18:29:50 +0000879 mapping = array_get_next(&(s->mapping));
880 mapping->begin = 0;
881 mapping->dir_index = 0;
882 mapping->info.dir.parent_mapping_index = -1;
883 mapping->first_mapping_index = -1;
884 mapping->path = strdup(dirname);
885 i = strlen(mapping->path);
886 if (i > 0 && mapping->path[i - 1] == '/')
887 mapping->path[i - 1] = '\0';
888 mapping->mode = MODE_DIRECTORY;
889 mapping->read_only = 0;
890 s->path = mapping->path;
bellardde167e42005-04-28 21:15:08 +0000891
bellarda0464332005-12-18 18:29:50 +0000892 for (i = 0, cluster = 0; i < s->mapping.next; i++) {
ths5fafdf22007-09-16 21:08:06 +0000893 /* MS-DOS expects the FAT to be 0 for the root directory
bellarda0464332005-12-18 18:29:50 +0000894 * (except for the media byte). */
895 /* LATER TODO: still true for FAT32? */
896 int fix_fat = (i != 0);
897 mapping = array_get(&(s->mapping), i);
bellardde167e42005-04-28 21:15:08 +0000898
bellarda0464332005-12-18 18:29:50 +0000899 if (mapping->mode & MODE_DIRECTORY) {
900 mapping->begin = cluster;
901 if(read_directory(s, i)) {
902 fprintf(stderr, "Could not read directory %s\n",
903 mapping->path);
bellardde167e42005-04-28 21:15:08 +0000904 return -1;
905 }
bellarda0464332005-12-18 18:29:50 +0000906 mapping = array_get(&(s->mapping), i);
907 } else {
908 assert(mapping->mode == MODE_UNDEFINED);
bellardde167e42005-04-28 21:15:08 +0000909 mapping->mode=MODE_NORMAL;
bellarda0464332005-12-18 18:29:50 +0000910 mapping->begin = cluster;
911 if (mapping->end > 0) {
912 direntry_t* direntry = array_get(&(s->directory),
913 mapping->dir_index);
bellardde167e42005-04-28 21:15:08 +0000914
bellarda0464332005-12-18 18:29:50 +0000915 mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
916 set_begin_of_direntry(direntry, mapping->begin);
917 } else {
918 mapping->end = cluster + 1;
919 fix_fat = 0;
920 }
921 }
922
923 assert(mapping->begin < mapping->end);
924
bellarda0464332005-12-18 18:29:50 +0000925 /* next free cluster */
926 cluster = mapping->end;
927
928 if(cluster > s->cluster_count) {
balrog8ce0f862008-11-10 01:34:27 +0000929 fprintf(stderr,"Directory does not fit in FAT%d (capacity %s)\n",
930 s->fat_type,
931 s->fat_type == 12 ? s->sector_count == 2880 ? "1.44 MB"
932 : "2.88 MB"
933 : "504MB");
934 return -EINVAL;
935 }
936
937 /* fix fat for entry */
938 if (fix_fat) {
939 int j;
940 for(j = mapping->begin; j < mapping->end - 1; j++)
941 fat_set(s, j, j+1);
942 fat_set(s, mapping->end - 1, s->max_fat_value);
bellardde167e42005-04-28 21:15:08 +0000943 }
944 }
945
bellarda0464332005-12-18 18:29:50 +0000946 mapping = array_get(&(s->mapping), 0);
947 s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
948 s->last_cluster_of_root_directory = mapping->end;
bellardde167e42005-04-28 21:15:08 +0000949
bellarda0464332005-12-18 18:29:50 +0000950 /* the FAT signature */
951 fat_set(s,0,s->max_fat_value);
952 fat_set(s,1,s->max_fat_value);
953
954 s->current_mapping = NULL;
955
956 bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
bellardde167e42005-04-28 21:15:08 +0000957 bootsector->jump[0]=0xeb;
958 bootsector->jump[1]=0x3e;
959 bootsector->jump[2]=0x90;
960 memcpy(bootsector->name,"QEMU ",8);
961 bootsector->sector_size=cpu_to_le16(0x200);
962 bootsector->sectors_per_cluster=s->sectors_per_cluster;
963 bootsector->reserved_sectors=cpu_to_le16(1);
964 bootsector->number_of_fats=0x2; /* number of FATs */
965 bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
bellarda0464332005-12-18 18:29:50 +0000966 bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
967 bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
968 s->fat.pointer[0] = bootsector->media_type;
bellardde167e42005-04-28 21:15:08 +0000969 bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
bellarda0464332005-12-18 18:29:50 +0000970 bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
971 bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
bellardde167e42005-04-28 21:15:08 +0000972 bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
bellarda0464332005-12-18 18:29:50 +0000973 bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
bellardde167e42005-04-28 21:15:08 +0000974
bellarda0464332005-12-18 18:29:50 +0000975 /* LATER TODO: if FAT32, this is wrong */
976 bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
bellardde167e42005-04-28 21:15:08 +0000977 bootsector->u.fat16.current_head=0;
978 bootsector->u.fat16.signature=0x29;
979 bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
980
981 memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
982 memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12 ":s->fat_type==16?"FAT16 ":"FAT32 "),8);
983 bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
984
985 return 0;
986}
987
bellard83f64092006-08-01 16:21:11 +0000988#ifdef DEBUG
bellarda0464332005-12-18 18:29:50 +0000989static BDRVVVFATState *vvv = NULL;
bellard83f64092006-08-01 16:21:11 +0000990#endif
bellarda0464332005-12-18 18:29:50 +0000991
992static int enable_write_target(BDRVVVFATState *s);
993static int is_consistent(BDRVVVFATState *s);
994
bellard83f64092006-08-01 16:21:11 +0000995static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
bellardde167e42005-04-28 21:15:08 +0000996{
997 BDRVVVFATState *s = bs->opaque;
bellarda0464332005-12-18 18:29:50 +0000998 int floppy = 0;
bellardde167e42005-04-28 21:15:08 +0000999 int i;
1000
bellard83f64092006-08-01 16:21:11 +00001001#ifdef DEBUG
bellarda0464332005-12-18 18:29:50 +00001002 vvv = s;
bellard83f64092006-08-01 16:21:11 +00001003#endif
bellarda0464332005-12-18 18:29:50 +00001004
1005DLOG(if (stderr == NULL) {
1006 stderr = fopen("vvfat.log", "a");
1007 setbuf(stderr, NULL);
1008})
1009
1010 s->bs = bs;
1011
bellardde167e42005-04-28 21:15:08 +00001012 s->fat_type=16;
bellarda0464332005-12-18 18:29:50 +00001013 /* LATER TODO: if FAT32, adjust */
bellarda0464332005-12-18 18:29:50 +00001014 s->sectors_per_cluster=0x10;
thsb5700942007-09-25 14:47:03 +00001015 /* 504MB disk*/
1016 bs->cyls=1024; bs->heads=16; bs->secs=63;
bellardde167e42005-04-28 21:15:08 +00001017
1018 s->current_cluster=0xffffffff;
bellardde167e42005-04-28 21:15:08 +00001019
bellardde167e42005-04-28 21:15:08 +00001020 s->first_sectors_number=0x40;
bellarda0464332005-12-18 18:29:50 +00001021 /* read only is the default for safety */
1022 bs->read_only = 1;
1023 s->qcow = s->write_target = NULL;
1024 s->qcow_filename = NULL;
1025 s->fat2 = NULL;
1026 s->downcase_short_names = 1;
ths3b46e622007-09-17 08:09:54 +00001027
bellarda0464332005-12-18 18:29:50 +00001028 if (!strstart(dirname, "fat:", NULL))
1029 return -1;
1030
bellarda0464332005-12-18 18:29:50 +00001031 if (strstr(dirname, ":floppy:")) {
1032 floppy = 1;
1033 s->fat_type = 12;
1034 s->first_sectors_number = 1;
1035 s->sectors_per_cluster=2;
1036 bs->cyls = 80; bs->heads = 2; bs->secs = 36;
1037 }
1038
thsb5700942007-09-25 14:47:03 +00001039 s->sector_count=bs->cyls*bs->heads*bs->secs;
1040
bellarda0464332005-12-18 18:29:50 +00001041 if (strstr(dirname, ":32:")) {
1042 fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1043 s->fat_type = 32;
1044 } else if (strstr(dirname, ":16:")) {
1045 s->fat_type = 16;
1046 } else if (strstr(dirname, ":12:")) {
1047 s->fat_type = 12;
1048 s->sector_count=2880;
1049 }
1050
thsb5700942007-09-25 14:47:03 +00001051 if (strstr(dirname, ":rw:")) {
1052 if (enable_write_target(s))
1053 return -1;
1054 bs->read_only = 0;
1055 }
1056
bellarda0464332005-12-18 18:29:50 +00001057 i = strrchr(dirname, ':') - dirname;
1058 assert(i >= 3);
blueswir1cd390082008-11-16 13:53:32 +00001059 if (dirname[i-2] == ':' && qemu_isalpha(dirname[i-1]))
bellarda0464332005-12-18 18:29:50 +00001060 /* workaround for DOS drive names */
1061 dirname += i-1;
1062 else
1063 dirname += i+1;
1064
1065 bs->total_sectors=bs->cyls*bs->heads*bs->secs;
thsb5700942007-09-25 14:47:03 +00001066
bellarda0464332005-12-18 18:29:50 +00001067 if(init_directories(s, dirname))
bellardde167e42005-04-28 21:15:08 +00001068 return -1;
1069
thsb5700942007-09-25 14:47:03 +00001070 s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
1071
bellardde167e42005-04-28 21:15:08 +00001072 if(s->first_sectors_number==0x40)
1073 init_mbr(s);
1074
bellarda0464332005-12-18 18:29:50 +00001075 /* for some reason or other, MS-DOS does not like to know about CHS... */
1076 if (floppy)
1077 bs->heads = bs->cyls = bs->secs = 0;
bellardde167e42005-04-28 21:15:08 +00001078
bellarda0464332005-12-18 18:29:50 +00001079 // assert(is_consistent(s));
bellardde167e42005-04-28 21:15:08 +00001080 return 0;
1081}
1082
1083static inline void vvfat_close_current_file(BDRVVVFATState *s)
1084{
1085 if(s->current_mapping) {
bellarda0464332005-12-18 18:29:50 +00001086 s->current_mapping = NULL;
1087 if (s->current_fd) {
1088 close(s->current_fd);
1089 s->current_fd = 0;
1090 }
bellardde167e42005-04-28 21:15:08 +00001091 }
bellarda0464332005-12-18 18:29:50 +00001092 s->current_cluster = -1;
bellardde167e42005-04-28 21:15:08 +00001093}
1094
1095/* mappings between index1 and index2-1 are supposed to be ordered
1096 * return value is the index of the last mapping for which end>cluster_num
1097 */
1098static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1099{
1100 int index3=index1+1;
bellardde167e42005-04-28 21:15:08 +00001101 while(1) {
1102 mapping_t* mapping;
1103 index3=(index1+index2)/2;
1104 mapping=array_get(&(s->mapping),index3);
bellarda0464332005-12-18 18:29:50 +00001105 assert(mapping->begin < mapping->end);
1106 if(mapping->begin>=cluster_num) {
bellardde167e42005-04-28 21:15:08 +00001107 assert(index2!=index3 || index2==0);
1108 if(index2==index3)
bellarda0464332005-12-18 18:29:50 +00001109 return index1;
bellardde167e42005-04-28 21:15:08 +00001110 index2=index3;
1111 } else {
1112 if(index1==index3)
bellarda0464332005-12-18 18:29:50 +00001113 return mapping->end<=cluster_num ? index2 : index1;
bellardde167e42005-04-28 21:15:08 +00001114 index1=index3;
1115 }
1116 assert(index1<=index2);
bellarda0464332005-12-18 18:29:50 +00001117 DLOG(mapping=array_get(&(s->mapping),index1);
1118 assert(mapping->begin<=cluster_num);
ths5fafdf22007-09-16 21:08:06 +00001119 assert(index2 >= s->mapping.next ||
bellarda0464332005-12-18 18:29:50 +00001120 ((mapping = array_get(&(s->mapping),index2)) &&
1121 mapping->end>cluster_num)));
bellardde167e42005-04-28 21:15:08 +00001122 }
1123}
1124
1125static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
1126{
1127 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
1128 mapping_t* mapping;
1129 if(index>=s->mapping.next)
1130 return 0;
1131 mapping=array_get(&(s->mapping),index);
1132 if(mapping->begin>cluster_num)
1133 return 0;
bellarda0464332005-12-18 18:29:50 +00001134 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
bellardde167e42005-04-28 21:15:08 +00001135 return mapping;
1136}
1137
bellarda0464332005-12-18 18:29:50 +00001138/*
1139 * This function simply compares path == mapping->path. Since the mappings
1140 * are sorted by cluster, this is expensive: O(n).
1141 */
1142static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
1143 const char* path)
1144{
1145 int i;
1146
1147 for (i = 0; i < s->mapping.next; i++) {
1148 mapping_t* mapping = array_get(&(s->mapping), i);
1149 if (mapping->first_mapping_index < 0 &&
1150 !strcmp(path, mapping->path))
1151 return mapping;
1152 }
1153
1154 return NULL;
1155}
1156
1157static int open_file(BDRVVVFATState* s,mapping_t* mapping)
bellardde167e42005-04-28 21:15:08 +00001158{
1159 if(!mapping)
1160 return -1;
bellardde167e42005-04-28 21:15:08 +00001161 if(!s->current_mapping ||
bellarda0464332005-12-18 18:29:50 +00001162 strcmp(s->current_mapping->path,mapping->path)) {
bellardde167e42005-04-28 21:15:08 +00001163 /* open file */
bellarda0464332005-12-18 18:29:50 +00001164 int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
bellardde167e42005-04-28 21:15:08 +00001165 if(fd<0)
1166 return -1;
1167 vvfat_close_current_file(s);
1168 s->current_fd = fd;
bellardde167e42005-04-28 21:15:08 +00001169 s->current_mapping = mapping;
1170 }
1171 return 0;
1172}
1173
1174static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1175{
1176 if(s->current_cluster != cluster_num) {
1177 int result=0;
1178 off_t offset;
bellarda0464332005-12-18 18:29:50 +00001179 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
bellardde167e42005-04-28 21:15:08 +00001180 if(!s->current_mapping
1181 || s->current_mapping->begin>cluster_num
1182 || s->current_mapping->end<=cluster_num) {
1183 /* binary search of mappings for file */
1184 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
bellardde167e42005-04-28 21:15:08 +00001185
bellarda0464332005-12-18 18:29:50 +00001186 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1187
1188 if (mapping && mapping->mode & MODE_DIRECTORY) {
1189 vvfat_close_current_file(s);
1190 s->current_mapping = mapping;
1191read_cluster_directory:
1192 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
thsffe8ab82007-12-16 03:16:05 +00001193 s->cluster = (unsigned char*)s->directory.pointer+offset
bellarda0464332005-12-18 18:29:50 +00001194 + 0x20*s->current_mapping->info.dir.first_dir_index;
1195 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1196 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1197 s->current_cluster = cluster_num;
1198 return 0;
1199 }
1200
1201 if(open_file(s,mapping))
1202 return -2;
1203 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1204 goto read_cluster_directory;
1205
1206 assert(s->current_fd);
1207
1208 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
bellardde167e42005-04-28 21:15:08 +00001209 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1210 return -3;
bellarda0464332005-12-18 18:29:50 +00001211 s->cluster=s->cluster_buffer;
bellardde167e42005-04-28 21:15:08 +00001212 result=read(s->current_fd,s->cluster,s->cluster_size);
1213 if(result<0) {
1214 s->current_cluster = -1;
1215 return -1;
1216 }
1217 s->current_cluster = cluster_num;
1218 }
1219 return 0;
1220}
1221
bellarda0464332005-12-18 18:29:50 +00001222#ifdef DEBUG
1223static void hexdump(const void* address, uint32_t len)
1224{
1225 const unsigned char* p = address;
1226 int i, j;
1227
1228 for (i = 0; i < len; i += 16) {
1229 for (j = 0; j < 16 && i + j < len; j++)
1230 fprintf(stderr, "%02x ", p[i + j]);
1231 for (; j < 16; j++)
1232 fprintf(stderr, " ");
1233 fprintf(stderr, " ");
1234 for (j = 0; j < 16 && i + j < len; j++)
1235 fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
1236 fprintf(stderr, "\n");
1237 }
1238}
1239
1240static void print_direntry(const direntry_t* direntry)
1241{
1242 int j = 0;
1243 char buffer[1024];
1244
1245 fprintf(stderr, "direntry 0x%x: ", (int)direntry);
1246 if(!direntry)
1247 return;
1248 if(is_long_name(direntry)) {
1249 unsigned char* c=(unsigned char*)direntry;
1250 int i;
1251 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
1252#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = '°'; j++;}
1253 ADD_CHAR(c[i]);
1254 for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
1255 ADD_CHAR(c[i]);
1256 for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
1257 ADD_CHAR(c[i]);
1258 buffer[j] = 0;
1259 fprintf(stderr, "%s\n", buffer);
1260 } else {
1261 int i;
1262 for(i=0;i<11;i++)
1263 ADD_CHAR(direntry->name[i]);
1264 buffer[j] = 0;
1265 fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1266 buffer,
1267 direntry->attributes,
1268 begin_of_direntry(direntry),le32_to_cpu(direntry->size));
1269 }
1270}
1271
1272static void print_mapping(const mapping_t* mapping)
1273{
1274 fprintf(stderr, "mapping (0x%x): begin, end = %d, %d, dir_index = %d, first_mapping_index = %d, name = %s, mode = 0x%x, " , (int)mapping, mapping->begin, mapping->end, mapping->dir_index, mapping->first_mapping_index, mapping->path, mapping->mode);
1275 if (mapping->mode & MODE_DIRECTORY)
1276 fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1277 else
1278 fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
1279}
1280#endif
1281
ths5fafdf22007-09-16 21:08:06 +00001282static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
bellardde167e42005-04-28 21:15:08 +00001283 uint8_t *buf, int nb_sectors)
1284{
1285 BDRVVVFATState *s = bs->opaque;
1286 int i;
1287
bellardde167e42005-04-28 21:15:08 +00001288 for(i=0;i<nb_sectors;i++,sector_num++) {
bellarda0464332005-12-18 18:29:50 +00001289 if (sector_num >= s->sector_count)
1290 return -1;
1291 if (s->qcow) {
1292 int n;
1293 if (s->qcow->drv->bdrv_is_allocated(s->qcow,
1294 sector_num, nb_sectors-i, &n)) {
1295DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
1296 if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
1297 return -1;
1298 i += n - 1;
1299 sector_num += n - 1;
1300 continue;
1301 }
1302DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
1303 }
bellardde167e42005-04-28 21:15:08 +00001304 if(sector_num<s->faked_sectors) {
bellarda0464332005-12-18 18:29:50 +00001305 if(sector_num<s->first_sectors_number)
1306 memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
1307 else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
1308 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
1309 else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
1310 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
bellardde167e42005-04-28 21:15:08 +00001311 } else {
bellarda0464332005-12-18 18:29:50 +00001312 uint32_t sector=sector_num-s->faked_sectors,
1313 sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1314 cluster_num=sector/s->sectors_per_cluster;
1315 if(read_cluster(s, cluster_num) != 0) {
1316 /* LATER TODO: strict: return -1; */
1317 memset(buf+i*0x200,0,0x200);
1318 continue;
1319 }
1320 memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
1321 }
1322 }
1323 return 0;
1324}
1325
1326/* LATER TODO: statify all functions */
1327
1328/*
1329 * Idea of the write support (use snapshot):
1330 *
1331 * 1. check if all data is consistent, recording renames, modifications,
1332 * new files and directories (in s->commits).
1333 *
1334 * 2. if the data is not consistent, stop committing
1335 *
1336 * 3. handle renames, and create new files and directories (do not yet
1337 * write their contents)
1338 *
1339 * 4. walk the directories, fixing the mapping and direntries, and marking
1340 * the handled mappings as not deleted
1341 *
1342 * 5. commit the contents of the files
1343 *
1344 * 6. handle deleted files and directories
1345 *
1346 */
1347
1348typedef struct commit_t {
1349 char* path;
1350 union {
1351 struct { uint32_t cluster; } rename;
1352 struct { int dir_index; uint32_t modified_offset; } writeout;
1353 struct { uint32_t first_cluster; } new_file;
1354 struct { uint32_t cluster; } mkdir;
1355 } param;
1356 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1357 enum {
1358 ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1359 } action;
1360} commit_t;
1361
1362static void clear_commits(BDRVVVFATState* s)
1363{
1364 int i;
1365DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1366 for (i = 0; i < s->commits.next; i++) {
1367 commit_t* commit = array_get(&(s->commits), i);
1368 assert(commit->path || commit->action == ACTION_WRITEOUT);
1369 if (commit->action != ACTION_WRITEOUT) {
1370 assert(commit->path);
1371 free(commit->path);
1372 } else
1373 assert(commit->path == NULL);
1374 }
1375 s->commits.next = 0;
1376}
1377
1378static void schedule_rename(BDRVVVFATState* s,
1379 uint32_t cluster, char* new_path)
1380{
1381 commit_t* commit = array_get_next(&(s->commits));
1382 commit->path = new_path;
1383 commit->param.rename.cluster = cluster;
1384 commit->action = ACTION_RENAME;
1385}
1386
1387static void schedule_writeout(BDRVVVFATState* s,
1388 int dir_index, uint32_t modified_offset)
1389{
1390 commit_t* commit = array_get_next(&(s->commits));
1391 commit->path = NULL;
1392 commit->param.writeout.dir_index = dir_index;
1393 commit->param.writeout.modified_offset = modified_offset;
1394 commit->action = ACTION_WRITEOUT;
1395}
1396
1397static void schedule_new_file(BDRVVVFATState* s,
1398 char* path, uint32_t first_cluster)
1399{
1400 commit_t* commit = array_get_next(&(s->commits));
1401 commit->path = path;
1402 commit->param.new_file.first_cluster = first_cluster;
1403 commit->action = ACTION_NEW_FILE;
1404}
1405
1406static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1407{
1408 commit_t* commit = array_get_next(&(s->commits));
1409 commit->path = path;
1410 commit->param.mkdir.cluster = cluster;
1411 commit->action = ACTION_MKDIR;
1412}
1413
1414typedef struct {
ths64eaabd2008-07-03 19:54:19 +00001415 /*
1416 * Since the sequence number is at most 0x3f, and the filename
1417 * length is at most 13 times the sequence number, the maximal
1418 * filename length is 0x3f * 13 bytes.
1419 */
1420 unsigned char name[0x3f * 13 + 1];
bellarda0464332005-12-18 18:29:50 +00001421 int checksum, len;
1422 int sequence_number;
1423} long_file_name;
1424
1425static void lfn_init(long_file_name* lfn)
1426{
1427 lfn->sequence_number = lfn->len = 0;
1428 lfn->checksum = 0x100;
1429}
1430
1431/* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1432static int parse_long_name(long_file_name* lfn,
1433 const direntry_t* direntry)
1434{
1435 int i, j, offset;
1436 const unsigned char* pointer = (const unsigned char*)direntry;
1437
1438 if (!is_long_name(direntry))
1439 return 1;
1440
1441 if (pointer[0] & 0x40) {
1442 lfn->sequence_number = pointer[0] & 0x3f;
1443 lfn->checksum = pointer[13];
1444 lfn->name[0] = 0;
ths59fdb012008-07-03 19:55:47 +00001445 lfn->name[lfn->sequence_number * 13] = 0;
bellarda0464332005-12-18 18:29:50 +00001446 } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
1447 return -1;
1448 else if (pointer[13] != lfn->checksum)
1449 return -2;
1450 else if (pointer[12] || pointer[26] || pointer[27])
1451 return -3;
1452
1453 offset = 13 * (lfn->sequence_number - 1);
1454 for (i = 0, j = 1; i < 13; i++, j+=2) {
1455 if (j == 11)
1456 j = 14;
1457 else if (j == 26)
1458 j = 28;
1459
1460 if (pointer[j+1] == 0)
1461 lfn->name[offset + i] = pointer[j];
1462 else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1463 return -4;
1464 else
1465 lfn->name[offset + i] = 0;
1466 }
1467
1468 if (pointer[0] & 0x40)
thsffe8ab82007-12-16 03:16:05 +00001469 lfn->len = offset + strlen((char*)lfn->name + offset);
bellarda0464332005-12-18 18:29:50 +00001470
1471 return 0;
1472}
1473
1474/* returns 0 if successful, >0 if no short_name, and <0 on error */
1475static int parse_short_name(BDRVVVFATState* s,
1476 long_file_name* lfn, direntry_t* direntry)
1477{
1478 int i, j;
1479
1480 if (!is_short_name(direntry))
1481 return 1;
1482
1483 for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1484 for (i = 0; i <= j; i++) {
1485 if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
1486 return -1;
1487 else if (s->downcase_short_names)
blueswir147398b92008-11-22 20:04:24 +00001488 lfn->name[i] = qemu_tolower(direntry->name[i]);
bellarda0464332005-12-18 18:29:50 +00001489 else
1490 lfn->name[i] = direntry->name[i];
1491 }
1492
1493 for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
1494 if (j >= 0) {
1495 lfn->name[i++] = '.';
1496 lfn->name[i + j + 1] = '\0';
1497 for (;j >= 0; j--) {
1498 if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
1499 return -2;
1500 else if (s->downcase_short_names)
blueswir147398b92008-11-22 20:04:24 +00001501 lfn->name[i + j] = qemu_tolower(direntry->extension[j]);
bellarda0464332005-12-18 18:29:50 +00001502 else
1503 lfn->name[i + j] = direntry->extension[j];
1504 }
1505 } else
1506 lfn->name[i + j + 1] = '\0';
1507
thsffe8ab82007-12-16 03:16:05 +00001508 lfn->len = strlen((char*)lfn->name);
bellarda0464332005-12-18 18:29:50 +00001509
1510 return 0;
1511}
1512
1513static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1514 unsigned int cluster)
1515{
1516 if (cluster < s->last_cluster_of_root_directory) {
1517 if (cluster + 1 == s->last_cluster_of_root_directory)
1518 return s->max_fat_value;
1519 else
1520 return cluster + 1;
1521 }
1522
1523 if (s->fat_type==32) {
1524 uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1525 return le32_to_cpu(*entry);
1526 } else if (s->fat_type==16) {
1527 uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1528 return le16_to_cpu(*entry);
1529 } else {
1530 const uint8_t* x=s->fat2+cluster*3/2;
1531 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1532 }
1533}
1534
1535static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1536{
1537 int was_modified = 0;
1538 int i, dummy;
1539
1540 if (s->qcow == NULL)
1541 return 0;
1542
1543 for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
1544 was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
1545 cluster2sector(s, cluster_num) + i, 1, &dummy);
1546
1547 return was_modified;
1548}
1549
1550static const char* get_basename(const char* path)
1551{
1552 char* basename = strrchr(path, '/');
1553 if (basename == NULL)
1554 return path;
1555 else
1556 return basename + 1; /* strip '/' */
1557}
1558
1559/*
1560 * The array s->used_clusters holds the states of the clusters. If it is
1561 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1562 * was modified, bit 3 is set.
1563 * If any cluster is allocated, but not part of a file or directory, this
1564 * driver refuses to commit.
1565 */
1566typedef enum {
1567 USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
1568} used_t;
1569
1570/*
1571 * get_cluster_count_for_direntry() not only determines how many clusters
1572 * are occupied by direntry, but also if it was renamed or modified.
1573 *
1574 * A file is thought to be renamed *only* if there already was a file with
1575 * exactly the same first cluster, but a different name.
1576 *
1577 * Further, the files/directories handled by this function are
1578 * assumed to be *not* deleted (and *only* those).
1579 */
1580static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
1581 direntry_t* direntry, const char* path)
1582{
1583 /*
1584 * This is a little bit tricky:
1585 * IF the guest OS just inserts a cluster into the file chain,
1586 * and leaves the rest alone, (i.e. the original file had clusters
1587 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1588 *
1589 * - do_commit will write the cluster into the file at the given
1590 * offset, but
1591 *
1592 * - the cluster which is overwritten should be moved to a later
1593 * position in the file.
1594 *
1595 * I am not aware that any OS does something as braindead, but this
1596 * situation could happen anyway when not committing for a long time.
1597 * Just to be sure that this does not bite us, detect it, and copy the
1598 * contents of the clusters to-be-overwritten into the qcow.
1599 */
1600 int copy_it = 0;
1601 int was_modified = 0;
1602 int32_t ret = 0;
1603
1604 uint32_t cluster_num = begin_of_direntry(direntry);
1605 uint32_t offset = 0;
1606 int first_mapping_index = -1;
1607 mapping_t* mapping = NULL;
1608 const char* basename2 = NULL;
1609
1610 vvfat_close_current_file(s);
1611
1612 /* the root directory */
1613 if (cluster_num == 0)
1614 return 0;
1615
1616 /* write support */
1617 if (s->qcow) {
1618 basename2 = get_basename(path);
1619
1620 mapping = find_mapping_for_cluster(s, cluster_num);
1621
1622 if (mapping) {
bellardda2414e2006-04-23 14:36:41 +00001623 const char* basename;
1624
bellarda0464332005-12-18 18:29:50 +00001625 assert(mapping->mode & MODE_DELETED);
1626 mapping->mode &= ~MODE_DELETED;
1627
bellardda2414e2006-04-23 14:36:41 +00001628 basename = get_basename(mapping->path);
bellarda0464332005-12-18 18:29:50 +00001629
1630 assert(mapping->mode & MODE_NORMAL);
1631
1632 /* rename */
1633 if (strcmp(basename, basename2))
1634 schedule_rename(s, cluster_num, strdup(path));
1635 } else if (is_file(direntry))
1636 /* new file */
1637 schedule_new_file(s, strdup(path), cluster_num);
1638 else {
1639 assert(0);
1640 return 0;
1641 }
1642 }
1643
1644 while(1) {
1645 if (s->qcow) {
1646 if (!copy_it && cluster_was_modified(s, cluster_num)) {
1647 if (mapping == NULL ||
1648 mapping->begin > cluster_num ||
1649 mapping->end <= cluster_num)
1650 mapping = find_mapping_for_cluster(s, cluster_num);
1651
1652
1653 if (mapping &&
1654 (mapping->mode & MODE_DIRECTORY) == 0) {
1655
1656 /* was modified in qcow */
1657 if (offset != mapping->info.file.offset + s->cluster_size
1658 * (cluster_num - mapping->begin)) {
1659 /* offset of this cluster in file chain has changed */
1660 assert(0);
1661 copy_it = 1;
1662 } else if (offset == 0) {
1663 const char* basename = get_basename(mapping->path);
1664
1665 if (strcmp(basename, basename2))
1666 copy_it = 1;
1667 first_mapping_index = array_index(&(s->mapping), mapping);
1668 }
1669
1670 if (mapping->first_mapping_index != first_mapping_index
1671 && mapping->info.file.offset > 0) {
1672 assert(0);
1673 copy_it = 1;
1674 }
1675
1676 /* need to write out? */
1677 if (!was_modified && is_file(direntry)) {
1678 was_modified = 1;
1679 schedule_writeout(s, mapping->dir_index, offset);
1680 }
bellardde167e42005-04-28 21:15:08 +00001681 }
bellarda0464332005-12-18 18:29:50 +00001682 }
bellardde167e42005-04-28 21:15:08 +00001683
bellarda0464332005-12-18 18:29:50 +00001684 if (copy_it) {
1685 int i, dummy;
1686 /*
1687 * This is horribly inefficient, but that is okay, since
1688 * it is rarely executed, if at all.
1689 */
1690 int64_t offset = cluster2sector(s, cluster_num);
bellardde167e42005-04-28 21:15:08 +00001691
bellarda0464332005-12-18 18:29:50 +00001692 vvfat_close_current_file(s);
1693 for (i = 0; i < s->sectors_per_cluster; i++)
1694 if (!s->qcow->drv->bdrv_is_allocated(s->qcow,
1695 offset + i, 1, &dummy)) {
1696 if (vvfat_read(s->bs,
1697 offset, s->cluster_buffer, 1))
1698 return -1;
1699 if (s->qcow->drv->bdrv_write(s->qcow,
1700 offset, s->cluster_buffer, 1))
1701 return -2;
1702 }
bellardde167e42005-04-28 21:15:08 +00001703 }
1704 }
bellarda0464332005-12-18 18:29:50 +00001705
1706 ret++;
1707 if (s->used_clusters[cluster_num] & USED_ANY)
1708 return 0;
1709 s->used_clusters[cluster_num] = USED_FILE;
1710
1711 cluster_num = modified_fat_get(s, cluster_num);
1712
1713 if (fat_eof(s, cluster_num))
1714 return ret;
1715 else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
1716 return -1;
1717
1718 offset += s->cluster_size;
bellardde167e42005-04-28 21:15:08 +00001719 }
1720}
1721
bellarda0464332005-12-18 18:29:50 +00001722/*
ths5fafdf22007-09-16 21:08:06 +00001723 * This function looks at the modified data (qcow).
bellarda0464332005-12-18 18:29:50 +00001724 * It returns 0 upon inconsistency or error, and the number of clusters
1725 * used by the directory, its subdirectories and their files.
1726 */
1727static int check_directory_consistency(BDRVVVFATState *s,
1728 int cluster_num, const char* path)
bellardde167e42005-04-28 21:15:08 +00001729{
bellarda0464332005-12-18 18:29:50 +00001730 int ret = 0;
1731 unsigned char* cluster = malloc(s->cluster_size);
1732 direntry_t* direntries = (direntry_t*)cluster;
1733 mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
bellardde167e42005-04-28 21:15:08 +00001734
bellarda0464332005-12-18 18:29:50 +00001735 long_file_name lfn;
1736 int path_len = strlen(path);
1737 char path2[PATH_MAX];
bellardde167e42005-04-28 21:15:08 +00001738
bellarda0464332005-12-18 18:29:50 +00001739 assert(path_len < PATH_MAX); /* len was tested before! */
blueswir1363a37d2008-08-21 17:58:08 +00001740 pstrcpy(path2, sizeof(path2), path);
bellarda0464332005-12-18 18:29:50 +00001741 path2[path_len] = '/';
1742 path2[path_len + 1] = '\0';
bellardde167e42005-04-28 21:15:08 +00001743
bellarda0464332005-12-18 18:29:50 +00001744 if (mapping) {
1745 const char* basename = get_basename(mapping->path);
1746 const char* basename2 = get_basename(path);
1747
1748 assert(mapping->mode & MODE_DIRECTORY);
1749
1750 assert(mapping->mode & MODE_DELETED);
1751 mapping->mode &= ~MODE_DELETED;
1752
1753 if (strcmp(basename, basename2))
1754 schedule_rename(s, cluster_num, strdup(path));
1755 } else
1756 /* new directory */
1757 schedule_mkdir(s, cluster_num, strdup(path));
ths3b46e622007-09-17 08:09:54 +00001758
bellarda0464332005-12-18 18:29:50 +00001759 lfn_init(&lfn);
1760 do {
1761 int i;
1762 int subret = 0;
1763
1764 ret++;
1765
1766 if (s->used_clusters[cluster_num] & USED_ANY) {
1767 fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
1768 return 0;
bellardde167e42005-04-28 21:15:08 +00001769 }
bellarda0464332005-12-18 18:29:50 +00001770 s->used_clusters[cluster_num] = USED_DIRECTORY;
bellardde167e42005-04-28 21:15:08 +00001771
bellarda0464332005-12-18 18:29:50 +00001772DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
1773 subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
1774 s->sectors_per_cluster);
1775 if (subret) {
1776 fprintf(stderr, "Error fetching direntries\n");
1777 fail:
1778 free(cluster);
1779 return 0;
1780 }
1781
1782 for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
1783 int cluster_count;
1784
1785DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
1786 if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
1787 is_free(direntries + i))
1788 continue;
1789
1790 subret = parse_long_name(&lfn, direntries + i);
1791 if (subret < 0) {
1792 fprintf(stderr, "Error in long name\n");
1793 goto fail;
bellardde167e42005-04-28 21:15:08 +00001794 }
bellarda0464332005-12-18 18:29:50 +00001795 if (subret == 0 || is_free(direntries + i))
1796 continue;
1797
1798 if (fat_chksum(direntries+i) != lfn.checksum) {
1799 subret = parse_short_name(s, &lfn, direntries + i);
1800 if (subret < 0) {
1801 fprintf(stderr, "Error in short name (%d)\n", subret);
1802 goto fail;
1803 }
thsffe8ab82007-12-16 03:16:05 +00001804 if (subret > 0 || !strcmp((char*)lfn.name, ".")
1805 || !strcmp((char*)lfn.name, ".."))
bellarda0464332005-12-18 18:29:50 +00001806 continue;
1807 }
1808 lfn.checksum = 0x100; /* cannot use long name twice */
1809
1810 if (path_len + 1 + lfn.len >= PATH_MAX) {
1811 fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
1812 goto fail;
1813 }
blueswir1363a37d2008-08-21 17:58:08 +00001814 pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
1815 (char*)lfn.name);
bellarda0464332005-12-18 18:29:50 +00001816
1817 if (is_directory(direntries + i)) {
1818 if (begin_of_direntry(direntries + i) == 0) {
1819 DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
1820 goto fail;
1821 }
1822 cluster_count = check_directory_consistency(s,
1823 begin_of_direntry(direntries + i), path2);
1824 if (cluster_count == 0) {
1825 DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
1826 goto fail;
1827 }
1828 } else if (is_file(direntries + i)) {
1829 /* check file size with FAT */
1830 cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
1831 if (cluster_count !=
1832 (le32_to_cpu(direntries[i].size) + s->cluster_size
1833 - 1) / s->cluster_size) {
1834 DLOG(fprintf(stderr, "Cluster count mismatch\n"));
1835 goto fail;
1836 }
1837 } else
1838 assert(0); /* cluster_count = 0; */
1839
1840 ret += cluster_count;
bellardde167e42005-04-28 21:15:08 +00001841 }
bellarda0464332005-12-18 18:29:50 +00001842
1843 cluster_num = modified_fat_get(s, cluster_num);
1844 } while(!fat_eof(s, cluster_num));
1845
1846 free(cluster);
1847 return ret;
bellardde167e42005-04-28 21:15:08 +00001848}
1849
bellarda0464332005-12-18 18:29:50 +00001850/* returns 1 on success */
1851static int is_consistent(BDRVVVFATState* s)
bellardde167e42005-04-28 21:15:08 +00001852{
bellarda0464332005-12-18 18:29:50 +00001853 int i, check;
1854 int used_clusters_count = 0;
1855
1856DLOG(checkpoint());
1857 /*
1858 * - get modified FAT
1859 * - compare the two FATs (TODO)
1860 * - get buffer for marking used clusters
1861 * - recurse direntries from root (using bs->bdrv_read to make
1862 * sure to get the new data)
1863 * - check that the FAT agrees with the size
1864 * - count the number of clusters occupied by this directory and
1865 * its files
1866 * - check that the cumulative used cluster count agrees with the
1867 * FAT
1868 * - if all is fine, return number of used clusters
1869 */
1870 if (s->fat2 == NULL) {
1871 int size = 0x200 * s->sectors_per_fat;
1872 s->fat2 = malloc(size);
1873 memcpy(s->fat2, s->fat.pointer, size);
1874 }
1875 check = vvfat_read(s->bs,
1876 s->first_sectors_number, s->fat2, s->sectors_per_fat);
1877 if (check) {
1878 fprintf(stderr, "Could not copy fat\n");
bellardde167e42005-04-28 21:15:08 +00001879 return 0;
1880 }
bellarda0464332005-12-18 18:29:50 +00001881 assert (s->used_clusters);
1882 for (i = 0; i < sector2cluster(s, s->sector_count); i++)
1883 s->used_clusters[i] &= ~USED_ANY;
1884
1885 clear_commits(s);
1886
1887 /* mark every mapped file/directory as deleted.
1888 * (check_directory_consistency() will unmark those still present). */
1889 if (s->qcow)
1890 for (i = 0; i < s->mapping.next; i++) {
1891 mapping_t* mapping = array_get(&(s->mapping), i);
1892 if (mapping->first_mapping_index < 0)
1893 mapping->mode |= MODE_DELETED;
1894 }
1895
1896 used_clusters_count = check_directory_consistency(s, 0, s->path);
1897 if (used_clusters_count <= 0) {
1898 DLOG(fprintf(stderr, "problem in directory\n"));
1899 return 0;
1900 }
1901
1902 check = s->last_cluster_of_root_directory;
1903 for (i = check; i < sector2cluster(s, s->sector_count); i++) {
1904 if (modified_fat_get(s, i)) {
1905 if(!s->used_clusters[i]) {
1906 DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
1907 return 0;
1908 }
1909 check++;
1910 }
1911
1912 if (s->used_clusters[i] == USED_ALLOCATED) {
1913 /* allocated, but not used... */
1914 DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
1915 return 0;
1916 }
1917 }
1918
1919 if (check != used_clusters_count)
1920 return 0;
1921
1922 return used_clusters_count;
bellardde167e42005-04-28 21:15:08 +00001923}
1924
bellarda0464332005-12-18 18:29:50 +00001925static inline void adjust_mapping_indices(BDRVVVFATState* s,
1926 int offset, int adjust)
bellardde167e42005-04-28 21:15:08 +00001927{
bellarda0464332005-12-18 18:29:50 +00001928 int i;
1929
1930 for (i = 0; i < s->mapping.next; i++) {
1931 mapping_t* mapping = array_get(&(s->mapping), i);
1932
1933#define ADJUST_MAPPING_INDEX(name) \
1934 if (mapping->name >= offset) \
1935 mapping->name += adjust
1936
1937 ADJUST_MAPPING_INDEX(first_mapping_index);
1938 if (mapping->mode & MODE_DIRECTORY)
1939 ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
1940 }
bellardde167e42005-04-28 21:15:08 +00001941}
1942
bellarda0464332005-12-18 18:29:50 +00001943/* insert or update mapping */
1944static mapping_t* insert_mapping(BDRVVVFATState* s,
1945 uint32_t begin, uint32_t end)
bellardde167e42005-04-28 21:15:08 +00001946{
bellarda0464332005-12-18 18:29:50 +00001947 /*
1948 * - find mapping where mapping->begin >= begin,
1949 * - if mapping->begin > begin: insert
1950 * - adjust all references to mappings!
1951 * - else: adjust
1952 * - replace name
1953 */
1954 int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
1955 mapping_t* mapping = NULL;
1956 mapping_t* first_mapping = array_get(&(s->mapping), 0);
1957
1958 if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
1959 && mapping->begin < begin) {
1960 mapping->end = begin;
1961 index++;
1962 mapping = array_get(&(s->mapping), index);
1963 }
1964 if (index >= s->mapping.next || mapping->begin > begin) {
1965 mapping = array_insert(&(s->mapping), index, 1);
1966 mapping->path = NULL;
1967 adjust_mapping_indices(s, index, +1);
1968 }
1969
bellardde167e42005-04-28 21:15:08 +00001970 mapping->begin = begin;
bellarda0464332005-12-18 18:29:50 +00001971 mapping->end = end;
1972
1973DLOG(mapping_t* next_mapping;
1974assert(index + 1 >= s->mapping.next ||
1975((next_mapping = array_get(&(s->mapping), index + 1)) &&
1976 next_mapping->begin >= end)));
1977
1978 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
1979 s->current_mapping = array_get(&(s->mapping),
1980 s->current_mapping - first_mapping);
1981
1982 return mapping;
bellardde167e42005-04-28 21:15:08 +00001983}
1984
bellarda0464332005-12-18 18:29:50 +00001985static int remove_mapping(BDRVVVFATState* s, int mapping_index)
bellardde167e42005-04-28 21:15:08 +00001986{
bellarda0464332005-12-18 18:29:50 +00001987 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
1988 mapping_t* first_mapping = array_get(&(s->mapping), 0);
bellardde167e42005-04-28 21:15:08 +00001989
bellarda0464332005-12-18 18:29:50 +00001990 /* free mapping */
1991 if (mapping->first_mapping_index < 0)
1992 free(mapping->path);
bellardde167e42005-04-28 21:15:08 +00001993
bellarda0464332005-12-18 18:29:50 +00001994 /* remove from s->mapping */
1995 array_remove(&(s->mapping), mapping_index);
bellardde167e42005-04-28 21:15:08 +00001996
bellarda0464332005-12-18 18:29:50 +00001997 /* adjust all references to mappings */
1998 adjust_mapping_indices(s, mapping_index, -1);
bellardde167e42005-04-28 21:15:08 +00001999
bellarda0464332005-12-18 18:29:50 +00002000 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
2001 s->current_mapping = array_get(&(s->mapping),
2002 s->current_mapping - first_mapping);
bellardde167e42005-04-28 21:15:08 +00002003
2004 return 0;
2005}
2006
bellarda0464332005-12-18 18:29:50 +00002007static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
bellardde167e42005-04-28 21:15:08 +00002008{
bellarda0464332005-12-18 18:29:50 +00002009 int i;
2010 for (i = 0; i < s->mapping.next; i++) {
2011 mapping_t* mapping = array_get(&(s->mapping), i);
2012 if (mapping->dir_index >= offset)
2013 mapping->dir_index += adjust;
2014 if ((mapping->mode & MODE_DIRECTORY) &&
2015 mapping->info.dir.first_dir_index >= offset)
2016 mapping->info.dir.first_dir_index += adjust;
bellardde167e42005-04-28 21:15:08 +00002017 }
bellardde167e42005-04-28 21:15:08 +00002018}
2019
bellarda0464332005-12-18 18:29:50 +00002020static direntry_t* insert_direntries(BDRVVVFATState* s,
2021 int dir_index, int count)
bellardde167e42005-04-28 21:15:08 +00002022{
bellarda0464332005-12-18 18:29:50 +00002023 /*
2024 * make room in s->directory,
2025 * adjust_dirindices
2026 */
2027 direntry_t* result = array_insert(&(s->directory), dir_index, count);
2028 if (result == NULL)
2029 return NULL;
2030 adjust_dirindices(s, dir_index, count);
bellardde167e42005-04-28 21:15:08 +00002031 return result;
2032}
2033
bellarda0464332005-12-18 18:29:50 +00002034static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
bellardde167e42005-04-28 21:15:08 +00002035{
bellarda0464332005-12-18 18:29:50 +00002036 int ret = array_remove_slice(&(s->directory), dir_index, count);
2037 if (ret)
2038 return ret;
2039 adjust_dirindices(s, dir_index, -count);
bellardde167e42005-04-28 21:15:08 +00002040 return 0;
2041}
2042
bellarda0464332005-12-18 18:29:50 +00002043/*
2044 * Adapt the mappings of the cluster chain starting at first cluster
2045 * (i.e. if a file starts at first_cluster, the chain is followed according
2046 * to the modified fat, and the corresponding entries in s->mapping are
2047 * adjusted)
2048 */
2049static int commit_mappings(BDRVVVFATState* s,
2050 uint32_t first_cluster, int dir_index)
bellardde167e42005-04-28 21:15:08 +00002051{
bellarda0464332005-12-18 18:29:50 +00002052 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2053 direntry_t* direntry = array_get(&(s->directory), dir_index);
2054 uint32_t cluster = first_cluster;
bellardde167e42005-04-28 21:15:08 +00002055
bellarda0464332005-12-18 18:29:50 +00002056 vvfat_close_current_file(s);
bellardde167e42005-04-28 21:15:08 +00002057
bellarda0464332005-12-18 18:29:50 +00002058 assert(mapping);
2059 assert(mapping->begin == first_cluster);
2060 mapping->first_mapping_index = -1;
2061 mapping->dir_index = dir_index;
2062 mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2063 MODE_DIRECTORY : MODE_NORMAL;
bellardde167e42005-04-28 21:15:08 +00002064
bellarda0464332005-12-18 18:29:50 +00002065 while (!fat_eof(s, cluster)) {
2066 uint32_t c, c1;
bellardde167e42005-04-28 21:15:08 +00002067
bellarda0464332005-12-18 18:29:50 +00002068 for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2069 c = c1, c1 = modified_fat_get(s, c1));
bellardde167e42005-04-28 21:15:08 +00002070
bellarda0464332005-12-18 18:29:50 +00002071 c++;
2072 if (c > mapping->end) {
2073 int index = array_index(&(s->mapping), mapping);
2074 int i, max_i = s->mapping.next - index;
2075 for (i = 1; i < max_i && mapping[i].begin < c; i++);
2076 while (--i > 0)
2077 remove_mapping(s, index + 1);
2078 }
2079 assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2080 || mapping[1].begin >= c);
2081 mapping->end = c;
2082
2083 if (!fat_eof(s, c1)) {
2084 int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
2085 mapping_t* next_mapping = i >= s->mapping.next ? NULL :
2086 array_get(&(s->mapping), i);
2087
2088 if (next_mapping == NULL || next_mapping->begin > c1) {
2089 int i1 = array_index(&(s->mapping), mapping);
2090
2091 next_mapping = insert_mapping(s, c1, c1+1);
2092
2093 if (c1 < c)
2094 i1++;
2095 mapping = array_get(&(s->mapping), i1);
bellardde167e42005-04-28 21:15:08 +00002096 }
bellarda0464332005-12-18 18:29:50 +00002097
2098 next_mapping->dir_index = mapping->dir_index;
ths5fafdf22007-09-16 21:08:06 +00002099 next_mapping->first_mapping_index =
bellarda0464332005-12-18 18:29:50 +00002100 mapping->first_mapping_index < 0 ?
2101 array_index(&(s->mapping), mapping) :
2102 mapping->first_mapping_index;
2103 next_mapping->path = mapping->path;
2104 next_mapping->mode = mapping->mode;
2105 next_mapping->read_only = mapping->read_only;
2106 if (mapping->mode & MODE_DIRECTORY) {
2107 next_mapping->info.dir.parent_mapping_index =
2108 mapping->info.dir.parent_mapping_index;
2109 next_mapping->info.dir.first_dir_index =
2110 mapping->info.dir.first_dir_index +
2111 0x10 * s->sectors_per_cluster *
2112 (mapping->end - mapping->begin);
2113 } else
2114 next_mapping->info.file.offset = mapping->info.file.offset +
2115 mapping->end - mapping->begin;
2116
2117 mapping = next_mapping;
2118 }
ths3b46e622007-09-17 08:09:54 +00002119
bellarda0464332005-12-18 18:29:50 +00002120 cluster = c1;
2121 }
2122
2123 return 0;
2124}
2125
2126static int commit_direntries(BDRVVVFATState* s,
2127 int dir_index, int parent_mapping_index)
2128{
2129 direntry_t* direntry = array_get(&(s->directory), dir_index);
2130 uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
2131 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2132
2133 int factor = 0x10 * s->sectors_per_cluster;
2134 int old_cluster_count, new_cluster_count;
2135 int current_dir_index = mapping->info.dir.first_dir_index;
2136 int first_dir_index = current_dir_index;
2137 int ret, i;
2138 uint32_t c;
2139
2140DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
2141
2142 assert(direntry);
2143 assert(mapping);
2144 assert(mapping->begin == first_cluster);
2145 assert(mapping->info.dir.first_dir_index < s->directory.next);
2146 assert(mapping->mode & MODE_DIRECTORY);
2147 assert(dir_index == 0 || is_directory(direntry));
2148
2149 mapping->info.dir.parent_mapping_index = parent_mapping_index;
2150
2151 if (first_cluster == 0) {
2152 old_cluster_count = new_cluster_count =
2153 s->last_cluster_of_root_directory;
2154 } else {
2155 for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2156 c = fat_get(s, c))
2157 old_cluster_count++;
2158
2159 for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2160 c = modified_fat_get(s, c))
2161 new_cluster_count++;
2162 }
2163
2164 if (new_cluster_count > old_cluster_count) {
2165 if (insert_direntries(s,
2166 current_dir_index + factor * old_cluster_count,
2167 factor * (new_cluster_count - old_cluster_count)) == NULL)
2168 return -1;
2169 } else if (new_cluster_count < old_cluster_count)
2170 remove_direntries(s,
2171 current_dir_index + factor * new_cluster_count,
2172 factor * (old_cluster_count - new_cluster_count));
2173
2174 for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
2175 void* direntry = array_get(&(s->directory), current_dir_index);
2176 int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2177 s->sectors_per_cluster);
2178 if (ret)
2179 return ret;
2180 assert(!strncmp(s->directory.pointer, "QEMU", 4));
2181 current_dir_index += factor;
2182 }
2183
2184 ret = commit_mappings(s, first_cluster, dir_index);
2185 if (ret)
2186 return ret;
2187
2188 /* recurse */
2189 for (i = 0; i < factor * new_cluster_count; i++) {
2190 direntry = array_get(&(s->directory), first_dir_index + i);
2191 if (is_directory(direntry) && !is_dot(direntry)) {
2192 mapping = find_mapping_for_cluster(s, first_cluster);
2193 assert(mapping->mode & MODE_DIRECTORY);
2194 ret = commit_direntries(s, first_dir_index + i,
2195 array_index(&(s->mapping), mapping));
2196 if (ret)
2197 return ret;
bellardde167e42005-04-28 21:15:08 +00002198 }
2199 }
bellarda0464332005-12-18 18:29:50 +00002200
bellardde167e42005-04-28 21:15:08 +00002201 return 0;
2202}
2203
bellarda0464332005-12-18 18:29:50 +00002204/* commit one file (adjust contents, adjust mapping),
2205 return first_mapping_index */
2206static int commit_one_file(BDRVVVFATState* s,
2207 int dir_index, uint32_t offset)
2208{
2209 direntry_t* direntry = array_get(&(s->directory), dir_index);
2210 uint32_t c = begin_of_direntry(direntry);
2211 uint32_t first_cluster = c;
2212 mapping_t* mapping = find_mapping_for_cluster(s, c);
2213 uint32_t size = filesize_of_direntry(direntry);
2214 char* cluster = malloc(s->cluster_size);
2215 uint32_t i;
2216 int fd = 0;
2217
2218 assert(offset < size);
2219 assert((offset % s->cluster_size) == 0);
2220
2221 for (i = s->cluster_size; i < offset; i += s->cluster_size)
2222 c = modified_fat_get(s, c);
2223
bellard6bcb76c2006-09-09 12:03:20 +00002224 fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
bellarda0464332005-12-18 18:29:50 +00002225 if (fd < 0) {
2226 fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2227 strerror(errno), errno);
2228 return fd;
2229 }
2230 if (offset > 0)
2231 if (lseek(fd, offset, SEEK_SET) != offset)
2232 return -3;
2233
2234 while (offset < size) {
2235 uint32_t c1;
2236 int rest_size = (size - offset > s->cluster_size ?
2237 s->cluster_size : size - offset);
2238 int ret;
2239
2240 c1 = modified_fat_get(s, c);
2241
2242 assert((size - offset == 0 && fat_eof(s, c)) ||
2243 (size > offset && c >=2 && !fat_eof(s, c)));
bellarda0464332005-12-18 18:29:50 +00002244
2245 ret = vvfat_read(s->bs, cluster2sector(s, c),
thsffe8ab82007-12-16 03:16:05 +00002246 (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
bellarda0464332005-12-18 18:29:50 +00002247
2248 if (ret < 0)
2249 return ret;
2250
2251 if (write(fd, cluster, rest_size) < 0)
2252 return -2;
2253
2254 offset += rest_size;
2255 c = c1;
2256 }
2257
2258 ftruncate(fd, size);
2259 close(fd);
2260
2261 return commit_mappings(s, first_cluster, dir_index);
2262}
2263
2264#ifdef DEBUG
2265/* test, if all mappings point to valid direntries */
2266static void check1(BDRVVVFATState* s)
2267{
2268 int i;
2269 for (i = 0; i < s->mapping.next; i++) {
2270 mapping_t* mapping = array_get(&(s->mapping), i);
2271 if (mapping->mode & MODE_DELETED) {
2272 fprintf(stderr, "deleted\n");
2273 continue;
2274 }
2275 assert(mapping->dir_index >= 0);
2276 assert(mapping->dir_index < s->directory.next);
2277 direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
2278 assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2279 if (mapping->mode & MODE_DIRECTORY) {
2280 assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2281 assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2282 }
2283 }
2284}
2285
2286/* test, if all direntries have mappings */
2287static void check2(BDRVVVFATState* s)
2288{
2289 int i;
2290 int first_mapping = -1;
2291
2292 for (i = 0; i < s->directory.next; i++) {
2293 direntry_t* direntry = array_get(&(s->directory), i);
2294
2295 if (is_short_name(direntry) && begin_of_direntry(direntry)) {
2296 mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
2297 assert(mapping);
2298 assert(mapping->dir_index == i || is_dot(direntry));
2299 assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2300 }
2301
2302 if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2303 /* cluster start */
2304 int j, count = 0;
2305
2306 for (j = 0; j < s->mapping.next; j++) {
2307 mapping_t* mapping = array_get(&(s->mapping), j);
2308 if (mapping->mode & MODE_DELETED)
2309 continue;
2310 if (mapping->mode & MODE_DIRECTORY) {
2311 if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2312 assert(++count == 1);
2313 if (mapping->first_mapping_index == -1)
2314 first_mapping = array_index(&(s->mapping), mapping);
2315 else
2316 assert(first_mapping == mapping->first_mapping_index);
2317 if (mapping->info.dir.parent_mapping_index < 0)
2318 assert(j == 0);
2319 else {
2320 mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
2321 assert(parent->mode & MODE_DIRECTORY);
2322 assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2323 }
2324 }
2325 }
2326 }
2327 if (count == 0)
2328 first_mapping = -1;
2329 }
2330 }
2331}
2332#endif
2333
2334static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2335{
2336 int i;
2337
2338#ifdef DEBUG
2339 fprintf(stderr, "handle_renames\n");
2340 for (i = 0; i < s->commits.next; i++) {
2341 commit_t* commit = array_get(&(s->commits), i);
2342 fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
2343 }
2344#endif
2345
2346 for (i = 0; i < s->commits.next;) {
2347 commit_t* commit = array_get(&(s->commits), i);
2348 if (commit->action == ACTION_RENAME) {
2349 mapping_t* mapping = find_mapping_for_cluster(s,
2350 commit->param.rename.cluster);
2351 char* old_path = mapping->path;
2352
2353 assert(commit->path);
2354 mapping->path = commit->path;
2355 if (rename(old_path, mapping->path))
2356 return -2;
2357
2358 if (mapping->mode & MODE_DIRECTORY) {
2359 int l1 = strlen(mapping->path);
2360 int l2 = strlen(old_path);
2361 int diff = l1 - l2;
2362 direntry_t* direntry = array_get(&(s->directory),
2363 mapping->info.dir.first_dir_index);
2364 uint32_t c = mapping->begin;
2365 int i = 0;
2366
2367 /* recurse */
2368 while (!fat_eof(s, c)) {
2369 do {
2370 direntry_t* d = direntry + i;
2371
2372 if (is_file(d) || (is_directory(d) && !is_dot(d))) {
2373 mapping_t* m = find_mapping_for_cluster(s,
2374 begin_of_direntry(d));
2375 int l = strlen(m->path);
2376 char* new_path = malloc(l + diff + 1);
2377
2378 assert(!strncmp(m->path, mapping->path, l2));
2379
blueswir1363a37d2008-08-21 17:58:08 +00002380 pstrcpy(new_path, l + diff + 1, mapping->path);
2381 pstrcpy(new_path + l1, l + diff + 1 - l1,
2382 m->path + l2);
bellarda0464332005-12-18 18:29:50 +00002383
2384 schedule_rename(s, m->begin, new_path);
2385 }
2386 i++;
2387 } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2388 c = fat_get(s, c);
2389 }
2390 }
2391
2392 free(old_path);
2393 array_remove(&(s->commits), i);
2394 continue;
2395 } else if (commit->action == ACTION_MKDIR) {
2396 mapping_t* mapping;
2397 int j, parent_path_len;
2398
bellard48c2f062005-12-19 22:11:49 +00002399#ifdef __MINGW32__
2400 if (mkdir(commit->path))
2401 return -5;
2402#else
2403 if (mkdir(commit->path, 0755))
2404 return -5;
2405#endif
bellarda0464332005-12-18 18:29:50 +00002406
2407 mapping = insert_mapping(s, commit->param.mkdir.cluster,
2408 commit->param.mkdir.cluster + 1);
2409 if (mapping == NULL)
2410 return -6;
2411
2412 mapping->mode = MODE_DIRECTORY;
2413 mapping->read_only = 0;
2414 mapping->path = commit->path;
2415 j = s->directory.next;
2416 assert(j);
2417 insert_direntries(s, s->directory.next,
2418 0x10 * s->sectors_per_cluster);
2419 mapping->info.dir.first_dir_index = j;
2420
2421 parent_path_len = strlen(commit->path)
2422 - strlen(get_basename(commit->path)) - 1;
2423 for (j = 0; j < s->mapping.next; j++) {
2424 mapping_t* m = array_get(&(s->mapping), j);
2425 if (m->first_mapping_index < 0 && m != mapping &&
2426 !strncmp(m->path, mapping->path, parent_path_len) &&
2427 strlen(m->path) == parent_path_len)
2428 break;
2429 }
2430 assert(j < s->mapping.next);
2431 mapping->info.dir.parent_mapping_index = j;
2432
2433 array_remove(&(s->commits), i);
2434 continue;
2435 }
2436
2437 i++;
2438 }
2439 return 0;
2440}
2441
2442/*
2443 * TODO: make sure that the short name is not matching *another* file
2444 */
2445static int handle_commits(BDRVVVFATState* s)
2446{
2447 int i, fail = 0;
2448
2449 vvfat_close_current_file(s);
2450
2451 for (i = 0; !fail && i < s->commits.next; i++) {
2452 commit_t* commit = array_get(&(s->commits), i);
2453 switch(commit->action) {
2454 case ACTION_RENAME: case ACTION_MKDIR:
2455 assert(0);
2456 fail = -2;
2457 break;
2458 case ACTION_WRITEOUT: {
2459 direntry_t* entry = array_get(&(s->directory),
2460 commit->param.writeout.dir_index);
2461 uint32_t begin = begin_of_direntry(entry);
2462 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2463
2464 assert(mapping);
2465 assert(mapping->begin == begin);
2466 assert(commit->path == NULL);
2467
2468 if (commit_one_file(s, commit->param.writeout.dir_index,
2469 commit->param.writeout.modified_offset))
2470 fail = -3;
2471
2472 break;
2473 }
2474 case ACTION_NEW_FILE: {
2475 int begin = commit->param.new_file.first_cluster;
2476 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2477 direntry_t* entry;
2478 int i;
2479
2480 /* find direntry */
2481 for (i = 0; i < s->directory.next; i++) {
2482 entry = array_get(&(s->directory), i);
2483 if (is_file(entry) && begin_of_direntry(entry) == begin)
2484 break;
2485 }
2486
2487 if (i >= s->directory.next) {
2488 fail = -6;
2489 continue;
2490 }
2491
2492 /* make sure there exists an initial mapping */
2493 if (mapping && mapping->begin != begin) {
2494 mapping->end = begin;
2495 mapping = NULL;
2496 }
2497 if (mapping == NULL) {
2498 mapping = insert_mapping(s, begin, begin+1);
2499 }
2500 /* most members will be fixed in commit_mappings() */
2501 assert(commit->path);
2502 mapping->path = commit->path;
2503 mapping->read_only = 0;
2504 mapping->mode = MODE_NORMAL;
2505 mapping->info.file.offset = 0;
2506
2507 if (commit_one_file(s, i, 0))
2508 fail = -7;
2509
2510 break;
2511 }
2512 default:
2513 assert(0);
2514 }
2515 }
2516 if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2517 return -1;
2518 return fail;
2519}
2520
2521static int handle_deletes(BDRVVVFATState* s)
2522{
2523 int i, deferred = 1, deleted = 1;
2524
2525 /* delete files corresponding to mappings marked as deleted */
2526 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2527 while (deferred && deleted) {
2528 deferred = 0;
2529 deleted = 0;
2530
2531 for (i = 1; i < s->mapping.next; i++) {
2532 mapping_t* mapping = array_get(&(s->mapping), i);
2533 if (mapping->mode & MODE_DELETED) {
2534 direntry_t* entry = array_get(&(s->directory),
2535 mapping->dir_index);
2536
2537 if (is_free(entry)) {
2538 /* remove file/directory */
2539 if (mapping->mode & MODE_DIRECTORY) {
2540 int j, next_dir_index = s->directory.next,
2541 first_dir_index = mapping->info.dir.first_dir_index;
2542
2543 if (rmdir(mapping->path) < 0) {
2544 if (errno == ENOTEMPTY) {
2545 deferred++;
2546 continue;
2547 } else
2548 return -5;
2549 }
2550
2551 for (j = 1; j < s->mapping.next; j++) {
2552 mapping_t* m = array_get(&(s->mapping), j);
2553 if (m->mode & MODE_DIRECTORY &&
2554 m->info.dir.first_dir_index >
2555 first_dir_index &&
2556 m->info.dir.first_dir_index <
2557 next_dir_index)
2558 next_dir_index =
2559 m->info.dir.first_dir_index;
2560 }
2561 remove_direntries(s, first_dir_index,
2562 next_dir_index - first_dir_index);
2563
2564 deleted++;
2565 }
2566 } else {
2567 if (unlink(mapping->path))
2568 return -4;
2569 deleted++;
2570 }
2571 DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2572 remove_mapping(s, i);
2573 }
2574 }
2575 }
2576
2577 return 0;
2578}
2579
2580/*
2581 * synchronize mapping with new state:
2582 *
2583 * - copy FAT (with bdrv_read)
2584 * - mark all filenames corresponding to mappings as deleted
2585 * - recurse direntries from root (using bs->bdrv_read)
2586 * - delete files corresponding to mappings marked as deleted
2587 */
2588static int do_commit(BDRVVVFATState* s)
2589{
2590 int ret = 0;
2591
2592 /* the real meat are the commits. Nothing to do? Move along! */
2593 if (s->commits.next == 0)
2594 return 0;
2595
2596 vvfat_close_current_file(s);
2597
2598 ret = handle_renames_and_mkdirs(s);
2599 if (ret) {
2600 fprintf(stderr, "Error handling renames (%d)\n", ret);
2601 assert(0);
2602 return ret;
2603 }
2604
ths5fafdf22007-09-16 21:08:06 +00002605 /* copy FAT (with bdrv_read) */
bellarda0464332005-12-18 18:29:50 +00002606 memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2607
2608 /* recurse direntries from root (using bs->bdrv_read) */
2609 ret = commit_direntries(s, 0, -1);
2610 if (ret) {
2611 fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
2612 assert(0);
2613 return ret;
2614 }
2615
2616 ret = handle_commits(s);
2617 if (ret) {
2618 fprintf(stderr, "Error handling commits (%d)\n", ret);
2619 assert(0);
2620 return ret;
2621 }
2622
2623 ret = handle_deletes(s);
2624 if (ret) {
2625 fprintf(stderr, "Error deleting\n");
2626 assert(0);
2627 return ret;
2628 }
2629
2630 s->qcow->drv->bdrv_make_empty(s->qcow);
2631
2632 memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2633
2634DLOG(checkpoint());
2635 return 0;
2636}
2637
2638static int try_commit(BDRVVVFATState* s)
2639{
2640 vvfat_close_current_file(s);
2641DLOG(checkpoint());
2642 if(!is_consistent(s))
2643 return -1;
2644 return do_commit(s);
2645}
2646
ths5fafdf22007-09-16 21:08:06 +00002647static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
bellardde167e42005-04-28 21:15:08 +00002648 const uint8_t *buf, int nb_sectors)
2649{
ths5fafdf22007-09-16 21:08:06 +00002650 BDRVVVFATState *s = bs->opaque;
bellarda0464332005-12-18 18:29:50 +00002651 int i, ret;
bellardde167e42005-04-28 21:15:08 +00002652
bellarda0464332005-12-18 18:29:50 +00002653DLOG(checkpoint());
bellardde167e42005-04-28 21:15:08 +00002654
bellarda0464332005-12-18 18:29:50 +00002655 vvfat_close_current_file(s);
bellardde167e42005-04-28 21:15:08 +00002656
bellarda0464332005-12-18 18:29:50 +00002657 /*
2658 * Some sanity checks:
2659 * - do not allow writing to the boot sector
2660 * - do not allow to write non-ASCII filenames
2661 */
bellardde167e42005-04-28 21:15:08 +00002662
bellarda0464332005-12-18 18:29:50 +00002663 if (sector_num < s->first_sectors_number)
2664 return -1;
bellardde167e42005-04-28 21:15:08 +00002665
bellarda0464332005-12-18 18:29:50 +00002666 for (i = sector2cluster(s, sector_num);
2667 i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
2668 mapping_t* mapping = find_mapping_for_cluster(s, i);
2669 if (mapping) {
2670 if (mapping->read_only) {
2671 fprintf(stderr, "Tried to write to write-protected file %s\n",
2672 mapping->path);
2673 return -1;
2674 }
bellardde167e42005-04-28 21:15:08 +00002675
bellarda0464332005-12-18 18:29:50 +00002676 if (mapping->mode & MODE_DIRECTORY) {
2677 int begin = cluster2sector(s, i);
2678 int end = begin + s->sectors_per_cluster, k;
2679 int dir_index;
2680 const direntry_t* direntries;
2681 long_file_name lfn;
bellardde167e42005-04-28 21:15:08 +00002682
bellarda0464332005-12-18 18:29:50 +00002683 lfn_init(&lfn);
bellardde167e42005-04-28 21:15:08 +00002684
bellarda0464332005-12-18 18:29:50 +00002685 if (begin < sector_num)
2686 begin = sector_num;
2687 if (end > sector_num + nb_sectors)
2688 end = sector_num + nb_sectors;
ths5fafdf22007-09-16 21:08:06 +00002689 dir_index = mapping->dir_index +
bellarda0464332005-12-18 18:29:50 +00002690 0x10 * (begin - mapping->begin * s->sectors_per_cluster);
2691 direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
bellardde167e42005-04-28 21:15:08 +00002692
bellarda0464332005-12-18 18:29:50 +00002693 for (k = 0; k < (end - begin) * 0x10; k++) {
2694 /* do not allow non-ASCII filenames */
2695 if (parse_long_name(&lfn, direntries + k) < 0) {
2696 fprintf(stderr, "Warning: non-ASCII filename\n");
2697 return -1;
bellardde167e42005-04-28 21:15:08 +00002698 }
bellarda0464332005-12-18 18:29:50 +00002699 /* no access to the direntry of a read-only file */
2700 else if (is_short_name(direntries+k) &&
2701 (direntries[k].attributes & 1)) {
2702 if (memcmp(direntries + k,
2703 array_get(&(s->directory), dir_index + k),
2704 sizeof(direntry_t))) {
2705 fprintf(stderr, "Warning: tried to write to write-protected file\n");
2706 return -1;
bellardde167e42005-04-28 21:15:08 +00002707 }
bellardde167e42005-04-28 21:15:08 +00002708 }
2709 }
2710 }
bellarda0464332005-12-18 18:29:50 +00002711 i = mapping->end;
2712 } else
2713 i++;
bellardde167e42005-04-28 21:15:08 +00002714 }
bellarda0464332005-12-18 18:29:50 +00002715
2716 /*
2717 * Use qcow backend. Commit later.
2718 */
2719DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
2720 ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
2721 if (ret < 0) {
2722 fprintf(stderr, "Error writing to qcow backend\n");
2723 return ret;
2724 }
2725
2726 for (i = sector2cluster(s, sector_num);
2727 i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
2728 if (i >= 0)
2729 s->used_clusters[i] |= USED_ALLOCATED;
2730
2731DLOG(checkpoint());
2732 /* TODO: add timeout */
2733 try_commit(s);
2734
2735DLOG(checkpoint());
2736 return 0;
2737}
2738
2739static int vvfat_is_allocated(BlockDriverState *bs,
2740 int64_t sector_num, int nb_sectors, int* n)
2741{
2742 BDRVVVFATState* s = bs->opaque;
2743 *n = s->sector_count - sector_num;
2744 if (*n > nb_sectors)
2745 *n = nb_sectors;
2746 else if (*n < 0)
2747 return 0;
ths5fafdf22007-09-16 21:08:06 +00002748 return 1;
bellarda0464332005-12-18 18:29:50 +00002749}
2750
2751static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
2752 const uint8_t* buffer, int nb_sectors) {
2753 BDRVVVFATState* s = bs->opaque;
2754 return try_commit(s);
2755}
2756
2757static void write_target_close(BlockDriverState *bs) {
2758 BDRVVVFATState* s = bs->opaque;
2759 bdrv_delete(s->qcow);
2760 free(s->qcow_filename);
2761}
2762
2763static BlockDriver vvfat_write_target = {
2764 "vvfat_write_target", 0, NULL, NULL, NULL,
2765 write_target_commit,
2766 write_target_close,
2767 NULL, NULL, NULL
2768};
2769
2770static int enable_write_target(BDRVVVFATState *s)
2771{
2772 int size = sector2cluster(s, s->sector_count);
2773 s->used_clusters = calloc(size, 1);
2774
2775 array_init(&(s->commits), sizeof(commit_t));
2776
2777 s->qcow_filename = malloc(1024);
bellard83f64092006-08-01 16:21:11 +00002778 get_tmp_filename(s->qcow_filename, 1024);
bellarda0464332005-12-18 18:29:50 +00002779 if (bdrv_create(&bdrv_qcow,
2780 s->qcow_filename, s->sector_count, "fat:", 0) < 0)
2781 return -1;
2782 s->qcow = bdrv_new("");
2783 if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
2784 return -1;
2785
2786#ifndef _WIN32
2787 unlink(s->qcow_filename);
2788#endif
2789
2790 s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
2791 s->bs->backing_hd->drv = &vvfat_write_target;
2792 s->bs->backing_hd->opaque = s;
2793
bellardde167e42005-04-28 21:15:08 +00002794 return 0;
2795}
2796
2797static void vvfat_close(BlockDriverState *bs)
2798{
2799 BDRVVVFATState *s = bs->opaque;
2800
2801 vvfat_close_current_file(s);
2802 array_free(&(s->fat));
2803 array_free(&(s->directory));
2804 array_free(&(s->mapping));
bellarda0464332005-12-18 18:29:50 +00002805 if(s->cluster_buffer)
2806 free(s->cluster_buffer);
bellardde167e42005-04-28 21:15:08 +00002807}
2808
2809BlockDriver bdrv_vvfat = {
2810 "vvfat",
2811 sizeof(BDRVVVFATState),
bellard83f64092006-08-01 16:21:11 +00002812 NULL, /* no probe for protocols */
bellardde167e42005-04-28 21:15:08 +00002813 vvfat_open,
2814 vvfat_read,
2815 vvfat_write,
2816 vvfat_close,
pbrook7a6cba62006-06-04 11:39:07 +00002817 NULL, /* ??? Not sure if we can do any meaningful flushing. */
bellarda0464332005-12-18 18:29:50 +00002818 NULL,
bellard83f64092006-08-01 16:21:11 +00002819 vvfat_is_allocated,
2820 .protocol_name = "fat",
bellardde167e42005-04-28 21:15:08 +00002821};
2822
bellarda0464332005-12-18 18:29:50 +00002823#ifdef DEBUG
blueswir13f47aa82008-03-09 06:59:01 +00002824static void checkpoint(void) {
bellarda0464332005-12-18 18:29:50 +00002825 assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
2826 check1(vvv);
2827 check2(vvv);
2828 assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
2829#if 0
2830 if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
2831 fprintf(stderr, "Nonono!\n");
2832 mapping_t* mapping;
2833 direntry_t* direntry;
2834 assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
2835 assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
2836 if (vvv->mapping.next<47)
2837 return;
2838 assert((mapping = array_get(&(vvv->mapping), 47)));
2839 assert(mapping->dir_index < vvv->directory.next);
2840 direntry = array_get(&(vvv->directory), mapping->dir_index);
2841 assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0);
2842#endif
2843 return;
2844 /* avoid compiler warnings: */
2845 hexdump(NULL, 100);
2846 remove_mapping(vvv, NULL);
2847 print_mapping(NULL);
2848 print_direntry(NULL);
2849}
2850#endif
bellardde167e42005-04-28 21:15:08 +00002851