From 50b81eadefa0aaeeece6e4458f45e9b931191191 Mon Sep 17 00:00:00 2001 From: Don Ho Date: Fri, 12 May 2023 11:18:34 +0200 Subject: [PATCH] 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 --- PowerEditor/src/MISC/Common/FileInterface.cpp | 10 ++++- PowerEditor/src/Parameters.cpp | 44 +++++++++++++++++-- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/PowerEditor/src/MISC/Common/FileInterface.cpp b/PowerEditor/src/MISC/Common/FileInterface.cpp index 0f1506b55..c5062adb8 100644 --- a/PowerEditor/src/MISC/Common/FileInterface.cpp +++ b/PowerEditor/src/MISC/Common/FileInterface.cpp @@ -47,7 +47,15 @@ Win32_IO_File::Win32_IO_File(const wchar_t *fname) pathAppend(nppIssueLog, issueFn); std::string msg = _path; - msg += " is opened."; + if (_hFile != INVALID_HANDLE_VALUE) + { + msg += " is opened."; + } + else + { + msg += " failed to open, CreateFileW ErrorCode: "; + msg += std::to_string(::GetLastError()); + } writeLog(nppIssueLog.c_str(), msg.c_str()); } } diff --git a/PowerEditor/src/Parameters.cpp b/PowerEditor/src/Parameters.cpp index 65f66a46b..59330de22 100644 --- a/PowerEditor/src/Parameters.cpp +++ b/PowerEditor/src/Parameters.cpp @@ -3434,9 +3434,18 @@ void NppParameters::insertScintKey(TiXmlNodeA *scintKeyRoot, const ScintillaKeyM 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("")); 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; }