]> git.proxmox.com Git - qemu.git/blame - block-vvfat.c
-no-fd-bootchk option (Lonnie Mendez)
[qemu.git] / block-vvfat.c
Content-type: text/html ]> git.proxmox.com Git - qemu.git/blame - block-vvfat.c


500 - Internal Server Error

Malformed UTF-8 character (fatal) at (eval 6) line 1, <$fd> line 2453.
CommitLineData
a046433a 1/* vim:set shiftwidth=4 ts=8: */
de167e41
FB
2/*
3 * QEMU Block driver for virtual VFAT (shadows a local directory)
4 *
a046433a 5 * Copyright (c) 2004,2005 Johannes E. Schindelin
de167e41
FB
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25#include <sys/stat.h>
26#include <dirent.h>
27#include <assert.h>
28#include "vl.h"
29#include "block_int.h"
30
a046433a
FB
31#ifndef S_IWGRP
32#define S_IWGRP 0
33#endif
34#ifndef S_IWOTH
35#define S_IWOTH 0
36#endif
37
38/* TODO: add ":bootsector=blabla.img:" */
39/* LATER TODO: add automatic boot sector generation from
40 BOOTEASY.ASM and Ranish Partition Manager
41 Note that DOS assumes the system files to be the first files in the
42 file system (test if the boot sector still relies on that fact)! */
43/* MAYBE TODO: write block-visofs.c */
44/* TODO: call try_commit() only after a timeout */
45
46/* #define DEBUG */
47
48#ifdef DEBUG
49
50#define DLOG(a) a
51
52#undef stderr
53#define stderr STDERR
54FILE* stderr = NULL;
de167e41 55
a046433a 56static void checkpoint();
de167e41 57
a046433a
FB
58#ifdef __MINGW32__
59void nonono(const char* file, int line, const char* msg) {
60 fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg);
61 exit(-5);
62}
63#undef assert
64#define assert(a) if (!(a)) nonono(__FILE__, __LINE__, #a)
65#endif
66
67#else
68
69#define DLOG(a)
70
71#endif
de167e41
FB
72
73/* dynamic array functions */
74typedef struct array_t {
75 char* pointer;
76 unsigned int size,next,item_size;
77} array_t;
78
79static inline void array_init(array_t* array,unsigned int item_size)
80{
81 array->pointer=0;
82 array->size=0;
83 array->next=0;
84 array->item_size=item_size;
85}
86
87static inline void array_free(array_t* array)
88{
89 if(array->pointer)
90 free(array->pointer);
91 array->size=array->next=0;
92}
93
a046433a 94/* does not automatically grow */
de167e41 95static inline void* array_get(array_t* array,unsigned int index) {
a046433a
FB
96 assert(index >= 0);
97 assert(index < array->next);
98 return array->pointer + index * array->item_size;
99}
100
101static inline int array_ensure_allocated(array_t* array, int index)
102{
103 if((index + 1) * array->item_size > array->size) {
104 int new_size = (index + 32) * array->item_size;
105 array->pointer = realloc(array->pointer, new_size);
106 if (!array->pointer)
107 return -1;
108 array->size = new_size;
109 array->next = index + 1;
de167e41 110 }
a046433a
FB
111
112 return 0;
de167e41
FB
113}
114
115static inline void* array_get_next(array_t* array) {
a046433a
FB
116 unsigned int next = array->next;
117 void* result;
118
119 if (array_ensure_allocated(array, next) < 0)
120 return NULL;
121
122 array->next = next + 1;
123 result = array_get(array, next);
124
de167e41
FB
125 return result;
126}
127
128static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
129 if((array->next+count)*array->item_size>array->size) {
130 int increment=count*array->item_size;
131 array->pointer=realloc(array->pointer,array->size+increment);
132 if(!array->pointer)
133 return 0;
134 array->size+=increment;
135 }
136 memmove(array->pointer+(index+count)*array->item_size,
137 array->pointer+index*array->item_size,
138 (array->next-index)*array->item_size);
139 array->next+=count;
140 return array->pointer+index*array->item_size;
141}
142
143/* this performs a "roll", so that the element which was at index_from becomes
144 * index_to, but the order of all other elements is preserved. */
145static inline int array_roll(array_t* array,int index_to,int index_from,int count)
146{
147 char* buf;
148 char* from;
149 char* to;
150 int is;
151
152 if(!array ||
153 index_to<0 || index_to>=array->next ||
154 index_from<0 || index_from>=array->next)
155 return -1;
156
157 if(index_to==index_from)
158 return 0;
159
160 is=array->item_size;
161 from=array->pointer+index_from*is;
162 to=array->pointer+index_to*is;
163 buf=malloc(is*count);
164 memcpy(buf,from,is*count);
165
166 if(index_to<index_from)
167 memmove(to+is*count,to,from-to);
168 else
169 memmove(from,from+is*count,to-from);
170
171 memcpy(to,buf,is*count);
172
173 free(buf);
174
175 return 0;
176}
177
a046433a 178inline int array_remove_slice(array_t* array,int index, int count)
de167e41 179{
a046433a
FB
180 assert(index >=0);
181 assert(count > 0);
182 assert(index + count <= array->next);
183 if(array_roll(array,array->next-1,index,count))
de167e41 184 return -1;
a046433a 185 array->next -= count;
de167e41
FB
186 return 0;
187}
188
a046433a
FB
189int array_remove(array_t* array,int index)
190{
191 return array_remove_slice(array, index, 1);
192}
193
194/* return the index for a given member */
195int array_index(array_t* array, void* pointer)
196{
197 size_t offset = (char*)pointer - array->pointer;
198 assert(offset >= 0);
199 assert((offset % array->item_size) == 0);
200 assert(offset/array->item_size < array->next);
201 return offset/array->item_size;
202}
203
de167e41
FB
204/* These structures are used to fake a disk and the VFAT filesystem.
205 * For this reason we need to use __attribute__((packed)). */
206
207typedef struct bootsector_t {
208 uint8_t jump[3];
209 uint8_t name[8];
210 uint16_t sector_size;
211 uint8_t sectors_per_cluster;
212 uint16_t reserved_sectors;
213 uint8_t number_of_fats;
214 uint16_t root_entries;
a046433a 215 uint16_t total_sectors16;
de167e41
FB
216 uint8_t media_type;
217 uint16_t sectors_per_fat;
218 uint16_t sectors_per_track;
219 uint16_t number_of_heads;
220 uint32_t hidden_sectors;
221 uint32_t total_sectors;
222 union {
223 struct {
224 uint8_t drive_number;
225 uint8_t current_head;
226 uint8_t signature;
227 uint32_t id;
228 uint8_t volume_label[11];
229 } __attribute__((packed)) fat16;
230 struct {
231 uint32_t sectors_per_fat;
232 uint16_t flags;
233 uint8_t major,minor;
234 uint32_t first_cluster_of_root_directory;
235 uint16_t info_sector;
236 uint16_t backup_boot_sector;
237 uint16_t ignored;
238 } __attribute__((packed)) fat32;
239 } u;
240 uint8_t fat_type[8];
241 uint8_t ignored[0x1c0];
242 uint8_t magic[2];
243} __attribute__((packed)) bootsector_t;
244
245typedef struct partition_t {
246 uint8_t attributes; /* 0x80 = bootable */
247 uint8_t start_head;
248 uint8_t start_sector;
249 uint8_t start_cylinder;
a046433a 250 uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xb = FAT32 */
de167e41
FB
251 uint8_t end_head;
252 uint8_t end_sector;
253 uint8_t end_cylinder;
254 uint32_t start_sector_long;
255 uint32_t end_sector_long;
256} __attribute__((packed)) partition_t;
257
258typedef struct mbr_t {
259 uint8_t ignored[0x1be];
260 partition_t partition[4];
261 uint8_t magic[2];
262} __attribute__((packed)) mbr_t;
263
264typedef struct direntry_t {
265 uint8_t name[8];
266 uint8_t extension[3];
267 uint8_t attributes;
268 uint8_t reserved[2];
269 uint16_t ctime;
270 uint16_t cdate;
271 uint16_t adate;
272 uint16_t begin_hi;
273 uint16_t mtime;
274 uint16_t mdate;
275 uint16_t begin;
276 uint32_t size;
277} __attribute__((packed)) direntry_t;
278
279/* this structure are used to transparently access the files */
280
281typedef struct mapping_t {
a046433a
FB
282 /* begin is the first cluster, end is the last+1 */
283 uint32_t begin,end;
de167e41
FB
284 /* as s->directory is growable, no pointer may be used here */
285 unsigned int dir_index;
a046433a
FB
286 /* the clusters of a file may be in any order; this points to the first */
287 int first_mapping_index;
288 union {
289 /* offset is
290 * - the offset in the file (in clusters) for a file, or
291 * - the next cluster of the directory for a directory, and
292 * - the address of the buffer for a faked entry
293 */
294 struct {
295 uint32_t offset;
296 } file;
297 struct {
298 int parent_mapping_index;
299 int first_dir_index;
300 } dir;
301 } info;
302 /* path contains the full path, i.e. it always starts with s->path */
303 char* path;
304
305 enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2,
306 MODE_DIRECTORY = 4, MODE_FAKED = 8,
307 MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
308 int read_only;
de167e41
FB
309} mapping_t;
310
a046433a
FB
311#ifdef DEBUG
312static void print_direntry(const struct direntry_t*);
313static void print_mapping(const struct mapping_t* mapping);
314#endif
de167e41
FB
315
316/* here begins the real VVFAT driver */
317
318typedef struct BDRVVVFATState {
a046433a 319 BlockDriverState* bs; /* pointer to parent */
de167e41
FB
320 unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
321 unsigned char first_sectors[0x40*0x200];
322
323 int fat_type; /* 16 or 32 */
324 array_t fat,directory,mapping;
325
326 unsigned int cluster_size;
327 unsigned int sectors_per_cluster;
328 unsigned int sectors_per_fat;
329 unsigned int sectors_of_root_directory;
a046433a 330 uint32_t last_cluster_of_root_directory;
de167e41
FB
331 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 */
de167e41
FB
334 uint32_t max_fat_value;
335
336 int current_fd;
de167e41 337 mapping_t* current_mapping;
a046433a
FB
338 unsigned char* cluster; /* points to current cluster */
339 unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
de167e41
FB
340 unsigned int current_cluster;
341
342 /* write support */
a046433a
FB
343 BlockDriverState* write_target;
344 char* qcow_filename;
345 BlockDriverState* qcow;
346 void* fat2;
347 char* used_clusters;
348 array_t commits;
349 const char* path;
350 int downcase_short_names;
de167e41
FB
351} BDRVVVFATState;
352
353
354static int vvfat_probe(const uint8_t *buf, int buf_size, const char *filename)
355{
a046433a 356 if (strstart(filename, "fat:", NULL))
de167e41
FB
357 return 100;
358 return 0;
359}
360
361static void init_mbr(BDRVVVFATState* s)
362{
363 /* TODO: if the files mbr.img and bootsect.img exist, use them */
364 mbr_t* real_mbr=(mbr_t*)s->first_sectors;
365 partition_t* partition=&(real_mbr->partition[0]);
366
367 memset(s->first_sectors,0,512);
368
369 partition->attributes=0x80; /* bootable */
370 partition->start_head=1;
371 partition->start_sector=1;
372 partition->start_cylinder=0;
a046433a
FB
373 /* FAT12/FAT16/FAT32 */
374 partition->fs_type=(s->fat_type==12?0x1:s->fat_type==16?0x6:0xb);
375 partition->end_head=s->bs->heads-1;
de167e41
FB
376 partition->end_sector=0xff; /* end sector & upper 2 bits of cylinder */;
377 partition->end_cylinder=0xff; /* lower 8 bits of end cylinder */;
a046433a 378 partition->start_sector_long=cpu_to_le32(s->bs->secs);
de167e41
FB
379 partition->end_sector_long=cpu_to_le32(s->sector_count);
380
381 real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
382}
383
a046433a
FB
384/* direntry functions */
385
de167e41
FB
386/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
387static inline int short2long_name(unsigned char* dest,const char* src)
388{
389 int i;
390 for(i=0;i<129 && src[i];i++) {
391 dest[2*i]=src[i];
392 dest[2*i+1]=0;
393 }
394 dest[2*i]=dest[2*i+1]=0;
395 for(i=2*i+2;(i%26);i++)
396 dest[i]=0xff;
397 return i;
398}
399
400static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
401{
402 char buffer[258];
403 int length=short2long_name(buffer,filename),
404 number_of_entries=(length+25)/26,i;
405 direntry_t* entry;
406
407 for(i=0;i<number_of_entries;i++) {
408 entry=array_get_next(&(s->directory));
409 entry->attributes=0xf;
410 entry->reserved[0]=0;
411 entry->begin=0;
412 entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
413 }
414 for(i=0;i<length;i++) {
415 int offset=(i%26);
416 if(offset<10) offset=1+offset;
417 else if(offset<22) offset=14+offset-10;
418 else offset=28+offset-22;
419 entry=array_get(&(s->directory),s->directory.next-1-(i/26));
420 entry->name[offset]=buffer[i];
421 }
422 return array_get(&(s->directory),s->directory.next-number_of_entries);
423}
424
a046433a
FB
425static char is_free(const direntry_t* direntry)
426{
427 /* return direntry->name[0]==0 ; */
428 return direntry->attributes == 0 || direntry->name[0]==0xe5;
429}
430
431static char is_volume_label(const direntry_t* direntry)
432{
433 return direntry->attributes == 0x28;
434}
435
436static char is_long_name(const direntry_t* direntry)
437{
438 return direntry->attributes == 0xf;
439}
440
441static char is_short_name(const direntry_t* direntry)
442{
443 return !is_volume_label(direntry) && !is_long_name(direntry)
444 && !is_free(direntry);
445}
446
447static char is_directory(const direntry_t* direntry)
448{
449 return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
450}
451
452static inline char is_dot(const direntry_t* direntry)
453{
454 return is_short_name(direntry) && direntry->name[0] == '.';
455}
456
457static char is_file(const direntry_t* direntry)
458{
459 return is_short_name(direntry) && !is_directory(direntry);
460}
461
462static inline uint32_t begin_of_direntry(const direntry_t* direntry)
463{
464 return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
465}
466
467static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
468{
469 return le32_to_cpu(direntry->size);
470}
471
472static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
473{
474 direntry->begin = cpu_to_le16(begin & 0xffff);
475 direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
476}
477
de167e41
FB
478/* fat functions */
479
a046433a 480static inline uint8_t fat_chksum(const direntry_t* entry)
de167e41
FB
481{
482 uint8_t chksum=0;
483 int i;
484
485 for(i=0;i<11;i++)
486 chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0))
487 +(unsigned char)entry->name[i];
488
489 return chksum;
490}
491
492/* if return_time==0, this returns the fat_date, else the fat_time */
493static uint16_t fat_datetime(time_t time,int return_time) {
494 struct tm* t;
495#ifdef _WIN32
496 t=localtime(&time); /* this is not thread safe */
497#else
498 struct tm t1;
499 t=&t1;
500 localtime_r(&time,t);
501#endif
502 if(return_time)
503 return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
504 return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
505}
506
507static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
508{
a046433a
FB
509 if(s->fat_type==32) {
510 uint32_t* entry=array_get(&(s->fat),cluster);
511 *entry=cpu_to_le32(value);
de167e41
FB
512 } else if(s->fat_type==16) {
513 uint16_t* entry=array_get(&(s->fat),cluster);
514 *entry=cpu_to_le16(value&0xffff);
515 } else {
a046433a
FB
516 int offset = (cluster*3/2);
517 unsigned char* p = array_get(&(s->fat), offset);
518 switch (cluster&1) {
519 case 0:
520 p[0] = value&0xff;
521 p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
522 break;
523 case 1:
524 p[0] = (p[0]&0xf) | ((value&0xf)<<4);
525 p[1] = (value>>4);
526 break;
527 }
de167e41
FB
528 }
529}
530
531static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
532{
a046433a
FB
533 if(s->fat_type==32) {
534 uint32_t* entry=array_get(&(s->fat),cluster);
535 return le32_to_cpu(*entry);
de167e41
FB
536 } else if(s->fat_type==16) {
537 uint16_t* entry=array_get(&(s->fat),cluster);
538 return le16_to_cpu(*entry);
539 } else {
a046433a
FB
540 const uint8_t* x=s->fat.pointer+cluster*3/2;
541 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
de167e41
FB
542 }
543}
544
545static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
546{
547 if(fat_entry>s->max_fat_value-8)
548 return -1;
549 return 0;
550}
551
552static inline void init_fat(BDRVVVFATState* s)
553{
a046433a
FB
554 if (s->fat_type == 12) {
555 array_init(&(s->fat),1);
556 array_ensure_allocated(&(s->fat),
557 s->sectors_per_fat * 0x200 * 3 / 2 - 1);
558 } else {
559 array_init(&(s->fat),(s->fat_type==32?4:2));
560 array_ensure_allocated(&(s->fat),
561 s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
562 }
de167e41 563 memset(s->fat.pointer,0,s->fat.size);
de167e41 564
de167e41
FB
565 switch(s->fat_type) {
566 case 12: s->max_fat_value=0xfff; break;
567 case 16: s->max_fat_value=0xffff; break;
a046433a 568 case 32: s->max_fat_value=0x0fffffff; break;
de167e41
FB
569 default: s->max_fat_value=0; /* error... */
570 }
571
572}
573
a046433a
FB
574/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
575/* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
576static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
577 unsigned int directory_start, const char* filename, int is_dot)
de167e41 578{
a046433a 579 int i,j,long_index=s->directory.next;
de167e41
FB
580 direntry_t* entry=0;
581 direntry_t* entry_long=0;
582
583 if(is_dot) {
584 entry=array_get_next(&(s->directory));
585 memset(entry->name,0x20,11);
586 memcpy(entry->name,filename,strlen(filename));
587 return entry;
588 }
589
de167e41 590 entry_long=create_long_filename(s,filename);
a046433a
FB
591
592 i = strlen(filename);
593 for(j = i - 1; j>0 && filename[j]!='.';j--);
594 if (j > 0)
595 i = (j > 8 ? 8 : j);
596 else if (i > 8)
597 i = 8;
598
de167e41
FB
599 entry=array_get_next(&(s->directory));
600 memset(entry->name,0x20,11);
601 strncpy(entry->name,filename,i);
602
a046433a
FB
603 if(j > 0)
604 for (i = 0; i < 3 && filename[j+1+i]; i++)
605 entry->extension[i] = filename[j+1+i];
de167e41
FB
606
607 /* upcase & remove unwanted characters */
608 for(i=10;i>=0;i--) {
a046433a 609 if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
de167e41 610 if(entry->name[i]<=' ' || entry->name[i]>0x7f
a046433a 611 || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
de167e41
FB
612 entry->name[i]='_';
613 else if(entry->name[i]>='a' && entry->name[i]<='z')
614 entry->name[i]+='A'-'a';
615 }
616
617 /* mangle duplicates */
618 while(1) {
619 direntry_t* entry1=array_get(&(s->directory),directory_start);
620 int j;
621
622 for(;entry1<entry;entry1++)
a046433a 623 if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
de167e41
FB
624 break; /* found dupe */
625 if(entry1==entry) /* no dupe found */
626 break;
627
628 /* use all 8 characters of name */
629 if(entry->name[7]==' ') {
630 int j;
631 for(j=6;j>0 && entry->name[j]==' ';j--)
632 entry->name[j]='~';
633 }
634
635 /* increment number */
636 for(j=7;j>0 && entry->name[j]=='9';j--)
637 entry->name[j]='0';
638 if(j>0) {
639 if(entry->name[j]<'0' || entry->name[j]>'9')
640 entry->name[j]='0';
641 else
642 entry->name[j]++;
643 }
644 }
645
646 /* calculate checksum; propagate to long name */
647 if(entry_long) {
648 uint8_t chksum=fat_chksum(entry);
649
650 /* calculate anew, because realloc could have taken place */
651 entry_long=array_get(&(s->directory),long_index);
a046433a 652 while(entry_long<entry && is_long_name(entry_long)) {
de167e41
FB
653 entry_long->reserved[1]=chksum;
654 entry_long++;
655 }
656 }
657
658 return entry;
659}
660
a046433a
FB
661/*
662 * Read a directory. (the index of the corresponding mapping must be passed).
663 */
664static int read_directory(BDRVVVFATState* s, int mapping_index)
de167e41 665{
a046433a
FB
666 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
667 direntry_t* direntry;
668 const char* dirname = mapping->path;
669 int first_cluster = mapping->begin;
670 int parent_index = mapping->info.dir.parent_mapping_index;
671 mapping_t* parent_mapping = (mapping_t*)
672 (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : 0);
673 int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
de167e41
FB
674
675 DIR* dir=opendir(dirname);
676 struct dirent* entry;
de167e41
FB
677 int i;
678
a046433a
FB
679 assert(mapping->mode & MODE_DIRECTORY);
680
681 if(!dir) {
682 mapping->end = mapping->begin;
de167e41 683 return -1;
a046433a
FB
684 }
685
686 i = mapping->info.dir.first_dir_index =
687 first_cluster == 0 ? 0 : s->directory.next;
688
689 /* actually read the directory, and allocate the mappings */
de167e41
FB
690 while((entry=readdir(dir))) {
691 unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
692 char* buffer;
693 direntry_t* direntry;
a046433a 694 struct stat st;
de167e41
FB
695 int is_dot=!strcmp(entry->d_name,".");
696 int is_dotdot=!strcmp(entry->d_name,"..");
697
a046433a 698 if(first_cluster == 0 && (is_dotdot || is_dot))
de167e41
FB
699 continue;
700
701 buffer=(char*)malloc(length);
a046433a 702 assert(buffer);
de167e41
FB
703 snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
704
705 if(stat(buffer,&st)<0) {
706 free(buffer);
707 continue;
708 }
709
710 /* create directory entry for this file */
a046433a
FB
711 direntry=create_short_and_long_name(s, i, entry->d_name,
712 is_dot || is_dotdot);
de167e41
FB
713 direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
714 direntry->reserved[0]=direntry->reserved[1]=0;
715 direntry->ctime=fat_datetime(st.st_ctime,1);
716 direntry->cdate=fat_datetime(st.st_ctime,0);
717 direntry->adate=fat_datetime(st.st_atime,0);
718 direntry->begin_hi=0;
719 direntry->mtime=fat_datetime(st.st_mtime,1);
720 direntry->mdate=fat_datetime(st.st_mtime,0);
721 if(is_dotdot)
a046433a 722 set_begin_of_direntry(direntry, first_cluster_of_parent);
de167e41 723 else if(is_dot)
a046433a 724 set_begin_of_direntry(direntry, first_cluster);
de167e41 725 else
a046433a
FB
726 direntry->begin=0; /* do that later */
727 if (st.st_size > 0x7fffffff) {
728 fprintf(stderr, "File %s is larger than 2GB\n", buffer);
729 free(buffer);
730 return -2;
731 }
732 direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
de167e41
FB
733
734 /* create mapping for this file */
a046433a
FB
735 if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
736 s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
de167e41
FB
737 s->current_mapping->begin=0;
738 s->current_mapping->end=st.st_size;
a046433a
FB
739 /*
740 * we get the direntry of the most recent direntry, which
741 * contains the short name and all the relevant information.
742 */
de167e41 743 s->current_mapping->dir_index=s->directory.next-1;
a046433a
FB
744 s->current_mapping->first_mapping_index = -1;
745 if (S_ISDIR(st.st_mode)) {
746 s->current_mapping->mode = MODE_DIRECTORY;
747 s->current_mapping->info.dir.parent_mapping_index =
748 mapping_index;
749 } else {
750 s->current_mapping->mode = MODE_UNDEFINED;
751 s->current_mapping->info.file.offset = 0;
752 }
753 s->current_mapping->path=buffer;
754 s->current_mapping->read_only =
755 (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
de167e41
FB
756 }
757 }
758 closedir(dir);
759
760 /* fill with zeroes up to the end of the cluster */
761 while(s->directory.next%(0x10*s->sectors_per_cluster)) {
762 direntry_t* direntry=array_get_next(&(s->directory));
763 memset(direntry,0,sizeof(direntry_t));
764 }
765
a046433a
FB
766/* TODO: if there are more entries, bootsector has to be adjusted! */
767#define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
768 if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
769 /* root directory */
770 int cur = s->directory.next;
771 array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
772 memset(array_get(&(s->directory), cur), 0,
773 (ROOT_ENTRIES - cur) * sizeof(direntry_t));
de167e41 774 }
a046433a
FB
775
776 /* reget the mapping, since s->mapping was possibly realloc()ed */
777 mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
778 first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
779 * 0x20 / s->cluster_size;
780 mapping->end = first_cluster;
781
782 direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
783 set_begin_of_direntry(direntry, mapping->begin);
784
785 return 0;
786}
de167e41 787
a046433a
FB
788static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
789{
790 return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
791}
de167e41 792
a046433a
FB
793static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
794{
795 return s->faked_sectors + s->sectors_per_cluster * cluster_num;
796}
de167e41 797
a046433a
FB
798static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
799{
800 return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
801}
de167e41 802
a046433a
FB
803#ifdef DBG
804static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
805{
806 if(mapping->mode==MODE_UNDEFINED)
807 return 0;
808 return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
de167e41 809}
a046433a 810#endif
de167e41 811
a046433a
FB
812static int init_directories(BDRVVVFATState* s,
813 const char* dirname)
de167e41 814{
a046433a
FB
815 bootsector_t* bootsector;
816 mapping_t* mapping;
de167e41
FB
817 unsigned int i;
818 unsigned int cluster;
819
820 memset(&(s->first_sectors[0]),0,0x40*0x200);
821
de167e41 822 s->cluster_size=s->sectors_per_cluster*0x200;
a046433a
FB
823 s->cluster_buffer=malloc(s->cluster_size);
824 assert(s->cluster_buffer);
825
826 /*
827 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
828 * where sc is sector_count,
829 * spf is sectors_per_fat,
830 * spc is sectors_per_clusters, and
831 * fat_type = 12, 16 or 32.
832 */
833 i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
834 s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
de167e41
FB
835
836 array_init(&(s->mapping),sizeof(mapping_t));
837 array_init(&(s->directory),sizeof(direntry_t));
de167e41
FB
838
839 /* add volume label */
840 {
841 direntry_t* entry=array_get_next(&(s->directory));
842 entry->attributes=0x28; /* archive | volume label */
843 snprintf(entry->name,11,"QEMU VVFAT");
844 }
845
de167e41
FB
846 /* Now build FAT, and write back information into directory */
847 init_fat(s);
848
a046433a
FB
849 s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
850 s->cluster_count=sector2cluster(s, s->sector_count);
851
852 mapping = array_get_next(&(s->mapping));
853 mapping->begin = 0;
854 mapping->dir_index = 0;
855 mapping->info.dir.parent_mapping_index = -1;
856 mapping->first_mapping_index = -1;
857 mapping->path = strdup(dirname);
858 i = strlen(mapping->path);
859 if (i > 0 && mapping->path[i - 1] == '/')
860 mapping->path[i - 1] = '\0';
861 mapping->mode = MODE_DIRECTORY;
862 mapping->read_only = 0;
863 s->path = mapping->path;
864
865 for (i = 0, cluster = 0; i < s->mapping.next; i++) {
866 int j;
867 /* MS-DOS expects the FAT to be 0 for the root directory
868 * (except for the media byte). */
869 /* LATER TODO: still true for FAT32? */
870 int fix_fat = (i != 0);
871 mapping = array_get(&(s->mapping), i);
872
873 if (mapping->mode & MODE_DIRECTORY) {
874 mapping->begin = cluster;
875 if(read_directory(s, i)) {
876 fprintf(stderr, "Could not read directory %s\n",
877 mapping->path);
de167e41
FB
878 return -1;
879 }
a046433a
FB
880 mapping = array_get(&(s->mapping), i);
881 } else {
882 assert(mapping->mode == MODE_UNDEFINED);
de167e41 883 mapping->mode=MODE_NORMAL;
a046433a
FB
884 mapping->begin = cluster;
885 if (mapping->end > 0) {
886 direntry_t* direntry = array_get(&(s->directory),
887 mapping->dir_index);
888
889 mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
890 set_begin_of_direntry(direntry, mapping->begin);
891 } else {
892 mapping->end = cluster + 1;
893 fix_fat = 0;
de167e41 894 }
a046433a
FB
895 }
896
897 assert(mapping->begin < mapping->end);
898
899 /* fix fat for entry */
900 if (fix_fat) {
901 for(j = mapping->begin; j < mapping->end - 1; j++)
902 fat_set(s, j, j+1);
903 fat_set(s, mapping->end - 1, s->max_fat_value);
904 }
905
906 /* next free cluster */
907 cluster = mapping->end;
de167e41 908
a046433a
FB
909 if(cluster > s->cluster_count) {
910 fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type);
911 return -1;
de167e41
FB
912 }
913 }
914
a046433a
FB
915 mapping = array_get(&(s->mapping), 0);
916 s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
917 s->last_cluster_of_root_directory = mapping->end;
918
919 /* the FAT signature */
920 fat_set(s,0,s->max_fat_value);
921 fat_set(s,1,s->max_fat_value);
de167e41 922
a046433a
FB
923 s->current_mapping = NULL;
924
925 bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
de167e41
FB
926 bootsector->jump[0]=0xeb;
927 bootsector->jump[1]=0x3e;
928 bootsector->jump[2]=0x90;
929 memcpy(bootsector->name,"QEMU ",8);
930 bootsector->sector_size=cpu_to_le16(0x200);
931 bootsector->sectors_per_cluster=s->sectors_per_cluster;
932 bootsector->reserved_sectors=cpu_to_le16(1);
933 bootsector->number_of_fats=0x2; /* number of FATs */
934 bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
a046433a
FB
935 bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
936 bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
937 s->fat.pointer[0] = bootsector->media_type;
de167e41 938 bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
a046433a
FB
939 bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
940 bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
de167e41 941 bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
a046433a 942 bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
de167e41 943
a046433a
FB
944 /* LATER TODO: if FAT32, this is wrong */
945 bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
de167e41
FB
946 bootsector->u.fat16.current_head=0;
947 bootsector->u.fat16.signature=0x29;
948 bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
949
950 memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
951 memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12 ":s->fat_type==16?"FAT16 ":"FAT32 "),8);
952 bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
953
954 return 0;
955}
956
a046433a
FB
957static BDRVVVFATState *vvv = NULL;
958
959static int enable_write_target(BDRVVVFATState *s);
960static int is_consistent(BDRVVVFATState *s);
961
de167e41
FB
962static int vvfat_open(BlockDriverState *bs, const char* dirname)
963{
964 BDRVVVFATState *s = bs->opaque;
a046433a 965 int floppy = 0;
de167e41
FB
966 int i;
967
a046433a
FB
968 vvv = s;
969
970DLOG(if (stderr == NULL) {
971 stderr = fopen("vvfat.log", "a");
972 setbuf(stderr, NULL);
973})
974
975 s->bs = bs;
976
de167e41 977 s->fat_type=16;
a046433a 978 /* LATER TODO: if FAT32, adjust */
de167e41 979 s->sector_count=0xec04f;
a046433a
FB
980 s->sectors_per_cluster=0x10;
981 /* LATER TODO: this could be wrong for FAT32 */
982 bs->cyls=1023; bs->heads=15; bs->secs=63;
de167e41
FB
983
984 s->current_cluster=0xffffffff;
de167e41 985
de167e41 986 s->first_sectors_number=0x40;
a046433a
FB
987 /* read only is the default for safety */
988 bs->read_only = 1;
989 s->qcow = s->write_target = NULL;
990 s->qcow_filename = NULL;
991 s->fat2 = NULL;
992 s->downcase_short_names = 1;
de167e41 993
a046433a
FB
994 if (!strstart(dirname, "fat:", NULL))
995 return -1;
996
997 if (strstr(dirname, ":rw:")) {
998 if (enable_write_target(s))
999 return -1;
1000 bs->read_only = 0;
1001 }
1002
1003 if (strstr(dirname, ":floppy:")) {
1004 floppy = 1;
1005 s->fat_type = 12;
1006 s->first_sectors_number = 1;
1007 s->sectors_per_cluster=2;
1008 bs->cyls = 80; bs->heads = 2; bs->secs = 36;
1009 }
1010
1011 if (strstr(dirname, ":32:")) {
1012 fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1013 s->fat_type = 32;
1014 } else if (strstr(dirname, ":16:")) {
1015 s->fat_type = 16;
1016 } else if (strstr(dirname, ":12:")) {
1017 s->fat_type = 12;
1018 s->sector_count=2880;
de167e41 1019 }
a046433a
FB
1020
1021 i = strrchr(dirname, ':') - dirname;
1022 assert(i >= 3);
1023 if (dirname[i-2] == ':' && isalpha(dirname[i-1]))
1024 /* workaround for DOS drive names */
1025 dirname += i-1;
1026 else
1027 dirname += i+1;
1028
1029 bs->total_sectors=bs->cyls*bs->heads*bs->secs;
1030 if (s->sector_count > bs->total_sectors)
1031 s->sector_count = bs->total_sectors;
1032 if(init_directories(s, dirname))
de167e41
FB
1033 return -1;
1034
1035 if(s->first_sectors_number==0x40)
1036 init_mbr(s);
1037
a046433a
FB
1038 /* for some reason or other, MS-DOS does not like to know about CHS... */
1039 if (floppy)
1040 bs->heads = bs->cyls = bs->secs = 0;
1041
1042 // assert(is_consistent(s));
de167e41 1043
de167e41
FB
1044 return 0;
1045}
1046
1047static inline void vvfat_close_current_file(BDRVVVFATState *s)
1048{
1049 if(s->current_mapping) {
a046433a
FB
1050 s->current_mapping = NULL;
1051 if (s->current_fd) {
1052 close(s->current_fd);
1053 s->current_fd = 0;
1054 }
de167e41 1055 }
a046433a 1056 s->current_cluster = -1;
de167e41
FB
1057}
1058
1059/* mappings between index1 and index2-1 are supposed to be ordered
1060 * return value is the index of the last mapping for which end>cluster_num
1061 */
1062static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1063{
1064 int index3=index1+1;
de167e41
FB
1065 while(1) {
1066 mapping_t* mapping;
1067 index3=(index1+index2)/2;
1068 mapping=array_get(&(s->mapping),index3);
a046433a
FB
1069 assert(mapping->begin < mapping->end);
1070 if(mapping->begin>=cluster_num) {
de167e41
FB
1071 assert(index2!=index3 || index2==0);
1072 if(index2==index3)
a046433a 1073 return index1;
de167e41
FB
1074 index2=index3;
1075 } else {
1076 if(index1==index3)
a046433a 1077 return mapping->end<=cluster_num ? index2 : index1;
de167e41
FB
1078 index1=index3;
1079 }
1080 assert(index1<=index2);
a046433a
FB
1081 DLOG(mapping=array_get(&(s->mapping),index1);
1082 assert(mapping->begin<=cluster_num);
1083 assert(index2 >= s->mapping.next ||
1084 ((mapping = array_get(&(s->mapping),index2)) &&
1085 mapping->end>cluster_num)));
de167e41
FB
1086 }
1087}
1088
1089static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
1090{
1091 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
1092 mapping_t* mapping;
1093 if(index>=s->mapping.next)
1094 return 0;
1095 mapping=array_get(&(s->mapping),index);
1096 if(mapping->begin>cluster_num)
1097 return 0;
a046433a 1098 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
de167e41
FB
1099 return mapping;
1100}
1101
a046433a
FB
1102/*
1103 * This function simply compares path == mapping->path. Since the mappings
1104 * are sorted by cluster, this is expensive: O(n).
1105 */
1106static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
1107 const char* path)
1108{
1109 int i;
1110
1111 for (i = 0; i < s->mapping.next; i++) {
1112 mapping_t* mapping = array_get(&(s->mapping), i);
1113 if (mapping->first_mapping_index < 0 &&
1114 !strcmp(path, mapping->path))
1115 return mapping;
1116 }
1117
1118 return NULL;
1119}
1120
1121static int open_file(BDRVVVFATState* s,mapping_t* mapping)
de167e41
FB
1122{
1123 if(!mapping)
1124 return -1;
de167e41 1125 if(!s->current_mapping ||
a046433a 1126 strcmp(s->current_mapping->path,mapping->path)) {
de167e41 1127 /* open file */
a046433a 1128 int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
de167e41
FB
1129 if(fd<0)
1130 return -1;
1131 vvfat_close_current_file(s);
1132 s->current_fd = fd;
de167e41
FB
1133 s->current_mapping = mapping;
1134 }
1135 return 0;
1136}
1137
1138static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1139{
1140 if(s->current_cluster != cluster_num) {
1141 int result=0;
1142 off_t offset;
a046433a 1143 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
de167e41
FB
1144 if(!s->current_mapping
1145 || s->current_mapping->begin>cluster_num
1146 || s->current_mapping->end<=cluster_num) {
1147 /* binary search of mappings for file */
1148 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
a046433a
FB
1149
1150 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1151
1152 if (mapping && mapping->mode & MODE_DIRECTORY) {
1153 vvfat_close_current_file(s);
1154 s->current_mapping = mapping;
1155read_cluster_directory:
1156 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
1157 s->cluster = s->directory.pointer+offset
1158 + 0x20*s->current_mapping->info.dir.first_dir_index;
1159 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1160 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1161 s->current_cluster = cluster_num;
1162 return 0;
1163 }
1164
1165 if(open_file(s,mapping))
de167e41 1166 return -2;
a046433a
FB
1167 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1168 goto read_cluster_directory;
de167e41 1169
a046433a
FB
1170 assert(s->current_fd);
1171
1172 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
de167e41
FB
1173 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1174 return -3;
a046433a 1175 s->cluster=s->cluster_buffer;
de167e41
FB
1176 result=read(s->current_fd,s->cluster,s->cluster_size);
1177 if(result<0) {
1178 s->current_cluster = -1;
1179 return -1;
1180 }
1181 s->current_cluster = cluster_num;
1182 }
1183 return 0;
1184}
1185
a046433a
FB
1186#ifdef DEBUG
1187static void hexdump(const void* address, uint32_t len)
de167e41 1188{
a046433a
FB
1189 const unsigned char* p = address;
1190 int i, j;
1191
1192 for (i = 0; i < len; i += 16) {
1193 for (j = 0; j < 16 && i + j < len; j++)
1194 fprintf(stderr, "%02x ", p[i + j]);
1195 for (; j < 16; j++)
1196 fprintf(stderr, " ");
1197 fprintf(stderr, " ");
1198 for (j = 0; j < 16 && i + j < len; j++)
1199 fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
1200 fprintf(stderr, "\n");
de167e41 1201 }
de167e41
FB
1202}
1203
a046433a 1204static void print_direntry(const direntry_t* direntry)
de167e41 1205{
a046433a
FB
1206 int j = 0;
1207 char buffer[1024];
1208
1209 fprintf(stderr, "direntry 0x%x: ", (int)direntry);
de167e41
FB
1210 if(!direntry)
1211 return;
a046433a 1212 if(is_long_name(direntry)) {
de167e41
FB
1213 unsigned char* c=(unsigned char*)direntry;
1214 int i;
1215 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
a046433a
FB
1216