📄 block-vvfat.c
字号:
for(i=0;i<number_of_entries;i++) { entry=array_get_next(&(s->directory)); entry->attributes=0xf; entry->reserved[0]=0; entry->begin=0; entry->name[0]=(number_of_entries-i)|(i==0?0x40:0); } for(i=0;i<length;i++) { int offset=(i%26); if(offset<10) offset=1+offset; else if(offset<22) offset=14+offset-10; else offset=28+offset-22; entry=array_get(&(s->directory),s->directory.next-1-(i/26)); entry->name[offset]=buffer[i]; } return array_get(&(s->directory),s->directory.next-number_of_entries);}static char is_free(const direntry_t* direntry){ /* return direntry->name[0]==0 ; */ return direntry->attributes == 0 || direntry->name[0]==0xe5;}static char is_volume_label(const direntry_t* direntry){ return direntry->attributes == 0x28;}static char is_long_name(const direntry_t* direntry){ return direntry->attributes == 0xf;}static char is_short_name(const direntry_t* direntry){ return !is_volume_label(direntry) && !is_long_name(direntry) && !is_free(direntry);}static char is_directory(const direntry_t* direntry){ return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;}static inline char is_dot(const direntry_t* direntry){ return is_short_name(direntry) && direntry->name[0] == '.';}static char is_file(const direntry_t* direntry){ return is_short_name(direntry) && !is_directory(direntry);}static inline uint32_t begin_of_direntry(const direntry_t* direntry){ return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);}static inline uint32_t filesize_of_direntry(const direntry_t* direntry){ return le32_to_cpu(direntry->size);}static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin){ direntry->begin = cpu_to_le16(begin & 0xffff); direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);}/* fat functions */static inline uint8_t fat_chksum(const direntry_t* entry){ uint8_t chksum=0; int i; for(i=0;i<11;i++) chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0)) +(unsigned char)entry->name[i]; return chksum;}/* if return_time==0, this returns the fat_date, else the fat_time */static uint16_t fat_datetime(time_t time,int return_time) { struct tm* t;#ifdef _WIN32 t=localtime(&time); /* this is not thread safe */#else struct tm t1; t=&t1; localtime_r(&time,t);#endif if(return_time) return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11)); return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));}static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value){ if(s->fat_type==32) { uint32_t* entry=array_get(&(s->fat),cluster); *entry=cpu_to_le32(value); } else if(s->fat_type==16) { uint16_t* entry=array_get(&(s->fat),cluster); *entry=cpu_to_le16(value&0xffff); } else { int offset = (cluster*3/2); unsigned char* p = array_get(&(s->fat), offset); switch (cluster&1) { case 0: p[0] = value&0xff; p[1] = (p[1]&0xf0) | ((value>>8)&0xf); break; case 1: p[0] = (p[0]&0xf) | ((value&0xf)<<4); p[1] = (value>>4); break; } }}static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster){ if(s->fat_type==32) { uint32_t* entry=array_get(&(s->fat),cluster); return le32_to_cpu(*entry); } else if(s->fat_type==16) { uint16_t* entry=array_get(&(s->fat),cluster); return le16_to_cpu(*entry); } else { const uint8_t* x=s->fat.pointer+cluster*3/2; return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff; }}static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry){ if(fat_entry>s->max_fat_value-8) return -1; return 0;}static inline void init_fat(BDRVVVFATState* s){ if (s->fat_type == 12) { array_init(&(s->fat),1); array_ensure_allocated(&(s->fat), s->sectors_per_fat * 0x200 * 3 / 2 - 1); } else { array_init(&(s->fat),(s->fat_type==32?4:2)); array_ensure_allocated(&(s->fat), s->sectors_per_fat * 0x200 / s->fat.item_size - 1); } memset(s->fat.pointer,0,s->fat.size); switch(s->fat_type) { case 12: s->max_fat_value=0xfff; break; case 16: s->max_fat_value=0xffff; break; case 32: s->max_fat_value=0x0fffffff; break; default: s->max_fat_value=0; /* error... */ }}/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! *//* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s, unsigned int directory_start, const char* filename, int is_dot){ int i,j,long_index=s->directory.next; direntry_t* entry=0; direntry_t* entry_long=0; if(is_dot) { entry=array_get_next(&(s->directory)); memset(entry->name,0x20,11); memcpy(entry->name,filename,strlen(filename)); return entry; } entry_long=create_long_filename(s,filename); i = strlen(filename); for(j = i - 1; j>0 && filename[j]!='.';j--); if (j > 0) i = (j > 8 ? 8 : j); else if (i > 8) i = 8; entry=array_get_next(&(s->directory)); memset(entry->name,0x20,11); strncpy(entry->name,filename,i); if(j > 0) for (i = 0; i < 3 && filename[j+1+i]; i++) entry->extension[i] = filename[j+1+i]; /* upcase & remove unwanted characters */ for(i=10;i>=0;i--) { if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--); if(entry->name[i]<=' ' || entry->name[i]>0x7f || strchr(".*?<>|\":/\\[];,+='",entry->name[i])) entry->name[i]='_'; else if(entry->name[i]>='a' && entry->name[i]<='z') entry->name[i]+='A'-'a'; } /* mangle duplicates */ while(1) { direntry_t* entry1=array_get(&(s->directory),directory_start); int j; for(;entry1<entry;entry1++) if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11)) break; /* found dupe */ if(entry1==entry) /* no dupe found */ break; /* use all 8 characters of name */ if(entry->name[7]==' ') { int j; for(j=6;j>0 && entry->name[j]==' ';j--) entry->name[j]='~'; } /* increment number */ for(j=7;j>0 && entry->name[j]=='9';j--) entry->name[j]='0'; if(j>0) { if(entry->name[j]<'0' || entry->name[j]>'9') entry->name[j]='0'; else entry->name[j]++; } } /* calculate checksum; propagate to long name */ if(entry_long) { uint8_t chksum=fat_chksum(entry); /* calculate anew, because realloc could have taken place */ entry_long=array_get(&(s->directory),long_index); while(entry_long<entry && is_long_name(entry_long)) { entry_long->reserved[1]=chksum; entry_long++; } } return entry;}/* * Read a directory. (the index of the corresponding mapping must be passed). */static int read_directory(BDRVVVFATState* s, int mapping_index){ mapping_t* mapping = array_get(&(s->mapping), mapping_index); direntry_t* direntry; const char* dirname = mapping->path; int first_cluster = mapping->begin; int parent_index = mapping->info.dir.parent_mapping_index; mapping_t* parent_mapping = (mapping_t*) (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : 0); int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1; DIR* dir=opendir(dirname); struct dirent* entry; int i; assert(mapping->mode & MODE_DIRECTORY); if(!dir) { mapping->end = mapping->begin; return -1; } i = mapping->info.dir.first_dir_index = first_cluster == 0 ? 0 : s->directory.next; /* actually read the directory, and allocate the mappings */ while((entry=readdir(dir))) { unsigned int length=strlen(dirname)+2+strlen(entry->d_name); char* buffer; direntry_t* direntry; struct stat st; int is_dot=!strcmp(entry->d_name,"."); int is_dotdot=!strcmp(entry->d_name,".."); if(first_cluster == 0 && (is_dotdot || is_dot)) continue; buffer=(char*)malloc(length); assert(buffer); snprintf(buffer,length,"%s/%s",dirname,entry->d_name); if(stat(buffer,&st)<0) { free(buffer); continue; } /* create directory entry for this file */ direntry=create_short_and_long_name(s, i, entry->d_name, is_dot || is_dotdot); direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20); direntry->reserved[0]=direntry->reserved[1]=0; direntry->ctime=fat_datetime(st.st_ctime,1); direntry->cdate=fat_datetime(st.st_ctime,0); direntry->adate=fat_datetime(st.st_atime,0); direntry->begin_hi=0; direntry->mtime=fat_datetime(st.st_mtime,1); direntry->mdate=fat_datetime(st.st_mtime,0); if(is_dotdot) set_begin_of_direntry(direntry, first_cluster_of_parent); else if(is_dot) set_begin_of_direntry(direntry, first_cluster); else direntry->begin=0; /* do that later */ if (st.st_size > 0x7fffffff) { fprintf(stderr, "File %s is larger than 2GB\n", buffer); free(buffer); return -2; } direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size); /* create mapping for this file */ if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) { s->current_mapping=(mapping_t*)array_get_next(&(s->mapping)); s->current_mapping->begin=0; s->current_mapping->end=st.st_size; /* * we get the direntry of the most recent direntry, which * contains the short name and all the relevant information. */ s->current_mapping->dir_index=s->directory.next-1; s->current_mapping->first_mapping_index = -1; if (S_ISDIR(st.st_mode)) { s->current_mapping->mode = MODE_DIRECTORY; s->current_mapping->info.dir.parent_mapping_index = mapping_index; } else { s->current_mapping->mode = MODE_UNDEFINED; s->current_mapping->info.file.offset = 0; } s->current_mapping->path=buffer; s->current_mapping->read_only = (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0; } } closedir(dir); /* fill with zeroes up to the end of the cluster */ while(s->directory.next%(0x10*s->sectors_per_cluster)) { direntry_t* direntry=array_get_next(&(s->directory)); memset(direntry,0,sizeof(direntry_t)); }/* TODO: if there are more entries, bootsector has to be adjusted! */#define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster) if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) { /* root directory */ int cur = s->directory.next; array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1); memset(array_get(&(s->directory), cur), 0, (ROOT_ENTRIES - cur) * sizeof(direntry_t)); } /* reget the mapping, since s->mapping was possibly realloc()ed */ mapping = (mapping_t*)array_get(&(s->mapping), mapping_index); first_cluster += (s->directory.next - mapping->info.dir.first_dir_index) * 0x20 / s->cluster_size; mapping->end = first_cluster; direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index); set_begin_of_direntry(direntry, mapping->begin); return 0;}static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num){ return (sector_num-s->faked_sectors)/s->sectors_per_cluster;}static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num){ return s->faked_sectors + s->sectors_per_cluster * cluster_num;}static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num){ return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;}#ifdef DBGstatic direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping){ if(mapping->mode==MODE_UNDEFINED) return 0; return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);}#endifstatic int init_directories(BDRVVVFATState* s,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -