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