问题
根目录中创建文件,扇区申请成功后,还需要做哪些工作?
根目录本质回顾
根目录 (文件) 中存储是 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() - 文件查找的核心 ![](https://i-blog.csdnimg.cn/blog_migrate/c7fe28d15e0999d73fc1cd948836b1ff.png)
在扇区中查找 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 被成功创建,并且已经存在硬盘中了,程序运行结果符合我们的预期。