c 写 ext2 的格式化工具

在写自己的格式化工具之前,先设定一下预设格式。

预设格式


以一个块组为例。
类型 超级块 块组描述符 块位图 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 后,在里面新建了目录,写入了文件。
阅读更多:   文件系统
添加新评论

icon_redface.gificon_idea.gificon_cool.gif2016kuk.gificon_mrgreen.gif2016shuai.gif2016tp.gif2016db.gif2016ch.gificon_razz.gif2016zj.gificon_sad.gificon_cry.gif2016zhh.gificon_question.gif2016jk.gif2016bs.gificon_lol.gif2016qiao.gificon_surprised.gif2016fendou.gif2016ll.gif