第二个任务是建立根目录。由make_root_inode()函数完成。在make_root_inode()函数运行之前如果命令中加入了-c选项,则会运行check_blocks()函数检查坏块,并把坏块对应的逻辑块位图块中对应的位置1。因为我们的系统是在bochs中运行,硬盘对应的是一个img文件,不是实体硬盘,所以不会有坏块。也没有必要加-c选项。
根目录对应的数据是:
#define ROOT_INO_STRING "\001\000"
static char root_block[BLOCK_SIZE] =
ROOT_INO_STRING ".\0\0\0\0\0\0\0\0\0\0\0\0\0"
ROOT_INO_STRING "..\0\0\0\0\0\0\0\0\0\0\0\0"
根目录文件有两个目录项,每个目录项16字节,前两个字节既前面的紫色的表示目录对应的i节点号既1,后14个字节是文件名,这里是"."既当前目录,".."既当前目录的父目录。
#define ROOT_INO 1
#define mark_inode(x) (setbit(inode_map,(x)))
#define unmark_inode(x) (clrbit(inode_map,(x)))
ROOT_INO表示的是根目录对应的节点号既1。
mark_inode(ROOT_INO);会把i节点位图块中的第1位置为1。第0位在setup_tables()函数中开始的:
memset(inode_map,0xff,sizeof(inode_map));
就设置为1了。后来的
for (i = ROOT_INO ; i<INODES ; i++)
unmark_inode(i);
因为ROOT_INO为1,所以第0位没有被重置为0。
void make_root_inode(void) {}
write_block()函数把buffer指向的字符串的内容写到块号为blk的块中。
void write_block(int blk, char * buffer)
{
if (blk*BLOCK_SIZE != lseek(DEV, blk*BLOCK_SIZE, SEEK_SET))
die("seek failed in write_block");
if (BLOCK_SIZE != write(DEV, buffer, BLOCK_SIZE))
die("write failed in write_block");
}
get_free_block()函数分析:get_free_block()函数在数据区从前往后寻找第一个未被使用的块。
make_root_inode()函数第一次调用get_free_block()函数时used_good_blocks等于0。所以
if (used_good_blocks)
blk = good_blocks_table[used_good_blocks-1]+1;
else
blk = FIRSTZONE;
执行的是else语句既blk = FIRSTZONE;。
while (blk < ZONES && zone_in_use(blk))
blk++;
的作用是检测块号为blk的块是否已经被使用既是否被置位。
good_blocks_table[0]等于FIRSTZONE既第一个数据块的块号。以后都是make_bad_inode()函数中调用的。
int get_free_block(void)
{
int blk;
if (used_good_blocks+1 >= MAX_GOOD_BLOCKS)
die("too many bad blocks");
if (used_good_blocks)
blk = good_blocks_table[used_good_blocks-1]+1;
else
blk = FIRSTZONE;
while (blk < ZONES && zone_in_use(blk))
blk++;
if (blk >= ZONES)
die("not enough good blocks");
good_blocks_table[used_good_blocks] = blk;
used_good_blocks++;
return blk;
}