2

UNIX では、次のように追加モードでファイルを開くと

fd = open("filename", O_APPEND);

次に、そのようなファイル記述子が与えられると、それがどのフラグで開かれたかを次のように使用して簡単に見つけることができますfcntl

fcntl(fd, F_GETFL) & O_APPEND

Windowsでは利用できないことは知ってfcntlいますが、これを判断する方法があるのだろうか. Windows は、たとえばフラグを使用してファイルを作成しCreateFile、渡すときに、追加モードを明確にサポートしています。FILE_APPEND_DATA

しかし、すでに開いているファイルへのハンドルしか持っていない場合、ファイルが最初に開かれたときにどのアクセス権が要求されたかを判断する方法を見つけることはできません。 この質問は、特定のファイルへのアクセス権をチェックするための基本的なレシピを提供しますが、それは役に立たないようです。私はそれを試してみましたが、読み取り専用モードでファイルを開いても、要求した場合、ファイルへのFILE_APPEND_DATA アクセス権があることがわかります。つまり、このメソッドは、プロセスが特定のファイルに対してどのようなアクセス権を持っているか (プロセスを開始したユーザーから継承されたもの) を教えてくれるだけです。ファイルが開かれたときに要求された正確なアクセスについては何も述べていません。

これは、Windows がファイルを追加するだけかどうかを追跡する方法とは関係ありません。そして、どこにも答えが見つからないのは後者の質問です。私が見つけた最も近いものはGetFileInformationByHandleEx ですが、ドキュメントを調べた後、「追加モード」を示唆するその API を介して返すことができるファイル属性は 1 つもありません。

更新:私の質問をもう少し明確にするために、この質問は実際にはMS VCランタイムライブラリに適用されます-POSIXのような関数で開かれ、_openなどに書き込まれるファイルfwrite。ネイティブの win32 ファイル ハンドルには「追加モード」の概念がないようです。

4

4 に答える 4

4

Windowsが「追加」モードにあると見なすファイルの場合、これは機能します。

を照会するには、半文書化NtQueryInformationFileされたシステム コール (からエクスポートntdll.dll) を使用しますFILE_ACCESS_INFORMATION。これにより、ファイルが開かれたときに使用されたアクセス マスクがわかるはずFILE_APPEND_DATAです。

ただし、 C ランタイムが「追加」モードで開くファイルの場合、これは機能しません。これは、Windows が実際には追加モードで開かないためです。これを行う方法は、何らかの方法でファイル記述子をファイル オブジェクトに変換し、そこでフラグをチェックすることですが、これを行う方法は文書化されていません。

Visual C++ CRT のソース コードを見て、その方法を理解できます...記述子がインデックスを付ける配列にアクセスする方法があるかもしれませんが、その方法はわかりません。
CRT のコードが_pioinfo(fd)->osfile |= FAPPEND役立つことを願っています。

于 2013-08-30T21:31:19.997 に答える
4

FileMode.Append は、.NET Framework チームの想像力の産物です。Windows がサポートするモードではありません。彼らはそれを追加して、ネイティブの winapi CreateFile() 関数 (FileStream) のラッパーを使いやすくしました。FileMode は、その dwCreationDisposition 引数の列挙ラッパーです。CREATE_APPEND オプションがありません。

FileStream.Init() メソッドの最も関連性の高いコードは次のとおりです。

   bool seekToEnd = (mode==FileMode.Append);
   // Must use a valid Win32 constant here...
   if (mode == FileMode.Append)
       mode = FileMode.OpenOrCreate;

つまり、FileMode.Append は有効な CreateFile() オプションと一致しないため、マップする必要があります。ファイルが存在する場合は開かれ、存在しない場合は作成されます。そして、ファイルを開いた後、ファイルの最後までシークする追加の操作を処理します。もちろん、既存のファイルに追加するときに期待することです。いくつかの追加のエラー チェックが存在します。また、書き込み用にファイルを開いたことが確認されます。

そのため、これを検出するための探求に穴が開きます. GetFileInformationByHandleEx() winapi 関数を使用して、ファイルの状態を回復できます。Mehrdad の文書化されていないネイティブ API 呼び出しの文書化された関数。FileDispositionInfo から dwCreationDisposition 引数を取得して、それが OpenOrCreate であったことを確認できます。ただし、これは一意ではなく、クライアント コードから FileMode.OpenOrCreate で開かれているファイルから開始された可能性もあります。まれですが、可能です。

あなたが失ったのは、ファイルの最後までシークした記憶です。FileStream.Position プロパティを使用することもできますが、もちろんそれはその間の書き込みの影響を受けます。これが本当に重要な場合は、使用された FileMode 値を保持する必要があります。

于 2013-08-30T23:26:09.390 に答える
2

@mehrdad と @HansPassant が私を正しい方向に向けてくれたことに感謝します。実際、MSVCRT は、呼び出された構造体の配列の配列をエクスポートioinfoし、プロセスで開いている各ファイル ハンドルに関する情報を格納します。

構造体の正確な内容は、VC のバージョンといくつかの定義によって異なりますが、一般に最初の 2 つのメンバーが定義されています。

typedef struct {
        intptr_t osfhnd;    /* underlying OS file HANDLE */
        char osfile;        /* attributes of file (e.g., open in text mode?) */
        ....
} ioinfo;

このosfileメンバーは興味深いものです。ファイルがdefined as_O_APPENDというフラグが設定された状態で開かれている場合です。FAPPEND0x20

このチェックを実行できる CPython の posixmodule の同様のコードに基づいて、Python で小さなユーティリティ関数を作成しました: https://gist.github.com/embray/6444262

于 2013-09-04T23:40:44.933 に答える