Cのファイル記述子からファイル名を取得する


105

Cでファイル記述子(Linux)のファイル名を取得することはできますか?


私の推測では、選択した答えはzneakに提供する必要があります。彼のソリューションは移植性が高く、アクセスに関する問題は指摘されていないためです。
セルゲイ

Ubuntu 14.04(カーネル3.16.0-76-generic)ではサポートされていません。Linuxではまったくサポートされていないと思います。
felipou 2016年

macOS については、D.Nathanaelによる別の質問に対するこの回答を参照してください。
ジョナサンレフラー

回答:


120

あなたは使用することができますreadlink上の/proc/self/fd/NNNNNNは、ファイル記述子です。これにより、ファイルを開いたときの名前が表示されます。ただし、それ以降にファイルが移動または削除された場合、正確ではなくなる可能性があります(Linuxが名前を追跡できる場合もあります)。確認するには、指定されstatたファイル名とfstatfdを確認st_devst_ino、同じであることを確認します。

もちろん、すべてのファイル記述子がファイルを参照しているわけではありません。それらについては、などの奇妙なテキスト文字列が表示されpipe:[1538488]ます。実際のファイル名はすべて絶対パスになるため、どれで十分かを判断できます。さらに、他の人が指摘したように、ファイルはそれらを指す複数のハードリンクを持つことができます-これはそれが開かれたものだけを報告します。特定のファイルのすべての名前を検索する場合は、ファイルシステム全体をトラバースする必要があります。


9
元のファイルがまだそのファイルへの参照を持っている限り(オープンfdはそのような参照になります)、iノード番号再利用することはできません。ファイルを閉じた後、または開く前にiノード番号を使用するソフトウェアは、本質的に競合状態の影響を受けます。
R .. GitHub ICE

3
危険、ウィル・ロビンソン!これは常に機能するとは限りません--- setuid()トリックを行うと/proc/self/fd、プロセスからアクセスできなくなる可能性があります。参照:permalink.gmane.org/gmane.linux.kernel/1302546
デビッドギヴン

2
@bdonlan:/ procがマウントされていない場合?
user2284570 2015年

1
@ user2284570、この回答はLinux固有です。NetBSDがprocfsをまったくサポートしているかどうかはわかりません。共有ホストがprocfsをサポートしていない場合は、おそらくNetBSDがまったくサポートしておらず、代わりに別のメカニズムを使用していることが原因です。NetBSDに焦点を当てた別の質問を投稿して、NetBSDがこの情報を公開する方法を誰かが知っているかどうかを確認することもできます(以下のzneakの回答も試してください。OSXはLinuxよりもBSDに似ています)
bdonlan

1
@bdonlan:NetBSDは/ procをサポートしていますが、マウントする必要はありません。私が言及するたびに、答えは「より高いコストのプロバイダーに切り替えると、/ procを取得する」となりました。だから私はproclessソリューションを探しています。
user2284570 2015年

90

Mac OS Xでこの問題が発生しました。/proc仮想ファイルシステムがないため、承認されたソリューションは機能しません。

代わりに、F_GETPATH次のコマンドがありfcntlます。

 F_GETPATH          Get the path of the file descriptor Fildes.  The argu-
                    ment must be a buffer of size MAXPATHLEN or greater.

したがって、ファイル記述子に関連付けられたファイルを取得するには、次のスニペットを使用できます。

#include <sys/syslimits.h>
#include <fcntl.h>

char filePath[PATH_MAX];
if (fcntl(fd, F_GETPATH, filePath) != -1)
{
    // do something with the file path
}

どこMAXPATHLENで定義されているのか覚えていないのでPATH_MAX、syslimits でいいと思いました。


@uchuugaka、おそらく違う。を使用しgetsocknameます。
zneak 2015年

2
何を期待していますか?UNIXソケットでない限り、ファイルは関連付けられていません。
zneak 2015年

2
@uchuugakaはい、すべてがファイルですが、すべてがファイルシステムツリー内の名前と場所を含むディレクトリエントリではありません。ファイルはiノードで表されます。ファイルを参照するディレクトリエントリがなくても存在できます。
lgeorget 2015

