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

问题

如何在根目录中创建文件?

根目录的本质

根目录在文件系统中是一个特殊的文件

根目录中存储了文件的基本信息 (FileEntry)

FileEntry 包含了文件名,文件起始扇区,文件大小等信息

根目录逻辑结构

 

文件实现的基础:扇区管理

如何 获取 / 归还 空闲扇区?

如何查找当前扇区的后续扇区?

如何为当前文件 增加 / 删除 一个扇区?

扇区申请

一些注意事项

 扇区操作是一种外存操作,因此需要仔细计算目标位置

扇区管理时使用相对扇区地址扇区读写时使用绝对地址

关系如下

  • offset = si - mapSize - 2
  • si = offset + mapSize + 2

扇区分配表的每个 item 下标和数据区每个扇区的下标是一一对应的 (从0开始)。

访问数据扇区对应的分配表项

计算相对地址:offset = si - mapSize - 2

计算目标扇区:sctOff = offset / MAP_ITEM_CNT

计算扇区内偏移:idxOff = offset % MAP_ITEM_CNT

需要实现的部分扇区管理函数

核心数据结构和数量关系

 

扇区管理函数的实现

 fs.c

typedef struct
{
    uint* pSct;
    uint sctIdex;
    uint sctOff;
    uint idxOff;
}MapPos;

MapPos FindInMap(uint si)
{
    MapPos ret = {0};
    FSHeader* header = (si != SCT_END_FLAG) ? (FSHeader*)ReadSector(HEADER_SCT_IDX) : NULL;

    if(header)
    {
        uint offset = si - FIXED_SCT_IDX - header->mapSize;
        uint sctOff = offset / MAP_ITEM_CNT;
        uint idxOff = offset % MAP_ITEM_CNT;
        uint* ps = (uint*)ReadSector(sctOff + FIXED_SCT_IDX);

        if(ps)
        {
            ret.pSct = ps;
            ret.sctIdex = si;
            ret.sctOff = sctOff;
            ret.idxOff = idxOff;
        }
    }

    Free(header);

    return ret;
}

static uint AllocSector()
{
    uint ret = SCT_END_FLAG;
    FSHeader* header = (FSHeader*)ReadSector(HEADER_SCT_IDX);

    if(header && (header->freeBegin != SCT_END_FLAG))
    {
        MapPos mp = FindInMap(header->freeBegin);

        if(mp.pSct)
        {
            uint* pInt = AddrOff(mp.pSct, mp.idxOff);
            uint next = *pInt;
            uint flag = 1;

            ret = header->freeBegin;

            header->freeNum--;
            header->freeBegin = next + FIXED_SCT_IDX + header->mapSize;

            *pInt = SCT_END_FLAG;

            flag = flag && HDRawWrite(HEADER_SCT_IDX, (byte*)header);
            flag = flag && HDRawWrite(FIXED_SCT_IDX + mp.sctOff, (byte*)mp.pSct);

            if(!flag)
            {
                ret = SCT_END_FLAG;
            }
        }

        Free(mp.pSec);
    }

    Free(header);

    return ret;
}

static uint FreeSector(uint si)
{
    uint ret = 0;
    FSHeader* header = (si == SCT_END_FLAG) ? NULL : (FSHeader*)ReadSector(HEADER_SCT_IDX);

    if(header)
    {
        MapPos mp = FindInMap(si);

        if(mp.pSct)
        {
            uint* pInt = AddrOff(mp.pSct, mp.idxOff);

            *pInt = header->freeBegin - FIXED_SCT_IDX - header->mapSize;

            header->freeNum++;
            header->freeBegin = si;

            ret = HDRawWrite(HEADER_SCT_IDX, (byte*)header) &&
                    HDRawWrite(FIXED_SCT_IDX + mp.sctOff, (byte*)mp.pSct);
        }

        Free(mp.pSct);
    }

    Free(header);

    return ret;
}

static uint NextSector(uint si)
{
    uint ret = SCT_END_FLAG;
    FSHeader* header = (si == SCT_END_FLAG) ? NULL : (FSHeader*)ReadSector(HEADER_SCT_IDX);

    if(header)
    {
        MapPos mp = FindInMap(si);

        if(mp.pSct)
        {
            uint* pInt = AddrOff(mp.pSct, mp.idxOff);

            if(*pInt != SCT_END_FLAG)
            {
                ret = *pInt + FIXED_SCT_IDX + header->mapSize;
            }
        }

        Free(mp.pSct);
    }

    Free(header);

    return ret;
}

