]> git.proxmox.com Git - mirror_qemu.git/blame - block-vvfat.c
Fix wrong signedness, by Andre Przywara.
[mirror_qemu.git] / block-vvfat.c
Content-type: text/html ]> git.proxmox.com Git - mirror_qemu.git/blame - block-vvfat.c


500 - Internal Server Error

Malformed UTF-8 character (fatal) at (eval 6) line 1, <$fd> line 2607.
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
a046433a 56static void checkpoint();
de167e41 57
a046433a
FB
58#ifdef __MINGW32__
59void nonono(const char* file, int line, const char* msg) {
60 fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg);
61 exit(-5);
62}
63#undef assert
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;
418 for(i=0;i<129 && src[i];i++) {
419 dest[2*i]=src[i];
420 dest[2*i+1]=0;
421 }
422 dest[2*i]=dest[2*i+1]=0;
423 for(i=2*i+2;(i%26);i++)
424 dest[i]=0xff;
425 return i;
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 }
442 for(i=0;i<length;i++) {
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{
455 /* return direntry->name[0]==0 ; */
456 return direntry->attributes == 0 || direntry->name[0]==0xe5;
457}
458
459static char is_volume_label(const direntry_t* direntry)
460{
461 return direntry->attributes == 0x28;
462}
463
464static char is_long_name(const direntry_t* direntry)
465{
466 return direntry->attributes == 0xf;
467}
468
469static char is_short_name(const direntry_t* direntry)
470{
471 return !is_volume_label(direntry) && !is_long_name(direntry)
472 && !is_free(direntry);
473}
474
475static char is_directory(const direntry_t* direntry)
476{
477 return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
478}
479
480static inline char is_dot(const direntry_t* direntry)
481{
482 return is_short_name(direntry) && direntry->name[0] == '.';
483}
484
485static char is_file(const direntry_t* direntry)
486{
487 return is_short_name(direntry) && !is_directory(direntry);
488}
489
490static inline uint32_t begin_of_direntry(const direntry_t* direntry)
491{
492 return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
493}
494
495static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
496{
497 return le32_to_cpu(direntry->size);
498}
499
500static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
501{
502 direntry->begin = cpu_to_le16(begin & 0xffff);
503 direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
504}
505
de167e41
FB
506/* fat functions */
507
a046433a 508static inline uint8_t fat_chksum(const direntry_t* entry)
de167e41
FB
509{
510 uint8_t chksum=0;
511 int i;
512
513 for(i=0;i<11;i++)
514 chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0))
515 +(unsigned char)entry->name[i];
3b46e624 516
de167e41
FB
517 return chksum;
518}
519
520/* if return_time==0, this returns the fat_date, else the fat_time */
521static uint16_t fat_datetime(time_t time,int return_time) {
522 struct tm* t;
523#ifdef _WIN32
524 t=localtime(&time); /* this is not thread safe */
525#else
526 struct tm t1;
527 t=&t1;
528 localtime_r(&time,t);
529#endif
530 if(return_time)
531 return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
532 return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
533}
534
535static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
536{
a046433a
FB
537 if(s->fat_type==32) {
538 uint32_t* entry=array_get(&(s->fat),cluster);
539 *entry=cpu_to_le32(value);
de167e41
FB
540 } else if(s->fat_type==16) {
541 uint16_t* entry=array_get(&(s->fat),cluster);
542 *entry=cpu_to_le16(value&0xffff);
543 } else {
a046433a
FB
544 int offset = (cluster*3/2);
545 unsigned char* p = array_get(&(s->fat), offset);
546 switch (cluster&1) {
547 case 0:
548 p[0] = value&0xff;
549 p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
550 break;
551 case 1:
552 p[0] = (p[0]&0xf) | ((value&0xf)<<4);
553 p[1] = (value>>4);
554 break;
555 }
de167e41
FB
556 }
557}
558
559static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
560{
a046433a
FB
561 if(s->fat_type==32) {
562 uint32_t* entry=array_get(&(s->fat),cluster);
563 return le32_to_cpu(*entry);
de167e41
FB
564 } else if(s->fat_type==16) {
565 uint16_t* entry=array_get(&(s->fat),cluster);
566 return le16_to_cpu(*entry);
567 } else {
a046433a
FB
568 const uint8_t* x=s->fat.pointer+cluster*3/2;
569 return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
de167e41
FB
570 }
571}
572
573static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
574{
575 if(fat_entry>s->max_fat_value-8)
576 return -1;
577 return 0;
578}
579
580static inline void init_fat(BDRVVVFATState* s)
581{
a046433a
FB
582 if (s->fat_type == 12) {
583 array_init(&(s->fat),1);
584 array_ensure_allocated(&(s->fat),
585 s->sectors_per_fat * 0x200 * 3 / 2 - 1);
586 } else {
587 array_init(&(s->fat),(s->fat_type==32?4:2));
588 array_ensure_allocated(&(s->fat),
589 s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
590 }
de167e41 591 memset(s->fat.pointer,0,s->fat.size);
3b46e624 592
de167e41
FB
593 switch(s->fat_type) {
594 case 12: s->max_fat_value=0xfff; break;
595 case 16: s->max_fat_value=0xffff; break;
a046433a 596 case 32: s->max_fat_value=0x0fffffff; break;
de167e41
FB
597 default: s->max_fat_value=0; /* error... */
598 }
599
600}
601
a046433a
FB
602/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
603/* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
604static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
605 unsigned int directory_start, const char* filename, int is_dot)
de167e41 606{
a046433a 607 int i,j,long_index=s->directory.next;
de167e41
FB
608 direntry_t* entry=0;
609 direntry_t* entry_long=0;
610
611 if(is_dot) {
612 entry=array_get_next(&(s->directory));
613 memset(entry->name,0x20,11);
614 memcpy(entry->name,filename,strlen(filename));
615 return entry;
616 }
3b46e624 617
de167e41 618 entry_long=create_long_filename(s,filename);
3b46e624 619
5fafdf24 620 i = strlen(filename);
a046433a
FB
621 for(j = i - 1; j>0 && filename[j]!='.';j--);
622 if (j > 0)
623 i = (j > 8 ? 8 : j);
624 else if (i > 8)
625 i = 8;
626
de167e41
FB
627 entry=array_get_next(&(s->directory));
628 memset(entry->name,0x20,11);
629 strncpy(entry->name,filename,i);
3b46e624 630
a046433a
FB
631 if(j > 0)
632 for (i = 0; i < 3 && filename[j+1+i]; i++)
633 entry->extension[i] = filename[j+1+i];
de167e41
FB
634
635 /* upcase & remove unwanted characters */
636 for(i=10;i>=0;i--) {
a046433a 637 if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
de167e41 638 if(entry->name[i]<=' ' || entry->name[i]>0x7f
a046433a 639 || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
de167e41
FB
640 entry->name[i]='_';
641 else if(entry->name[i]>='a' && entry->name[i]<='z')
642 entry->name[i]+='A'-'a';
643 }
644
645 /* mangle duplicates */
646 while(1) {
647 direntry_t* entry1=array_get(&(s->directory),directory_start);
648 int j;
649
650 for(;entry1<entry;entry1++)
a046433a 651 if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
de167e41
FB
652 break; /* found dupe */
653 if(entry1==entry) /* no dupe found */
654 break;
655
5fafdf24 656 /* use all 8 characters of name */
de167e41
FB
657 if(entry->name[7]==' ') {
658 int j;
659 for(j=6;j>0 && entry->name[j]==' ';j--)
660 entry->name[j]='~';
661 }
662
663 /* increment number */
664 for(j=7;j>0 && entry->name[j]=='9';j--)
665 entry->name[j]='0';
666 if(j>0) {
667 if(entry->name[j]<'0' || entry->name[j]>'9')
668 entry->name[j]='0';
669 else
670 entry->name[j]++;
671 }
672 }
673
674 /* calculate checksum; propagate to long name */
675 if(entry_long) {
676 uint8_t chksum=fat_chksum(entry);
677
678 /* calculate anew, because realloc could have taken place */
679 entry_long=array_get(&(s->directory),long_index);
a046433a 680 while(entry_long<entry && is_long_name(entry_long)) {
de167e41
FB
681 entry_long->reserved[1]=chksum;
682 entry_long++;
683 }
684 }
685
686 return entry;
687}
688
a046433a
FB
689/*
690 * Read a directory. (the index of the corresponding mapping must be passed).
691 */
692static int read_directory(BDRVVVFATState* s, int mapping_index)
de167e41 693{
a046433a
FB
694 mapping_t* mapping = array_get(&(s->mapping), mapping_index);
695 direntry_t* direntry;
696 const char* dirname = mapping->path;
697 int first_cluster = mapping->begin;
698 int parent_index = mapping->info.dir.parent_mapping_index;
699 mapping_t* parent_mapping = (mapping_t*)
700 (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : 0);
701 int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
de167e41
FB
702
703 DIR* dir=opendir(dirname);
704 struct dirent* entry;
de167e41
FB
705 int i;
706
a046433a
FB
707 assert(mapping->mode & MODE_DIRECTORY);
708
709 if(!dir) {
710 mapping->end = mapping->begin;
de167e41 711 return -1;
a046433a 712 }
3b46e624 713
a046433a
FB
714 i = mapping->info.dir.first_dir_index =
715 first_cluster == 0 ? 0 : s->directory.next;
716
5fafdf24 717 /* actually read the directory, and allocate the mappings */
de167e41
FB
718 while((entry=readdir(dir))) {
719 unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
720 char* buffer;
721 direntry_t* direntry;
a046433a 722 struct stat st;
de167e41
FB
723 int is_dot=!strcmp(entry->d_name,".");
724 int is_dotdot=!strcmp(entry->d_name,"..");
725
a046433a 726 if(first_cluster == 0 && (is_dotdot || is_dot))
de167e41 727 continue;
5fafdf24 728
de167e41 729 buffer=(char*)malloc(length);
a046433a 730 assert(buffer);
de167e41
FB
731 snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
732
733 if(stat(buffer,&st)<0) {
734 free(buffer);
735 continue;
736 }
737
738 /* create directory entry for this file */
a046433a
FB
739 direntry=create_short_and_long_name(s, i, entry->d_name,
740 is_dot || is_dotdot);
de167e41
FB
741 direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
742 direntry->reserved[0]=direntry->reserved[1]=0;
743 direntry->ctime=fat_datetime(st.st_ctime,1);
744 direntry->cdate=fat_datetime(st.st_ctime,0);
745 direntry->adate=fat_datetime(st.st_atime,0);
746 direntry->begin_hi=0;
747 direntry->mtime=fat_datetime(st.st_mtime,1);
748 direntry->mdate=fat_datetime(st.st_mtime,0);
749 if(is_dotdot)
a046433a 750 set_begin_of_direntry(direntry, first_cluster_of_parent);
de167e41 751 else if(is_dot)
a046433a 752 set_begin_of_direntry(direntry, first_cluster);
de167e41 753 else
a046433a
FB
754 direntry->begin=0; /* do that later */
755 if (st.st_size > 0x7fffffff) {
756 fprintf(stderr, "File %s is larger than 2GB\n", buffer);
757 free(buffer);
758 return -2;
759 }
760 direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
de167e41
FB
761
762 /* create mapping for this file */
a046433a
FB
763 if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
764 s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
de167e41
FB
765 s->current_mapping->begin=0;
766 s->current_mapping->end=st.st_size;
a046433a
FB
767 /*
768 * we get the direntry of the most recent direntry, which
769 * contains the short name and all the relevant information.
770 */
de167e41 771 s->current_mapping->dir_index=s->directory.next-1;
a046433a
FB
772 s->current_mapping->first_mapping_index = -1;
773 if (S_ISDIR(st.st_mode)) {
774 s->current_mapping->mode = MODE_DIRECTORY;
775 s->current_mapping->info.dir.parent_mapping_index =
776 mapping_index;
777 } else {
778 s->current_mapping->mode = MODE_UNDEFINED;
779 s->current_mapping->info.file.offset = 0;
780 }
781 s->current_mapping->path=buffer;
782 s->current_mapping->read_only =
783 (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
de167e41
FB
784 }
785 }
786 closedir(dir);
787
788 /* fill with zeroes up to the end of the cluster */
789 while(s->directory.next%(0x10*s->sectors_per_cluster)) {
790 direntry_t* direntry=array_get_next(&(s->directory));
791 memset(direntry,0,sizeof(direntry_t));
792 }
793
a046433a
FB
794/* TODO: if there are more entries, bootsector has to be adjusted! */
795#define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
796 if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
797 /* root directory */
798 int cur = s->directory.next;
799 array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
800 memset(array_get(&(s->directory), cur), 0,
801 (ROOT_ENTRIES - cur) * sizeof(direntry_t));
de167e41 802 }
5fafdf24 803
a046433a
FB
804 /* reget the mapping, since s->mapping was possibly realloc()ed */
805 mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
806 first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
807 * 0x20 / s->cluster_size;
808 mapping->end = first_cluster;
809
810 direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
811 set_begin_of_direntry(direntry, mapping->begin);
3b46e624 812
a046433a
FB
813 return 0;
814}
de167e41 815
a046433a
FB
816static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
817{
818 return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
819}
de167e41 820
a046433a
FB
821static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
822{
823 return s->faked_sectors + s->sectors_per_cluster * cluster_num;
824}
de167e41 825
a046433a
FB
826static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
827{
828 return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
829}
de167e41 830
a046433a
FB
831#ifdef DBG
832static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
833{
834 if(mapping->mode==MODE_UNDEFINED)
835 return 0;
836 return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
de167e41 837}
a046433a 838#endif
de167e41 839
a046433a
FB
840static int init_directories(BDRVVVFATState* s,
841 const char* dirname)
de167e41 842{
a046433a
FB
843 bootsector_t* bootsector;
844 mapping_t* mapping;
de167e41
FB
845 unsigned int i;
846 unsigned int cluster;
847
848 memset(&(s->first_sectors[0]),0,0x40*0x200);
849
de167e41 850 s->cluster_size=s->sectors_per_cluster*0x200;
a046433a
FB
851 s->cluster_buffer=malloc(s->cluster_size);
852 assert(s->cluster_buffer);
853
854 /*
855 * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
856 * where sc is sector_count,
857 * spf is sectors_per_fat,
858 * spc is sectors_per_clusters, and
859 * fat_type = 12, 16 or 32.
860 */
861 i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
862 s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
3b46e624 863
de167e41
FB
864 array_init(&(s->mapping),sizeof(mapping_t));
865 array_init(&(s->directory),sizeof(direntry_t));
de167e41
FB
866
867 /* add volume label */
868 {
869 direntry_t* entry=array_get_next(&(s->directory));
870 entry->attributes=0x28; /* archive | volume label */
871 snprintf(entry->name,11,"QEMU VVFAT");
872 }
873
de167e41
FB
874 /* Now build FAT, and write back information into directory */
875 init_fat(s);
876
a046433a
FB
877 s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
878 s->cluster_count=sector2cluster(s, s->sector_count);
879
880 mapping = array_get_next(&(s->mapping));
881 mapping->begin = 0;
882 mapping->dir_index = 0;
883 mapping->info.dir.parent_mapping_index = -1;
884 mapping->first_mapping_index = -1;
885 mapping->path = strdup(dirname);
886 i = strlen(mapping->path);
887 if (i > 0 && mapping->path[i - 1] == '/')
888 mapping->path[i - 1] = '\0';
889 mapping->mode = MODE_DIRECTORY;
890 mapping->read_only = 0;
891 s->path = mapping->path;
892
893 for (i = 0, cluster = 0; i < s->mapping.next; i++) {
894 int j;
5fafdf24 895 /* MS-DOS expects the FAT to be 0 for the root directory
a046433a
FB
896 * (except for the media byte). */
897 /* LATER TODO: still true for FAT32? */
898 int fix_fat = (i != 0);
899 mapping = array_get(&(s->mapping), i);
900
901 if (mapping->mode & MODE_DIRECTORY) {
902 mapping->begin = cluster;
903 if(read_directory(s, i)) {
904 fprintf(stderr, "Could not read directory %s\n",
905 mapping->path);
de167e41
FB
906 return -1;
907 }
a046433a
FB
908 mapping = array_get(&(s->mapping), i);
909 } else {
910 assert(mapping->mode == MODE_UNDEFINED);
de167e41 911 mapping->mode=MODE_NORMAL;
a046433a
FB
912 mapping->begin = cluster;
913 if (mapping->end > 0) {
914 direntry_t* direntry = array_get(&(s->directory),
915 mapping->dir_index);
916
917 mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
918 set_begin_of_direntry(direntry, mapping->begin);
919 } else {
920 mapping->end = cluster + 1;
921 fix_fat = 0;
de167e41 922 }
a046433a
FB
923 }
924
925 assert(mapping->begin < mapping->end);
926
927 /* fix fat for entry */
928 if (fix_fat) {
929 for(j = mapping->begin; j < mapping->end - 1; j++)
930 fat_set(s, j, j+1);
931 fat_set(s, mapping->end - 1, s->max_fat_value);
932 }
933
934 /* next free cluster */
935 cluster = mapping->end;
de167e41 936
a046433a
FB
937 if(cluster > s->cluster_count) {
938 fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type);
939 return -1;
de167e41
FB
940 }
941 }
942
a046433a
FB
943 mapping = array_get(&(s->mapping), 0);
944 s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
945 s->last_cluster_of_root_directory = mapping->end;
946
947 /* the FAT signature */
948 fat_set(s,0,s->max_fat_value);
949 fat_set(s,1,s->max_fat_value);
de167e41 950
a046433a
FB
951 s->current_mapping = NULL;
952
953 bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
de167e41
FB
954 bootsector->jump[0]=0xeb;
955 bootsector->jump[1]=0x3e;
956 bootsector->jump[2]=0x90;
957 memcpy(bootsector->name,"QEMU ",8);
958 bootsector->sector_size=cpu_to_le16(0x200);
959 bootsector->sectors_per_cluster=s->sectors_per_cluster;
960 bootsector->reserved_sectors=cpu_to_le16(1);
961 bootsector->number_of_fats=0x2; /* number of FATs */
962 bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
a046433a
FB
963 bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
964 bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
965 s->fat.pointer[0] = bootsector->media_type;
de167e41 966 bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
a046433a
FB
967 bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
968 bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
de167e41 969 bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
a046433a 970 bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
de167e41 971
a046433a
FB
972 /* LATER TODO: if FAT32, this is wrong */
973 bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
de167e41
FB
974 bootsector->u.fat16.current_head=0;
975 bootsector->u.fat16.signature=0x29;
976 bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
977
978 memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
979 memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12 ":s->fat_type==16?"FAT16 ":"FAT32 "),8);
980 bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
981
982 return 0;
983}
984
83f64091 985#ifdef DEBUG
a046433a 986static BDRVVVFATState *vvv = NULL;
83f64091 987#endif
a046433a
FB
988
989static int enable_write_target(BDRVVVFATState *s);
990static int is_consistent(BDRVVVFATState *s);
991
83f64091 992static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
de167e41
FB
993{
994 BDRVVVFATState *s = bs->opaque;
a046433a 995 int floppy = 0;
de167e41
FB
996 int i;
997
83f64091 998#ifdef DEBUG
a046433a 999 vvv = s;
83f64091 1000#endif
a046433a
FB
1001
1002DLOG(if (stderr == NULL) {
1003 stderr = fopen("vvfat.log", "a");
1004 setbuf(stderr, NULL);
1005})
1006
1007 s->bs = bs;
1008
de167e41 1009 s->fat_type=16;
a046433a 1010 /* LATER TODO: if FAT32, adjust */
a046433a 1011 s->sectors_per_cluster=0x10;
b570094d
TS
1012 /* 504MB disk*/
1013 bs->cyls=1024; bs->heads=16; bs->secs=63;
de167e41
FB
1014
1015 s->current_cluster=0xffffffff;
de167e41 1016
de167e41 1017 s->first_sectors_number=0x40;
a046433a
FB
1018 /* read only is the default for safety */
1019 bs->read_only = 1;
1020 s->qcow = s->write_target = NULL;
1021 s->qcow_filename = NULL;
1022 s->fat2 = NULL;
1023 s->downcase_short_names = 1;
3b46e624 1024
a046433a
FB
1025 if (!strstart(dirname, "fat:", NULL))
1026 return -1;
1027
a046433a
FB
1028 if (strstr(dirname, ":floppy:")) {
1029 floppy = 1;
1030 s->fat_type = 12;
1031 s->first_sectors_number = 1;
1032 s->sectors_per_cluster=2;
1033 bs->cyls = 80; bs->heads = 2; bs->secs = 36;
1034 }
1035
b570094d
TS
1036 s->sector_count=bs->cyls*bs->heads*bs->secs;
1037
a046433a
FB
1038 if (strstr(dirname, ":32:")) {
1039 fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
1040 s->fat_type = 32;
1041 } else if (strstr(dirname, ":16:")) {
1042 s->fat_type = 16;
1043 } else if (strstr(dirname, ":12:")) {
1044 s->fat_type = 12;
1045 s->sector_count=2880;
de167e41 1046 }
a046433a 1047
b570094d
TS
1048 if (strstr(dirname, ":rw:")) {
1049 if (enable_write_target(s))
1050 return -1;
1051 bs->read_only = 0;
1052 }
1053
a046433a
FB
1054 i = strrchr(dirname, ':') - dirname;
1055 assert(i >= 3);
1056 if (dirname[i-2] == ':' && isalpha(dirname[i-1]))
1057 /* workaround for DOS drive names */
1058 dirname += i-1;
1059 else
1060 dirname += i+1;
1061
1062 bs->total_sectors=bs->cyls*bs->heads*bs->secs;
b570094d 1063
a046433a 1064 if(init_directories(s, dirname))
de167e41
FB
1065 return -1;
1066
b570094d
TS
1067 s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
1068
de167e41
FB
1069 if(s->first_sectors_number==0x40)
1070 init_mbr(s);
1071
a046433a
FB
1072 /* for some reason or other, MS-DOS does not like to know about CHS... */
1073 if (floppy)
1074 bs->heads = bs->cyls = bs->secs = 0;
1075
1076 // assert(is_consistent(s));
de167e41
FB
1077 return 0;
1078}
1079
1080static inline void vvfat_close_current_file(BDRVVVFATState *s)
1081{
1082 if(s->current_mapping) {
a046433a
FB
1083 s->current_mapping = NULL;
1084 if (s->current_fd) {
1085 close(s->current_fd);
1086 s->current_fd = 0;
1087 }
de167e41 1088 }
a046433a 1089 s->current_cluster = -1;
de167e41
FB
1090}
1091
1092/* mappings between index1 and index2-1 are supposed to be ordered
1093 * return value is the index of the last mapping for which end>cluster_num
1094 */
1095static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
1096{
1097 int index3=index1+1;
de167e41
FB
1098 while(1) {
1099 mapping_t* mapping;
1100 index3=(index1+index2)/2;
1101 mapping=array_get(&(s->mapping),index3);
a046433a
FB
1102 assert(mapping->begin < mapping->end);
1103 if(mapping->begin>=cluster_num) {
de167e41
FB
1104 assert(index2!=index3 || index2==0);
1105 if(index2==index3)
a046433a 1106 return index1;
de167e41
FB
1107 index2=index3;
1108 } else {
1109 if(index1==index3)
a046433a 1110 return mapping->end<=cluster_num ? index2 : index1;
de167e41
FB
1111 index1=index3;
1112 }
1113 assert(index1<=index2);
a046433a
FB
1114 DLOG(mapping=array_get(&(s->mapping),index1);
1115 assert(mapping->begin<=cluster_num);
5fafdf24 1116 assert(index2 >= s->mapping.next ||
a046433a
FB
1117 ((mapping = array_get(&(s->mapping),index2)) &&
1118 mapping->end>cluster_num)));
de167e41
FB
1119 }
1120}
1121
1122static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
1123{
1124 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
1125 mapping_t* mapping;
1126 if(index>=s->mapping.next)
1127 return 0;
1128 mapping=array_get(&(s->mapping),index);
1129 if(mapping->begin>cluster_num)
1130 return 0;
a046433a 1131 assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
de167e41
FB
1132 return mapping;
1133}
1134
a046433a
FB
1135/*
1136 * This function simply compares path == mapping->path. Since the mappings
1137 * are sorted by cluster, this is expensive: O(n).
1138 */
1139static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
1140 const char* path)
1141{
1142 int i;
1143
1144 for (i = 0; i < s->mapping.next; i++) {
1145 mapping_t* mapping = array_get(&(s->mapping), i);
1146 if (mapping->first_mapping_index < 0 &&
1147 !strcmp(path, mapping->path))
1148 return mapping;
1149 }
1150
1151 return NULL;
1152}
1153
1154static int open_file(BDRVVVFATState* s,mapping_t* mapping)
de167e41
FB
1155{
1156 if(!mapping)
1157 return -1;
de167e41 1158 if(!s->current_mapping ||
a046433a 1159 strcmp(s->current_mapping->path,mapping->path)) {
de167e41 1160 /* open file */
a046433a 1161 int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
de167e41
FB
1162 if(fd<0)
1163 return -1;
1164 vvfat_close_current_file(s);
1165 s->current_fd = fd;
de167e41
FB
1166 s->current_mapping = mapping;
1167 }
1168 return 0;
1169}
1170
1171static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
1172{
1173 if(s->current_cluster != cluster_num) {
1174 int result=0;
1175 off_t offset;
a046433a 1176 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
de167e41
FB
1177 if(!s->current_mapping
1178 || s->current_mapping->begin>cluster_num
1179 || s->current_mapping->end<=cluster_num) {
1180 /* binary search of mappings for file */
1181 mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
a046433a
FB
1182
1183 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
1184
1185 if (mapping && mapping->mode & MODE_DIRECTORY) {
1186 vvfat_close_current_file(s);
1187 s->current_mapping = mapping;
1188read_cluster_directory:
1189 offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
1190 s->cluster = s->directory.pointer+offset
1191 + 0x20*s->current_mapping->info.dir.first_dir_index;
1192 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
1193 assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
1194 s->current_cluster = cluster_num;
1195 return 0;
1196 }
1197
1198 if(open_file(s,mapping))
de167e41 1199 return -2;
a046433a
FB
1200 } else if (s->current_mapping->mode & MODE_DIRECTORY)
1201 goto read_cluster_directory;
de167e41 1202
a046433a
FB
1203 assert(s->current_fd);
1204
1205 offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
de167e41
FB
1206 if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
1207 return -3;
a046433a 1208 s->cluster=s->cluster_buffer;
de167e41
FB
1209 result=read(s->current_fd,s->cluster,s->cluster_size);
1210 if(result<0) {
1211 s->current_cluster = -1;
1212 return -1;
1213 }
1214 s->current_cluster = cluster_num;
1215 }
1216 return 0;
1217}
1218
a046433a
FB
1219#ifdef DEBUG
1220static void hexdump(const void* address, uint32_t len)
de167e41 1221{
a046433a
FB
1222 const unsigned char* p = address;
1223 int i, j;
1224
1225 for (i = 0; i < len; i += 16) {
1226 for (j = 0; j < 16 && i + j < len; j++)
1227 fprintf(stderr, "%02x ", p[i + j]);
1228 for (; j < 16; j++)
1229 fprintf(stderr, " ");
1230 fprintf(stderr, " ");
1231 for (j = 0; j < 16 && i + j < len; j++)
1232 fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
1233 fprintf(stderr, "\n");
de167e41 1234 }
de167e41
FB
1235}
1236
a046433a 1237static void print_direntry(const direntry_t* direntry)
de167e41 1238{
a046433a
FB
1239 int j = 0;
1240 char buffer[1024];
1241
1242 fprintf(stderr, "direntry 0x%x: ", (int)direntry);
de167e41
FB
1243 if(!direntry)
1244 return;
a046433a 1245 if(is_long_name(direntry)) {
de167e41
FB
1246 unsigned char* c=(unsigned char*)direntry;
1247 int i;
1248 for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
a046433a
FB
1249