文件系统设计与实现(三)

问题

根目录中创建文件,扇区申请成功后,还需要做哪些工作?

根目录本质回顾

根目录 (文件) 中存储是 FileEntry 类型的值,每个 FileEntry 值表示一个硬盘上的文件。

根目录中创建文件的流程

在根目录中创建文件

CheckStorage() - 写入数据前的检查

 在根目录中写入新文件的信息

在根目录中创建文件

fs.c

#define FE_BYTES        sizeof(FileEntry)
#define FE_ITEM_CNT     (SECT_SIZE / FE_BYTES)

typedef struct
{
    char magic[32];
    uint sctBegin;
    uint sctNum;
    uint lastBytes;
} FSRoot;

typedef struct
{
    char name[32];
    uint sctBegin;
    uint sctNum;
    uint lastBytes;
    uint type;
    uint inSctOff;
    uint inSctIdx;
    uint reserved[2];
} FileEntry;

static uint CreateInRoot(const char* name)
{
    FSRoot* root = (FSRoot*)ReadSector(ROOT_SCT_IDX);
    uint ret = 0;

    if(root)
    {
        CheckStroage(root);

        if(CreateFileEntry(name, root->sctBegin, root->lastBytes))
        {
            root->lastBytes += FE_BYTES;

            ret = HDRawWrite(ROOT_SCT_IDX, (byte*)root);
        }
    }

    Free(root);

    return ret;
}

static uint CheckStroage(FSRoot* root)
{
    uint ret = 0;

    if(root)
    {
        if(root->lastBytes == SECT_SIZE)
        {
            uint si = AllocSector();

            if(si != SCT_END_FLAG)
            {
                if(root->sctBegin == SCT_END_FLAG)
                {
                    root->sctBegin = si;
                }
                else
                {
                    AddToLast(root->sctBegin, si);
                }

                root->sctNum++;
                root->lastBytes = 0;

                ret = 1;
            }
        }
    }

    return ret;
}

static uint CreateFileEntry(const char* name, uint sctBegin, uint lastBytes)
{
    uint ret = 0;
    uint last = FindLast(sctBegin);
    FileEntry* feBase = NULL;

    if((last != SCT_END_FLAG) && (feBase = (FileEntry*)ReadSector(last)))
    {
        uint offset = lastBytes / FE_BYTES;
        FileEntry* fe = (FileEntry*)AddrOff(feBase, offset);

        StrCpy(fe->name, name, sizeof(fe->name) - 1);
        fe->sctBegin = SCT_END_FLAG;
        fe->sctNum = 0;
        fe->type = 0;
        fe->inSctIdx = last;
        fe->inSctOff = offset;
        fe->lastBytes = SECT_SIZE;

        ret = HDRawWrite(last, (byte*)feBase);
    }

    Free(feBase);

    return ret;
}

static uint AddToLast(uint sctBegin, uint si)
{
    uint ret = 0;

    if((sctBegin != SCT_END_FLAG) && (si != SCT_END_FLAG))
    {
        uint last = FindLast(sctBegin);

        if(last != SCT_END_FLAG)
        {
            MapPos lmp = FindInMap(last);
            MapPos smp = FindInMap(si);

            if(lmp.pSec && smp.pSec)
            {
                if(lmp.sctOff == smp.sctOff)
                {
                    uint* pInt = (uint*)AddrOff(lmp.pSec, lmp.idxOff);

                    *pInt = lmp.sctOff * MAP_ITEM_CNT + smp.idxOff;

                    pInt = (uint*)AddrOff(lmp.pSec, smp.idxOff);

                    *pInt = SCT_END_FLAG;

                    ret = HDRawWrite(lmp.sctOff + FIXED_SCT_SIZE, (byte*)lmp.pSec);
                }
                else
                {
                    uint* pInt = (uint*)AddrOff(lmp.pSec, lmp.idxOff);

                    *pInt = smp.sctOff * MAP_ITEM_CNT + smp.idxOff;

                    pInt = (uint*)AddrOff(smp.pSec, smp.idxOff);

                    *pInt = SCT_END_FLAG;

                    ret = HDRawWrite(lmp.sctOff + FIXED_SCT_SIZE, (byte*)lmp.pSec)
                            && HDRawWrite(smp.sctOff + FIXED_SCT_SIZE, (byte*)smp.pSec);
                }
            }

            Free(lmp.pSec);
            Free(smp.pSec);
        }
    }

    return ret;
}

test

void test()
{
    uint r = 0;

    // r = CreateInRoot("test.txt");
    r = CreateInRoot("liu.txt");
    r = r && CreateInRoot("jie.txt");

    printf("create = %d\n", r);

    if(r)
    {
        uint i = 0;
        FSRoot* root = (FSRoot*)ReadSector(ROOT_SCT_IDX);
        FileEntry* feBase = (FileEntry*)ReadSector(root->sctBegin);

        printf("sctNum = %d\n", root->sctNum);
        printf("lastBytes = %d\n", root->lastBytes);

        for(i = 0; i < root->lastBytes / FE_BYTES; i++)
        {
            FileEntry* fe = (FileEntry*)AddrOff(feBase, i);

            printf("name = %s\n", fe->name);
        }

        Free(root);
        Free(feBase);
    }

}

FileEntry 结构体在面向对象的层次来说,它是 FSRoot 的子类,因为 FileEntry 前面几个变量的内存布局和 FSRoot 是一样的。

