

Windows
APIのCreateFileMapping()/MapViewOfFile()でファイルの読み出しをする場合で、他プロセスからの書き込みや削除がありうる状況(それらを妨げてはならない状況)での処理について質問します。

  1. MapViewOfFile()で取得したポインタでファイルの内容にアクセスしたとき、その直前までに他のプロセスがファイルを削除したりファイルを切り詰めたりしてその位置に相当するファイルのデータがなくなっていた場合、何が起こりますか? CreateFileMapping() にPAGE_READONLY、PAGE_READWRITE、PAGE_WRITECOPY のいずれを渡すかで違いはありますか? なお、当プロセスでCreateFileMapping()に渡すハンドルをCreateFile()で作成したとき、`FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE`を指定した(他プロセスからの書き込みや削除を許す旨指定した)ものとします。
  2. 私の予想は「削除されても何も起こらず正しく読み込まれるが、切り詰められたときはEXCEPTION_IN_PAGE_ERRORの構造化例外が発生する」ですが、EXCEPTION_IN_PAGE_ERROR は C++の`try {} catch (...) {}`ではキャッチできず、SEHを使うしかありませんか?
  3. このような状況ではVSSを使うのが適切なのかも知れません。VSSでスナップショットを取得してからCreateFileMapping()を使用する場合、ファイルをいったんコピーする必要がありますか? パフォーマンスが重要なため、コピーは避けたいと思っています。

追記: そもそも「削除できない」ということが判明しました。検証用コードを追記します。

[code]

    #include <iostream>
    #include <string>
    #include <atlbase.h>
    #include <atlconv.h>
    
    #define USE_MMAP
    
    int main()
    {
        static const _TCHAR filename[] = _T("test.txt");
        static const char dummydata[] = "abcdefghijklmnopqrstuvwxyz";
    
        const auto hCreate = ::CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
        ATLENSURE(hCreate != INVALID_HANDLE_VALUE);
        DWORD dwWritten;
        for (int i = 0; i < 10000; ++i) ATLENSURE(::WriteFile(hCreate, dummydata, sizeof(dummydata) - 1, &dwWritten, NULL) && dwWritten == sizeof(dummydata) - 1);
        ATLENSURE(::CloseHandle(hCreate));
    
    
        const auto hFile = ::CreateFile(filename, GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        ATLENSURE(hFile != INVALID_HANDLE_VALUE);
    #ifdef USE_MMAP
        const auto hMap = ::CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
        ATLENSURE(hMap != NULL);
        const auto pMap = (LPCSTR)::MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
    #endif
    
        std::string cmd = std::string("del ");
        cmd += CT2A(filename);
        system(cmd.data()); // アクセスが拒否されました。
    
    #ifdef USE_MMAP
        std::cout << pMap[10000] << std::endl;
    #endif
    }
    
[/code]


CC BY-SA 4.0
2021-05-21T19:27:02.030
76001
2021-05-24T00:52:27.207
2021-05-24T00:52:27.207
45446
45446
question
c++ winapi
File Mappingでのアクセス中に他から削除された場合などについて