Lines Matching +full:- +full:- +full:disable +full:- +full:live +full:- +full:block +full:- +full:migration
3 * QEMU Block driver for virtual VFAT (shadows a local directory)
30 #include "block/block-io.h"
31 #include "block/block_int.h"
32 #include "block/qdict.h"
36 #include "migration/blocker.h"
41 #include "qemu/error-report.h"
55 /* MAYBE TODO: write block-visofs.c */
73 * https://jdebp.eu/FGA/volume-boot-block-oem-name-field.html
91 array->pointer = NULL; in array_init()
92 array->size=0; in array_init()
93 array->next=0; in array_init()
94 array->item_size=item_size; in array_init()
99 g_free(array->pointer); in array_free()
100 array->size=array->next=0; in array_free()
105 assert(index < array->next); in array_get()
106 assert(array->pointer); in array_get()
107 return array->pointer + index * array->item_size; in array_get()
112 if((index + 1) * array->item_size > array->size) { in array_ensure_allocated()
113 int new_size = (index + 32) * array->item_size; in array_ensure_allocated()
114 array->pointer = g_realloc(array->pointer, new_size); in array_ensure_allocated()
115 assert(array->pointer); in array_ensure_allocated()
116 memset(array->pointer + array->size, 0, new_size - array->size); in array_ensure_allocated()
117 array->size = new_size; in array_ensure_allocated()
118 array->next = index + 1; in array_ensure_allocated()
123 unsigned int next = array->next; in array_get_next()
126 array->next = next + 1; in array_get_next()
131 if((array->next+count)*array->item_size>array->size) { in array_insert()
132 int increment=count*array->item_size; in array_insert()
133 array->pointer=g_realloc(array->pointer,array->size+increment); in array_insert()
134 if(!array->pointer) in array_insert()
136 array->size+=increment; in array_insert()
138 memmove(array->pointer+(index+count)*array->item_size, in array_insert()
139 array->pointer+index*array->item_size, in array_insert()
140 (array->next-index)*array->item_size); in array_insert()
141 array->next+=count; in array_insert()
142 return array->pointer+index*array->item_size; in array_insert()
149 assert(index + count <= array->next); in array_remove_slice()
151 memmove(array->pointer + index * array->item_size, in array_remove_slice()
152 array->pointer + (index + count) * array->item_size, in array_remove_slice()
153 (array->next - index - count) * array->item_size); in array_remove_slice()
155 array->next -= count; in array_remove_slice()
167 size_t offset = (char*)pointer - array->pointer; in array_index()
168 assert((offset % array->item_size) == 0); in array_index()
169 assert(offset/array->item_size < array->next); in array_index()
170 return offset/array->item_size; in array_index()
263 /* as s->directory is growable, no pointer may be used here */
269 * - the offset in the file (in clusters) for a file, or
270 * - the next cluster of the directory for a directory
280 /* path contains the full path, i.e. it always starts with s->path */
354 chs->head = 0xFF; in sector2CHS()
355 chs->sector = 0xFF; in sector2CHS()
356 chs->cylinder = 0xFF; in sector2CHS()
359 chs->head = (uint8_t)head; in sector2CHS()
360 chs->sector = (uint8_t)( (sector+1) | ((spos>>8)<<6) ); in sector2CHS()
361 chs->cylinder = (uint8_t)spos; in sector2CHS()
368 mbr_t* real_mbr=(mbr_t*)s->first_sectors; in init_mbr()
369 partition_t* partition = &(real_mbr->partition[0]); in init_mbr()
372 memset(s->first_sectors,0,512); in init_mbr()
375 real_mbr->nt_id= cpu_to_le32(0xbe1afdfa); in init_mbr()
377 partition->attributes=0x80; /* bootable */ in init_mbr()
380 lba = sector2CHS(&partition->start_CHS, s->offset_to_bootsector, in init_mbr()
382 lba |= sector2CHS(&partition->end_CHS, s->bs->total_sectors - 1, in init_mbr()
386 partition->start_sector_long = cpu_to_le32(s->offset_to_bootsector); in init_mbr()
387 partition->length_sector_long = cpu_to_le32(s->bs->total_sectors in init_mbr()
388 - s->offset_to_bootsector); in init_mbr()
393 partition->fs_type = s->fat_type == 12 ? 0x1 : in init_mbr()
394 s->fat_type == 16 ? (lba ? 0xe : 0x06) : in init_mbr()
395 /*s->fat_type == 32*/ (lba ? 0xc : 0x0b); in init_mbr()
397 real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa; in init_mbr()
407 gunichar2 *longname = g_utf8_to_utf16(filename, -1, NULL, &length, NULL); in create_long_filename()
409 fprintf(stderr, "vvfat: invalid UTF-8 name: %s\n", filename); in create_long_filename()
416 direntry_t *entry=array_get_next(&(s->directory)); in create_long_filename()
417 entry->attributes=0xf; in create_long_filename()
418 entry->reserved[0]=0; in create_long_filename()
419 entry->begin=0; in create_long_filename()
420 entry->name[0]=(number_of_entries-i)|(i==0?0x40:0); in create_long_filename()
423 unsigned char *entry=array_get(&(s->directory),s->directory.next-1-(i/26)); in create_long_filename()
426 else if(offset<22) offset=14+offset-10; in create_long_filename()
427 else offset=28+offset-22; in create_long_filename()
437 return array_get(&(s->directory),s->directory.next-number_of_entries); in create_long_filename()
442 return direntry->name[0] == DIR_DELETED || direntry->name[0] == DIR_FREE; in is_free()
447 return direntry->attributes == 0x28; in is_volume_label()
452 return direntry->attributes == 0xf; in is_long_name()
463 return direntry->attributes & 0x10 && direntry->name[0] != DIR_DELETED; in is_directory()
468 return is_short_name(direntry) && direntry->name[0] == '.'; in is_dot()
478 return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16); in begin_of_direntry()
483 return le32_to_cpu(direntry->size); in filesize_of_direntry()
488 direntry->begin = cpu_to_le16(begin & 0xffff); in set_begin_of_direntry()
489 direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff); in set_begin_of_direntry()
503 strchr(" $%'-_@~`!(){}^#&.+,;=[]", c) != NULL)) in valid_filename()
516 strchr("$%'-_@~`!(){}^#&", c) != NULL) { in to_valid_short_char()
528 direntry_t *entry = array_get_next(&(s->directory)); in create_short_filename()
537 memset(entry->name, 0x20, sizeof(entry->name)); in create_short_filename()
558 entry->name[j++] = v; in create_short_filename()
576 entry->name[8 + (j++)] = v; in create_short_filename()
584 if (entry->name[0] == DIR_KANJI) { in create_short_filename()
585 entry->name[0] = DIR_KANJI_FAKE; in create_short_filename()
588 /* numeric-tail generation */ in create_short_filename()
590 if (entry->name[j] == ' ') { in create_short_filename()
599 memcpy(entry->name + MIN(j, 8 - len), tail, len); in create_short_filename()
601 for (entry1 = array_get(&(s->directory), directory_start); in create_short_filename()
604 !memcmp(entry1->name, entry->name, 11)) { in create_short_filename()
623 for (i = 0; i < ARRAY_SIZE(entry->name); i++) { in fat_chksum()
625 ((chksum & 0x01) ? 0x80 : 0)) + entry->name[i]; in fat_chksum()
638 return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11)); in fat_datetime()
639 return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9)); in fat_datetime()
644 if(s->fat_type==32) { in fat_set()
645 uint32_t* entry=array_get(&(s->fat),cluster); in fat_set()
647 } else if(s->fat_type==16) { in fat_set()
648 uint16_t* entry=array_get(&(s->fat),cluster); in fat_set()
652 unsigned char* p = array_get(&(s->fat), offset); in fat_set()
668 if(s->fat_type==32) { in fat_get()
669 uint32_t* entry=array_get(&(s->fat),cluster); in fat_get()
671 } else if(s->fat_type==16) { in fat_get()
672 uint16_t* entry=array_get(&(s->fat),cluster); in fat_get()
675 const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2; in fat_get()
682 if(fat_entry>s->max_fat_value-8) in fat_eof()
683 return -1; in fat_eof()
689 if (s->fat_type == 12) { in init_fat()
690 array_init(&(s->fat),1); in init_fat()
691 array_ensure_allocated(&(s->fat), in init_fat()
692 s->sectors_per_fat * 0x200 * 3 / 2 - 1); in init_fat()
694 array_init(&(s->fat),(s->fat_type==32?4:2)); in init_fat()
695 array_ensure_allocated(&(s->fat), in init_fat()
696 s->sectors_per_fat * 0x200 / s->fat.item_size - 1); in init_fat()
698 memset(s->fat.pointer,0,s->fat.size); in init_fat()
700 switch(s->fat_type) { in init_fat()
701 case 12: s->max_fat_value=0xfff; break; in init_fat()
702 case 16: s->max_fat_value=0xffff; break; in init_fat()
703 case 32: s->max_fat_value=0x0fffffff; break; in init_fat()
704 default: s->max_fat_value=0; /* error... */ in init_fat()
712 int long_index = s->directory.next; in create_short_and_long_name()
717 entry=array_get_next(&(s->directory)); in create_short_and_long_name()
718 memset(entry->name, 0x20, sizeof(entry->name)); in create_short_and_long_name()
719 memcpy(entry->name,filename,strlen(filename)); in create_short_and_long_name()
731 entry_long=array_get(&(s->directory),long_index); in create_short_and_long_name()
733 entry_long->reserved[1]=chksum; in create_short_and_long_name()
746 mapping_t* mapping = array_get(&(s->mapping), mapping_index); in read_directory()
748 const char* dirname = mapping->path; in read_directory()
749 int first_cluster = mapping->begin; in read_directory()
750 int parent_index = mapping->info.dir.parent_mapping_index; in read_directory()
752 (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL); in read_directory()
753 int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1; in read_directory()
759 assert(mapping->mode & MODE_DIRECTORY); in read_directory()
762 mapping->end = mapping->begin; in read_directory()
763 return -1; in read_directory()
766 i = mapping->info.dir.first_dir_index = in read_directory()
767 first_cluster == 0 ? 0 : s->directory.next; in read_directory()
777 unsigned int length=strlen(dirname)+2+strlen(entry->d_name); in read_directory()
780 int is_dot=!strcmp(entry->d_name,"."); in read_directory()
781 int is_dotdot=!strcmp(entry->d_name,".."); in read_directory()
783 if (first_cluster == 0 && s->directory.next >= s->root_entries - 1) { in read_directory()
786 return -2; in read_directory()
793 snprintf(buffer,length,"%s/%s",dirname,entry->d_name); in read_directory()
802 direntry = create_short_and_long_name(s, i, entry->d_name, 0); in read_directory()
804 direntry = array_get(&(s->directory), is_dot ? i : i + 1); in read_directory()
806 direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20); in read_directory()
807 direntry->reserved[0]=direntry->reserved[1]=0; in read_directory()
808 direntry->ctime=fat_datetime(st.st_ctime,1); in read_directory()
809 direntry->cdate=fat_datetime(st.st_ctime,0); in read_directory()
810 direntry->adate=fat_datetime(st.st_atime,0); in read_directory()
811 direntry->begin_hi=0; in read_directory()
812 direntry->mtime=fat_datetime(st.st_mtime,1); in read_directory()
813 direntry->mdate=fat_datetime(st.st_mtime,0); in read_directory()
819 direntry->begin=0; /* do that later */ in read_directory()
824 return -2; in read_directory()
826 direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size); in read_directory()
830 s->current_mapping = array_get_next(&(s->mapping)); in read_directory()
831 s->current_mapping->begin=0; in read_directory()
832 s->current_mapping->end=st.st_size; in read_directory()
837 s->current_mapping->dir_index=s->directory.next-1; in read_directory()
838 s->current_mapping->first_mapping_index = -1; in read_directory()
840 s->current_mapping->mode = MODE_DIRECTORY; in read_directory()
841 s->current_mapping->info.dir.parent_mapping_index = in read_directory()
844 s->current_mapping->mode = MODE_UNDEFINED; in read_directory()
845 s->current_mapping->info.file.offset = 0; in read_directory()
847 s->current_mapping->path=buffer; in read_directory()
848 s->current_mapping->read_only = in read_directory()
857 while(s->directory.next%(0x10*s->sectors_per_cluster)) { in read_directory()
858 direntry = array_get_next(&(s->directory)); in read_directory()
862 if (s->fat_type != 32 && in read_directory()
864 s->directory.next < s->root_entries) { in read_directory()
866 int cur = s->directory.next; in read_directory()
867 array_ensure_allocated(&(s->directory), s->root_entries - 1); in read_directory()
868 s->directory.next = s->root_entries; in read_directory()
869 memset(array_get(&(s->directory), cur), 0, in read_directory()
870 (s->root_entries - cur) * sizeof(direntry_t)); in read_directory()
873 /* re-get the mapping, since s->mapping was possibly realloc()ed */ in read_directory()
874 mapping = array_get(&(s->mapping), mapping_index); in read_directory()
875 first_cluster += (s->directory.next - mapping->info.dir.first_dir_index) in read_directory()
876 * 0x20 / s->cluster_size; in read_directory()
877 mapping->end = first_cluster; in read_directory()
879 direntry = array_get(&(s->directory), mapping->dir_index); in read_directory()
880 set_begin_of_direntry(direntry, mapping->begin); in read_directory()
887 return (sector_num - s->offset_to_root_dir) / s->sectors_per_cluster; in sector2cluster()
892 return s->offset_to_root_dir + s->sectors_per_cluster * cluster_num; in cluster2sector()
904 memset(&(s->first_sectors[0]),0,0x40*0x200); in init_directories()
906 s->cluster_size=s->sectors_per_cluster*0x200; in init_directories()
907 s->cluster_buffer=g_malloc(s->cluster_size); in init_directories()
916 i = 1+s->sectors_per_cluster*0x200*8/s->fat_type; in init_directories()
917 s->sectors_per_fat=(s->sector_count+i)/i; /* round up */ in init_directories()
919 s->offset_to_fat = s->offset_to_bootsector + 1; in init_directories()
920 s->offset_to_root_dir = s->offset_to_fat + s->sectors_per_fat * 2; in init_directories()
922 array_init(&(s->mapping),sizeof(mapping_t)); in init_directories()
923 array_init(&(s->directory),sizeof(direntry_t)); in init_directories()
927 direntry_t* entry=array_get_next(&(s->directory)); in init_directories()
928 entry->attributes=0x28; /* archive | volume label */ in init_directories()
929 memcpy(entry->name, s->volume_label, sizeof(entry->name)); in init_directories()
936 s->root_entries = 0x02 * 0x10 * s->sectors_per_cluster; in init_directories()
937 s->cluster_count=sector2cluster(s, s->sector_count); in init_directories()
939 mapping = array_get_next(&(s->mapping)); in init_directories()
940 mapping->begin = 0; in init_directories()
941 mapping->dir_index = 0; in init_directories()
942 mapping->info.dir.parent_mapping_index = -1; in init_directories()
943 mapping->first_mapping_index = -1; in init_directories()
944 mapping->path = g_strdup(dirname); in init_directories()
945 i = strlen(mapping->path); in init_directories()
946 if (i > 0 && mapping->path[i - 1] == '/') in init_directories()
947 mapping->path[i - 1] = '\0'; in init_directories()
948 mapping->mode = MODE_DIRECTORY; in init_directories()
949 mapping->read_only = 0; in init_directories()
950 s->path = mapping->path; in init_directories()
952 for (i = 0, cluster = 0; i < s->mapping.next; i++) { in init_directories()
953 /* MS-DOS expects the FAT to be 0 for the root directory in init_directories()
957 mapping = array_get(&(s->mapping), i); in init_directories()
959 if (mapping->mode & MODE_DIRECTORY) { in init_directories()
960 char *path = mapping->path; in init_directories()
961 mapping->begin = cluster; in init_directories()
964 return -1; in init_directories()
966 mapping = array_get(&(s->mapping), i); in init_directories()
968 assert(mapping->mode == MODE_UNDEFINED); in init_directories()
969 mapping->mode=MODE_NORMAL; in init_directories()
970 mapping->begin = cluster; in init_directories()
971 if (mapping->end > 0) { in init_directories()
972 direntry_t* direntry = array_get(&(s->directory), in init_directories()
973 mapping->dir_index); in init_directories()
975 mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size; in init_directories()
976 set_begin_of_direntry(direntry, mapping->begin); in init_directories()
978 mapping->end = cluster + 1; in init_directories()
983 assert(mapping->begin < mapping->end); in init_directories()
986 cluster = mapping->end; in init_directories()
988 if(cluster > s->cluster_count) { in init_directories()
991 s->fat_type, s->sector_count / 2000.0); in init_directories()
992 return -1; in init_directories()
998 for(j = mapping->begin; j < mapping->end - 1; j++) in init_directories()
1000 fat_set(s, mapping->end - 1, s->max_fat_value); in init_directories()
1004 mapping = array_get(&(s->mapping), 0); in init_directories()
1005 s->last_cluster_of_root_directory = mapping->end; in init_directories()
1008 fat_set(s,0,s->max_fat_value); in init_directories()
1009 fat_set(s,1,s->max_fat_value); in init_directories()
1011 s->current_mapping = NULL; in init_directories()
1013 bootsector = (bootsector_t *)(s->first_sectors in init_directories()
1014 + s->offset_to_bootsector * 0x200); in init_directories()
1015 bootsector->jump[0]=0xeb; in init_directories()
1016 bootsector->jump[1]=0x3e; in init_directories()
1017 bootsector->jump[2]=0x90; in init_directories()
1018 memcpy(bootsector->name, BOOTSECTOR_OEM_NAME, 8); in init_directories()
1019 bootsector->sector_size=cpu_to_le16(0x200); in init_directories()
1020 bootsector->sectors_per_cluster=s->sectors_per_cluster; in init_directories()
1021 bootsector->reserved_sectors=cpu_to_le16(1); in init_directories()
1022 bootsector->number_of_fats=0x2; /* number of FATs */ in init_directories()
1023 bootsector->root_entries = cpu_to_le16(s->root_entries); in init_directories()
1024 bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count); in init_directories()
1026 bootsector->media_type = (s->offset_to_bootsector > 0 ? 0xf8 : 0xf0); in init_directories()
1027 s->fat.pointer[0] = bootsector->media_type; in init_directories()
1028 bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat); in init_directories()
1029 bootsector->sectors_per_track = cpu_to_le16(secs); in init_directories()
1030 bootsector->number_of_heads = cpu_to_le16(heads); in init_directories()
1031 bootsector->hidden_sectors = cpu_to_le32(s->offset_to_bootsector); in init_directories()
1032 bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0); in init_directories()
1036 bootsector->u.fat16.drive_number = s->offset_to_bootsector == 0 ? 0 : 0x80; in init_directories()
1037 bootsector->u.fat16.signature=0x29; in init_directories()
1038 bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd); in init_directories()
1040 memcpy(bootsector->u.fat16.volume_label, s->volume_label, in init_directories()
1041 sizeof(bootsector->u.fat16.volume_label)); in init_directories()
1042 memcpy(bootsector->u.fat16.fat_type, in init_directories()
1043 s->fat_type == 12 ? "FAT12 " : "FAT16 ", 8); in init_directories()
1044 bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa; in init_directories()
1066 .name = "fat-type",
1120 i = strrchr(filename, ':') - filename; in vvfat_parse_filename()
1122 if (filename[i - 2] == ':' && qemu_isalpha(filename[i - 1])) { in vvfat_parse_filename()
1124 filename += i - 1; in vvfat_parse_filename()
1131 qdict_put_int(options, "fat-type", fat_type); in vvfat_parse_filename()
1139 BDRVVVFATState *s = bs->opaque; in vvfat_open()
1154 ret = -EINVAL; in vvfat_open()
1160 error_setg(errp, "vvfat block driver requires a 'dir' option"); in vvfat_open()
1161 ret = -EINVAL; in vvfat_open()
1165 s->fat_type = qemu_opt_get_number(opts, "fat-type", 0); in vvfat_open()
1168 memset(s->volume_label, ' ', sizeof(s->volume_label)); in vvfat_open()
1174 ret = -EINVAL; in vvfat_open()
1177 memcpy(s->volume_label, label, label_length); in vvfat_open()
1179 memcpy(s->volume_label, "QEMU VVFAT", 10); in vvfat_open()
1184 if (!s->fat_type) { in vvfat_open()
1185 s->fat_type = 12; in vvfat_open()
1187 s->sectors_per_cluster = 2; in vvfat_open()
1189 secs = s->fat_type == 12 ? 18 : 36; in vvfat_open()
1190 s->sectors_per_cluster = 1; in vvfat_open()
1196 if (!s->fat_type) { in vvfat_open()
1197 s->fat_type = 16; in vvfat_open()
1199 s->offset_to_bootsector = 0x3f; in vvfat_open()
1200 cyls = s->fat_type == 12 ? 64 : 1024; in vvfat_open()
1205 switch (s->fat_type) { in vvfat_open()
1214 ret = -EINVAL; in vvfat_open()
1219 s->bs = bs; in vvfat_open()
1222 s->sectors_per_cluster=0x10; in vvfat_open()
1224 s->current_cluster=0xffffffff; in vvfat_open()
1226 s->qcow = NULL; in vvfat_open()
1227 s->qcow_filename = NULL; in vvfat_open()
1228 s->fat2 = NULL; in vvfat_open()
1229 s->downcase_short_names = 1; in vvfat_open()
1234 s->sector_count = cyls * heads * secs - s->offset_to_bootsector; in vvfat_open()
1235 bs->total_sectors = cyls * heads * secs; in vvfat_open()
1244 ret = -EPERM; in vvfat_open()
1246 "Unable to set VVFAT to 'rw' when drive is read-only"); in vvfat_open()
1257 ret = -EIO; in vvfat_open()
1261 s->sector_count = s->offset_to_root_dir in vvfat_open()
1262 + s->sectors_per_cluster * s->cluster_count; in vvfat_open()
1264 /* Disable migration when vvfat is used rw */ in vvfat_open()
1265 if (s->qcow) { in vvfat_open()
1266 error_setg(&s->migration_blocker, in vvfat_open()
1268 "does not support live migration", in vvfat_open()
1270 ret = migrate_add_blocker_normal(&s->migration_blocker, errp); in vvfat_open()
1276 if (s->offset_to_bootsector > 0) { in vvfat_open()
1280 qemu_co_mutex_init(&s->lock); in vvfat_open()
1287 g_free(s->qcow_filename); in vvfat_open()
1288 s->qcow_filename = NULL; in vvfat_open()
1289 g_free(s->cluster_buffer); in vvfat_open()
1290 s->cluster_buffer = NULL; in vvfat_open()
1291 g_free(s->used_clusters); in vvfat_open()
1292 s->used_clusters = NULL; in vvfat_open()
1300 bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */ in vvfat_refresh_limits()
1305 if(s->current_mapping) { in vvfat_close_current_file()
1306 s->current_mapping = NULL; in vvfat_close_current_file()
1307 if (s->current_fd) { in vvfat_close_current_file()
1308 qemu_close(s->current_fd); in vvfat_close_current_file()
1309 s->current_fd = 0; in vvfat_close_current_file()
1312 s->current_cluster = -1; in vvfat_close_current_file()
1315 /* mappings between index1 and index2-1 are supposed to be ordered
1324 mapping=array_get(&(s->mapping),index3); in find_mapping_for_cluster_aux()
1325 assert(mapping->begin < mapping->end); in find_mapping_for_cluster_aux()
1326 if(mapping->begin>=cluster_num) { in find_mapping_for_cluster_aux()
1333 return mapping->end<=cluster_num ? index2 : index1; in find_mapping_for_cluster_aux()
1337 DLOG(mapping=array_get(&(s->mapping),index1); in find_mapping_for_cluster_aux()
1338 assert(mapping->begin<=cluster_num); in find_mapping_for_cluster_aux()
1339 assert(index2 >= s->mapping.next || in find_mapping_for_cluster_aux()
1340 ((mapping = array_get(&(s->mapping),index2)) && in find_mapping_for_cluster_aux()
1341 mapping->end>cluster_num))); in find_mapping_for_cluster_aux()
1347 int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next); in find_mapping_for_cluster()
1349 if(index>=s->mapping.next) in find_mapping_for_cluster()
1351 mapping=array_get(&(s->mapping),index); in find_mapping_for_cluster()
1352 if(mapping->begin>cluster_num) in find_mapping_for_cluster()
1354 assert(mapping->begin<=cluster_num && mapping->end>cluster_num); in find_mapping_for_cluster()
1361 return -1; in open_file()
1362 if(!s->current_mapping || in open_file()
1363 strcmp(s->current_mapping->path,mapping->path)) { in open_file()
1365 int fd = qemu_open_old(mapping->path, in open_file()
1368 return -1; in open_file()
1370 s->current_fd = fd; in open_file()
1373 s->current_mapping = mapping; in open_file()
1379 if(s->current_cluster != cluster_num) { in read_cluster()
1382 assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY)); in read_cluster()
1383 if(!s->current_mapping in read_cluster()
1384 || s->current_mapping->begin>cluster_num in read_cluster()
1385 || s->current_mapping->end<=cluster_num) { in read_cluster()
1389 assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end)); in read_cluster()
1391 if (mapping && mapping->mode & MODE_DIRECTORY) { in read_cluster()
1393 s->current_mapping = mapping; in read_cluster()
1395 offset = s->cluster_size*(cluster_num-s->current_mapping->begin); in read_cluster()
1396 s->cluster = (unsigned char*)s->directory.pointer+offset in read_cluster()
1397 + 0x20*s->current_mapping->info.dir.first_dir_index; in read_cluster()
1398 assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0); in read_cluster()
1399 …assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.it… in read_cluster()
1400 s->current_cluster = cluster_num; in read_cluster()
1405 return -2; in read_cluster()
1406 } else if (s->current_mapping->mode & MODE_DIRECTORY) in read_cluster()
1409 assert(s->current_fd); in read_cluster()
1411 offset = s->cluster_size * in read_cluster()
1412 ((cluster_num - s->current_mapping->begin) in read_cluster()
1413 + s->current_mapping->info.file.offset); in read_cluster()
1414 if(lseek(s->current_fd, offset, SEEK_SET)!=offset) in read_cluster()
1415 return -3; in read_cluster()
1416 s->cluster=s->cluster_buffer; in read_cluster()
1417 result=read(s->current_fd,s->cluster,s->cluster_size); in read_cluster()
1419 s->current_cluster = -1; in read_cluster()
1420 return -1; in read_cluster()
1422 s->current_cluster = cluster_num; in read_cluster()
1451 ADD_CHAR(direntry->name[i]); in print_direntry()
1455 direntry->attributes, in print_direntry()
1456 begin_of_direntry(direntry),le32_to_cpu(direntry->size)); in print_direntry()
1464 mapping, mapping->begin, mapping->end, mapping->dir_index, in print_mapping()
1465 mapping->first_mapping_index, mapping->path, mapping->mode); in print_mapping()
1467 if (mapping->mode & MODE_DIRECTORY) in print_mapping()
1468 …ent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->… in print_mapping()
1470 fprintf(stderr, "offset = %u\n", mapping->info.file.offset); in print_mapping()
1477 BDRVVVFATState *s = bs->opaque; in vvfat_read()
1481 if (sector_num >= bs->total_sectors) in vvfat_read()
1482 return -1; in vvfat_read()
1483 if (s->qcow) { in vvfat_read()
1486 ret = bdrv_co_is_allocated(s->qcow->bs, sector_num * BDRV_SECTOR_SIZE, in vvfat_read()
1487 (nb_sectors - i) * BDRV_SECTOR_SIZE, &n); in vvfat_read()
1495 if (bdrv_co_pread(s->qcow, sector_num * BDRV_SECTOR_SIZE, n, in vvfat_read()
1497 return -1; in vvfat_read()
1499 i += (n >> BDRV_SECTOR_BITS) - 1; in vvfat_read()
1500 sector_num += (n >> BDRV_SECTOR_BITS) - 1; in vvfat_read()
1506 if (sector_num < s->offset_to_root_dir) { in vvfat_read()
1507 if (sector_num < s->offset_to_fat) { in vvfat_read()
1509 &(s->first_sectors[sector_num * 0x200]), in vvfat_read()
1511 } else if (sector_num < s->offset_to_fat + s->sectors_per_fat) { in vvfat_read()
1513 &(s->fat.pointer[(sector_num in vvfat_read()
1514 - s->offset_to_fat) * 0x200]), in vvfat_read()
1516 } else if (sector_num < s->offset_to_root_dir) { in vvfat_read()
1518 &(s->fat.pointer[(sector_num - s->offset_to_fat in vvfat_read()
1519 - s->sectors_per_fat) * 0x200]), in vvfat_read()
1523 uint32_t sector = sector_num - s->offset_to_root_dir, in vvfat_read()
1524 sector_offset_in_cluster=(sector%s->sectors_per_cluster), in vvfat_read()
1525 cluster_num=sector/s->sectors_per_cluster; in vvfat_read()
1526 if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) { in vvfat_read()
1527 /* LATER TODO: strict: return -1; */ in vvfat_read()
1531 memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200); in vvfat_read()
1542 BDRVVVFATState *s = bs->opaque; in vvfat_co_preadv()
1552 return -ENOMEM; in vvfat_co_preadv()
1555 qemu_co_mutex_lock(&s->lock); in vvfat_co_preadv()
1557 qemu_co_mutex_unlock(&s->lock); in vvfat_co_preadv()
1571 * new files and directories (in s->commits).
1604 DLOG(fprintf(stderr, "clear_commits (%u commits)\n", s->commits.next)); in clear_commits()
1605 for (i = 0; i < s->commits.next; i++) { in clear_commits()
1606 commit_t* commit = array_get(&(s->commits), i); in clear_commits()
1607 assert(commit->path || commit->action == ACTION_WRITEOUT); in clear_commits()
1608 if (commit->action != ACTION_WRITEOUT) { in clear_commits()
1609 assert(commit->path); in clear_commits()
1610 g_free(commit->path); in clear_commits()
1612 assert(commit->path == NULL); in clear_commits()
1614 s->commits.next = 0; in clear_commits()
1620 commit_t* commit = array_get_next(&(s->commits)); in schedule_rename()
1621 commit->path = new_path; in schedule_rename()
1622 commit->param.rename.cluster = cluster; in schedule_rename()
1623 commit->action = ACTION_RENAME; in schedule_rename()
1629 commit_t* commit = array_get_next(&(s->commits)); in schedule_writeout()
1630 commit->path = NULL; in schedule_writeout()
1631 commit->param.writeout.dir_index = dir_index; in schedule_writeout()
1632 commit->param.writeout.modified_offset = modified_offset; in schedule_writeout()
1633 commit->action = ACTION_WRITEOUT; in schedule_writeout()
1639 commit_t* commit = array_get_next(&(s->commits)); in schedule_new_file()
1640 commit->path = path; in schedule_new_file()
1641 commit->param.new_file.first_cluster = first_cluster; in schedule_new_file()
1642 commit->action = ACTION_NEW_FILE; in schedule_new_file()
1647 commit_t* commit = array_get_next(&(s->commits)); in schedule_mkdir()
1648 commit->path = path; in schedule_mkdir()
1649 commit->param.mkdir.cluster = cluster; in schedule_mkdir()
1650 commit->action = ACTION_MKDIR; in schedule_mkdir()
1667 lfn->sequence_number = lfn->len = 0; in lfn_init()
1668 lfn->checksum = 0x100; in lfn_init()
1683 lfn->sequence_number = pointer[0] & 0x3f; in parse_long_name()
1684 lfn->checksum = pointer[13]; in parse_long_name()
1685 lfn->name[0] = 0; in parse_long_name()
1686 lfn->name[lfn->sequence_number * 13] = 0; in parse_long_name()
1687 } else if ((pointer[0] & 0x3f) != --lfn->sequence_number) { in parse_long_name()
1689 return -1; in parse_long_name()
1690 } else if (pointer[13] != lfn->checksum) { in parse_long_name()
1692 return -2; in parse_long_name()
1695 return -3; in parse_long_name()
1698 offset = 13 * (lfn->sequence_number - 1); in parse_long_name()
1710 lfn->name2[offset + i] = c; in parse_long_name()
1715 lfn->len = offset + i; in parse_long_name()
1720 gchar *utf8 = g_utf16_to_utf8(lfn->name2, lfn->len, NULL, &olen, NULL); in parse_long_name()
1722 return -4; in parse_long_name()
1724 lfn->len = olen; in parse_long_name()
1725 memcpy(lfn->name, utf8, olen + 1); in parse_long_name()
1741 for (j = 7; j >= 0 && direntry->name[j] == ' '; j--); in parse_short_name()
1743 uint8_t c = direntry->name[i]; in parse_short_name()
1745 return -1; in parse_short_name()
1746 } else if (s->downcase_short_names) { in parse_short_name()
1747 lfn->name[i] = qemu_tolower(direntry->name[i]); in parse_short_name()
1749 lfn->name[i] = direntry->name[i]; in parse_short_name()
1753 for (j = 2; j >= 0 && direntry->name[8 + j] == ' '; j--) { in parse_short_name()
1756 lfn->name[i++] = '.'; in parse_short_name()
1757 lfn->name[i + j + 1] = '\0'; in parse_short_name()
1758 for (;j >= 0; j--) { in parse_short_name()
1759 uint8_t c = direntry->name[8 + j]; in parse_short_name()
1761 return -2; in parse_short_name()
1762 } else if (s->downcase_short_names) { in parse_short_name()
1763 lfn->name[i + j] = qemu_tolower(c); in parse_short_name()
1765 lfn->name[i + j] = c; in parse_short_name()
1769 lfn->name[i + j + 1] = '\0'; in parse_short_name()
1771 if (lfn->name[0] == DIR_KANJI_FAKE) { in parse_short_name()
1772 lfn->name[0] = DIR_KANJI; in parse_short_name()
1774 lfn->len = strlen((char*)lfn->name); in parse_short_name()
1782 if (cluster < s->last_cluster_of_root_directory) { in modified_fat_get()
1783 if (cluster + 1 == s->last_cluster_of_root_directory) in modified_fat_get()
1784 return s->max_fat_value; in modified_fat_get()
1789 if (s->fat_type==32) { in modified_fat_get()
1790 uint32_t* entry=((uint32_t*)s->fat2)+cluster; in modified_fat_get()
1792 } else if (s->fat_type==16) { in modified_fat_get()
1793 uint16_t* entry=((uint16_t*)s->fat2)+cluster; in modified_fat_get()
1796 const uint8_t* x=s->fat2+cluster*3/2; in modified_fat_get()
1807 if (s->qcow == NULL) { in cluster_was_modified()
1811 for (i = 0; !was_modified && i < s->sectors_per_cluster; i++) { in cluster_was_modified()
1812 was_modified = bdrv_co_is_allocated(s->qcow->bs, in cluster_was_modified()
1837 * The array s->used_clusters holds the states of the clusters. If it is
1864 * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens: in get_cluster_count_for_direntry()
1866 * - do_commit will write the cluster into the file at the given in get_cluster_count_for_direntry()
1869 * - the cluster which is overwritten should be moved to a later in get_cluster_count_for_direntry()
1875 * contents of the clusters to-be-overwritten into the qcow. in get_cluster_count_for_direntry()
1893 if (s->qcow) { in get_cluster_count_for_direntry()
1901 assert(mapping->mode & MODE_DELETED); in get_cluster_count_for_direntry()
1902 mapping->mode &= ~MODE_DELETED; in get_cluster_count_for_direntry()
1904 basename = get_basename(mapping->path); in get_cluster_count_for_direntry()
1906 assert(mapping->mode & MODE_NORMAL); in get_cluster_count_for_direntry()
1921 if (s->qcow) { in get_cluster_count_for_direntry()
1924 mapping->begin > cluster_num || in get_cluster_count_for_direntry()
1925 mapping->end <= cluster_num) in get_cluster_count_for_direntry()
1930 (mapping->mode & MODE_DIRECTORY) == 0) { in get_cluster_count_for_direntry()
1933 if (offset != s->cluster_size in get_cluster_count_for_direntry()
1934 * ((cluster_num - mapping->begin) in get_cluster_count_for_direntry()
1935 + mapping->info.file.offset)) { in get_cluster_count_for_direntry()
1940 const char* basename = get_basename(mapping->path); in get_cluster_count_for_direntry()
1945 assert(mapping->first_mapping_index == -1 in get_cluster_count_for_direntry()
1946 || mapping->info.file.offset > 0); in get_cluster_count_for_direntry()
1951 schedule_writeout(s, mapping->dir_index, offset); in get_cluster_count_for_direntry()
1965 for (i = 0; i < s->sectors_per_cluster; i++) { in get_cluster_count_for_direntry()
1968 res = bdrv_co_is_allocated(s->qcow->bs, in get_cluster_count_for_direntry()
1972 return -1; in get_cluster_count_for_direntry()
1975 res = vvfat_read(s->bs, offs, s->cluster_buffer, 1); in get_cluster_count_for_direntry()
1977 return -1; in get_cluster_count_for_direntry()
1979 res = bdrv_co_pwrite(s->qcow, offs * BDRV_SECTOR_SIZE, in get_cluster_count_for_direntry()
1980 BDRV_SECTOR_SIZE, s->cluster_buffer, in get_cluster_count_for_direntry()
1983 return -2; in get_cluster_count_for_direntry()
1991 if (s->used_clusters[cluster_num] & USED_ANY) in get_cluster_count_for_direntry()
1993 s->used_clusters[cluster_num] = USED_FILE; in get_cluster_count_for_direntry()
1999 else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16) in get_cluster_count_for_direntry()
2000 return -1; in get_cluster_count_for_direntry()
2002 offset += s->cluster_size; in get_cluster_count_for_direntry()
2015 unsigned char* cluster = g_malloc(s->cluster_size); in check_directory_consistency()
2029 const char* basename = get_basename(mapping->path); in check_directory_consistency()
2032 assert(mapping->mode & MODE_DIRECTORY); in check_directory_consistency()
2034 assert(mapping->mode & MODE_DELETED); in check_directory_consistency()
2035 mapping->mode &= ~MODE_DELETED; in check_directory_consistency()
2050 if (s->used_clusters[cluster_num] & USED_ANY) { in check_directory_consistency()
2054 s->used_clusters[cluster_num] = USED_DIRECTORY; in check_directory_consistency()
2057 subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster, in check_directory_consistency()
2058 s->sectors_per_cluster); in check_directory_consistency()
2066 for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) { in check_directory_consistency()
2102 pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1, in check_directory_consistency()
2120 DIV_ROUND_UP(le32_to_cpu(direntries[i].size), s->cluster_size)) { in check_directory_consistency()
2146 * - get modified FAT in is_consistent()
2147 * - compare the two FATs (TODO) in is_consistent()
2148 * - get buffer for marking used clusters in is_consistent()
2149 * - recurse direntries from root (using bs->bdrv_pread to make in is_consistent()
2151 * - check that the FAT agrees with the size in is_consistent()
2152 * - count the number of clusters occupied by this directory and in is_consistent()
2154 * - check that the cumulative used cluster count agrees with the in is_consistent()
2156 * - if all is fine, return number of used clusters in is_consistent()
2158 if (s->fat2 == NULL) { in is_consistent()
2159 int size = 0x200 * s->sectors_per_fat; in is_consistent()
2160 s->fat2 = g_malloc(size); in is_consistent()
2161 memcpy(s->fat2, s->fat.pointer, size); in is_consistent()
2163 check = vvfat_read(s->bs, in is_consistent()
2164 s->offset_to_fat, s->fat2, s->sectors_per_fat); in is_consistent()
2169 assert (s->used_clusters); in is_consistent()
2170 for (i = 0; i < sector2cluster(s, s->sector_count); i++) in is_consistent()
2171 s->used_clusters[i] &= ~USED_ANY; in is_consistent()
2177 if (s->qcow) in is_consistent()
2178 for (i = 0; i < s->mapping.next; i++) { in is_consistent()
2179 mapping_t* mapping = array_get(&(s->mapping), i); in is_consistent()
2180 if (mapping->first_mapping_index < 0) in is_consistent()
2181 mapping->mode |= MODE_DELETED; in is_consistent()
2184 used_clusters_count = check_directory_consistency(s, 0, s->path); in is_consistent()
2190 check = s->last_cluster_of_root_directory; in is_consistent()
2191 for (i = check; i < sector2cluster(s, s->sector_count); i++) { in is_consistent()
2193 if(!s->used_clusters[i]) { in is_consistent()
2200 if (s->used_clusters[i] == USED_ALLOCATED) { in is_consistent()
2218 for (i = 0; i < s->mapping.next; i++) { in adjust_mapping_indices()
2219 mapping_t* mapping = array_get(&(s->mapping), i); in adjust_mapping_indices()
2222 if (mapping->name >= offset) \ in adjust_mapping_indices()
2223 mapping->name += adjust in adjust_mapping_indices()
2226 if (mapping->mode & MODE_DIRECTORY) in adjust_mapping_indices()
2236 * - find mapping where mapping->begin >= begin, in insert_mapping()
2237 * - if mapping->begin > begin: insert in insert_mapping()
2238 * - adjust all references to mappings! in insert_mapping()
2239 * - else: adjust in insert_mapping()
2240 * - replace name in insert_mapping()
2242 int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next); in insert_mapping()
2244 mapping_t* first_mapping = array_get(&(s->mapping), 0); in insert_mapping()
2246 if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index)) in insert_mapping()
2247 && mapping->begin < begin) { in insert_mapping()
2248 mapping->end = begin; in insert_mapping()
2250 mapping = array_get(&(s->mapping), index); in insert_mapping()
2252 if (index >= s->mapping.next || mapping->begin > begin) { in insert_mapping()
2253 mapping = array_insert(&(s->mapping), index, 1); in insert_mapping()
2254 mapping->path = NULL; in insert_mapping()
2258 mapping->begin = begin; in insert_mapping()
2259 mapping->end = end; in insert_mapping()
2262 assert(index + 1 >= s->mapping.next || in insert_mapping()
2263 ((next_mapping = array_get(&(s->mapping), index + 1)) && in insert_mapping()
2264 next_mapping->begin >= end))); in insert_mapping()
2266 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer) in insert_mapping()
2267 s->current_mapping = array_get(&(s->mapping), in insert_mapping()
2268 s->current_mapping - first_mapping); in insert_mapping()
2275 mapping_t* mapping = array_get(&(s->mapping), mapping_index); in remove_mapping()
2276 mapping_t* first_mapping = array_get(&(s->mapping), 0); in remove_mapping()
2279 if (mapping->first_mapping_index < 0) { in remove_mapping()
2280 g_free(mapping->path); in remove_mapping()
2283 /* remove from s->mapping */ in remove_mapping()
2284 array_remove(&(s->mapping), mapping_index); in remove_mapping()
2287 adjust_mapping_indices(s, mapping_index, -1); in remove_mapping()
2289 if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer) in remove_mapping()
2290 s->current_mapping = array_get(&(s->mapping), in remove_mapping()
2291 s->current_mapping - first_mapping); in remove_mapping()
2299 for (i = 0; i < s->mapping.next; i++) { in adjust_dirindices()
2300 mapping_t* mapping = array_get(&(s->mapping), i); in adjust_dirindices()
2301 if (mapping->dir_index >= offset) in adjust_dirindices()
2302 mapping->dir_index += adjust; in adjust_dirindices()
2303 if ((mapping->mode & MODE_DIRECTORY) && in adjust_dirindices()
2304 mapping->info.dir.first_dir_index >= offset) in adjust_dirindices()
2305 mapping->info.dir.first_dir_index += adjust; in adjust_dirindices()
2313 * make room in s->directory, in insert_direntries()
2316 direntry_t* result = array_insert(&(s->directory), dir_index, count); in insert_direntries()
2325 int ret = array_remove_slice(&(s->directory), dir_index, count); in remove_direntries()
2328 adjust_dirindices(s, dir_index, -count); in remove_direntries()
2335 * to the modified fat, and the corresponding entries in s->mapping are
2342 direntry_t* direntry = array_get(&(s->directory), dir_index); in commit_mappings()
2348 assert(mapping->begin == first_cluster); in commit_mappings()
2349 mapping->first_mapping_index = -1; in commit_mappings()
2350 mapping->dir_index = dir_index; in commit_mappings()
2351 mapping->mode = (dir_index <= 0 || is_directory(direntry)) ? in commit_mappings()
2361 if (c > mapping->end) { in commit_mappings()
2362 int index = array_index(&(s->mapping), mapping); in commit_mappings()
2363 int i, max_i = s->mapping.next - index; in commit_mappings()
2365 while (--i > 0) in commit_mappings()
2368 assert(mapping == array_get(&(s->mapping), s->mapping.next - 1) in commit_mappings()
2370 mapping->end = c; in commit_mappings()
2373 int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next); in commit_mappings()
2374 mapping_t* next_mapping = i >= s->mapping.next ? NULL : in commit_mappings()
2375 array_get(&(s->mapping), i); in commit_mappings()
2377 if (next_mapping == NULL || next_mapping->begin > c1) { in commit_mappings()
2378 int i1 = array_index(&(s->mapping), mapping); in commit_mappings()
2384 mapping = array_get(&(s->mapping), i1); in commit_mappings()
2387 next_mapping->dir_index = mapping->dir_index; in commit_mappings()
2388 next_mapping->first_mapping_index = in commit_mappings()
2389 mapping->first_mapping_index < 0 ? in commit_mappings()
2390 array_index(&(s->mapping), mapping) : in commit_mappings()
2391 mapping->first_mapping_index; in commit_mappings()
2392 next_mapping->path = mapping->path; in commit_mappings()
2393 next_mapping->mode = mapping->mode; in commit_mappings()
2394 next_mapping->read_only = mapping->read_only; in commit_mappings()
2395 if (mapping->mode & MODE_DIRECTORY) { in commit_mappings()
2396 next_mapping->info.dir.parent_mapping_index = in commit_mappings()
2397 mapping->info.dir.parent_mapping_index; in commit_mappings()
2398 next_mapping->info.dir.first_dir_index = in commit_mappings()
2399 mapping->info.dir.first_dir_index + in commit_mappings()
2400 0x10 * s->sectors_per_cluster * in commit_mappings()
2401 (mapping->end - mapping->begin); in commit_mappings()
2403 next_mapping->info.file.offset = mapping->info.file.offset + in commit_mappings()
2404 (mapping->end - mapping->begin); in commit_mappings()
2418 direntry_t* direntry = array_get(&(s->directory), dir_index); in commit_direntries()
2421 int factor = 0x10 * s->sectors_per_cluster; in commit_direntries()
2430 assert(mapping->begin == first_cluster); in commit_direntries()
2431 assert(mapping->info.dir.first_dir_index < s->directory.next); in commit_direntries()
2432 assert(mapping->mode & MODE_DIRECTORY); in commit_direntries()
2436 mapping->path, parent_mapping_index)); in commit_direntries()
2438 current_dir_index = mapping->info.dir.first_dir_index; in commit_direntries()
2440 mapping->info.dir.parent_mapping_index = parent_mapping_index; in commit_direntries()
2444 s->last_cluster_of_root_directory; in commit_direntries()
2458 factor * (new_cluster_count - old_cluster_count)) == NULL) in commit_direntries()
2459 return -1; in commit_direntries()
2463 factor * (old_cluster_count - new_cluster_count)); in commit_direntries()
2468 direntry = array_get(&(s->directory), current_dir_index); in commit_direntries()
2469 ret = vvfat_read(s->bs, cluster2sector(s, c), (uint8_t *)direntry, in commit_direntries()
2470 s->sectors_per_cluster); in commit_direntries()
2475 first_direntry = (direntry_t*) s->directory.pointer; in commit_direntries()
2476 assert(!memcmp(first_direntry->name, s->volume_label, 11)); in commit_direntries()
2487 direntry = array_get(&(s->directory), first_dir_index + i); in commit_direntries()
2491 return -1; in commit_direntries()
2493 assert(mapping->mode & MODE_DIRECTORY); in commit_direntries()
2495 array_index(&(s->mapping), mapping)); in commit_direntries()
2509 direntry_t* direntry = array_get(&(s->directory), dir_index); in commit_one_file()
2519 assert((offset % s->cluster_size) == 0); in commit_one_file()
2522 return -1; in commit_one_file()
2525 for (i = 0; i < offset; i += s->cluster_size) { in commit_one_file()
2529 fd = qemu_open_old(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666); in commit_one_file()
2531 fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path, in commit_one_file()
2538 return -3; in commit_one_file()
2542 cluster = g_malloc(s->cluster_size); in commit_one_file()
2546 int rest_size = (size - offset > s->cluster_size ? in commit_one_file()
2547 s->cluster_size : size - offset); in commit_one_file()
2552 assert((size - offset == 0 && fat_eof(s, c)) || in commit_one_file()
2555 ret = vvfat_read(s->bs, cluster2sector(s, c), in commit_one_file()
2567 return -2; in commit_one_file()
2578 return -4; in commit_one_file()
2591 for (i = 0; i < s->mapping.next; i++) { in check1()
2592 mapping_t* mapping = array_get(&(s->mapping), i); in check1()
2593 if (mapping->mode & MODE_DELETED) { in check1()
2597 assert(mapping->dir_index < s->directory.next); in check1()
2598 direntry_t* direntry = array_get(&(s->directory), mapping->dir_index); in check1()
2599 assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0); in check1()
2600 if (mapping->mode & MODE_DIRECTORY) { in check1()
2601 …assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping… in check1()
2602 assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0); in check1()
2611 int first_mapping = -1; in check2()
2613 for (i = 0; i < s->directory.next; i++) { in check2()
2614 direntry_t* direntry = array_get(&(s->directory), i); in check2()
2619 assert(mapping->dir_index == i || is_dot(direntry)); in check2()
2620 assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry)); in check2()
2623 if ((i % (0x10 * s->sectors_per_cluster)) == 0) { in check2()
2627 for (j = 0; j < s->mapping.next; j++) { in check2()
2628 mapping_t* mapping = array_get(&(s->mapping), j); in check2()
2629 if (mapping->mode & MODE_DELETED) in check2()
2631 if (mapping->mode & MODE_DIRECTORY) { in check2()
2632 …if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sector… in check2()
2634 if (mapping->first_mapping_index == -1) in check2()
2635 first_mapping = array_index(&(s->mapping), mapping); in check2()
2637 assert(first_mapping == mapping->first_mapping_index); in check2()
2638 if (mapping->info.dir.parent_mapping_index < 0) in check2()
2641 … mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index); in check2()
2642 assert(parent->mode & MODE_DIRECTORY); in check2()
2643 … assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index); in check2()
2649 first_mapping = -1; in check2()
2661 for (i = 0; i < s->commits.next; i++) { in handle_renames_and_mkdirs()
2662 commit_t* commit = array_get(&(s->commits), i); in handle_renames_and_mkdirs()
2664 commit->path ? commit->path : "(null)", in handle_renames_and_mkdirs()
2665 commit->param.rename.cluster, commit->action); in handle_renames_and_mkdirs()
2669 for (i = 0; i < s->commits.next;) { in handle_renames_and_mkdirs()
2670 commit_t* commit = array_get(&(s->commits), i); in handle_renames_and_mkdirs()
2671 if (commit->action == ACTION_RENAME) { in handle_renames_and_mkdirs()
2673 commit->param.rename.cluster); in handle_renames_and_mkdirs()
2677 return -1; in handle_renames_and_mkdirs()
2679 old_path = mapping->path; in handle_renames_and_mkdirs()
2680 assert(commit->path); in handle_renames_and_mkdirs()
2681 mapping->path = commit->path; in handle_renames_and_mkdirs()
2682 if (rename(old_path, mapping->path)) in handle_renames_and_mkdirs()
2683 return -2; in handle_renames_and_mkdirs()
2685 if (mapping->mode & MODE_DIRECTORY) { in handle_renames_and_mkdirs()
2686 int l1 = strlen(mapping->path); in handle_renames_and_mkdirs()
2688 int diff = l1 - l2; in handle_renames_and_mkdirs()
2689 direntry_t* direntry = array_get(&(s->directory), in handle_renames_and_mkdirs()
2690 mapping->info.dir.first_dir_index); in handle_renames_and_mkdirs()
2691 uint32_t c = mapping->begin; in handle_renames_and_mkdirs()
2705 return -1; in handle_renames_and_mkdirs()
2707 l = strlen(m->path); in handle_renames_and_mkdirs()
2710 assert(!strncmp(m->path, mapping->path, l2)); in handle_renames_and_mkdirs()
2712 pstrcpy(new_path, l + diff + 1, mapping->path); in handle_renames_and_mkdirs()
2713 pstrcpy(new_path + l1, l + diff + 1 - l1, in handle_renames_and_mkdirs()
2714 m->path + l2); in handle_renames_and_mkdirs()
2716 schedule_rename(s, m->begin, new_path); in handle_renames_and_mkdirs()
2719 } while (j % (0x10 * s->sectors_per_cluster) != 0); in handle_renames_and_mkdirs()
2725 array_remove(&(s->commits), i); in handle_renames_and_mkdirs()
2727 } else if (commit->action == ACTION_MKDIR) { in handle_renames_and_mkdirs()
2731 if (g_mkdir(commit->path, 0755)) { in handle_renames_and_mkdirs()
2732 return -5; in handle_renames_and_mkdirs()
2735 mapping = insert_mapping(s, commit->param.mkdir.cluster, in handle_renames_and_mkdirs()
2736 commit->param.mkdir.cluster + 1); in handle_renames_and_mkdirs()
2738 return -6; in handle_renames_and_mkdirs()
2740 mapping->mode = MODE_DIRECTORY; in handle_renames_and_mkdirs()
2741 mapping->read_only = 0; in handle_renames_and_mkdirs()
2742 mapping->path = commit->path; in handle_renames_and_mkdirs()
2743 j = s->directory.next; in handle_renames_and_mkdirs()
2745 insert_direntries(s, s->directory.next, in handle_renames_and_mkdirs()
2746 0x10 * s->sectors_per_cluster); in handle_renames_and_mkdirs()
2747 mapping->info.dir.first_dir_index = j; in handle_renames_and_mkdirs()
2749 parent_path_len = strlen(commit->path) in handle_renames_and_mkdirs()
2750 - strlen(get_basename(commit->path)) - 1; in handle_renames_and_mkdirs()
2751 for (j = 0; j < s->mapping.next; j++) { in handle_renames_and_mkdirs()
2752 mapping_t* m = array_get(&(s->mapping), j); in handle_renames_and_mkdirs()
2753 if (m->first_mapping_index < 0 && m != mapping && in handle_renames_and_mkdirs()
2754 !strncmp(m->path, mapping->path, parent_path_len) && in handle_renames_and_mkdirs()
2755 strlen(m->path) == parent_path_len) in handle_renames_and_mkdirs()
2758 assert(j < s->mapping.next); in handle_renames_and_mkdirs()
2759 mapping->info.dir.parent_mapping_index = j; in handle_renames_and_mkdirs()
2761 array_remove(&(s->commits), i); in handle_renames_and_mkdirs()
2779 for (i = 0; !fail && i < s->commits.next; i++) { in handle_commits()
2780 commit_t* commit = array_get(&(s->commits), i); in handle_commits()
2781 switch(commit->action) { in handle_commits()
2784 fail = -2; in handle_commits()
2787 direntry_t* entry = array_get(&(s->directory), in handle_commits()
2788 commit->param.writeout.dir_index); in handle_commits()
2793 assert(mapping->begin == begin); in handle_commits()
2794 assert(commit->path == NULL); in handle_commits()
2796 if (commit_one_file(s, commit->param.writeout.dir_index, in handle_commits()
2797 commit->param.writeout.modified_offset)) in handle_commits()
2798 fail = -3; in handle_commits()
2803 int begin = commit->param.new_file.first_cluster; in handle_commits()
2809 for (j = 0; j < s->directory.next; j++) { in handle_commits()
2810 entry = array_get(&(s->directory), j); in handle_commits()
2815 if (j >= s->directory.next) { in handle_commits()
2816 fail = -6; in handle_commits()
2821 if (mapping && mapping->begin != begin) { in handle_commits()
2822 mapping->end = begin; in handle_commits()
2829 assert(commit->path); in handle_commits()
2830 mapping->path = commit->path; in handle_commits()
2831 mapping->read_only = 0; in handle_commits()
2832 mapping->mode = MODE_NORMAL; in handle_commits()
2833 mapping->info.file.offset = 0; in handle_commits()
2836 fail = -7; in handle_commits()
2845 if (i > 0 && array_remove_slice(&(s->commits), 0, i)) in handle_commits()
2846 return -1; in handle_commits()
2855 /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */ in handle_deletes()
2860 for (i = 1; i < s->mapping.next; i++) { in handle_deletes()
2861 mapping_t* mapping = array_get(&(s->mapping), i); in handle_deletes()
2862 if (mapping->mode & MODE_DELETED) { in handle_deletes()
2863 direntry_t* entry = array_get(&(s->directory), in handle_deletes()
2864 mapping->dir_index); in handle_deletes()
2868 if (mapping->mode & MODE_DIRECTORY) { in handle_deletes()
2869 int j, next_dir_index = s->directory.next, in handle_deletes()
2870 first_dir_index = mapping->info.dir.first_dir_index; in handle_deletes()
2872 if (rmdir(mapping->path) < 0) { in handle_deletes()
2877 return -5; in handle_deletes()
2880 for (j = 1; j < s->mapping.next; j++) { in handle_deletes()
2881 mapping_t* m = array_get(&(s->mapping), j); in handle_deletes()
2882 if (m->mode & MODE_DIRECTORY && in handle_deletes()
2883 m->info.dir.first_dir_index > in handle_deletes()
2885 m->info.dir.first_dir_index < in handle_deletes()
2888 m->info.dir.first_dir_index; in handle_deletes()
2891 next_dir_index - first_dir_index); in handle_deletes()
2896 if (unlink(mapping->path)) in handle_deletes()
2897 return -4; in handle_deletes()
2912 * - copy FAT (with bdrv_pread)
2913 * - mark all filenames corresponding to mappings as deleted
2914 * - recurse direntries from root (using bs->bdrv_pread)
2915 * - delete files corresponding to mappings marked as deleted
2922 if (s->commits.next == 0) in do_commit()
2935 memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat); in do_commit()
2937 /* recurse direntries from root (using bs->bdrv_pread) */ in do_commit()
2938 ret = commit_direntries(s, 0, -1); in do_commit()
2959 bdrv_make_empty(s->qcow, NULL); in do_commit()
2961 memset(s->used_clusters, 0, sector2cluster(s, s->sector_count)); in do_commit()
2972 return -1; in try_commit()
2980 BDRVVVFATState *s = bs->opaque; in vvfat_write()
2986 /* Check if we're operating in read-only mode */ in vvfat_write()
2987 if (s->qcow == NULL) { in vvfat_write()
2988 return -EACCES; in vvfat_write()
2993 if (sector_num == s->offset_to_bootsector && nb_sectors == 1) { in vvfat_write()
2998 unsigned char *bootsector = s->first_sectors in vvfat_write()
2999 + s->offset_to_bootsector * 0x200; in vvfat_write()
3009 return -1; in vvfat_write()
3020 * - do not allow writing to the boot sector in vvfat_write()
3022 if (sector_num < s->offset_to_fat) in vvfat_write()
3023 return -1; in vvfat_write()
3030 last_cluster = sector2cluster(s, sector_num + nb_sectors - 1); in vvfat_write()
3040 if (mapping->read_only) { in vvfat_write()
3041 fprintf(stderr, "Tried to write to write-protected file %s\n", in vvfat_write()
3042 mapping->path); in vvfat_write()
3043 return -1; in vvfat_write()
3046 if (mapping->mode & MODE_DIRECTORY) { in vvfat_write()
3048 int end = begin + s->sectors_per_cluster, k; in vvfat_write()
3059 dir_index = mapping->dir_index + in vvfat_write()
3060 0x10 * (begin - mapping->begin * s->sectors_per_cluster); in vvfat_write()
3061 direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num)); in vvfat_write()
3063 for (k = 0; k < (end - begin) * 0x10; k++) { in vvfat_write()
3064 /* no access to the direntry of a read-only file */ in vvfat_write()
3068 array_get(&(s->directory), dir_index + k), in vvfat_write()
3070 warn_report("tried to write to write-protected " in vvfat_write()
3072 return -1; in vvfat_write()
3077 i = mapping->end; in vvfat_write()
3087 ret = bdrv_co_pwrite(s->qcow, sector_num * BDRV_SECTOR_SIZE, in vvfat_write()
3096 s->used_clusters[i] |= USED_ALLOCATED; in vvfat_write()
3113 BDRVVVFATState *s = bs->opaque; in vvfat_co_pwritev()
3123 return -ENOMEM; in vvfat_co_pwritev()
3127 qemu_co_mutex_lock(&s->lock); in vvfat_co_pwritev()
3129 qemu_co_mutex_unlock(&s->lock); in vvfat_co_pwritev()
3159 BDRVVVFATState *s = bs->opaque; in enable_write_target()
3163 int size = sector2cluster(s, s->sector_count); in enable_write_target()
3166 s->used_clusters = g_malloc0(size); in enable_write_target()
3168 array_init(&(s->commits), sizeof(commit_t)); in enable_write_target()
3170 s->qcow_filename = create_tmp_file(errp); in enable_write_target()
3171 if (!s->qcow_filename) { in enable_write_target()
3172 ret = -ENOENT; in enable_write_target()
3179 ret = -ENOENT; in enable_write_target()
3183 opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort); in enable_write_target()
3185 bs->total_sectors * BDRV_SECTOR_SIZE, &error_abort); in enable_write_target()
3188 ret = bdrv_create(bdrv_qcow, s->qcow_filename, opts, errp); in enable_write_target()
3195 qdict_put_str(options, "write-target.driver", "qcow"); in enable_write_target()
3196 s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs, in enable_write_target()
3201 if (!s->qcow) { in enable_write_target()
3202 ret = -EINVAL; in enable_write_target()
3207 unlink(s->qcow_filename); in enable_write_target()
3230 BDRVVVFATState *s = bs->opaque; in vvfat_close()
3233 array_free(&(s->fat)); in vvfat_close()
3234 array_free(&(s->directory)); in vvfat_close()
3235 array_free(&(s->mapping)); in vvfat_close()
3236 g_free(s->cluster_buffer); in vvfat_close()
3238 if (s->qcow) { in vvfat_close()
3239 migrate_del_blocker(&s->migration_blocker); in vvfat_close()
3245 "fat-type",
3283 assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2); in checkpoint()
3286 … assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY)); in checkpoint()