UNIX / Linuxでディレクトリへのハードリンクが許可されないのはなぜですか?


130

Unix / Linuxはディレクトリへのハードリンクを許可しないが、ソフトリンクは許可することを教科書で読みました。それは、サイクルがあり、ハードリンクを作成し、しばらくしてから元のファイルを削除すると、ガベージ値がポイントされるからでしょうか?

循環がハードリンクを許可しない唯一の理由である場合、ディレクトリへのソフトリンクが許可されるのはなぜですか?


2
どこを..指すべきですか?特に、このディレクトリへのハードリンクを削除した後、..?が指すディレクトリで どこかを指す必要があります。
トールビョーンラヴンアンデルセン

2
..ドライブに物理的に存在する必要はありません。とにかく、現在の作業ディレクトリを追跡するのはオペレーティングシステムの仕事です。したがって、各プロセスのcwdに関連付けられたiノードのリストを保持し、の使用を参照するときに参照することも比較的簡単です..。もちろん、それはそれを念頭に置いてシンボリックリンクを作成する必要があることを意味しますが、すでにシンボリックリンクを壊さないように注意する必要があり、追加のルールがそれらを役に立たないだろうとは思いません。
パルティアショット

この説明が好きです。簡潔で読みやすい、またはスキム。
トレバーボイドスミス

回答:


143

ハードリンクと元の名前の違いを伝える方法がないため、これは単なる悪い考えです。

ディレクトリへのハードリンクを許可すると、ファイルシステムの有向非循環グラフ構造が壊れ、ディレクトリループが作成され、ディレクトリサブツリーがぶら下がりfsckます。

まず、これを理解するために、iノードについて説明しましょう。ファイルシステム内のデータはディスク上のブロックに保持され、それらのブロックはiノードによって一緒に収集されます。iノードはTHEファイルと考えることができます。ただし、iノードにはファイル名がありません。それがリンクの出番です。

リンクは、iノードへの単なるポインターです。ディレクトリは、リンクを保持するiノードです。ディレクトリ内の各ファイル名は、単にiノードへのリンクです。Unixでファイルを開くとリンクも作成されますが、それは別のタイプのリンクです(名前付きリンクではありません)。

ハードリンクは、そのiノードを指す追加のディレクトリエントリです。の場合ls -l、権限の後の数字は名前付きリンクカウントです。ほとんどの通常ファイルには1つのリンクがあります。ファイルへの新しいハードリンクを作成すると、両方のファイル名が同じiノードを指すようになります。注意:

% ls -l test
ls: test: No such file or directory
% touch test
% ls -l test
-rw-r--r--  1 danny  staff  0 Oct 13 17:58 test
% ln test test2
% ls -l test*
-rw-r--r--  2 danny  staff  0 Oct 13 17:58 test
-rw-r--r--  2 danny  staff  0 Oct 13 17:58 test2
% touch test3
% ls -l test*
-rw-r--r--  2 danny  staff  0 Oct 13 17:58 test
-rw-r--r--  2 danny  staff  0 Oct 13 17:58 test2
-rw-r--r--  1 danny  staff  0 Oct 13 17:59 test3
            ^
            ^ this is the link count

これで、ハードリンクなどはないことが明確にわかります。ハードリンクは通常の名前と同じです。上記の例では、testまたはtest2、元のファイルとハードリンクはどちらですか?両方の名前が同じコンテンツ、同じiノードを指しているため、最後には、(タイムスタンプでさえ)実際に伝えることはできません。

% ls -li test*  
14445750 -rw-r--r--  2 danny  staff  0 Oct 13 17:58 test
14445750 -rw-r--r--  2 danny  staff  0 Oct 13 17:58 test2
14445892 -rw-r--r--  1 danny  staff  0 Oct 13 17:59 test3

-iフラグlsは、行の先頭にiノード番号を表示します。どのように同じiノード番号testtest2持っているかを確認してくださいtest3

これで、ディレクトリに対してこれを行うことが許可された場合、ファイルシステム内の異なるポイントにある2つの異なるディレクトリが同じものを指す可能性があります。実際、サブディレクトリは祖父母を指すことがあり、ループを作成します。

このループが問題になるのはなぜですか?移動中は、ループしていることを検出する方法がないため(移動中にiノード番号を追跡せずに)。duディスク使用量を調べるためにサブディレクトリを再帰的に処理する必要があるコマンドを書いていると想像してください。duループが発生したときはどうすればわかりますか?duこの単純なタスクを実行するためだけに、エラーが発生しやすく、多くの簿記が必要になります。