CheckStroage 函数会检查 root->lastBytes 是否到达上限,到达上限的话,会分配出一个新的扇区,root->freeBegin 类似于一个指针,最先还没创建文件的时候 root->freeBegin 为 SCT_END_FLAG,此时将 root->freeBegin 赋值为新分配出的扇区,否则将新分配出的扇区插入到 root->freeBegin 这个扇区的末尾。

CreateFileEntry 函数创建一个 FileEntry,首先它需要找到 root->freeBegin 的最后一个扇区,然后根据 lastBytes 算出要写入 FileEntry 的偏移,最后将各个值写入。

test函数中,首先创建 test.txt 文件项信息,然后创建 liu.txt 和 jie.txt 文件项信息,最后读取它们的信息。

可以看出输出结果符合我们的预期。root->freeBegin 对应的扇区此时记录了 3个 FileEntry。并且这3个 FileEntry 占据了192字节,没有超过一个扇区,因此 root->sctNum = 1。如果这些 FileEntry 超过了一个扇区的大小,就会新分配一个扇区,将此扇区插入到 root->freeBegin 扇区的末尾,root->sctNum 会加1,用此新分配的扇区来创建 FileEntry。

思考

如何判断根目录区中是否存在指定文件?

根目录中查找文件的流程

 

文件查找的本质

 

FindFileEntry() - 文件查找的核心 

在扇区中查找 FileEntry

在根目录中查找目标文件

uint FCreate(const char* name)
{
    uint ret = FExisted(name);

    if(ret == FS_NONEXISTED)
    {
        ret = (CreateInRoot(name) ? FS_SUCCESSED : FS_FAILED);
    }

    return ret;
}

uint FExisted(const char* name)
{
    uint ret = FS_FAILED;

    if(name)
    {
        FileEntry* fe = FindInRoot(name);

        ret = ((fe == NULL) ? FS_NONEXISTED : FS_EXISTED);

        Free(fe);
    }

    return ret;
}

static FileEntry* FindInRoot(const char* name)
{
    FileEntry* ret = NULL;

    if(name)
    {
        FSRoot* root = (FSRoot*)ReadSector(ROOT_SCT_IDX);

        if(root && root->sctNum)
        {
            ret = FindFileEntry(name, root->sctBegin, root->sctNum, root->lastBytes);
        }

        Free(root);
    }

    return ret;
}

static FileEntry* FindFileEntry(const char* name, uint sctBegin, uint sctNum, uint lastBytes)
{
    FileEntry* ret = NULL;
    FileEntry* feBase = NULL;
    uint next = sctBegin;
    uint i = 0;

    for(i = 0; i < sctNum - 1; i++)
    {
        feBase = (FileEntry*)ReadSector(next);

        if(feBase)
        {
            ret = FindInSector(name, feBase, FE_ITEM_CNT);
        }

        Free(feBase);

        if(!ret)
        {
            next = NextSector(next);
        }
        else
        {
            break;
        }
    }

    if(!ret)
    {
        uint cnt = lastBytes / FE_BYTES;

        feBase = (FileEntry*)ReadSector(next);

        if(feBase)
        {
            ret = FindInSector(name, feBase, cnt);
        }

        Free(feBase);
    }

    return ret;
}


static FileEntry* FindInSector(const char* name, FileEntry* feBase, uint cnt)
{
    FileEntry* ret = NULL;
    uint i = 0;

    for(i = 0; i < cnt; i++)
    {
        FileEntry* fe = (FileEntry*)AddrOff(feBase, i);

        if(StrCmp(name, fe->name, -1))
        {
            ret = (FileEntry*)Malloc(SECT_SIZE);

            if(ret)
            {
                *ret = *fe;
            }

            break;
        }
    }

    return ret;
}

fs.h

enum
{
    FS_FAILED,
    FS_SUCCESSED,
    FS_EXISTED,
    FS_NONEXISTED
};

test_1

void test_1()
{
    if(FindInRoot("test.txt"))  printf("test.txt existed!\n");
    if(FindInRoot("liu.txt"))  printf("liu.txt existed!\n");
    if(FindInRoot("jie.txt"))  printf("jie.txt existed!\n");
}

程序运行结果如下所示

当前根目录中已经创建了 test.txt,liu.txt 和 jie.txt,程序运行结果符合预期。

test_2

int main(void)
{
    HDRawSetName("hd.img");

    HDRawModInit();

    //printf("FSFormat: %d\n", FSFormat());
    //printf("FSIsFormat: %d\n", FSIsFormated());

    printf("create: %d\n", FCreate("test.txt"));
    printf("existed: %d\n", FExisted("test.txt"));

    HDRawFlush();

    return 0;
}

程序运行结果如下所示

因为 test.txt 文件已经存在,所以程序运行结果符合预期。

test_3

int main(void)
{
    HDRawSetName("hd.img");

    HDRawModInit();

    printf("FSFormat: %d\n", FSFormat());
    //printf("FSIsFormat: %d\n", FSIsFormated());

    printf("create: %d\n", FCreate("test.txt"));
    printf("existed: %d\n", FExisted("test.txt"));

    HDRawFlush();

    return 0;
}

 程序运行结果如下所示

因为当前文件系统被格式化后,所有文件都没了,所以 test.txt 被成功创建,并且已经存在硬盘中了,程序运行结果符合我们的预期。 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值