Revision 5fafdf24 block-vvfat.c
b/block-vvfat.c | ||
---|---|---|
1 | 1 |
/* vim:set shiftwidth=4 ts=8: */ |
2 | 2 |
/* |
3 | 3 |
* QEMU Block driver for virtual VFAT (shadows a local directory) |
4 |
*
|
|
4 |
* |
|
5 | 5 |
* Copyright (c) 2004,2005 Johannes E. Schindelin |
6 |
*
|
|
6 |
* |
|
7 | 7 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
8 | 8 |
* of this software and associated documentation files (the "Software"), to deal |
9 | 9 |
* in the Software without restriction, including without limitation the rights |
... | ... | |
38 | 38 |
/* TODO: add ":bootsector=blabla.img:" */ |
39 | 39 |
/* LATER TODO: add automatic boot sector generation from |
40 | 40 |
BOOTEASY.ASM and Ranish Partition Manager |
41 |
Note that DOS assumes the system files to be the first files in the
|
|
41 |
Note that DOS assumes the system files to be the first files in the |
|
42 | 42 |
file system (test if the boot sector still relies on that fact)! */ |
43 | 43 |
/* MAYBE TODO: write block-visofs.c */ |
44 | 44 |
/* TODO: call try_commit() only after a timeout */ |
... | ... | |
153 | 153 |
index_to<0 || index_to>=array->next || |
154 | 154 |
index_from<0 || index_from>=array->next) |
155 | 155 |
return -1; |
156 |
|
|
156 |
|
|
157 | 157 |
if(index_to==index_from) |
158 | 158 |
return 0; |
159 | 159 |
|
... | ... | |
167 | 167 |
memmove(to+is*count,to,from-to); |
168 | 168 |
else |
169 | 169 |
memmove(from,from+is*count,to-from); |
170 |
|
|
170 |
|
|
171 | 171 |
memcpy(to,buf,is*count); |
172 | 172 |
|
173 | 173 |
free(buf); |
... | ... | |
319 | 319 |
BlockDriverState* bs; /* pointer to parent */ |
320 | 320 |
unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */ |
321 | 321 |
unsigned char first_sectors[0x40*0x200]; |
322 |
|
|
322 |
|
|
323 | 323 |
int fat_type; /* 16 or 32 */ |
324 | 324 |
array_t fat,directory,mapping; |
325 |
|
|
325 |
|
|
326 | 326 |
unsigned int cluster_size; |
327 | 327 |
unsigned int sectors_per_cluster; |
328 | 328 |
unsigned int sectors_per_fat; |
... | ... | |
332 | 332 |
uint32_t sector_count; /* total number of sectors of the partition */ |
333 | 333 |
uint32_t cluster_count; /* total number of clusters of this partition */ |
334 | 334 |
uint32_t max_fat_value; |
335 |
|
|
335 |
|
|
336 | 336 |
int current_fd; |
337 | 337 |
mapping_t* current_mapping; |
338 | 338 |
unsigned char* cluster; /* points to current cluster */ |
... | ... | |
358 | 358 |
partition_t* partition=&(real_mbr->partition[0]); |
359 | 359 |
|
360 | 360 |
memset(s->first_sectors,0,512); |
361 |
|
|
361 |
|
|
362 | 362 |
partition->attributes=0x80; /* bootable */ |
363 | 363 |
partition->start_head=1; |
364 | 364 |
partition->start_sector=1; |
... | ... | |
478 | 478 |
for(i=0;i<11;i++) |
479 | 479 |
chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0)) |
480 | 480 |
+(unsigned char)entry->name[i]; |
481 |
|
|
481 |
|
|
482 | 482 |
return chksum; |
483 | 483 |
} |
484 | 484 |
|
... | ... | |
554 | 554 |
s->sectors_per_fat * 0x200 / s->fat.item_size - 1); |
555 | 555 |
} |
556 | 556 |
memset(s->fat.pointer,0,s->fat.size); |
557 |
|
|
557 |
|
|
558 | 558 |
switch(s->fat_type) { |
559 | 559 |
case 12: s->max_fat_value=0xfff; break; |
560 | 560 |
case 16: s->max_fat_value=0xffff; break; |
... | ... | |
579 | 579 |
memcpy(entry->name,filename,strlen(filename)); |
580 | 580 |
return entry; |
581 | 581 |
} |
582 |
|
|
582 |
|
|
583 | 583 |
entry_long=create_long_filename(s,filename); |
584 |
|
|
585 |
i = strlen(filename);
|
|
584 |
|
|
585 |
i = strlen(filename); |
|
586 | 586 |
for(j = i - 1; j>0 && filename[j]!='.';j--); |
587 | 587 |
if (j > 0) |
588 | 588 |
i = (j > 8 ? 8 : j); |
... | ... | |
592 | 592 |
entry=array_get_next(&(s->directory)); |
593 | 593 |
memset(entry->name,0x20,11); |
594 | 594 |
strncpy(entry->name,filename,i); |
595 |
|
|
595 |
|
|
596 | 596 |
if(j > 0) |
597 | 597 |
for (i = 0; i < 3 && filename[j+1+i]; i++) |
598 | 598 |
entry->extension[i] = filename[j+1+i]; |
... | ... | |
618 | 618 |
if(entry1==entry) /* no dupe found */ |
619 | 619 |
break; |
620 | 620 |
|
621 |
/* use all 8 characters of name */
|
|
621 |
/* use all 8 characters of name */ |
|
622 | 622 |
if(entry->name[7]==' ') { |
623 | 623 |
int j; |
624 | 624 |
for(j=6;j>0 && entry->name[j]==' ';j--) |
... | ... | |
675 | 675 |
mapping->end = mapping->begin; |
676 | 676 |
return -1; |
677 | 677 |
} |
678 |
|
|
678 |
|
|
679 | 679 |
i = mapping->info.dir.first_dir_index = |
680 | 680 |
first_cluster == 0 ? 0 : s->directory.next; |
681 | 681 |
|
682 |
/* actually read the directory, and allocate the mappings */
|
|
682 |
/* actually read the directory, and allocate the mappings */ |
|
683 | 683 |
while((entry=readdir(dir))) { |
684 | 684 |
unsigned int length=strlen(dirname)+2+strlen(entry->d_name); |
685 | 685 |
char* buffer; |
... | ... | |
690 | 690 |
|
691 | 691 |
if(first_cluster == 0 && (is_dotdot || is_dot)) |
692 | 692 |
continue; |
693 |
|
|
693 |
|
|
694 | 694 |
buffer=(char*)malloc(length); |
695 | 695 |
assert(buffer); |
696 | 696 |
snprintf(buffer,length,"%s/%s",dirname,entry->d_name); |
... | ... | |
765 | 765 |
memset(array_get(&(s->directory), cur), 0, |
766 | 766 |
(ROOT_ENTRIES - cur) * sizeof(direntry_t)); |
767 | 767 |
} |
768 |
|
|
768 |
|
|
769 | 769 |
/* reget the mapping, since s->mapping was possibly realloc()ed */ |
770 | 770 |
mapping = (mapping_t*)array_get(&(s->mapping), mapping_index); |
771 | 771 |
first_cluster += (s->directory.next - mapping->info.dir.first_dir_index) |
... | ... | |
774 | 774 |
|
775 | 775 |
direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index); |
776 | 776 |
set_begin_of_direntry(direntry, mapping->begin); |
777 |
|
|
777 |
|
|
778 | 778 |
return 0; |
779 | 779 |
} |
780 | 780 |
|
... | ... | |
825 | 825 |
*/ |
826 | 826 |
i = 1+s->sectors_per_cluster*0x200*8/s->fat_type; |
827 | 827 |
s->sectors_per_fat=(s->sector_count+i)/i; /* round up */ |
828 |
|
|
828 |
|
|
829 | 829 |
array_init(&(s->mapping),sizeof(mapping_t)); |
830 | 830 |
array_init(&(s->directory),sizeof(direntry_t)); |
831 | 831 |
|
... | ... | |
857 | 857 |
|
858 | 858 |
for (i = 0, cluster = 0; i < s->mapping.next; i++) { |
859 | 859 |
int j; |
860 |
/* MS-DOS expects the FAT to be 0 for the root directory
|
|
860 |
/* MS-DOS expects the FAT to be 0 for the root directory |
|
861 | 861 |
* (except for the media byte). */ |
862 | 862 |
/* LATER TODO: still true for FAT32? */ |
863 | 863 |
int fix_fat = (i != 0); |
... | ... | |
987 | 987 |
s->qcow_filename = NULL; |
988 | 988 |
s->fat2 = NULL; |
989 | 989 |
s->downcase_short_names = 1; |
990 |
|
|
990 |
|
|
991 | 991 |
if (!strstart(dirname, "fat:", NULL)) |
992 | 992 |
return -1; |
993 | 993 |
|
... | ... | |
1076 | 1076 |
assert(index1<=index2); |
1077 | 1077 |
DLOG(mapping=array_get(&(s->mapping),index1); |
1078 | 1078 |
assert(mapping->begin<=cluster_num); |
1079 |
assert(index2 >= s->mapping.next ||
|
|
1079 |
assert(index2 >= s->mapping.next || |
|
1080 | 1080 |
((mapping = array_get(&(s->mapping),index2)) && |
1081 | 1081 |
mapping->end>cluster_num))); |
1082 | 1082 |
} |
... | ... | |
1239 | 1239 |
} |
1240 | 1240 |
#endif |
1241 | 1241 |
|
1242 |
static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
|
|
1242 |
static int vvfat_read(BlockDriverState *bs, int64_t sector_num, |
|
1243 | 1243 |
uint8_t *buf, int nb_sectors) |
1244 | 1244 |
{ |
1245 | 1245 |
BDRVVVFATState *s = bs->opaque; |
... | ... | |
1674 | 1674 |
} |
1675 | 1675 |
|
1676 | 1676 |
/* |
1677 |
* This function looks at the modified data (qcow).
|
|
1677 |
* This function looks at the modified data (qcow). |
|
1678 | 1678 |
* It returns 0 upon inconsistency or error, and the number of clusters |
1679 | 1679 |
* used by the directory, its subdirectories and their files. |
1680 | 1680 |
*/ |
... | ... | |
1709 | 1709 |
} else |
1710 | 1710 |
/* new directory */ |
1711 | 1711 |
schedule_mkdir(s, cluster_num, strdup(path)); |
1712 |
|
|
1712 |
|
|
1713 | 1713 |
lfn_init(&lfn); |
1714 | 1714 |
do { |
1715 | 1715 |
int i; |
... | ... | |
2049 | 2049 |
} |
2050 | 2050 |
|
2051 | 2051 |
next_mapping->dir_index = mapping->dir_index; |
2052 |
next_mapping->first_mapping_index =
|
|
2052 |
next_mapping->first_mapping_index = |
|
2053 | 2053 |
mapping->first_mapping_index < 0 ? |
2054 | 2054 |
array_index(&(s->mapping), mapping) : |
2055 | 2055 |
mapping->first_mapping_index; |
... | ... | |
2069 | 2069 |
|
2070 | 2070 |
mapping = next_mapping; |
2071 | 2071 |
} |
2072 |
|
|
2072 |
|
|
2073 | 2073 |
cluster = c1; |
2074 | 2074 |
} |
2075 | 2075 |
|
... | ... | |
2555 | 2555 |
return ret; |
2556 | 2556 |
} |
2557 | 2557 |
|
2558 |
/* copy FAT (with bdrv_read) */
|
|
2558 |
/* copy FAT (with bdrv_read) */ |
|
2559 | 2559 |
memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat); |
2560 | 2560 |
|
2561 | 2561 |
/* recurse direntries from root (using bs->bdrv_read) */ |
... | ... | |
2597 | 2597 |
return do_commit(s); |
2598 | 2598 |
} |
2599 | 2599 |
|
2600 |
static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
|
|
2600 |
static int vvfat_write(BlockDriverState *bs, int64_t sector_num, |
|
2601 | 2601 |
const uint8_t *buf, int nb_sectors) |
2602 | 2602 |
{ |
2603 |
BDRVVVFATState *s = bs->opaque;
|
|
2603 |
BDRVVVFATState *s = bs->opaque; |
|
2604 | 2604 |
int i, ret; |
2605 | 2605 |
|
2606 | 2606 |
DLOG(checkpoint()); |
... | ... | |
2639 | 2639 |
begin = sector_num; |
2640 | 2640 |
if (end > sector_num + nb_sectors) |
2641 | 2641 |
end = sector_num + nb_sectors; |
2642 |
dir_index = mapping->dir_index +
|
|
2642 |
dir_index = mapping->dir_index + |
|
2643 | 2643 |
0x10 * (begin - mapping->begin * s->sectors_per_cluster); |
2644 | 2644 |
direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num)); |
2645 | 2645 |
|
... | ... | |
2698 | 2698 |
*n = nb_sectors; |
2699 | 2699 |
else if (*n < 0) |
2700 | 2700 |
return 0; |
2701 |
return 1;
|
|
2701 |
return 1; |
|
2702 | 2702 |
} |
2703 | 2703 |
|
2704 | 2704 |
static int write_target_commit(BlockDriverState *bs, int64_t sector_num, |
Also available in: Unified diff