9
<sys / param.h>内:#define MAXPATHLEN PATH_MAX
geowar

1
私はこれをテストしましたが、ファイルが移動されて再度呼び出した場合でも正しいままです(つまり、ファイルの新しいパスを取得します)。ただし、これはLinuxではサポートされていません(Ubuntu 14.04でテスト済み-F_GETPATHが定義されていません)。
felipou 2016年


15

Tylerが指摘するように、特定のFDが0のファイル名(さまざまな場合)または> 1(複数の「ハードリンク」とは一般的に後者の状況がどのように説明されるか)に対応する場合があるため、「直接かつ確実に」必要なことを行う方法はありません。 )。それでもすべての制限付きの機能が必要な場合(速度が1でなく、0、2、...の結果が得られる可能性がある場合)は、次の方法でそれを行うことができます。最初に、FDをfstatします。これにより、 、結果struct statので、ファイルが存在するデバイス、ファイルのハードリンクの数、特殊ファイルかどうかなど。これはすでに質問に答えている可能性があります。たとえば、ハードリンクが0の場合、実際には対応するファイル名がないことを知っています。ディスク上。

統計で希望が得られる場合は、すべてのハードリンクが見つかるまで、関連するデバイス上のディレクトリの「ツリーをたどる」必要があります(または、最初のリンクだけで、複数のハードリンクが必要ない場合は、1つだけで十分です) )。そのために、readdir(そしてもちろんopendir&c)を使用struct direntして、元のディレクトリと同じinode番号が見つかるまで、サブディレクトリを再帰的に開きますstruct stat(このとき、名前だけでなくパス全体が必要な場合は、再構築するには、ディレクトリのチェーンを逆方向にたどる必要があります)。

この一般的なアプローチは受け入れられますが、より詳細なCコードが必要な場合はお知らせください。役に立たない場合、つまり、必然的に遅いパフォーマンスやアプリケーションの目的で!= 1の結果が得られる可能性;-)


9

これを不可能と書く前に、lsofコマンドのソースコードを確認することをお勧めします。

制限があるかもしれませんが、lsofはファイル記述子とファイル名を判別できるようです。この情報は/ procファイルシステムに存在するため、プログラムからアクセスできるはずです。


6

fstat()を使用すると、struct statによってファイルのiノードを取得できます。次に、readdir()を使用して、見つかったiノードをディレクトリ内に存在するもの(struct dirent)と比較し(ディレクトリがわかっている場合は、ファイルシステム全体を検索する必要があります)、対応するファイル名を見つけます。不快な?


2

不可能な。ファイル記述子は、ファイルシステム内に複数の名前を持っているか、まったく名前を持たない場合があります。

編集:OSを指定しなかったので、OS固有のAPIのないプレーンな古いPOSIXシステムについて話していると仮定します。


4
その後、私の答えが適用されます。Linuxにはこれを行う機能がありません。Linux(POSIX)ファイル記述子は必ずしもファイルを参照するわけではなく、参照する場合でも、ファイル名ではなくiノードを参照します。記述子は、削除されたファイル(したがって、名前がないため、これは一時ファイルを作成する一般的な方法です)を指すことも、複数の名前(ハードリンク)を持つiノードを指すこともあります。
タイラーマクヘンリー

3
lsofソースコードを見てみましょう。:)それは私が以前に同じ質問をしたときに私がやったことです。lsofは黒魔術と犠牲山羊で動作します-その動作を再現することはできません。具体的には、lsofはLinuxカーネルと緊密に結合されており、ユーザーランドコードで利用可能なAPIを使用して実行することはありません。
タイラーマクヘンリー

27
Linuxには、このための移植性のないproc APIがあります。確かに制限はありますが、不可能だと言っているのは単なる誤りです。
bdonlan 2009

1
@Tyler-lsofはユーザー空間で実行されます。したがって、ユーザーランドコードで利用できるAPIがあります:)
bdonlan

1
@Duck、移植性があるのには、lsofのソースに多くの黒魔術があるのでしょう。それぞれのUNIXバリアントは異なる方法でそれを行います。Linuxのprocインターフェースはそれほど悪くはありませんが、実際にはalebitはまばらに文書化されています。
bdonlan 2009
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.