c 写 ext2 的格式化工具
发表于: 2018-05-09 11:56:00 | 已被阅读: 19 | 分类于: 文件系统
在写自己的格式化工具之前,先设定一下预设格式。
预设格式
以一个块组为例。
类型 | 超级块 | 块组描述符 | 块位图 | inode位图 | inode表 | 数据块 |
---|---|---|---|---|---|---|
占空间 | 1KB | 1块 | 1块 | 1块 | (inodeSize * num)/blockSize块 | 块组余下全部 |
- 根据 ext2 被系统保留的部分分析 小节的分析,必须保留根目录,否则系统无法挂载 disk。因此初始化时,必须占用 1 个 inode 表,而且必须占用第 2 个inode。这里把第 1 个inode,也保留,为了连续。则inode 表需要保留 2 个。根目录对应 1 个数据块。
根据要保留的 inode,需要把 inode 位图设置一下。
结合上表,至少需要保留 n 个数据块,当 inode 表的大小和数量均为 128,块大小为 1024 时,n = 4 + 128 * 128 /1024 + 1 = 21。(视超级块也占 1 块,最后一个1 是根目录需要的数据块)
根据要保留的数据块,需要把块位图设置一下。
c 程序参数
- 超级块信息可以如下这么填写。
以块大小 1KB,块数量 1024,inode size = 128,inode num =128 为例。
uint16 freeBlocks = 1024-21;
uint16 freeInodes = 128 -2;
sSuperBlock sbtmp;
sbtmp.inodes = 128;
sbtmp.blocks = 1024;
sbtmp.reservedBlocks = 21; //
sbtmp.freeBlocks = freeBlocks; //
sbtmp.freeInodes = freeInodes; //
sbtmp.firstBlock = 1;
sbtmp.blockSize = 0; // 1024<<0 = 1024
sbtmp.log = 0;
sbtmp.blocksPerGroup = 8192; // 块大小 * 8 bits
sbtmp.framsPerGroup = 8192;
sbtmp.inodesPerGroup = 128;
sbtmp.lastMountTime = 0;
sbtmp.lastWriteTime = 0;
sbtmp.mountNum = 0;
sbtmp.maxMountNum = 0x00ef; // 随机写的
sbtmp.magic = 0xef53; // 随机写的
sbtmp.fsState = 1;
sbtmp.errBehav = 1;
sbtmp.minorRev = 0;
sbtmp.lastCheck = 0x4764cc3b; // 随机写的
sbtmp.checkIntvl = 0x00ed4e00; // 随机写的
sbtmp.osType = 0;
sbtmp.majorRev = 1;
sbtmp.reserverdBlocksUid = 0;
sbtmp.reserverdBlocksGid = 0;
sbtmp.firstInode = 1;
sbtmp.inodeSize = 128;
sbtmp.blockGroupIndex = 0;
- 块组描述符
sGroupDescriptor sgtmp;
sgtmp.blockBmLoc = 3; // 0启动块,1超级块,2快组
sgtmp.inodeBmLoc = 4;
sgtmp.inodeTable = 5;
sgtmp.freeBlocks = freeBlocks; //
sgtmp.freeInodes = freeInodes; //
sgtmp.directories = 1; // 至少有个根目录
- 块位图:因为保留了 21 个块,所以块位图中应该有 21 个位为 1。(0xffff1f000...)
inode 表:这里写入必须写入的根目录
sitmp.st_mode = 0x41ed;
sitmp.user = 0x0;
sitmp.size = 1024;
sitmp.atime = 0x4764cc3b; // 随机写的
sitmp.ctime = 0x4764cc3b; // 随机写的
sitmp.mtime = 0x4764cc3b; // 随机写的
sitmp.dtime = 0x4764cc3b; // 随机写的
sitmp.group = 0;
sitmp.links = 2;
sitmp.ocupiedBlocks = 2;
sitmp.flags = 0;
sitmp.osInfo = 0;
sitmp.blocks[0] = 21; // 放根目录信息,前 20 个保留放各种表和位图了
for(i=1; i<15; i++)
sitmp.blocks[i] = 0;
inode 位图:因为保留了 2 个 inode,所以 inode 位图应该有 2 个位为 1。(0x03000...)
根目录的数据块,可以这样设置:
sDataBlock sdtmp;
sdtmp.inodeIndex = 2;
sdtmp.recordLen = 12;
sdtmp.fileNameLen = 1;
sdtmp.fileType = 2;
strcpy(sdtmp.fileName, ".");
// 写入 (sitmp.blocks[0])*1024
sdtmp.fileNameLen = 2;
sdtmp.recordLen = 1024-12; // 这个必须把剩余的空间填充完,否则挂载后,linux无法写入文件
memset(sdtmp.fileName, 0, sizeof(sdtmp.fileName));
strcpy(sdtmp.fileName, "..");
// 写入 (sitmp.blocks[0])*1024+12
C 程序
- 在贴格式化函数之前,先在 MExt2 模块添加几个函数,如下:
方便在写数据块和 inode 表时,对对应的位图置 1。
// 将 addr 开始的第 n bit 置 1
int sSetAddrBitN(off_t addr, uint32 n)
{
uint8 tmp = 0;
uint8 byteTmp = 0;
addr = addr + (uint32)(n/8);
byteTmp = n%8;
if(byteTmp>0)
tmp = 0x01 << byteTmp;
else
tmp = 0x01;
byteTmp = MFileReadByte(addr);
byteTmp |= tmp;
MFileWriteByte(addr, byteTmp);
return 0;
}
// 将 addr 开始的第 n bit 置 0
int sResetAddrBitN(off_t addr, uint32 n)
{
uint8 tmp = 0;
uint8 byteTmp = 0;
addr = addr + (uint32)(n/8);
byteTmp = n%8;
if(byteTmp>0)
tmp = 0x01 << byteTmp;
else
tmp = 0x01;
byteTmp = MFileReadByte(addr);
byteTmp &= ~tmp;
MFileWriteByte(addr, byteTmp);
return 0;
}
- 因此几个加载结构体的函数后添加上述函数,添加后的函数更新如下:
int sLoadInode(off_t addr, sInode* pInode, off_t bmLoc) // 加载 inode 信息,就是填表. 这里的扇区大小要获取一下
{
int i = 0, j=0;
MFileWriteUint16InByte(addr, pInode->st_mode);
MFileWriteUint16InByte(addr+2, pInode->user);
MFileWriteUint32InByte(addr+4, pInode->size);
MFileWriteUint32InByte(addr+8, pInode->atime);
MFileWriteUint32InByte(addr+12, pInode->ctime);
MFileWriteUint32InByte(addr+16, pInode->mtime);
MFileWriteUint32InByte(addr+20, pInode->dtime);
MFileWriteUint16InByte(addr+24, pInode->group);
MFileWriteUint16InByte(addr+26, pInode->links);
MFileWriteUint32InByte(addr+28, pInode->ocupiedBlocks);
MFileWriteUint32InByte(addr+32, pInode->flags);
MFileWriteUint32InByte(addr+36, pInode->osInfo);
for(i=0; i<15; i++){
MFileWriteUint32InByte(addr+40+4*i, pInode->blocks[i]);
}
for(j=0; j<1024-i; j++){
MFileWriteByte(addr+40+4*i+j, 0);
}
// 将对应的位图置 1
sSetAddrBitN(s_grpDescrpt.inodeBmLoc, bmLoc);
return MEXT2_OK;
}
int sLoadDataBlock(off_t addr, sDataBlock* pDataBlock, off_t bmLoc) // 加载 数据块 信息,就是填表.
{
MFileWriteUint32InByte(addr, pDataBlock->inodeIndex);
MFileWriteUint16InByte(addr+4, pDataBlock->recordLen);
MFileWriteByte(addr+6, pDataBlock->fileNameLen);
MFileWriteByte(addr+7, pDataBlock->fileType);
MFileWriteStringInByte(addr+8, pDataBlock->fileName);
//将对应的位图置 1
sSetAddrBitN(s_grpDescrpt.blockBmLoc, bmLoc);
return MEXT2_OK;
}
- 格式化函数如下,其实就是加载刚才填写的数据。
int FormatExt2()
{
// 先全部清零
uint32 i = 0;
for(i=1024; i<1024*1024; i++)
MFileWriteByte(i, 0x00);
// 先写特定程序,快,方便测试
uint16 freeBlocks = 1023-21; // 这个的空余数一定要与位图一致
uint16 freeInodes = 128 -2;
// 超级块
sSuperBlock sbtmp;
sbtmp.inodes = 128;
sbtmp.blocks = 1024;
sbtmp.reservedBlocks = 21; //
sbtmp.freeBlocks = freeBlocks; //
sbtmp.freeInodes = freeInodes; //
sbtmp.firstBlock = 1;
sbtmp.blockSize = 0;
sbtmp.log = 0;
sbtmp.blocksPerGroup = 8192;
sbtmp.framsPerGroup = 8192;
sbtmp.inodesPerGroup = 128;
sbtmp.lastMountTime = 0;
sbtmp.lastWriteTime = 0;
sbtmp.mountNum = 0;
sbtmp.maxMountNum = 0x00ef;
sbtmp.magic = 0xef53;
sbtmp.fsState = 1;
sbtmp.errBehav = 1;
sbtmp.minorRev = 0;
sbtmp.lastCheck = 0x4764cc3b;
sbtmp.checkIntvl = 0x00ed4e00;
sbtmp.osType = 0;
sbtmp.majorRev = 1;
sbtmp.reserverdBlocksUid = 0;
sbtmp.reserverdBlocksGid = 0;
sbtmp.firstInode = 1;
sbtmp.inodeSize = 128;
sbtmp.blockGroupIndex = 0;
uint8* buf1[] = {0x30, 0,0,0,2,0,0,0,1,0,0,0}; // 胡乱写的
strcpy(sbtmp.compatibleFeatures, buf1);
uint8* buf2[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}; // 胡乱写的
strcpy(sbtmp.uuid, buf2);
memset(sbtmp.volmName, 0 ,sizeof(sbtmp.volmName));
sLoadSuperBlock(0x400, &sbtmp);
sGetSuperBlockInfo(&s_sprBlk); // 更新超级块
// 快组描述符
sGroupDescriptor sgtmp;
sgtmp.blockBmLoc = 3; // 0启动块,1超级块,2快组
sgtmp.inodeBmLoc = 4;
sgtmp.inodeTable = 5;
sgtmp.freeBlocks = freeBlocks; //
sgtmp.freeInodes = freeInodes; //
sgtmp.directories = 1; // 根目录
sLoadGroupDescriptor(0x800, &sgtmp);
sGetGroupDescriptorInfo(&s_grpDescrpt); // 更新块组描述符信息
// 快位图
MFileWriteByte(sgtmp.blockBmLoc*1024, 0xff);
MFileWriteByte(sgtmp.blockBmLoc*1024+1, 0xff); // 各种表,位图
MFileWriteByte(sgtmp.blockBmLoc*1024+2, 0x1f);
MFileWriteByte(sgtmp.blockBmLoc*1024+3, 0x00);
MFileWriteByte(sgtmp.blockBmLoc*1024+4, 0x00); // 根目录的
for(i=0; i<1024/8-5; i++)
MFileWriteByte(sgtmp.blockBmLoc*1024+5+i, 0x00);
for(i=1024/8-5;i<1024-5;i++)
MFileWriteByte(sgtmp.blockBmLoc*1024+5+i, 0xff);
// inode 位图
for(i=0; i<128/8; i++)
MFileWriteByte(sgtmp.inodeBmLoc*1024+i, 0x00);
for(i=128/8; i<1024; i++)
MFileWriteByte(sgtmp.inodeBmLoc*1024+i, 0xff);
MFileWriteByte(sgtmp.inodeBmLoc*1024, 0x03);
MFileWriteByte(sgtmp.inodeBmLoc*1024+1, 0x00); // 共用 3 个
// 写入根目录信息 ----------------- *******固定在 第二 inode******
// 先写 inode 表
sInode sitmp;
sitmp.st_mode = 0x41ed;
sitmp.user = 0x0;
sitmp.size = 1024;
sitmp.atime = 0x4764cc3b;
sitmp.ctime = 0x4764cc3b;
sitmp.mtime = 0x4764cc3b;
sitmp.dtime = 0x4764cc3b;
sitmp.group = 0;
sitmp.links = 3;
sitmp.ocupiedBlocks = 2;
sitmp.flags = 0;
sitmp.osInfo = 0;
sitmp.blocks[0] = 21;
for(i=1; i<15; i++)
sitmp.blocks[i] = 0;
sLoadInode(1024*sgtmp.inodeTable+128, &sitmp, 2); //*******固定在 第二 inode******
// 写 datablock
sDataBlock sdtmp;
sdtmp.inodeIndex = 2;
sdtmp.recordLen = 12;
sdtmp.fileNameLen = 1;
sdtmp.fileType = 2;
strcpy(sdtmp.fileName, ".");
sLoadDataBlock((sitmp.blocks[0])*1024, &sdtmp, sitmp.blocks[0]);
sdtmp.fileNameLen = 2;
sdtmp.recordLen = 1024-12; // 这个必须把剩余的空间填充完,否则挂载后,linux无法写入文件
memset(sdtmp.fileName, 0, sizeof(sdtmp.fileName));
strcpy(sdtmp.fileName, "..");
sLoadDataBlock((sitmp.blocks[0])*1024+12, &sdtmp, sitmp.blocks[0]);
return 0;
}
- 编译后,执行,得到咱们自己格式化后的 disk。先用 dumpe2fs 命令查看一下:
$ dumpe2fs disk
dumpe2fs 1.42.13 (17-May-2015)
Filesystem volume name: <none>
Last mounted on: <not available>
Filesystem UUID: 01000000-0000-0000-0000-000000000000
Filesystem magic number: 0xEF53
Filesystem revision #: 1 (dynamic)
Filesystem features: resize_inode dir_index
Default mount options: (none)
Filesystem state: clean
Errors behavior: Continue
Filesystem OS type: Linux
Inode count: 128
Block count: 1024
Reserved block count: 21
Free blocks: 1003
Free inodes: 126
First block: 1
Block size: 1024
Fragment size: 1024
Blocks per group: 8192
Fragments per group: 8192
Inodes per group: 128
Inode blocks per group: 16
Last mount time: n/a
Last write time: Thu Jan 1 08:00:00 1970
Mount count: 0
Maximum mount count: 239
Last checked: Sun Dec 16 14:56:59 2007
Check interval: 15552000 (6 months)
Next check after: Fri Jun 13 14:56:59 2008
Reserved blocks uid: 0 (user root)
Reserved blocks gid: 0 (group root)
First inode: 1
Inode size: 128
Default directory hash: legacy
Group 0: (Blocks 1-1023)
Primary superblock at 1, Group descriptors at 2-2
Block bitmap at 3 (+2), Inode bitmap at 4 (+3)
Inode table at 5-20 (+4)
1003 free blocks, 126 free inodes, 1 directories
Free blocks: 22-1024
Free inodes: 3-128
- 可以看出,我们去除了被系统保留的部分,并且一切都与预期一致。再试试能否 mount。
$ sudo mount -o loop disk /mnt
$ cd /mnt
$ sudo mkdir testDir
$ cd testDir/
$ sudo vim xrk # 写入 www.xrkxzz.cn
$ cat xrk
www.xrkxzz.cn
- 成功了。我们挂载 disk 后,在里面新建了目录,写入了文件。