UNIX 6th code reading - unix/fio.c

はじめに

今回はunix/fio.cを見ていきます。

u.u_ofile[ ]やfile[ ]の割り当てや、権限チェックなどの関数が揃っています。

getf( )

getf( )(6619行目)は、ファイルディスクリプタから、該当のfile構造体を取得してそれをreturnします。

ファイルディスクリプタはu.u_ofile[ ]のindexで、Cのfp = open( 'hoge', 'r' ) ;などと書いた時にfpに格納されるのがそれです。

以前載せた絵の再掲です。u.u_ofile[ ]の各要素はfile[ ]の各要素を指しているので、ファイルディスクリプタ(=u.u_ofile[ ]のindex)から対応したfile構造体を取得できるのです。

closef( )

closef( )(6643行目)はファイルを閉じたり削除する時に呼ばれ、file構造体の参照カウンタをデクリメントします。

参照カウンタが0になるとき、closei( )を呼んでそのfile構造体が指しているinode構造体の参照カウンタをデクリメントします。

closei( )

closei( )(6672行目)は、iput( )を呼んで、inode構造体の参照カウンタをデクリメントします。

また、inodeが特殊型(IFCHR, IFBLK)である場合、デバイスのclose処理も行います。

openi( )

openi( )(6700行目)は、inodeが特殊型(IFCHR, IFBLK)である場合、デバイスのclose処理を行います。

通常のinodeの場合は何も行いません。

access( )

access( )(6746行目)は、ファイルのパーミッションをチェックします。

引数で与えられたmode(write, read, exec)とinodeのi_modeを比較し、権限があるかどうかを確認します。i_modeの下位9bitsがファイルのパーミッションを表しており、3bitsずつ{owner, group, other}に割り当てられています。(644とか755とか、例のアレです)

writeの場合は、ファイルシステム自体がリードオンリーでない必要が有ります。また、テキストセグメントにも書き込むことができません。

super user(u.u_uidが0)の場合は必ず権限があります。ただしexecで開こうとしている場合、ファイルのexecパーミッションがowner, group, otherの少なくともどれか1つに対して与えられている必要が有ります。

権限があれば0を、なければ1を返します。また権限がない場合はu.u_errorにエラーコードが格納されます。

owner( )

owner( )(6791行目)は、inodeがowner(カレントユーザのもの)かどうかをチェックします。

namei( )でinodeを取得し、取得したinodeのi_uidとu.u_uidを比較し判断する。namei( )の引数に&uchar( )を渡すので、予めu.u_dirpにパス名の先頭アドレスを与えておく必要があります。

また、カレントユーザがsuper userだった場合もownerであると判断されます。

ownerであればinode pointerが、そうでなければNULLがreturnされます。

suser( )

suser( )(6811行目)は、カレントユーザがsuper userかどうかをチェックします。

super userはu.u_uidが0なので、それを見て判断します。

super userならば1を、そうでなければ0を返し、かつ、u.u_errorにEPERMをセットします。

ufalloc( )

ufalloc( )(6824行目)は、u.u_ofile[ ]のエントリを新たに割り当てます。

u.u_file[ ]を先頭から順に辿り空のエントリ探します。見つかればそのエントリのindexをuserのr0に格納し、さらにそのindexをreturnします。

もし空きエントリがなければu.u_errorにEMFILEをセットし、-1をreturnします。

falloc( )

falloc( )(6847行目)は、u.u_file[ ]のエントリとfile[ ]のエントリを割り当てます。

最初にualloc( )を呼んでu.u_ofile[ ]のエントリを取得し、次にfile[ ]を先頭から順に辿り空のエントリ(file構造体の参照カウンタが0)を探します。

空のエントリが見つかれば、uallocで取得したu.u_ofile[ ]のエントリから該当のfile[ ]エントリを指すようにし、かつ、file[ ]の該当エントリの参照カウンタをインクリメントし、offsetを0に初期化し、該当file[ ]エントリのポインタをreturnします。

ualloc( )でu.u_ofile[ ]に空きエントリが見つからなければNULLをreturnします。

file[ ]に空きエントリが見つからなければ"no file" messageを表示し、u.u_errorにENFILE(空きfile構造体がない)をセットし、NULLをreturnします。

ualloc( )とfalloc( )をまとめて図示するとこんな感じです。


コードメモ

getf( )
  • arguments
    • f : file descriptor(u.u_ofile[ ]のindex)
  • 6624-6625 : 引数のfile descriptorがu.u_ofile[ ]の範囲外だったらエラー
  • 6626-6628 : u.u_ofile[ ]の該当要素をfpに格納し、それをreturn。該当要素がNULLならばエラー
