私はUnixベースのオペレーティングシステムで空のディレクトリのリンク数が1ではなく2である理由について多くの説明をしました。みんな「。」だからと言いましたね。それぞれ自身を指すディレクトリ。 「.」という概念が相対パスを指定するのに役立つ理由は理解していますが、それをファイルシステムレベルで実装すると何が得られますか?パスを取るシェルやシステムコールにパスを解釈する方法を教えてください。
「..」は実際のリンクであり、私にとってより意味があります。ファイルシステムは、親ディレクトリに移動するために親ディレクトリへのポインタを保存する必要があります。しかし、なぜそうなのか理解できません。 '真のリンクになることが必要です。これも実装時に醜い特殊事例につながるようです。リンク数が 1 より小さい inode で使用する空き領域だけを確保できると考えることができますが、ディレクトリの場合は実際にリンク数が少ないことを確認する必要があります。 2より。なぜ一貫性がないのですか?
答え1
本当に興味深い質問です。一見すると、次のような利点があります。
.
まず、「」は、シェルまたはシステムコールを介して現在のディレクトリとして解釈できることを指定します。ただし、ディレクトリにドット入力を使用すると、事実上これらの必要性が消え、低レベルで一貫性が維持されます。
しかし、私はこれがこのデザイン決定の基本的なアイデアだとは思いません。
ディレクトリからファイルが作成または削除されると、ディレクトリの修正タイムスタンプも更新する必要があります。このタイムスタンプは対応するインデックスノードに保存されます。 inode 番号は対応するディレクトリエントリに保存されます。
もしドットエントリは存在せず、ルーチンはそのディレクトリエントリからinode番号の親ディレクトリを検索する必要があり、これにより別のディレクトリ検索が発生します。
しかし、幸いなことに、現在のディレクトリにいくつかの項目があります。現在のディレクトリにファイルを追加または削除するルーチンは、単に最初のエントリ(通常はドットエントリがある場所)に戻り、すぐに現在のディレクトリのinode番号を見つけます。
ポイント入力には3番目の利点があります。
破損したファイルシステムを調べて、fsck
利用可能なリストにもない未接続ブロックを処理する必要があるときに、データブロック(ディレクトリリストとして解釈されたとき)にinodeを指すポイントエントリがあるかどうかを簡単に確認できます。順番にデータブロックを指します。その場合、データブロックは失われたディレクトリと見なされ、再接続する必要があります。
答え2
(うーん:今、次の内容がちょっと叙事的に変わっています...)
Unixファイルシステムのディレクトリデザインは(現象的に言えば、通常しかし、必ずしもUnixオペレーティングシステムに接続する必要はありません)は、実際に必要な特別なケースの数を減らす驚くべき洞察を表します。
「ディレクトリ」は実際にはファイルシステムのファイルにすぎません。ファイルシステム内のファイルのすべての実際の内容は、次の場所にあります。インデックスノード(あなたの質問からあなたはすでにこれについていくつか知っていることがわかります。)ディスクのInodeには何の構造もありません。ピーナッツバターのようにディスクに広がっている番号が付けられたバイトの塊だけです。これは何の目的もなく、少しでもすっきりしている人には本当に嫌いです。
これただ特殊 inode は inode 番号 2 です(従来の理由により 0 または 1 ではありません)。 inode 2はディレクトリファイルです。ルートディレクトリ。システムがファイルシステムをマウントするときに起動する前に、ディレクトリinode 2を読み取る必要があることを「認識」します。
ディレクトリファイルは opendir(3) と友達が読む内部構造を持つファイルだけです。 dir(5)で内部構造を見ることができます(オペレーティングシステムによって異なります)。見てみると、ディレクトリファイルエントリにファイルに関する情報がほとんど含まれていないことがわかります。すべての情報はinodeファイルにあります。このファイルのいくつかの特別な点の1つは、書き込みを許可するモードでディレクトリファイルを開こうとすると、open(2)関数がエラーを引き起こすことです。他のさまざまなコマンド(例hexdump
:)は、ディレクトリファイルを通常の方法で処理することを拒否します。これはおそらくユーザーが望むものではないかもしれません(しかしこれはファイルシステムではなく特別な場合です)。
ㅏハードリンクディレクトリファイルマップのエントリにすぎません。これらのマップには複数の項目があり、どちらも同じ inode 番号にマップされます。したがって、そのinodeへのハードリンクが2つ(またはそれ以上)あります。これも理由を説明します。すべてファイルには1つ以上の「ハードリンク」があります。 inodeには、ファイルシステムのディレクトリファイル内のinodeが言及された回数を記録する参照回数があります(この数字は、操作を実行したときに表示される数字ですls -l
)。
いいですね。それでは仕事を始めましょう。
カタログファイルは、文字列(「ファイル名」)を数値(inode番号)にマップしたものです。これらの inode 番号は、ディレクトリ内にあるファイルの inode 番号です。このディレクトリ内の「存在する」ファイルには別のディレクトリファイルを含めることができるため、そのinode番号はディレクトリにリストされている番号の1つです。したがって、fileがある場合、/tmp/foo/bar
ディレクトリファイルにはその文字列をそのファイルのinodeにマップするfoo
エントリが含まれます。bar
カタログ「にある」カタログファイルのエントリもカタログファイルにあります/tmp
。foo
/tmp
mkdir(2) を使用してディレクトリを作成する場合、この関数は
- 正しい内部構造(一部のinode番号を含む)でディレクトリファイルを作成します。
- 新しいディレクトリの名前をこの新しいinode(リンクの1つ)にマップする親ディレクトリにエントリを追加します。
- 新しいディレクトリにエントリを追加し、「。」文字列を同じinodeにマップします(これは別のリンクを表します)。
- 新しいディレクトリに別のエントリを追加し、文字列 ".."を(2)の手順で変更したディレクトリファイルのinodeにマップします(これは、サブディレクトリを含むディレクトリファイルに多数のハードリンクが表示されることを意味します)。
最終結果は(ほぼ)唯一の特別なケースは次のとおりです。
- open(2) 関数は、書き込み用にディレクトリファイルを開くのを防ぐことで、ユーザーが自責しにくくします。
- mkdir(2) 関数は、純粋にファイルシステムから簡単に移動できるように、新しいディレクトリファイルにいくつかの追加項目 ("." および "..") を追加することで、仕事を素晴らしくシンプルに保ちます。 「.」がなくてもファイルシステムが正常に動作するかどうか疑われます。と「..」がありますが、使いにくい場合があります。
- ディレクトリファイルは、「特殊」とマークされているいくつかのファイルタイプの1つです。これは本質的に、open(2)のような機能がわずかに異なる動作をするように指示します。
st_mode
統計(2)を参照してください。
(元のstackoverflow質問、2011-10-20からコピーされました)