15

新しい記述子がファイルテーブル内の同じ内部ファイル構造/エントリを共有しないように、既存のファイル記述子から新しいファイル記述子を作成するにはどうすればよいですか? 具体的には、ファイル オフセットなどの属性 (およびできればパーミッション、共有、モード) は、新しいファイル記述子と古いファイル記述子の間で共有されるべきではありません。

Windows と Linux の両方で、dup()はファイル記述子を複製しますが、両方の記述子はプロセスのファイル テーブル内の同じファイル構造を指します。いずれかの記述子をシークすると、他の記述子の位置も調整されます。

ノート

それ以来、私は Windows と Linux の両方について回答を受け取り、質問を頻繁に調整しすぎたため、人々が回答するのが難しくなりました。投票を調整し、WindowsLinux の両方をカバーする最もクリーンな回答を受け入れます。申し訳ありませんが、私はまだSOパラダイムに慣れていません。素晴らしい答えをありがとう!

4

3 に答える 3

13

したがって、基本的に、本当に必要なのは、ファイル記述子が与えられ、基本的に同じファイルをもう一度開いて、別の位置、共有、モードなどを取得することです。そして、これを Windows (「ファイル記述子」 " は基本的に外部オブジェクトであり、OSランタイム ライブラリによって直接使用されるものではありません。

驚くべきことに、少なくとも MS VC++ ではそれを行う方法があります2 つのステップを除いてすべて Win32 API のみを使用するため、他のコンパイラ/ライブラリへの移植はかなり合理的なはずです (ほとんどの場合、これら 2 つの関数のバージョンが提供されていると思います)。これらは、Unix スタイルのファイル記述子をネイティブの Win32 ファイル ハンドルに変換し、ネイティブの Win32 ファイル ハンドルを Unix スタイルのファイル記述子に変換するためのものです。

  1. _get_osfhandle() を使用して、ファイル記述子をネイティブ ファイル ハンドルに変換します。
  2. GetFileInformationByHandleEx(FILE_NAME_INFO) 1でファイルの名前を取得します。
  3. CreateFile を使用して、そのファイルへの新しいハンドルを開きます
  4. _open_osfhandle() でそのハンドルのファイル記述子を作成します

ほら、同じファイルを参照する新しいファイル記述子がありますが、独自の権限、位置などがあります。

質問の終わりに向かって、「アクセス許可」も必要なように聞こえますが、それは実際には意味がないようです-アクセス許可は、ファイルを開く方法ではなく、ファイル自体に添付されるため、ファイルを開いたり、再度開いたりしても、ファイルのアクセス許可には影響しません。本当に知りたい場合は、GetFileInformationByHandle で取得できますが、Windows のファイル アクセス許可は、Unix の (従来の) ファイル アクセス許可とはかなり異なることに注意してください。Unix には、すべてのファイルに対する所有者/グループ/世界のアクセス許可があり、ほとんどのシステムにも ACL があります (ただし、動作方法にはさらにバリエーションがあります)。Windows にはパーミッションがまったくない (例: FAT または FAT32 上のファイル) か、ACL を使用する (例: NTFS 上のファイル) かのいずれかですが、

おそらく、「アクセス許可」を使用して、ファイルが読み取り、書き込み、またはその両方で開かれていたかどうかを参照しています。それを取得することは、前述のいずれよりもかなり醜いです。問題は、そのほとんどが Win32 ではなくライブラリにあることです。そのため、コンパイラ間で移植可能に近い方法はおそらくないでしょう。MS VC++ 9.0 SP1 (他のコンパイラでは保証されていません) では、次のことができます。

#include <stdio.h>

int get_perms(int fd) {
    int i;
 FILE * base = __iob_func();

    for (i=0; i<_IOB_ENTRIES; i++) 
        if (base[i]._file == fd)
            return base[i]._flag;     // we've found our file
    return 0; // file wasn't found.
}

これにはいくつかの探検が含まれていたため、実際に機能するかどうかを確認するための簡単なテストを作成しました。

#ifdef TEST
#include <io.h>

void show_perms(int perms, char const *caption) { 
 printf("File opened for %s\n", caption);
 printf("Read permission = %d\n", (perms & _IOREAD)!=0);
 printf("Write permission = %d\n", (perms & _IOWRT)!=0);
}

int main(int argc, char **argv) { 
 FILE *file1, *file2;
 int perms1, perms2;

 file1=fopen(argv[1], "w");
 perms1 = get_perms(_fileno(file1));
 fclose(file1);

 file2=fopen(argv[1], "r");
 perms2 = get_perms(_fileno(file2));
 fclose(file2);

 show_perms(perms1, "writing");
 show_perms(perms2, "reading");
 return 0;
}
#endif

結果は成功を示しているようです。

File opened for writing
Read permission = 0
Write permission = 1
File opened for reading
Read permission = 1
Write permission = 0

次に、stdio.h で定義されている _IOREAD、_IOWRT、および _IORW に対して、返されたフラグをテストできます。以前の警告にもかかわらず、ライブラリのこの部分がかなり安定していると思われる (確かに保証はできませんが) ので、大きな変更が実際に行われる可能性はおそらくごくわずかです。

ただし、他の方向では、基本的に他のライブラリで動作する可能性はまったくありません。Intel 、MinGW、またはバックエンドとして MS VC++ を使用する Comeau など、MS ライブラリを使用する他のコンパイラで動作する可能性があります (ただし、保証されているわけではありません)。それらの中で、動作する可能性が最も高いのは Comeau であり、MinGW が最も可能性が低いと思います (ただし、これは推測にすぎません。それらのいずれでも動作しない可能性は十分にあります)。

  1. 再配布可能な Win32 FileID API ライブラリが必要です
于 2009-10-27T05:16:50.787 に答える
3

ですから、これについてもう少し読むことをお勧めします。dup()および関連する関数は、開いているファイル テーブルの同じエントリを指すファイル記述子テーブルに重複する値を作成するのに役立ちます。これは、同じオフセットを持つことを意図しています。を呼び出すとopen()、開いているファイル テーブルに新しいエントリが作成されます。

ファイル記述子の複製を作成しても意味がなく、その新しいファイル記述子は開いているファイル テーブルで異なるオフセットを持っています (これは「複製」という言葉の意味と矛盾しているようです)。

あなたの質問が実際に何であるかわかりません。つまり、それは複製と同じものではありません。あなたは読むことができます:

/proc/self/fd/[descriptor]

そのファイル記述子を開くために使用された文字列を取得します。これはいくつかの落とし穴を提供する可能性があることに注意してください。そのうちのいくつかは、open()再呼び出しの観察で実際に指摘したものです。

多分あなたはもう少し説明することができ、私は助けるために更新しようとすることができます.

于 2009-10-21T03:59:42.837 に答える
0

Windows で open() または CreateFile() を使用してもう一度ファイルを開かないのはなぜですか? これにより、さまざまなアクセス権と個別のオフセットの自由がすべて与えられます。

もちろん、これにはファイルを排他的に開くことができないという欠点がありますが、問題は非常に簡単に解決されます。

于 2009-10-29T10:24:31.073 に答える