2006 年 11 月 2 日 22 時 39 分

ファイルパスの拡張表現


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


いよいよ、保留にしていたパスについて考えてみる。
GetVolumeNameForVolumeMountPoint が返却したパスは、
以下のような形式であった。

\\?\Volume{f08e7d20-64f1-11db-b10d-001125868411}\

実は、これもファイルのパス表現なのである。

最初に \\ と並んでいるので、UNC パスにも見えるが、
「?」というサーバに接続するわけではない。
では、上記のパスはどのように解釈されるのか。

昨日、ファイルパスは内部で正規化が行われた後、
DOS デバイス名前空間(??)のパスとして扱われると書いた。

ところが、先頭に「\\?\」をつけたパスを指定すると、
あらゆる正規化が抑制され、\\?\ を取り除いた結果が、
そのまま ?? 配下のデバイスパスとして扱われるのである。

例えば、?? には、PhysicalDrive0 という名前がある。
これは最初のハードディスクを示す MS-DOS デバイス名だ。
このハードディスクを直接読もうとしても、
通常のパスではうまくいかない。

「PhysicalDrive0」というファイルパスを指定しても、
正規化の段階で、普通の相対パスと解釈されてしまい、
「C:\Documents and Settings\kes\PhysicalDrive0」
などに正規化され、ただのファイルを指し示してしまう。

しかしながら、拡張表現を使えば、
「\\?\PhysicalDrive0」というファイルパスで表せる。
これは正規化されず「PhysicalDrive0」として扱われ、
「\??\PhysicalDrive0」というデバイスパスとなり、
最終的に「\Device\Harddisk0\DR0」等となる。

つまり、この拡張表現を使えば、MS-DOS デバイス名を
直接指定したアクセスができることになる。
冒頭のパスは、拡張表現を使うことで、より直接的に
?? デバイス名前空間にあるボリュームを示していたのだ。

さて、拡張表現を使うと、通常のパスでは示せない
色々なデバイスにアクセスできるので便利ではあるが、
大いな危険性をはらんでいることでもある。

ユーザが自由にファイル名を指定可能なシステムで、
上記の拡張表現を使ったパスを指定した場合、
そのパスを受け取って処理するプログラムが、
予期せぬデバイスにアクセスしてしまう危険性がある。

というのも、プログラマからしてみると、
パスをファイルアクセス用 APIに渡すだけだ。
例え変なファイル名が渡されたとしても、
「ファイルが見つからない」エラーが返るだろうと考える。
ところが、それが思わぬ挙動を引き起こす

例えば、上記で例示した物理ドライブは、
「\\?\PhysicalDrive0」というファイルパスで開ける。
デバイスを、ファイルと同じように開けてしまうのである。

万が一、これを書き込みアクセスで開き、
適当にデータを書き込んでしまうと、
マスターブートレコードを破壊することになる。

読み込みアクセスの場合は問題ないと思うかもしれないが、
ハードディスク全体を表す巨大なデータ(ファイル)なので、
指定したファイルをメモリに読み込むようなプログラムなら、
確実にメモリを食いつぶしてクラッシュするだろう。

Windows のユーザ権限を適切に設定していれば、
デバイスへの書き込みや、物理ディスクのアクセスは、
デバイスの持つアクセス権限で拒否されるのだが、
Windows では往々にして管理者権限が使われているので、
根本的な解決策にはならない。

なお、Windows でファイル名を指定させる場合、
コモンダイアログと呼ばれる専用のダイアログを使うが、
このコモンダイアログは、ファイルパスとして、
拡張表現を使えないように配慮がなされている。

ファイル名を扱うプログラムには、
このような配慮が必要なのである。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.