Backup session file in case of its corruption

It could be, in certain unknown circumstances, the session file (session.xml) is saved with the incorrect characters (for example NUL characters) which leads session file corrupted and empty session loaded on the next launch. This commit makes a backup of session file before rewritting it, then check the session file after it having been writting - if written session file is corrupted, the backup session file will be restored, otherwise the backup file will be removed.

Ref:
1. https://github.com/notepad-plus-plus/notepad-plus-plus/issues/6133#issuecomment-1121781830
2. https://github.com/notepad-plus-plus/notepad-plus-plus/issues/6133#issuecomment-1544703701

Fix #13514, close #13648
This commit is contained in:
Don Ho 2023-05-12 11:18:34 +02:00
parent 34186d2e85
commit 50b81eadef
2 changed files with 50 additions and 4 deletions

View File

@ -47,7 +47,15 @@ Win32_IO_File::Win32_IO_File(const wchar_t *fname)
pathAppend(nppIssueLog, issueFn); pathAppend(nppIssueLog, issueFn);
std::string msg = _path; std::string msg = _path;
if (_hFile != INVALID_HANDLE_VALUE)
{
msg += " is opened."; msg += " is opened.";
}
else
{
msg += " failed to open, CreateFileW ErrorCode: ";
msg += std::to_string(::GetLastError());
}
writeLog(nppIssueLog.c_str(), msg.c_str()); writeLog(nppIssueLog.c_str(), msg.c_str());
} }
} }

View File

@ -3434,9 +3434,18 @@ void NppParameters::insertScintKey(TiXmlNodeA *scintKeyRoot, const ScintillaKeyM
void NppParameters::writeSession(const Session & session, const TCHAR *fileName) void NppParameters::writeSession(const Session & session, const TCHAR *fileName)
{ {
const TCHAR *pathName = fileName?fileName:_sessionPath.c_str(); const TCHAR *sessionPathName = fileName ? fileName : _sessionPath.c_str();
TiXmlDocument* pXmlSessionDoc = new TiXmlDocument(pathName); // Backup session file before overriting it
TCHAR backupPathName[MAX_PATH]{};
if (PathFileExists(sessionPathName))
{
_tcscpy(backupPathName, sessionPathName);
_tcscat(backupPathName, TEXT(".inCaseOfCorruption.bak"));
CopyFile(sessionPathName, backupPathName, FALSE);
}
TiXmlDocument* pXmlSessionDoc = new TiXmlDocument(sessionPathName);
TiXmlDeclaration* decl = new TiXmlDeclaration(TEXT("1.0"), TEXT("UTF-8"), TEXT("")); TiXmlDeclaration* decl = new TiXmlDeclaration(TEXT("1.0"), TEXT("UTF-8"), TEXT(""));
pXmlSessionDoc->LinkEndChild(decl); pXmlSessionDoc->LinkEndChild(decl);
@ -3530,7 +3539,36 @@ void NppParameters::writeSession(const Session & session, const TCHAR *fileName)
} }
} }
} }
pXmlSessionDoc->SaveFile();
bool sessionSaveOK = pXmlSessionDoc->SaveFile();
if (sessionSaveOK)
{
// Double checking: prevent written session file corrupted while writting
TiXmlDocument* pXmlSessionCheck = new TiXmlDocument(sessionPathName);
sessionSaveOK = pXmlSessionCheck->LoadFile();
delete pXmlSessionCheck;
}
if (!sessionSaveOK)
{
if (backupPathName[0]) // session backup file exists, restore it
{
_pNativeLangSpeaker->messageBox("ErrorOfSavingSessionFile",
nullptr,
TEXT("The old session file will be restored."),
TEXT("Error of saving session file"),
MB_OK | MB_APPLMODAL | MB_ICONWARNING);
CopyFile(backupPathName, sessionPathName, FALSE);
}
}
else
{
if (backupPathName[0]) // session backup file not useful, delete it
{
::DeleteFile(backupPathName);
}
}
delete pXmlSessionDoc; delete pXmlSessionDoc;
} }