fat

#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;
}

 

转载于:https://www.cnblogs.com/fqqq/p/10999633.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值