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