リンクとファイル

ファイルやディレクトリを扱う上で、Unixのファイルとディレクトリについて理解することが大切だということで、よくわかっていない部分もあるけど、とりあえずメモ。


Unix系のOSは、ファイルを実際のデータ領域とiノードにわけて管理しているらしい。iノードとは、パーミッションや作成日、ファイルの内容がどこにあるかを示すポインタなどの情報を格納する領域。


ディレクトリは特別なファイルで、ファイル名とそれに対応するiノード番号のテーブルになっている。そして、自分自身を表す.(ドット)と、親ディレクトリを表す、..(ドットドット)の二つの特別なエントリが必ず存在する。多分こういう感じかと。

. 345
.. 4563
hoge.txt 10032
hoge.pl 2560

ディレクトリにファイルを作る時、システムは、そのファイルの名前と、それが指し示す新しいiノード番号を持つエントリを追加する。


iノードはリンク数という数を保持している。これが1なら、どこかのディレクトリにiノードが入っているということ。逆に0ならば、iノードはどのディレクトリにも入っていないということ。
ディレクトリに対するリンク数は、親ディレクトリと自分自身の、最低でも二つ。


普通のファイルのiノードが複数のディレクトリに表れることがあるか?Perlでは、link関数を使うと可能。link関数は、指定のファイルに別の名前を与える。

link "chicken", "egg" or warn ....

chickenとeggはiノードを指す。つまり同じデータ領域を参照する。二つ分のデーター領域を使うわけではない。chickenを編集すれば、eggの内容も変わる。また、chickenを削除しても、iノードのリンク数が一つ減るだけで、それが指し示すデータは削除されない。そのデータはeggから参照できる。逆も同じ。


一つのディレクトリが複数の親ディレクトリを持ってしまうと困るので、ディレクトリに対してlink関数を使うことはできない。また、あるマウントされたボリュームから、別のボリュームへとリンクすることもできない。つまり、CドライブにあるchickenとDドライブにあるeggが同じデータ領域を参照するということはない。


それらを行ないたい場合は、シンボリックリンクというものを使う。Windowsでいうショートカットのようなもの。Perlではsymlink関数を使って、シンボリックリンクを作成する。ちなみにlink関数で作成されるリンクを、ハードリンクともいう。

symlink "apple", "ringo" or warn ....

シンボリックリンクを作成しても、iノードのリンク数は増えない。シンボリックリンクはシステムに対して、「niwatoriを探しているなら、chickenを見つけなさい」と指示するだけのもの。chickenとniwatoriが同じiノードを指しているわけではない。また、存在しないファイル名を指すこともできる。


ハードリンクはデータが失われるのを防いでくれるが、シンボリックリンクは防いでくれない。chickenが削除されても、eggがあればデータは消えない。だが、appleが削除されれば、ringoからそのデータ領域を参照することはできない。


unlink関数を使うと、どちらのリンクも削除できる。unlink関数は、指定されたファイル名に対するディレクトリのエントリを取り除き、iノードのリンク数を一つ減らす。


ディレクトリに表示されているhoge.txtやhoge.plというものは、データそのものではなく、iノードを参照するための名前、データの場所はiノードが知っている。名前は複数持つことができ、ハードリンクという本物の名前と、シンボリックリンクという仮の名前がある。ファイルを削除するということは、データを消すと言うことではなく、その名前でデータを参照できなくするということ。本物の名前がある限り、それが指し示すデータ領域が、勝手に書きかえられるということはない。ということでいいだろうか。