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