按照上一篇的文件系统描述方法,我们基本虚拟出了我们的文件系统的构成,它包括系统文件块,扇区位图,inode位图, inode信息区,扇区信息区;
现在想想你新拿到一个硬盘装系统时第一件事情是什么?你仔细观察就会发现它要先提示你格式化硬盘并选择安装一个文件系统;之后它就可以把它操作系统相关相关的东西复制到你的磁盘中,写的位置,占用了哪些扇区都明明白白的纪录在它的文件系统中。这样在系统安装后,你才能正常的使用。
大家生活中可能 也遇到 过这种情况:系统跑的好好的,突然下次开机时提示文件异常。然后系统各种修复 ,这个情况在LInux上比较常见。我的虚拟机会时不时的出现这种情况,最严重的时候,整个都无法启动,它也蒙了,我也蒙了。。常见的原因就是文件系统被破坏了,比如你还明明是个光棍,但纪录 上表明已经有了爱人,有了小孩子,这样会禁止你再次结婚,你冤不冤?你们家到你这一代就算是绝迹了。
好,那我们也模拟实现下文件系统 的初始化,初始化后就支持文件的写入,也支持查询当前所有文件的信息,包括文件名,文件大小,文件占用扇区列表信息。代码可能比较长,而且我们态度会比较严肃,请大家保持安静,嗑瓜子的,还的抠脚丫子的都注意个人形象。
1.文件初始化代码。
/*--------------------------------------------------------------*/
/*---------------------------- mkpfs.c --------------------------*/
/*--------------------------------------------------------------*/
#include "ddfs.h"
/*DDFS: 扁平文件系统,没有文件夹,扇区编号从0开始
第0个扇区作boot代码区,其中包含启动代码与分区表信息
第1个分区开始作systemblock分区,
1.总扇区数目, 已经使用扇区
2.总INODE数目,已经使用INODE
第2扇区SECTOR_BITMAP区,每个bit表示一个sector,总共4096扇区
第3扇区INODEINFO_BITMAP区,每个bit表示一个inode_INFO,当前设定Inode总共有512,占用一个扇区
第4扇区到第515扇区INODE_INFO区,大小为总INODE数目*INODE结构体大小,INDOE结构体包含以下内容:
1.文件名
2.文件大小
3.文件起始扇区
第516扇区到第547扇区FILE_SECTORLIST区,大小为总扇区数*扇区结构体大小,扇区结构体包含以下内容:
1.是否是最后一个扇区
2.下一个扇区号(如果当前扇区已经是最后一个扇区了,那么访问时将忽略这个字段)
扇区548之后就是用户扇区区域
*/
int main(int argc, char **argv)
{
int devfd = 0;
unsigned int uiRet = 0;
unsigned int uiLoop = 0;
InodeInfo_s stInodeInfo = {0};
FileSectorList_s stFileSectorList = {0};
SystemBlockInfo_s stSystemBlockInfo= {0};
if (argc != 2)
{
printf("mkddfs: Need to specify device\n");
return 1;
}
devfd = open(argv[1], O_RDWR);
if (devfd < 0)
{
printf("mkddfs: Failed to open device\n");
return 1;
}
/*文件系统区全部清0,用户区的不用清零,*/
uiRet = DDfs_Clr_AllFileSystem(devfd);
/*初始化文件系统块,*/
stSystemBlockInfo.uiTotalSectorNum = MACRO_DDFS_SECTOR_TOTAL_NUM;
stSystemBlockInfo.uiUsedSectorNum = MACRO_DDFS_FILE_DATA_START_SECTOR_NO;
stSystemBlockInfo.uiTotalInodeNum = MACRO_DDFS_INODE_TOTAL_NUM;
stSystemBlockInfo.uiUsedInodeNum = 0;
DDfs_Set_SystemBlockInfo(&stSystemBlockInfo, devfd);
/*初始化SECTOR_BITMAP*/
for (; uiLoop < MACRO_DDFS_FILE_DATA_START_SECTOR_NO; uiLoop++)
{
DDfs_Set_SectorBitMap_By_SectorNo(uiLoop, devfd);
}
/*初始化INODE_BITMAP,已经全部清0,不需要重复设置*/
/*INODE信息清零,已经全部清0,不需要重复设置*/
/*文件扇区列表,已经全部清0,不需要重复设置*/
close(devfd);
return 0;
}
初始化代码其实很简单,先格式化整个文件系统区;然后依次考虑系统文件块、扇区位图、inode位图、inode信息区,文件扇区列表信息区。
这里特殊的是:扇区0是mbr,天生要占用;其次文件系统也是保存在磁盘中的,因此初始化时要把这一块的使用位图置上,避免被其它文件改写。改写后的后果是不可预料的,你可能写不了任何文件。
2.文件写
写文件其实注意一点:如果文件已经存在,要先删除文件,然后再写入;而删除无非就是释放它之前占用的扇区使用信息
/*--------------------------------------------------------------*/
/*---------------------------- install_file.c --------------------------*/
/*--------------------------------------------------------------*/
#include "ddfs.h"
/*DDFS: 扁平文件系统,没有文件夹,扇区编号从0开始
第0个扇区作boot代码区,其中包含启动代码与分区表信息
第1个分区开始作systemblock分区,
1.总扇区数目, 已经使用扇区
2.总INODE数目,已经使用INODE
第2扇区SECTOR_BITMAP区,每个bit表示一个sector,总共4096扇区
第3扇区INODEINFO_BITMAP区,每个bit表示一个inode_INFO,当前设定Inode总共有512,占用一个扇区
第4扇区到第515扇区INODE_INFO区,大小为总INODE数目*INODE结构体大小,INDOE结构体包含以下内容:
1.文件名
2.文件大小
3.文件起始扇区
第516扇区到第547扇区FILE_SECTORLIST区,大小为总扇区数*扇区结构体大小,扇区结构体包含以下内容:
1.是否是最后一个扇区
2.下一个扇区号(如果当前扇区已经是最后一个扇区了,那么访问时将忽略这个字段)
扇区548之后就是用户扇区区域
*/
void main(int argc, char **argv)
{
int iRet = 0;
int devfd = 0;
int filefd = 0;
unsigned int uiRet = 0;
unsigned char *pBaseName = NULL;
unsigned int isExist = false;
unsigned int uiInode = 0;
SystemBlockInfo_s stSystemBlockInfo = {0};
struct stat stFilestat = {0};
/*参数检查*/
if (argc != 3) {
printf("install_file: Need to specify device and file name.\r\n"
"install_file: ./install_file devicename filename\r\n");
return;
}
pBaseName = basename(argv[2]);
if (NULL == pBaseName || MACRO_DDFS_INODE_INFO_FILENAME_LEN <= strlen(pBaseName))
{
printf("Invalid file name\r\n");
return;
}
/*设备与需要拷贝的文件句柄打开*/
devfd = open(argv[1], O_RDWR);
if (devfd < 0) {
printf("install_file: Failed to open device\n");
return;
}
filefd = open(argv[2], O_RDWR);
if (filefd < 0) {
printf("install_file: Failed to open file\n");
close(devfd);
return;
}
printf("Info: %s will be install in %s\r\n", pBaseName, argv[1]);
/*检查是否有重名文件,如果存在,就释放已经占用的扇区与INODE信息*/
DDfs_Delete_File_By_FileName(pBaseName, devfd);
DDfs_Add_File_By_FileName(pBaseName, filefd, devfd);
close(devfd);
close(filefd);
return;
}
3.文件系统信息读取
可以方便的查看当前文件系统使用情况,它会显示文件的使用情况
#include "ddfs.h"
/**********************************************************************
函数名: DDFS_dump_systemblock
函数说明: 显示系统块信息
入参: devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDFS_dump_systemblock(int devfd)
{
unsigned int uiMallocSize = 0;
SystemBlockInfo_s *pstSystemBlock = NULL;
uiMallocSize = MACRO_DDFS_SYSTEM_BLOCK_STRUCT_SIZE;
pstSystemBlock = (SystemBlockInfo_s*)malloc(uiMallocSize);
if (NULL == pstSystemBlock)
{
return;
}
memset(pstSystemBlock, 0, uiMallocSize);
DDfs_Get_SystemBlockInfo(pstSystemBlock, devfd);
printf("=============SYSTEMBLOCK INFO====================\r\n");
printf("Total Sector : %u\r\n", pstSystemBlock->uiTotalSectorNum);
printf("Used Sector : %u\r\n", pstSystemBlock->uiUsedSectorNum);
printf("Free Sector : %u\r\n", pstSystemBlock->uiTotalSectorNum-pstSystemBlock->uiUsedSectorNum);
printf("Total Inode : %u\r\n", pstSystemBlock->uiTotalInodeNum);
printf("Used Inode : %u\r\n", pstSystemBlock->uiUsedInodeNum);
printf("Free Inode : %u\r\n", pstSystemBlock->uiTotalInodeNum-pstSystemBlock->uiUsedInodeNum);
printf("================================================\r\n");
free(pstSystemBlock);
return;
}
/**********************************************************************
函数名: DDFS_dump_sectorbitmap
函数说明: 显示扇区位图信息
入参: devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDFS_dump_sectorbitmap(int devfd)
{
unsigned int uiMallocSize = 0;
unsigned int uiLoop = 0;
unsigned char *pucBlock = NULL;
uiMallocSize = MACRO_DDFS_SECTOR_BYTE_SIZE*MACRO_DDFS_SECTOR_BITMAP_TOTAL_SECTOR_NUM;
pucBlock = (unsigned char*)malloc(uiMallocSize);
if (NULL == pucBlock)
{
return;
}
memset(pucBlock, 0, uiMallocSize);
DDfs_Get_SectorBitMap(pucBlock, uiMallocSize, devfd);
printf("=============SECTORBITMAP INFO====================\r\n");
for (; uiLoop < uiMallocSize; uiLoop++)
{
printf("%02X ", pucBlock[uiLoop]);
if (15 == uiLoop % 16)
{
printf("\r\n");
}
}
if (0 != uiLoop%16)
{
printf("\r\n");
}
printf("================================================\r\n");
free(pucBlock);
return;
}
/**********************************************************************
函数名: DDFS_dump_sectorbitmap
函数说明: 显示INODE位图信息
入参: devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDFS_dump_inodebitmap(int devfd)
{
unsigned int uiMallocSize = 0;
unsigned int uiLoop = 0;
unsigned char *pucBlock = NULL;
uiMallocSize = MACRO_DDFS_SECTOR_BYTE_SIZE*MACRO_DDFS_INODE_BITMAP_TOTAL_SECTOR_NUM;
pucBlock = (unsigned char*)malloc(uiMallocSize);
if (NULL == pucBlock)
{
return;
}
memset(pucBlock, 0, uiMallocSize);
DDfs_Get_InodeBitMap(pucBlock,uiMallocSize, devfd);
printf("=============INODEBITMAP INFO====================\r\n");
for (; uiLoop < uiMallocSize; uiLoop++)
{
printf("%02X ", pucBlock[uiLoop]);
if (15 == uiLoop % 16)
{
printf("\r\n");
}
}
if (0 != uiLoop%16)
{
printf("\r\n");
}
printf("================================================\r\n");
free(pucBlock);
return;
}
/**********************************************************************
函数名: DDFS_dump_filesector
函数说明: 显示文件扇区链表信息
入参: uiStartSector
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDFS_dump_filesector(unsigned int uiStartSector, int devfd)
{
unsigned int uiLoop = 0;
FileSectorList_s stFileSector = {0};
printf("==========SECTOR INFO(User-Space)=========\r\n");
printf(" %u ", uiStartSector);
uiLoop++;
DDfs_Get_FileSectorList_By_SectorNo(uiStartSector, &stFileSector, devfd);
while(stFileSector.uiIsNextSectorValid)
{
printf(" %u ", stFileSector.uiNextSector);
if (15 == uiLoop % 16)
{
printf("\r\n");
}
uiLoop++;
DDfs_Get_FileSectorList_By_SectorNo(stFileSector.uiNextSector, &stFileSector, devfd);
}
if (0 != uiLoop%16)
{
printf("\r\n");
}
return;
}
/**********************************************************************
函数名: DDFS_dump_inodeinfo
函数说明: 显示文件inode信息
入参: uiStartSector
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDFS_dump_inodeinfo(int devfd)
{
unsigned int uiMallocSize = 0;
unsigned int uiLoop = 0;
unsigned char *pucBlock = NULL;
InodeInfo_s stInodeInfo = {0};
uiMallocSize = MACRO_DDFS_SECTOR_BYTE_SIZE*MACRO_DDFS_INODE_BITMAP_TOTAL_SECTOR_NUM;
pucBlock = (unsigned char*)malloc(uiMallocSize);
if (NULL == pucBlock)
{
return;
}
memset(pucBlock, 0, uiMallocSize);
DDfs_Get_InodeBitMap(pucBlock,uiMallocSize, devfd);
printf("=============INODE INFO====================\r\n");
for (; uiLoop < MACRO_DDFS_INODE_TOTAL_NUM; uiLoop++)
{
if (!MACRO_DDFS_IS_BIT_SET_IN_BLOCK(uiLoop,pucBlock))
{
continue;
}
DDfs_Get_InodeInfo_By_InodeIndex(uiLoop,&stInodeInfo, devfd);
printf("###################################################\r\n");
printf("Inode No : %u\r\n", uiLoop);
printf("File Name : %s\r\n", stInodeInfo.acFileName);
printf("File Size : %u\r\n", stInodeInfo.uiFileSize);
printf("File Total Sector: %u\r\n", stInodeInfo.uiFileSectorNum);
printf("File Start Sector: %u\r\n", stInodeInfo.uiFileStartSector);
DDFS_dump_filesector(stInodeInfo.uiFileStartSector, devfd);
}
printf("================================================\r\n");
free(pucBlock);
return;
}
/*DDFS: 扁平文件系统,没有文件夹,扇区编号从0开始
第0个扇区作boot代码区,其中包含启动代码与分区表信息
第1个分区开始作systemblock分区,
1.总扇区数目, 已经使用扇区
2.总INODE数目,已经使用INODE
第2扇区SECTOR_BITMAP区,每个bit表示一个sector,总共4096扇区
第3扇区INODEINFO_BITMAP区,每个bit表示一个inode_INFO,当前设定Inode总共有512,占用一个扇区
第4扇区到第515扇区INODE_INFO区,大小为总INODE数目*INODE结构体大小,INDOE结构体包含以下内容:
1.文件名
2.文件大小
3.文件起始扇区
第516扇区到第547扇区FILE_SECTORLIST区,大小为总扇区数*扇区结构体大小,扇区结构体包含以下内容:
1.是否是最后一个扇区
2.下一个扇区号(如果当前扇区已经是最后一个扇区了,那么访问时将忽略这个字段)
扇区548之后就是用户扇区区域
*/
void main(int argc, char **argv)
{
int devfd = 0;
if (argc != 2)
{
printf("readddfs error\r\n");
return;
}
devfd = open(argv[1], O_RDWR);
if (devfd < 0)
{
printf("open error\r\n");
return;
}
DDFS_dump_systemblock(devfd);
DDFS_dump_sectorbitmap(devfd);
DDFS_dump_inodebitmap(devfd);
DDFS_dump_inodeinfo(devfd);
close(devfd);
}
初始化,写,读 三大掌门已经聚集,细心的同学发现他们包含了一个ddfs.h头文件,里面还调用了一些ddfs接口,这部分接口是文件操作相关的,抽象在ddfs.c中
Ddfs.c
#include "ddfs.h"
#if MACRO_DESC("文件系统块操作", 1)
/**********************************************************************
函数名: DDfs_Get_SystemBlockInfo
函数说明: 获取系统块信息
入参: devfd
出参: pstSystemBlockInfo
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Get_SystemBlockInfo(
SystemBlockInfo_s *pstSystemBlockInfo,
int devfd)
{
unsigned int uiOffset = 0;
uiOffset = MACRO_DDFS_SYSTEM_BLOCK_SECTOR_NO * MACRO_DDFS_SECTOR_BYTE_SIZE;
lseek(devfd, uiOffset, SEEK_SET);
read(devfd, pstSystemBlockInfo, MACRO_DDFS_SYSTEM_BLOCK_STRUCT_SIZE);
return;
}
/**********************************************************************
函数名: DDfs_Set_SystemBlockInfo
函数说明: 更新系统块信息
入参: pstSystemBlockInfo
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Set_SystemBlockInfo(
SystemBlockInfo_s *pstSystemBlockInfo,
int devfd)
{
unsigned int uiOffset = 0;
uiOffset = MACRO_DDFS_SYSTEM_BLOCK_SECTOR_NO * MACRO_DDFS_SECTOR_BYTE_SIZE;
lseek(devfd, uiOffset, SEEK_SET);
write(devfd, pstSystemBlockInfo, MACRO_DDFS_SYSTEM_BLOCK_STRUCT_SIZE);
return;
}
/**********************************************************************
函数名: DDfs_Update_SystemBlockInfo_By_Sector
函数说明: 根据sectornum更新系统块信息
入参: bisAlloc: true:占用,false:释放
uiSectorNum: 发生变化的扇区数目
devfd :
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Update_SystemBlockInfo_By_Sector(
bool bisAlloc,
unsigned int uiSectorNum,
int devfd)
{
SystemBlockInfo_s stSystemBlockInfo = {0};
DDfs_Get_SystemBlockInfo(&stSystemBlockInfo, devfd);
if (bisAlloc)
{
stSystemBlockInfo.uiUsedSectorNum += uiSectorNum;
}
else
{
stSystemBlockInfo.uiUsedSectorNum -= uiSectorNum;
}
DDfs_Set_SystemBlockInfo(&stSystemBlockInfo, devfd);
return;
}
/**********************************************************************
函数名: DDfs_Update_SystemBlockInfo_By_Inode
函数说明: 根据inode更新系统块信息
入参: bisAlloc: true:占用,false:释放
uiInodeNum: 发生变化的inode数目
devfd :
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Update_SystemBlockInfo_By_Inode(
bool bisAlloc,
unsigned int uiInodeNum,
int devfd)
{
SystemBlockInfo_s stSystemBlockInfo = {0};
DDfs_Get_SystemBlockInfo(&stSystemBlockInfo, devfd);
if (bisAlloc)
{
stSystemBlockInfo.uiUsedInodeNum += uiInodeNum;
}
else
{
stSystemBlockInfo.uiUsedInodeNum -= uiInodeNum;
}
DDfs_Set_SystemBlockInfo(&stSystemBlockInfo, devfd);
return;
}
/**********************************************************************
函数名: DDfs_IsInodeEnough
函数说明: 检查是否有可用的inode
入参: uiFileInodeNum
devfd :
出参: 无
返回值: MACRO_DDFS_OK:有可用inode,
其余值: 无可用inode
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
unsigned int DDfs_IsInodeEnough(
unsigned int uiFileInodeNum,
int devfd)
{
SystemBlockInfo_s stSystemBlockInfo = {0};
DDfs_Get_SystemBlockInfo(&stSystemBlockInfo, devfd);
if (stSystemBlockInfo.uiTotalInodeNum-stSystemBlockInfo.uiUsedInodeNum < uiFileInodeNum)
{
return MACRO_DDFS_ERR_NO_ENOUGH_INODE;
}
return MACRO_DDFS_OK;
}
/**********************************************************************
函数名: DDfs_IsSectorEnough
函数说明: 检查是否有可用的sector
入参: uiFileSectorNum
devfd :
出参: 无
返回值: MACRO_DDFS_OK:有可用sector,
其余值: 无可用sector
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
unsigned int DDfs_IsSectorEnough(
unsigned int uiFileSectorNum,
int devfd)
{
SystemBlockInfo_s stSystemBlockInfo = {0};
DDfs_Get_SystemBlockInfo(&stSystemBlockInfo, devfd);
if (stSystemBlockInfo.uiTotalSectorNum-stSystemBlockInfo.uiUsedSectorNum < uiFileSectorNum)
{
return MACRO_DDFS_ERR_NO_ENOUGH_SECTOR;
}
return MACRO_DDFS_OK;
}
/**********************************************************************
函数名: DDfs_Clr_AllFileSystem
函数说明: 清除整个文件系统
入参: devfd :
出参: 无
返回值: MACRO_DDFS_OK:操作成功
其余值: 操作失败
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
unsigned int DDfs_Clr_AllFileSystem(int devfd)
{
unsigned int uiOffset = 0;
unsigned int uiSize = 0;
unsigned char *pBlock = NULL;
/*文件系统区全部清0,用户区的不用清零,*/
uiOffset = MACRO_DDFS_START_SECTOR_NO * MACRO_DDFS_SECTOR_BYTE_SIZE;
uiSize = MACRO_DDFS_TOTAL_SECTOR_NUM * MACRO_DDFS_SECTOR_BYTE_SIZE;
pBlock = (unsigned char*)malloc(uiSize);
if (NULL == pBlock)
{
return MACRO_DDFS_ERR_NO_ENOUGH_MEMORY;
}
memset(pBlock, 0, uiSize);
lseek(devfd, uiOffset, SEEK_SET);
write(devfd, pBlock, uiSize);
free(pBlock);
return MACRO_DDFS_OK;
}
#endif
#if MACRO_DESC("扇区位图块操作", 1)
/**********************************************************************
函数名: DDfs_Get_SectorBitMap
函数说明: 获取扇区位图信息
入参: uiSectorBitMapsize
devfd
出参: pucSectorBitMap
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Get_SectorBitMap(
unsigned char * pucSectorBitMap,
unsigned int uiSectorBitMapsize,
int devfd)
{
unsigned int uiOffset = 0;
uiOffset = MACRO_DDFS_SECTOR_BITMAP_SECTOR_NO * MACRO_DDFS_SECTOR_BYTE_SIZE;
lseek(devfd, uiOffset, SEEK_SET);
read(devfd, pucSectorBitMap, uiSectorBitMapsize);
return;
}
/**********************************************************************
函数名: DDfs_Set_SectorBitMap
函数说明: 设置扇区位图信息
入参: pucSectorBitMap
uiSectorBitMapsize
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Set_SectorBitMap(
unsigned char * pucSectorBitMap,
unsigned int uiSectorBitMapsize,
int devfd)
{
unsigned int uiOffset = 0;
uiOffset = MACRO_DDFS_SECTOR_BITMAP_SECTOR_NO * MACRO_DDFS_SECTOR_BYTE_SIZE;
lseek(devfd, uiOffset, SEEK_SET);
write(devfd, pucSectorBitMap, uiSectorBitMapsize);
return;
}
/**********************************************************************
函数名: DDfs_Set_SectorBitMap
函数说明: 通过扇区号设置相应的扇区位图信息
入参: uiSectorNo
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Set_SectorBitMap_By_SectorNo(
unsigned int uiSectorNo,
int devfd)
{
unsigned int uiSize = 0;
unsigned char *pucBitMap = NULL;
uiSize = MACRO_DDFS_SECTOR_BITMAP_TOTAL_SECTOR_NUM* MACRO_DDFS_SECTOR_BYTE_SIZE;
pucBitMap = (unsigned char*)malloc(uiSize);
if (NULL == pucBitMap)
{
return ;
}
memset(pucBitMap, 0, uiSize);
DDfs_Get_SectorBitMap(pucBitMap, uiSize, devfd);
MACRO_DDFS_SET_BIT_IN_BLOCK(uiSectorNo, pucBitMap);
DDfs_Set_SectorBitMap(pucBitMap, uiSize, devfd);
free(pucBitMap);
return;
}
/**********************************************************************
函数名: DDfs_Clr_SectorBitMap_By_SectorNo
函数说明: 通过扇区号清除相应的扇区位图信息
入参: uiSectorNo
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Clr_SectorBitMap_By_SectorNo(
unsigned int uiSectorNo,
int devfd)
{
unsigned int uiSize = 0;
unsigned char *pucBitMap = NULL;
uiSize = MACRO_DDFS_SECTOR_BITMAP_TOTAL_SECTOR_NUM* MACRO_DDFS_SECTOR_BYTE_SIZE;
pucBitMap = (unsigned char*)malloc(uiSize);
if (NULL == pucBitMap)
{
return ;
}
memset(pucBitMap, 0, uiSize);
DDfs_Get_SectorBitMap(pucBitMap, uiSize, devfd);
MACRO_DDFS_CLR_BIT_IN_BLOCK(uiSectorNo, pucBitMap);
DDfs_Set_SectorBitMap(pucBitMap, uiSize, devfd);
free(pucBitMap);
return;
}
#endif
#if MACRO_DESC("inode位图块操作", 1)
/**********************************************************************
函数名: DDfs_Get_InodeBitMap
函数说明: 获取相应的INODE位图信息
入参: uiInodeBitMapsize
devfd
出参: pucInodeBitMap
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Get_InodeBitMap(
unsigned char * pucInodeBitMap,
unsigned int uiInodeBitMapsize,
int devfd)
{
unsigned int uiOffset = 0;
uiOffset = MACRO_DDFS_INODE_BITMAP_SECTOR_NO * MACRO_DDFS_SECTOR_BYTE_SIZE;
lseek(devfd, uiOffset, SEEK_SET);
read(devfd, pucInodeBitMap, uiInodeBitMapsize);
return;
}
/**********************************************************************
函数名: DDfs_Set_InodeBitMap
函数说明: 设置相应的INODE位图信息
入参: pucInodeBitMap
uiInodeBitMapsize
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Set_InodeBitMap(
unsigned char * pucInodeBitMap,
unsigned int uiInodeBitMapsize,
int devfd)
{
unsigned int uiOffset = 0;
uiOffset = MACRO_DDFS_INODE_BITMAP_SECTOR_NO * MACRO_DDFS_SECTOR_BYTE_SIZE;
lseek(devfd, uiOffset, SEEK_SET);
write(devfd, pucInodeBitMap, uiInodeBitMapsize);
return;
}
/**********************************************************************
函数名: DDfs_Set_InodeBitMap_By_InodeIndex
函数说明: 通过inode索引设置相应的INODE位图信息
入参: pucInodeBitMap
uiInodeBitMapsize
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Set_InodeBitMap_By_InodeIndex(
unsigned int uiInodeIndex,
int devfd)
{
unsigned int uiSize = 0;
unsigned char *pucBitMap = NULL;
uiSize = MACRO_DDFS_INODE_BITMAP_TOTAL_SECTOR_NUM* MACRO_DDFS_SECTOR_BYTE_SIZE;
pucBitMap = (unsigned char*)malloc(uiSize);
if (NULL == pucBitMap)
{
return ;
}
memset(pucBitMap, 0, uiSize);
DDfs_Get_InodeBitMap(pucBitMap, uiSize, devfd);
MACRO_DDFS_SET_BIT_IN_BLOCK(uiInodeIndex, pucBitMap);
DDfs_Set_InodeBitMap(pucBitMap, uiSize, devfd);
free(pucBitMap);
return;
}
/**********************************************************************
函数名: DDfs_Clr_InodeBitMap_By_InodeIndex
函数说明: 通过inode索引清除相应的INODE位图信息
入参: pucInodeBitMap
uiInodeBitMapsize
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Clr_InodeBitMap_By_InodeIndex(
unsigned int uiInodeIndex,
int devfd)
{
unsigned int uiSize = 0;
unsigned char *pucBitMap = NULL;
uiSize = MACRO_DDFS_INODE_BITMAP_TOTAL_SECTOR_NUM* MACRO_DDFS_SECTOR_BYTE_SIZE;
pucBitMap = (unsigned char*)malloc(uiSize);
if (NULL == pucBitMap)
{
return ;
}
memset(pucBitMap, 0, uiSize);
DDfs_Get_InodeBitMap(pucBitMap, uiSize, devfd);
MACRO_DDFS_CLR_BIT_IN_BLOCK(uiInodeIndex, pucBitMap);
DDfs_Set_InodeBitMap(pucBitMap, uiSize, devfd);
free(pucBitMap);
return;
}
#endif
#if MACRO_DESC("inode信息操作", 1)
/**********************************************************************
函数名: DDfs_Get_InodeInfo_By_InodeIndex
函数说明: 通过inode索引获取inode信息
入参: uiInodeIndex
devfd
出参: pstInodeInfo
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Get_InodeInfo_By_InodeIndex(
unsigned int uiInodeIndex,
InodeInfo_s *pstInodeInfo,
int devfd)
{
unsigned int uiOffset = 0;
uiOffset = MACRO_DDFS_INODE_INFO_START_SECTOR_NO * MACRO_DDFS_SECTOR_BYTE_SIZE;
uiOffset += uiInodeIndex * MACRO_DDFS_INODE_INFO_STRUCT_SIZE;
lseek(devfd, uiOffset, SEEK_SET);
read(devfd, pstInodeInfo, MACRO_DDFS_INODE_INFO_STRUCT_SIZE);
return;
}
/**********************************************************************
函数名: DDfs_Set_InodeInfo_By_InodeIndex
函数说明: 通过inode索引设置inode信息
入参: uiInodeIndex
pstInodeInfo
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Set_InodeInfo_By_InodeIndex(
unsigned int uiInodeIndex,
InodeInfo_s *pstInodeInfo,
int devfd)
{
unsigned int uiOffset = 0;
uiOffset = MACRO_DDFS_INODE_INFO_START_SECTOR_NO * MACRO_DDFS_SECTOR_BYTE_SIZE;
uiOffset += uiInodeIndex * MACRO_DDFS_INODE_INFO_STRUCT_SIZE;
lseek(devfd, uiOffset, SEEK_SET);
write(devfd, pstInodeInfo, MACRO_DDFS_INODE_INFO_STRUCT_SIZE);
return;
}
/**********************************************************************
函数名: DDfs_Clr_InodeInfo_By_InodeIndex
函数说明: 通过inode索引清除inode信息
入参: uiInodeIndex
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Clr_InodeInfo_By_InodeIndex(
unsigned int uiInodeIndex,
int devfd)
{
unsigned int uiOffset = 0;
InodeInfo_s stInodeInfo= {0};
uiOffset = MACRO_DDFS_INODE_INFO_START_SECTOR_NO * MACRO_DDFS_SECTOR_BYTE_SIZE;
uiOffset += uiInodeIndex * MACRO_DDFS_INODE_INFO_STRUCT_SIZE;
lseek(devfd, uiOffset, SEEK_SET);
write(devfd, &stInodeInfo, MACRO_DDFS_INODE_INFO_STRUCT_SIZE);
return;
}
#endif
#if MACRO_DESC("文件扇区链表操作", 1)
/**********************************************************************
函数名: DDfs_Get_FileSectorList_By_SectorNo
函数说明: 通过扇区号索引获取文件扇区信息
入参: uiSectorNo
devfd
出参: pstFileSectorList
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Get_FileSectorList_By_SectorNo(
unsigned int uiSectorNo,
FileSectorList_s *pstFileSectorList,
int devfd)
{
unsigned int uiOffset = 0;
uiOffset = MACRO_DDFS_FILE_SECTOR_LIST_START_SECTOR_NO * MACRO_DDFS_SECTOR_BYTE_SIZE;
uiOffset += uiSectorNo * MACRO_DDFS_FILE_SECTOR_LIST_STRUCT_SIZE;
lseek(devfd, uiOffset, SEEK_SET);
read(devfd, pstFileSectorList, MACRO_DDFS_FILE_SECTOR_LIST_STRUCT_SIZE);
return;
}
/**********************************************************************
函数名: DDfs_Set_FileSectorList_By_SectorNo
函数说明: 通过扇区号索引设置文件扇区信息
入参: uiSectorNo
pstFileSectorList
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Set_FileSectorList_By_SectorNo(
unsigned int uiSectorNo,
FileSectorList_s *pstFileSectorList,
int devfd)
{
unsigned int uiOffset = 0;
uiOffset = MACRO_DDFS_FILE_SECTOR_LIST_START_SECTOR_NO * MACRO_DDFS_SECTOR_BYTE_SIZE;
uiOffset += uiSectorNo * MACRO_DDFS_FILE_SECTOR_LIST_STRUCT_SIZE;
lseek(devfd, uiOffset, SEEK_SET);
write(devfd, pstFileSectorList, MACRO_DDFS_FILE_SECTOR_LIST_STRUCT_SIZE);
return;
}
/**********************************************************************
函数名: DDfs_Clr_FileSectorList_By_SectorNo
函数说明: 通过扇区号索引清除文件扇区信息
入参: uiSectorNo
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Clr_FileSectorList_By_SectorNo(
unsigned int uiSectorNo,
int devfd)
{
unsigned int uiOffset = 0;
FileSectorList_s stFileSectorList = {0};
uiOffset = MACRO_DDFS_FILE_SECTOR_LIST_START_SECTOR_NO * MACRO_DDFS_SECTOR_BYTE_SIZE;
uiOffset += uiSectorNo * MACRO_DDFS_FILE_SECTOR_LIST_STRUCT_SIZE;
lseek(devfd, uiOffset, SEEK_SET);
write(devfd, &stFileSectorList, MACRO_DDFS_FILE_SECTOR_LIST_STRUCT_SIZE);
return;
}
/**********************************************************************
函数名: DDfs_Get_AllSectorList_By_FirstSector
函数说明: 通过首扇区号获取所有的扇区信息
入参: uiFileStartSector
uiSectorListNum
devfd
出参: puiSectorList
puiOutSectorNum
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Get_AllSectorList_By_FirstSector(
unsigned int uiFileStartSector,
unsigned int uiSectorListNum,
unsigned int *puiSectorList,
unsigned int *puiOutSectorNum,
int devfd)
{
unsigned int uiSectorNum = 0;
FileSectorList_s stFileSectorList = {0};
unsigned int *puiTempSectorList=puiSectorList;
puiTempSectorList[uiSectorNum++] = uiFileStartSector;
DDfs_Get_FileSectorList_By_SectorNo(uiFileStartSector, &stFileSectorList, devfd);
while(stFileSectorList.uiIsNextSectorValid && uiSectorNum < uiSectorListNum)
{
puiTempSectorList[uiSectorNum++] = stFileSectorList.uiNextSector;
DDfs_Get_FileSectorList_By_SectorNo(stFileSectorList.uiNextSector, &stFileSectorList, devfd);
}
*puiOutSectorNum = uiSectorNum;
return;
}
#endif
#if MACRO_DESC("文件操作", 1)
/**********************************************************************
函数名: DDfs_Alloc_File_InodeIndex
函数说明: 为文件分配一个inode
入参: devfd
出参: puiInodeIndex
返回值: MACRO_DDFS_OK:分配成功
其余值:分配失败
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
unsigned int DDfs_Alloc_File_InodeIndex(
unsigned int *puiInodeIndex,
int devfd)
{
unsigned int uiRet = MACRO_DDFS_OK;
unsigned int uiIndexLoop = 0;
unsigned int uiSize = 0;
unsigned char *pucBitMap = NULL;
uiRet = DDfs_IsInodeEnough(1, devfd);
if (uiRet != MACRO_DDFS_OK)
{
return MACRO_DDFS_ERR_NO_ENOUGH_INODE;
}
uiSize = MACRO_DDFS_INODE_BITMAP_TOTAL_SECTOR_NUM* MACRO_DDFS_SECTOR_BYTE_SIZE;
pucBitMap = (unsigned char*)malloc(uiSize);
if (NULL == pucBitMap)
{
return MACRO_DDFS_ERR_NO_ENOUGH_MEMORY;
}
memset(pucBitMap, 0, uiSize);
DDfs_Get_InodeBitMap(pucBitMap, uiSize, devfd);
for (uiIndexLoop = 0; uiIndexLoop < MACRO_DDFS_INODE_TOTAL_NUM; uiIndexLoop++)
{
if (MACRO_DDFS_IS_BIT_SET_IN_BLOCK(uiIndexLoop, pucBitMap))
{
continue;
}
else
{
*puiInodeIndex = uiIndexLoop;
break;
}
}
if (uiIndexLoop >= MACRO_DDFS_INODE_TOTAL_NUM)
{
return MACRO_DDFS_ERR_NO_ENOUGH_INODE;
}
free(pucBitMap);
return MACRO_DDFS_OK;
}
/**********************************************************************
函数名: DDfs_Alloc_File_SectorList
函数说明: 为文件分配所需要的全部扇区信息
入参: uiSectorNum
devfd
出参: puiSectorList
返回值: MACRO_DDFS_OK:分配成功
其余值:分配失败
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
unsigned int DDfs_Alloc_File_SectorList(
unsigned int uiSectorNum,
unsigned int *puiSectorList,
int devfd)
{
unsigned int uiRet = MACRO_DDFS_OK;
unsigned int uiSectorLoop = 0;
unsigned int uiSize = 0;
unsigned int uiAllocNum = 0;
unsigned char *pucBitMap = NULL;
uiRet = DDfs_IsSectorEnough(uiSectorNum, devfd);
if (uiRet != MACRO_DDFS_OK)
{
return MACRO_DDFS_ERR_NO_ENOUGH_SECTOR;
}
uiSize = MACRO_DDFS_SECTOR_BITMAP_TOTAL_SECTOR_NUM* MACRO_DDFS_SECTOR_BYTE_SIZE;
pucBitMap = (unsigned char*)malloc(uiSize);
if (NULL == pucBitMap)
{
return MACRO_DDFS_ERR_NO_ENOUGH_MEMORY;
}
memset(pucBitMap, 0, uiSize);
DDfs_Get_SectorBitMap(pucBitMap, uiSize, devfd);
for (uiSectorLoop = 0; uiSectorLoop < MACRO_DDFS_SECTOR_TOTAL_NUM; uiSectorLoop++)
{
if (MACRO_DDFS_IS_BIT_SET_IN_BLOCK(uiSectorLoop, pucBitMap))
{
continue;
}
else
{
puiSectorList[uiAllocNum++] = uiSectorLoop;
if (uiAllocNum >= uiSectorNum)
{
break;
}
}
}
if (uiSectorLoop >= MACRO_DDFS_SECTOR_TOTAL_NUM)
{
return MACRO_DDFS_ERR_NO_ENOUGH_SECTOR;
}
free(pucBitMap);
return MACRO_DDFS_OK;
}
/**********************************************************************
函数名: DDfs_Get_InodeInfo_By_FileName
函数说明: 通过文件名获取其文件信息
入参: pcFileName
devfd
出参: puiInodeIndex
pstInodeInfo
返回值: MACRO_DDFS_OK:操作成功
其余值:操作失败
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
unsigned int DDfs_Get_InodeInfo_By_FileName(
char *pcFileName,
unsigned int *puiInodeIndex,
InodeInfo_s *pstInodeInfo,
int devfd)
{
unsigned int uiFileInodeIndex = 0;
unsigned int uiSize = 0;
unsigned char * pucInodeBitMap = NULL;
InodeInfo_s stInodeInfo = {0};
uiSize = MACRO_DDFS_INODE_BITMAP_TOTAL_SECTOR_NUM * MACRO_DDFS_SECTOR_BYTE_SIZE;
pucInodeBitMap = (unsigned char*)malloc(uiSize);
if (NULL == pucInodeBitMap)
{
return MACRO_DDFS_ERR_NO_ENOUGH_MEMORY;
}
memset(pucInodeBitMap, 0, uiSize);
DDfs_Get_InodeBitMap(pucInodeBitMap, uiSize, devfd);
for (uiFileInodeIndex = 0; uiFileInodeIndex < MACRO_DDFS_INODE_TOTAL_NUM; uiFileInodeIndex++)
{
if (MACRO_DDFS_IS_BIT_SET_IN_BLOCK(uiFileInodeIndex, pucInodeBitMap))
{
/* 找到了同名的文件 */
DDfs_Get_InodeInfo_By_InodeIndex(uiFileInodeIndex, &stInodeInfo, devfd);
if (strlen(stInodeInfo.acFileName) != strlen(pcFileName))
{
continue;
}
if (0 != memcmp(stInodeInfo.acFileName, pcFileName, strlen(pcFileName)))
{
continue;
}
if (NULL != pstInodeInfo)
{
memcpy(pstInodeInfo, &stInodeInfo, MACRO_DDFS_INODE_INFO_STRUCT_SIZE);
}
if (NULL != puiInodeIndex)
{
*puiInodeIndex = uiFileInodeIndex;
}
free(pucInodeBitMap);
return MACRO_DDFS_OK;
}
}
free(pucInodeBitMap);
return MACRO_DDFS_ERR_NO_FILE_NOT_EXIST;
}
/**********************************************************************
函数名: DDfs_Write_FileData_2_Sector
函数说明: 文件内容写入指定的扇区中
入参: uiFileSize
uiSectorNum
puiSectorList
filefd
devfd
出参: 无
返回值: MACRO_DDFS_OK:操作成功
其余值:操作失败
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
unsigned int DDfs_Write_FileData_2_Sector(
unsigned int uiFileSize,
unsigned int uiSectorNum,
unsigned int *puiSectorList,
int filefd,
int devfd)
{
unsigned char *pBuff = NULL;
unsigned int uiSectorLoop = 0;
unsigned int uiFileLen = 0;
unsigned int uiFileOffset = 0;
/*将文件内容写入对应的扇区*/
pBuff = (unsigned char *)malloc(uiFileSize);
if (NULL == pBuff)
{
return MACRO_DDFS_ERR_NO_ENOUGH_MEMORY;
}
memset(pBuff, 0, uiFileSize);
lseek(filefd, 0, SEEK_SET);
read(filefd, pBuff, uiFileSize);
uiFileLen = uiFileSize;
uiFileOffset = 0;
for (uiSectorLoop = 0; uiSectorLoop < uiSectorNum; uiSectorLoop++)
{
uiFileLen = uiFileLen < MACRO_DDFS_SECTOR_BYTE_SIZE ? uiFileLen : MACRO_DDFS_SECTOR_BYTE_SIZE;
lseek(devfd, MACRO_DDFS_SECTOR_BYTE_SIZE * puiSectorList[uiSectorLoop], SEEK_SET);
write(devfd, &pBuff[uiFileOffset], uiFileLen);
uiFileOffset += uiFileLen;
uiFileLen = uiFileSize - uiFileOffset;
}
free(pBuff);
return MACRO_DDFS_OK;
}
/**********************************************************************
函数名: DDfs_Add_File_By_FileName
函数说明: 文件写入文件系统中
入参: pcFileName
filefd
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Add_File_By_FileName(
char* pcFileName,
int filefd,
int devfd)
{
int iRet = 0;
unsigned int uiRet = 0;
unsigned int uiInodeIndex = 0;
InodeInfo_s stInodeInfo = {0};
FileSectorList_s stFileSector = {0};
unsigned int uiFileSize = 0;
unsigned int uiFileSector = 0;
unsigned int uiFileSectorLoop = 0;
struct stat stFilestat = {0};
unsigned int *puiSectorNum = NULL;
iRet = fstat(filefd, &stFilestat);
if (iRet || (0 == stFilestat.st_size))
{
printf("install_file: Failed to get file stat\n");
return;
}
uiFileSize = stFilestat.st_size;
uiFileSector = MACRO_DDFS_BYTE_TO_SECTORS(uiFileSize);
printf("install_file: File %s size is %u(sector num: %u)\n", pcFileName, uiFileSize, uiFileSector);
uiRet = DDfs_Alloc_File_InodeIndex(&uiInodeIndex, devfd);
if (MACRO_DDFS_OK != uiRet)
{
return;
}
printf("install_file: File %s inode %u\n", pcFileName, uiInodeIndex);
puiSectorNum= (unsigned int *)malloc(sizeof(unsigned int)*uiFileSector);
if (NULL == puiSectorNum)
{
return;
}
memset(puiSectorNum, 0, sizeof(unsigned int)*uiFileSector);
uiRet = DDfs_Alloc_File_SectorList(uiFileSector, puiSectorNum, devfd);
if (MACRO_DDFS_OK != uiRet)
{
return;
}
printf("sector list:");
for(uiFileSectorLoop = 0; uiFileSectorLoop < uiFileSector; uiFileSectorLoop++)
{
printf(" %u ", puiSectorNum[uiFileSectorLoop]);
}
printf("\r\n");
//文件内容写入
uiRet = DDfs_Write_FileData_2_Sector(uiFileSize, uiFileSector, puiSectorNum, filefd, devfd);
if (MACRO_DDFS_OK != uiRet)
{
return;
}
//更新inodebitmap inodeinfo
DDfs_Set_InodeBitMap_By_InodeIndex(uiInodeIndex, devfd);
memcpy(stInodeInfo.acFileName, pcFileName, strlen(pcFileName));
stInodeInfo.uiFileSectorNum = uiFileSector;
stInodeInfo.uiFileSize = uiFileSize;
stInodeInfo.uiFileStartSector= puiSectorNum[0];
DDfs_Set_InodeInfo_By_InodeIndex(uiInodeIndex, &stInodeInfo, devfd);
//更新sectorbitmap ,filesectorlist
for(uiFileSectorLoop = 0; uiFileSectorLoop < uiFileSector; uiFileSectorLoop++)
{
DDfs_Set_SectorBitMap_By_SectorNo(puiSectorNum[uiFileSectorLoop], devfd);
if (uiFileSectorLoop+1 < uiFileSector)
{
stFileSector.uiIsNextSectorValid = true;
stFileSector.uiNextSector = puiSectorNum[uiFileSectorLoop+1];
}
else
{
stFileSector.uiIsNextSectorValid = false;
stFileSector.uiNextSector = 0;
}
DDfs_Set_FileSectorList_By_SectorNo(puiSectorNum[uiFileSectorLoop], &stFileSector, devfd);
}
//3. 刷新systemblock中扇区与inode纪录
DDfs_Update_SystemBlockInfo_By_Sector(true, uiFileSector, devfd);
DDfs_Update_SystemBlockInfo_By_Inode(true, 1, devfd);
return;
}
/**********************************************************************
函数名: DDfs_Delete_File_By_FileName
函数说明: 文件系统中删除指定的文件
入参: pcFileName
devfd
出参: 无
返回值: MACRO_DDFS_OK:操作成功
其余值:操作失败
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Delete_File_By_FileName(
char* pcFileName,
int devfd)
{
unsigned int uiRet = 0;
unsigned int uiInodeIndex = 0;
InodeInfo_s stInodeInfo = {0};
unsigned int *puiSectorNum= NULL;
unsigned int uiSectorNum = 0;
unsigned int uiOutSectorNum=0;
uiRet = DDfs_Get_InodeInfo_By_FileName(pcFileName,&uiInodeIndex,&stInodeInfo, devfd);
if (MACRO_DDFS_OK != uiRet)
{
return;
}
uiSectorNum = stInodeInfo.uiFileSectorNum;
puiSectorNum= (unsigned int *)malloc(sizeof(unsigned int)*uiSectorNum);
if (NULL == puiSectorNum)
{
return;
}
DDfs_Get_AllSectorList_By_FirstSector(stInodeInfo.uiFileStartSector, uiSectorNum, puiSectorNum, &uiOutSectorNum, devfd);
//一个文件,会涉及到sectorebitmap inodebitmap inodeinfo filesectorlist systemblock这些信息,因此需要删除
//文件内容所写入的扇区可不用删除
//1. 清除sectorbitmap filesectorlist
uiSectorNum = uiOutSectorNum;
while(uiOutSectorNum)
{
uiOutSectorNum--;
DDfs_Clr_SectorBitMap_By_SectorNo(puiSectorNum[uiOutSectorNum], devfd);
DDfs_Clr_FileSectorList_By_SectorNo(puiSectorNum[uiOutSectorNum], devfd);
}
//2. 清除inodebitmap inodeinfo
DDfs_Clr_InodeBitMap_By_InodeIndex(uiInodeIndex, devfd);
DDfs_Clr_InodeInfo_By_InodeIndex(uiInodeIndex, devfd);
//3. 刷新systemblock中扇区与inode纪录
DDfs_Update_SystemBlockInfo_By_Sector(false, uiSectorNum, devfd);
DDfs_Update_SystemBlockInfo_By_Inode(false, 1, devfd);
return;
}
#endif
Ddfs.h
#ifndef _DDFS_H_
#define _DDFS_H_
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <time.h>
#include <linux/fs.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <libgen.h>
#define MACRO_DESC(desc, enable) (enable)
/*计算CHAR/SHORT/INT/LONG类型占用的BIT大小*/
#define MACRO_TYPE_CHAR_BIT_SIZE (sizeof(char)*8)
#define MACRO_TYPE_SHORT_BIT_SIZE (sizeof(short)*8)
#define MACRO_TYPE_INT_BIT_SIZE (sizeof(int)*8)
#define MACRO_TYPE_LONG_BIT_SIZE (sizeof(long)*8)
/*各种异常返回值定义*/
#define MACRO_DDFS_OK (0)
#define MACRO_DDFS_ERR_NO_ENOUGH_INODE ((unsigned int)1 << 0)
#define MACRO_DDFS_ERR_NO_ENOUGH_SECTOR ((unsigned int)1 << 1)
#define MACRO_DDFS_ERR_NO_ENOUGH_MEMORY ((unsigned int)1 << 2)
#define MACRO_DDFS_ERR_NO_FILE_NOT_EXIST ((unsigned int)1 << 3)
/*一个扇区的字节数*/
#define MACRO_DDFS_SECTOR_BYTE_SIZE (512)
/*文件系统块信息相关宏定义*/
#define MACRO_DDFS_SYSTEM_BLOCK_SECTOR_NO (1)
#define MACRO_DDFS_SYSTEM_BLOCK_TOTAL_SECTOR_NUM (1)
/*扇区使用BITMAP信息相关宏定义*/
#define MACRO_DDFS_SECTOR_BITMAP_SECTOR_NO (2)
#define MACRO_DDFS_SECTOR_BITMAP_TOTAL_SECTOR_NUM (1)
#define MACRO_DDFS_SECTOR_TOTAL_NUM (4096)
/*INODE使用BITMAP信息相关宏定义*/
#define MACRO_DDFS_INODE_BITMAP_SECTOR_NO (3)
#define MACRO_DDFS_INODE_BITMAP_TOTAL_SECTOR_NUM (1)
#define MACRO_DDFS_INODE_TOTAL_NUM (4096)
/*INODE信息相关宏定义*/
#define MACRO_DDFS_INODE_INFO_START_SECTOR_NO (4)
#define MACRO_DDFS_INODE_INFO_TOTAL_SECTOR_NUM (512)
#define MACRO_DDFS_INODE_INFO_FILENAME_LEN (32)
#define MACRO_DDFS_INODE_INFO_RSV_LEN (20)
/*文件扇区列表信息相关宏定义*/
#define MACRO_DDFS_FILE_SECTOR_LIST_START_SECTOR_NO (516)
#define MACRO_DDFS_FILE_SECTOR_LIST_TOTAL_SECTOR_NUM (32)
/*文件系统区相关宏定义*/
#define MACRO_DDFS_START_SECTOR_NO (1)
#define MACRO_DDFS_TOTAL_SECTOR_NUM (547)
/*文件数据区信息相关宏定义*/
#define MACRO_DDFS_FILE_DATA_START_SECTOR_NO (548)
#define MACRO_DDFS_FILE_DATA_TOTAL_SECTOR_NUM (3548)
/*SystemBlock结构构体当前8字节*/
typedef struct tagSystemBlockInfo{
unsigned int uiTotalSectorNum;
unsigned int uiUsedSectorNum;
unsigned int uiTotalInodeNum;
unsigned int uiUsedInodeNum;
}SystemBlockInfo_s;
#define MACRO_DDFS_SYSTEM_BLOCK_STRUCT_SIZE (sizeof(SystemBlockInfo_s))
/*InodeInfo结构构体当前64字节*/
typedef struct tagInodeInfo{
char acFileName[MACRO_DDFS_INODE_INFO_FILENAME_LEN];
unsigned int uiFileSize;
unsigned int uiFileSectorNum;
unsigned int uiFileStartSector;
char acRsv[MACRO_DDFS_INODE_INFO_RSV_LEN];
}InodeInfo_s;
#define MACRO_DDFS_INODE_INFO_STRUCT_SIZE (sizeof(InodeInfo_s))
/*纪录sector的使用情况*/
typedef struct tagFileSectorList{
unsigned int uiIsNextSectorValid;
unsigned int uiNextSector;
}FileSectorList_s;
#define MACRO_DDFS_FILE_SECTOR_LIST_STRUCT_SIZE (sizeof(FileSectorList_s))
#define MACRO_DDFS_BYTE_TO_SECTORS(bytes)\
((bytes+MACRO_DDFS_SECTOR_BYTE_SIZE-1)/MACRO_DDFS_SECTOR_BYTE_SIZE)
#define MACRO_DDFS_IS_BIT_SET_IN_BLOCK(bitOffset, block) \
(block[(bitOffset)/MACRO_TYPE_CHAR_BIT_SIZE] & (1 << ((bitOffset)%MACRO_TYPE_CHAR_BIT_SIZE)))
#define MACRO_DDFS_SET_BIT_IN_BLOCK(bitOffset, block) \
(block[(bitOffset)/MACRO_TYPE_CHAR_BIT_SIZE] |= (1 << ((bitOffset)%MACRO_TYPE_CHAR_BIT_SIZE)))
#define MACRO_DDFS_CLR_BIT_IN_BLOCK(bitOffset, block) \
(block[(bitOffset)/MACRO_TYPE_CHAR_BIT_SIZE] &= (~(1 << ((bitOffset)%MACRO_TYPE_CHAR_BIT_SIZE))))
#define DDFS_RETURN_IF_MALLOC_FAIL(ptr)\
do\
{\
if (NULL == ptr)\
{\
exit(1);\
}\
}while(0);
#define DDFS_FREE_PTR(ptr)\
do\
{\
if (NULL != ptr)\
{\
free(ptr);\
}\
}while(0);
#define DDFS_DUMP_MEMORY(ptr, ptrLen, outLenEachLine) \
do\
{\
int i = 0;\
for (i = 0; i < ptrLen; i++)\
{\
if (i%outLenEachLine == 0)\
{\
printf("%08X: ", i);\
}\
printf("%02X ", ptr[i]);\
if ((i+1)%outLenEachLine == 0)\
{\
printf("\r\n");\
}\
}\
if (i%outLenEachLine != 0)\
{\
printf("\r\n");\
}\
}while(0);
#if MACRO_DESC("文件系统块操作", 1)
/**********************************************************************
函数名: DDfs_Get_SystemBlockInfo
函数说明: 获取系统块信息
入参: devfd
出参: pstSystemBlockInfo
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Get_SystemBlockInfo(
SystemBlockInfo_s *pstSystemBlockInfo,
int devfd);
/**********************************************************************
函数名: DDfs_Set_SystemBlockInfo
函数说明: 更新系统块信息
入参: pstSystemBlockInfo
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Set_SystemBlockInfo(
SystemBlockInfo_s *pstSystemBlockInfo,
int devfd);
/**********************************************************************
函数名: DDfs_Update_SystemBlockInfo_By_Sector
函数说明: 根据sectornum更新系统块信息
入参: bisAlloc: true:占用,false:释放
uiSectorNum: 发生变化的扇区数目
devfd :
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Update_SystemBlockInfo_By_Sector(
bool bisAlloc,
unsigned int uiSectorNum,
int devfd);
/**********************************************************************
函数名: DDfs_Update_SystemBlockInfo_By_Inode
函数说明: 根据inode更新系统块信息
入参: bisAlloc: true:占用,false:释放
uiInodeNum: 发生变化的inode数目
devfd :
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Update_SystemBlockInfo_By_Inode(
bool bisAlloc,
unsigned int uiInodeNum,
int devfd);
/**********************************************************************
函数名: DDfs_Clr_AllFileSystem
函数说明: 清除整个文件系统
入参: devfd :
出参: 无
返回值: MACRO_DDFS_OK:操作成功
其余值: 操作失败
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
unsigned int DDfs_Clr_AllFileSystem(int devfd);
/**********************************************************************
函数名: DDfs_IsInodeEnough
函数说明: 检查是否有可用的inode
入参: uiFileInodeNum
devfd :
出参: 无
返回值: MACRO_DDFS_OK:有可用inode,
其余值: 无可用inode
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
unsigned int DDfs_IsInodeEnough(
unsigned int uiFileInodeNum,
int devfd);
/**********************************************************************
函数名: DDfs_IsSectorEnough
函数说明: 检查是否有可用的sector
入参: uiFileSectorNum
devfd :
出参: 无
返回值: MACRO_DDFS_OK:有可用sector,
其余值: 无可用sector
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
unsigned int DDfs_IsSectorEnough(
unsigned int uiFileSectorNum,
int devfd);
#endif
#if MACRO_DESC("扇区位图块操作", 1)
/**********************************************************************
函数名: DDfs_Get_SectorBitMap
函数说明: 获取扇区位图信息
入参: uiSectorBitMapsize
devfd
出参: pucSectorBitMap
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Get_SectorBitMap(
unsigned char * pucSectorBitMap,
unsigned int uiSectorBitMapsize,
int devfd);
/**********************************************************************
函数名: DDfs_Set_SectorBitMap
函数说明: 设置扇区位图信息
入参: pucSectorBitMap
uiSectorBitMapsize
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Set_SectorBitMap(
unsigned char * pucSectorBitMap,
unsigned int uiSectorBitMapsize,
int devfd);
/**********************************************************************
函数名: DDfs_Set_SectorBitMap
函数说明: 通过扇区号设置相应的扇区位图信息
入参: uiSectorNo
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Set_SectorBitMap_By_SectorNo(
unsigned int uiSectorNo,
int devfd);
/**********************************************************************
函数名: DDfs_Clr_SectorBitMap_By_SectorNo
函数说明: 通过扇区号清除相应的扇区位图信息
入参: uiSectorNo
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Clr_SectorBitMap_By_SectorNo(
unsigned int uiSectorNo,
int devfd);
#endif
#if MACRO_DESC("inode位图块操作", 1)
/**********************************************************************
函数名: DDfs_Get_InodeBitMap
函数说明: 获取相应的INODE位图信息
入参: uiInodeBitMapsize
devfd
出参: pucInodeBitMap
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Get_InodeBitMap(
unsigned char * pucInodeBitMap,
unsigned int uiInodeBitMapsize,
int devfd);
/**********************************************************************
函数名: DDfs_Set_InodeBitMap
函数说明: 设置相应的INODE位图信息
入参: pucInodeBitMap
uiInodeBitMapsize
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Set_InodeBitMap(
unsigned char * pucInodeBitMap,
unsigned int uiInodeBitMapsize,
int devfd);
/**********************************************************************
函数名: DDfs_Set_InodeBitMap_By_InodeIndex
函数说明: 通过inode索引设置相应的INODE位图信息
入参: pucInodeBitMap
uiInodeBitMapsize
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Set_InodeBitMap_By_InodeIndex(
unsigned int uiInodeIndex,
int devfd);
/**********************************************************************
函数名: DDfs_Clr_InodeBitMap_By_InodeIndex
函数说明: 通过inode索引清除相应的INODE位图信息
入参: pucInodeBitMap
uiInodeBitMapsize
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Clr_InodeBitMap_By_InodeIndex(
unsigned int uiInodeIndex,
int devfd);
#endif
#if MACRO_DESC("inode信息操作", 1)
/**********************************************************************
函数名: DDfs_Get_InodeInfo_By_InodeIndex
函数说明: 通过inode索引获取inode信息
入参: uiInodeIndex
devfd
出参: pstInodeInfo
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Get_InodeInfo_By_InodeIndex(
unsigned int uiInodeIndex,
InodeInfo_s *pstInodeInfo,
int devfd);
/**********************************************************************
函数名: DDfs_Set_InodeInfo_By_InodeIndex
函数说明: 通过inode索引设置inode信息
入参: uiInodeIndex
pstInodeInfo
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Set_InodeInfo_By_InodeIndex(
unsigned int uiInodeIndex,
InodeInfo_s *pstInodeInfo,
int devfd);
/**********************************************************************
函数名: DDfs_Clr_InodeInfo_By_InodeIndex
函数说明: 通过inode索引清除inode信息
入参: uiInodeIndex
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Clr_InodeInfo_By_InodeIndex(
unsigned int uiInodeIndex,
int devfd);
#endif
#if MACRO_DESC("文件扇区链表操作", 1)
/**********************************************************************
函数名: DDfs_Get_FileSectorList_By_SectorNo
函数说明: 通过扇区号索引获取文件扇区信息
入参: uiSectorNo
devfd
出参: pstFileSectorList
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Get_FileSectorList_By_SectorNo(
unsigned int uiSectorNo,
FileSectorList_s *pstFileSectorList,
int devfd);
/**********************************************************************
函数名: DDfs_Set_FileSectorList_By_SectorNo
函数说明: 通过扇区号索引设置文件扇区信息
入参: uiSectorNo
pstFileSectorList
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Set_FileSectorList_By_SectorNo(
unsigned int uiSectorNo,
FileSectorList_s *pstFileSectorList,
int devfd);
/**********************************************************************
函数名: DDfs_Clr_FileSectorList_By_SectorNo
函数说明: 通过扇区号索引清除文件扇区信息
入参: uiSectorNo
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Clr_FileSectorList_By_SectorNo(
unsigned int uiSectorNo,
int devfd);
/**********************************************************************
函数名: DDfs_Get_AllSectorList_By_FirstSector
函数说明: 通过首扇区号获取所有的扇区信息
入参: uiFileStartSector
uiSectorListNum
devfd
出参: puiSectorList
puiOutSectorNum
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Get_AllSectorList_By_FirstSector(
unsigned int uiFileStartSector,
unsigned int uiSectorListNum,
unsigned int *puiSectorList,
unsigned int *puiOutSectorNum,
int devfd);
#endif
#if MACRO_DESC("文件操作", 1)
/**********************************************************************
函数名: DDfs_Alloc_File_InodeIndex
函数说明: 为文件分配一个inode
入参: devfd
出参: puiInodeIndex
返回值: MACRO_DDFS_OK:分配成功
其余值:分配失败
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
unsigned int DDfs_Alloc_File_InodeIndex(
unsigned int *puiInodeIndex,
int devfd);
/**********************************************************************
函数名: DDfs_Alloc_File_SectorList
函数说明: 为文件分配所需要的全部扇区信息
入参: uiSectorNum
devfd
出参: puiSectorList
返回值: MACRO_DDFS_OK:分配成功
其余值:分配失败
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
unsigned int DDfs_Alloc_File_SectorList(
unsigned int uiSectorNum,
unsigned int *puiSectorList,
int devfd);
/**********************************************************************
函数名: DDfs_Get_InodeInfo_By_FileName
函数说明: 通过文件名获取其文件信息
入参: pcFileName
devfd
出参: puiInodeIndex
pstInodeInfo
返回值: MACRO_DDFS_OK:操作成功
其余值:操作失败
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
unsigned int DDfs_Get_InodeInfo_By_FileName(
char *pcFileName,
unsigned int *puiInodeIndex,
InodeInfo_s *pstInodeInfo,
int devfd);
/**********************************************************************
函数名: DDfs_Write_FileData_2_Sector
函数说明: 文件内容写入指定的扇区中
入参: uiFileSize
uiSectorNum
puiSectorList
filefd
devfd
出参: 无
返回值: MACRO_DDFS_OK:操作成功
其余值:操作失败
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
unsigned int DDfs_Write_FileData_2_Sector(
unsigned int uiFileSize,
unsigned int uiSectorNum,
unsigned int *puiSectorList,
int filefd,
int devfd);
/**********************************************************************
函数名: DDfs_Add_File_By_FileName
函数说明: 文件写入文件系统中
入参: pcFileName
filefd
devfd
出参: 无
返回值: 无
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Add_File_By_FileName(
char* pcFileName,
int filefd,
int devfd);
/**********************************************************************
函数名: DDfs_Delete_File_By_FileName
函数说明: 文件系统中删除指定的文件
入参: pcFileName
devfd
出参: 无
返回值: MACRO_DDFS_OK:操作成功
其余值:操作失败
变更历史:
1.操作: 新增
作者: 彭胜
时间: 20170605
**********************************************************************/
void DDfs_Delete_File_By_FileName(
char* pcFileName,
int devfd);
#endif
#endif
大家可以把这五个文件拷贝到本地,然后用source insight打开,可以先熟悉下(我是常用这个,形式不限。)这里的读写操作直接调用的linux接口,有现成的操作,完全可以抄袭,不,是借鉴一下,省时省力
因为我是在ubuntu上调试的,还写了个简单的makefile,
.PHONY : all mkddfs readddfs install_file clean
CC=gcc
RELEASE_DIR=../release/tools
all : mkddfs readddfs install_file
if [ ! -d $(RELEASE_DIR) ]; then mkdir -p $(RELEASE_DIR); fi
mv $^ $(RELEASE_DIR)
clean :
rm $(RELEASE_DIR)/*
mkddfs : mkddfs.c ddfs.c ddfs.h
$(CC) $^ -o $@
readddfs : readddfs.c ddfs.c ddfs.h
$(CC) $^ -o $@
install_file : install_file.c ddfs.c ddfs.h
$(CC) $^ -o $@
RELEASE_DIR:大家改下,改成自己的目录就行 。
执行很简单,执行make即可
这里release/tools下会有三个工具。
但现存这三个还用不了,我们没有磁盘,用你当前的系统磁盘直接操作,你肯定不乐意,太危险。没关系,在你安装bochs时,它自带了一个工具bximage,可搞一个虚拟磁盘,如下
这一步完成后,它会生成一个叫test.img,大小为10M的hd硬盘,这个可像真的磁盘一样进行操作。
到这一步,磁盘有了,工具也编译生成了,按照常规操作,我们来尝试下初始化看看。
查看 下初始化的情况,按照之前说明的,理论上它已经被占用了548扇区,inode未被占用
从这里面看,初始化符合我们的预期 ,但写文件会怎么样,直接用ddfs.h写一下看看,第一个文件理论上它占用inode 0, 扇区从548开始 ,占用37个扇区
这里它占用的Inode及扇区信息都显示出来 ,再检查下文件系统纪录的是否正确
不错,信息都 对上了,扇区使用总数548+37=585,inode使用一个,那它保存的扇区信息是否正确呢。
从这里面我们得知,它占用37个扇区,扇区从548开始 ,inode为0,文件名为ddfs.h,都正确,再检查下文件大小18570
完全正确。
有兴趣的同学可自己写点其它文件,更改文件内容后,再尝试写下看看。
这里的工具有我们将loader core user-app设计完成后,将通过 这个工具来写入。同时在我们的系统 内还会有相应的文件代码来读取。
等我们涉及到会一一讲解。
好了,今天就到这里面了,祝大家晚安,一想到明天 还要上班,兴趣顿无。
have a nice dream.