18日目 その2
まずは前回作成したext2イメージ(root_fs)をFDイメージに書き込み。Makefileを以下のとおり編集。
${TARGET}.bin: ${IPL} ${ASMHEAD} ${BOOTPACK} root_fs ← root_fs追加 dd if=/dev/zero of=$@ bs=512 count=2880 &> /dev/null dd if=${IPL} of=$@ conv=notrunc &> /dev/null dd if=${ASMHEAD} of=$@ conv=notrunc seek=1 &> /dev/null dd if=${BOOTPACK} of=$@ conv=notrunc seek=2 &> /dev/null dd if=root_fs of=$@ conv=notrunc seek=60 &> /dev/null ←この行を追加
書き込みセクタ60は適当に決定。iplやbootpackを書き込んだ時点で50セクタ弱なので少し余裕をみて60にしてみた。
次にディレクトリの内容を引数で渡されたsheetに表示する関数を作成。
ext2の構造に関してはUNIX USER誌2005年9月号のLinuxカーネル2.6解読室を参考にした。
ネット上の日本語ドキュメントはこのあたり。
http://opentechpress.jp/kernel/internal22/node100.shtml
http://www.atmarkit.co.jp/flinux/rensai/fs02/fs02b.html
日本語で詳細に解説してくれているサイトは見つけることができなかった。
関数の全体は文末に記載する。以下関数の簡単な説明。
(構造体やマクロの定義はLinuxのソースから拝借)
まずはファイルイメージのアドレスを取得
ptr = (char*)(ADR_DISKIMG + (512 * 60));
FDイメージの先頭(ADR_DISKIMG)から60セクタ目(512 * 60)。
スーパーブロックは常に先頭からEXT2_MIN_BLOCK_SIZE(=1024)の位置にある。
ptr_sb = (struct ext2_super_block*)(ptr + EXT2_MIN_BLOCK_SIZE);
グループディスクリプタはスーパーブロックを含むブロックの次ブロックにある。ブロックサイズによる違いを吸収するためにext2_super_block.s_first_data_blockを使う。
(ちなみにs_first_data_blockの値はブロックサイズが1024バイトの場合は1。2048,4096バイトの場合は0)
ptr_gp = (struct ext2_group_desc*)(ptr + blocksize * (ptr_sb->s_first_data_block + 1));
ルートディレクトリのiノードを取得。ルートディレクトリのiノード番号は2(=EXT2_ROOT_INO)で固定。
ptr_inode = (struct ext2_inode*)(ptr + blocksize * ptr_gp->bg_inode_table + ptr_sb->s_inode_size * (EXT2_ROOT_INO - 1));
ディレクトリエントリを格納しているブロックを取得。
dir_ent_start = ptr + blocksize * ptr_inode->i_block[0]; ptr_rdir = (struct ext2_dir_entry*)dir_ent_start;
あとはブロック内にあるエントリを順に読み出してsheetに表示していくだけ。
while(rdir_offset < blocksize){ // エントリ名取得 sprintf(s, "%s", ptr_rdir->name); // エントリ名表示 putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, s, 30); cursor_y = cons_newline(cursor_y, sheet); // 次のエントリへ rdir_offset += ptr_rdir->rec_len; ptr_rdir = (struct ext2_dir_entry*)(dir_ent_start + rdir_offset); }
みてのとおりルートディレクトリしか表示できないし、1ブロック以上エントリがある場合に対応できてないけど、それは追々…。
ひとまずこれでルートディレクトリの内容が表示できるようになった。
int cmd_dir(int cursor_y, struct SHEET *sheet) { char* ptr; int blocksize; int rdir_offset = 0; //ディレクトリエントリの先頭からのバイト数 struct ext2_super_block* ptr_sb; struct ext2_group_desc* ptr_gp; struct ext2_inode* ptr_inode; struct ext2_dir_entry* ptr_rdir; char* dir_ent_start; char s[256]; ptr = (char*)(ADR_DISKIMG + (512 * 60)); // スーパーブロックを取得 ptr_sb = (struct ext2_super_block*)(ptr + EXT2_MIN_BLOCK_SIZE); // ブロックサイズを取得 blocksize = EXT2_BLOCK_SIZE(ptr_sb); // ブロックグループディスクリプタを取得 ptr_gp = (struct ext2_group_desc*)(ptr + blocksize * (ptr_sb->s_first_data_block + 1)); // ルートディレクトリノードを取得 ptr_inode = (struct ext2_inode*)(ptr + blocksize * ptr_gp->bg_inode_table + ptr_sb->s_inode_size * (EXT2_ROOT_INO - 1)); dir_ent_start = ptr + blocksize * ptr_inode->i_block[0]; ptr_rdir = (struct ext2_dir_entry*)dir_ent_start; while(rdir_offset < blocksize){ // エントリ名取得 sprintf(s, "%s", ptr_rdir->name); // エントリ名表示 putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, s, 30); cursor_y = cons_newline(cursor_y, sheet); // 次のエントリへ rdir_offset += ptr_rdir->rec_len; ptr_rdir = (struct ext2_dir_entry*)(dir_ent_start + rdir_offset); } return cursor_y; }