]> git.proxmox.com Git - qemu.git/blame - block-vvfat.c
Account for MacOS X ABI reserved space in linkage area (Andreas Faerber)
[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 2649.
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;
104 array->pointer = realloc(array->pointer, new_size);
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;
130 array->pointer=realloc(array->pointer,array->size+increment);
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);
ffe8ab83 628 strncpy((char*)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++) {
893 int j;
5fafdf24 894 /* MS-DOS expects the FAT to be 0 for the root directory
a046433a
FB
895 * (except for the media byte). */
896 /* LATER TODO: still true for FAT32? */
897 int fix_fat = (i != 0);
898 mapping = array_get(&(s->mapping), i);
899
900 if (mapping->mode & MODE_DIRECTORY) {
901 mapping->begin = cluster;
902 if(read_directory(s, i)) {
903 fprintf(stderr, "Could not read directory %s\n",
904 mapping->path);
de167e41
FB
905 return -1;
906 }
a046433a
FB
907 mapping = array_get(&(s->mapping), i);
908 } else {
909 assert(mapping->mode == MODE_UNDEFINED);
de167e41 910 mapping->mode=MODE_NORMAL;
a046433a
FB
911 mapping->begin = cluster;
912 if (mapping->end > 0) {
913 direntry_t* direntry = array_get(&(s->directory),
914 mapping->dir_index);
915
916 mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
917 set_begin_of_direntry(direntry, mapping->begin);
918 } else {
919 mapping->end = cluster + 1;
920 fix_fat = 0;
de167e41 921 }
a046433a
FB
922 }
923
924 assert(mapping->begin < mapping->end);
925
926 /* fix fat for entry */
927 if (fix_fat) {
928 for(j = mapping->begin; j < mapping->end - 1; j++)
929 fat_set(s, j, j+1);
930 fat_set(s, mapping->end - 1, s->max_fat_value);
931 }
932
933 /* next free cluster */
934 cluster = mapping->end;
de167e41 935
a046433a
FB
936 if(cluster > s->cluster_count) {
937 fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type);
938 return -1;
de167e41
FB
939 }
940 }
941
a046433a
FB
942 mapping = array_get(&(s->mapping), 0);
943 s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
944 s->last_cluster_of_root_directory = mapping->end;
945
946 /* the FAT signature */
947 fat_set(s,0,s->max_fat_value);
948 fat_set(s,1,s->max_fat_value);
de167e41 949
a046433a
FB
950 s->current_mapping = NULL;
951
952 bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
de167e41
FB
953 bootsector->jump[0]=0xeb;
954 bootsector->jump[1]=0x3e;
955 bootsector->jump[2]=0x90;
956 memcpy(bootsector->name,"QEMU ",8);
957 bootsector->sector_size=cpu_to_le16(0x200);
958 bootsector->sectors_per_cluster=s->sectors_per_cluster;
959 bootsector->reserved_sectors=cpu_to_le16(1);
960 bootsector->number_of_fats=0x2; /* number of FATs */
961 bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
a046433a
FB
962 bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
963 bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
964 s->fat.pointer[0] = bootsector->media_type;
de167e41 965 bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
a046433a
FB
966 bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
967 bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
de167e41 968 bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
a046433a 969 bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
de167e41 970
a046433a
FB
971 /* LATER TODO: if FAT32, this is wrong */
972 bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
de167e41
FB
973 bootsector->u.fat16.current_head=0;
974 bootsector->u.fat16.signature=0x29;
975 bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
976
977 memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
978 memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12 ":s->fat_type==16?"FAT16 ":"FAT32 "),8);
979 bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
980
981 return 0;
982}
983
83f64091 984#ifdef DEBUG
a046433a 985static BDRVVVFATState *vvv = NULL;
83f64091 986#endif
a046433a
FB
987
988static int enable_write_target(BDRVVVFATState *s);
989static int is_consistent(BDRVVVFATState *s);
990
83f64091 991static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
de167e41
FB
992{
993 BDRVVVFATState *s = bs->opaque;
a046433a 994 int floppy = 0;
de167e41
FB
995 int i;
996
83f64091 997#ifdef DEBUG
a046433a 998 vvv = s;
83f64091 999#endif
a046433a
FB
1000
1001DLOG(if (stderr == NULL) {
1002 stderr = fopen("vvfat.log", "a");
1003 setbuf(stderr, NULL);
1004})
1005
1006 s->bs = bs;
1007
de167e41 1008 s->fat_type=16;
a046433a 1009 /* LATER TODO: if FAT32, adjust */
a046433a 1010 s->sectors_per_cluster=0x10;
b570094d
TS
1011 /* 504MB disk*/
1012 bs->cyls=1024; bs->heads=16; bs->secs=63;
de167e41
FB
1013
1014 s->current_cluster=0xffffffff;
de167e41 1015
de167e41 1016 s->first_sectors_number=0x40;
a046433a
FB
1017 /* read only is the default for safety */
1018 bs->read_only = 1;
1019 s->qcow = s->write_target = NULL;
1020 s->qcow_filename = NULL;
1021 s->fat2 = NULL;
1022 s->downcase_short_names = 1;
3b46e624 1023
a046433a
FB
1024 if (!strstart(dirname, "fat:", NULL))
1025 return -1;
1026
a046433a
FB
1027 if (strstr(dirname, ":floppy:")) {
1028 floppy = 1;
1029 s->fat_type = 12;
1030 s->first_sectors_number = 1;
1031 s->sectors_per_cluster=2;
1032 bs->cyls = 80; bs->heads = 2; bs->secs = 36;
1033 }
1034
b570094d
TS
1035 s->sector_count=bs->cyls*bs->heads*bs->secs;
1036
a046433a
FB
1037 if (strstr(dirname, ":32:")) {
1038 fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1039 s->fat_type = 32;
1040 } else if (strstr(dirname, ":16:")) {
1041 s->fat_type = 16;
1042 } else if (strstr(dirname, ":12:")) {
1043 s->fat_type = 12;
1044 s->sector_count=2880;
de167e41 1045 }
a046433a 1046
b570094d
TS
1047 if (strstr(dirname, ":rw:")) {
1048 if (enable_write_target(s))
1049 return -1;
1050 bs->read_only = 0;
1051 }
1052
a046433a
FB
1053 i = strrchr(dirname, ':') - dirname;
1054 assert(i >= 3);
1055 if (dirname[i-2] == ':' && isalpha(dirname[i-1]))
1056 /* workaround for DOS drive names */
1057 dirname += i-1;
1058 else
1059 dirname += i+1;
1060
1061 bs->total_sectors=bs->cyls*bs->heads*bs->secs;
b570094d 1062
a046433a 1063 if(init_directories(s, dirname))
de167e41
FB
1064 return -1;
1065
b570094d
TS
1066 s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
1067
de167e41
FB
1068 if(s->first_sectors_number==0x40)
1069 init_mbr(s);
1070
a046433a
FB
1071 /* for some reason or other, MS-DOS does not like to know about CHS... */
1072 if (floppy)
1073 bs->heads = bs->cyls = bs->secs = 0;
1074
1075 // assert(is_consistent(s));
de167e41
FB
1076 return 0;
1077}
1078
1079static inline void vvfat_close_current_file(BDRVVVFATState *s)
1080{
1081 if(s->current_mapping) {
a046433a
FB
1082 s->current_mapping = NULL;
1083 if (s->current_fd) {
1084 close(s->current_fd);
1085 s->current_fd = 0;
1086 }
de167e41 1087 }
a046433a 1088 s->current_cluster = -1;
de167e41
FB
1089}
1090
1091/* mappings between index1 and index2-1 are supposed to be ordered
1092 * return value is the index of the last mapping for which end>cluster_num
1093 */
1094static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1095{
1096 int index3=index1+1;
de167e41
FB
1097 while(1) {
1098 mapping_t* mapping;
1099 index3=(index1+index2)/2;
1100 mapping=array_get(&(s->mapping),index3);
a046433a
FB
1101 assert(mapping->begin < mapping->end);
1102 if(mapping->begin>=cluster_num) {
de167e41
FB
1103 assert(index2!=index3 || index2==0);
1104 if(index2==index3)
a046433a 1105 return index1;
de167e41
FB
1106 index2=index3;
1107 } else {
1108 if(index1==index3)
a046433a 1109 return mapping->end<=cluster_num ? index2 : index1;
de167e41
FB
1110 index1=index3;
1111 }
1112 assert(index1<=index2);
a046433a
FB
1113 DLOG(mapping=array_get(&(s->mapping),index1);
1114 assert(mapping->begin<=cluster_num);
5fafdf24 1115 assert(index2 >= s->mapping.next ||
a046433a
FB
1116 ((mapping = array_get(&(s->mapping),index2)) &&
1117 mapping->end>cluster_num)));
de167e41
FB
1118 }
1119}
1120
1121static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
1122{
1123 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
1124 mapping_t* mapping;
1125 if(index>=s->mapping.next)
1126 return 0;
1127 mapping=array_get(&(s->mapping),index);
1128 if(mapping->begin>cluster_num)
1129 return 0;
a046433a 1130 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
de167e41
FB
1131 return mapping;
1132}
1133
a046433a
FB
1134/*
1135 * This function simply compares path == mapping->path. Since the mappings
1136 * are sorted by cluster, this is expensive: O(n).
1137 */
1138static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
1139 const char* path)
1140{
1141 int i;
1142
1143 for (i = 0; i < s->mapping.next; i++) {
1144 mapping_t* mapping = array_get(&(s->mapping), i);
1145 if (mapping->first_mapping_index < 0 &&
1146 !strcmp(path, mapping->path))
1147 return mapping;
1148 }
1149
1150 return NULL;
1151}
1152
1153static int open_file(BDRVVVFATState* s,mapping_t* mapping)
de167e41
FB
1154{
1155 if(!mapping)
1156 return -1;
de167e41 1157 if(!s->current_mapping ||
a046433a 1158 strcmp(s->current_mapping->path,mapping->path)) {
de167e41 1159 /* open file */
a046433a 1160 int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
de167e41
FB
1161 if(fd<0)
1162 return -1;
1163 vvfat_close_current_file(s);
1164 s->current_fd = fd;
de167e41
FB
1165 s->current_mapping = mapping;
1166 }
1167 return 0;
1168}
1169
1170static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1171{
1172 if(s->current_cluster != cluster_num) {
1173 int result=0;
1174 off_t offset;
a046433a 1175 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
de167e41
FB
1176 if(!s->current_mapping
1177 || s->current_mapping->begin>cluster_num
1178 || s->current_mapping->end<=cluster_num) {
1179 /* binary search of mappings for file */
1180 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
a046433a
FB
1181
1182 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1183
1184 if (mapping && mapping->mode & MODE_DIRECTORY) {
1185 vvfat_close_current_file(s);
1186 s->current_mapping = mapping;
1187read_cluster_directory:
1188 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
ffe8ab83 1189 s->cluster = (unsigned char*)s->directory.pointer+offset
a046433a
FB
1190 + 0x20*s->current_mapping->info.dir.first_dir_index;
1191 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1192 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1193 s->current_cluster = cluster_num;
1194 return 0;
1195 }
1196
1197 if(open_file(s,mapping))
de167e41 1198 return -2;
a046433a
FB
1199 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1200 goto read_cluster_directory;
de167e41 1201
a046433a
FB
1202 assert(s->current_fd);
1203
1204 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
de167e41
FB
1205 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1206 return -3;
a046433a 1207 s->cluster=s->cluster_buffer;
de167e41
FB
1208 result=read(s->current_fd,s->cluster,s->cluster_size);
1209 if(result<0) {
1210 s->current_cluster = -1;
1211 return -1;
1212 }
1213 s->current_cluster = cluster_num;
1214 }
1215 return 0;
1216}
1217
a046433a
FB
1218#ifdef DEBUG
1219static void hexdump(const void* address, uint32_t len)
de167e41 1220{
a046433a
FB
1221 const unsigned char* p = address;
1222 int i, j;
1223
1224 for (i = 0; i < len; i += 16) {
1225 for (j = 0; j < 16 && i + j < len; j++)
1226 fprintf(stderr, "%02x ", p[i + j]);
1227 for (; j < 16; j++)
1228 fprintf(stderr, " ");
1229 fprintf(stderr, " ");
1230 for (j = 0; j < 16 && i + j < len; j++)
1231 fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
1232 fprintf(stderr, "\n");
de167e41 1233 }
de167e41
FB
1234}
1235
a046433a 1236static void print_direntry(const direntry_t* direntry)
de167e41 1237{
a046433a
FB
1238 int j = 0;
1239 char buffer[1024];
1240
1241 fprintf(stderr, "direntry 0x%x: ", (int)direntry);
de167e41
FB
1242 if(!direntry)
1243 return;
a046433a 1244 if(is_long_name(direntry)) {
de167e41
FB
1245 unsigned char* c=(unsigned char*)direntry;
1246 int i;
1247 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
a046433a
FB
1248