回答:
歴史的に(V7 UNIXまで、または1979年頃)、read
システムコールはファイルとディレクトリの両方で機能していました。read
ディレクトリでは、ユーザープログラムがディレクトリエントリを取得するために解析する単純なデータ構造を返します。実際、V7 ls
ツールはまさにこれをread
行いました。ディレクトリ上で、結果のデータ構造を解析し、構造化リスト形式で出力します。
ファイルシステムがより複雑になると、この「単純な」データ構造はより複雑になり、readdir
プログラムがの出力を解析できるようにライブラリ関数が追加されましたread(directory)
。システムやファイルシステムが異なれば、ディスク上のフォーマットも異なる可能性があり、複雑になりました。
SunがNetwork File System(NFS)を導入したとき、彼らはディスク上のディレクトリ構造を完全に抽象化することを望んでいました。read(directory)
ただし、プラットフォームに依存しないディレクトリの表現を返す代わりに、新しいシステムコールを追加しましたgetdirents
-- read
ネットワークにマウントされたディレクトリで禁止されました。このシステムコールは、さまざまなUNIXフレーバーのすべてのディレクトリで動作するように急速に適応され、ディレクトリの内容を取得するデフォルトの方法になりました。(https://utcc.utoronto.ca/~cks/space/blog/unix/ReaddirHistoryから抽出された履歴)
readdir
現在、ディレクトリを読み取るためのデフォルトの方法であるため、read(directory)
通常、ほとんどの最新のOSで実装されていません(-EISDIRを返します)(たとえば、QNXはreaddir
として実装する注目すべき例外read(directory)
です)。ただし、最新のカーネルの「仮想ファイルシステム」設計では、ディレクトリの読み取りが機能するかどうかは、実際には個々のファイルシステム次第です。
実際、macOSでは、マウントポイントのdevfs
基礎となるファイルシステムは/dev
実際に読み取りをサポートしています(https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/bsd/miscfs/devfs/devfs_vnops.c#L629) :
static int
devfs_read(struct vnop_read_args *ap)
{
devnode_t * dn_p = VTODN(ap->a_vp);
switch (ap->a_vp->v_type) {
case VDIR: {
dn_p->dn_access = 1;
return VNOP_READDIR(ap->a_vp, ap->a_uio, 0, NULL, NULL, ap->a_context);
これはREADDIR
、読み込もうとすると明示的に呼び出されます/dev
(ファイルの読み取り/dev
は別の関数で処理されます- devfsspec_read
)。したがって、プログラムがread
システムコールonを呼び出すと、プログラム/dev
は成功し、ディレクトリリストを取得します!
これは事実上、UNIXの非常に初期の時代からのホールドオーバーであり、非常に長い間触れられていない機能です。私の一部は、これが何らかの後方互換性の理由で保持されていると疑っていますが、実際には何も傷つけていないので、誰も機能を削除することを気にしないという事実である可能性があります。
Lessはテキストファイルビューアーであり、catは任意のデータをコピーするためのツールです。そのため、lessは独自のチェックを実行して、大量のデータを持つものや非常に奇妙な動作をするものを開かないようにします。一方、catにはそのようなチェックがまったくありません。カーネルが何かを開くことを許可する場合(パイプやデバイス、さらに悪いものであっても)、catはそれを読み取ります。
では、なぜOSはcatがディレクトリを開くことを許可するのですか?従来のBSDスタイルのシステムでは、すべてのディレクトリをファイルとして読み取ることができました。それは、プログラムが最初にディレクトリをリストする方法でした。ディスクに保存された異なる構造を解釈するだけです。
後に、それらのディスク上の構造は、カーネルが使用するディレントから分岐し始めました。以前はディレクトリが線形リストでしたが、後のファイルシステムはハッシュテーブル、Bツリーなどを使用し始めました。そのため、ディレクトリを直接読み取ることはもはや簡単ではありませんでした–カーネルはこのための専用機能を増やしました。(それが主な理由であったのか、それとも主にキャッシングなどの他の理由で追加されたのかはわかりません。)
一部のBSDシステムでは、引き続きすべてのディレクトリを読み取り用に開くことができます。ディスクから生データを提供するのか、エミュレートされたdirentリストを代わりに返すのか、ファイルシステムドライバーに決定させるのかはわかりません。
したがって、おそらくmacOSは、ファイルシステムがデータを提供する限り、カーネルが許可するオペレーティングシステムの1つです。違いは、初期にはこれを可能にするために作成さ/dev
れたdevfs
ファイルシステム上にあるのに対し/
、現代ではこの機能が不要であるAPFSファイルシステム上にあるということです。
免責事項:私は実際にBSDまたはmacOSに関する研究を行っていません。私はちょうどそれを翼にしている。
/etc
そうするだろうと思ったので、それをベンチマークとして使用しました。
mount
か/sbin/mount
、現在どこにマウントされているかを確認します。
/dev
は、devfs
それ/etc
がドライバーを使用している仮想ファイルシステムであるのに対し、ドライバーを使用している/
ファイルシステムの一部であることを確認しますapfs
。そのため、理由cat
は1つを読み、もう1つは読みません。ドライバーapfs
とdevfs
ドライバーの違いです。
neofetch
情報があります:) i.imgur.com/3azpnDt.png