blob: 731e591ec197c9d27ac8d55a7d393beeacdb9f64 [file] [log] [blame]
Kevin Wolf7ad9be62013-04-12 19:42:04 +02001/* vim:set shiftwidth=4 ts=4: */
bellardde167e42005-04-28 21:15:08 +00002/*
3 * QEMU Block driver for virtual VFAT (shadows a local directory)
ths5fafdf22007-09-16 21:08:06 +00004 *
bellarda0464332005-12-18 18:29:50 +00005 * Copyright (c) 2004,2005 Johannes E. Schindelin
ths5fafdf22007-09-16 21:08:06 +00006 *
bellardde167e42005-04-28 21:15:08 +00007 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25#include <sys/stat.h>
26#include <dirent.h>
pbrookfaf07962007-11-11 02:51:17 +000027#include "qemu-common.h"
Paolo Bonzini737e1502012-12-17 18:19:44 +010028#include "block/block_int.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010029#include "qemu/module.h"
Paolo Bonzinicaf71f82012-12-17 18:19:50 +010030#include "migration/migration.h"
Kevin Wolf7ad9be62013-04-12 19:42:04 +020031#include "qapi/qmp/qint.h"
32#include "qapi/qmp/qbool.h"
bellardde167e42005-04-28 21:15:08 +000033
bellarda0464332005-12-18 18:29:50 +000034#ifndef S_IWGRP
35#define S_IWGRP 0
36#endif
37#ifndef S_IWOTH
38#define S_IWOTH 0
39#endif
bellardde167e42005-04-28 21:15:08 +000040
bellarda0464332005-12-18 18:29:50 +000041/* TODO: add ":bootsector=blabla.img:" */
42/* LATER TODO: add automatic boot sector generation from
43 BOOTEASY.ASM and Ranish Partition Manager
ths5fafdf22007-09-16 21:08:06 +000044 Note that DOS assumes the system files to be the first files in the
bellarda0464332005-12-18 18:29:50 +000045 file system (test if the boot sector still relies on that fact)! */
46/* MAYBE TODO: write block-visofs.c */
47/* TODO: call try_commit() only after a timeout */
bellardde167e42005-04-28 21:15:08 +000048
bellarda0464332005-12-18 18:29:50 +000049/* #define DEBUG */
50
51#ifdef DEBUG
52
53#define DLOG(a) a
54
blueswir13f47aa82008-03-09 06:59:01 +000055static void checkpoint(void);
bellarda0464332005-12-18 18:29:50 +000056
57#ifdef __MINGW32__
58void nonono(const char* file, int line, const char* msg) {
59 fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg);
60 exit(-5);
61}
62#undef assert
bellard6bcb76c2006-09-09 12:03:20 +000063#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
bellarda0464332005-12-18 18:29:50 +000064#endif
65
66#else
67
68#define DLOG(a)
69
70#endif
bellardde167e42005-04-28 21:15:08 +000071
72/* dynamic array functions */
Anthony Liguoric227f092009-10-01 16:12:16 -050073typedef struct array_t {
bellardde167e42005-04-28 21:15:08 +000074 char* pointer;
75 unsigned int size,next,item_size;
Anthony Liguoric227f092009-10-01 16:12:16 -050076} array_t;
bellardde167e42005-04-28 21:15:08 +000077
Anthony Liguoric227f092009-10-01 16:12:16 -050078static inline void array_init(array_t* array,unsigned int item_size)
bellardde167e42005-04-28 21:15:08 +000079{
blueswir1511d2b12009-03-07 15:32:56 +000080 array->pointer = NULL;
bellardde167e42005-04-28 21:15:08 +000081 array->size=0;
82 array->next=0;
83 array->item_size=item_size;
84}
85
Anthony Liguoric227f092009-10-01 16:12:16 -050086static inline void array_free(array_t* array)
bellardde167e42005-04-28 21:15:08 +000087{
Stefan Weilce137822011-09-30 23:29:53 +020088 g_free(array->pointer);
bellardde167e42005-04-28 21:15:08 +000089 array->size=array->next=0;
90}
91
bellarda0464332005-12-18 18:29:50 +000092/* does not automatically grow */
Anthony Liguoric227f092009-10-01 16:12:16 -050093static inline void* array_get(array_t* array,unsigned int index) {
bellarda0464332005-12-18 18:29:50 +000094 assert(index < array->next);
95 return array->pointer + index * array->item_size;
96}
97
Anthony Liguoric227f092009-10-01 16:12:16 -050098static inline int array_ensure_allocated(array_t* array, int index)
bellarda0464332005-12-18 18:29:50 +000099{
100 if((index + 1) * array->item_size > array->size) {
101 int new_size = (index + 32) * array->item_size;
Anthony Liguori7267c092011-08-20 22:09:37 -0500102 array->pointer = g_realloc(array->pointer, new_size);
bellarda0464332005-12-18 18:29:50 +0000103 if (!array->pointer)
104 return -1;
105 array->size = new_size;
106 array->next = index + 1;
bellardde167e42005-04-28 21:15:08 +0000107 }
bellarda0464332005-12-18 18:29:50 +0000108
109 return 0;
bellardde167e42005-04-28 21:15:08 +0000110}
111
Anthony Liguoric227f092009-10-01 16:12:16 -0500112static inline void* array_get_next(array_t* array) {
bellarda0464332005-12-18 18:29:50 +0000113 unsigned int next = array->next;
114 void* result;
115
116 if (array_ensure_allocated(array, next) < 0)
117 return NULL;
118
119 array->next = next + 1;
120 result = array_get(array, next);
121
bellardde167e42005-04-28 21:15:08 +0000122 return result;
123}
124
Anthony Liguoric227f092009-10-01 16:12:16 -0500125static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
bellardde167e42005-04-28 21:15:08 +0000126 if((array->next+count)*array->item_size>array->size) {
127 int increment=count*array->item_size;
Anthony Liguori7267c092011-08-20 22:09:37 -0500128 array->pointer=g_realloc(array->pointer,array->size+increment);
bellardde167e42005-04-28 21:15:08 +0000129 if(!array->pointer)
blueswir1511d2b12009-03-07 15:32:56 +0000130 return NULL;
bellardde167e42005-04-28 21:15:08 +0000131 array->size+=increment;
132 }
133 memmove(array->pointer+(index+count)*array->item_size,
134 array->pointer+index*array->item_size,
135 (array->next-index)*array->item_size);
136 array->next+=count;
137 return array->pointer+index*array->item_size;
138}
139
140/* this performs a "roll", so that the element which was at index_from becomes
141 * index_to, but the order of all other elements is preserved. */
Anthony Liguoric227f092009-10-01 16:12:16 -0500142static inline int array_roll(array_t* array,int index_to,int index_from,int count)
bellardde167e42005-04-28 21:15:08 +0000143{
144 char* buf;
145 char* from;
146 char* to;
147 int is;
148
149 if(!array ||
150 index_to<0 || index_to>=array->next ||
151 index_from<0 || index_from>=array->next)
152 return -1;
ths3b46e622007-09-17 08:09:54 +0000153
bellardde167e42005-04-28 21:15:08 +0000154 if(index_to==index_from)
155 return 0;
156
157 is=array->item_size;
158 from=array->pointer+index_from*is;
159 to=array->pointer+index_to*is;
Anthony Liguori7267c092011-08-20 22:09:37 -0500160 buf=g_malloc(is*count);
bellardde167e42005-04-28 21:15:08 +0000161 memcpy(buf,from,is*count);
162
163 if(index_to<index_from)
164 memmove(to+is*count,to,from-to);
165 else
166 memmove(from,from+is*count,to-from);
ths3b46e622007-09-17 08:09:54 +0000167
bellardde167e42005-04-28 21:15:08 +0000168 memcpy(to,buf,is*count);
169
Stefan Weilce137822011-09-30 23:29:53 +0200170 g_free(buf);
bellardde167e42005-04-28 21:15:08 +0000171
172 return 0;
173}
174
Anthony Liguoric227f092009-10-01 16:12:16 -0500175static inline int array_remove_slice(array_t* array,int index, int count)
bellarda0464332005-12-18 18:29:50 +0000176{
177 assert(index >=0);
178 assert(count > 0);
179 assert(index + count <= array->next);
180 if(array_roll(array,array->next-1,index,count))
181 return -1;
182 array->next -= count;
183 return 0;
184}
185
Anthony Liguoric227f092009-10-01 16:12:16 -0500186static int array_remove(array_t* array,int index)
bellardde167e42005-04-28 21:15:08 +0000187{
bellarda0464332005-12-18 18:29:50 +0000188 return array_remove_slice(array, index, 1);
189}
190
191/* return the index for a given member */
Anthony Liguoric227f092009-10-01 16:12:16 -0500192static int array_index(array_t* array, void* pointer)
bellarda0464332005-12-18 18:29:50 +0000193{
194 size_t offset = (char*)pointer - array->pointer;
bellarda0464332005-12-18 18:29:50 +0000195 assert((offset % array->item_size) == 0);
196 assert(offset/array->item_size < array->next);
197 return offset/array->item_size;
bellardde167e42005-04-28 21:15:08 +0000198}
199
200/* These structures are used to fake a disk and the VFAT filesystem.
Stefan Weil541dc0d2011-08-31 12:38:01 +0200201 * For this reason we need to use QEMU_PACKED. */
bellardde167e42005-04-28 21:15:08 +0000202
Anthony Liguoric227f092009-10-01 16:12:16 -0500203typedef struct bootsector_t {
bellardde167e42005-04-28 21:15:08 +0000204 uint8_t jump[3];
205 uint8_t name[8];
206 uint16_t sector_size;
207 uint8_t sectors_per_cluster;
208 uint16_t reserved_sectors;
209 uint8_t number_of_fats;
210 uint16_t root_entries;
bellarda0464332005-12-18 18:29:50 +0000211 uint16_t total_sectors16;
bellardde167e42005-04-28 21:15:08 +0000212 uint8_t media_type;
213 uint16_t sectors_per_fat;
214 uint16_t sectors_per_track;
215 uint16_t number_of_heads;
216 uint32_t hidden_sectors;
217 uint32_t total_sectors;
218 union {
219 struct {
220 uint8_t drive_number;
221 uint8_t current_head;
222 uint8_t signature;
223 uint32_t id;
224 uint8_t volume_label[11];
Stefan Weil541dc0d2011-08-31 12:38:01 +0200225 } QEMU_PACKED fat16;
bellardde167e42005-04-28 21:15:08 +0000226 struct {
227 uint32_t sectors_per_fat;
228 uint16_t flags;
229 uint8_t major,minor;
230 uint32_t first_cluster_of_root_directory;
231 uint16_t info_sector;
232 uint16_t backup_boot_sector;
233 uint16_t ignored;
Stefan Weil541dc0d2011-08-31 12:38:01 +0200234 } QEMU_PACKED fat32;
bellardde167e42005-04-28 21:15:08 +0000235 } u;
236 uint8_t fat_type[8];
237 uint8_t ignored[0x1c0];
238 uint8_t magic[2];
Stefan Weil541dc0d2011-08-31 12:38:01 +0200239} QEMU_PACKED bootsector_t;
bellardde167e42005-04-28 21:15:08 +0000240
thsb5700942007-09-25 14:47:03 +0000241typedef struct {
242 uint8_t head;
243 uint8_t sector;
244 uint8_t cylinder;
Anthony Liguoric227f092009-10-01 16:12:16 -0500245} mbr_chs_t;
thsb5700942007-09-25 14:47:03 +0000246
Anthony Liguoric227f092009-10-01 16:12:16 -0500247typedef struct partition_t {
bellardde167e42005-04-28 21:15:08 +0000248 uint8_t attributes; /* 0x80 = bootable */
Anthony Liguoric227f092009-10-01 16:12:16 -0500249 mbr_chs_t start_CHS;
thsb5700942007-09-25 14:47:03 +0000250 uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
Anthony Liguoric227f092009-10-01 16:12:16 -0500251 mbr_chs_t end_CHS;
bellardde167e42005-04-28 21:15:08 +0000252 uint32_t start_sector_long;
thsb5700942007-09-25 14:47:03 +0000253 uint32_t length_sector_long;
Stefan Weil541dc0d2011-08-31 12:38:01 +0200254} QEMU_PACKED partition_t;
bellardde167e42005-04-28 21:15:08 +0000255
Anthony Liguoric227f092009-10-01 16:12:16 -0500256typedef struct mbr_t {
thsb5700942007-09-25 14:47:03 +0000257 uint8_t ignored[0x1b8];
258 uint32_t nt_id;
259 uint8_t ignored2[2];
Anthony Liguoric227f092009-10-01 16:12:16 -0500260 partition_t partition[4];
bellardde167e42005-04-28 21:15:08 +0000261 uint8_t magic[2];
Stefan Weil541dc0d2011-08-31 12:38:01 +0200262} QEMU_PACKED mbr_t;
bellardde167e42005-04-28 21:15:08 +0000263
Anthony Liguoric227f092009-10-01 16:12:16 -0500264typedef struct direntry_t {
Stefan Weilf671d172013-12-11 21:37:11 +0100265 uint8_t name[8 + 3];
bellardde167e42005-04-28 21:15:08 +0000266 uint8_t attributes;
267 uint8_t reserved[2];
268 uint16_t ctime;
269 uint16_t cdate;
270 uint16_t adate;
271 uint16_t begin_hi;
272 uint16_t mtime;
273 uint16_t mdate;
274 uint16_t begin;
275 uint32_t size;
Stefan Weil541dc0d2011-08-31 12:38:01 +0200276} QEMU_PACKED direntry_t;
bellardde167e42005-04-28 21:15:08 +0000277
278/* this structure are used to transparently access the files */
279
Anthony Liguoric227f092009-10-01 16:12:16 -0500280typedef struct mapping_t {
bellarda0464332005-12-18 18:29:50 +0000281 /* begin is the first cluster, end is the last+1 */
282 uint32_t begin,end;
bellardde167e42005-04-28 21:15:08 +0000283 /* as s->directory is growable, no pointer may be used here */
284 unsigned int dir_index;
bellarda0464332005-12-18 18:29:50 +0000285 /* the clusters of a file may be in any order; this points to the first */
286 int first_mapping_index;
287 union {
288 /* offset is
289 * - the offset in the file (in clusters) for a file, or
290 * - the next cluster of the directory for a directory, and
291 * - the address of the buffer for a faked entry
292 */
293 struct {
294 uint32_t offset;
295 } file;
296 struct {
297 int parent_mapping_index;
298 int first_dir_index;
299 } dir;
300 } info;
301 /* path contains the full path, i.e. it always starts with s->path */
302 char* path;
303
304 enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2,
305 MODE_DIRECTORY = 4, MODE_FAKED = 8,
306 MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
307 int read_only;
Anthony Liguoric227f092009-10-01 16:12:16 -0500308} mapping_t;
bellardde167e42005-04-28 21:15:08 +0000309
bellarda0464332005-12-18 18:29:50 +0000310#ifdef DEBUG
Anthony Liguoric227f092009-10-01 16:12:16 -0500311static void print_direntry(const struct direntry_t*);
312static void print_mapping(const struct mapping_t* mapping);
bellarda0464332005-12-18 18:29:50 +0000313#endif
bellardde167e42005-04-28 21:15:08 +0000314
315/* here begins the real VVFAT driver */
316
317typedef struct BDRVVVFATState {
Paolo Bonzini848c66e2011-10-20 13:16:21 +0200318 CoMutex lock;
bellarda0464332005-12-18 18:29:50 +0000319 BlockDriverState* bs; /* pointer to parent */
bellardde167e42005-04-28 21:15:08 +0000320 unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
321 unsigned char first_sectors[0x40*0x200];
ths3b46e622007-09-17 08:09:54 +0000322
bellardde167e42005-04-28 21:15:08 +0000323 int fat_type; /* 16 or 32 */
Anthony Liguoric227f092009-10-01 16:12:16 -0500324 array_t fat,directory,mapping;
ths3b46e622007-09-17 08:09:54 +0000325
bellardde167e42005-04-28 21:15:08 +0000326 unsigned int cluster_size;
327 unsigned int sectors_per_cluster;
328 unsigned int sectors_per_fat;
329 unsigned int sectors_of_root_directory;
bellarda0464332005-12-18 18:29:50 +0000330 uint32_t last_cluster_of_root_directory;
bellardde167e42005-04-28 21:15:08 +0000331 unsigned int faked_sectors; /* how many sectors are faked before file data */
332 uint32_t sector_count; /* total number of sectors of the partition */
333 uint32_t cluster_count; /* total number of clusters of this partition */
bellardde167e42005-04-28 21:15:08 +0000334 uint32_t max_fat_value;
ths3b46e622007-09-17 08:09:54 +0000335
bellardde167e42005-04-28 21:15:08 +0000336 int current_fd;
Anthony Liguoric227f092009-10-01 16:12:16 -0500337 mapping_t* current_mapping;
bellarda0464332005-12-18 18:29:50 +0000338 unsigned char* cluster; /* points to current cluster */
339 unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
bellardde167e42005-04-28 21:15:08 +0000340 unsigned int current_cluster;
341
342 /* write support */
bellarda0464332005-12-18 18:29:50 +0000343 BlockDriverState* write_target;
344 char* qcow_filename;
345 BlockDriverState* qcow;
346 void* fat2;
347 char* used_clusters;
Anthony Liguoric227f092009-10-01 16:12:16 -0500348 array_t commits;
bellarda0464332005-12-18 18:29:50 +0000349 const char* path;
350 int downcase_short_names;
Kevin Wolf3397f0c2011-11-22 16:52:13 +0100351
352 Error *migration_blocker;
bellardde167e42005-04-28 21:15:08 +0000353} BDRVVVFATState;
354
thsb5700942007-09-25 14:47:03 +0000355/* take the sector position spos and convert it to Cylinder/Head/Sector position
356 * if the position is outside the specified geometry, fill maximum value for CHS
357 * and return 1 to signal overflow.
358 */
Markus Armbruster4480e0f2012-07-10 11:12:29 +0200359static int sector2CHS(mbr_chs_t *chs, int spos, int cyls, int heads, int secs)
360{
thsb5700942007-09-25 14:47:03 +0000361 int head,sector;
Markus Armbruster4480e0f2012-07-10 11:12:29 +0200362 sector = spos % secs; spos /= secs;
363 head = spos % heads; spos /= heads;
364 if (spos >= cyls) {
thsb5700942007-09-25 14:47:03 +0000365 /* Overflow,
366 it happens if 32bit sector positions are used, while CHS is only 24bit.
367 Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
368 chs->head = 0xFF;
369 chs->sector = 0xFF;
370 chs->cylinder = 0xFF;
371 return 1;
372 }
373 chs->head = (uint8_t)head;
374 chs->sector = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
375 chs->cylinder = (uint8_t)spos;
376 return 0;
377}
bellardde167e42005-04-28 21:15:08 +0000378
Markus Armbruster4480e0f2012-07-10 11:12:29 +0200379static void init_mbr(BDRVVVFATState *s, int cyls, int heads, int secs)
bellardde167e42005-04-28 21:15:08 +0000380{
381 /* TODO: if the files mbr.img and bootsect.img exist, use them */
Anthony Liguoric227f092009-10-01 16:12:16 -0500382 mbr_t* real_mbr=(mbr_t*)s->first_sectors;
383 partition_t* partition = &(real_mbr->partition[0]);
thsb5700942007-09-25 14:47:03 +0000384 int lba;
bellardde167e42005-04-28 21:15:08 +0000385
386 memset(s->first_sectors,0,512);
ths3b46e622007-09-17 08:09:54 +0000387
thsb5700942007-09-25 14:47:03 +0000388 /* Win NT Disk Signature */
389 real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
390
bellardde167e42005-04-28 21:15:08 +0000391 partition->attributes=0x80; /* bootable */
thsb5700942007-09-25 14:47:03 +0000392
393 /* LBA is used when partition is outside the CHS geometry */
Markus Armbruster4480e0f2012-07-10 11:12:29 +0200394 lba = sector2CHS(&partition->start_CHS, s->first_sectors_number - 1,
395 cyls, heads, secs);
396 lba |= sector2CHS(&partition->end_CHS, s->bs->total_sectors - 1,
397 cyls, heads, secs);
thsb5700942007-09-25 14:47:03 +0000398
399 /*LBA partitions are identified only by start/length_sector_long not by CHS*/
Markus Armbrusterf91cbef2012-07-10 11:12:28 +0200400 partition->start_sector_long = cpu_to_le32(s->first_sectors_number - 1);
401 partition->length_sector_long = cpu_to_le32(s->bs->total_sectors
402 - s->first_sectors_number + 1);
thsb5700942007-09-25 14:47:03 +0000403
bellarda0464332005-12-18 18:29:50 +0000404 /* FAT12/FAT16/FAT32 */
thsb5700942007-09-25 14:47:03 +0000405 /* DOS uses different types when partition is LBA,
406 probably to prevent older versions from using CHS on them */
407 partition->fs_type= s->fat_type==12 ? 0x1:
408 s->fat_type==16 ? (lba?0xe:0x06):
409 /*fat_tyoe==32*/ (lba?0xc:0x0b);
bellardde167e42005-04-28 21:15:08 +0000410
411 real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
412}
413
bellarda0464332005-12-18 18:29:50 +0000414/* direntry functions */
415
bellardde167e42005-04-28 21:15:08 +0000416/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
ths60fe76f2007-12-16 03:02:09 +0000417static inline int short2long_name(char* dest,const char* src)
bellardde167e42005-04-28 21:15:08 +0000418{
419 int i;
balrog1e080d52007-12-24 13:26:04 +0000420 int len;
bellardde167e42005-04-28 21:15:08 +0000421 for(i=0;i<129 && src[i];i++) {
422 dest[2*i]=src[i];
423 dest[2*i+1]=0;
424 }
balrog1e080d52007-12-24 13:26:04 +0000425 len=2*i;
bellardde167e42005-04-28 21:15:08 +0000426 dest[2*i]=dest[2*i+1]=0;
427 for(i=2*i+2;(i%26);i++)
428 dest[i]=0xff;
balrog1e080d52007-12-24 13:26:04 +0000429 return len;
bellardde167e42005-04-28 21:15:08 +0000430}
431
Anthony Liguoric227f092009-10-01 16:12:16 -0500432static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
bellardde167e42005-04-28 21:15:08 +0000433{
434 char buffer[258];
435 int length=short2long_name(buffer,filename),
436 number_of_entries=(length+25)/26,i;
Anthony Liguoric227f092009-10-01 16:12:16 -0500437 direntry_t* entry;
bellardde167e42005-04-28 21:15:08 +0000438
439 for(i=0;i<number_of_entries;i++) {
440 entry=array_get_next(&(s->directory));
441 entry->attributes=0xf;
442 entry->reserved[0]=0;
443 entry->begin=0;
444 entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
445 }
balrog1e080d52007-12-24 13:26:04 +0000446 for(i=0;i<26*number_of_entries;i++) {
bellardde167e42005-04-28 21:15:08 +0000447 int offset=(i%26);
448 if(offset<10) offset=1+offset;
449 else if(offset<22) offset=14+offset-10;
450 else offset=28+offset-22;
451 entry=array_get(&(s->directory),s->directory.next-1-(i/26));
452 entry->name[offset]=buffer[i];
453 }
454 return array_get(&(s->directory),s->directory.next-number_of_entries);
455}
456
Anthony Liguoric227f092009-10-01 16:12:16 -0500457static char is_free(const direntry_t* direntry)
bellarda0464332005-12-18 18:29:50 +0000458{
thsad1a8972008-07-01 16:44:58 +0000459 return direntry->name[0]==0xe5 || direntry->name[0]==0x00;
bellarda0464332005-12-18 18:29:50 +0000460}
461
Anthony Liguoric227f092009-10-01 16:12:16 -0500462static char is_volume_label(const direntry_t* direntry)
bellarda0464332005-12-18 18:29:50 +0000463{
464 return direntry->attributes == 0x28;
465}
466
Anthony Liguoric227f092009-10-01 16:12:16 -0500467static char is_long_name(const direntry_t* direntry)
bellarda0464332005-12-18 18:29:50 +0000468{
469 return direntry->attributes == 0xf;
470}
471
Anthony Liguoric227f092009-10-01 16:12:16 -0500472static char is_short_name(const direntry_t* direntry)
bellarda0464332005-12-18 18:29:50 +0000473{
474 return !is_volume_label(direntry) && !is_long_name(direntry)
475 && !is_free(direntry);
476}
477
Anthony Liguoric227f092009-10-01 16:12:16 -0500478static char is_directory(const direntry_t* direntry)
bellarda0464332005-12-18 18:29:50 +0000479{
480 return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
481}
482
Anthony Liguoric227f092009-10-01 16:12:16 -0500483static inline char is_dot(const direntry_t* direntry)
bellarda0464332005-12-18 18:29:50 +0000484{
485 return is_short_name(direntry) && direntry->name[0] == '.';
486}
487
Anthony Liguoric227f092009-10-01 16:12:16 -0500488static char is_file(const direntry_t* direntry)
bellarda0464332005-12-18 18:29:50 +0000489{
490 return is_short_name(direntry) && !is_directory(direntry);
491}
492
Anthony Liguoric227f092009-10-01 16:12:16 -0500493static inline uint32_t begin_of_direntry(const direntry_t* direntry)
bellarda0464332005-12-18 18:29:50 +0000494{
495 return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
496}
497
Anthony Liguoric227f092009-10-01 16:12:16 -0500498static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
bellarda0464332005-12-18 18:29:50 +0000499{
500 return le32_to_cpu(direntry->size);
501}
502
Anthony Liguoric227f092009-10-01 16:12:16 -0500503static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
bellarda0464332005-12-18 18:29:50 +0000504{
505 direntry->begin = cpu_to_le16(begin & 0xffff);
506 direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
507}
508
bellardde167e42005-04-28 21:15:08 +0000509/* fat functions */
510
Anthony Liguoric227f092009-10-01 16:12:16 -0500511static inline uint8_t fat_chksum(const direntry_t* entry)
bellardde167e42005-04-28 21:15:08 +0000512{
513 uint8_t chksum=0;
514 int i;
515
Stefan Weilf671d172013-12-11 21:37:11 +0100516 for (i = 0; i < ARRAY_SIZE(entry->name); i++) {
517 chksum = (((chksum & 0xfe) >> 1) |
518 ((chksum & 0x01) ? 0x80 : 0)) + entry->name[i];
Aurelien Jarno5606c222009-04-25 00:08:05 +0200519 }
ths3b46e622007-09-17 08:09:54 +0000520
bellardde167e42005-04-28 21:15:08 +0000521 return chksum;
522}
523
524/* if return_time==0, this returns the fat_date, else the fat_time */
525static uint16_t fat_datetime(time_t time,int return_time) {
526 struct tm* t;
bellardde167e42005-04-28 21:15:08 +0000527 struct tm t1;
Michael S. Tsirkin6ab00ce2009-09-30 19:43:31 +0200528 t = &t1;
bellardde167e42005-04-28 21:15:08 +0000529 localtime_r(&time,t);
bellardde167e42005-04-28 21:15:08 +0000530 if(return_time)
531 return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
532 return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
533}
534
535static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
536{
bellarda0464332005-12-18 18:29:50 +0000537 if(s->fat_type==32) {
538 uint32_t* entry=array_get(&(s->fat),cluster);
539 *entry=cpu_to_le32(value);
bellardde167e42005-04-28 21:15:08 +0000540 } else if(s->fat_type==16) {
541 uint16_t* entry=array_get(&(s->fat),cluster);
542 *entry=cpu_to_le16(value&0xffff);
543 } else {
bellarda0464332005-12-18 18:29:50 +0000544 int offset = (cluster*3/2);
545 unsigned char* p = array_get(&(s->fat), offset);
546 switch (cluster&1) {
547 case 0:
548 p[0] = value&0xff;
549 p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
550 break;
551 case 1:
552 p[0] = (p[0]&0xf) | ((value&0xf)<<4);
553 p[1] = (value>>4);
554 break;
555 }
bellardde167e42005-04-28 21:15:08 +0000556 }
557}
558
559static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
560{
bellarda0464332005-12-18 18:29:50 +0000561 if(s->fat_type==32) {
562 uint32_t* entry=array_get(&(s->fat),cluster);
563 return le32_to_cpu(*entry);
bellardde167e42005-04-28 21:15:08 +0000564 } else if(s->fat_type==16) {
565 uint16_t* entry=array_get(&(s->fat),cluster);
566 return le16_to_cpu(*entry);
567 } else {
thsffe8ab82007-12-16 03:16:05 +0000568 const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
bellarda0464332005-12-18 18:29:50 +0000569 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
bellardde167e42005-04-28 21:15:08 +0000570 }
571}
572
573static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
574{
575 if(fat_entry>s->max_fat_value-8)
576 return -1;
577 return 0;
578}
579
580static inline void init_fat(BDRVVVFATState* s)
581{
bellarda0464332005-12-18 18:29:50 +0000582 if (s->fat_type == 12) {
583 array_init(&(s->fat),1);
584 array_ensure_allocated(&(s->fat),
585 s->sectors_per_fat * 0x200 * 3 / 2 - 1);
586 } else {
587 array_init(&(s->fat),(s->fat_type==32?4:2));
588 array_ensure_allocated(&(s->fat),
589 s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
590 }
bellardde167e42005-04-28 21:15:08 +0000591 memset(s->fat.pointer,0,s->fat.size);
ths3b46e622007-09-17 08:09:54 +0000592
bellardde167e42005-04-28 21:15:08 +0000593 switch(s->fat_type) {
594 case 12: s->max_fat_value=0xfff; break;
595 case 16: s->max_fat_value=0xffff; break;
bellarda0464332005-12-18 18:29:50 +0000596 case 32: s->max_fat_value=0x0fffffff; break;
bellardde167e42005-04-28 21:15:08 +0000597 default: s->max_fat_value=0; /* error... */
598 }
599
600}
601
bellarda0464332005-12-18 18:29:50 +0000602/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
603/* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
Anthony Liguoric227f092009-10-01 16:12:16 -0500604static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
bellarda0464332005-12-18 18:29:50 +0000605 unsigned int directory_start, const char* filename, int is_dot)
bellardde167e42005-04-28 21:15:08 +0000606{
bellarda0464332005-12-18 18:29:50 +0000607 int i,j,long_index=s->directory.next;
Anthony Liguoric227f092009-10-01 16:12:16 -0500608 direntry_t* entry = NULL;
609 direntry_t* entry_long = NULL;
bellardde167e42005-04-28 21:15:08 +0000610
611 if(is_dot) {
612 entry=array_get_next(&(s->directory));
Stefan Weilf671d172013-12-11 21:37:11 +0100613 memset(entry->name, 0x20, sizeof(entry->name));
bellardde167e42005-04-28 21:15:08 +0000614 memcpy(entry->name,filename,strlen(filename));
615 return entry;
616 }
ths3b46e622007-09-17 08:09:54 +0000617
bellardde167e42005-04-28 21:15:08 +0000618 entry_long=create_long_filename(s,filename);
ths3b46e622007-09-17 08:09:54 +0000619
ths5fafdf22007-09-16 21:08:06 +0000620 i = strlen(filename);
bellarda0464332005-12-18 18:29:50 +0000621 for(j = i - 1; j>0 && filename[j]!='.';j--);
622 if (j > 0)
623 i = (j > 8 ? 8 : j);
624 else if (i > 8)
625 i = 8;
626
bellardde167e42005-04-28 21:15:08 +0000627 entry=array_get_next(&(s->directory));
Stefan Weilf671d172013-12-11 21:37:11 +0100628 memset(entry->name, 0x20, sizeof(entry->name));
blueswir151a0f562008-10-26 10:22:11 +0000629 memcpy(entry->name, filename, i);
ths3b46e622007-09-17 08:09:54 +0000630
Stefan Weilf671d172013-12-11 21:37:11 +0100631 if (j > 0) {
632 for (i = 0; i < 3 && filename[j + 1 + i]; i++) {
633 entry->name[8 + i] = filename[j + 1 + i];
634 }
635 }
bellardde167e42005-04-28 21:15:08 +0000636
637 /* upcase & remove unwanted characters */
638 for(i=10;i>=0;i--) {
bellarda0464332005-12-18 18:29:50 +0000639 if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
bellardde167e42005-04-28 21:15:08 +0000640 if(entry->name[i]<=' ' || entry->name[i]>0x7f
bellarda0464332005-12-18 18:29:50 +0000641 || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
bellardde167e42005-04-28 21:15:08 +0000642 entry->name[i]='_';
643 else if(entry->name[i]>='a' && entry->name[i]<='z')
644 entry->name[i]+='A'-'a';
645 }
646
647 /* mangle duplicates */
648 while(1) {
Anthony Liguoric227f092009-10-01 16:12:16 -0500649 direntry_t* entry1=array_get(&(s->directory),directory_start);
bellardde167e42005-04-28 21:15:08 +0000650 int j;
651
652 for(;entry1<entry;entry1++)
bellarda0464332005-12-18 18:29:50 +0000653 if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
bellardde167e42005-04-28 21:15:08 +0000654 break; /* found dupe */
655 if(entry1==entry) /* no dupe found */
656 break;
657
ths5fafdf22007-09-16 21:08:06 +0000658 /* use all 8 characters of name */
bellardde167e42005-04-28 21:15:08 +0000659 if(entry->name[7]==' ') {
660 int j;
661 for(j=6;j>0 && entry->name[j]==' ';j--)
662 entry->name[j]='~';
663 }
664
665 /* increment number */
666 for(j=7;j>0 && entry->name[j]=='9';j--)
667 entry->name[j]='0';
668 if(j>0) {
669 if(entry->name[j]<'0' || entry->name[j]>'9')
670 entry->name[j]='0';
671 else
672 entry->name[j]++;
673 }
674 }
675
676 /* calculate checksum; propagate to long name */
677 if(entry_long) {
678 uint8_t chksum=fat_chksum(entry);
679
680 /* calculate anew, because realloc could have taken place */
681 entry_long=array_get(&(s->directory),long_index);
bellarda0464332005-12-18 18:29:50 +0000682 while(entry_long<entry && is_long_name(entry_long)) {
bellardde167e42005-04-28 21:15:08 +0000683 entry_long->reserved[1]=chksum;
684 entry_long++;
685 }
686 }
687
688 return entry;
689}
690
bellarda0464332005-12-18 18:29:50 +0000691/*
692 * Read a directory. (the index of the corresponding mapping must be passed).
693 */
694static int read_directory(BDRVVVFATState* s, int mapping_index)
bellardde167e42005-04-28 21:15:08 +0000695{
Anthony Liguoric227f092009-10-01 16:12:16 -0500696 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
697 direntry_t* direntry;
bellarda0464332005-12-18 18:29:50 +0000698 const char* dirname = mapping->path;
699 int first_cluster = mapping->begin;
700 int parent_index = mapping->info.dir.parent_mapping_index;
Anthony Liguoric227f092009-10-01 16:12:16 -0500701 mapping_t* parent_mapping = (mapping_t*)
blueswir1511d2b12009-03-07 15:32:56 +0000702 (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL);
bellarda0464332005-12-18 18:29:50 +0000703 int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
bellardde167e42005-04-28 21:15:08 +0000704
705 DIR* dir=opendir(dirname);
706 struct dirent* entry;
bellardde167e42005-04-28 21:15:08 +0000707 int i;
708
bellarda0464332005-12-18 18:29:50 +0000709 assert(mapping->mode & MODE_DIRECTORY);
710
711 if(!dir) {
712 mapping->end = mapping->begin;
bellardde167e42005-04-28 21:15:08 +0000713 return -1;
bellarda0464332005-12-18 18:29:50 +0000714 }
ths3b46e622007-09-17 08:09:54 +0000715
bellarda0464332005-12-18 18:29:50 +0000716 i = mapping->info.dir.first_dir_index =
717 first_cluster == 0 ? 0 : s->directory.next;
718
ths5fafdf22007-09-16 21:08:06 +0000719 /* actually read the directory, and allocate the mappings */
bellardde167e42005-04-28 21:15:08 +0000720 while((entry=readdir(dir))) {
721 unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
722 char* buffer;
Anthony Liguoric227f092009-10-01 16:12:16 -0500723 direntry_t* direntry;
bellarda0464332005-12-18 18:29:50 +0000724 struct stat st;
bellardde167e42005-04-28 21:15:08 +0000725 int is_dot=!strcmp(entry->d_name,".");
726 int is_dotdot=!strcmp(entry->d_name,"..");
727
bellarda0464332005-12-18 18:29:50 +0000728 if(first_cluster == 0 && (is_dotdot || is_dot))
bellardde167e42005-04-28 21:15:08 +0000729 continue;
ths5fafdf22007-09-16 21:08:06 +0000730
Markus Armbrusterd4df3db2014-08-19 10:31:11 +0200731 buffer = g_malloc(length);
bellardde167e42005-04-28 21:15:08 +0000732 snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
733
734 if(stat(buffer,&st)<0) {
Stefan Weilce137822011-09-30 23:29:53 +0200735 g_free(buffer);
bellardde167e42005-04-28 21:15:08 +0000736 continue;
737 }
738
739 /* create directory entry for this file */
bellarda0464332005-12-18 18:29:50 +0000740 direntry=create_short_and_long_name(s, i, entry->d_name,
741 is_dot || is_dotdot);
bellardde167e42005-04-28 21:15:08 +0000742 direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
743 direntry->reserved[0]=direntry->reserved[1]=0;
744 direntry->ctime=fat_datetime(st.st_ctime,1);
745 direntry->cdate=fat_datetime(st.st_ctime,0);
746 direntry->adate=fat_datetime(st.st_atime,0);
747 direntry->begin_hi=0;
748 direntry->mtime=fat_datetime(st.st_mtime,1);
749 direntry->mdate=fat_datetime(st.st_mtime,0);
750 if(is_dotdot)
bellarda0464332005-12-18 18:29:50 +0000751 set_begin_of_direntry(direntry, first_cluster_of_parent);
bellardde167e42005-04-28 21:15:08 +0000752 else if(is_dot)
bellarda0464332005-12-18 18:29:50 +0000753 set_begin_of_direntry(direntry, first_cluster);
bellardde167e42005-04-28 21:15:08 +0000754 else
bellarda0464332005-12-18 18:29:50 +0000755 direntry->begin=0; /* do that later */
756 if (st.st_size > 0x7fffffff) {
757 fprintf(stderr, "File %s is larger than 2GB\n", buffer);
Stefan Weilce137822011-09-30 23:29:53 +0200758 g_free(buffer);
Blue Swirl08089ed2011-01-12 19:48:58 +0000759 closedir(dir);
bellarda0464332005-12-18 18:29:50 +0000760 return -2;
761 }
762 direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
bellardde167e42005-04-28 21:15:08 +0000763
764 /* create mapping for this file */
bellarda0464332005-12-18 18:29:50 +0000765 if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
Markus Armbrusterd4df3db2014-08-19 10:31:11 +0200766 s->current_mapping = array_get_next(&(s->mapping));
bellardde167e42005-04-28 21:15:08 +0000767 s->current_mapping->begin=0;
768 s->current_mapping->end=st.st_size;
bellarda0464332005-12-18 18:29:50 +0000769 /*
770 * we get the direntry of the most recent direntry, which
771 * contains the short name and all the relevant information.
772 */
bellardde167e42005-04-28 21:15:08 +0000773 s->current_mapping->dir_index=s->directory.next-1;
bellarda0464332005-12-18 18:29:50 +0000774 s->current_mapping->first_mapping_index = -1;
775 if (S_ISDIR(st.st_mode)) {
776 s->current_mapping->mode = MODE_DIRECTORY;
777 s->current_mapping->info.dir.parent_mapping_index =
778 mapping_index;
779 } else {
780 s->current_mapping->mode = MODE_UNDEFINED;
781 s->current_mapping->info.file.offset = 0;
782 }
783 s->current_mapping->path=buffer;
784 s->current_mapping->read_only =
785 (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
Markus Armbrusterb122c3b2014-05-28 11:17:05 +0200786 } else {
787 g_free(buffer);
788 }
bellardde167e42005-04-28 21:15:08 +0000789 }
790 closedir(dir);
791
792 /* fill with zeroes up to the end of the cluster */
793 while(s->directory.next%(0x10*s->sectors_per_cluster)) {
Anthony Liguoric227f092009-10-01 16:12:16 -0500794 direntry_t* direntry=array_get_next(&(s->directory));
795 memset(direntry,0,sizeof(direntry_t));
bellardde167e42005-04-28 21:15:08 +0000796 }
797
bellarda0464332005-12-18 18:29:50 +0000798/* TODO: if there are more entries, bootsector has to be adjusted! */
799#define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
800 if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
801 /* root directory */
802 int cur = s->directory.next;
803 array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
Paolo Bonzini2b6a43a2011-10-05 09:12:03 +0200804 s->directory.next = ROOT_ENTRIES;
bellarda0464332005-12-18 18:29:50 +0000805 memset(array_get(&(s->directory), cur), 0,
Anthony Liguoric227f092009-10-01 16:12:16 -0500806 (ROOT_ENTRIES - cur) * sizeof(direntry_t));
bellardde167e42005-04-28 21:15:08 +0000807 }
ths5fafdf22007-09-16 21:08:06 +0000808
bellarda0464332005-12-18 18:29:50 +0000809 /* reget the mapping, since s->mapping was possibly realloc()ed */
Markus Armbrusterd4df3db2014-08-19 10:31:11 +0200810 mapping = array_get(&(s->mapping), mapping_index);
bellarda0464332005-12-18 18:29:50 +0000811 first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
812 * 0x20 / s->cluster_size;
813 mapping->end = first_cluster;
bellardde167e42005-04-28 21:15:08 +0000814
Markus Armbrusterd4df3db2014-08-19 10:31:11 +0200815 direntry = array_get(&(s->directory), mapping->dir_index);
bellarda0464332005-12-18 18:29:50 +0000816 set_begin_of_direntry(direntry, mapping->begin);
ths3b46e622007-09-17 08:09:54 +0000817
bellardde167e42005-04-28 21:15:08 +0000818 return 0;
819}
820
bellarda0464332005-12-18 18:29:50 +0000821static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
bellardde167e42005-04-28 21:15:08 +0000822{
bellarda0464332005-12-18 18:29:50 +0000823 return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
824}
825
826static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
827{
828 return s->faked_sectors + s->sectors_per_cluster * cluster_num;
829}
830
bellarda0464332005-12-18 18:29:50 +0000831static int init_directories(BDRVVVFATState* s,
Markus Armbrusterd11c8912014-05-16 11:00:18 +0200832 const char *dirname, int heads, int secs,
833 Error **errp)
bellarda0464332005-12-18 18:29:50 +0000834{
Anthony Liguoric227f092009-10-01 16:12:16 -0500835 bootsector_t* bootsector;
836 mapping_t* mapping;
bellardde167e42005-04-28 21:15:08 +0000837 unsigned int i;
838 unsigned int cluster;
839
840 memset(&(s->first_sectors[0]),0,0x40*0x200);
841
bellardde167e42005-04-28 21:15:08 +0000842 s->cluster_size=s->sectors_per_cluster*0x200;
Anthony Liguori7267c092011-08-20 22:09:37 -0500843 s->cluster_buffer=g_malloc(s->cluster_size);
bellarda0464332005-12-18 18:29:50 +0000844
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 */
ths3b46e622007-09-17 08:09:54 +0000854
Anthony Liguoric227f092009-10-01 16:12:16 -0500855 array_init(&(s->mapping),sizeof(mapping_t));
856 array_init(&(s->directory),sizeof(direntry_t));
bellardde167e42005-04-28 21:15:08 +0000857
858 /* add volume label */
859 {
Anthony Liguoric227f092009-10-01 16:12:16 -0500860 direntry_t* entry=array_get_next(&(s->directory));
bellardde167e42005-04-28 21:15:08 +0000861 entry->attributes=0x28; /* archive | volume label */
Stefan Weilf671d172013-12-11 21:37:11 +0100862 memcpy(entry->name, "QEMU VVFAT ", sizeof(entry->name));
bellardde167e42005-04-28 21:15:08 +0000863 }
864
bellardde167e42005-04-28 21:15:08 +0000865 /* Now build FAT, and write back information into directory */
866 init_fat(s);
867
bellarda0464332005-12-18 18:29:50 +0000868 s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
869 s->cluster_count=sector2cluster(s, s->sector_count);
bellardde167e42005-04-28 21:15:08 +0000870
bellarda0464332005-12-18 18:29:50 +0000871 mapping = array_get_next(&(s->mapping));
872 mapping->begin = 0;
873 mapping->dir_index = 0;
874 mapping->info.dir.parent_mapping_index = -1;
875 mapping->first_mapping_index = -1;
Anthony Liguori7267c092011-08-20 22:09:37 -0500876 mapping->path = g_strdup(dirname);
bellarda0464332005-12-18 18:29:50 +0000877 i = strlen(mapping->path);
878 if (i > 0 && mapping->path[i - 1] == '/')
879 mapping->path[i - 1] = '\0';
880 mapping->mode = MODE_DIRECTORY;
881 mapping->read_only = 0;
882 s->path = mapping->path;
bellardde167e42005-04-28 21:15:08 +0000883
bellarda0464332005-12-18 18:29:50 +0000884 for (i = 0, cluster = 0; i < s->mapping.next; i++) {
ths5fafdf22007-09-16 21:08:06 +0000885 /* MS-DOS expects the FAT to be 0 for the root directory
bellarda0464332005-12-18 18:29:50 +0000886 * (except for the media byte). */
887 /* LATER TODO: still true for FAT32? */
888 int fix_fat = (i != 0);
889 mapping = array_get(&(s->mapping), i);
bellardde167e42005-04-28 21:15:08 +0000890
bellarda0464332005-12-18 18:29:50 +0000891 if (mapping->mode & MODE_DIRECTORY) {
892 mapping->begin = cluster;
893 if(read_directory(s, i)) {
Markus Armbrusterd11c8912014-05-16 11:00:18 +0200894 error_setg(errp, "Could not read directory %s",
895 mapping->path);
bellardde167e42005-04-28 21:15:08 +0000896 return -1;
897 }
bellarda0464332005-12-18 18:29:50 +0000898 mapping = array_get(&(s->mapping), i);
899 } else {
900 assert(mapping->mode == MODE_UNDEFINED);
bellardde167e42005-04-28 21:15:08 +0000901 mapping->mode=MODE_NORMAL;
bellarda0464332005-12-18 18:29:50 +0000902 mapping->begin = cluster;
903 if (mapping->end > 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -0500904 direntry_t* direntry = array_get(&(s->directory),
bellarda0464332005-12-18 18:29:50 +0000905 mapping->dir_index);
bellardde167e42005-04-28 21:15:08 +0000906
bellarda0464332005-12-18 18:29:50 +0000907 mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
908 set_begin_of_direntry(direntry, mapping->begin);
909 } else {
910 mapping->end = cluster + 1;
911 fix_fat = 0;
912 }
913 }
914
915 assert(mapping->begin < mapping->end);
916
bellarda0464332005-12-18 18:29:50 +0000917 /* next free cluster */
918 cluster = mapping->end;
919
920 if(cluster > s->cluster_count) {
Markus Armbrusterd11c8912014-05-16 11:00:18 +0200921 error_setg(errp,
922 "Directory does not fit in FAT%d (capacity %.2f MB)",
923 s->fat_type, s->sector_count / 2000.0);
924 return -1;
balrog8ce0f862008-11-10 01:34:27 +0000925 }
926
927 /* fix fat for entry */
928 if (fix_fat) {
929 int j;
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);
bellardde167e42005-04-28 21:15:08 +0000933 }
934 }
935
bellarda0464332005-12-18 18:29:50 +0000936 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;
bellardde167e42005-04-28 21:15:08 +0000939
bellarda0464332005-12-18 18:29:50 +0000940 /* the FAT signature */
941 fat_set(s,0,s->max_fat_value);
942 fat_set(s,1,s->max_fat_value);
943
944 s->current_mapping = NULL;
945
Anthony Liguoric227f092009-10-01 16:12:16 -0500946 bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
bellardde167e42005-04-28 21:15:08 +0000947 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);
bellarda0464332005-12-18 18:29:50 +0000956 bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
Paolo Bonziniaad37c02011-10-05 09:12:05 +0200957 bootsector->media_type=(s->first_sectors_number>1?0xf8:0xf0); /* media descriptor (f8=hd, f0=3.5 fd)*/
bellarda0464332005-12-18 18:29:50 +0000958 s->fat.pointer[0] = bootsector->media_type;
bellardde167e42005-04-28 21:15:08 +0000959 bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
Markus Armbruster4480e0f2012-07-10 11:12:29 +0200960 bootsector->sectors_per_track = cpu_to_le16(secs);
961 bootsector->number_of_heads = cpu_to_le16(heads);
bellardde167e42005-04-28 21:15:08 +0000962 bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
bellarda0464332005-12-18 18:29:50 +0000963 bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
bellardde167e42005-04-28 21:15:08 +0000964
bellarda0464332005-12-18 18:29:50 +0000965 /* LATER TODO: if FAT32, this is wrong */
Paolo Bonziniaad37c02011-10-05 09:12:05 +0200966 bootsector->u.fat16.drive_number=s->first_sectors_number==1?0:0x80; /* fda=0, hda=0x80 */
bellardde167e42005-04-28 21:15:08 +0000967 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
bellard83f64092006-08-01 16:21:11 +0000978#ifdef DEBUG
bellarda0464332005-12-18 18:29:50 +0000979static BDRVVVFATState *vvv = NULL;
bellard83f64092006-08-01 16:21:11 +0000980#endif
bellarda0464332005-12-18 18:29:50 +0000981
Markus Armbruster68c70af2014-05-16 11:00:17 +0200982static int enable_write_target(BDRVVVFATState *s, Error **errp);
bellarda0464332005-12-18 18:29:50 +0000983static int is_consistent(BDRVVVFATState *s);
984
Paolo Bonzinie023b2e2012-05-08 16:51:41 +0200985static void vvfat_rebind(BlockDriverState *bs)
986{
987 BDRVVVFATState *s = bs->opaque;
988 s->bs = bs;
989}
990
Kevin Wolf7ad9be62013-04-12 19:42:04 +0200991static QemuOptsList runtime_opts = {
992 .name = "vvfat",
993 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
994 .desc = {
995 {
996 .name = "dir",
997 .type = QEMU_OPT_STRING,
998 .help = "Host directory to map to the vvfat device",
999 },
1000 {
1001 .name = "fat-type",
1002 .type = QEMU_OPT_NUMBER,
1003 .help = "FAT type (12, 16 or 32)",
1004 },
1005 {
1006 .name = "floppy",
1007 .type = QEMU_OPT_BOOL,
1008 .help = "Create a floppy rather than a hard disk image",
1009 },
1010 {
1011 .name = "rw",
1012 .type = QEMU_OPT_BOOL,
1013 .help = "Make the image writable",
1014 },
1015 { /* end of list */ }
1016 },
1017};
1018
1019static void vvfat_parse_filename(const char *filename, QDict *options,
1020 Error **errp)
1021{
1022 int fat_type = 0;
1023 bool floppy = false;
1024 bool rw = false;
1025 int i;
1026
1027 if (!strstart(filename, "fat:", NULL)) {
1028 error_setg(errp, "File name string must start with 'fat:'");
1029 return;
1030 }
1031
1032 /* Parse options */
1033 if (strstr(filename, ":32:")) {
1034 fat_type = 32;
1035 } else if (strstr(filename, ":16:")) {
1036 fat_type = 16;
1037 } else if (strstr(filename, ":12:")) {
1038 fat_type = 12;
1039 }
1040
1041 if (strstr(filename, ":floppy:")) {
1042 floppy = true;
1043 }
1044
1045 if (strstr(filename, ":rw:")) {
1046 rw = true;
1047 }
1048
1049 /* Get the directory name without options */
1050 i = strrchr(filename, ':') - filename;
1051 assert(i >= 3);
1052 if (filename[i - 2] == ':' && qemu_isalpha(filename[i - 1])) {
1053 /* workaround for DOS drive names */
1054 filename += i - 1;
1055 } else {
1056 filename += i + 1;
1057 }
1058
1059 /* Fill in the options QDict */
1060 qdict_put(options, "dir", qstring_from_str(filename));
1061 qdict_put(options, "fat-type", qint_from_int(fat_type));
1062 qdict_put(options, "floppy", qbool_from_int(floppy));
1063 qdict_put(options, "rw", qbool_from_int(rw));
1064}
1065
Max Reitz015a1032013-09-05 14:22:29 +02001066static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
1067 Error **errp)
bellardde167e42005-04-28 21:15:08 +00001068{
1069 BDRVVVFATState *s = bs->opaque;
Kevin Wolf7ad9be62013-04-12 19:42:04 +02001070 int cyls, heads, secs;
1071 bool floppy;
1072 const char *dirname;
1073 QemuOpts *opts;
1074 Error *local_err = NULL;
1075 int ret;
bellardde167e42005-04-28 21:15:08 +00001076
bellard83f64092006-08-01 16:21:11 +00001077#ifdef DEBUG
bellarda0464332005-12-18 18:29:50 +00001078 vvv = s;
bellard83f64092006-08-01 16:21:11 +00001079#endif
bellarda0464332005-12-18 18:29:50 +00001080
Peter Crosthwaite87ea75d2014-01-01 18:49:17 -08001081 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
Kevin Wolf7ad9be62013-04-12 19:42:04 +02001082 qemu_opts_absorb_qdict(opts, options, &local_err);
Markus Armbruster84d18f02014-01-30 15:07:28 +01001083 if (local_err) {
Paolo Bonzinic0f92b52014-02-17 14:44:01 +01001084 error_propagate(errp, local_err);
Kevin Wolf7ad9be62013-04-12 19:42:04 +02001085 ret = -EINVAL;
1086 goto fail;
1087 }
1088
1089 dirname = qemu_opt_get(opts, "dir");
1090 if (!dirname) {
Paolo Bonzinic0f92b52014-02-17 14:44:01 +01001091 error_setg(errp, "vvfat block driver requires a 'dir' option");
Kevin Wolf7ad9be62013-04-12 19:42:04 +02001092 ret = -EINVAL;
1093 goto fail;
1094 }
1095
1096 s->fat_type = qemu_opt_get_number(opts, "fat-type", 0);
1097 floppy = qemu_opt_get_bool(opts, "floppy", false);
1098
1099 if (floppy) {
1100 /* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */
1101 if (!s->fat_type) {
1102 s->fat_type = 12;
1103 secs = 36;
1104 s->sectors_per_cluster = 2;
1105 } else {
1106 secs = s->fat_type == 12 ? 18 : 36;
1107 s->sectors_per_cluster = 1;
1108 }
1109 s->first_sectors_number = 1;
1110 cyls = 80;
1111 heads = 2;
1112 } else {
1113 /* 32MB or 504MB disk*/
1114 if (!s->fat_type) {
1115 s->fat_type = 16;
1116 }
Markus Armbruster4c709662014-03-27 13:35:31 +01001117 s->first_sectors_number = 0x40;
Kevin Wolf7ad9be62013-04-12 19:42:04 +02001118 cyls = s->fat_type == 12 ? 64 : 1024;
1119 heads = 16;
1120 secs = 63;
1121 }
1122
1123 switch (s->fat_type) {
1124 case 32:
1125 fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. "
1126 "You are welcome to do so!\n");
1127 break;
1128 case 16:
1129 case 12:
1130 break;
1131 default:
Paolo Bonzinic0f92b52014-02-17 14:44:01 +01001132 error_setg(errp, "Valid FAT types are only 12, 16 and 32");
Kevin Wolf7ad9be62013-04-12 19:42:04 +02001133 ret = -EINVAL;
1134 goto fail;
1135 }
1136
1137
bellarda0464332005-12-18 18:29:50 +00001138 s->bs = bs;
1139
bellarda0464332005-12-18 18:29:50 +00001140 /* LATER TODO: if FAT32, adjust */
bellarda0464332005-12-18 18:29:50 +00001141 s->sectors_per_cluster=0x10;
bellardde167e42005-04-28 21:15:08 +00001142
1143 s->current_cluster=0xffffffff;
bellardde167e42005-04-28 21:15:08 +00001144
bellarda0464332005-12-18 18:29:50 +00001145 /* read only is the default for safety */
1146 bs->read_only = 1;
1147 s->qcow = s->write_target = NULL;
1148 s->qcow_filename = NULL;
1149 s->fat2 = NULL;
1150 s->downcase_short_names = 1;
ths3b46e622007-09-17 08:09:54 +00001151
Markus Armbruster4480e0f2012-07-10 11:12:29 +02001152 fprintf(stderr, "vvfat %s chs %d,%d,%d\n",
1153 dirname, cyls, heads, secs);
bellarda0464332005-12-18 18:29:50 +00001154
Markus Armbruster4480e0f2012-07-10 11:12:29 +02001155 s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
Paolo Bonzini5a742b52011-10-05 09:12:06 +02001156
Kevin Wolf7ad9be62013-04-12 19:42:04 +02001157 if (qemu_opt_get_bool(opts, "rw", false)) {
Markus Armbruster68c70af2014-05-16 11:00:17 +02001158 ret = enable_write_target(s, errp);
Fam Zheng78f27bd2013-07-17 17:57:37 +08001159 if (ret < 0) {
Kevin Wolf7ad9be62013-04-12 19:42:04 +02001160 goto fail;
1161 }
1162 bs->read_only = 0;
thsb5700942007-09-25 14:47:03 +00001163 }
1164
Markus Armbruster4480e0f2012-07-10 11:12:29 +02001165 bs->total_sectors = cyls * heads * secs;
thsb5700942007-09-25 14:47:03 +00001166
Markus Armbrusterd11c8912014-05-16 11:00:18 +02001167 if (init_directories(s, dirname, heads, secs, errp)) {
Kevin Wolf7ad9be62013-04-12 19:42:04 +02001168 ret = -EIO;
1169 goto fail;
Markus Armbruster4480e0f2012-07-10 11:12:29 +02001170 }
bellardde167e42005-04-28 21:15:08 +00001171
thsb5700942007-09-25 14:47:03 +00001172 s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
1173
Markus Armbruster4480e0f2012-07-10 11:12:29 +02001174 if (s->first_sectors_number == 0x40) {
1175 init_mbr(s, cyls, heads, secs);
Paolo Bonzini273e4e02011-11-04 17:21:53 +01001176 }
bellardde167e42005-04-28 21:15:08 +00001177
bellarda0464332005-12-18 18:29:50 +00001178 // assert(is_consistent(s));
Paolo Bonzini848c66e2011-10-20 13:16:21 +02001179 qemu_co_mutex_init(&s->lock);
Kevin Wolf3397f0c2011-11-22 16:52:13 +01001180
1181 /* Disable migration when vvfat is used rw */
1182 if (s->qcow) {
1183 error_set(&s->migration_blocker,
1184 QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
1185 "vvfat (rw)", bs->device_name, "live migration");
1186 migrate_add_blocker(s->migration_blocker);
1187 }
1188
Kevin Wolf7ad9be62013-04-12 19:42:04 +02001189 ret = 0;
1190fail:
1191 qemu_opts_del(opts);
1192 return ret;
bellardde167e42005-04-28 21:15:08 +00001193}
1194
1195static inline void vvfat_close_current_file(BDRVVVFATState *s)
1196{
1197 if(s->current_mapping) {
bellarda0464332005-12-18 18:29:50 +00001198 s->current_mapping = NULL;
1199 if (s->current_fd) {
Corey Bryant2e1e79d2012-08-14 16:43:46 -04001200 qemu_close(s->current_fd);
bellarda0464332005-12-18 18:29:50 +00001201 s->current_fd = 0;
1202 }
bellardde167e42005-04-28 21:15:08 +00001203 }
bellarda0464332005-12-18 18:29:50 +00001204 s->current_cluster = -1;
bellardde167e42005-04-28 21:15:08 +00001205}
1206
1207/* mappings between index1 and index2-1 are supposed to be ordered
1208 * return value is the index of the last mapping for which end>cluster_num
1209 */
1210static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1211{
bellardde167e42005-04-28 21:15:08 +00001212 while(1) {
Blue Swirl88bf7952010-04-25 15:27:14 +00001213 int index3;
Anthony Liguoric227f092009-10-01 16:12:16 -05001214 mapping_t* mapping;
bellardde167e42005-04-28 21:15:08 +00001215 index3=(index1+index2)/2;
1216 mapping=array_get(&(s->mapping),index3);
bellarda0464332005-12-18 18:29:50 +00001217 assert(mapping->begin < mapping->end);
1218 if(mapping->begin>=cluster_num) {
bellardde167e42005-04-28 21:15:08 +00001219 assert(index2!=index3 || index2==0);
1220 if(index2==index3)
bellarda0464332005-12-18 18:29:50 +00001221 return index1;
bellardde167e42005-04-28 21:15:08 +00001222 index2=index3;
1223 } else {
1224 if(index1==index3)
bellarda0464332005-12-18 18:29:50 +00001225 return mapping->end<=cluster_num ? index2 : index1;
bellardde167e42005-04-28 21:15:08 +00001226 index1=index3;
1227 }
1228 assert(index1<=index2);
bellarda0464332005-12-18 18:29:50 +00001229 DLOG(mapping=array_get(&(s->mapping),index1);
1230 assert(mapping->begin<=cluster_num);
ths5fafdf22007-09-16 21:08:06 +00001231 assert(index2 >= s->mapping.next ||
bellarda0464332005-12-18 18:29:50 +00001232 ((mapping = array_get(&(s->mapping),index2)) &&
1233 mapping->end>cluster_num)));
bellardde167e42005-04-28 21:15:08 +00001234 }
1235}
1236
Anthony Liguoric227f092009-10-01 16:12:16 -05001237static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
bellardde167e42005-04-28 21:15:08 +00001238{
1239 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
Anthony Liguoric227f092009-10-01 16:12:16 -05001240 mapping_t* mapping;
bellardde167e42005-04-28 21:15:08 +00001241 if(index>=s->mapping.next)
blueswir1511d2b12009-03-07 15:32:56 +00001242 return NULL;
bellardde167e42005-04-28 21:15:08 +00001243 mapping=array_get(&(s->mapping),index);
1244 if(mapping->begin>cluster_num)
blueswir1511d2b12009-03-07 15:32:56 +00001245 return NULL;
bellarda0464332005-12-18 18:29:50 +00001246 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
bellardde167e42005-04-28 21:15:08 +00001247 return mapping;
1248}
1249
Anthony Liguoric227f092009-10-01 16:12:16 -05001250static int open_file(BDRVVVFATState* s,mapping_t* mapping)
bellardde167e42005-04-28 21:15:08 +00001251{
1252 if(!mapping)
1253 return -1;
bellardde167e42005-04-28 21:15:08 +00001254 if(!s->current_mapping ||
bellarda0464332005-12-18 18:29:50 +00001255 strcmp(s->current_mapping->path,mapping->path)) {
bellardde167e42005-04-28 21:15:08 +00001256 /* open file */
Corey Bryant6165f4d2012-08-14 16:43:45 -04001257 int fd = qemu_open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
bellardde167e42005-04-28 21:15:08 +00001258 if(fd<0)
1259 return -1;
1260 vvfat_close_current_file(s);
1261 s->current_fd = fd;
bellardde167e42005-04-28 21:15:08 +00001262 s->current_mapping = mapping;
1263 }
1264 return 0;
1265}
1266
1267static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1268{
1269 if(s->current_cluster != cluster_num) {
1270 int result=0;
1271 off_t offset;
bellarda0464332005-12-18 18:29:50 +00001272 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
bellardde167e42005-04-28 21:15:08 +00001273 if(!s->current_mapping
1274 || s->current_mapping->begin>cluster_num
1275 || s->current_mapping->end<=cluster_num) {
1276 /* binary search of mappings for file */
Anthony Liguoric227f092009-10-01 16:12:16 -05001277 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
bellardde167e42005-04-28 21:15:08 +00001278
bellarda0464332005-12-18 18:29:50 +00001279 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1280
1281 if (mapping && mapping->mode & MODE_DIRECTORY) {
1282 vvfat_close_current_file(s);
1283 s->current_mapping = mapping;
1284read_cluster_directory:
1285 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
thsffe8ab82007-12-16 03:16:05 +00001286 s->cluster = (unsigned char*)s->directory.pointer+offset
bellarda0464332005-12-18 18:29:50 +00001287 + 0x20*s->current_mapping->info.dir.first_dir_index;
1288 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1289 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1290 s->current_cluster = cluster_num;
1291 return 0;
1292 }
1293
1294 if(open_file(s,mapping))
1295 return -2;
1296 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1297 goto read_cluster_directory;
1298
1299 assert(s->current_fd);
1300
1301 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
bellardde167e42005-04-28 21:15:08 +00001302 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1303 return -3;
bellarda0464332005-12-18 18:29:50 +00001304 s->cluster=s->cluster_buffer;
bellardde167e42005-04-28 21:15:08 +00001305 result=read(s->current_fd,s->cluster,s->cluster_size);
1306 if(result<0) {
1307 s->current_cluster = -1;
1308 return -1;
1309 }
1310 s->current_cluster = cluster_num;
1311 }
1312 return 0;
1313}
1314
bellarda0464332005-12-18 18:29:50 +00001315#ifdef DEBUG
Anthony Liguoric227f092009-10-01 16:12:16 -05001316static void print_direntry(const direntry_t* direntry)
bellarda0464332005-12-18 18:29:50 +00001317{
1318 int j = 0;
1319 char buffer[1024];
1320
Kevin Wolf3e89cb02010-05-20 10:34:50 +02001321 fprintf(stderr, "direntry %p: ", direntry);
bellarda0464332005-12-18 18:29:50 +00001322 if(!direntry)
1323 return;
1324 if(is_long_name(direntry)) {
1325 unsigned char* c=(unsigned char*)direntry;
1326 int i;
1327 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
blueswir13891b372008-12-14 09:30:41 +00001328#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
bellarda0464332005-12-18 18:29:50 +00001329 ADD_CHAR(c[i]);
1330 for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
1331 ADD_CHAR(c[i]);
1332 for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
1333 ADD_CHAR(c[i]);
1334 buffer[j] = 0;
1335 fprintf(stderr, "%s\n", buffer);
1336 } else {
1337 int i;
1338 for(i=0;i<11;i++)
1339 ADD_CHAR(direntry->name[i]);
1340 buffer[j] = 0;
1341 fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
1342 buffer,
1343 direntry->attributes,
1344 begin_of_direntry(direntry),le32_to_cpu(direntry->size));
1345 }
1346}
1347
Anthony Liguoric227f092009-10-01 16:12:16 -05001348static void print_mapping(const mapping_t* mapping)
bellarda0464332005-12-18 18:29:50 +00001349{
Kevin Wolf3e89cb02010-05-20 10:34:50 +02001350 fprintf(stderr, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1351 "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1352 mapping, mapping->begin, mapping->end, mapping->dir_index,
1353 mapping->first_mapping_index, mapping->path, mapping->mode);
1354
bellarda0464332005-12-18 18:29:50 +00001355 if (mapping->mode & MODE_DIRECTORY)
1356 fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
1357 else
1358 fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
1359}
1360#endif
1361
ths5fafdf22007-09-16 21:08:06 +00001362static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
bellardde167e42005-04-28 21:15:08 +00001363 uint8_t *buf, int nb_sectors)
1364{
1365 BDRVVVFATState *s = bs->opaque;
1366 int i;
1367
bellardde167e42005-04-28 21:15:08 +00001368 for(i=0;i<nb_sectors;i++,sector_num++) {
Paolo Bonzinie654bfe2011-10-05 09:12:04 +02001369 if (sector_num >= bs->total_sectors)
bellarda0464332005-12-18 18:29:50 +00001370 return -1;
1371 if (s->qcow) {
1372 int n;
Kevin Wolf7704df92011-11-08 10:50:12 +01001373 if (bdrv_is_allocated(s->qcow, sector_num, nb_sectors-i, &n)) {
bellarda0464332005-12-18 18:29:50 +00001374DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
Kevin Wolf7704df92011-11-08 10:50:12 +01001375 if (bdrv_read(s->qcow, sector_num, buf + i*0x200, n)) {
1376 return -1;
1377 }
1378 i += n - 1;
1379 sector_num += n - 1;
1380 continue;
1381 }
bellarda0464332005-12-18 18:29:50 +00001382DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
1383 }
bellardde167e42005-04-28 21:15:08 +00001384 if(sector_num<s->faked_sectors) {
bellarda0464332005-12-18 18:29:50 +00001385 if(sector_num<s->first_sectors_number)
1386 memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
1387 else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
1388 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
1389 else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
1390 memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
bellardde167e42005-04-28 21:15:08 +00001391 } else {
bellarda0464332005-12-18 18:29:50 +00001392 uint32_t sector=sector_num-s->faked_sectors,
1393 sector_offset_in_cluster=(sector%s->sectors_per_cluster),
1394 cluster_num=sector/s->sectors_per_cluster;
Paolo Bonzinie654bfe2011-10-05 09:12:04 +02001395 if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) {
bellarda0464332005-12-18 18:29:50 +00001396 /* LATER TODO: strict: return -1; */
1397 memset(buf+i*0x200,0,0x200);
1398 continue;
1399 }
1400 memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
1401 }
1402 }
1403 return 0;
1404}
1405
Paolo Bonzini2914caa2011-10-20 13:16:22 +02001406static coroutine_fn int vvfat_co_read(BlockDriverState *bs, int64_t sector_num,
1407 uint8_t *buf, int nb_sectors)
1408{
1409 int ret;
1410 BDRVVVFATState *s = bs->opaque;
1411 qemu_co_mutex_lock(&s->lock);
1412 ret = vvfat_read(bs, sector_num, buf, nb_sectors);
1413 qemu_co_mutex_unlock(&s->lock);
1414 return ret;
1415}
1416
bellarda0464332005-12-18 18:29:50 +00001417/* LATER TODO: statify all functions */
1418
1419/*
1420 * Idea of the write support (use snapshot):
1421 *
1422 * 1. check if all data is consistent, recording renames, modifications,
1423 * new files and directories (in s->commits).
1424 *
1425 * 2. if the data is not consistent, stop committing
1426 *
1427 * 3. handle renames, and create new files and directories (do not yet
1428 * write their contents)
1429 *
1430 * 4. walk the directories, fixing the mapping and direntries, and marking
1431 * the handled mappings as not deleted
1432 *
1433 * 5. commit the contents of the files
1434 *
1435 * 6. handle deleted files and directories
1436 *
1437 */
1438
Anthony Liguoric227f092009-10-01 16:12:16 -05001439typedef struct commit_t {
bellarda0464332005-12-18 18:29:50 +00001440 char* path;
1441 union {
1442 struct { uint32_t cluster; } rename;
1443 struct { int dir_index; uint32_t modified_offset; } writeout;
1444 struct { uint32_t first_cluster; } new_file;
1445 struct { uint32_t cluster; } mkdir;
1446 } param;
1447 /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
1448 enum {
1449 ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
1450 } action;
Anthony Liguoric227f092009-10-01 16:12:16 -05001451} commit_t;
bellarda0464332005-12-18 18:29:50 +00001452
1453static void clear_commits(BDRVVVFATState* s)
1454{
1455 int i;
1456DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
1457 for (i = 0; i < s->commits.next; i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05001458 commit_t* commit = array_get(&(s->commits), i);
bellarda0464332005-12-18 18:29:50 +00001459 assert(commit->path || commit->action == ACTION_WRITEOUT);
1460 if (commit->action != ACTION_WRITEOUT) {
1461 assert(commit->path);
Stefan Weilce137822011-09-30 23:29:53 +02001462 g_free(commit->path);
bellarda0464332005-12-18 18:29:50 +00001463 } else
1464 assert(commit->path == NULL);
1465 }
1466 s->commits.next = 0;
1467}
1468
1469static void schedule_rename(BDRVVVFATState* s,
1470 uint32_t cluster, char* new_path)
1471{
Anthony Liguoric227f092009-10-01 16:12:16 -05001472 commit_t* commit = array_get_next(&(s->commits));
bellarda0464332005-12-18 18:29:50 +00001473 commit->path = new_path;
1474 commit->param.rename.cluster = cluster;
1475 commit->action = ACTION_RENAME;
1476}
1477
1478static void schedule_writeout(BDRVVVFATState* s,
1479 int dir_index, uint32_t modified_offset)
1480{
Anthony Liguoric227f092009-10-01 16:12:16 -05001481 commit_t* commit = array_get_next(&(s->commits));
bellarda0464332005-12-18 18:29:50 +00001482 commit->path = NULL;
1483 commit->param.writeout.dir_index = dir_index;
1484 commit->param.writeout.modified_offset = modified_offset;
1485 commit->action = ACTION_WRITEOUT;
1486}
1487
1488static void schedule_new_file(BDRVVVFATState* s,
1489 char* path, uint32_t first_cluster)
1490{
Anthony Liguoric227f092009-10-01 16:12:16 -05001491 commit_t* commit = array_get_next(&(s->commits));
bellarda0464332005-12-18 18:29:50 +00001492 commit->path = path;
1493 commit->param.new_file.first_cluster = first_cluster;
1494 commit->action = ACTION_NEW_FILE;
1495}
1496
1497static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
1498{
Anthony Liguoric227f092009-10-01 16:12:16 -05001499 commit_t* commit = array_get_next(&(s->commits));
bellarda0464332005-12-18 18:29:50 +00001500 commit->path = path;
1501 commit->param.mkdir.cluster = cluster;
1502 commit->action = ACTION_MKDIR;
1503}
1504
1505typedef struct {
ths64eaabd2008-07-03 19:54:19 +00001506 /*
1507 * Since the sequence number is at most 0x3f, and the filename
1508 * length is at most 13 times the sequence number, the maximal
1509 * filename length is 0x3f * 13 bytes.
1510 */
1511 unsigned char name[0x3f * 13 + 1];
bellarda0464332005-12-18 18:29:50 +00001512 int checksum, len;
1513 int sequence_number;
1514} long_file_name;
1515
1516static void lfn_init(long_file_name* lfn)
1517{
1518 lfn->sequence_number = lfn->len = 0;
1519 lfn->checksum = 0x100;
1520}
1521
1522/* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
1523static int parse_long_name(long_file_name* lfn,
Anthony Liguoric227f092009-10-01 16:12:16 -05001524 const direntry_t* direntry)
bellarda0464332005-12-18 18:29:50 +00001525{
1526 int i, j, offset;
1527 const unsigned char* pointer = (const unsigned char*)direntry;
1528
1529 if (!is_long_name(direntry))
1530 return 1;
1531
1532 if (pointer[0] & 0x40) {
1533 lfn->sequence_number = pointer[0] & 0x3f;
1534 lfn->checksum = pointer[13];
1535 lfn->name[0] = 0;
ths59fdb012008-07-03 19:55:47 +00001536 lfn->name[lfn->sequence_number * 13] = 0;
bellarda0464332005-12-18 18:29:50 +00001537 } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
1538 return -1;
1539 else if (pointer[13] != lfn->checksum)
1540 return -2;
1541 else if (pointer[12] || pointer[26] || pointer[27])
1542 return -3;
1543
1544 offset = 13 * (lfn->sequence_number - 1);
1545 for (i = 0, j = 1; i < 13; i++, j+=2) {
1546 if (j == 11)
1547 j = 14;
1548 else if (j == 26)
1549 j = 28;
1550
1551 if (pointer[j+1] == 0)
1552 lfn->name[offset + i] = pointer[j];
1553 else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
1554 return -4;
1555 else
1556 lfn->name[offset + i] = 0;
1557 }
1558
1559 if (pointer[0] & 0x40)
thsffe8ab82007-12-16 03:16:05 +00001560 lfn->len = offset + strlen((char*)lfn->name + offset);
bellarda0464332005-12-18 18:29:50 +00001561
1562 return 0;
1563}
1564
1565/* returns 0 if successful, >0 if no short_name, and <0 on error */
1566static int parse_short_name(BDRVVVFATState* s,
Anthony Liguoric227f092009-10-01 16:12:16 -05001567 long_file_name* lfn, direntry_t* direntry)
bellarda0464332005-12-18 18:29:50 +00001568{
1569 int i, j;
1570
1571 if (!is_short_name(direntry))
1572 return 1;
1573
1574 for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
1575 for (i = 0; i <= j; i++) {
1576 if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
1577 return -1;
1578 else if (s->downcase_short_names)
blueswir147398b92008-11-22 20:04:24 +00001579 lfn->name[i] = qemu_tolower(direntry->name[i]);
bellarda0464332005-12-18 18:29:50 +00001580 else
1581 lfn->name[i] = direntry->name[i];
1582 }
1583
Stefan Weilf671d172013-12-11 21:37:11 +01001584 for (j = 2; j >= 0 && direntry->name[8 + j] == ' '; j--) {
1585 }
bellarda0464332005-12-18 18:29:50 +00001586 if (j >= 0) {
1587 lfn->name[i++] = '.';
1588 lfn->name[i + j + 1] = '\0';
1589 for (;j >= 0; j--) {
Stefan Weilf671d172013-12-11 21:37:11 +01001590 uint8_t c = direntry->name[8 + j];
1591 if (c <= ' ' || c > 0x7f) {
1592 return -2;
1593 } else if (s->downcase_short_names) {
1594 lfn->name[i + j] = qemu_tolower(c);
1595 } else {
1596 lfn->name[i + j] = c;
1597 }
bellarda0464332005-12-18 18:29:50 +00001598 }
1599 } else
1600 lfn->name[i + j + 1] = '\0';
1601
thsffe8ab82007-12-16 03:16:05 +00001602 lfn->len = strlen((char*)lfn->name);
bellarda0464332005-12-18 18:29:50 +00001603
1604 return 0;
1605}
1606
1607static inline uint32_t modified_fat_get(BDRVVVFATState* s,
1608 unsigned int cluster)
1609{
1610 if (cluster < s->last_cluster_of_root_directory) {
1611 if (cluster + 1 == s->last_cluster_of_root_directory)
1612 return s->max_fat_value;
1613 else
1614 return cluster + 1;
1615 }
1616
1617 if (s->fat_type==32) {
1618 uint32_t* entry=((uint32_t*)s->fat2)+cluster;
1619 return le32_to_cpu(*entry);
1620 } else if (s->fat_type==16) {
1621 uint16_t* entry=((uint16_t*)s->fat2)+cluster;
1622 return le16_to_cpu(*entry);
1623 } else {
1624 const uint8_t* x=s->fat2+cluster*3/2;
1625 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
1626 }
1627}
1628
1629static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
1630{
1631 int was_modified = 0;
1632 int i, dummy;
1633
1634 if (s->qcow == NULL)
1635 return 0;
1636
1637 for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
Kevin Wolf7704df92011-11-08 10:50:12 +01001638 was_modified = bdrv_is_allocated(s->qcow,
bellarda0464332005-12-18 18:29:50 +00001639 cluster2sector(s, cluster_num) + i, 1, &dummy);
1640
1641 return was_modified;
1642}
1643
1644static const char* get_basename(const char* path)
1645{
1646 char* basename = strrchr(path, '/');
1647 if (basename == NULL)
1648 return path;
1649 else
1650 return basename + 1; /* strip '/' */
1651}
1652
1653/*
1654 * The array s->used_clusters holds the states of the clusters. If it is
1655 * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
1656 * was modified, bit 3 is set.
1657 * If any cluster is allocated, but not part of a file or directory, this
1658 * driver refuses to commit.
1659 */
1660typedef enum {
1661 USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
Anthony Liguoric227f092009-10-01 16:12:16 -05001662} used_t;
bellarda0464332005-12-18 18:29:50 +00001663
1664/*
1665 * get_cluster_count_for_direntry() not only determines how many clusters
1666 * are occupied by direntry, but also if it was renamed or modified.
1667 *
1668 * A file is thought to be renamed *only* if there already was a file with
1669 * exactly the same first cluster, but a different name.
1670 *
1671 * Further, the files/directories handled by this function are
1672 * assumed to be *not* deleted (and *only* those).
1673 */
1674static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
Anthony Liguoric227f092009-10-01 16:12:16 -05001675 direntry_t* direntry, const char* path)
bellarda0464332005-12-18 18:29:50 +00001676{
1677 /*
1678 * This is a little bit tricky:
1679 * IF the guest OS just inserts a cluster into the file chain,
1680 * and leaves the rest alone, (i.e. the original file had clusters
1681 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
1682 *
1683 * - do_commit will write the cluster into the file at the given
1684 * offset, but
1685 *
1686 * - the cluster which is overwritten should be moved to a later
1687 * position in the file.
1688 *
1689 * I am not aware that any OS does something as braindead, but this
1690 * situation could happen anyway when not committing for a long time.
1691 * Just to be sure that this does not bite us, detect it, and copy the
1692 * contents of the clusters to-be-overwritten into the qcow.
1693 */
1694 int copy_it = 0;
1695 int was_modified = 0;
1696 int32_t ret = 0;
1697
1698 uint32_t cluster_num = begin_of_direntry(direntry);
1699 uint32_t offset = 0;
1700 int first_mapping_index = -1;
Anthony Liguoric227f092009-10-01 16:12:16 -05001701 mapping_t* mapping = NULL;
bellarda0464332005-12-18 18:29:50 +00001702 const char* basename2 = NULL;
1703
1704 vvfat_close_current_file(s);
1705
1706 /* the root directory */
1707 if (cluster_num == 0)
1708 return 0;
1709
1710 /* write support */
1711 if (s->qcow) {
1712 basename2 = get_basename(path);
1713
1714 mapping = find_mapping_for_cluster(s, cluster_num);
1715
1716 if (mapping) {
bellardda2414e2006-04-23 14:36:41 +00001717 const char* basename;
1718
bellarda0464332005-12-18 18:29:50 +00001719 assert(mapping->mode & MODE_DELETED);
1720 mapping->mode &= ~MODE_DELETED;
1721
bellardda2414e2006-04-23 14:36:41 +00001722 basename = get_basename(mapping->path);
bellarda0464332005-12-18 18:29:50 +00001723
1724 assert(mapping->mode & MODE_NORMAL);
1725
1726 /* rename */
1727 if (strcmp(basename, basename2))
Anthony Liguori7267c092011-08-20 22:09:37 -05001728 schedule_rename(s, cluster_num, g_strdup(path));
bellarda0464332005-12-18 18:29:50 +00001729 } else if (is_file(direntry))
1730 /* new file */
Anthony Liguori7267c092011-08-20 22:09:37 -05001731 schedule_new_file(s, g_strdup(path), cluster_num);
bellarda0464332005-12-18 18:29:50 +00001732 else {
Blue Swirl43dc2a62010-03-18 18:41:57 +00001733 abort();
bellarda0464332005-12-18 18:29:50 +00001734 return 0;
1735 }
1736 }
1737
1738 while(1) {
1739 if (s->qcow) {
1740 if (!copy_it && cluster_was_modified(s, cluster_num)) {
1741 if (mapping == NULL ||
1742 mapping->begin > cluster_num ||
1743 mapping->end <= cluster_num)
1744 mapping = find_mapping_for_cluster(s, cluster_num);
1745
1746
1747 if (mapping &&
1748 (mapping->mode & MODE_DIRECTORY) == 0) {
1749
1750 /* was modified in qcow */
1751 if (offset != mapping->info.file.offset + s->cluster_size
1752 * (cluster_num - mapping->begin)) {
1753 /* offset of this cluster in file chain has changed */
Blue Swirl43dc2a62010-03-18 18:41:57 +00001754 abort();
bellarda0464332005-12-18 18:29:50 +00001755 copy_it = 1;
1756 } else if (offset == 0) {
1757 const char* basename = get_basename(mapping->path);
1758
1759 if (strcmp(basename, basename2))
1760 copy_it = 1;
1761 first_mapping_index = array_index(&(s->mapping), mapping);
1762 }
1763
1764 if (mapping->first_mapping_index != first_mapping_index
1765 && mapping->info.file.offset > 0) {
Blue Swirl43dc2a62010-03-18 18:41:57 +00001766 abort();
bellarda0464332005-12-18 18:29:50 +00001767 copy_it = 1;
1768 }
1769
1770 /* need to write out? */
1771 if (!was_modified && is_file(direntry)) {
1772 was_modified = 1;
1773 schedule_writeout(s, mapping->dir_index, offset);
1774 }
bellardde167e42005-04-28 21:15:08 +00001775 }
bellarda0464332005-12-18 18:29:50 +00001776 }
bellardde167e42005-04-28 21:15:08 +00001777
bellarda0464332005-12-18 18:29:50 +00001778 if (copy_it) {
1779 int i, dummy;
1780 /*
1781 * This is horribly inefficient, but that is okay, since
1782 * it is rarely executed, if at all.
1783 */
1784 int64_t offset = cluster2sector(s, cluster_num);
bellardde167e42005-04-28 21:15:08 +00001785
bellarda0464332005-12-18 18:29:50 +00001786 vvfat_close_current_file(s);
Kevin Wolf7704df92011-11-08 10:50:12 +01001787 for (i = 0; i < s->sectors_per_cluster; i++) {
1788 if (!bdrv_is_allocated(s->qcow, offset + i, 1, &dummy)) {
1789 if (vvfat_read(s->bs, offset, s->cluster_buffer, 1)) {
1790 return -1;
1791 }
1792 if (bdrv_write(s->qcow, offset, s->cluster_buffer, 1)) {
1793 return -2;
1794 }
1795 }
1796 }
bellardde167e42005-04-28 21:15:08 +00001797 }
1798 }
bellarda0464332005-12-18 18:29:50 +00001799
1800 ret++;
1801 if (s->used_clusters[cluster_num] & USED_ANY)
1802 return 0;
1803 s->used_clusters[cluster_num] = USED_FILE;
1804
1805 cluster_num = modified_fat_get(s, cluster_num);
1806
1807 if (fat_eof(s, cluster_num))
1808 return ret;
1809 else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
1810 return -1;
1811
1812 offset += s->cluster_size;
bellardde167e42005-04-28 21:15:08 +00001813 }
1814}
1815
bellarda0464332005-12-18 18:29:50 +00001816/*
ths5fafdf22007-09-16 21:08:06 +00001817 * This function looks at the modified data (qcow).
bellarda0464332005-12-18 18:29:50 +00001818 * It returns 0 upon inconsistency or error, and the number of clusters
1819 * used by the directory, its subdirectories and their files.
1820 */
1821static int check_directory_consistency(BDRVVVFATState *s,
1822 int cluster_num, const char* path)
bellardde167e42005-04-28 21:15:08 +00001823{
bellarda0464332005-12-18 18:29:50 +00001824 int ret = 0;
Anthony Liguori7267c092011-08-20 22:09:37 -05001825 unsigned char* cluster = g_malloc(s->cluster_size);
Anthony Liguoric227f092009-10-01 16:12:16 -05001826 direntry_t* direntries = (direntry_t*)cluster;
1827 mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
bellardde167e42005-04-28 21:15:08 +00001828
bellarda0464332005-12-18 18:29:50 +00001829 long_file_name lfn;
1830 int path_len = strlen(path);
Kevin Wolf0d460d62011-06-01 10:57:00 +02001831 char path2[PATH_MAX + 1];
bellardde167e42005-04-28 21:15:08 +00001832
bellarda0464332005-12-18 18:29:50 +00001833 assert(path_len < PATH_MAX); /* len was tested before! */
blueswir1363a37d2008-08-21 17:58:08 +00001834 pstrcpy(path2, sizeof(path2), path);
bellarda0464332005-12-18 18:29:50 +00001835 path2[path_len] = '/';
1836 path2[path_len + 1] = '\0';
bellardde167e42005-04-28 21:15:08 +00001837
bellarda0464332005-12-18 18:29:50 +00001838 if (mapping) {
1839 const char* basename = get_basename(mapping->path);
1840 const char* basename2 = get_basename(path);
1841
1842 assert(mapping->mode & MODE_DIRECTORY);
1843
1844 assert(mapping->mode & MODE_DELETED);
1845 mapping->mode &= ~MODE_DELETED;
1846
1847 if (strcmp(basename, basename2))
Anthony Liguori7267c092011-08-20 22:09:37 -05001848 schedule_rename(s, cluster_num, g_strdup(path));
bellarda0464332005-12-18 18:29:50 +00001849 } else
1850 /* new directory */
Anthony Liguori7267c092011-08-20 22:09:37 -05001851 schedule_mkdir(s, cluster_num, g_strdup(path));
ths3b46e622007-09-17 08:09:54 +00001852
bellarda0464332005-12-18 18:29:50 +00001853 lfn_init(&lfn);
1854 do {
1855 int i;
1856 int subret = 0;
1857
1858 ret++;
1859
1860 if (s->used_clusters[cluster_num] & USED_ANY) {
1861 fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
Markus Armbruster6262bbd2014-05-28 11:17:04 +02001862 goto fail;
bellardde167e42005-04-28 21:15:08 +00001863 }
bellarda0464332005-12-18 18:29:50 +00001864 s->used_clusters[cluster_num] = USED_DIRECTORY;
bellardde167e42005-04-28 21:15:08 +00001865
bellarda0464332005-12-18 18:29:50 +00001866DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
1867 subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
1868 s->sectors_per_cluster);
1869 if (subret) {
1870 fprintf(stderr, "Error fetching direntries\n");
1871 fail:
Stefan Weilce137822011-09-30 23:29:53 +02001872 g_free(cluster);
bellarda0464332005-12-18 18:29:50 +00001873 return 0;
1874 }
1875
1876 for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
blueswir13f4cb3d2009-04-13 16:31:01 +00001877 int cluster_count = 0;
bellarda0464332005-12-18 18:29:50 +00001878
Stefan Weilb2bedb22011-09-12 22:33:01 +02001879DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i));
bellarda0464332005-12-18 18:29:50 +00001880 if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
1881 is_free(direntries + i))
1882 continue;
1883
1884 subret = parse_long_name(&lfn, direntries + i);
1885 if (subret < 0) {
1886 fprintf(stderr, "Error in long name\n");
1887 goto fail;
bellardde167e42005-04-28 21:15:08 +00001888 }
bellarda0464332005-12-18 18:29:50 +00001889 if (subret == 0 || is_free(direntries + i))
1890 continue;
1891
1892 if (fat_chksum(direntries+i) != lfn.checksum) {
1893 subret = parse_short_name(s, &lfn, direntries + i);
1894 if (subret < 0) {
1895 fprintf(stderr, "Error in short name (%d)\n", subret);
1896 goto fail;
1897 }
thsffe8ab82007-12-16 03:16:05 +00001898 if (subret > 0 || !strcmp((char*)lfn.name, ".")
1899 || !strcmp((char*)lfn.name, ".."))
bellarda0464332005-12-18 18:29:50 +00001900 continue;
1901 }
1902 lfn.checksum = 0x100; /* cannot use long name twice */
1903
1904 if (path_len + 1 + lfn.len >= PATH_MAX) {
1905 fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
1906 goto fail;
1907 }
blueswir1363a37d2008-08-21 17:58:08 +00001908 pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
1909 (char*)lfn.name);
bellarda0464332005-12-18 18:29:50 +00001910
1911 if (is_directory(direntries + i)) {
1912 if (begin_of_direntry(direntries + i) == 0) {
1913 DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
1914 goto fail;
1915 }
1916 cluster_count = check_directory_consistency(s,
1917 begin_of_direntry(direntries + i), path2);
1918 if (cluster_count == 0) {
1919 DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
1920 goto fail;
1921 }
1922 } else if (is_file(direntries + i)) {
1923 /* check file size with FAT */
1924 cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
1925 if (cluster_count !=
1926 (le32_to_cpu(direntries[i].size) + s->cluster_size
1927 - 1) / s->cluster_size) {
1928 DLOG(fprintf(stderr, "Cluster count mismatch\n"));
1929 goto fail;
1930 }
1931 } else
Blue Swirl43dc2a62010-03-18 18:41:57 +00001932 abort(); /* cluster_count = 0; */
bellarda0464332005-12-18 18:29:50 +00001933
1934 ret += cluster_count;
bellardde167e42005-04-28 21:15:08 +00001935 }
bellarda0464332005-12-18 18:29:50 +00001936
1937 cluster_num = modified_fat_get(s, cluster_num);
1938 } while(!fat_eof(s, cluster_num));
1939
Stefan Weilce137822011-09-30 23:29:53 +02001940 g_free(cluster);
bellarda0464332005-12-18 18:29:50 +00001941 return ret;
bellardde167e42005-04-28 21:15:08 +00001942}
1943
bellarda0464332005-12-18 18:29:50 +00001944/* returns 1 on success */
1945static int is_consistent(BDRVVVFATState* s)
bellardde167e42005-04-28 21:15:08 +00001946{
bellarda0464332005-12-18 18:29:50 +00001947 int i, check;
1948 int used_clusters_count = 0;
1949
1950DLOG(checkpoint());
1951 /*
1952 * - get modified FAT
1953 * - compare the two FATs (TODO)
1954 * - get buffer for marking used clusters
1955 * - recurse direntries from root (using bs->bdrv_read to make
1956 * sure to get the new data)
1957 * - check that the FAT agrees with the size
1958 * - count the number of clusters occupied by this directory and
1959 * its files
1960 * - check that the cumulative used cluster count agrees with the
1961 * FAT
1962 * - if all is fine, return number of used clusters
1963 */
1964 if (s->fat2 == NULL) {
1965 int size = 0x200 * s->sectors_per_fat;
Anthony Liguori7267c092011-08-20 22:09:37 -05001966 s->fat2 = g_malloc(size);
bellarda0464332005-12-18 18:29:50 +00001967 memcpy(s->fat2, s->fat.pointer, size);
1968 }
1969 check = vvfat_read(s->bs,
1970 s->first_sectors_number, s->fat2, s->sectors_per_fat);
1971 if (check) {
1972 fprintf(stderr, "Could not copy fat\n");
bellardde167e42005-04-28 21:15:08 +00001973 return 0;
1974 }
bellarda0464332005-12-18 18:29:50 +00001975 assert (s->used_clusters);
1976 for (i = 0; i < sector2cluster(s, s->sector_count); i++)
1977 s->used_clusters[i] &= ~USED_ANY;
1978
1979 clear_commits(s);
1980
1981 /* mark every mapped file/directory as deleted.
1982 * (check_directory_consistency() will unmark those still present). */
1983 if (s->qcow)
1984 for (i = 0; i < s->mapping.next; i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05001985 mapping_t* mapping = array_get(&(s->mapping), i);
bellarda0464332005-12-18 18:29:50 +00001986 if (mapping->first_mapping_index < 0)
1987 mapping->mode |= MODE_DELETED;
1988 }
1989
1990 used_clusters_count = check_directory_consistency(s, 0, s->path);
1991 if (used_clusters_count <= 0) {
1992 DLOG(fprintf(stderr, "problem in directory\n"));
1993 return 0;
1994 }
1995
1996 check = s->last_cluster_of_root_directory;
1997 for (i = check; i < sector2cluster(s, s->sector_count); i++) {
1998 if (modified_fat_get(s, i)) {
1999 if(!s->used_clusters[i]) {
2000 DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
2001 return 0;
2002 }
2003 check++;
2004 }
2005
2006 if (s->used_clusters[i] == USED_ALLOCATED) {
2007 /* allocated, but not used... */
2008 DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
2009 return 0;
2010 }
2011 }
2012
2013 if (check != used_clusters_count)
2014 return 0;
2015
2016 return used_clusters_count;
bellardde167e42005-04-28 21:15:08 +00002017}
2018
bellarda0464332005-12-18 18:29:50 +00002019static inline void adjust_mapping_indices(BDRVVVFATState* s,
2020 int offset, int adjust)
bellardde167e42005-04-28 21:15:08 +00002021{
bellarda0464332005-12-18 18:29:50 +00002022 int i;
2023
2024 for (i = 0; i < s->mapping.next; i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002025 mapping_t* mapping = array_get(&(s->mapping), i);
bellarda0464332005-12-18 18:29:50 +00002026
2027#define ADJUST_MAPPING_INDEX(name) \
2028 if (mapping->name >= offset) \
2029 mapping->name += adjust
2030
2031 ADJUST_MAPPING_INDEX(first_mapping_index);
2032 if (mapping->mode & MODE_DIRECTORY)
2033 ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
2034 }
bellardde167e42005-04-28 21:15:08 +00002035}
2036
bellarda0464332005-12-18 18:29:50 +00002037/* insert or update mapping */
Anthony Liguoric227f092009-10-01 16:12:16 -05002038static mapping_t* insert_mapping(BDRVVVFATState* s,
bellarda0464332005-12-18 18:29:50 +00002039 uint32_t begin, uint32_t end)
bellardde167e42005-04-28 21:15:08 +00002040{
bellarda0464332005-12-18 18:29:50 +00002041 /*
2042 * - find mapping where mapping->begin >= begin,
2043 * - if mapping->begin > begin: insert
2044 * - adjust all references to mappings!
2045 * - else: adjust
2046 * - replace name
2047 */
2048 int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
Anthony Liguoric227f092009-10-01 16:12:16 -05002049 mapping_t* mapping = NULL;
2050 mapping_t* first_mapping = array_get(&(s->mapping), 0);
bellarda0464332005-12-18 18:29:50 +00002051
2052 if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
2053 && mapping->begin < begin) {
2054 mapping->end = begin;
2055 index++;
2056 mapping = array_get(&(s->mapping), index);
2057 }
2058 if (index >= s->mapping.next || mapping->begin > begin) {
2059 mapping = array_insert(&(s->mapping), index, 1);
2060 mapping->path = NULL;
2061 adjust_mapping_indices(s, index, +1);
2062 }
2063
bellardde167e42005-04-28 21:15:08 +00002064 mapping->begin = begin;
bellarda0464332005-12-18 18:29:50 +00002065 mapping->end = end;
2066
Anthony Liguoric227f092009-10-01 16:12:16 -05002067DLOG(mapping_t* next_mapping;
bellarda0464332005-12-18 18:29:50 +00002068assert(index + 1 >= s->mapping.next ||
2069((next_mapping = array_get(&(s->mapping), index + 1)) &&
2070 next_mapping->begin >= end)));
2071
Anthony Liguoric227f092009-10-01 16:12:16 -05002072 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
bellarda0464332005-12-18 18:29:50 +00002073 s->current_mapping = array_get(&(s->mapping),
2074 s->current_mapping - first_mapping);
2075
2076 return mapping;
bellardde167e42005-04-28 21:15:08 +00002077}
2078
bellarda0464332005-12-18 18:29:50 +00002079static int remove_mapping(BDRVVVFATState* s, int mapping_index)
bellardde167e42005-04-28 21:15:08 +00002080{
Anthony Liguoric227f092009-10-01 16:12:16 -05002081 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
2082 mapping_t* first_mapping = array_get(&(s->mapping), 0);
bellardde167e42005-04-28 21:15:08 +00002083
bellarda0464332005-12-18 18:29:50 +00002084 /* free mapping */
Stefan Weilce137822011-09-30 23:29:53 +02002085 if (mapping->first_mapping_index < 0) {
2086 g_free(mapping->path);
2087 }
bellardde167e42005-04-28 21:15:08 +00002088
bellarda0464332005-12-18 18:29:50 +00002089 /* remove from s->mapping */
2090 array_remove(&(s->mapping), mapping_index);
bellardde167e42005-04-28 21:15:08 +00002091
bellarda0464332005-12-18 18:29:50 +00002092 /* adjust all references to mappings */
2093 adjust_mapping_indices(s, mapping_index, -1);
bellardde167e42005-04-28 21:15:08 +00002094
Anthony Liguoric227f092009-10-01 16:12:16 -05002095 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
bellarda0464332005-12-18 18:29:50 +00002096 s->current_mapping = array_get(&(s->mapping),
2097 s->current_mapping - first_mapping);
bellardde167e42005-04-28 21:15:08 +00002098
2099 return 0;
2100}
2101
bellarda0464332005-12-18 18:29:50 +00002102static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
bellardde167e42005-04-28 21:15:08 +00002103{
bellarda0464332005-12-18 18:29:50 +00002104 int i;
2105 for (i = 0; i < s->mapping.next; i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002106 mapping_t* mapping = array_get(&(s->mapping), i);
bellarda0464332005-12-18 18:29:50 +00002107 if (mapping->dir_index >= offset)
2108 mapping->dir_index += adjust;
2109 if ((mapping->mode & MODE_DIRECTORY) &&
2110 mapping->info.dir.first_dir_index >= offset)
2111 mapping->info.dir.first_dir_index += adjust;
bellardde167e42005-04-28 21:15:08 +00002112 }
bellardde167e42005-04-28 21:15:08 +00002113}
2114
Anthony Liguoric227f092009-10-01 16:12:16 -05002115static direntry_t* insert_direntries(BDRVVVFATState* s,
bellarda0464332005-12-18 18:29:50 +00002116 int dir_index, int count)
bellardde167e42005-04-28 21:15:08 +00002117{
bellarda0464332005-12-18 18:29:50 +00002118 /*
2119 * make room in s->directory,
2120 * adjust_dirindices
2121 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002122 direntry_t* result = array_insert(&(s->directory), dir_index, count);
bellarda0464332005-12-18 18:29:50 +00002123 if (result == NULL)
2124 return NULL;
2125 adjust_dirindices(s, dir_index, count);
bellardde167e42005-04-28 21:15:08 +00002126 return result;
2127}
2128
bellarda0464332005-12-18 18:29:50 +00002129static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
bellardde167e42005-04-28 21:15:08 +00002130{
bellarda0464332005-12-18 18:29:50 +00002131 int ret = array_remove_slice(&(s->directory), dir_index, count);
2132 if (ret)
2133 return ret;
2134 adjust_dirindices(s, dir_index, -count);
bellardde167e42005-04-28 21:15:08 +00002135 return 0;
2136}
2137
bellarda0464332005-12-18 18:29:50 +00002138/*
2139 * Adapt the mappings of the cluster chain starting at first cluster
2140 * (i.e. if a file starts at first_cluster, the chain is followed according
2141 * to the modified fat, and the corresponding entries in s->mapping are
2142 * adjusted)
2143 */
2144static int commit_mappings(BDRVVVFATState* s,
2145 uint32_t first_cluster, int dir_index)
bellardde167e42005-04-28 21:15:08 +00002146{
Anthony Liguoric227f092009-10-01 16:12:16 -05002147 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
2148 direntry_t* direntry = array_get(&(s->directory), dir_index);
bellarda0464332005-12-18 18:29:50 +00002149 uint32_t cluster = first_cluster;
bellardde167e42005-04-28 21:15:08 +00002150
bellarda0464332005-12-18 18:29:50 +00002151 vvfat_close_current_file(s);
bellardde167e42005-04-28 21:15:08 +00002152
bellarda0464332005-12-18 18:29:50 +00002153 assert(mapping);
2154 assert(mapping->begin == first_cluster);
2155 mapping->first_mapping_index = -1;
2156 mapping->dir_index = dir_index;
2157 mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
2158 MODE_DIRECTORY : MODE_NORMAL;
bellardde167e42005-04-28 21:15:08 +00002159
bellarda0464332005-12-18 18:29:50 +00002160 while (!fat_eof(s, cluster)) {
2161 uint32_t c, c1;
bellardde167e42005-04-28 21:15:08 +00002162
bellarda0464332005-12-18 18:29:50 +00002163 for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
2164 c = c1, c1 = modified_fat_get(s, c1));
bellardde167e42005-04-28 21:15:08 +00002165
bellarda0464332005-12-18 18:29:50 +00002166 c++;
2167 if (c > mapping->end) {
2168 int index = array_index(&(s->mapping), mapping);
2169 int i, max_i = s->mapping.next - index;
2170 for (i = 1; i < max_i && mapping[i].begin < c; i++);
2171 while (--i > 0)
2172 remove_mapping(s, index + 1);
2173 }
2174 assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
2175 || mapping[1].begin >= c);
2176 mapping->end = c;
2177
2178 if (!fat_eof(s, c1)) {
2179 int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
Anthony Liguoric227f092009-10-01 16:12:16 -05002180 mapping_t* next_mapping = i >= s->mapping.next ? NULL :
bellarda0464332005-12-18 18:29:50 +00002181 array_get(&(s->mapping), i);
2182
2183 if (next_mapping == NULL || next_mapping->begin > c1) {
2184 int i1 = array_index(&(s->mapping), mapping);
2185
2186 next_mapping = insert_mapping(s, c1, c1+1);
2187
2188 if (c1 < c)
2189 i1++;
2190 mapping = array_get(&(s->mapping), i1);
bellardde167e42005-04-28 21:15:08 +00002191 }
bellarda0464332005-12-18 18:29:50 +00002192
2193 next_mapping->dir_index = mapping->dir_index;
ths5fafdf22007-09-16 21:08:06 +00002194 next_mapping->first_mapping_index =
bellarda0464332005-12-18 18:29:50 +00002195 mapping->first_mapping_index < 0 ?
2196 array_index(&(s->mapping), mapping) :
2197 mapping->first_mapping_index;
2198 next_mapping->path = mapping->path;
2199 next_mapping->mode = mapping->mode;
2200 next_mapping->read_only = mapping->read_only;
2201 if (mapping->mode & MODE_DIRECTORY) {
2202 next_mapping->info.dir.parent_mapping_index =
2203 mapping->info.dir.parent_mapping_index;
2204 next_mapping->info.dir.first_dir_index =
2205 mapping->info.dir.first_dir_index +
2206 0x10 * s->sectors_per_cluster *
2207 (mapping->end - mapping->begin);
2208 } else
2209 next_mapping->info.file.offset = mapping->info.file.offset +
2210 mapping->end - mapping->begin;
2211
2212 mapping = next_mapping;
2213 }
ths3b46e622007-09-17 08:09:54 +00002214
bellarda0464332005-12-18 18:29:50 +00002215 cluster = c1;
2216 }
2217
2218 return 0;
2219}
2220
2221static int commit_direntries(BDRVVVFATState* s,
2222 int dir_index, int parent_mapping_index)
2223{
Anthony Liguoric227f092009-10-01 16:12:16 -05002224 direntry_t* direntry = array_get(&(s->directory), dir_index);
bellarda0464332005-12-18 18:29:50 +00002225 uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
Anthony Liguoric227f092009-10-01 16:12:16 -05002226 mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
bellarda0464332005-12-18 18:29:50 +00002227
2228 int factor = 0x10 * s->sectors_per_cluster;
2229 int old_cluster_count, new_cluster_count;
2230 int current_dir_index = mapping->info.dir.first_dir_index;
2231 int first_dir_index = current_dir_index;
2232 int ret, i;
2233 uint32_t c;
2234
2235DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
2236
2237 assert(direntry);
2238 assert(mapping);
2239 assert(mapping->begin == first_cluster);
2240 assert(mapping->info.dir.first_dir_index < s->directory.next);
2241 assert(mapping->mode & MODE_DIRECTORY);
2242 assert(dir_index == 0 || is_directory(direntry));
2243
2244 mapping->info.dir.parent_mapping_index = parent_mapping_index;
2245
2246 if (first_cluster == 0) {
2247 old_cluster_count = new_cluster_count =
2248 s->last_cluster_of_root_directory;
2249 } else {
2250 for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2251 c = fat_get(s, c))
2252 old_cluster_count++;
2253
2254 for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
2255 c = modified_fat_get(s, c))
2256 new_cluster_count++;
2257 }
2258
2259 if (new_cluster_count > old_cluster_count) {
2260 if (insert_direntries(s,
2261 current_dir_index + factor * old_cluster_count,
2262 factor * (new_cluster_count - old_cluster_count)) == NULL)
2263 return -1;
2264 } else if (new_cluster_count < old_cluster_count)
2265 remove_direntries(s,
2266 current_dir_index + factor * new_cluster_count,
2267 factor * (old_cluster_count - new_cluster_count));
2268
2269 for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
2270 void* direntry = array_get(&(s->directory), current_dir_index);
2271 int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
2272 s->sectors_per_cluster);
2273 if (ret)
2274 return ret;
2275 assert(!strncmp(s->directory.pointer, "QEMU", 4));
2276 current_dir_index += factor;
2277 }
2278
2279 ret = commit_mappings(s, first_cluster, dir_index);
2280 if (ret)
2281 return ret;
2282
2283 /* recurse */
2284 for (i = 0; i < factor * new_cluster_count; i++) {
2285 direntry = array_get(&(s->directory), first_dir_index + i);
2286 if (is_directory(direntry) && !is_dot(direntry)) {
2287 mapping = find_mapping_for_cluster(s, first_cluster);
2288 assert(mapping->mode & MODE_DIRECTORY);
2289 ret = commit_direntries(s, first_dir_index + i,
2290 array_index(&(s->mapping), mapping));
2291 if (ret)
2292 return ret;
bellardde167e42005-04-28 21:15:08 +00002293 }
2294 }
bellarda0464332005-12-18 18:29:50 +00002295
bellardde167e42005-04-28 21:15:08 +00002296 return 0;
2297}
2298
bellarda0464332005-12-18 18:29:50 +00002299/* commit one file (adjust contents, adjust mapping),
2300 return first_mapping_index */
2301static int commit_one_file(BDRVVVFATState* s,
2302 int dir_index, uint32_t offset)
2303{
Anthony Liguoric227f092009-10-01 16:12:16 -05002304 direntry_t* direntry = array_get(&(s->directory), dir_index);
bellarda0464332005-12-18 18:29:50 +00002305 uint32_t c = begin_of_direntry(direntry);
2306 uint32_t first_cluster = c;
Anthony Liguoric227f092009-10-01 16:12:16 -05002307 mapping_t* mapping = find_mapping_for_cluster(s, c);
bellarda0464332005-12-18 18:29:50 +00002308 uint32_t size = filesize_of_direntry(direntry);
Anthony Liguori7267c092011-08-20 22:09:37 -05002309 char* cluster = g_malloc(s->cluster_size);
bellarda0464332005-12-18 18:29:50 +00002310 uint32_t i;
2311 int fd = 0;
2312
2313 assert(offset < size);
2314 assert((offset % s->cluster_size) == 0);
2315
2316 for (i = s->cluster_size; i < offset; i += s->cluster_size)
2317 c = modified_fat_get(s, c);
2318
Corey Bryant6165f4d2012-08-14 16:43:45 -04002319 fd = qemu_open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
bellarda0464332005-12-18 18:29:50 +00002320 if (fd < 0) {
2321 fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
2322 strerror(errno), errno);
Stefan Weilce137822011-09-30 23:29:53 +02002323 g_free(cluster);
bellarda0464332005-12-18 18:29:50 +00002324 return fd;
2325 }
Stefan Weilce137822011-09-30 23:29:53 +02002326 if (offset > 0) {
2327 if (lseek(fd, offset, SEEK_SET) != offset) {
Corey Bryant2e1e79d2012-08-14 16:43:46 -04002328 qemu_close(fd);
Stefan Weilce137822011-09-30 23:29:53 +02002329 g_free(cluster);
2330 return -3;
2331 }
2332 }
bellarda0464332005-12-18 18:29:50 +00002333
2334 while (offset < size) {
2335 uint32_t c1;
2336 int rest_size = (size - offset > s->cluster_size ?
2337 s->cluster_size : size - offset);
2338 int ret;
2339
2340 c1 = modified_fat_get(s, c);
2341
2342 assert((size - offset == 0 && fat_eof(s, c)) ||
2343 (size > offset && c >=2 && !fat_eof(s, c)));
bellarda0464332005-12-18 18:29:50 +00002344
2345 ret = vvfat_read(s->bs, cluster2sector(s, c),
thsffe8ab82007-12-16 03:16:05 +00002346 (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
bellarda0464332005-12-18 18:29:50 +00002347
Stefan Weilce137822011-09-30 23:29:53 +02002348 if (ret < 0) {
Corey Bryant2e1e79d2012-08-14 16:43:46 -04002349 qemu_close(fd);
Stefan Weilce137822011-09-30 23:29:53 +02002350 g_free(cluster);
2351 return ret;
2352 }
bellarda0464332005-12-18 18:29:50 +00002353
Stefan Weilce137822011-09-30 23:29:53 +02002354 if (write(fd, cluster, rest_size) < 0) {
Corey Bryant2e1e79d2012-08-14 16:43:46 -04002355 qemu_close(fd);
Stefan Weilce137822011-09-30 23:29:53 +02002356 g_free(cluster);
2357 return -2;
2358 }
bellarda0464332005-12-18 18:29:50 +00002359
2360 offset += rest_size;
2361 c = c1;
2362 }
2363
Kirill A. Shutemov2dedf832010-01-20 00:56:14 +01002364 if (ftruncate(fd, size)) {
2365 perror("ftruncate()");
Corey Bryant2e1e79d2012-08-14 16:43:46 -04002366 qemu_close(fd);
Stefan Weilce137822011-09-30 23:29:53 +02002367 g_free(cluster);
Kirill A. Shutemov2dedf832010-01-20 00:56:14 +01002368 return -4;
2369 }
Corey Bryant2e1e79d2012-08-14 16:43:46 -04002370 qemu_close(fd);
Stefan Weilce137822011-09-30 23:29:53 +02002371 g_free(cluster);
bellarda0464332005-12-18 18:29:50 +00002372
2373 return commit_mappings(s, first_cluster, dir_index);
2374}
2375
2376#ifdef DEBUG
2377/* test, if all mappings point to valid direntries */
2378static void check1(BDRVVVFATState* s)
2379{
2380 int i;
2381 for (i = 0; i < s->mapping.next; i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002382 mapping_t* mapping = array_get(&(s->mapping), i);
bellarda0464332005-12-18 18:29:50 +00002383 if (mapping->mode & MODE_DELETED) {
2384 fprintf(stderr, "deleted\n");
2385 continue;
2386 }
bellarda0464332005-12-18 18:29:50 +00002387 assert(mapping->dir_index < s->directory.next);
Anthony Liguoric227f092009-10-01 16:12:16 -05002388 direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
bellarda0464332005-12-18 18:29:50 +00002389 assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
2390 if (mapping->mode & MODE_DIRECTORY) {
2391 assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
2392 assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
2393 }
2394 }
2395}
2396
2397/* test, if all direntries have mappings */
2398static void check2(BDRVVVFATState* s)
2399{
2400 int i;
2401 int first_mapping = -1;
2402
2403 for (i = 0; i < s->directory.next; i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002404 direntry_t* direntry = array_get(&(s->directory), i);
bellarda0464332005-12-18 18:29:50 +00002405
2406 if (is_short_name(direntry) && begin_of_direntry(direntry)) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002407 mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
bellarda0464332005-12-18 18:29:50 +00002408 assert(mapping);
2409 assert(mapping->dir_index == i || is_dot(direntry));
2410 assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
2411 }
2412
2413 if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
2414 /* cluster start */
2415 int j, count = 0;
2416
2417 for (j = 0; j < s->mapping.next; j++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002418 mapping_t* mapping = array_get(&(s->mapping), j);
bellarda0464332005-12-18 18:29:50 +00002419 if (mapping->mode & MODE_DELETED)
2420 continue;
2421 if (mapping->mode & MODE_DIRECTORY) {
2422 if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
2423 assert(++count == 1);
2424 if (mapping->first_mapping_index == -1)
2425 first_mapping = array_index(&(s->mapping), mapping);
2426 else
2427 assert(first_mapping == mapping->first_mapping_index);
2428 if (mapping->info.dir.parent_mapping_index < 0)
2429 assert(j == 0);
2430 else {
Anthony Liguoric227f092009-10-01 16:12:16 -05002431 mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
bellarda0464332005-12-18 18:29:50 +00002432 assert(parent->mode & MODE_DIRECTORY);
2433 assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
2434 }
2435 }
2436 }
2437 }
2438 if (count == 0)
2439 first_mapping = -1;
2440 }
2441 }
2442}
2443#endif
2444
2445static int handle_renames_and_mkdirs(BDRVVVFATState* s)
2446{
2447 int i;
2448
2449#ifdef DEBUG
2450 fprintf(stderr, "handle_renames\n");
2451 for (i = 0; i < s->commits.next; i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002452 commit_t* commit = array_get(&(s->commits), i);
bellarda0464332005-12-18 18:29:50 +00002453 fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
2454 }
2455#endif
2456
2457 for (i = 0; i < s->commits.next;) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002458 commit_t* commit = array_get(&(s->commits), i);
bellarda0464332005-12-18 18:29:50 +00002459 if (commit->action == ACTION_RENAME) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002460 mapping_t* mapping = find_mapping_for_cluster(s,
bellarda0464332005-12-18 18:29:50 +00002461 commit->param.rename.cluster);
2462 char* old_path = mapping->path;
2463
2464 assert(commit->path);
2465 mapping->path = commit->path;
2466 if (rename(old_path, mapping->path))
2467 return -2;
2468
2469 if (mapping->mode & MODE_DIRECTORY) {
2470 int l1 = strlen(mapping->path);
2471 int l2 = strlen(old_path);
2472 int diff = l1 - l2;
Anthony Liguoric227f092009-10-01 16:12:16 -05002473 direntry_t* direntry = array_get(&(s->directory),
bellarda0464332005-12-18 18:29:50 +00002474 mapping->info.dir.first_dir_index);
2475 uint32_t c = mapping->begin;
2476 int i = 0;
2477
2478 /* recurse */
2479 while (!fat_eof(s, c)) {
2480 do {
Anthony Liguoric227f092009-10-01 16:12:16 -05002481 direntry_t* d = direntry + i;
bellarda0464332005-12-18 18:29:50 +00002482
2483 if (is_file(d) || (is_directory(d) && !is_dot(d))) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002484 mapping_t* m = find_mapping_for_cluster(s,
bellarda0464332005-12-18 18:29:50 +00002485 begin_of_direntry(d));
2486 int l = strlen(m->path);
Anthony Liguori7267c092011-08-20 22:09:37 -05002487 char* new_path = g_malloc(l + diff + 1);
bellarda0464332005-12-18 18:29:50 +00002488
2489 assert(!strncmp(m->path, mapping->path, l2));
2490
blueswir1363a37d2008-08-21 17:58:08 +00002491 pstrcpy(new_path, l + diff + 1, mapping->path);
2492 pstrcpy(new_path + l1, l + diff + 1 - l1,
2493 m->path + l2);
bellarda0464332005-12-18 18:29:50 +00002494
2495 schedule_rename(s, m->begin, new_path);
2496 }
2497 i++;
2498 } while((i % (0x10 * s->sectors_per_cluster)) != 0);
2499 c = fat_get(s, c);
2500 }
2501 }
2502
Stefan Weilce137822011-09-30 23:29:53 +02002503 g_free(old_path);
bellarda0464332005-12-18 18:29:50 +00002504 array_remove(&(s->commits), i);
2505 continue;
2506 } else if (commit->action == ACTION_MKDIR) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002507 mapping_t* mapping;
bellarda0464332005-12-18 18:29:50 +00002508 int j, parent_path_len;
2509
bellard48c2f062005-12-19 22:11:49 +00002510#ifdef __MINGW32__
2511 if (mkdir(commit->path))
2512 return -5;
2513#else
2514 if (mkdir(commit->path, 0755))
2515 return -5;
2516#endif
bellarda0464332005-12-18 18:29:50 +00002517
2518 mapping = insert_mapping(s, commit->param.mkdir.cluster,
2519 commit->param.mkdir.cluster + 1);
2520 if (mapping == NULL)
2521 return -6;
2522
2523 mapping->mode = MODE_DIRECTORY;
2524 mapping->read_only = 0;
2525 mapping->path = commit->path;
2526 j = s->directory.next;
2527 assert(j);
2528 insert_direntries(s, s->directory.next,
2529 0x10 * s->sectors_per_cluster);
2530 mapping->info.dir.first_dir_index = j;
2531
2532 parent_path_len = strlen(commit->path)
2533 - strlen(get_basename(commit->path)) - 1;
2534 for (j = 0; j < s->mapping.next; j++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002535 mapping_t* m = array_get(&(s->mapping), j);
bellarda0464332005-12-18 18:29:50 +00002536 if (m->first_mapping_index < 0 && m != mapping &&
2537 !strncmp(m->path, mapping->path, parent_path_len) &&
2538 strlen(m->path) == parent_path_len)
2539 break;
2540 }
2541 assert(j < s->mapping.next);
2542 mapping->info.dir.parent_mapping_index = j;
2543
2544 array_remove(&(s->commits), i);
2545 continue;
2546 }
2547
2548 i++;
2549 }
2550 return 0;
2551}
2552
2553/*
2554 * TODO: make sure that the short name is not matching *another* file
2555 */
2556static int handle_commits(BDRVVVFATState* s)
2557{
2558 int i, fail = 0;
2559
2560 vvfat_close_current_file(s);
2561
2562 for (i = 0; !fail && i < s->commits.next; i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002563 commit_t* commit = array_get(&(s->commits), i);
bellarda0464332005-12-18 18:29:50 +00002564 switch(commit->action) {
2565 case ACTION_RENAME: case ACTION_MKDIR:
Blue Swirl43dc2a62010-03-18 18:41:57 +00002566 abort();
bellarda0464332005-12-18 18:29:50 +00002567 fail = -2;
2568 break;
2569 case ACTION_WRITEOUT: {
Blue Swirla6c6f762010-03-13 14:18:50 +00002570#ifndef NDEBUG
2571 /* these variables are only used by assert() below */
Anthony Liguoric227f092009-10-01 16:12:16 -05002572 direntry_t* entry = array_get(&(s->directory),
bellarda0464332005-12-18 18:29:50 +00002573 commit->param.writeout.dir_index);
2574 uint32_t begin = begin_of_direntry(entry);
Anthony Liguoric227f092009-10-01 16:12:16 -05002575 mapping_t* mapping = find_mapping_for_cluster(s, begin);
Blue Swirla6c6f762010-03-13 14:18:50 +00002576#endif
bellarda0464332005-12-18 18:29:50 +00002577
2578 assert(mapping);
2579 assert(mapping->begin == begin);
2580 assert(commit->path == NULL);
2581
2582 if (commit_one_file(s, commit->param.writeout.dir_index,
2583 commit->param.writeout.modified_offset))
2584 fail = -3;
2585
2586 break;
2587 }
2588 case ACTION_NEW_FILE: {
2589 int begin = commit->param.new_file.first_cluster;
Anthony Liguoric227f092009-10-01 16:12:16 -05002590 mapping_t* mapping = find_mapping_for_cluster(s, begin);
2591 direntry_t* entry;
bellarda0464332005-12-18 18:29:50 +00002592 int i;
2593
2594 /* find direntry */
2595 for (i = 0; i < s->directory.next; i++) {
2596 entry = array_get(&(s->directory), i);
2597 if (is_file(entry) && begin_of_direntry(entry) == begin)
2598 break;
2599 }
2600
2601 if (i >= s->directory.next) {
2602 fail = -6;
2603 continue;
2604 }
2605
2606 /* make sure there exists an initial mapping */
2607 if (mapping && mapping->begin != begin) {
2608 mapping->end = begin;
2609 mapping = NULL;
2610 }
2611 if (mapping == NULL) {
2612 mapping = insert_mapping(s, begin, begin+1);
2613 }
2614 /* most members will be fixed in commit_mappings() */
2615 assert(commit->path);
2616 mapping->path = commit->path;
2617 mapping->read_only = 0;
2618 mapping->mode = MODE_NORMAL;
2619 mapping->info.file.offset = 0;
2620
2621 if (commit_one_file(s, i, 0))
2622 fail = -7;
2623
2624 break;
2625 }
2626 default:
Blue Swirl43dc2a62010-03-18 18:41:57 +00002627 abort();
bellarda0464332005-12-18 18:29:50 +00002628 }
2629 }
2630 if (i > 0 && array_remove_slice(&(s->commits), 0, i))
2631 return -1;
2632 return fail;
2633}
2634
2635static int handle_deletes(BDRVVVFATState* s)
2636{
2637 int i, deferred = 1, deleted = 1;
2638
2639 /* delete files corresponding to mappings marked as deleted */
2640 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
2641 while (deferred && deleted) {
2642 deferred = 0;
2643 deleted = 0;
2644
2645 for (i = 1; i < s->mapping.next; i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002646 mapping_t* mapping = array_get(&(s->mapping), i);
bellarda0464332005-12-18 18:29:50 +00002647 if (mapping->mode & MODE_DELETED) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002648 direntry_t* entry = array_get(&(s->directory),
bellarda0464332005-12-18 18:29:50 +00002649 mapping->dir_index);
2650
2651 if (is_free(entry)) {
2652 /* remove file/directory */
2653 if (mapping->mode & MODE_DIRECTORY) {
2654 int j, next_dir_index = s->directory.next,
2655 first_dir_index = mapping->info.dir.first_dir_index;
2656
2657 if (rmdir(mapping->path) < 0) {
2658 if (errno == ENOTEMPTY) {
2659 deferred++;
2660 continue;
2661 } else
2662 return -5;
2663 }
2664
2665 for (j = 1; j < s->mapping.next; j++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002666 mapping_t* m = array_get(&(s->mapping), j);
bellarda0464332005-12-18 18:29:50 +00002667 if (m->mode & MODE_DIRECTORY &&
2668 m->info.dir.first_dir_index >
2669 first_dir_index &&
2670 m->info.dir.first_dir_index <
2671 next_dir_index)
2672 next_dir_index =
2673 m->info.dir.first_dir_index;
2674 }
2675 remove_direntries(s, first_dir_index,
2676 next_dir_index - first_dir_index);
2677
2678 deleted++;
2679 }
2680 } else {
2681 if (unlink(mapping->path))
2682 return -4;
2683 deleted++;
2684 }
2685 DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
2686 remove_mapping(s, i);
2687 }
2688 }
2689 }
2690
2691 return 0;
2692}
2693
2694/*
2695 * synchronize mapping with new state:
2696 *
2697 * - copy FAT (with bdrv_read)
2698 * - mark all filenames corresponding to mappings as deleted
2699 * - recurse direntries from root (using bs->bdrv_read)
2700 * - delete files corresponding to mappings marked as deleted
2701 */
2702static int do_commit(BDRVVVFATState* s)
2703{
2704 int ret = 0;
2705
2706 /* the real meat are the commits. Nothing to do? Move along! */
2707 if (s->commits.next == 0)
2708 return 0;
2709
2710 vvfat_close_current_file(s);
2711
2712 ret = handle_renames_and_mkdirs(s);
2713 if (ret) {
2714 fprintf(stderr, "Error handling renames (%d)\n", ret);
Blue Swirl43dc2a62010-03-18 18:41:57 +00002715 abort();
bellarda0464332005-12-18 18:29:50 +00002716 return ret;
2717 }
2718
ths5fafdf22007-09-16 21:08:06 +00002719 /* copy FAT (with bdrv_read) */
bellarda0464332005-12-18 18:29:50 +00002720 memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
2721
2722 /* recurse direntries from root (using bs->bdrv_read) */
2723 ret = commit_direntries(s, 0, -1);
2724 if (ret) {
2725 fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
Blue Swirl43dc2a62010-03-18 18:41:57 +00002726 abort();
bellarda0464332005-12-18 18:29:50 +00002727 return ret;
2728 }
2729
2730 ret = handle_commits(s);
2731 if (ret) {
2732 fprintf(stderr, "Error handling commits (%d)\n", ret);
Blue Swirl43dc2a62010-03-18 18:41:57 +00002733 abort();
bellarda0464332005-12-18 18:29:50 +00002734 return ret;
2735 }
2736
2737 ret = handle_deletes(s);
2738 if (ret) {
2739 fprintf(stderr, "Error deleting\n");
Blue Swirl43dc2a62010-03-18 18:41:57 +00002740 abort();
bellarda0464332005-12-18 18:29:50 +00002741 return ret;
2742 }
2743
Kevin Wolf7704df92011-11-08 10:50:12 +01002744 if (s->qcow->drv->bdrv_make_empty) {
2745 s->qcow->drv->bdrv_make_empty(s->qcow);
2746 }
bellarda0464332005-12-18 18:29:50 +00002747
2748 memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
2749
2750DLOG(checkpoint());
2751 return 0;
2752}
2753
2754static int try_commit(BDRVVVFATState* s)
2755{
2756 vvfat_close_current_file(s);
2757DLOG(checkpoint());
2758 if(!is_consistent(s))
2759 return -1;
2760 return do_commit(s);
2761}
2762
ths5fafdf22007-09-16 21:08:06 +00002763static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
bellardde167e42005-04-28 21:15:08 +00002764 const uint8_t *buf, int nb_sectors)
2765{
ths5fafdf22007-09-16 21:08:06 +00002766 BDRVVVFATState *s = bs->opaque;
bellarda0464332005-12-18 18:29:50 +00002767 int i, ret;
bellardde167e42005-04-28 21:15:08 +00002768
bellarda0464332005-12-18 18:29:50 +00002769DLOG(checkpoint());
bellardde167e42005-04-28 21:15:08 +00002770
Kevin Wolfac48e382010-09-10 12:27:02 +02002771 /* Check if we're operating in read-only mode */
2772 if (s->qcow == NULL) {
2773 return -EACCES;
2774 }
2775
bellarda0464332005-12-18 18:29:50 +00002776 vvfat_close_current_file(s);
bellardde167e42005-04-28 21:15:08 +00002777
bellarda0464332005-12-18 18:29:50 +00002778 /*
2779 * Some sanity checks:
2780 * - do not allow writing to the boot sector
2781 * - do not allow to write non-ASCII filenames
2782 */
bellardde167e42005-04-28 21:15:08 +00002783
bellarda0464332005-12-18 18:29:50 +00002784 if (sector_num < s->first_sectors_number)
2785 return -1;
bellardde167e42005-04-28 21:15:08 +00002786
bellarda0464332005-12-18 18:29:50 +00002787 for (i = sector2cluster(s, sector_num);
2788 i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002789 mapping_t* mapping = find_mapping_for_cluster(s, i);
bellarda0464332005-12-18 18:29:50 +00002790 if (mapping) {
2791 if (mapping->read_only) {
2792 fprintf(stderr, "Tried to write to write-protected file %s\n",
2793 mapping->path);
2794 return -1;
2795 }
bellardde167e42005-04-28 21:15:08 +00002796
bellarda0464332005-12-18 18:29:50 +00002797 if (mapping->mode & MODE_DIRECTORY) {
2798 int begin = cluster2sector(s, i);
2799 int end = begin + s->sectors_per_cluster, k;
2800 int dir_index;
Anthony Liguoric227f092009-10-01 16:12:16 -05002801 const direntry_t* direntries;
bellarda0464332005-12-18 18:29:50 +00002802 long_file_name lfn;
bellardde167e42005-04-28 21:15:08 +00002803
bellarda0464332005-12-18 18:29:50 +00002804 lfn_init(&lfn);
bellardde167e42005-04-28 21:15:08 +00002805
bellarda0464332005-12-18 18:29:50 +00002806 if (begin < sector_num)
2807 begin = sector_num;
2808 if (end > sector_num + nb_sectors)
2809 end = sector_num + nb_sectors;
ths5fafdf22007-09-16 21:08:06 +00002810 dir_index = mapping->dir_index +
bellarda0464332005-12-18 18:29:50 +00002811 0x10 * (begin - mapping->begin * s->sectors_per_cluster);
Anthony Liguoric227f092009-10-01 16:12:16 -05002812 direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
bellardde167e42005-04-28 21:15:08 +00002813
bellarda0464332005-12-18 18:29:50 +00002814 for (k = 0; k < (end - begin) * 0x10; k++) {
2815 /* do not allow non-ASCII filenames */
2816 if (parse_long_name(&lfn, direntries + k) < 0) {
2817 fprintf(stderr, "Warning: non-ASCII filename\n");
2818 return -1;
bellardde167e42005-04-28 21:15:08 +00002819 }
bellarda0464332005-12-18 18:29:50 +00002820 /* no access to the direntry of a read-only file */
2821 else if (is_short_name(direntries+k) &&
2822 (direntries[k].attributes & 1)) {
2823 if (memcmp(direntries + k,
2824 array_get(&(s->directory), dir_index + k),
Anthony Liguoric227f092009-10-01 16:12:16 -05002825 sizeof(direntry_t))) {
bellarda0464332005-12-18 18:29:50 +00002826 fprintf(stderr, "Warning: tried to write to write-protected file\n");
2827 return -1;
bellardde167e42005-04-28 21:15:08 +00002828 }
bellardde167e42005-04-28 21:15:08 +00002829 }
2830 }
2831 }
bellarda0464332005-12-18 18:29:50 +00002832 i = mapping->end;
2833 } else
2834 i++;
bellardde167e42005-04-28 21:15:08 +00002835 }
bellarda0464332005-12-18 18:29:50 +00002836
2837 /*
2838 * Use qcow backend. Commit later.
2839 */
2840DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
Kevin Wolf7704df92011-11-08 10:50:12 +01002841 ret = bdrv_write(s->qcow, sector_num, buf, nb_sectors);
bellarda0464332005-12-18 18:29:50 +00002842 if (ret < 0) {
2843 fprintf(stderr, "Error writing to qcow backend\n");
2844 return ret;
2845 }
2846
2847 for (i = sector2cluster(s, sector_num);
2848 i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
2849 if (i >= 0)
2850 s->used_clusters[i] |= USED_ALLOCATED;
2851
2852DLOG(checkpoint());
2853 /* TODO: add timeout */
2854 try_commit(s);
2855
2856DLOG(checkpoint());
2857 return 0;
2858}
2859
Paolo Bonzinie183ef72011-10-20 13:16:23 +02002860static coroutine_fn int vvfat_co_write(BlockDriverState *bs, int64_t sector_num,
2861 const uint8_t *buf, int nb_sectors)
2862{
2863 int ret;
2864 BDRVVVFATState *s = bs->opaque;
2865 qemu_co_mutex_lock(&s->lock);
2866 ret = vvfat_write(bs, sector_num, buf, nb_sectors);
2867 qemu_co_mutex_unlock(&s->lock);
2868 return ret;
2869}
2870
Paolo Bonzinib6b8a332013-09-04 19:00:28 +02002871static int64_t coroutine_fn vvfat_co_get_block_status(BlockDriverState *bs,
bellarda0464332005-12-18 18:29:50 +00002872 int64_t sector_num, int nb_sectors, int* n)
2873{
2874 BDRVVVFATState* s = bs->opaque;
2875 *n = s->sector_count - sector_num;
Paolo Bonzini4bc74be2013-09-04 19:00:30 +02002876 if (*n > nb_sectors) {
2877 *n = nb_sectors;
2878 } else if (*n < 0) {
2879 return 0;
2880 }
2881 return BDRV_BLOCK_DATA;
bellarda0464332005-12-18 18:29:50 +00002882}
2883
2884static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
2885 const uint8_t* buffer, int nb_sectors) {
Kevin Wolf9217e262010-09-10 12:27:03 +02002886 BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
bellarda0464332005-12-18 18:29:50 +00002887 return try_commit(s);
2888}
2889
2890static void write_target_close(BlockDriverState *bs) {
Kevin Wolf9217e262010-09-10 12:27:03 +02002891 BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
Fam Zheng4f6fd342013-08-23 09:14:47 +08002892 bdrv_unref(s->qcow);
Stefan Weilce137822011-09-30 23:29:53 +02002893 g_free(s->qcow_filename);
bellarda0464332005-12-18 18:29:50 +00002894}
2895
2896static BlockDriver vvfat_write_target = {
Christoph Hellwigf9e96432009-05-27 16:14:13 +02002897 .format_name = "vvfat_write_target",
2898 .bdrv_write = write_target_commit,
2899 .bdrv_close = write_target_close,
bellarda0464332005-12-18 18:29:50 +00002900};
2901
Markus Armbruster68c70af2014-05-16 11:00:17 +02002902static int enable_write_target(BDRVVVFATState *s, Error **errp)
bellarda0464332005-12-18 18:29:50 +00002903{
Chunyan Liufacdbb02014-06-05 17:20:52 +08002904 BlockDriver *bdrv_qcow = NULL;
Chunyan Liufacdbb02014-06-05 17:20:52 +08002905 QemuOpts *opts = NULL;
Kevin Wolfa6552112010-09-10 12:27:04 +02002906 int ret;
bellarda0464332005-12-18 18:29:50 +00002907 int size = sector2cluster(s, s->sector_count);
2908 s->used_clusters = calloc(size, 1);
2909
Anthony Liguoric227f092009-10-01 16:12:16 -05002910 array_init(&(s->commits), sizeof(commit_t));
bellarda0464332005-12-18 18:29:50 +00002911
Anthony Liguori7267c092011-08-20 22:09:37 -05002912 s->qcow_filename = g_malloc(1024);
Jim Meyeringeba25052012-05-28 09:27:54 +02002913 ret = get_tmp_filename(s->qcow_filename, 1024);
2914 if (ret < 0) {
Markus Armbruster68c70af2014-05-16 11:00:17 +02002915 error_setg_errno(errp, -ret, "can't create temporary file");
Fam Zheng78f27bd2013-07-17 17:57:37 +08002916 goto err;
Jim Meyeringeba25052012-05-28 09:27:54 +02002917 }
Kevin Wolf91a073a2009-05-27 14:48:06 +02002918
2919 bdrv_qcow = bdrv_find_format("qcow");
Chunyan Liuc282e1f2014-06-05 17:21:11 +08002920 opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort);
Chunyan Liufacdbb02014-06-05 17:20:52 +08002921 qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512);
2922 qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:");
Kevin Wolf91a073a2009-05-27 14:48:06 +02002923
Chunyan Liuc282e1f2014-06-05 17:21:11 +08002924 ret = bdrv_create(bdrv_qcow, s->qcow_filename, opts, errp);
Chunyan Liufacdbb02014-06-05 17:20:52 +08002925 qemu_opts_del(opts);
Fam Zheng78f27bd2013-07-17 17:57:37 +08002926 if (ret < 0) {
2927 goto err;
2928 }
Kevin Wolfa6552112010-09-10 12:27:04 +02002929
Max Reitzf67503e2014-02-18 18:33:05 +01002930 s->qcow = NULL;
Max Reitzddf56362014-02-18 18:33:06 +01002931 ret = bdrv_open(&s->qcow, s->qcow_filename, NULL, NULL,
Markus Armbruster68c70af2014-05-16 11:00:17 +02002932 BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH,
2933 bdrv_qcow, errp);
Kevin Wolfa6552112010-09-10 12:27:04 +02002934 if (ret < 0) {
Fam Zheng78f27bd2013-07-17 17:57:37 +08002935 goto err;
Kevin Wolfd6e90982010-03-31 14:40:27 +02002936 }
bellarda0464332005-12-18 18:29:50 +00002937
2938#ifndef _WIN32
2939 unlink(s->qcow_filename);
2940#endif
2941
Fam Zheng920beae2014-05-23 21:29:46 +08002942 bdrv_set_backing_hd(s->bs, bdrv_new("", &error_abort));
bellarda0464332005-12-18 18:29:50 +00002943 s->bs->backing_hd->drv = &vvfat_write_target;
Markus Armbruster5839e532014-08-19 10:31:08 +02002944 s->bs->backing_hd->opaque = g_new(void *, 1);
Kevin Wolf9217e262010-09-10 12:27:03 +02002945 *(void**)s->bs->backing_hd->opaque = s;
bellarda0464332005-12-18 18:29:50 +00002946
bellardde167e42005-04-28 21:15:08 +00002947 return 0;
Fam Zheng78f27bd2013-07-17 17:57:37 +08002948
2949err:
2950 g_free(s->qcow_filename);
2951 s->qcow_filename = NULL;
2952 return ret;
bellardde167e42005-04-28 21:15:08 +00002953}
2954
2955static void vvfat_close(BlockDriverState *bs)
2956{
2957 BDRVVVFATState *s = bs->opaque;
2958
2959 vvfat_close_current_file(s);
2960 array_free(&(s->fat));
2961 array_free(&(s->directory));
2962 array_free(&(s->mapping));
Stefan Weilce137822011-09-30 23:29:53 +02002963 g_free(s->cluster_buffer);
Kevin Wolf3397f0c2011-11-22 16:52:13 +01002964
2965 if (s->qcow) {
2966 migrate_del_blocker(s->migration_blocker);
2967 error_free(s->migration_blocker);
2968 }
bellardde167e42005-04-28 21:15:08 +00002969}
2970
Anthony Liguori5efa9d52009-05-09 17:03:42 -05002971static BlockDriver bdrv_vvfat = {
Kevin Wolf7ad9be62013-04-12 19:42:04 +02002972 .format_name = "vvfat",
2973 .protocol_name = "fat",
2974 .instance_size = sizeof(BDRVVVFATState),
2975
2976 .bdrv_parse_filename = vvfat_parse_filename,
2977 .bdrv_file_open = vvfat_open,
2978 .bdrv_close = vvfat_close,
2979 .bdrv_rebind = vvfat_rebind,
2980
2981 .bdrv_read = vvfat_co_read,
2982 .bdrv_write = vvfat_co_write,
Paolo Bonzinib6b8a332013-09-04 19:00:28 +02002983 .bdrv_co_get_block_status = vvfat_co_get_block_status,
bellardde167e42005-04-28 21:15:08 +00002984};
2985
Anthony Liguori5efa9d52009-05-09 17:03:42 -05002986static void bdrv_vvfat_init(void)
2987{
2988 bdrv_register(&bdrv_vvfat);
2989}
2990
2991block_init(bdrv_vvfat_init);
2992
bellarda0464332005-12-18 18:29:50 +00002993#ifdef DEBUG
blueswir13f47aa82008-03-09 06:59:01 +00002994static void checkpoint(void) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002995 assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
bellarda0464332005-12-18 18:29:50 +00002996 check1(vvv);
2997 check2(vvv);
2998 assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
2999#if 0
Anthony Liguoric227f092009-10-01 16:12:16 -05003000 if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
bellarda0464332005-12-18 18:29:50 +00003001 fprintf(stderr, "Nonono!\n");
Anthony Liguoric227f092009-10-01 16:12:16 -05003002 mapping_t* mapping;
3003 direntry_t* direntry;
bellarda0464332005-12-18 18:29:50 +00003004 assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
3005 assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
3006 if (vvv->mapping.next<47)
3007 return;
3008 assert((mapping = array_get(&(vvv->mapping), 47)));
3009 assert(mapping->dir_index < vvv->directory.next);
3010 direntry = array_get(&(vvv->directory), mapping->dir_index);
3011 assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0);
3012#endif
bellarda0464332005-12-18 18:29:50 +00003013}
3014#endif