穴のあいた抽象化について(または予測不可能な環境について)

したがって、Windows用プログラムのかなり単純な部分です。 いくつかのエントリを含むファイルがあります。 そして、それらは特定の方法でフィルタリングする必要があります。



解決策は非常に簡単です。ファイルを開き、レコードを1つずつ読み取り、必要なレコードを一時ファイルに書き込みます。 ファイルを閉じます。 削除します。 一時的な名前を元の名前に変更します。 すべてが単純なので、コードを提供することさえしません。 これは本当に記事の十分な理由ですか?



すべてが機能している間、それについて書く理由は本当にありません。 しかし、その後突然「すべてが落ちる」、なぜなら 「アクセス拒否」エラーのため、名前の変更は行われません。 これはごくまれにしか発生しませんが、宇宙線を疑う頻度はさらに高くなります。



発掘を始めます。 最初に見つかった手がかり:掘り下げの過程で、Microsoftのドキュメントからの次の引用は警告しました。

DeleteFile関数は、ファイルを閉じるときに削除対象としてマークします。 したがって、ファイルの最後のハンドルが閉じられるまで、ファイルの削除は発生しません。 ファイルを開くためのCreateFileへの後続の呼び出しは、ERROR_ACCESS_DENIEDで失敗します。
症状の点では非常に似ていますが、この「他のハンドラー」はどこから来たのでしょうか。 そして、このファイルで何かをするスレッドを持つ他のスレッドはありませんか?



原因は、SysInternalsとそのProcessMonitorのおかげです。 それを開始し、問題のあるファイルにフィルターを設定し、長く永続的にそれを再現しようとします。 再現します。 見ます。 そして、そこに何が見えますか?

01.2:30:28.3162097 PM our_prog.exe 1288 CreateFile our.file SUCCESS目的のアクセス:一般的な読み取り/書き込み

02. 2:25:28.3164513 PM our_prog.exe 1288 WriteFile our.file SUCCESSオフセット:0、長さ:898、優先度:通常

...

34.2:25:28.3173405 PM our_prog.exe 1288 WriteFile our.file SUCCESSオフセット:35,290、長さ:1,113

35.2:25:28.3173493 PM our_prog.exe 1288 WriteFile our.file SUCCESSオフセット:36,403、長さ:1,128

36.2:25:28.3173736 PM our_prog.exe 1288 FlushBuffersFile our.file SUCCESS

37.2:25:28.3174212 PM our_prog.exe 1288 WriteFile our.file SUCCESS Offset:0、Length:40,960、

38.2:25:28.3175927 PM Explorer.EXE 1884 QueryBasicInformationFile our.file SUCCESS

39.2:25:28.3176144 PM Explorer.EXE 1884 CloseFile our.file SUCCESS

40.2:25:28.3263642 PM Explorer.EXE 1884 CreateFile our.file SUCCESS必要なアクセス:属性の読み取り、

41.2:25:28.3294990 PM our_prog.exe 1288 CloseFile our.file SUCCESS

42.2:25:28.3351356 PM our_prog.exe 1288 CreateFile our.file SUCCESS目的のアクセス:属性の読み取り、削除、

43.2:25:28.3351856 PM our_prog.exe 1288 QueryAttributeTagFile our.file SUCCESS属性:A、ReparseTag:0x0

44.2:25:28.3352020 PM our_prog.exe 1288 SetDispositionInformationFile our.file SUCCESS Delete:True

45.2:25:28.3352218 PM our_prog.exe 1288 CloseFile our.file SUCCESS

46.2:25:28.3358275 PM our_prog.exe 1288 CreateFile our.file DELETE PENDING目的のアクセス:一般的な読み取り/書き込み、

47.2:25:28.3362207 PM our_prog.exe 1288 CreateFile our.file DELETE PENDING必要なアクセス:一般的な読み取り/書き込み、

48.2:25:28.3367696 PM Explorer.EXE 1884 QueryBasicInformationFile our.file SUCCESS

49.2:25:28.4279152 PM Explorer.EXE 1884 CloseFile our.file SUCCESS

50.2:25:28.4282859 PM Explorer.EXE 1884 CreateFile our.file NAME NOT FOUND望ましいアクセス:属性の読み取り、

...

83.2:25:29.3497760 PM our_prog.exe 1288 CreateFile our.file SUCCESS目的のアクセス:一般的な読み取り/書き込み、
そして、次のように表示されます(混乱しないように、余分なデータが削除されました)。 1行目から36行目-ファイルを作成し、書き込み、フラッシュを行います。 最も興味深いのは38〜40行目です。 Explorer.exeが表示され、ファイルの読み取りが開始されます。



41行目で、ファイルを閉じます。 42行目-削除。 そして、explorer.exeはまだそれを読んでいるので、ファイルは削除されません。 一時ファイルの名前をメインファイル(SUCCESSではなくDELETE PENDINGステータス)に変更しようとすると、46行目と47行目に表示される内容。



Explorer.exeは行49でのみ読み取りを終了します。その時点でのみファイルが物理的に削除されます(行50が間接的に、永続的なexplorer.exeが再び読み取り用にファイルを開こうとしますが、もはや)。



これから何が続きますか? Microsoft Windowsのおかげで、単純なファイル削除操作でさえ、偏執的なプログラミングのスタイルで行う必要があります。 削除機能を呼び出し、OKが返されることを確認し、「ファイルが物理的に削除されるまで」待機サイクルに入りました。 まあ、はい、「彼女はネオンを持っている」ことを知らずに、ほとんど何もすることができません...



しかし今、そのようなアプローチが一般に受け入れられている慣行であると私は疑っています。 Windowsでファイルを操作する際に、OSがいつでもユーザーの知らないうちにファイルを処理することを決定し、これに耐えるコードを作成することを念頭に置いてください。 これに関連して、調査は低くなります。



All Articles