From c730e5d70aa6db2bb3be1cf226be8d4499dcaf1b Mon Sep 17 00:00:00 2001 From: krcroft Date: Thu, 23 Jan 2020 17:46:03 -0800 Subject: [PATCH] Permit the use of protected game data files Many DOS games open all their files in write-mode regardless if the game actually intends to write to them or not. This can result the files' metadata being updated (lossing the original date-stamp) as well as putting the file at-risk of corruption if the game crashes with the file open for writing. Under the existing DOSBox implementation, if a user attempts to write-protect their data files then DOSBox will quit with an error in the above scenario. This commit allows the use of write-protected files (similar to running a game from CDROM) and indicates which files are being actively protected against modification. Typically the only files that need to be left writable are those that the game actually changes, such as: save-game files, highscore files, in-game settings, and so on. If these are also protected, then the game will quit/crash immediately after the protected message is printed, and thus indicate which file require write-allowance. --- include/drives.h | 3 +++ src/dos/drive_local.cpp | 55 ++++++++++++++++++++++++++--------------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/include/drives.h b/include/drives.h index daa08c35..dec9f266 100644 --- a/include/drives.h +++ b/include/drives.h @@ -22,6 +22,7 @@ #include "dosbox.h" #include +#include #include #include @@ -75,6 +76,7 @@ public: virtual bool isRemovable(void); virtual Bits UnMount(void); const char* getBasedir() {return basedir;}; + virtual bool isNewWriteProtectedFile(const std::string& filename); protected: char basedir[CROSS_LEN]; struct { @@ -82,6 +84,7 @@ protected: } srchInfo[MAX_OPENDIRS]; private: + std::set write_protected_files; struct { Bit16u bytes_sector; Bit8u sectors_cluster; diff --git a/src/dos/drive_local.cpp b/src/dos/drive_local.cpp index 1fac1aaa..f907046c 100644 --- a/src/dos/drive_local.cpp +++ b/src/dos/drive_local.cpp @@ -62,8 +62,14 @@ bool localDrive::FileCreate(DOS_File * * file,char * name,Bit16u /*attributes*/) return true; } -bool localDrive::FileOpen(DOS_File * * file,char * name,Bit32u flags) { - const char* type; +bool localDrive::isNewWriteProtectedFile(const std::string& filename){ + const std::pair::iterator, bool> \ + ret(write_protected_files.insert(filename)); + return ret.second; +} + +bool localDrive::FileOpen(DOS_File** file, char * name, Bit32u flags) { + const char* type = nullptr; switch (flags&0xf) { case OPEN_READ: type = "rb" ; break; case OPEN_WRITE: type = "rb+"; break; @@ -81,37 +87,46 @@ bool localDrive::FileOpen(DOS_File * * file,char * name,Bit32u flags) { //Flush the buffer of handles for the same file. (Betrayal in Antara) Bit8u i,drive=DOS_DRIVES; - localFile *lfp; - for (i=0;iIsOpen() && Files[i]->GetDrive()==drive && Files[i]->IsName(name)) { lfp=dynamic_cast(Files[i]); if (lfp) lfp->Flush(); } } - FILE * hand = fopen_wrap(newname,type); -// Bit32u err=errno; - if (!hand) { - if((flags&0xf) != OPEN_READ) { - FILE * hmm = fopen_wrap(newname,"rb"); - if (hmm) { - fclose(hmm); - LOG_MSG("Warning: file %s exists and failed to open in write mode.\nPlease Remove write-protection",newname); + FILE* fhandle = fopen(newname, type); + // Was the file was opened with the desired type? + if (!fhandle) { + // No; but do the requested flags require write-access? + if ((flags & 0xf) != OPEN_READ) { + // Yes; maybe the local file is simply be protected, so try again with read-only + fhandle = fopen_wrap(newname, "rb"); + if (fhandle) { + // Ok! so the file is protected file; fool the DOS program into thinking its OK + flags &= ~OPEN_READWRITE; + // Inform the user that the file is being protected against modification. + // If the DOS program /really/ needs to write to the file, it will crash/exit + // and this will be one of the last messages on the screen, so the user can + // decide to un-write-protect the file if they wish. + if (isNewWriteProtectedFile(newname)) { + LOG_MSG("FILESYSTEM: protected from modification: %s", newname); + } } } - return false; } - *file=new localFile(name,hand); - (*file)->flags=flags; //for the inheritance flag and maybe check for others. -// (*file)->SetFileName(newname); - return true; + if (fhandle) { + *file = new localFile(name, fhandle); + (*file)->flags=flags; //for the inheritance flag and maybe check for others. + } + return (fhandle != NULL); } FILE * localDrive::GetSystemFilePtr(char const * const name, char const * const type) {