Linux上のファイルのOpenとClose処理について考えてみた。

プログラムを実行すると、そのプログラムが扱うファイル情報のための領域が確保されます。この領域はリスト形式で複数個、用意されます。このリストを利用者ファイル記述子表と呼んでいます。C言語でfopen関数を呼ぶとファイルポインタが返りますが、このファイルポインタは利用者ファイル記述子表のどの場所かを示すポインタとなります。またopenシステムコールを呼んだ場合はファイル記述子(ファイルディスクリプターとも呼ぶ)が返りますが、ファイル記述子はリストの何番目かを示す配列の番号です。

※上の絵のfdはファイルディスクリプターの略、fpはファイルポインタの略です。

標準入力、標準出力、標準エラー出力はプログラム実行時に自動的に割り当てられるファイル情報の領域で、ファイル記述子はそれぞれ、0、1、2 と決まっています。通常、標準入力はキーボード、標準出力、標準エラー出力は端末の画面となります。

ここで新規にファイルを作成する場合を考えてみます。ファイル記述子は3以降が使われます。openシステムコールを新規作成で呼ぶと以下の領域が確保されます。

  • プログラム内のファイル記述子表に新規ファイル分を追加
  • ファイルシステムのiノードリストに新規ファイル分を追加
  • ファイルアクセスのための入出力用バッファを用意

絵に書くと以下のような感じです(iノードについては前回前々回を参照ください)。

ファイルのOPENにより利用者ファイル記述子表とiノードリストの紐付けを行っています。これによりファイル記述子からファイルのアクセス権の設定やファイルの読み出し/書き込みが行えることになります。またファイルのCLOSEを行うことにより利用者ファイル記述子表とiノードリストの紐付きを解除しています。

ちなみに、別々のプログラムが同一ファイルをOPENして読み書きを行う場合(共通のログファイルへの書き出しなど)は以下のような絵になると思います。

同一ファイルへのアクセスでも利用者ファイル記述子表のファイル記述子は(プログラム内で保持するため)別々のものとなります(たまたま同じになるときももちろんあります)。

Linuxのハードリンクとシンボリックリンクの違いについて

Linuxではiノードという仕組みでファイルの管理をしています(iノードについては前回の記事を見てください)。ルートディレクトリ配下に「aaa」ディレクトリがあり「aaa」ディレクトリの直下に「ccc」ファイルがあったとします。

この場合、Linuxのファイルシステムではiノードを使って以下のように管理しています。

ルートディレクトリのiノード番号は「2」と決められていて、ディレクトリファイルと一般ファイルはデータブロックに置かれています。ディレクトリファイルを簡単に言うと「iノード番号とファイル名のペアを1つのエントリとして登録しておく入れ物」です。ルートディレクトリ(iノード番号「2」)からポインタをたどっていくと「ccc」ファイルまでたどり着けます。

上の図を見てわかるようにLinuxではファイル名をディレクトリファイルで管理しています。これはアプリケーションがログを書き込んでいる最中にログファイル名を変更したり、ログファイルを別の場所に移動しても影響を与えないということです(アプリケーションから見ると、ログファイルをiノード番号で認識している)。システム開発をしているとログローテーションの機能を組み込みますが、Linuxではアプリケーションがログを書き込んでいる最中にログローテンションをしても影響がないということです。

ディレクトリファイルの保護モードも一般ファイルと異なるので書いておきます。Linuxでは「ls -l」コマンドでファイルの保護モードを見ることができます。一般ファイルだと、r:読み出し可、w:書き込み可、x:実行可、となりますがディレクトリファイルだと以下のようになります。

  • r: 許可されていればlsコマンドで表示することができる
  • w: 許可されていれば新しくファイルを作成したり既存のファイルを削除できる
  • x: 許可されていればcdコマンドでそのディレクトリに移動できる

[広告]

ここで以下のように「bbb」ディレクトリ直下に「ddd」という名前で「ccc」ファイルのリンクを作成した場合を考えてみます( ddd と ccc は名前は違うけれども実体は同じファイルということ)。

まずはハードリンクで作成した場合です。Linuxのコマンドだと「ln ccc ddd」です。

ハードリンクはディレクトリファイルにiノード番号「300」、ファイル名「ddd」のエントリを追加することでリンクを作っています。次にシンボリックリンクで作成した場合です。Linuxのコマンドだと「ln -s ccc ddd」です。

シンボリックリンクでは新たにiノード番号「400」を使用するとともに、ディレクトリファイルにiノード番号「400」、ファイル名「ddd」のエントリを追加することでリンクを作っています。

[広告]

ハードリンクではiノードを使用せず、シンボリックリンクではiノードを使用するところを実際に確かめてみました。まずはハードリンクの場合です。

IUsedが194890ですが、リンクを作成した後も194890のままです。次にシンボリックリンクの場合です。

IUsedが194887だったのが194888に1つ増えています。逆にIFreeが1681081から1681080に1つ減っています。シンボリックリンクではiノードを消費しているようです。また、ハードリンクだとcccとdddのファイルサイズ、タイムスタンプはいっしょですが、シンボリックリンクだと異なってますね。