【不具合】排他処理されたファイルが読み込みできない

  1. 毎日Meryを便利に使用させていただいております。便利なソフトの提供有り難うございます。

    さて、タイトルの件についてですが、ロックされたファイルを開くとおかしなデータが表示されることに気付きました。
    Windows7 x64上で、以下のようなWin32/C言語コードで他プロセスからの書き込みをロックしたログファイルに書き出しを行うプログラムを使用しています。

    FILE* fp=fopen("log.txt","w");
    OVERLAPPED ov={0};
    LockFileEx((HANDLE)_get_osfhandle(_fileno(fp)), LOCKFILE_FAIL_IMMEDIATELY | LOCKFILE_EXCLUSIVE_LOCK, 0, -1, -1, &ov );    /* 全部ロック */

    処理の途中経過の確認のためログファイルを開くと、メモ帳では正しく表示されるのですが、Meryでは想定した内容が表示されません。
    代わりに何かの設定ファイルや、バイナリデータが表示されます。
    Meryの内部メモリが見えてしまっているように思えますが、いずれにせよ、開くタイミングにより表示されるデータは変わります。

    ご確認のほどよろしくお願いいたします。

     |  Claybird  |  返信
  2. Mery をご愛用くださりありがとうございます。

    ご報告いただいた件ですが、C 言語の知識 (と環境) がないため同様のプログラムを実行することができませんが、Delphi でも Windows API が呼び出せますので LockFileEx を実行してロックをかけた状態で確認してみましたところ、通常通りテキストファイルを開くことができました。(Mery 2.2.0.4910 + Windows 7 x64)

    保存しようとすると「他のプロセスが使用中です」と、想定内の挙動をしております。

    Claybird さんと同様の環境で検証できれば調査しやすいのですが、現状、これ以上の検証ができない状態です。

    現象が再現できるコンパイル済みの exe でもいただければ助かるのですが・・・

     |  Kuro  |  返信
  3. 再現条件の洗い出しの過程で気付いたのですが、先日の条件だけでは不十分でした。失礼しました。
    ログには書き込みバッファ無しでのファイル出力を行っているのですが、これとファイルロックの両方が無ければ問題が再現できないようです。

    問題が再現できるCコードおよびexeを用意いたしました。
    http://claybird.sakura.ne.jp/mery_test.zip
    このコードを用いて、Windows 7 x64およびWindows XPで問題が再現されることを確認しました。
    ご確認のほどよろしくお願いいたします。

     |  Claybird  |  返信
  4. ご報告ありがとうございます。
    再現できるコード、ありがとうございます。お手数をおかけします。

    頂いたサンプルで現象が再現することを確認しました。
    早速調査してみます。

     |  Kuro  |  返信
  5. 早速の反応有り難うございます。
    お時間のあるときで結構ですので、よろしくお願いいたします。

     |  Claybird  |  返信
  6. こんばんは、書き込みありがとうございます。
    調査していると日曜日が終わってしまいましたorz と、同情を誘ってごまかすつもりはありませんが、このテーマは重いです!そもそも Windows の排他モードってほんとにちゃんと動いているの!っていう・・・、でも、まあ調べていると面白くてつい時間を忘れて調査してしまいました。

    一応、調査完了 (というか挫折・・・なのかもしれませんが) しましたのでご報告いたします。
    結論から申しますと、これ、アカンわ・・・。せっかくテスト用のプログラムまでご用意してくださったのに、ご希望の動作が実現できなくて申し訳ないのですが、現状、下記のような状況だと判断いたしました。

    LOCKFILE_EXCLUSIVE_LOCK と書き込みバッファ無しのケースにおいて、通常、テキストエディタの動作はどうなるのか?いくつかのテキストエディタで試してみました。

    notepad.exe -> 普通に開くことができる
    wordpad.exe -> アクセス禁止で開くことすらできない
    Windows の type コマンド -> アクセス禁止で開くことすらできない
    真魚 -> 内部メモリが見える感じの表示 (エンジンが同じなので Mery と同じ)
    秀丸 -> アクセス禁止で開くことすらできない
    EmEditor -> アクセス禁止で開くことすらできない
    サクラエディタ -> アクセス禁止で開くことすらできない
    NotePad++ -> アクセス禁止で開くことすらできない
    SynEditor -> アクセス禁止で開くことすらできない
    K2Editor -> アクセス禁止で開くことすらできない

    若干サンプル数が少ないかもしれませんが、LOCKFILE_EXCLUSIVE_LOCK  と書き込みバッファ無しのケースは、排他制御により開くこと自体が禁止されているべきなのではないかと見受けられました。

    Mery ではファイルを開くときの処理で Windows の API の CreateFile を使用しておりますが、さまざまな引数を試してみましたがファイルを開くことすらできない状態でした。
    (Mery の開発環境の Delphi だと、ファイルを開くことはできないものの、共有モードの引数で FILE_SHARE_READ | FILE_SHARE_WRITE を指定すればファイルのサイズだけは返ってきてる感じで、内部的には開くことができたと認識されてるようでした)

    なので、notepad.exe が内部的にどういう原理で開くことができているのかは分りませんが、今回のケースでは開くことができない方が正しいのではないか、という結論に達しました。特に、wordpad.exe でも開くことができない点を考慮してのことですが。

    ただ、Mery ではおっしゃるとおり内部メモリが見える感じになっていましたので、ここの部分のみを修正する感じになると思います。

    notepad.exe のように、排他モードでアクセス禁止で書き込みバッファ無しのファイルにアクセスできる機能を作ることは現状できそうにありませんでした。(方法があればぜひ知りたいところではありますが、それって Windows のバグじゃないの?って思うほどのレベルですw)

    次バージョンでは、内部メモリが見えちゃう現象のみ回避するような修正になると思います。色々お手数をおかけしてしまい、ご希望の動作が実現できず申し訳ない限りですが、ご了承いただければ幸いです。

     |  Kuro  |  返信
  7. こんばんは。
    貴重なお時間を使って調査していただき有り難うございます。

    > 結論から申しますと、これ、アカンわ・・・。(略)
    > 若干サンプル数が少ないかもしれませんが、LOCKFILE_EXCLUSIVE_LOCK  と書き込みバッファ無しのケースは、排他制御により開くこと自体が禁止されているべきなのではないかと見受けられました。

    確かに、"LOCKFILE_EXCLUSIVE_LOCK"という名前からすれば、本来は開けないのが正解ですね。
    MSDNにも「ロックされた領域を読み書きできなくなります」と書いてありますし、エクスプローラでもファイルコピーすら拒否されます。
    Notepadの謎挙動が際だちます。

    …と思っていたら、昔使っていたGreenPadというエディタがNotepadと同じように開けることを発見しました。
    ソースを見たところ、キモはメモリにマッピングする、という処理のようです。
    CreateFileでとりあえずファイルを開いたら、そのあとCreateFileMappingでファイルマッピングをすれば読み出せるようです。
    私も長らくCreateFile + ReadFileを使っていたので、こんな回避手段があるとは知りませんでした。

    とはいえ、そもそも開けなくて当たり前のファイルなので、
    > 次バージョンでは、内部メモリが見えちゃう現象のみ回避するような修正になると思います。
    でも全く問題ありません。
    とりあえず、ご参考までに。

     |  Claybird  |  返信
  8. こんばんは、返信ありがとうございます。

    GreenPad、見てみました。確かに開くことができますね、コレ!しかもソースが公開されているんですね、ありがたや。

    CreateFileMapping を使用してみたところ、あっさり開くことができました。

    私はてっきりメモ帳が Windows の隠し機能みたいなものを使って開くことができるような特殊な設計になっているものかと思っておりましたが、CreateFileMapping を使用すれば技術的に可能なんですね。

    そうなってくると話は別、メモ帳で開くことができてて技術的に可能なのであればそれに準拠しても良いんじゃないかと思い始めました。(他のテキストエディタではできないけど、Mery でできるというのはメリットにもなりますし)

    でも、ほんとは開いちゃダメなのかな・・・。

    貴重な情報ありがとうございました。
    たぶん次のバージョンでは開くことができるようになってると思います。

     |  Kuro  |  返信
  9. おぉ、対応していただけるとなると、かゆいところに手が届く感じになって、とてもありがたいです。
    メモ帳もCreateFileMappingを呼んでいるようですし、同じ手法でAPIの手順通りにやっているので、開いてしまって問題ないと思います。

    次のバージョンを楽しみに待たせていただきます。ありがとうございました。

     |  Claybird  |  返信
  10. 件の排他とは違うんだけど
    書き込み禁止フラグ付きのファイル開いておいて、
    禁止フラグ解除して
    読み込み直しても(=ファイル→読み直し)フラグの変更反映されないのね
    フラグの変更が反映されるようになるといいな(はあと

     |  クリ廃止  |  返信