#include <errno.h> #include <string.h> #include <unistd.h> #include <assert.h> #include <sys/types.h> #include <sys/stat.h> #define FUSE_USE_VERSION 26 #include <fuse.h> #include "fat16.h" char* FAT_FILE_NAME = "fat16.img"; /* 将扇区号为secnum的扇区读到buffer中 */ void sector_read(FILE* fd, unsigned int secnum, void* buffer) { fseek(fd, BYTES_PER_SECTOR * secnum, SEEK_SET); fread(buffer, BYTES_PER_SECTOR, 1, fd); } /** TODO: * 将输入路径按“/”分割成多个字符串,并按照FAT文件名格式转换字符串 * * Hint1:假设pathInput为“/dir1/dir2/file.txt”,则将其分割成“dir1”,“dir2”,“file.txt”, * 每个字符串转换成长度为11的FAT格式的文件名,如“file.txt”转换成“FILE TXT”, * 返回转换后的字符串数组,并将*pathDepth_ret设置为3 * Hint2:可能会出现过长的字符串输入,如“/.Trash-1000”,需要自行截断字符串 **/ char** path_split(char* pathInput, int* pathDepth_ret) { int pathDepth = 1; int l = 0, dot = 0; char** paths = malloc(pathDepth * sizeof(char*)); char* path = malloc(11 * sizeof(char)); memset(path, 0x20, 11); int length = strlen(pathInput); int i, j; for (i = 1; i < length; i++) { if (pathInput[i] == '/') { *(paths + pathDepth - 1) = path; pathDepth++; paths = realloc(paths, pathDepth * sizeof(char*)); l = 0; path = malloc(11 * sizeof(char)); memset(path, 0x20, 11); } else if (pathInput[i] != '.') { if (!dot && l < 8 || dot && l < 11) { if (pathInput[i] >= 'a' && pathInput[i] <= 'z') * (path + l) = pathInput[i] - 32; else *(path + l) = pathInput[i]; l++; } } else { l = 8; dot = 1; } } *(paths + pathDepth - 1) = path; *pathDepth_ret = pathDepth; return paths; } /** TODO: * 将FAT文件名格式解码成原始的文件名 * * Hint:假设path是“FILE TXT”,则返回"file.txt" **/ BYTE* path_decode(BYTE* path) { BYTE* pathDecoded = malloc(MAX_SHORT_NAME_LEN * sizeof(BYTE)); memset(pathDecoded, 0x00, MAX_SHORT_NAME_LEN); int i; int k = 0; for (i = 0; i < 11; i++) { if (i == 8 && *(path + i) != 0x20) { *(pathDecoded + k) = '.'; k++; } if (*(path + i) >= 'A' && *(path + i) <= 'Z') { *(pathDecoded + k) = *(path + i) + 32; k++; } else if (*(path + i) != 0x20) { *(pathDecoded + k) = *(path + i); k++; } } return pathDecoded; } FAT16* pre_init_fat16(void) { /* Opening the FAT16 image file */ FILE* fd; FAT16* fat16_ins; fd = fopen(FAT_FILE_NAME, "rb"); if (fd == NULL) { fprintf(stderr, "Missing FAT16 image file!\n"); exit(EXIT_FAILURE); } fat16_ins = malloc(sizeof(FAT16)); fat16_ins->fd = fd; /** TODO: * 初始化fat16_ins的其余成员变量 * Hint: root directory的大小与Bpb.BPB_RootEntCnt有关,并且是扇区对齐的 **/ fread(fat16_ins->Bpb.BS_jmpBoot, sizeof(BYTE), 3, fd); fread(fat16_ins->Bpb.BS_OEMName, sizeof(BYTE), 8, fd); fread(&fat16_ins->Bpb.BPB_BytsPerSec, sizeof(WORD), 1, fd); fread(&fat16_ins->Bpb.BPB_SecPerClus, sizeof(BYTE), 1, fd); fread(&fat16_ins->Bpb.BPB_RsvdSecCnt, sizeof(WORD), 1, fd); fread(&fat16_ins->Bpb.BPB_NumFATS, sizeof(BYTE), 1, fd); fread(&fat16_ins->Bpb.BPB_RootEntCnt, sizeof(WORD), 1, fd); fread(&fat16_ins->Bpb.BPB_TotSec16, sizeof(WORD), 1, fd); fread(&fat16_ins->Bpb.BPB_Media, sizeof(BYTE), 1, fd); fread(&fat16_ins->Bpb.BPB_FATSz16, sizeof(WORD), 1, fd); fread(&fat16_ins->Bpb.BPB_SecPerTrk, sizeof(WORD), 1, fd); fread(&fat16_ins->Bpb.BPB_NumHeads, sizeof(WORD), 1, fd); fread(&fat16_ins->Bpb.BPB_HiddSec, sizeof(DWORD), 1, fd); fread(&fat16_ins->Bpb.BPB_TotSec32, sizeof(DWORD), 1, fd); fread(&fat16_ins->Bpb.BS_DrvNum, sizeof(BYTE), 1, fd); fread(&fat16_ins->Bpb.BS_Reserved1, sizeof(BYTE), 1, fd); fread(&fat16_ins->Bpb.BS_BootSig, sizeof(BYTE), 1, fd); fread(&fat16_ins->Bpb.BS_VollID, sizeof(DWORD), 1, fd); fread(fat16_ins->Bpb.BS_VollLab, sizeof(BYTE), 11, fd); fread(fat16_ins->Bpb.BS_FilSysType, sizeof(BYTE), 8, fd); fread(fat16_ins->Bpb.Reserved2, sizeof(BYTE), 448, fd); fread(&fat16_ins->Bpb.Signature_word, sizeof(WORD), 1, fd); fat16_ins->FirstRootDirSecNum = fat16_ins->Bpb.BPB_RsvdSecCnt + fat16_ins->Bpb.BPB_FATSz16 + fat16_ins->Bpb.BPB_FATSz16; fat16_ins->FirstDataSector = fat16_ins->FirstRootDirSecNum + 32 * fat16_ins->Bpb.BPB_RootEntCnt / fat16_ins->Bpb.BPB_BytsPerSec; return fat16_ins; } /** TODO: * 返回簇号为ClusterN对应的FAT表项 **/ WORD fat_entry_by_cluster(FAT16* fat16_ins, WORD ClusterN) { BYTE sector_buffer[BYTES_PER_SECTOR]; WORD clu; fseek(fat16_ins->fd, (ClusterN * 2 / fat16_ins->Bpb.BPB_BytsPerSec + fat16_ins->Bpb.BPB_RsvdSecCnt) * BYTES_PER_SECTOR, 0); fread(sector_buffer, sizeof(BYTE), fat16_ins->Bpb.BPB_BytsPerSec, fat16_ins->fd); clu = sector_buffer[(ClusterN % (fat16_ins->Bpb.BPB_BytsPerSec / 2)) * 2 + 1] * 0x100 + sector_buffer[(ClusterN % (BYTES_PER_SECTOR / 2)) * 2]; if (clu != 0xffff) return clu; return 0xffff; } /** * 根据簇号ClusterN,获取其对应的第一个扇区的扇区号和数据,以及对应的FAT表项 **/ void first_sector_by_cluster(FAT16* fat16_ins, WORD ClusterN, WORD* FatClusEntryVal, WORD* FirstSectorofCluster, BYTE* buffer) { *FatClusEntryVal = fat_entry_by_cluster(fat16_ins, ClusterN); *FirstSectorofCluster = ((ClusterN - 2) * fat16_ins->Bpb.BPB_SecPerClus) + fat16_ins->FirstDataSector; sector_read(fat16_ins->fd, *FirstSectorofCluster, buffer); } /** * 从root directory开始,查找path对应的文件或目录,找到返回0,没找到返回1,并将Dir填充为查找到的对应目录项 * * Hint: 假设path是“/dir1/dir2/file”,则先在root directory中查找名为dir1的目录, * 然后在dir1中查找名为dir2的目录,最后在dir2中查找名为file的文件,找到则返回0,并且将file的目录项数据写入到参数Dir对应的DIR_ENTRY中 **/ int find_root(FAT16* fat16_ins, DIR_ENTRY* Dir, const char* path) { int pathDepth; char** paths = path_split((char*)path, &pathDepth); /* 先读取root directory */ int i, j; int RootDirCnt = 1; /* 用于统计已读取的扇区数 */ BYTE buffer[BYTES_PER_SECTOR]; BYTE name[11]; sector_read(fat16_ins->fd, fat16_ins->FirstRootDirSecNum, buffer); /** TODO: * 查找名字为paths[0]的目录项, * 如果找到目录,则根据pathDepth判断是否需要调用find_subdir继续查找, * * !!注意root directory可能包含多个扇区 **/ for (i = 1; i <= fat16_ins->Bpb.BPB_RootEntCnt; i++) { for (j = 0; j < 11; j++) { name[j] = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + j]; } if (strncmp(name, paths[0], 11) == 0) { if (pathDepth == 1) { strcpy(Dir->DIR_Name, name); Dir->DIR_Attr = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 11]; Dir->DIR_NTRes = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 12]; Dir->DIR_CrtTimeTenth = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 13]; Dir->DIR_CrtTime = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 15] * 0x100 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 14]; Dir->DIR_CrtDate = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 17] * 0x100 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 16]; Dir->DIR_LstAccDate = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 19] * 0x100 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 18]; Dir->DIR_FstClusHI = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 21] * 0x100 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 20]; Dir->DIR_WrtTime = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 23] * 0x100 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 22]; Dir->DIR_WrtDate = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 25] * 0x100 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 24]; Dir->DIR_FstClusLO = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 27] * 0x100 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 26]; Dir->DIR_FileSize = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 31] * 0x1000000 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 30] * 0x10000 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 29] * 0x100 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 28]; return 0; } else { Dir->DIR_FstClusLO = buffer[32 * (i - 1) + 27] * 0x100 + buffer[32 * (i - 1) + 26]; return find_subdir(fat16_ins, Dir, paths, pathDepth, 1); } } if (32 * i - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) >= fat16_ins->Bpb.BPB_BytsPerSec) { sector_read(fat16_ins->fd, fat16_ins->FirstRootDirSecNum + RootDirCnt, buffer); RootDirCnt++; } /** * return find_subdir(fat16_ins, Dir, paths, pathDepth, 1); **/ } return 1; } /** TODO: * 从子目录开始查找path对应的文件或目录,找到返回0,没找到返回1,并将Dir填充为查找到的对应目录项 * * Hint1: 在find_subdir入口处,Dir应该是要查找的这一级目录的表项,需要根据其中的簇号,读取这级目录对应的扇区数据 * Hint2: 目录的大小是未知的,可能跨越多个扇区或跨越多个簇;当查找到某表项以0x00开头就可以停止查找 * Hint3: 需要查找名字为paths[curDepth]的文件或目录,同样需要根据pathDepth判断是否继续调用find_subdir函数 **/ int find_subdir(FAT16* fat16_ins, DIR_ENTRY* Dir, char** paths, int pathDepth, int curDepth) { int i, j; int DirSecCnt = 1; /* 用于统计已读取的扇区数 */ int DirCluCnt = 1; BYTE buffer[BYTES_PER_SECTOR]; BYTE name[11]; WORD ClusterN, FatClusEntryVal, FirstSectorofCluster; ClusterN = Dir->DIR_FstClusLO; first_sector_by_cluster(fat16_ins, ClusterN, &FatClusEntryVal, &FirstSectorofCluster, buffer); for (i = 1; buffer[32 * (i - 1)] != 0x00; i++) { for (j = 0; j < 11; j++) { name[j] = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + j]; } if (strncmp(name, paths[curDepth], 11) == 0) { if (curDepth == pathDepth - 1) { strcpy(Dir->DIR_Name, name); Dir->DIR_Attr = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 11]; Dir->DIR_NTRes = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 12]; Dir->DIR_CrtTimeTenth = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 13]; Dir->DIR_CrtTime = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 15] * 0x100 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 14]; Dir->DIR_CrtDate = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 17] * 0x100 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 16]; Dir->DIR_LstAccDate = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 19] * 0x100 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 18]; Dir->DIR_FstClusHI = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 21] * 0x100 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 20]; Dir->DIR_WrtTime = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 23] * 0x100 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 22]; Dir->DIR_WrtDate = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 25] * 0x100 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 24]; Dir->DIR_FstClusLO = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 27] * 0x100 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 26]; Dir->DIR_FileSize = buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 31] * 0x1000000 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 30] * 0x10000 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 29] * 0x100 + buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 28]; return 0; } else { Dir->DIR_FstClusLO = buffer[32 * (i - 1) + 27] * 0x100 + buffer[32 * (i - 1) + 26]; return find_subdir(fat16_ins, Dir, paths, pathDepth, curDepth + 1); } } if (32 * i - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) >= fat16_ins->Bpb.BPB_BytsPerSec) { sector_read(fat16_ins->fd, FirstSectorofCluster + DirSecCnt, buffer); DirSecCnt++; } if (DirSecCnt - fat16_ins->Bpb.BPB_SecPerClus * (DirCluCnt - 1) > fat16_ins->Bpb.BPB_SecPerClus) { first_sector_by_cluster(fat16_ins, FatClusEntryVal, &FatClusEntryVal, &FirstSectorofCluster, buffer); DirCluCnt++; } } return 1; } /** * ------------------------------------------------------------------------------ * FUSE相关的函数实现 **/ void* fat16_init(struct fuse_conn_info* conn) { struct fuse_context* context; context = fuse_get_context(); return context->private_data; } void fat16_destroy(void* data) { free(data); } int fat16_getattr(const char* path, struct stat* stbuf) { FAT16* fat16_ins; struct fuse_context* context; context = fuse_get_context(); fat16_ins = (FAT16*)context->private_data; memset(stbuf, 0, sizeof(struct stat)); stbuf->st_dev = fat16_ins->Bpb.BS_VollID; stbuf->st_blksize = BYTES_PER_SECTOR * fat16_ins->Bpb.BPB_SecPerClus; stbuf->st_uid = getuid(); stbuf->st_gid = getgid(); if (strcmp(path, "/") == 0) { stbuf->st_mode = S_IFDIR | S_IRWXU; stbuf->st_size = 0; stbuf->st_blocks = 0; stbuf->st_ctime = stbuf->st_atime = stbuf->st_mtime = 0; } else { DIR_ENTRY Dir; int res = find_root(fat16_ins, &Dir, path); if (res == 0) { if (Dir.DIR_Attr == ATTR_DIRECTORY) { stbuf->st_mode = S_IFDIR | 0755; } else { stbuf->st_mode = S_IFREG | 0755; } stbuf->st_size = Dir.DIR_FileSize; if (stbuf->st_size % stbuf->st_blksize != 0) { stbuf->st_blocks = (int)(stbuf->st_size / stbuf->st_blksize) + 1; } else { stbuf->st_blocks = (int)(stbuf->st_size / stbuf->st_blksize); } struct tm t; memset((char*)& t, 0, sizeof(struct tm)); t.tm_sec = Dir.DIR_WrtTime & ((1 << 5) - 1); t.tm_min = (Dir.DIR_WrtTime >> 5) & ((1 << 6) - 1); t.tm_hour = Dir.DIR_WrtTime >> 11; t.tm_mday = (Dir.DIR_WrtDate & ((1 << 5) - 1)); t.tm_mon = (Dir.DIR_WrtDate >> 5) & ((1 << 4) - 1); t.tm_year = 80 + (Dir.DIR_WrtDate >> 9); stbuf->st_ctime = stbuf->st_atime = stbuf->st_mtime = mktime(&t); } } return 0; } int fat16_readdir(const char* path, void* buffer, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info* fi) { FAT16* fat16_ins; BYTE sector_buffer[BYTES_PER_SECTOR]; int i, j; int RootDirCnt = 1, DirSecCnt = 1; /* 用于统计已读取的扇区数 */ int DirCluCnt = 1; BYTE name[11]; struct fuse_context* context; context = fuse_get_context(); fat16_ins = (FAT16*)context->private_data; sector_read(fat16_ins->fd, fat16_ins->FirstRootDirSecNum, sector_buffer); if (strcmp(path, "/") == 0) { DIR_ENTRY Root; /** TODO: * 将root directory下的文件或目录通过filler填充到buffer中 * 注意不需要遍历子目录 **/ for (i = 1; i <= fat16_ins->Bpb.BPB_RootEntCnt; i++) { for (j = 0; j < 11; j++) { name[j] = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + j]; } strcpy(Root.DIR_Name, name); Root.DIR_Attr = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 11]; //Root.DIR_NTRes = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 12]; //Root.DIR_CrtTimeTenth = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 13]; //Root.DIR_CrtTime = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 15] * 0x100 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 14]; //Root.DIR_CrtDate = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 17] * 0x100 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 16]; //Root.DIR_LstAccDate = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 19] * 0x100 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 18]; //Root.DIR_FstClusHI = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 21] * 0x100 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 20]; //Root.DIR_WrtTime = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 23] * 0x100 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 22]; //Root.DIR_WrtDate = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 25] * 0x100 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 24]; //Root.DIR_FstClusLO = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 27] * 0x100 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 26]; //Root.DIR_FileSize = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 31] * 0x1000000 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 30] * 0x10000 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 29] * 0x100 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) + 28]; if (Root.DIR_Name[0] != 0xE5 && (Root.DIR_Attr == 0x20 || Root.DIR_Attr == 0x10)) { const char* filename = (const char*)path_decode(Root.DIR_Name); filler(buffer, filename, NULL, 0); } if (32 * i - fat16_ins->Bpb.BPB_BytsPerSec * (RootDirCnt - 1) >= BYTES_PER_SECTOR) { sector_read(fat16_ins->fd, fat16_ins->FirstRootDirSecNum + RootDirCnt, sector_buffer); RootDirCnt++; } } } else { DIR_ENTRY Dir; /** TODO: * 通过find_root获取path对应的目录的目录项, * 然后访问该目录,将其下的文件或目录通过filler填充到buffer中, * 同样注意不需要遍历子目录 * Hint: 需要考虑目录大小,可能跨扇区,跨簇 **/ find_root(fat16_ins, &Dir, path); WORD ClusterN, FatClusEntryVal, FirstSectorofCluster; ClusterN = Dir.DIR_FstClusLO; first_sector_by_cluster(fat16_ins, ClusterN, &FatClusEntryVal, &FirstSectorofCluster, sector_buffer); for (i = 1; ; i++) { for (j = 0; j < 11; j++) { name[j] = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + j]; } if (name[0] == 0x00) break; strcpy(Dir.DIR_Name, name); Dir.DIR_Attr = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 11]; //Dir.DIR_NTRes = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 12]; //Dir.DIR_CrtTimeTenth = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 13]; //Dir.DIR_CrtTime = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 15] * 0x100 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 14]; //Dir.DIR_CrtDate = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 17] * 0x100 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 16]; //Dir.DIR_LstAccDate = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 19] * 0x100 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 18]; //Dir.DIR_FstClusHI = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 21] * 0x100 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 20]; //Dir.DIR_WrtTime = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 23] * 0x100 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 22]; //Dir.DIR_WrtDate = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 25] * 0x100 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 24]; //Dir.DIR_FstClusLO = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 27] * 0x100 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 26]; //Dir.DIR_FileSize = sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 31] * 0x1000000 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 30] * 0x10000 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 29] * 0x100 + sector_buffer[32 * (i - 1) - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) + 28]; if (Dir.DIR_Name[0] != 0xE5 && (Dir.DIR_Attr == 0x20 || Dir.DIR_Attr == 0x10)) { const char* filename = (const char*)path_decode(Dir.DIR_Name); filler(buffer, filename, NULL, 0); } if (32 * i - fat16_ins->Bpb.BPB_BytsPerSec * (DirSecCnt - 1) >= fat16_ins->Bpb.BPB_BytsPerSec) { sector_read(fat16_ins->fd, FirstSectorofCluster + DirSecCnt, sector_buffer); DirSecCnt++; } if (DirSecCnt - fat16_ins->Bpb.BPB_SecPerClus * (DirCluCnt - 1) > fat16_ins->Bpb.BPB_SecPerClus) { first_sector_by_cluster(fat16_ins, FatClusEntryVal, &FatClusEntryVal, &FirstSectorofCluster, sector_buffer); if (FatClusEntryVal == 0 || FatClusEntryVal >= 0xFFF0) break; DirCluCnt++; } } } return 0; } /** TODO: * 从path对应的文件的offset字节处开始读取size字节的数据到buffer中,并返回实际读取的字节数 * * Hint: 文件大小属性是Dir.DIR_FileSize;当offset超过文件大小时,应该返回0 **/ int fat16_read(const char* path, char* buffer, size_t size, off_t offset, struct fuse_file_info* fi) { FAT16* fat16_ins; DIR_ENTRY Dir; WORD ClusterN, FatClusEntryVal, FirstSectorofCluster; BYTE sector_buffer[BYTES_PER_SECTOR]; int DirSecCnt = 0; size_t readSize; int i; struct fuse_context* context; context = fuse_get_context(); fat16_ins = (FAT16*)context->private_data; find_root(fat16_ins, &Dir, path); ClusterN = Dir.DIR_FstClusLO; first_sector_by_cluster(fat16_ins, ClusterN, &FatClusEntryVal, &FirstSectorofCluster, sector_buffer); if (offset >= Dir.DIR_FileSize) return 0; else if (offset + size > Dir.DIR_FileSize) readSize = Dir.DIR_FileSize - offset; else readSize = size; while (offset >= fat16_ins->Bpb.BPB_SecPerClus * fat16_ins->Bpb.BPB_BytsPerSec) { first_sector_by_cluster(fat16_ins, FatClusEntryVal, &FatClusEntryVal, &FirstSectorofCluster, sector_buffer); offset -= fat16_ins->Bpb.BPB_SecPerClus * fat16_ins->Bpb.BPB_BytsPerSec; } while (offset >= fat16_ins->Bpb.BPB_BytsPerSec) { DirSecCnt++; offset -= fat16_ins->Bpb.BPB_BytsPerSec; } sector_read(fat16_ins->fd, FirstSectorofCluster + DirSecCnt, sector_buffer); for (i = 0; i < readSize; i++) { if (offset >= fat16_ins->Bpb.BPB_BytsPerSec) { DirSecCnt++; sector_read(fat16_ins->fd, FirstSectorofCluster + DirSecCnt, sector_buffer); offset = 0; } if (DirSecCnt >= fat16_ins->Bpb.BPB_SecPerClus) { first_sector_by_cluster(fat16_ins, FatClusEntryVal, &FatClusEntryVal, &FirstSectorofCluster, sector_buffer); DirSecCnt -= fat16_ins->Bpb.BPB_SecPerClus; } buffer[i] = sector_buffer[offset]; offset++; } return readSize; } /** * ------------------------------------------------------------------------------ * 测试函数 **/ void test_path_split() { printf("#1 running %s\n", __FUNCTION__); char s[][32] = { "/texts", "/dir1/dir2/file.txt", "/.Trash-100" }; int dr[] = { 1, 3, 1 }; char sr[][3][32] = { {"TEXTS "}, {"DIR1 ", "DIR2 ", "FILE TXT"}, {" TRA"} }; int i, j, r; for (i = 0; i < sizeof(dr) / sizeof(dr[0]); i++) { char** ss = path_split(s[i], &r); assert(r == dr[i]); for (j = 0; j < dr[i]; j++) { assert(strcmp(sr[i][j], ss[j]) == 0); free(ss[j]); } free(ss); printf("test case %d: OK\n", i + 1); } printf("success in %s\n\n", __FUNCTION__); } void test_path_decode() { printf("#2 running %s\n", __FUNCTION__); char s[][32] = { ".. ", "FILE TXT", "ABCD RM " }; char sr[][32] = { "..", "file.txt", "abcd.rm" }; int i, j, r; for (i = 0; i < sizeof(s) / sizeof(s[0]); i++) { char* ss = (char*)path_decode(s[i]); assert(strcmp(ss, sr[i]) == 0); free(ss); printf("test case %d: OK\n", i + 1); } printf("success in %s\n\n", __FUNCTION__); } void test_pre_init_fat16() { printf("#3 running %s\n", __FUNCTION__); FAT16* fat16_ins = pre_init_fat16(); assert(fat16_ins->FirstRootDirSecNum == 124); assert(fat16_ins->FirstDataSector == 156); assert(fat16_ins->Bpb.BPB_RsvdSecCnt == 4); assert(fat16_ins->Bpb.BPB_RootEntCnt == 512); assert(fat16_ins->Bpb.BS_BootSig == 41); assert(fat16_ins->Bpb.BS_VollID == 1576933109); assert(fat16_ins->Bpb.Signature_word == 43605); fclose(fat16_ins->fd); free(fat16_ins); printf("success in %s\n\n", __FUNCTION__); } void test_fat_entry_by_cluster() { printf("#4 running %s\n", __FUNCTION__); FAT16* fat16_ins = pre_init_fat16(); int cn[] = { 1, 2, 4 }; int ce[] = { 65535, 0, 65535 }; int i; for (i = 0; i < sizeof(cn) / sizeof(cn[0]); i++) { int r = fat_entry_by_cluster(fat16_ins, cn[i]); assert(r == ce[i]); printf("test case %d: OK\n", i + 1); } fclose(fat16_ins->fd); free(fat16_ins); printf("success in %s\n\n", __FUNCTION__); } void test_find_root() { printf("#5 running %s\n", __FUNCTION__); FAT16* fat16_ins = pre_init_fat16(); char path[][32] = { "/dir1", "/makefile", "/log.c" }; char names[][32] = { "DIR1 ", "MAKEFILE ", "LOG C " }; int others[][3] = { {100, 4, 0}, {100, 8, 226}, {100, 3, 517} }; int i; for (i = 0; i < sizeof(path) / sizeof(path[0]); i++) { DIR_ENTRY Dir; find_root(fat16_ins, &Dir, path[i]); assert(strncmp(Dir.DIR_Name, names[i], 11) == 0); assert(Dir.DIR_CrtTimeTenth == others[i][0]); assert(Dir.DIR_FstClusLO == others[i][1]); assert(Dir.DIR_FileSize == others[i][2]); printf("test case %d: OK\n", i + 1); } fclose(fat16_ins->fd); free(fat16_ins); printf("success in %s\n\n", __FUNCTION__); } void test_find_subdir() { printf("#6 running %s\n", __FUNCTION__); FAT16* fat16_ins = pre_init_fat16(); char path[][32] = { "/dir1/dir2", "/dir1/dir2/dir3", "/dir1/dir2/dir3/test.c" }; char names[][32] = { "DIR2 ", "DIR3 ", "TEST C " }; int others[][3] = { {100, 5, 0}, {0, 6, 0}, {0, 7, 517} }; int i; for (i = 0; i < sizeof(path) / sizeof(path[0]); i++) { DIR_ENTRY Dir; find_root(fat16_ins, &Dir, path[i]); assert(strncmp(Dir.DIR_Name, names[i], 11) == 0); assert(Dir.DIR_CrtTimeTenth == others[i][0]); assert(Dir.DIR_FstClusLO == others[i][1]); assert(Dir.DIR_FileSize == others[i][2]); printf("test case %d: OK\n", i + 1); } fclose(fat16_ins->fd); free(fat16_ins); printf("success in %s\n\n", __FUNCTION__); } struct fuse_operations fat16_oper = { .init = fat16_init, .destroy = fat16_destroy, .getattr = fat16_getattr, .readdir = fat16_readdir, .read = fat16_read }; int main(int argc, char* argv[]) { int ret; if (strcmp(argv[1], "--test") == 0) { printf("--------------\nrunning test\n--------------\n"); FAT_FILE_NAME = "fat16_test.img"; test_path_split(); test_path_decode(); test_pre_init_fat16(); test_fat_entry_by_cluster(); test_find_root(); test_find_subdir(); exit(EXIT_SUCCESS); } FAT16* fat16_ins = pre_init_fat16(); ret = fuse_main(argc, argv, &fat16_oper, fat16_ins); return ret; }