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