4

While working with the OpenXcom app, I noticed that at some point the app stopped updating the options.cfg file. I tracked this issue down to a failure creating an ofstream object for the options.cfg file in the Options::save() method. A search uncovered no explanation for my issue. The only solution I could find was to delete the options.cfg file and let the program recreate it with the default settings.

I have recreated what appears to be a similar issue with a very simple C++ program (modeled on the first few lines of the Options::save() method in the OpenXcom project):

#include <iostream>
#include <fstream>

void check(const std::string& filename)
{
    std::ofstream stream(filename.c_str());

    if (!stream) {
        std::cout << "FAIL " << filename << std::endl;
    }
    else {
        std::cout << "PASS " << filename << std::endl;
    }
}

int main()
{
    check("options1.cfg");
    check("options2.cfg");
}

Using this test program, I created the following test case using the Command Prompt:

  • Create a directory containing only the test program.
  • Run the test program to create two empty .cfg files.
  • Run the test program again to verify that the program can still work with both .cfg files.
  • Delete options2.cfg
  • Copy options1.cfg to options2.cfg
  • Run the test program again. Now the program can no longer create an ofstream object for the options2.cfg file.

Here is Command Prompt listing for the test case (which I have edited a bit to remove extraneous information):

C:\...\test>dir

12/19/2022  09:10 AM            27,648 ofstream-test.exe

C:\Users\jwlent\Documents\test>ofstream-test.exe
PASS options1.cfg
PASS options2.cfg

C:\...\test>dir

12/19/2022  09:10 AM            27,648 ofstream-test.exe
12/19/2022  02:39 PM                 0 options1.cfg
12/19/2022  02:39 PM                 0 options2.cfg

C:\...\test>ofstream-test.exe
PASS options1.cfg
PASS options2.cfg

C:\....\test>del options2.cfg

C:\....\test>copy options1.cfg options2.cfg
        1 file(s) copied.

C:\...\test>dir

12/19/2022  09:10 AM            27,648 ofstream-test.exe
12/19/2022  02:39 PM                 0 options1.cfg
12/19/2022  02:39 PM                 0 options2.cfg

C:\....\test>ofstream-test.exe
PASS options1.cfg
FAIL options2.cfg 

Other things I noted:

  • Closing the Command Prompt console and creating a new one did not change the result (i.e. allow the test program to create an ofstream object for the options2.cfg file).
  • Closing the Command Prompt console and creating a new one with Admin authority did not change the result.
  • A restart of my laptop did clear the issue. Since a restart clears the issue, that would indicate that there is nothing wrong with the file permissions.
  • There are several other ways to create this issue. For example, manually creating the files using any editor.
  • I used VS 2022 on a Win 10 laptop to create the test program.

Can anyone explain what may be going on? Especially if there is a way to modify the test program to work around this issue in a way that can be applied to the Options::save() file in the OpenXcom project.

A few more observations:

  • The problem can persist for many hours (overnight).
  • While the problem persists, Python has no problem writing to the file from the same Command Prompt.

Here is the slightly edited Command Prompt output.

C:\...\test>ofstream-test.exe
PASS options1.cfg
FAIL options2.cfg
    
C:\...\test>python
Python 2.7.18 (v2.7.18:8d21aa21f2, Apr 20 2020, 13:25:05) [MSC v.1500 64 bit (AMD64)] on win32
>>> f = open("options2.cfg", "w")
>>> f.write("overwrite")
>>> f.close()
>>> exit()
    
C:\...\test>ofstream-test.exe
PASS options1.cfg
FAIL options2.cfg
    
C:\...\test>more options2.cfg
 overwrite

Here is what Process Monitor recorded for the C++ program and then Python trying to open the file for write:

46:23.0 ofstream-test.exe 22396 CreateFile C:\Users\jwlent\Documents\test\options2.cfg ACCESS DENIED Desired Access: Generic Write, Read Attributes, Disposition: OverwriteIf, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: 0

46:39.9 python.exe 3000 CreateFile C:\Users\jwlent\Documents\test\options2.cfg SUCCESS Desired Access: Generic Write, Read Attributes, Disposition: OverwriteIf, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: 0, OpenResult: Overwritten

James Lent
  • 99
  • 1
  • 4
  • 5
    I've tried replicating this and unfortunately I wasn't able to. My wild guess here is that this has something to do with file permissions on your system. I have other wild guesses but unfortunately without replicating this error I can't help you. EDIT: Have you tried disabling your antivirus? I once used to have similar problems with Avast AV. Had to fiddle with the config files for it to work properly. – Milan Š. Dec 19 '22 at 21:21
  • 3
    use sysinternals procmon tool to see all the file io the ap does – pm100 Dec 19 '22 at 21:53
  • 2
    I would guess that the `.cfg` file in question is likely open somewhere else (ie, probably an antivirus/antimalware, etc), and that open handle doesn't share write access to the file. That would explain why creating a new `ofstream` to the same file right away after creating/copying it is failing until you reboot the machine and then create the `ofstream` without first opening/creating the file again. If the test fails, try waiting a few seconds and try again, maybe the file will have been released by then. – Remy Lebeau Dec 19 '22 at 22:22
  • Thanks for the suggestions. I played around with both the Process Monitor and the Process Explorer tools. I have found no indication of any other process having access to the "options2.cfg" file. I will try turning off antivirus code later. I saved the raw Process Monitor data if anyone is interested. – James Lent Dec 20 '22 at 12:51
  • Not solved exactly, but better understood. I finally noticed that the problem only occurred under certain directory patterns. Specifically it fails in at least the following cases "C:\Users\*\Documents" and "C:\Users\*\Desktop". I then stumbled across something called "Protected Directories". I could not create the problem under "C:\junk". But if I added that directory (including "sub folders") to "Protected Directories" the problem started occurring there too. And when I removed that setting the problem went away. – James Lent Dec 21 '22 at 21:00
  • Protected Directories appear to be a Windows Defender feature. I am actually using Norton but it also seems to support the concept. I need to research it a bit more. OpenXcom writes its configuration file to a folder under "Documents" so with my setup it can trigger this issue. – James Lent Dec 21 '22 at 21:02
  • For Windows OpenXcom will search for the options.cfg file in three different locations. The last choice is the one explicitly under "Documents". Adding a directory named "user" under "..\OpenXcom\bin\Win32\" will trigger the application to find/create the options.cfg file there instead. With that change to the source code installation I can now run OpenXcom in debug mode (via VS) and swap in and out different versions of the options.cfg file without running into a write issue. Assuming of course the source code installation is itself not under a "Protected Folder". – James Lent Dec 22 '22 at 21:53

0 Answers0