static uint FindLast(uint sctBegin)
{
    uint ret = SCT_END_FLAG;
    uint next = sctBegin;

    while(next != SCT_END_FLAG)
    {
        ret = next;
        next = NextSector(next);
    }

    return ret;
}

static uint FindPrev(uint sctBegin, uint si)
{
    uint ret = SCT_END_FLAG;
    uint next = sctBegin;

    while((next != SCT_END_FLAG) && (next != si))
    {
        ret = next;
        next = NextSector(next);
    }

    if(next == SCT_END_FLAG)
    {
        ret = SCT_END_FLAG;
    }

    return ret;
}

static uint FindIndex(uint sctBegin, uint idx)
{
    uint ret = sctBegin;
    uint i = 0;

    while((ret != SCT_END_FLAG) && (i < idx))
    {
        ret = NextSector(ret);

        i++;
    }

    return ret;
}

static uint MarkSector(uint si)
{
    uint ret = (si == SCT_END_FLAG) ? 1 : 0;
    MapPos mp = FindInMap(si);

    if(mp.pSec)
    {
        uint* pInt = (uint*)AddrOff(mp.pSct, mp.idxOff);

        *pInt = SCT_END_FLAG;

        ret = HdRawWrite(FIXED_SCT_IDX + mp.sctOff, (byte*)mp.pSct);
    }

    Free(mp.pSec);

    return ret;
}

test

void test_1()
{
    uint i = 0;
    uint a[5] = {0};
    FSHeader* header = (FSHeader*)ReadSector(HEADER_SCT_IDX);

    printf("begin alloc, sector num = %d\n", header->freeNum);

    Free(header);

    for(i = 0; i < 5; i++)
    {
        a[i] = AllocSector();
    }

    header = (FSHeader*)ReadSector(HEADER_SCT_IDX);

    printf("after alloc, sector num = %d\n", header->freeNum);

    Free(header);

    for(i = 0; i < 5; i++)
    {
        printf("a[%d] = %d\n", i, a[i]);
        FreeSector(a[i]);
    }

    header = (FSHeader*)ReadSector(HEADER_SCT_IDX);

    printf("after free, sector num = %d\n", header->freeNum);

    Free(header);
}

void test_2()
{
    FSHeader* header = (FSHeader*)ReadSector(HEADER_SCT_IDX);
    uint i = 0;
    uint curr = header->freeBegin;

    printf("header->freeNum = %d\n", header->freeNum);

    while(curr != SCT_END_FLAG)
    {
        i++;

        curr = NextSector(curr);
    }

    printf("i = %d\n", i);

    Free(header);
}

MapPos 结构体中记录了分配表和数据区之间的下标关系。

我们本文件系统的策略是扇区管理时使用相对扇区地址,扇区读写时使用绝对地址。当需要通过数据区扇区的绝对地址找到对应管理扇区的相对地址时,FindInMap 函数返回一个 MapPos 结构体来做这个事情。

分配表类似于链表,分配表上的每一个值都代表了它的下一个扇区号。AllocSector 函数用于分配一个空闲扇区,它需要将 header->freeBegin 对应分配单元的值取出来,保存到 next 中,这个值代表了此扇区的下一个扇区号,接下来将 header->freeBegin 作为分配出来的扇区号进行返回,然后将 header->freeBegin 对应分配单元的值设置为 SCT_END_FLAG,代表这个扇区已被分配,最后将 header->freeBegin 重新赋值为 next + FIXED_SCT_IDX + header->mapSize。还需要把修改的内容写到内存中。FreeSector 函数将对应的扇区号进行回收,首先找到 si 所对应的分配单元,将这个分配单元上的值赋值为 header->freeBegin - FIXED_SCT_IDX - header->mapSize,表示这个扇区号的下一个扇区号为 header->freeBegin,然后将 header->freeBegin 赋值为 si,si 成为了空闲链表的头部。还需要把修改的内容写到内存中。

test_1 测试结果如下

分配5个扇区后,总扇区数减少了5;当回收5个扇区后,总扇区数增加了5。并且第二次获取到的扇区号正好和第一次相反,这是因为最后回收的扇区会被添加到链表的头部,所以首先分配到的扇区号是最后被回收的扇区。 这和我们的预期相同。

test_2 测试结果如下

当前空闲的扇区数为162028,我们通过 NextSector 来遍历空闲链表,遍历了162028次,表明空闲扇区数有162028。这和我们的预期是相同的。 

To be continue

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值