C 言語ファミリをルーツとし、コンポーネント指向プログラミングのサポートを含む、オブジェクト指向およびタイプセーフのプログラミング言語。
解析結果
SetFileInformationByHandleに以下のFILE_RENAME_INFOを渡したとする
#SetFileInformationByHandle : FILE_RENAME_INFO
01 00 00 00 00 00 00 00 44 00 00 00 00 00 00 00
20 00 00 00 2E 00 5C 00 54 00 65 00 73 00 74 00
31 00 39 00 32 00 35 00 32 00 34 00 2E 00 74 00
78 00 74 00
これはRootDirectoryが0x44で、 FileNameは文字数が0x20の./Test192524.txtである。(ReplaceIfExistsはtrue)
SetFileInformationByHandleはいくつか処理したのちにNtSetInformationFileを呼び出しているが、NtSetInformationFileへ渡されるFILE_RENAME_INFORMATIONは以下のようになってしまっている。
これはRootDirectoryが0x44で、 FileNameは文字数が0x56の\??\D:Test\bin\Debug\net481\Test192524.txtである。
#NtSetInformationFile : FILE_RENAME_INFORMATION
01 00 00 00 0D F0 AD BA 44 00 00 00 00 00 00 00
56 00 00 00 5C 00 3F 00 3F 00 5C 00 44 00 3A 00
5C 00 54 00 65 00 73 00 74 00 5C 00 62 00 69 00
6E 00 5C 00 44 00 65 00 62 00 75 00 67 00 5C 00
6E 00 65 00 74 00 34 00 38 00 31 00 5C 00 54 00
65 00 73 00 74 00 31 00 39 00 32 00 35 00 32 00
34 00 2E 00 74 00 78 00 74 00
SetFileInformationByHandleの逆アセンブラを追っていくと、受けとった引数をFILE_RENAME_INFORMATIONに変換してNtSetInformationFileを実行している。
引数チェックが通ったら元のファイル名がドライブレターを含んでいなければRtlDosPathNameToNtPathName_U_WithStatus関数でNTパスに変換されている。
この変換により相対パスが絶対パスに変換されている。
(RtlDosPathNameToNtPathName_U_WithStatusではカレント基準で絶対パスに変換されているかもしれない)
注目するのはFILE_RENAME_INFOのRootDirectoryがそのままコピーされてしまっているということと、RtlDosPathNameToNtPathName_U_WithStatusが1文字の判定のみで変換が行われていること。
なお、NtSetInformationFileでブレークさせて、FILE_RENAME_INFORMATIONのFileNameを相対パス文字列に書きかえると想定したとおりにRootDirectory以下に移動されました。
結論
SetFileInformationByHandleの現在の実装はFILE_RENAME_INFORMATIONに対して
- RootDirectoryにNULLを設定する方法がない
- FileNameに絶対パスを渡す場合RootDirectoryはNULLにしなければならない決まりとなっているのに RootDirectoryが設定されている。
- フルパスへの変換の判定が手抜きであること。
によりこの問題が発生しているのである。
多分バグ
現状では、RootDirectoryを0にすることを忘れているのか、間違ってフルパスに変換してしまっているのかのどちらかは判断がつきません。
回避方法
SetFileInformationByHandleでRootDirectoryを使わない
- 絶対パスを指定する。
- SetFileInformationByHandleを使わずにNtSetInformationFileを直接使う
FullTrustでNtSetInformationFileつかえるかは、コミュニティーサポートではどうなるかは公式情報ではないのであてにはなりません。
最小限の機能の非公開アプリを作ってNtSetInformationFile使ってますという説明を書いて申請して試すか、有料チケット使って公式に質問するしかないと思う。
# アプリローカルではなくグローバルにディスクアクセスするようなアプリは判定が厳しくなるだろうし