シンボリックリンクは、多くのファイルファイルシステムAPIが自動的に追跡する傾向がある特殊なタイプの「ファイル」であるという点で、まったく別のものです。シンボリックリンクは、直接iノードを指すのではなく、名前で指すため、存在しない宛先を指すことができます。「ハードリンク」の単なる存在はファイルが存在することを意味するため、その概念はハードリンクでは意味がありません。

それでは、なぜduシンボリックリンクをハードリンクではなく簡単に処理できるのでしょうか?上記で、ハードリンクが通常のディレクトリエントリと見分けがつかないことがわかりました。ただし、シンボリックリンクは特別であり、検出可能であり、スキップ可能です!  duシンボリックリンクはシンボリックリンクであることに気付き、完全にスキップします!

% ls -l 
total 4
drwxr-xr-x  3 danny  staff  102 Oct 13 18:14 test1/
lrwxr-xr-x  1 danny  staff    5 Oct 13 18:13 test2@ -> test1
% du -ah
242M    ./test1/bigfile
242M    ./test1
4.0K    ./test2
242M    .

7
Allowing hard links to directories would break the directed acyclic graph structure of the filesystem。ハードリンクを使用したサイクルの問題について詳しく説明してください。シンボリックリンクで
問題ない理由-user3539

33
彼らは、link()システムコールにサイクル検出を追加し、サイクルを作成する場合はディレクトリハードリンクを作成できるようにすることを拒否することにより、Mac上でそれを許可したようです。合理的な解決策のようです。
psusi

10
@psusi mkdir -pa / b; nocheckln ca; mv ca /​​ b; -nochecklnには、ディレクトリ引数をチェックせず、リンクに渡されるだけの理論上のlnがあります。また、サイクルが作成されないため、 'c'を作成するのに適しています。次に、「c」を「a / b」に移動し、a / b / cからサイクルが作成されます-> a /-link()のチェックインでは十分ではありません
ダニーデュライ

3
サイクルは非常に悪いです。Windowsには、ハードリンクディレクトリである「ジャンクション」の問題があります。誤ってプロファイル全体にアクセス許可を適用すると、無限のサイクルを作成する一連のジャンクションが明らかになります。パスの長さの制限によって停止されるまで、ディレクトリを再帰的に繰り返します。
-doug65536

4
@WhiteWinterWolfは、このリンクによると、彼らは、特にタイムマシンのためにそれのためのサポートを追加しましたが、唯一のルートは、それを行うには許可されている:superuser.com/questions/360926/...
psusi

14

マウントポイントを除き、各ディレクトリには親が1つだけあります..

1つの方法pwdは、device:inodeで「。」を確認することです。および「..」。それらが同じ場合、ファイルシステムのルートに到達しています。それ以外の場合は、親で現在のディレクトリの名前を見つけ、それをスタックにプッシュし、「../。」の比較を開始します 「../ ..」、次に「../../。」「../../ ..」などを使用します。ルートにアクセスしたら、ポップしてスタックから名前を出力し始めます。このアルゴリズムは、各ディレクトリに1つだけの親があるという事実に依存しています。

ディレクトリへのハードリンクが許可されている場合、複数の親のうちのどれが..指すべきですか?これが、ディレクトリへのハードリンクが許可されない理由の1つです。

ディレクトリへのシンボリックリンクはその問題を引き起こしません。プログラムが必要な場合lstat()は、パス名の各部分を実行し、シンボリックリンクが検出されたことを検出できます。pwdこのアルゴリズムは、ターゲットディレクトリのための真の絶対パス名を返します。ターゲットディレクトリを指すテキスト(シンボリックリンク)がどこかにあるという事実は、ほとんど無関係です。このようなシンボリックリンクの存在は、グラフにループを作成しません。


3
これについてはよくわかりません。..親に対する一種の仮想ハードリンクであると考える場合、リンクのターゲットが他のリンクを1つしか持つことができないという技術的な理由はありません。pwd別のアルゴリズムを使用してパスを解決する必要があります。
ベヌバード14年

13

バインドマウントを使用して、ハードリンクディレクトリをシミュレートできます。

sudo mount --bind /some/existing_real_contents /else/dummy_but_existing_directory
sudo umount /else/dummy_but_existing_directory

7

