番外編 ファイルシステムドライバ嵌まり所

ファイルシステムドライバを作っていて嵌まったところを一覧にしておきます。

DIRコマンドのファイル指定やワイルドカードが効かない

IRP_MJ_DIRECTORY_CONTROL→IRP_MN_QUERY_DIRECTORYの時には、IRPスタックポインタにファイルパターン(例えば*.txt等)が入っています。 場所はirpSp->Parameters.QueryDirectory.FileNameです。

IRP_MJ_QUERY_VOLUME_INFORMATIONやIRP_MJ_QUERY_INFORMATIONで渡されたバッファサイズが小さい

ファイル名など使う気のない所のバッファを確保しないでコールされるのは仕様通りです。 この場合、バッファに書けるだけ書いてSTATUS_BUFFER_OVERFLOWを返し、Informationには書けたバイト数を入れるのが正解です。

ファイル検索が上手く行かない

複数返すモードと一つだけ返すモードがあります。 irpSp->FlagsにSL_RETURN_SINGLE_ENTRYが立っているときは1つだけ、そうでないときは複数を返してください。 また、バッファに入りきらない場合は入る範囲で書いてSTATUS_SUCCESS(STATUS_BUFFER_OVERFLOWではない)を返し、再度コールされたときに続きを送ります。 バッファが小さくて1つも返せないときはSTATUS_BUFFER_TOO_SMALLを返します。 最後まで列挙を終えたために1つも返せないときはSTATUS_NO_MORE_FILESを返します。 なお、irpSp->FlagsにSL_RESTART_SCANが立っているときは列挙を最初からやり直します。

複数返すモードの時にはNextEntryOffsetを入れてください。 また、今回のIRPで返す最後のファイルに対してはNextEntryOffsetを入れないでください(0にする)。

NT3.xのファイル選択で該当拡張子のないディレクトリを選択するとツリーが消える

1つ以上のファイルがあるときに列挙が完了したときに返すべきステータスはSTATUS_NO_MORE_FILESですが、該当するファイルが1つもないときに返すべきステータスはSTATUS_OBJECT_NAME_NOT_FOUNDです。 これを間違えるとツリー自体の表示が消えることがあります。

メモ帳での表示やEXE実行を行うとCREATEしっぱなしになって溜まっていく

SectionObjectPointerの実装を間違えるとこのような挙動になります。 例えば、ファイル単位で共通なのにCREATE毎に毎回新規生成していると挙動がおかしくなります。 これを簡単に実装するminisop.c, minisop.hというものを作りました。よろしければご利用ください。

メモ帳でファイルが開けない・保存されない・COPY CONが正しく動かない・EXEが実行できない・CREATEしっぱなしになる等

メモリマップトファイルとキャッシュが正しく動いていないとこのような状況になります。 キャッシュの実装は全然情報が無く正しい実装がよく分からない上に、下手に使うとむしろ状況が悪化します。 そこで極力キャッシュを有効にしないようにしつつ、メモリマップトファイルを正しく動かせるようにしたminisop.c, minisop.hというものを作りました。よろしければご利用ください。

ファイルの削除はどうやるのか

ファイルの削除はDeleteというコマンドがあるわけでは無く、Createで開いたファイルにIRP_MJ_SET_INFORMATIONで削除のマークを付け、CLOSEでファイルを閉じたときに削除という流れになります。 なお、Createで開くときに「Close時に削除する」という属性もあります。

CLOSEしていないファイルを開きに来る

IRP_MJ_CLEANUPが来た段階で実質的にファイルは閉じてファイルロックは解除してください ただし、IRP_MJ_CLEANUPの後でCLOSEせずにREAD/WRITE等が来ることもあります。 その場合は、一時的に開き直すなどして応答してください。

ファイルへのパスなのにディレクトリのつもりでCreateしてくる

Createの時、irpSp->FlagsにSL_OPEN_TARGET_DIRECTORYの指定がある場合は、パスからファイル名を除去したディレクトリを開いてください。例えば、SL_OPEN_TARGET_DIRECTORYフラグ付きでA:\AAA\BBB\CCC.TXTと指定されてきた場合は、A:\AAA\BBBを開いてください。

サブディレクトリなのにルートディレクトリの時のようにファイル名を指定してくる

Createの時、FileObject->RelatedFileObjectがNULLでない場合はFileObject->RelatedFileObjectで指定されたFileObjectのパスを起点にしてファイル名を指定します。

ファイル表示の自動更新が動かない

IRP_MJ_DIRECTORY_CONTROL→IRP_MN_NOTIFY_CHANGE_DIRECTORYを実装すれば更新されるようになります。 ただし、このIRPは使い方が特殊で、ファイル更新があったときにIRPを完了(IoCompleteRequest)させる仕組みになっています。 これを実装しようとするとコードの複雑化は避けられないと思います。 いっそ手動更新を前提にして実装しないというのも選択肢です。

仮想ファイルシステム上のパスを作業ディレクトリにしてプログラム起動すると変

IRP_MJ_CREATE時に異常なパスが渡されたときに返すステータスが不正確だとおかしくなることがあります。 ワイルドカードが含まれているなどパスとして異常な時はSTATUS_OBJECT_NAME_INVALID、パスとして正しいがファイルがないときにはSTATUS_OBJECT_NAME_NOT_FOUNDを返してください。 また、オープン成功時にはInformationの値も正確に返してください。

Officeでデータを保存しようとすると失敗する

IRP_MJ_LOCK_CONTROLで未実装などのエラーを返すとファイル保存が機能しません。 とりあえず動けばいいということであれば、IRP_MJ_LOCK_CONTROLは常に成功したことにしましょう。

最小構成の仮想ファイルシステムドライバの製作に戻る

資料集に戻る

トップに戻る