Linux/Unixのファイルの特徴は何ですか?
ファイルには多くの種類があります:通常のファイル、ディレクトリ、 シンボリックリンク 、 デバイスファイル 、 ソケット 、 パイプ 、- fifo 、そして私が見逃していること。たとえば、シンボリックリンク:
$ Sudo file /proc/22277/fd/23
/proc/22277/fd/23: broken symbolic link to socket:[7540288]
ソケット:
$ Sudo ls -l /run/user/1001/systemd/notify
srwxrwxr-x 1 testme testme 0 Feb 6 16:41 /run/user/1001/systemd/notify
ファイルは inode (メモリまたはセカンダリストレージデバイスのいずれかのファイルシステムのiノード)を持つものとして特徴付けられていますか?すべてのファイルタイプのファイルにiノードがありますか? (両方の質問に「はい」と思います。)
Linuxのインターネットドメインソケット、トランスポートプロトコル(TCP/UDP)のソケットとポート ファイル記述が開いているものはファイルであると言っているようです。ファイルの説明が開いているものには、必ずiノードがありますか?
開いているファイルの説明は、ファイルよりもはるかに優れた用語であり、「ファイル」を定義することはできません。ネットワークソケットとUnixドメインソケットはすべて開いているファイルの説明です。 UDSは、ディスク上で何かを関連付ける場合と関連付ける場合があります(多くの状態がこれに影響を与える可能性があります)。 NSディスク上のものを関連付けることはありません。
ありがとう。
ファイルの定義方法については、 POSIX定義2017、セクション3.164 を参照してください。
書き込み、読み取り、またはその両方が可能なオブジェクト。ファイルには、アクセス許可やタイプなど、特定の属性があります。ファイルタイプには、通常ファイル、文字特殊ファイル、ブロック特殊ファイル、FIFO特殊ファイル、シンボリックリンク、ソケット、およびディレクトリが含まれます。他のタイプのファイルは、実装によってサポートされる場合があります。
つまり、ファイルとは、読み取り、書き込み、またはその両方が可能なものであり、メタデータも含まれています。みんな-家に帰って、名探偵コナン!
まあ、それほど速くはありません。このような定義は、関連する概念のための多くの余地を開き、通常のファイルと言うパイプの間には明らかに違いがあります。 「すべてがファイルです」は、それ自体が概念であり、リテラルステートメントではなく、設計パターンです。そのパターンに基づいて、ディレクトリ、パイプ、デバイスファイル、メモリ内ファイル、ソケットなどのファイルタイプ-これらすべては、open()
、openat()
などのシステムコールのセットを介して操作できます。 write()
、およびソケットrecv()
およびsend()
の場合、一貫した方法で。たとえば、USBを例にとると、さまざまなデバイスがありますが、それらはすべてまったく同じUSBポートに接続します(実際には、AからCまで複数のタイプのUSBポートタイプがあることに注意してください)。
もちろん、それが機能するためには、一貫した方法で実際のデータへの特定のインターフェースまたは参照が必要であり、それは ファイル記述子 :です。
ファイルアクセスの目的で開いているファイルを識別するために使用されるプロセスごとの一意の非負整数。新しく作成されたファイル記述子の値はゼロから{OPEN_MAX} -1です。
そのため、通常のファイル_/home/user/foobar.txt
_に書き込むのと同じ方法で、ファイル記述子1を介してwrite()
をSTDOUTに送信できます。ファイルをopen()
すると、ファイル記述子が取得され、同じwrite()
関数を使用してそのファイルに書き込むことができます。これが、元のUnix作成者が対処しようとしたすべてのポイントです-ミニマリストで一貫した動作。 _command > /home/user/foobar.txt
_を実行すると、シェルは_foobar.txt
_を参照するファイル記述子のコピーを作成し、それをcommand
のファイル記述子1(echoのSTDOUT)として渡します。より正確には、 dup2(3,1)
を実行してから、execve()
コマンドを実行します。ただし、それにもかかわらず、command
は、何も起こらなかったかのように、ファイル記述子1への同じ書き込みシステムコールを使用します。
もちろん、ほとんどのユーザーがファイルと考えるものに関して、彼らはディスクファイルシステム上の通常のファイルを考えます。これは、 通常のファイル定義、セクション3.32 とより一貫性があります。
ランダムにアクセス可能なバイトのシーケンスであり、システムによってそれ以上の構造が課されていないファイル。
対照的に、 Sockets があります:
POSIX.1-2017のSystem Interfacesボリュームで説明されているように、プロセス間通信の通信エンドポイントとして使用される特定のタイプのファイル。
タイプに関係なく、さまざまなファイルタイプに対して実行できるアクションは、概念的にはまったく同じです(open、read、write、close)。
ファイル定義で気付いたはずのことは、ファイルには「特定の属性」があり、iノードに格納されているということです。実際、特にLinuxでは、 inode(7)manual の最初の行を参照できます。
各ファイルには、ファイルに関するメタデータを含むiノードがあります。アプリケーションは、stat(2)(または関連する呼び出し)を使用してこのメタデータを取得できます
ブーム。明確で直接的な。私たちは、ディスク上のデータのブロックとディレクトリに格納されているファイル名との間のブリッジとしてのiノードにほとんど精通しています(ディレクトリとは、ファイル名と対応するiノードのリストであるため)。カーネルのpipefsやsockfsなどの 仮想ファイルシステム でも、iノードを見つけることができます。たとえば、次のコードスニペットを考えてみます。
_static char *pipefs_dname(struct dentry *dent, char *buffer, int buflen)
{
return dynamic_dname(dentry, buffer, buflen, "pipe:[%lu]",
dentry->d_inode->i_ino);
}
_
完全に混乱しているので、Linux/UnixはOpenFile Descriptionと呼ばれるものを導入し、説明を簡単にするために、これは別の抽象化です。 Stephane Chazelasの言葉で
それは、ファイル自体よりも、ファイルがどのように開かれたかの記録に関するものです。
そしてそれは POSIX定義 と一致しています:
プロセスまたはプロセスのグループがファイルにアクセスする方法の記録。各ファイル記述子は正確に1つの開いているファイル記述を参照しますが、開いているファイル記述は複数のファイル記述子によって参照される場合があります。ファイルオフセット、ファイルステータス、およびファイルアクセスモードは、開いているファイルの説明の属性です。
さて、 Linuxカーネルを理解する 本も見ると、著者は次のように述べています。
Linuxは、BSDソケットをsockfs特殊ファイルシステムに属するファイルとして実装します...より正確には、新しいBSDソケットごとに、カーネルはsockfs特別なファイルシステム。
ソケットはファイル記述子によっても参照されます であることを覚えておいてください。したがって、カーネルにソケットに関連するオープンファイルの説明があり、ソケットは問題ないファイルであると結論付けることができます。
つづく 。 。 。多分
Linuxのファイルは、基本的には操作できるものにすぎません。ファイルには正確に7つのタイプがあります。
コンテキストに応じてさまざまな方法でファイルについて話すため、多くの混乱が生じます。この議論では、2つの別々のコンテキストについて説明します。
Linux(メモリ内)では、すべてのファイルにiノードが(またはありますか?)です。このファイルが何であるかをLinuxに伝えるのはiノードであるため、1つ必要です。 iノードをディスク上のファイルのような意味のあるものにリンクするために、iノードは3つの重要な情報を格納します。
ファイルを操作する方法は、ファイルのタイプによって異なります。たとえば、ディレクトリを一覧表示したり、ブロックデバイスを一覧表示したりすることはできません。ソケットに接続することはできますが、通常のファイルに接続することはできません。
異なるファイルシステムは非常に異なります。 ext4のようなファイルシステムは、UNIXおよびLinux用に作成され、iノードのコンセプトを反映しています。したがって、メモリ内のiノードはディスク上のiノードから読み取られるだけです。
しかし、それらは異なります。たとえば、ディスク上のiノードはデバイスIDを持たないか、必要としません。 Linuxメモリ(メモリ内)のiノードは、ファイルデータがディスク上のどこに保存されているかを記録する必要があります。 Linuxのiノードはそれを理解するためにドライバーに依存しています。
ディスク上のiノード番号は通常、Linuxのiノード番号としてドライバーによって使用されます。したがって、ディスク上のiノードは、メモリ内のiノードと同じであると誤解されることがよくあります。
ファイル名は、ファイルを参照(検索)する最も一般的な方法です。ファイルシステムはファイル名のツリーを格納し、Linuxはmount
を使用してこれらのツリーを1つのツリーにまとめます。ツリー内の各名前は、単にiノードを指しています。
Linuxのファイルには、複数のファイル名を付けることができます。これは、ファイルシステムもサポートできる場合にのみ可能です。 Linuxとディスクの両方で、複数のファイル名(ハードリンク)は、複数の名前が同じiノードを指すようにすることで実現されます。
ファイルの削除とは、ファイル名を削除することです。実際に占有されているスペースは、すべてのファイル名が削除され、すべての「ファイル記述子」が閉じられたときにのみ再利用できます。
したがって、(ディスク上の)通常のファイルの場合、ファイル名-> iノード->データの3つがあります。
プログラムがファイルを開くと、ファイル名がファイル記述子(番号)と交換されます。これは、名前やパスを持たないiノードへの別の種類のリンクです。 「読み取り」や「書き込み」などのファイルに対するすべての操作は、ファイル名ではなくファイル記述子を使用します。
ファイル記述子は、open()を介して取得する必要はありません。ファイル記述子を取得すると、子プロセスに継承(コピー)でき、(UNIXドメインソケットを介して)まったく別のプロセスにコピーすることもできます。
OPが参照したコメントで「ファイルの説明」という言葉が使用されていたため、これが混乱を引き起こしたと思います。これらのコメントは、ファイル記述子が単なる数字ではないことを伝えようとしていたと思います。しかし、彼らはそれを紛らわしい方法で言っています。
このモデルにはいくつかの癖があります。まず、ファイルを開いてから(ファイルを閉じずに)削除すると、開いているファイル記述子により、ディスク上のファイルがリサイクルされなくなります。これにより、ファイル名のないファイルが作成されます。
さらに奇妙なことに、ファイルシステムの一部ではないファイルがあります。プログラムは、 非メッドパイプ または 非メッドスコケット を作成できます。これらはLinuxではiノードを持ちますが、Linuxカーネルに存在するものとしてのみ存在するため、ファイルシステムに直接接続されることはありません。これらはまだファイルです(奇妙なものですが)... iノードを参照するファイル記述子があります。
名前のないパイプの一般的な例は、コマンドラインプログラムのSTDIN、STDOUTです。 2つのプログラムを一緒にパイプする場合(foo | bar
)、それらの間のパイプは無名パイプになります。
通常、これらの概念をすべて1つの単語「ファイル」にまとめます。通常、これに別のファイル名が含まれることを気にせずに「ファイルに書き込む」ことができます。inodeは、ディスク上のファイル名とディスク上のinodeに変換され、最終的にディスクにコンテンツを書き込みます。 「ファイルに書き込む」というフレーズは、そのすべてを意味します。
これらの概念の分離を開始する必要があるのは、特別な状況のみです。
1)Unix上のほとんどのファイルシステムでは、ファイル、fifo、ディレクトリなどがiノードによって記述されます。 iノードにはいくつかのフィールドがありますが、この場合で最も興味深いのはi_modeフィールドです。権限の横には、iノードが指す「ファイル」のタイプが含まれています。
Constant Value Description
-- file format --
EXT2_S_IFSOCK 0xC000 socket
EXT2_S_IFLNK 0xA000 symbolic link
EXT2_S_IFREG 0x8000 regular file
EXT2_S_IFBLK 0x6000 block device
EXT2_S_IFDIR 0x4000 directory
EXT2_S_IFCHR 0x2000 character device
EXT2_S_IFIFO 0x1000 fifo
2)それはあなたがそれをどのように見るかに依存します。開いているすべてのファイルについて、それが「実際の」ファイルであろうと、名前のないパイプなどの別の構成であろうと、システムコールを介してiノードを取得できます。ただし、ファイルハンドルが閉じている場合、そのiノードは使用できません。 (セクション2は、事実に基づく不正確さを排除するために編集されています)