fat.c.svn-base
来自「psp播放器PPA源码,在MSYS/CYGWIN环境下编译(GNU-C)」· SVN-BASE 代码 · 共 542 行
SVN-BASE
542 行
#include <stdlib.h>#include <string.h>#include <stdio.h>#include <pspkernel.h>#include "fat.h"#include "libminiconv.h"static int fwVersion;static int fatfd = -1;static t_fat_dbr dbr;static t_fat_mbr mbr;static u32 * fat_table = NULL;static u64 dbr_pos = 0;static u64 root_pos = 0;static u64 data_pos = 0;static u64 bytes_per_clus = 0;static u32 loadcount = 0;static u32 clus_max = 0;static enum { fat12, fat16, fat32} fat_type = fat16;int fat_init(int devkitVersion){ fwVersion = devkitVersion; fatfd = sceIoOpen("msstor:", PSP_O_RDONLY, 0777); if(fatfd < 0) return 0; if(sceIoRead(fatfd, &mbr, sizeof(mbr)) != sizeof(mbr)) { sceIoClose(fatfd); fatfd = -1; return 0; } dbr_pos = mbr.dpt[0].start_sec * 0x200; if(sceIoLseek32(fatfd, dbr_pos, PSP_SEEK_SET) != dbr_pos || sceIoRead(fatfd, &dbr, sizeof(dbr)) < sizeof(dbr)) { dbr_pos = 0; if(sceIoLseek32(fatfd, dbr_pos, PSP_SEEK_SET) != dbr_pos || sceIoRead(fatfd, &dbr, sizeof(dbr)) < sizeof(dbr)) { sceIoClose(fatfd); fatfd = -1; return 0; } } u64 total_sec = ( dbr.total_sec == 0 ) ? dbr.big_total_sec : dbr.total_sec; u64 fat_sec = (dbr.sec_per_fat == 0 ) ? dbr.ufat.fat32.sec_per_fat : dbr.sec_per_fat; u64 root_sec = ( dbr.root_entry * 32 + dbr.bytes_per_sec - 1 ) / dbr.bytes_per_sec; u64 data_sec = total_sec - dbr.reserved_sec - ( dbr.num_fats * fat_sec ) - root_sec; u64 data_clus = data_sec / dbr.sec_per_clus ; if ( data_clus < 4085 ) { fat_type = fat12; clus_max = 0x0FF0; } else if ( data_clus < 65525 ) { fat_type = fat16; clus_max = 0xFFF0; } else { fat_type = fat32; clus_max = 0x0FFFFFF0; } // if ( dbr.root_entry == 0 )// {// fat_type = fat32;// clus_max = 0x0FFFFFF0;// }// else if(mbr.dpt[0].id == 0x1)// {// fat_type = fat12;// clus_max = 0x0FF0;// }// else //if(mbr.dpt[0].id == 0x4 || mbr.dpt[0].id == 0x6 || mbr.dpt[0].id == 0xE || mbr.dpt[0].id == 0xB )// {// fat_type = fat16;// clus_max = 0xFFF0;// } bytes_per_clus = 1ull * dbr.sec_per_clus * dbr.bytes_per_sec; if(fat_type == fat32) { data_pos = 1ull * dbr_pos; data_pos += 1ull * (dbr.ufat.fat32.sec_per_fat * dbr.num_fats + dbr.reserved_sec) * dbr.bytes_per_sec; root_pos = data_pos; root_pos += 1ull * bytes_per_clus * dbr.ufat.fat32.root_clus; } else { root_pos = 1ull * dbr_pos; root_pos += 1ull * (dbr.num_fats * dbr.sec_per_fat + dbr.reserved_sec) * dbr.bytes_per_sec; data_pos = root_pos; data_pos += 1ull * dbr.root_entry * sizeof(t_fat_entry); } sceIoClose(fatfd); return 1;}static int convert_table_fat12(){ u16 * otable = (u16 *)malloc(dbr.sec_per_fat * dbr.bytes_per_sec); if(otable == NULL) return 0; memcpy(otable, fat_table, dbr.sec_per_fat * dbr.bytes_per_sec); int i, j, entrycount = dbr.sec_per_fat * dbr.bytes_per_sec / sizeof(u16) * 4 / 3; free((void *)fat_table); fat_table = (u32 *)malloc(sizeof(u32) * entrycount); if(fat_table == NULL) { free((void *)otable); return 0; } for(i = 0, j = 0; i < entrycount; i += 4, j += 3) { fat_table[i] = otable[j] & 0x0FFF; fat_table[i + 1] = ((otable[j] >> 12) & 0x000F) | ((otable[j + 1] & 0x00FF) << 4); fat_table[i + 2] = ((otable[j + 1] >> 8) & 0x00FF) | ((otable[j + 2] & 0x000F) << 8); fat_table[i + 3] = otable[j + 2] >> 4; } free((void *)otable); return 1;}static int convert_table_fat16(){ u16 * otable = (u16 *)malloc(dbr.sec_per_fat * dbr.bytes_per_sec); if(otable == NULL) return 0; memcpy(otable, fat_table, dbr.sec_per_fat * dbr.bytes_per_sec); int i, entrycount = dbr.sec_per_fat * dbr.bytes_per_sec / sizeof(u16); free((void *)fat_table); fat_table = (u32 *)malloc(sizeof(u32) * entrycount); if(fat_table == NULL) { free((void *)otable); return 0; } for(i = 0; i < entrycount; i ++) fat_table[i] = otable[i]; free((void *)otable); return 1;}static int fat_load_table(){ if(loadcount > 0) { loadcount ++; return 1; } fatfd = sceIoOpen("msstor:", PSP_O_RDONLY, 0777); if(fatfd < 0) return 0; u32 fat_table_size = ((fat_type == fat32) ? dbr.ufat.fat32.sec_per_fat : dbr.sec_per_fat) * dbr.bytes_per_sec; if(sceIoLseek32(fatfd, dbr_pos + dbr.reserved_sec * dbr.bytes_per_sec, PSP_SEEK_SET) != dbr_pos + dbr.reserved_sec * dbr.bytes_per_sec || (fat_table = (u32 *)malloc(fat_table_size)) == NULL) { sceIoClose(fatfd); fatfd = -1; return 0; } if( (sceIoRead(fatfd, fat_table, fat_table_size) != fat_table_size) || (fat_type == fat12 && !convert_table_fat12()) || ( fat_type == fat16 && !convert_table_fat16())) { sceIoClose(fatfd); fatfd = -1; free((void *)fat_table); fat_table = NULL; return 0; } loadcount = 1; return 1;}static void fat_free_table(){ if(loadcount > 0) { loadcount --; if(loadcount > 0) return; if(fat_table != NULL) { free((void *)fat_table); fat_table = NULL; } sceIoClose(fatfd); }}static u8 fat_calc_chksum(p_fat_entry info){ u8 * n = (u8 *)&info->norm.filename[0]; u8 chksum = 0; u32 i; for(i = 0; i < 11; i ++) chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + n[i]; return chksum;}static int fat_dir_list(u32 clus, u32 * count, p_fat_entry * entrys){ if(clus == 0) return 0; if(clus < 2) { * count = dbr.root_entry; if((* entrys = (p_fat_entry)malloc(* count * sizeof(t_fat_entry))) == NULL) return 0; if(sceIoLseek(fatfd, root_pos, PSP_SEEK_SET) != root_pos || sceIoRead(fatfd, * entrys, * count * sizeof(t_fat_entry)) != * count * sizeof(t_fat_entry)) { free((void *)* entrys); return 0; } } else { if(fat_table[clus] < 2) return 0; u32 c2 = clus; * count = 1; while(fat_table[c2] < clus_max && fat_table[c2] > 1) { c2 = fat_table[c2]; (* count) ++; } c2 = clus; u32 epc = (bytes_per_clus / sizeof(t_fat_entry)), ep = 0; (* count) *= epc; if((* entrys = (p_fat_entry)malloc(* count * sizeof(t_fat_entry))) == NULL) return 0; do { u64 epos = data_pos + 1ull * (c2 - 2) * bytes_per_clus; if(sceIoLseek(fatfd, epos, PSP_SEEK_SET) != epos || sceIoRead(fatfd, &(* entrys)[ep], bytes_per_clus) != bytes_per_clus) { free((void *)* entrys); return 0; } ep += epc; c2 = fat_table[c2]; } while(c2 < clus_max && c2 > 1); } return 1;}static int fat_get_longname(p_fat_entry entrys, u32 cur, char * longnamestr){ u16 chksum = fat_calc_chksum(&entrys[cur]); u32 j = cur; u16 longname[260]; memset(longname, 0, 260 * sizeof(u16)); while(j > 0) { j --; if(entrys[j].norm.attr != 0x0F || entrys[j].longfile.checksum != chksum || entrys[j].norm.filename[0] == 0 || (u8)entrys[j].norm.filename[0] == 0xE5) return 0; u32 order = entrys[j].longfile.order & 0x3F; if(order > 20) return 0; u32 ppos = (order - 1) * 13; u32 k; for(k = 0; k < 5; k ++) longname[ppos ++] = entrys[j].longfile.uni_name[k]; for(k = 0; k < 6; k ++) longname[ppos ++] = entrys[j].longfile.uni_name2[k]; for(k = 0; k < 2; k ++) longname[ppos ++] = entrys[j].longfile.uni_name3[k]; if((entrys[j].longfile.order & 0x40) > 0) break; } if(entrys[j].norm.attr != 0x0F || (entrys[j].longfile.order & 0x40) == 0) return 0; longname[255] = 0; memset(longnamestr, 0, 256); char* temp = miniConvUTF16LEConv(longname); if(temp) { strncpy(longnamestr, temp, 255); } return 1;}static void fat_get_shortname(p_fat_entry entry, char * shortnamestr){ static int chartable[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x30 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 0x50 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 0x70 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xA0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xB0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xC0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xD0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xE0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 0xF0 }; u32 i = 0; u8 abit = 0; if((entry->norm.flag & 0x08) > 0) abit = 0x20; while(i < 8 && entry->norm.filename[i] != 0x20) { *shortnamestr ++ = entry->norm.filename[i] | ((chartable[(u8)entry->norm.filename[i]]) ? abit : 0); i ++; } if(entry->norm.fileext[0] != 0x20) { *shortnamestr ++ = '.'; i = 0; while(i < 3 && entry->norm.fileext[i] != 0x20) *shortnamestr ++ = entry->norm.fileext[i ++] | abit; } *shortnamestr = 0;}int fat_locate(const char * name, char * sname, u32 clus, p_fat_entry info){ u32 count; p_fat_entry entrys; if(!fat_dir_list(clus, &count, &entrys)) return 0; SceUID dl = sceIoDopen(sname); if(dl < 0) return 0; char shortname[11]; int onlylong = 0; u32 nlen = strlen(name); if(nlen > 12) onlylong = 1; else { char * dot = strrchr(name, '.'); if((dot == NULL && nlen < 9) || (dot - name < 9 && nlen - 1 - (dot - name) < 4)) { memset(&shortname[0], 0x20, 11); memcpy(&shortname[0], name, (dot == NULL) ? nlen : (dot - name)); if(dot != NULL) memcpy(&shortname[8], dot + 1, nlen - 1 - (dot - name)); } else onlylong = 1; } SceIoDirent sid; u32 i; for(i = 0; i < count; i ++) { if((entrys[i].norm.attr & FAT_FILEATTR_VOLUME) == 0 && entrys[i].norm.filename[0] != 0 && (u8)entrys[i].norm.filename[0] != 0xE5) { memset(&sid, 0, sizeof(SceIoDirent)); int result; while((result = sceIoDread(dl, &sid)) > 0 && (sid.d_stat.st_attr & 0x08) > 0); if(result == 0) break; if(entrys[i].norm.filename[0] == 0x05) entrys[i].norm.filename[0] = 0xE5; if(!onlylong && strnicmp(shortname, &entrys[i].norm.filename[0], 11) == 0) { if((u8)entrys[i].norm.filename[0] == 0xE5) entrys[i].norm.filename[0] = 0x05; memcpy(info, &entrys[i], sizeof(t_fat_entry)); free((void *)entrys); if (fwVersion < 0x04000110) strcat(sname, sid.d_name); else { char short_name[256]; memset(short_name, 0, 256); fat_get_shortname(info, short_name); strcat(sname, short_name); } if((info->norm.attr & FAT_FILEATTR_DIRECTORY) > 0) strcat(sname, "/"); sceIoDclose(dl); return 1; } if((u8)entrys[i].norm.filename[0] == 0xE5) entrys[i].norm.filename[0] = 0x05; char longnames[256]; if(!fat_get_longname(entrys, i, longnames)) continue; if(stricmp(name, longnames) == 0) { memcpy(info, &entrys[i], sizeof(t_fat_entry)); free((void *)entrys); if (fwVersion < 0x04000110) strcat(sname, sid.d_name); else { char short_name[256]; memset(short_name, 0, 256); fat_get_shortname(info, short_name); strcat(sname, short_name); } if((info->norm.attr & FAT_FILEATTR_DIRECTORY) > 0) strcat(sname, "/"); sceIoDclose(dl); return 1; } } } free((void *)entrys); sceIoDclose(dl); return 0;}static u32 fat_dir_clus(const char * dir, char * shortdir){ if(!fat_load_table() || fatfd < 0) return 0; char rdir[256]; strcpy(rdir, dir); char * partname = strtok(rdir, "/\\"); if(partname == NULL) { fat_free_table(); return 0; } if(strcmp(partname, "ms0:") != 0 && strcmp(partname, "fatms:") != 0 && strcmp(partname, "fatms0:") != 0) { fat_free_table(); return 0; } strcpy(shortdir, partname); strcat(shortdir, "/"); partname = strtok(NULL, "/\\"); u32 clus = (fat_type == fat32) ? dbr.ufat.fat32.root_clus : 1; t_fat_entry entry; while(partname != NULL) { if(partname[0] != 0) { if(fat_locate(partname, shortdir, clus, &entry)) { clus = entry.norm.clus_high; clus = ((fat_type == fat32) ? (clus << 16) : 0) + entry.norm.clus; } else { fat_free_table(); return 0; } } partname = strtok(NULL, "/\\"); } fat_free_table(); return clus;}u32 fat_readdir(const char * dir, char * sdir, p_fat_info * info){ if(!fat_load_table() || fatfd < 0) return INVALID; u32 clus = fat_dir_clus(dir, sdir); SceUID dl = 0; if(clus == 0 || (dl = sceIoDopen(sdir)) < 0) { fat_free_table(); sceIoDclose(dl); return INVALID; } u32 ecount = 0; p_fat_entry entrys; if(!fat_dir_list(clus, &ecount, &entrys)) { fat_free_table(); sceIoDclose(dl); return INVALID; } u32 count = 0, cur = 0, i; for(i = 0; i < ecount; i ++) { if((entrys[i].norm.attr & FAT_FILEATTR_VOLUME) != 0 || entrys[i].norm.filename[0] == 0 || (u8)entrys[i].norm.filename[0] == 0xE5 || (entrys[i].norm.filename[0] == '.' && entrys[i].norm.filename[1] == 0x20)) continue; count ++; } if(count == 0 || (*info = (p_fat_info)malloc(count * sizeof(t_fat_info))) == NULL) { free(entrys); fat_free_table(); sceIoDclose(dl); return INVALID; } SceIoDirent sid; for(i = 0; i < ecount; i ++) { if((entrys[i].norm.attr & FAT_FILEATTR_VOLUME) != 0 || entrys[i].norm.filename[0] == 0 || (u8)entrys[i].norm.filename[0] == 0xE5 || (entrys[i].norm.filename[0] == '.' && entrys[i].norm.filename[1] == 0x20)) continue; memset(&sid, 0, sizeof(SceIoDirent)); int result; while((result = sceIoDread(dl, &sid)) > 0 && ((sid.d_stat.st_attr & 0x08) > 0 || (sid.d_name[0] == '.' && sid.d_name[1] == 0))); if(result == 0) break; p_fat_info inf = &((*info)[cur]); fat_get_shortname(&entrys[i], inf->filename); if(inf->filename[0] == 0x05) inf->filename[0] = 0xE5; if(!fat_get_longname(entrys, i, inf->longname)) strcpy(inf->longname, inf->filename); if (fwVersion < 0x04000110) strcpy(inf->filename, sid.d_name); inf->filesize = entrys[i].norm.filesize; inf->cdate = entrys[i].norm.cr_date; inf->ctime = entrys[i].norm.cr_time; inf->mdate = entrys[i].norm.last_mod_date; inf->mtime = entrys[i].norm.last_mod_time; inf->clus = ((fat_type == fat32) ? (((u32)entrys[i].norm.clus_high) << 16) : 0) + entrys[i].norm.clus; inf->attr = entrys[i].norm.attr; cur ++; } free(entrys); fat_free_table(); sceIoDclose(dl); return cur;}void fat_free(){ if(fatfd >= 0) { sceIoClose(fatfd); fatfd = -1; } memset(&dbr, 0, sizeof(dbr)); memset(&mbr, 0, sizeof(mbr)); root_pos = 0; data_pos = 0; bytes_per_clus = 0; loadcount = 0; clus_max = 0; fat_type = fat16;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?