From e2951174da52ef303980b8a5113436f952ad45a8 Mon Sep 17 00:00:00 2001 From: "Michael J. Seiferling" Date: Fri, 1 Mar 2019 13:53:26 -0600 Subject: [PATCH] Changes for #151 - Pass 1: Functional, needs testing, code slimming and UI fixes --- GBM/Classes/clsGame.vb | 7 +- GBM/Forms/frmMain.vb | 12 +- GBM/Managers/mgrBackup.vb | 354 +++++++++++++++++---------- GBM/Managers/mgrPath.vb | 10 + GBM/Managers/mgrRestore.vb | 225 +++++++++++------ GBM/My Project/Resources.Designer.vb | 63 +++++ GBM/My Project/Resources.resx | 21 ++ 7 files changed, 488 insertions(+), 204 deletions(-) diff --git a/GBM/Classes/clsGame.vb b/GBM/Classes/clsGame.vb index 7c30b7b..3a4f9a8 100644 --- a/GBM/Classes/clsGame.vb +++ b/GBM/Classes/clsGame.vb @@ -112,7 +112,12 @@ Public Class clsGame bAbsolutePath = value End Set Get - Return bAbsolutePath + 'This makes sure a registry key path isn't seen as a relative path. + If mgrPath.IsSupportedRegistryPath(TruePath) Then + Return True + Else + Return bAbsolutePath + End If End Get End Property diff --git a/GBM/Forms/frmMain.vb b/GBM/Forms/frmMain.vb index f17c515..703b50a 100644 --- a/GBM/Forms/frmMain.vb +++ b/GBM/Forms/frmMain.vb @@ -221,10 +221,14 @@ Public Class frmMain bOSVerified = VerifyBackupForOS(oGame, oRestoreInfo.RestorePath) - If mgrRestore.CheckPath(oRestoreInfo, oGame, bTriggerReload) Then + If mgrPath.IsSupportedRegistryPath(oRestoreInfo.TruePath) Then bPathVerified = True Else - UpdateLog(mgrCommon.FormatString(frmMain_ErrorRestorePath, oRestoreInfo.Name), False, ToolTipIcon.Error, True) + If mgrRestore.CheckPath(oRestoreInfo, oGame, bTriggerReload) Then + bPathVerified = True + Else + UpdateLog(mgrCommon.FormatString(frmMain_ErrorRestorePath, oRestoreInfo.Name), False, ToolTipIcon.Error, True) + End If End If If bOSVerified And bPathVerified Then @@ -2112,16 +2116,16 @@ Public Class frmMain If DoMultiGameCheck() Then UpdateLog(mgrCommon.FormatString(frmMain_GameEnded, oProcess.GameInfo.Name), False) If oProcess.WineProcess Then + oProcess.WineData.MonitorID = oProcess.GameInfo.ID 'Attempt a path conversion if the game configuration is using an absolute windows path that we can convert If mgrVariables.CheckForReservedVariables(oProcess.GameInfo.TruePath) Then - oProcess.WineData.MonitorID = oProcess.GameInfo.ID oProcess.WineData.SavePath = mgrPath.GetWineSavePath(oProcess.WineData.Prefix, oProcess.GameInfo.TruePath) If Not oProcess.WineData.SavePath = oProcess.GameInfo.TruePath Then oProcess.GameInfo.TruePath = oProcess.WineData.SavePath - mgrWineData.DoWineDataAddUpdate(oProcess.WineData) UpdateLog(mgrCommon.FormatString(frmMain_WineSavePath, oProcess.WineData.SavePath), False) End If End If + mgrWineData.DoWineDataAddUpdate(oProcess.WineData) 'This does required mods to include/exclude data and relative paths (if required) mgrPath.ModWinePathData(oProcess.GameInfo) End If diff --git a/GBM/Managers/mgrBackup.vb b/GBM/Managers/mgrBackup.vb index 511e5cf..7d9e4d0 100644 --- a/GBM/Managers/mgrBackup.vb +++ b/GBM/Managers/mgrBackup.vb @@ -120,47 +120,64 @@ Public Class mgrBackup Dim lAvailableSpace As Long Dim lFolderSize As Long = 0 Dim sDeepFolder As String + Dim bRegistry As Boolean + Dim sExtension As String + + 'Check if this is a registry backup + bRegistry = mgrPath.IsSupportedRegistryPath(oGame.TruePath) + + If bRegistry Then + 'If this is a registry backup, we need to have elevated permissions in Windows to use regedit + If Not mgrCommon.IsUnix And Not mgrCommon.IsElevated Then + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_ErrorRegBackupElevation, oGame.Name), False, ToolTipIcon.Info, True) + Return False + End If + sExtension = ".reg" + Else + 'Verify saved game path + sSavePath = VerifySavePath(oGame) + + 'Check if disk space check should be disabled (UNC path or Setting) + If Not mgrPath.IsPathUNC(oSettings.BackupFolder) And Not Settings.DisableDiskSpaceCheck Then + 'Calculate space + lAvailableSpace = mgrCommon.GetAvailableDiskSpace(oSettings.BackupFolder) + + 'If any includes are using a deep path and we aren't using recursion, we need to go directly to folders to do file size calculations or they will be missed. + If Not oGame.RecurseSubFolders Then + For Each s As String In oGame.IncludeArray + If s.Contains(Path.DirectorySeparatorChar) Then + sDeepFolder = Path.GetDirectoryName(sSavePath & Path.DirectorySeparatorChar & s) + If Directory.Exists(sDeepFolder) Then + lFolderSize += mgrCommon.GetFolderSize(sDeepFolder, oGame.IncludeArray, oGame.ExcludeArray, oGame.RecurseSubFolders) + End If + End If + Next + End If + lFolderSize += mgrCommon.GetFolderSize(sSavePath, oGame.IncludeArray, oGame.ExcludeArray, oGame.RecurseSubFolders) + + 'Show Available Space + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrCommon_AvailableDiskSpace, mgrCommon.FormatDiskSpace(lAvailableSpace)), False, ToolTipIcon.Info, True) + + 'Show Save Folder Size + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrCommon_SavedGameFolderSize, New String() {oGame.Name, mgrCommon.FormatDiskSpace(lFolderSize)}), False, ToolTipIcon.Info, True) + + If lFolderSize >= lAvailableSpace Then + If mgrCommon.ShowMessage(mgrBackup_ConfirmDiskSpace, MsgBoxStyle.YesNo) = MsgBoxResult.No Then + RaiseEvent UpdateLog(mgrBackup_ErrorDiskSpace, False, ToolTipIcon.Error, True) + Return False + End If + End If + Else + 'Show that disk space check was skipped due to UNC path + If Not Settings.DisableDiskSpaceCheck Then RaiseEvent UpdateLog(mgrBackup_ErrorBackupPathIsUNC, False, ToolTipIcon.Info, True) + End If + + sExtension = ".7z" + End If If oSettings.CreateSubFolder Then sBackupFile = sBackupFile & Path.DirectorySeparatorChar & GetFileName(oGame) - sBackupFile = sBackupFile & Path.DirectorySeparatorChar & GetFileName(oGame) & ".7z" - 'Verify saved game path - sSavePath = VerifySavePath(oGame) - - 'Check if disk space check should be disabled (UNC path or Setting) - If Not mgrPath.IsPathUNC(oSettings.BackupFolder) And Not Settings.DisableDiskSpaceCheck Then - 'Calculate space - lAvailableSpace = mgrCommon.GetAvailableDiskSpace(oSettings.BackupFolder) - - 'If any includes are using a deep path and we aren't using recursion, we need to go directly to folders to do file size calculations or they will be missed. - If Not oGame.RecurseSubFolders Then - For Each s As String In oGame.IncludeArray - If s.Contains(Path.DirectorySeparatorChar) Then - sDeepFolder = Path.GetDirectoryName(sSavePath & Path.DirectorySeparatorChar & s) - If Directory.Exists(sDeepFolder) Then - lFolderSize += mgrCommon.GetFolderSize(sDeepFolder, oGame.IncludeArray, oGame.ExcludeArray, oGame.RecurseSubFolders) - End If - End If - Next - End If - lFolderSize += mgrCommon.GetFolderSize(sSavePath, oGame.IncludeArray, oGame.ExcludeArray, oGame.RecurseSubFolders) - - 'Show Available Space - RaiseEvent UpdateLog(mgrCommon.FormatString(mgrCommon_AvailableDiskSpace, mgrCommon.FormatDiskSpace(lAvailableSpace)), False, ToolTipIcon.Info, True) - - 'Show Save Folder Size - RaiseEvent UpdateLog(mgrCommon.FormatString(mgrCommon_SavedGameFolderSize, New String() {oGame.Name, mgrCommon.FormatDiskSpace(lFolderSize)}), False, ToolTipIcon.Info, True) - - If lFolderSize >= lAvailableSpace Then - If mgrCommon.ShowMessage(mgrBackup_ConfirmDiskSpace, MsgBoxStyle.YesNo) = MsgBoxResult.No Then - RaiseEvent UpdateLog(mgrBackup_ErrorDiskSpace, False, ToolTipIcon.Error, True) - Return False - End If - End If - Else - 'Show that disk space check was skipped due to UNC path - If Not Settings.DisableDiskSpaceCheck Then RaiseEvent UpdateLog(mgrBackup_ErrorBackupPathIsUNC, False, ToolTipIcon.Info, True) - End If + sBackupFile = sBackupFile & Path.DirectorySeparatorChar & GetFileName(oGame) & sExtension 'A manifest check is only required when "Save Multiple Backups" is disabled If Not oGame.AppendTimeStamp Then @@ -185,7 +202,7 @@ Public Class mgrBackup End If End If - Return True + Return True End Function Private Sub CheckOldBackups(ByVal oGame As clsGame) @@ -292,23 +309,166 @@ Public Class mgrBackup Next End Sub + Private Function RunRegistryBackup(ByVal oGame As clsGame, ByVal sBackupFile As String) As Boolean + Dim prsReg As New Process + Dim sBinaryPath As String + Dim sArguments As String + Dim oWineData As clsWineData + Dim sWineRegEdit As String + Dim bPathVerified As Boolean = False + Dim bBackupCompleted As Boolean = False + + sArguments = "export """ & oGame.TruePath & """ """ & sBackupFile & """" + + If mgrCommon.IsUnix Then + oWineData = mgrWineData.DoWineDataGetbyID(oGame.ID) + sBinaryPath = oWineData.BinaryPath & Path.DirectorySeparatorChar & "wine" + sWineRegEdit = oWineData.Prefix & Path.DirectorySeparatorChar & "drive_c/windows/system32/reg.exe" + sArguments = """" & sWineRegEdit & """ " & sArguments + If File.Exists(sBinaryPath) Then + If File.Exists(sWineRegEdit) Then + bPathVerified = True + Else + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_ErrorRegNotFound, sWineRegEdit), False, ToolTipIcon.Error, True) + End If + Else + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_ErrorWineNotFound, sBinaryPath), False, ToolTipIcon.Error, True) + End If + Else + sBinaryPath = Environment.GetFolderPath(Environment.SpecialFolder.Windows) & Path.DirectorySeparatorChar & "system32\reg.exe" + If File.Exists(sBinaryPath) Then + bPathVerified = True + Else + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_ErrorRegNotFound, sBinaryPath), False, ToolTipIcon.Error, True) + End If + End If + + If bPathVerified Then + Try + 'Need to delete any prior file if it exists, otherwise reg.exe will get stuck waiting for input it'll never get. + If File.Exists(sBackupFile) Then + File.Delete(sBackupFile) + End If + + prsReg.StartInfo.Arguments = sArguments + prsReg.StartInfo.FileName = sBinaryPath + prsReg.StartInfo.UseShellExecute = False + prsReg.StartInfo.RedirectStandardOutput = True + prsReg.StartInfo.CreateNoWindow = True + prsReg.Start() + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_BackupInProgress, oGame.TruePath), False, ToolTipIcon.Info, True) + While Not prsReg.StandardOutput.EndOfStream + If CancelOperation Then + prsReg.Kill() + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_ErrorFullAbort, oGame.Name), True, ToolTipIcon.Error, True) + Exit While + End If + RaiseEvent UpdateLog(prsReg.StandardOutput.ReadLine, False, ToolTipIcon.Info, False) + End While + prsReg.WaitForExit() + Select Case prsReg.ExitCode + Case 0 + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_BackupComplete, New String() {oGame.Name, mgrCommon.FormatDiskSpace(mgrCommon.GetFileSize(sBackupFile))}), False, ToolTipIcon.Info, True) + bBackupCompleted = True + Case Else + RaiseEvent UpdateLog(mgrBackup_ErrorRegBackupFailed, False, ToolTipIcon.Info, True) + End Select + prsReg.Dispose() + Catch ex As Exception + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_ErrorOtherFailure, New String() {oGame.Name, ex.Message}), False, ToolTipIcon.Error, True) + End Try + End If + + Return bBackupCompleted + End Function + + Private Function Run7zBackup(ByVal oGame As clsGame, ByVal sBackupFile As String) As Boolean + Dim prs7z As New Process + Dim sSavePath As String + Dim sArguments As String + Dim bBackupCompleted As Boolean = False + + sSavePath = VerifySavePath(oGame) + + If oGame.FolderSave = True Then + BuildFileList("*", mgrPath.IncludeFileLocation) + Else + BuildFileList(oGame.FileType, mgrPath.IncludeFileLocation) + End If + + BuildFileList(oGame.ExcludeList, mgrPath.ExcludeFileLocation) + + sArguments = "a" & oSettings.Prepared7zArguments & "-t7z -mx" & oSettings.CompressionLevel & " -i@""" & mgrPath.IncludeFileLocation & """ -x@""" & mgrPath.ExcludeFileLocation & """ """ & sBackupFile & """" + + If oGame.RecurseSubFolders Then sArguments &= " -r" + + Try + If Directory.Exists(sSavePath) Then + If Settings.Is7zUtilityValid Then + 'Need to delete any prior archive if it exists, the 7za utility does not support overwriting or deleting existing archives. + 'If we let 7za update existing archives it will lead to excessive bloat with games that routinely add and remove files with many different file names. + If File.Exists(sBackupFile) Then + File.Delete(sBackupFile) + End If + + prs7z.StartInfo.Arguments = sArguments + prs7z.StartInfo.FileName = oSettings.Utility7zLocation + prs7z.StartInfo.WorkingDirectory = sSavePath + prs7z.StartInfo.UseShellExecute = False + prs7z.StartInfo.RedirectStandardOutput = True + prs7z.StartInfo.CreateNoWindow = True + prs7z.Start() + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_BackupInProgress, sSavePath), False, ToolTipIcon.Info, True) + While Not prs7z.StandardOutput.EndOfStream + If CancelOperation Then + prs7z.Kill() + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_ErrorFullAbort, oGame.Name), True, ToolTipIcon.Error, True) + Exit While + End If + RaiseEvent UpdateLog(prs7z.StandardOutput.ReadLine, False, ToolTipIcon.Info, False) + End While + prs7z.WaitForExit() + If Not CancelOperation Then + Select Case prs7z.ExitCode + Case 0 + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_BackupComplete, New String() {oGame.Name, mgrCommon.FormatDiskSpace(mgrCommon.GetFileSize(sBackupFile))}), False, ToolTipIcon.Info, True) + bBackupCompleted = True + Case 1 + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_7zWarnings, oGame.Name), True, ToolTipIcon.Warning, True) + bBackupCompleted = True + Case 2 + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_7zFatalError, oGame.Name), True, ToolTipIcon.Error, True) + Case 7 + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_7zCommandFailure, oGame.Name), True, ToolTipIcon.Error, True) + End Select + End If + prs7z.Dispose() + Else + RaiseEvent UpdateLog(App_Invalid7zDetected, True, ToolTipIcon.Error, True) + End If + Else + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_ErrorNoSavePath, oGame.Name), True, ToolTipIcon.Error, True) + End If + Catch ex As Exception + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_ErrorOtherFailure, New String() {oGame.Name, ex.Message}), False, ToolTipIcon.Error, True) + End Try + + Return bBackupCompleted + End Function + Public Sub DoBackup(ByVal oBackupList As List(Of clsGame)) Dim oGame As clsGame Dim bDoBackup As Boolean - Dim bBackupCompleted As Boolean - Dim prs7z As Process Dim sBackupFile As String - Dim sSavePath As String + Dim sBackupExt As String Dim dTimeStamp As DateTime Dim sTimeStamp As String Dim sHash As String - Dim sArguments As String + Dim bBackupCompleted As Boolean For Each oGame In oBackupList 'Init - prs7z = New Process sBackupFile = oSettings.BackupFolder - sSavePath = String.Empty dTimeStamp = Date.Now sTimeStamp = BuildFileTimeStamp(dTimeStamp) sHash = String.Empty @@ -322,100 +482,42 @@ Public Class mgrBackup bDoBackup = HandleSubFolder(oGame, sBackupFile) End If + If mgrPath.IsSupportedRegistryPath(oGame.TruePath) Then + sBackupExt = ".reg" + Else + sBackupExt = ".7z" + End If + If oGame.AppendTimeStamp Then If oGame.BackupLimit > 0 Then CheckOldBackups(oGame) - sBackupFile = sBackupFile & Path.DirectorySeparatorChar & GetFileName(oGame) & sTimeStamp & ".7z" + sBackupFile = sBackupFile & Path.DirectorySeparatorChar & GetFileName(oGame) & sTimeStamp & sBackupExt Else - sBackupFile = sBackupFile & Path.DirectorySeparatorChar & GetFileName(oGame) & ".7z" + sBackupFile = sBackupFile & Path.DirectorySeparatorChar & GetFileName(oGame) & sBackupExt End If If bDoBackup Then - - sSavePath = VerifySavePath(oGame) - - If oGame.FolderSave = True Then - BuildFileList("*", mgrPath.IncludeFileLocation) + 'Choose Backup Type + If mgrPath.IsSupportedRegistryPath(oGame.TruePath) Then + bBackupCompleted = RunRegistryBackup(oGame, sBackupFile) Else - BuildFileList(oGame.FileType, mgrPath.IncludeFileLocation) + bBackupCompleted = Run7zBackup(oGame, sBackupFile) End If - BuildFileList(oGame.ExcludeList, mgrPath.ExcludeFileLocation) + 'Write Main Manifest + If bBackupCompleted Then + 'Generate checksum for new backup + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_GenerateHash, oGame.Name), False, ToolTipIcon.Info, True) + sHash = mgrHash.Generate_SHA256_Hash(sBackupFile) - sArguments = "a" & oSettings.Prepared7zArguments & "-t7z -mx" & oSettings.CompressionLevel & " -i@""" & mgrPath.IncludeFileLocation & """ -x@""" & mgrPath.ExcludeFileLocation & """ """ & sBackupFile & """" - - If oGame.RecurseSubFolders Then sArguments &= " -r" - - Try - If Directory.Exists(sSavePath) Then - If Settings.Is7zUtilityValid Then - 'Need to delete any prior archive if it exists, the 7za utility does not support overwriting or deleting existing archives. - 'If we let 7za update existing archives it will lead to excessive bloat with games that routinely add and remove files with many different file names. - If File.Exists(sBackupFile) Then - File.Delete(sBackupFile) - End If - - prs7z.StartInfo.Arguments = sArguments - prs7z.StartInfo.FileName = oSettings.Utility7zLocation - prs7z.StartInfo.WorkingDirectory = sSavePath - prs7z.StartInfo.UseShellExecute = False - prs7z.StartInfo.RedirectStandardOutput = True - prs7z.StartInfo.CreateNoWindow = True - prs7z.Start() - RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_BackupInProgress, sSavePath), False, ToolTipIcon.Info, True) - While Not prs7z.StandardOutput.EndOfStream - If CancelOperation Then - prs7z.Kill() - RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_ErrorFullAbort, oGame.Name), True, ToolTipIcon.Error, True) - Exit While - End If - RaiseEvent UpdateLog(prs7z.StandardOutput.ReadLine, False, ToolTipIcon.Info, False) - End While - prs7z.WaitForExit() - If Not CancelOperation Then - Select Case prs7z.ExitCode - Case 0 - RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_BackupComplete, New String() {oGame.Name, mgrCommon.FormatDiskSpace(mgrCommon.GetFileSize(sBackupFile))}), False, ToolTipIcon.Info, True) - bBackupCompleted = True - Case 1 - RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_7zWarnings, oGame.Name), True, ToolTipIcon.Warning, True) - bBackupCompleted = True - Case 2 - RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_7zFatalError, oGame.Name), True, ToolTipIcon.Error, True) - bBackupCompleted = False - Case 7 - RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_7zCommandFailure, oGame.Name), True, ToolTipIcon.Error, True) - bBackupCompleted = False - End Select - End If - prs7z.Dispose() - Else - RaiseEvent UpdateLog(App_Invalid7zDetected, True, ToolTipIcon.Error, True) - bBackupCompleted = False - End If - Else - RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_ErrorNoSavePath, oGame.Name), True, ToolTipIcon.Error, True) - bBackupCompleted = False + If Not DoManifestUpdate(oGame, sBackupFile, dTimeStamp, sHash) Then + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_ErrorManifestFailure, oGame.Name), True, ToolTipIcon.Error, True) End If - 'Write Main Manifest - If bBackupCompleted Then - - 'Generate checksum for new backup - RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_GenerateHash, oGame.Name), False, ToolTipIcon.Info, True) - sHash = mgrHash.Generate_SHA256_Hash(sBackupFile) - - If Not DoManifestUpdate(oGame, sBackupFile, dTimeStamp, sHash) Then - RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_ErrorManifestFailure, oGame.Name), True, ToolTipIcon.Error, True) - End If - - 'Write the process path if we have it - If oGame.AbsolutePath = False Then - mgrMonitorList.DoListFieldUpdate("ProcessPath", oGame.ProcessPath, oGame.ID) - End If + 'Write the process path if we have it + If oGame.AbsolutePath = False Then + mgrMonitorList.DoListFieldUpdate("ProcessPath", oGame.ProcessPath, oGame.ID) End If - Catch ex As Exception - RaiseEvent UpdateLog(mgrCommon.FormatString(mgrBackup_ErrorOtherFailure, New String() {oGame.Name, ex.Message}), False, ToolTipIcon.Error, True) - End Try + End If End If If bBackupCompleted Then diff --git a/GBM/Managers/mgrPath.vb b/GBM/Managers/mgrPath.vb index 1542b70..f3a4647 100644 --- a/GBM/Managers/mgrPath.vb +++ b/GBM/Managers/mgrPath.vb @@ -485,6 +485,16 @@ Public Class mgrPath Return sValue End Function + Public Shared Function IsSupportedRegistryPath(ByVal sPath As String) + If sPath.StartsWith("HKEY_CURRENT_USER") Then + Return True + ElseIf sPath.StartsWith("HKEY_LOCAL_MACHINE") Then + Return True + End If + + Return False + End Function + Public Shared Function IsPathUNC(sPath As String) As Boolean Dim sPrefix As String = Path.DirectorySeparatorChar & Path.DirectorySeparatorChar If sPath.StartsWith(sPrefix) Then Return True diff --git a/GBM/Managers/mgrRestore.vb b/GBM/Managers/mgrRestore.vb index 3f89ac9..697ac6a 100644 --- a/GBM/Managers/mgrRestore.vb +++ b/GBM/Managers/mgrRestore.vb @@ -122,31 +122,43 @@ Public Class mgrRestore Public Function CheckRestorePrereq(ByVal oBackupInfo As clsBackup, ByVal bCleanFolder As Boolean) As Boolean Dim sHash As String Dim sExtractPath As String + Dim bRegistry As Boolean Dim sBackupFile As String = oSettings.BackupFolder & Path.DirectorySeparatorChar & oBackupInfo.FileName - If oBackupInfo.AbsolutePath Then - sExtractPath = oBackupInfo.RestorePath - Else - sExtractPath = oBackupInfo.RelativeRestorePath - End If + 'Check if this is a registry backup + bRegistry = mgrPath.IsSupportedRegistryPath(oBackupInfo.TruePath) - 'Check if restore location exists, prompt to create if it doesn't. - If Not Directory.Exists(sExtractPath) Then - If mgrCommon.ShowMessage(mgrRestore_ConfirmCreatePath, sExtractPath, MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then - Try - Directory.CreateDirectory(sExtractPath) - Catch ex As Exception - RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_ErrorCreatePath, ex.Message), False, ToolTipIcon.Error, True) - Return False - End Try - Else - RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_ErrorNoPath, sExtractPath), False, ToolTipIcon.Error, True) + If bRegistry Then + 'If this is a registry backup, we need to have elevated permissions in Windows to use regedit + If Not mgrCommon.IsUnix And Not mgrCommon.IsElevated Then + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_ErrorRegBackupElevation, oBackupInfo.Name), False, ToolTipIcon.Info, True) Return False End If Else - If bCleanFolder Then - mgrCommon.DeleteDirectory(sExtractPath, True) - Directory.CreateDirectory(sExtractPath) + If oBackupInfo.AbsolutePath Then + sExtractPath = oBackupInfo.RestorePath + Else + sExtractPath = oBackupInfo.RelativeRestorePath + End If + + 'Check if restore location exists, prompt to create if it doesn't. + If Not Directory.Exists(sExtractPath) Then + If mgrCommon.ShowMessage(mgrRestore_ConfirmCreatePath, sExtractPath, MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then + Try + Directory.CreateDirectory(sExtractPath) + Catch ex As Exception + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_ErrorCreatePath, ex.Message), False, ToolTipIcon.Error, True) + Return False + End Try + Else + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_ErrorNoPath, sExtractPath), False, ToolTipIcon.Error, True) + Return False + End If + Else + If bCleanFolder Then + mgrCommon.DeleteDirectory(sExtractPath, True) + Directory.CreateDirectory(sExtractPath) + End If End If End If @@ -170,77 +182,144 @@ Public Class mgrRestore Return True End Function + Private Function RunRegistryRestore(ByVal oBackupInfo As clsBackup, ByVal sBackupFile As String) As Boolean + Dim prsReg As New Process + Dim sBinaryPath As String + Dim sArguments As String + Dim oWineData As clsWineData + Dim sWineRegEdit As String + Dim bPathVerified As Boolean + Dim bRestoreCompleted As Boolean = False + + sArguments = "import """ & sBackupFile & """" + + If mgrCommon.IsUnix Then + oWineData = mgrWineData.DoWineDataGetbyID(oBackupInfo.MonitorID) + sBinaryPath = oWineData.BinaryPath & Path.DirectorySeparatorChar & "wine" + sWineRegEdit = oWineData.Prefix & Path.DirectorySeparatorChar & "drive_c/windows/system32/reg.exe" + sArguments = """" & sWineRegEdit & """ " & sArguments + If File.Exists(sBinaryPath) Then + If File.Exists(sWineRegEdit) Then + bPathVerified = True + Else + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_ErrorRegNotFound, sWineRegEdit), False, ToolTipIcon.Error, True) + End If + Else + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_ErrorWineNotFound, sBinaryPath), False, ToolTipIcon.Error, True) + End If + Else + sBinaryPath = Environment.GetFolderPath(Environment.SpecialFolder.Windows) & Path.DirectorySeparatorChar & "system32\reg.exe" + If File.Exists(sBinaryPath) Then + bPathVerified = True + Else + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_ErrorRegNotFound, sBinaryPath), False, ToolTipIcon.Error, True) + End If + End If + + If bPathVerified Then + Try + prsReg.StartInfo.Arguments = sArguments + prsReg.StartInfo.FileName = sBinaryPath + prsReg.StartInfo.UseShellExecute = False + prsReg.StartInfo.RedirectStandardOutput = True + prsReg.StartInfo.CreateNoWindow = True + prsReg.Start() + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_RestoreInProgress, oBackupInfo.TruePath), False, ToolTipIcon.Info, True) + prsReg.WaitForExit() + Select Case prsReg.ExitCode + Case 0 + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_RestoreComplete, oBackupInfo.Name), False, ToolTipIcon.Info, True) + bRestoreCompleted = True + Case Else + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_RestoreWarnings, oBackupInfo.Name), True, ToolTipIcon.Warning, True) + End Select + prsReg.Dispose() + Catch ex As Exception + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_ErrorOtherFailure, ex.Message), False, ToolTipIcon.Error, True) + End Try + End If + + Return bRestoreCompleted + End Function + + Private Function Run7zRestore(ByVal oBackupInfo As clsBackup, ByVal sBackupFile As String) As Boolean + Dim prs7z As New Process + Dim sExtractPath As String + Dim bRestoreCompleted As Boolean = False + + If oBackupInfo.AbsolutePath Then + sExtractPath = oBackupInfo.RestorePath + Else + sExtractPath = oBackupInfo.RelativeRestorePath + End If + + Try + If File.Exists(sBackupFile) Then + If Settings.Is7zUtilityValid Then + prs7z.StartInfo.Arguments = "x" & oSettings.Prepared7zArguments & """" & sBackupFile & """ -o""" & sExtractPath & Path.DirectorySeparatorChar & """ -aoa -r" + prs7z.StartInfo.FileName = oSettings.Utility7zLocation + prs7z.StartInfo.UseShellExecute = False + prs7z.StartInfo.RedirectStandardOutput = True + prs7z.StartInfo.CreateNoWindow = True + prs7z.Start() + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_RestoreInProgress, sExtractPath), False, ToolTipIcon.Info, True) + While Not prs7z.StandardOutput.EndOfStream + If CancelOperation Then + prs7z.Kill() + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_ErrorFullAbort, oBackupInfo.Name), True, ToolTipIcon.Error, True) + Exit While + End If + RaiseEvent UpdateLog(prs7z.StandardOutput.ReadLine, False, ToolTipIcon.Info, False) + End While + prs7z.WaitForExit() + If Not CancelOperation Then + If prs7z.ExitCode = 0 Then + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_RestoreComplete, oBackupInfo.Name), False, ToolTipIcon.Info, True) + bRestoreCompleted = True + Else + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_RestoreWarnings, oBackupInfo.Name), True, ToolTipIcon.Warning, True) + End If + End If + prs7z.Dispose() + Else + RaiseEvent UpdateLog(App_Invalid7zDetected, True, ToolTipIcon.Error, True) + End If + Else + RaiseEvent UpdateLog(mgrRestore_ErrorNoBackup, True, ToolTipIcon.Error, True) + End If + Catch ex As Exception + RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_ErrorOtherFailure, ex.Message), False, ToolTipIcon.Error, True) + End Try + + Return bRestoreCompleted + End Function + Public Sub DoRestore(ByVal oRestoreList As List(Of clsBackup)) - Dim prs7z As Process Dim sBackupFile As String Dim sExtractPath As String Dim bRestoreCompleted As Boolean For Each oBackupInfo In oRestoreList 'Init - prs7z = New Process sBackupFile = oSettings.BackupFolder & Path.DirectorySeparatorChar & oBackupInfo.FileName sExtractPath = String.Empty bRestoreCompleted = False CancelOperation = False RaiseEvent UpdateRestoreInfo(oBackupInfo) - If oBackupInfo.AbsolutePath Then - sExtractPath = oBackupInfo.RestorePath + If mgrPath.IsSupportedRegistryPath(oBackupInfo.TruePath) Then + bRestoreCompleted = RunRegistryRestore(oBackupInfo, sBackupFile) Else - sExtractPath = oBackupInfo.RelativeRestorePath + bRestoreCompleted = Run7zRestore(oBackupInfo, sBackupFile) End If - Try - If File.Exists(sBackupFile) Then - If Settings.Is7zUtilityValid Then - prs7z.StartInfo.Arguments = "x" & oSettings.Prepared7zArguments & """" & sBackupFile & """ -o""" & sExtractPath & Path.DirectorySeparatorChar & """ -aoa -r" - prs7z.StartInfo.FileName = oSettings.Utility7zLocation - prs7z.StartInfo.UseShellExecute = False - prs7z.StartInfo.RedirectStandardOutput = True - prs7z.StartInfo.CreateNoWindow = True - prs7z.Start() - RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_RestoreInProgress, sExtractPath), False, ToolTipIcon.Info, True) - While Not prs7z.StandardOutput.EndOfStream - If CancelOperation Then - prs7z.Kill() - RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_ErrorFullAbort, oBackupInfo.Name), True, ToolTipIcon.Error, True) - Exit While - End If - RaiseEvent UpdateLog(prs7z.StandardOutput.ReadLine, False, ToolTipIcon.Info, False) - End While - prs7z.WaitForExit() - If Not CancelOperation Then - If prs7z.ExitCode = 0 Then - RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_RestoreComplete, oBackupInfo.Name), False, ToolTipIcon.Info, True) - bRestoreCompleted = True - Else - RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_RestoreWarnings, oBackupInfo.Name), True, ToolTipIcon.Warning, True) - bRestoreCompleted = False - End If - End If - prs7z.Dispose() - Else - RaiseEvent UpdateLog(App_Invalid7zDetected, True, ToolTipIcon.Error, True) - bRestoreCompleted = False - End If - Else - RaiseEvent UpdateLog(mgrRestore_ErrorNoBackup, True, ToolTipIcon.Error, True) - End If - - If bRestoreCompleted Then - 'Save Local Manifest - If mgrManifest.DoManifestCheck(oBackupInfo.MonitorID, mgrSQLite.Database.Local) Then - mgrManifest.DoManifestUpdateByMonitorID(oBackupInfo, mgrSQLite.Database.Local) - Else - mgrManifest.DoManifestAdd(oBackupInfo, mgrSQLite.Database.Local) - End If - End If - Catch ex As Exception - RaiseEvent UpdateLog(mgrCommon.FormatString(mgrRestore_ErrorOtherFailure, ex.Message), False, ToolTipIcon.Error, True) - End Try - If bRestoreCompleted Then + 'Save Local Manifest + If mgrManifest.DoManifestCheck(oBackupInfo.MonitorID, mgrSQLite.Database.Local) Then + mgrManifest.DoManifestUpdateByMonitorID(oBackupInfo, mgrSQLite.Database.Local) + Else + mgrManifest.DoManifestAdd(oBackupInfo, mgrSQLite.Database.Local) + End If RaiseEvent SetLastAction(mgrCommon.FormatString(mgrRestore_ActionComplete, oBackupInfo.CroppedName)) Else RaiseEvent SetLastAction(mgrCommon.FormatString(mgrRestore_ActionFailed, oBackupInfo.CroppedName)) diff --git a/GBM/My Project/Resources.Designer.vb b/GBM/My Project/Resources.Designer.vb index b39afad..e6b3f8a 100644 --- a/GBM/My Project/Resources.Designer.vb +++ b/GBM/My Project/Resources.Designer.vb @@ -6123,6 +6123,33 @@ Namespace My.Resources End Get End Property + ''' + ''' Looks up a localized string similar to [PARAM] stores saved games in the Windows registry, accessing the registry requires elevated permissions. Please restart GBM as Administrator to perform this backup.. + ''' + Friend ReadOnly Property mgrBackup_ErrorRegBackupElevation() As String + Get + Return ResourceManager.GetString("mgrBackup_ErrorRegBackupElevation", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to The backup has failed, please ensure the registry path is correct.. + ''' + Friend ReadOnly Property mgrBackup_ErrorRegBackupFailed() As String + Get + Return ResourceManager.GetString("mgrBackup_ErrorRegBackupFailed", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to The regedit utility could not be located at [PARAM]. The backup cannot continue.. + ''' + Friend ReadOnly Property mgrBackup_ErrorRegNotFound() As String + Get + Return ResourceManager.GetString("mgrBackup_ErrorRegNotFound", resourceCulture) + End Get + End Property + ''' ''' Looks up a localized string similar to A failure occured while creating a backup sub-folder for [PARAM].[BR][PARAM]. ''' @@ -6132,6 +6159,15 @@ Namespace My.Resources End Get End Property + ''' + ''' Looks up a localized string similar to The wine binary could not be located at [PARAM]. The backup cannot continue.. + ''' + Friend ReadOnly Property mgrBackup_ErrorWineNotFound() As String + Get + Return ResourceManager.GetString("mgrBackup_ErrorWineNotFound", resourceCulture) + End Get + End Property + ''' ''' Looks up a localized string similar to Generating SHA-256 hash for [PARAM] backup file.. ''' @@ -6636,6 +6672,33 @@ Namespace My.Resources End Get End Property + ''' + ''' Looks up a localized string similar to [PARAM] stores saved games in the Windows registry, accessing the registry requires elevated permissions. Please restart GBM as Administrator to restore this backup.. + ''' + Friend ReadOnly Property mgrRestore_ErrorRegBackupElevation() As String + Get + Return ResourceManager.GetString("mgrRestore_ErrorRegBackupElevation", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to The regedit utility could not be located at [PARAM]. The restore cannot continue.. + ''' + Friend ReadOnly Property mgrRestore_ErrorRegNotFound() As String + Get + Return ResourceManager.GetString("mgrRestore_ErrorRegNotFound", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to The wine binary could not be located at [PARAM]. The restore cannot continue.. + ''' + Friend ReadOnly Property mgrRestore_ErrorWineNotFound() As String + Get + Return ResourceManager.GetString("mgrRestore_ErrorWineNotFound", resourceCulture) + End Get + End Property + ''' ''' Looks up a localized string similar to [PARAM] has no stored checksum, verification has been skipped.. ''' diff --git a/GBM/My Project/Resources.resx b/GBM/My Project/Resources.resx index 0ce53fa..9fd943c 100644 --- a/GBM/My Project/Resources.resx +++ b/GBM/My Project/Resources.resx @@ -2347,4 +2347,25 @@ An error occured while creating the autostart link:[BR][BR][PARAM] + + [PARAM] stores saved games in the Windows registry, accessing the registry requires elevated permissions. Please restart GBM as Administrator to perform this backup. + + + The backup has failed, please ensure the registry path is correct. + + + The regedit utility could not be located at [PARAM]. The backup cannot continue. + + + The wine binary could not be located at [PARAM]. The backup cannot continue. + + + The regedit utility could not be located at [PARAM]. The restore cannot continue. + + + The wine binary could not be located at [PARAM]. The restore cannot continue. + + + [PARAM] stores saved games in the Windows registry, accessing the registry requires elevated permissions. Please restart GBM as Administrator to restore this backup. + \ No newline at end of file