closef( )
  • arguments
    • fp : file構造体(file[ ]の1エントリ)のポインタ
  • 6649-6654 : fileがPIPEだったときの処理。詳細は後々確認する予定
  • 6655-6656 : 参照カウンタが0になるならばclosei( )を呼んでinodeの参照カウンタをデクリメントする
  • 6657 : 参照カウンタを0にする
closei( )
  • arguments
    • ip : inode pointer
    • rw : read, writeを示すmode
  • 6679-6690 : inodeの参照カウンタが0になり、かつ、inodeがIFMT型ならば、デバイスのclose処理を実行する
  • 6691 : iput( )を呼んでinodeの参照カウンタをデクリメントする
openi( )
  • arguments
    • ip : inode pointer
    • rw : read, writeを示すmode
  • 6709-6724 : inodeがIFMT型ならば、デバイスのopen処理を実行する
access( )
  • arguments
    • aip : inode pointer
    • mode : write, read, execを示すmode
  • 6753-6758 : writeの権限があるかチェックする場合。getfs( )を使ってfilsys(superblock)を取得し、read onlyでないかチェックする。read onlyの場合は書き込むことができないのでエラー。また、inodeがテキストセグメント(プログラム本体)を表すかをチェックする。テキストセグメントの場合は書き込めない(テキストセグメントはread only)のでエラー
  • 6763-6768 : カレントユーザがsuper user(u.u_uidが0)の場合。基本的に必ずアクセス権限を持つが、execで開こうとしている場合はinodeにはowner, group, otherの少なくともどれか1つにexecパーミッションが与えられている必要がある。もし与えられていなければEACCESS(アクセス権限ありません)エラー
  • 6769-6773 : アクセス権限チェックを行うinodeに対し、カレントユーザがowner, group, otherのどれかなのかを鑑み、modeを調整する。i_modeの下位9bitsがパーミッションを表し、3bitsずつ{owner, group, other}のパーミッションを示している。引数のmodeは0x00とownerの位置の値が格納されているので、group, otherの場合はmodeを右シフトする
  • 6774-6775 : inodeのi_modeと引数のmodeとで&を取り、0でないならばアクセス権限がある。アクセス権限がある場合0を返す
  • 6777-6779 : EACCESS(アクセス権限がない)エラー。1を返す
owner( )
  • 6796-6797 : namei( )を呼んでinode pointerを取得する。事前にu.u_pdirにファイルパス名を表す文字列の先頭アドレスを格納しておく必要がある。namei( )でinode pointerを取得できなければNULLをreturn
  • 6798-6799 : u.u_uidとinode pointerのi_uidが等しければ、カレントユーザはそのinodeのownerである。その場合はinode pointerをreturnする
  • 6800-6801 : suser( )を呼び、カレントユーザがsuper userならばinode pointerをreturnする
  • 6802-6803 : ownerではないのでipを解放し、NULLをreturnする
suser( )
  • 6814-6815 : u.u_uidが0ならばsuper userである。その場合は1をreturnする
  • 6816-6817 : super userではないので、u.u_errorにEPERMをセットし0をreturnする
ufalloc( )
  • 6828-6832 : u.u_ofile[ ]を先頭から順に辿り、空のエントリを探す。見つかったらuserのr0にそのindexを格納した後に、indexをreturnする
  • 6833-6834 : u.u_ofile[ ]に空きエントリがなかったのでEMFILE(空きu.u_ofile[ ]エントリがない)エラーで-1をreturn
falloc( )
  • 6852-6853 : ufalloc( )を呼び、u.u_ofile[ ]の空きエントリを取得する。取得に失敗したらNULLをretun. 取得に成功した場合はu.u_ofile[ ]のindexがiにセットされる
  • 6854-6861 : file[ ]を先頭から順に辿り、空きエントリ(file構造体の参照カウンタが0)を探す。見つかったら、先ほど取得したu.u_ofile[ ]のエントリに、見つかったfile[ ]のエントリであるfile構造体のポインタをセット。file構造体の参照カウンタをインクリメントし、ファイル中のオフセットを0にし、file構造体のポインタをreturnする
  • 6862-6864 : file[ ]中に空きエントリが見つからなかったので、"no file" messageを出力し、u.u_errorにENFILE(file[ ]に空きエントリが見つからなかった)エラーをセットし、NULLをreturn.

終わりに

u.u_ofile[ ]とfile[ ]の間を関連付ける処理の内容が理解できました。

次回はunix/rdwri.cを見ていきます。