この質問についてもう少しポイントを追加したいです。Linuxではディレクトリのハードリンクが許可されていますが、制限されています。

これをテストする1つの方法は、ディレクトリのコンテンツをリストするときに、2つの特別なディレクトリ「。」を見つけることです。および「..」。みなさんご存じのとおり "。" 同じディレクトリを指し、「..」は親ディレクトリを指します。

したがって、ディレクトリツリーを作成します。ここで、「a」は、子としてディレクトリ「b」を持つ親ディレクトリです。

 a
 `-- b

ディレクトリ「a」のiノードを書き留めます。また、ls -laディレクトリ「a」からaを実行すると、「。」が表示されます。ディレクトリも同じiノードを指します。

797358 drwxr-xr-x 3 mkannan mkannan 4096 Sep 17 19:13 a

ここで、ディレクトリ「a」には3つのハードリンクがあることがわかります。これは、inode 797358に「。」という名前の3つのハードリンクがあるためです。「a」ディレクトリ内の名前と「..」という名前のディレクトリ「b」内の名前と「a」という名前のディレクトリ

$ ls -ali a/
797358 drwxr-xr-x 3 mkannan mkannan 4096 Sep 17 19:13 .

$ ls -ali a/b/
797358 drwxr-xr-x 3 mkannan mkannan 4096 Sep 17 19:13 ..

したがって、ここでは、ディレクトリが親ディレクトリと子ディレクトリにのみ接続するためにハードリンクが存在することを理解できます。したがって、子のないディレクトリには2つのハードリンクしかありません。したがって、ディレクトリ「b」には2つのハードリンクしかありません。

ディレクトリのハードリンクが自由に防止される理由の1つは、ファイルシステムを横断するプログラムを混乱させる無限参照ループを避けるためです。

ファイルシステムはツリーとして編成されており、ツリーが循環参照を持つことはできないため、これは避けるべきでした。


1
良い例え。それは私の疑問をクリアしました。したがって、これらのケースは、無限ループを回避するために特別な方法で処理されます。右?
Gギル

1
ディレクトリのハードリンクを許可する方法は限られているため、「..」と「。」無限ループに到達しないため、それらが発生しないため、それらを回避するための特別な方法は必要ありません。)
Kannan Mohan 14年

6

次のどれも、ディレクトリへのハードリンクを許可しない本当の理由ではありません。各問題はかなり簡単に解決できます。

  • ツリー構造のサイクルは、困難なトラバースを引き起こします
  • 複数の親、それで「本当の」親はどれですか?
  • ファイルシステムのガベージコレクション

本当の理由(するThorbjörnRavnアンデルセン@によって示唆される)あなたは時に来て、削除ディレクトリから複数の親を持つディレクトリには、が指します..

今何を..指しているのでしょうか?

ディレクトリがその親から削除されているが、そのリンク数がまだそれよりも大きい場合0、どこかにまだそれを指しているものが存在する必要があります。..何も指さしておくことはできません。多くのプログラムはに依存している..ため、システムは、更新するために、削除されたディレクトリを指す最初のものを見つけるまで、ファイルシステム全体を走査する必要があります..。または、ファイルシステムは、ハードリンクディレクトリを指すすべてのディレクトリのリストを保持する必要があります。

いずれにせよ、これはパフォーマンスのオーバーヘッドであり、ファイルシステムのメタデータやコードの複雑さを増すため、設計者はそれを許可しないことにしました。


3
これも簡単に解決できます。子ディレクトリの親のリストを保持し、子へのリンクを追加または削除するときに更新します。正規の親(子ののターゲット..)を削除したら..、リスト内の他の親のいずれかを指すように更新します。
ジャッド

2
同意する。ロケット科学では解決できません。しかし、それでもパフォーマンスのオーバーヘッドが発生し、ファイルシステムのメタデータに少し余分なスペースが必要になり、複雑さが増します。そのため、デザイナーはシンプルで高速なアプローチを採用しました。ハードディレクトリへのリンクは許可しません。
Lqueryvg

1
dirsへのsymリンクは「解決されたセマンティクスと動作に違反します」が、まだ許可されています。そのため、一部のコマンドには、symリンクをたどるかどうかを制御するオプションが必要です(たとえば、findおよびcpの-L)。プログラムが「..」の後に続くとさらに混乱が生じます。したがって、symリンクを通過した後のpwdと/ bin / pwdの出力の違いがあります。「Unixの回答」はありません。設計を決定するだけです。これは、私の答えで述べたように、「..」になるものを中心に展開します。残念なことに、「..」は、他の誰もがひどく投票しているという答えにさえ言及されていません。
Lqueryvg

ところで、私はdirsへのハードリンクに賛成だと言っているわけではありません。どういたしまして。私の日課が既にあるよりも困難になりたくありません。
Lqueryvg

これは、POSIXが言うことではないのですが、IMO「..」ファイルシステムの概念ではありませんでしたはず、というパスに構文的に解決し、そのためには、a/..常に意味します.。これがURLの仕組みです。サーバーにヒットする前に「..」を解決しているのはブラウザです。そしてそれは素晴らしく機能します。
イブンガロビル

3

ディレクトリでのハードリンクの作成は元に戻せません。私たちが持っていると仮定します:

/dir1
├──this.txt
├──directory
│  └──subfiles
└──etc

にハードリンクし/dir2ます。

したがって/dir2、これらのファイルとディレクトリもすべて含まれるようになりました

気が変わったらどうなりますか?ただrmdir /dir2(空ではないから)

そして、私が再帰的に削除すると/dir2...から/dir1も削除されます!

私見では、これを回避するのに十分な理由です!

編集:

コメントは、ディレクトリを削除することを示唆してrmいます。ただしrm、空でないディレクトリでは失敗し、ディレクトリがハードリンクされているかどうかにかかわらず、この動作を維持する必要があります。したがってrm、リンクだけを解除することはできません。rm「ディレクトリiノードの参照カウントが1より大きい場合、ディレクトリのリンクを解除するだけ」と言うために、への新しい引数が必要になります。

順番に、驚きの最小の別の原則を破る:それは私がちょうど作成したディレクトリハードリンクの削除が通常のファイルハードリンクの削除と同じではないことを意味します...

私は文を言い換えます:さらなる開発がなければ、ハードリンクの作成は元に戻せません(現在のコマンドは現在の動作と矛盾せずに削除を処理できないため)

ケース、落とし穴の数、およびシステムがどのように機能するかを十分に認識していない場合のデータ損失リスクをより多くの開発が処理できるようにすると、そのような開発は、ディレクトリ上のハードリンクを制限する十分な理由です。


それは問題ではないはずです。あなたの場合、dir2へのハードリンクを作成するとき、dir1のすべてのコンテンツへのハードリンクを作成する必要があるため、dir2の名前を変更または削除すると、iノードへの余分なリンクのみが削除されます。そして、iノードへのリンクが少なくとも1つ(dir1)あるので、dir1とその内容には影響しません。
カンナンモハン14

3
引数が間違っています。rm -rfではなく、リンクを解除するだけです。また、リンクカウントが0に達すると、システムはすべてのコンテンツも削除できることを認識します。
LtWorf

rmとにかく、すべてが下にあります(リンク解除)。参照:unix.stackexchange.com/questions/151951/…これは実際には問題ではなく、ハードリンクファイルの場合と同じです。リンクを解除すると、名前付き参照が削除され、リンク数が減ります。rmdir空でないディレクトリを削除しないという事実は関係ありません- dir1 どちらに対してもそれをしません。ハードリンクはデータのコピーではなく、同じ実際のファイルです。したがって、実際にdir2ファイルを「削除」すると、dir1のディレクトリリストが消去されます。常にリンクを解除する必要があります。
BryKKan

通常のファイルのようにリンクを解除することはできません。rmディレクトリ上で空でない場合は、リンクを解除しないでください。編集を参照してください。
ピエールオリビエヴァレス

1

これは良い説明です。「複数の親のうち、どちらを指すべきですか?」について 1つの解決策は、プロセスがiノードまたは文字列として、完全なwdパスを維持することです。名前は変更できるため、inodeはより堅牢です。少なくとも昔は、開いているファイルごとにコア内のiノードがあり、ファイルが開かれるたびに増加し、閉じるときに減少していました。ゼロに達すると、それが指していたストレージが解放されます。ファイルが誰かによって開かれなくなると、そのファイル(コア内コピー)は破棄されます。これにより、サブディレクトリが別のプロセスのパスにある間に他のプロセスがディレクトリを別のディレクトリに移動した場合、パスは有効なままになります。開いているファイルを削除する方法と似ていますが、ディレクトリから単純に削除されますが、

以前はBell Labs UNIX、少なくともV6およびV7では、ハードリンクディレクトリは自由に許可されていましたが、Berkeley以降については知りません。フラグは必要ありません。ループを作ってもらえますか?はい、そうしないでください。ループを作成すると、何をしているのかが非常に明確になります。ネザーは、バルクヘッドのフックに他の端が便利にぶら下がっている場合、飛行機から飛び降りるターンを待っている間に、首に結び目を作る練習をする必要があります。

どのような私は、今日は私が/ホーム/かどうか利用できるadministを持つことができるように、/ homeは、ホームの上にautomoutで/ lhomeへのシンボリックリンクという名前administを持っている自動マウントを覆われていた家にハードリンクlhomeにしたそれを行うことを望ん/ administ。これにより、プライマリホームファイルシステムの状態に関係なく機能する管理アカウントを持つことができます。これは、IS Linux用の実験が、私は自動マウントは、ASCII文字列レベルで行われていることをUCBベースSunOSのため、一度に学んだと思います。任意のFSの最上位のレイヤーとして、それらがどのように行われるかを確認することは困難です。

それを他の場所で読んだ。および..もディレクトリ内のファイルではありません。このすべてに正当な理由があり、そのような理由で(NTFSをマウントできるなど)私たちが楽しんでいることの多くは可能であると確信していますが、UNIXの優雅さの一部は実装にありました。この優雅さが提供する一般性や順応性などの利点は、非常に堅牢で、40年間にわたって耐えることを可能にしました。エレガントな実装を失うと、最終的にはWindowsのようになります(間違っていると思います!)。誰かがエレガントな原則に基づいた新しいOSを作成します。考えること。おそらく私は間違っている、私は(明らかに)現在の実装に精通していない。それ 驚くべきことに、30年前の理解がLinuxにどのように当てはまるか...ほとんどの場合です!


私は、私が間違っているかもしれないが、と思う...近代的なファイル・システムでは、ファイル・システム内のハードリンクではありません。ただし、ファイルシステムドライバーはそれらを偽装します。ハードリンクディレクトリを停止するのは、これらのファイルシステムです。古いファイルシステムの場合、それは可能でした(しかし危険です)。あなたがしようとしていることを行うにはmount --bind、を参照しmount --make…、おそらくコンテナを参照してください。
ctrl-alt-delor

0

私が収集したものの主な理由は、作業ディレクトリを使用して他のファイルを参照する実行中のプログラムを台無しにすることなくディレクトリ名を変更できると便利だからです。Wineを使用して実行して~/.newwineprefix/drive_c/Program Files/Firefox/Firefox.exeおり、~/.wine代わりにプレフィックス全体を移動したいとします。何らかの奇妙な理由でFirefoxがdrive_c/windowsを参照してアクセスしていた../../windows場合、名前を変更すると、iノードではなくテキスト文字列として親ディレクトリを追跡する~/.newwineprefix実装が壊れ..ます。

単一の親ディレクトリのiノードを保存することは、すべてのパスをテキスト文字列と一連のiノードの両方として追跡しようとするよりも簡単でなければなりません。

別の理由は、不正な動作をするアプリケーションがループを作成できる可能性があることです。動作中のアプリケーションは、ディレクトリを自分自身に移動できないように、移動中のディレクトリのiノードが、移動先のネストされたディレクトリのiノードと同じであるかどうかを確認できる必要がありますが、これは強制されない場合がありますファイルシステムレベルで。

さらに別の理由として、ディレクトリをハードリンクできる場合は、変更できないディレクトリのハードリンクを防ぎたいことがあります。find他のユーザーが作成したファイルを一時ディレクトリから消去するために使用されるため、セキュリティ上の考慮事項がありますfind。重要なディレクトリをハードリンクできると、管理者はfindそれらに影響を与えないようにテストを追加する必要があります。(OK、あなたはすでにファイルに対してこれを行うことができないので、この理由は無効です。)

さらに別の理由は、親ディレクトリのiノードを保存すると、ファイルシステムが破損または損傷した場合に余分な冗長性が提供される可能性があるためです。この..ディレクトリにハードリンクするすべての親ディレクトリをリストしたい場合、現在のディレクトリがリンク解除されている場合、別の任意の親を簡単に見つけることができます。ハードリンクが等しいという考えに違反しているだけでなく、ファイルシステムは、iノードを保存および使用します。プログラムがパスを一連の(各ハードリンクに固有の)ディレクトリiノードとして扱うようにすると、これを回避できますが、ファイルシステムが破損した場合に冗長性を得ることができません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.