private void ExtractPluginAsync(MemoryStream stream, DependencyObject item, ApiEndpoint.Mod.PlatformFile fileInfo) { // (3.3) Logger.updater.Debug($"Extracting ZIP file for {item.Name}"); var data = stream.GetBuffer(); SHA1 sha = new SHA1CryptoServiceProvider(); var hash = sha.ComputeHash(data); if (!LoneFunctions.UnsafeCompare(hash, fileInfo.Hash)) { throw new Exception("The hash for the file doesn't match what is defined"); } var targetDir = Path.Combine(BeatSaber.InstallPath, "IPA", Path.GetRandomFileName() + "_Pending"); Directory.CreateDirectory(targetDir); var eventualOutput = Path.Combine(BeatSaber.InstallPath, "IPA", "Pending"); if (!Directory.Exists(eventualOutput)) { Directory.CreateDirectory(eventualOutput); } try { bool shouldDeleteOldFile = !(item.LocalPluginMeta?.Plugin is SelfPlugin); using (var zipFile = ZipFile.Read(stream)) { Logger.updater.Debug("Streams opened"); foreach (var entry in zipFile) { if (entry.IsDirectory) { Logger.updater.Debug($"Creating directory {entry.FileName}"); Directory.CreateDirectory(Path.Combine(targetDir, entry.FileName)); } else { using (var ostream = new MemoryStream((int)entry.UncompressedSize)) { entry.Extract(ostream); ostream.Seek(0, SeekOrigin.Begin); sha = new SHA1CryptoServiceProvider(); var fileHash = sha.ComputeHash(ostream); try { if (!LoneFunctions.UnsafeCompare(fileHash, fileInfo.FileHashes[entry.FileName])) { throw new Exception("The hash for the file doesn't match what is defined"); } } catch (KeyNotFoundException) { throw new ModsaberInterceptException("ModSaber did not send the hashes for the zip's content!"); } ostream.Seek(0, SeekOrigin.Begin); FileInfo targetFile = new FileInfo(Path.Combine(targetDir, entry.FileName)); Directory.CreateDirectory(targetFile.DirectoryName ?? throw new InvalidOperationException()); if (LoneFunctions.GetRelativePath(targetFile.FullName, targetDir) == LoneFunctions.GetRelativePath(item.LocalPluginMeta?.Filename, BeatSaber.InstallPath)) { shouldDeleteOldFile = false; // overwriting old file, no need to delete } /*if (targetFile.Exists) * backup.Add(targetFile); * else * newFiles.Add(targetFile);*/ Logger.updater.Debug($"Extracting file {targetFile.FullName}"); targetFile.Delete(); using (var fstream = targetFile.Create()) ostream.CopyTo(fstream); } } } } if (shouldDeleteOldFile && item.LocalPluginMeta != null) { File.AppendAllLines(Path.Combine(targetDir, SpecialDeletionsFile), new[] { LoneFunctions.GetRelativePath(item.LocalPluginMeta.Filename, BeatSaber.InstallPath) }); } } catch (Exception) { // something failed; restore /*foreach (var file in newFiles) * file.Delete(); * backup.Restore(); * backup.Delete();*/ Directory.Delete(targetDir, true); // delete extraction site throw; } if (item.LocalPluginMeta?.Plugin is SelfPlugin) { // currently updating self, so copy to working dir and update LoneFunctions.CopyAll(new DirectoryInfo(targetDir), new DirectoryInfo(BeatSaber.InstallPath)); if (File.Exists(Path.Combine(BeatSaber.InstallPath, SpecialDeletionsFile))) { File.Delete(Path.Combine(BeatSaber.InstallPath, SpecialDeletionsFile)); } Process.Start(new ProcessStartInfo { FileName = item.LocalPluginMeta.Filename, Arguments = $"-nw={Process.GetCurrentProcess().Id}", UseShellExecute = false }); } else { LoneFunctions.CopyAll(new DirectoryInfo(targetDir), new DirectoryInfo(eventualOutput), SpecialDeletionsFile); } Directory.Delete(targetDir, true); // delete extraction site Logger.updater.Debug("Extractor exited"); }
public static void InstallPendingUpdates() { var pendingDir = Path.Combine(BeatSaber.InstallPath, "IPA", "Pending"); if (!Directory.Exists(pendingDir)) { return; } // there are pending updates, install updater.Info("Installing pending updates"); var toDelete = new string[0]; var delFn = Path.Combine(pendingDir, DeleteFileName); if (File.Exists(delFn)) { toDelete = File.ReadAllLines(delFn); File.Delete(delFn); } foreach (var file in toDelete) { try { File.Delete(Path.Combine(BeatSaber.InstallPath, file)); } catch (Exception e) { updater.Error("While trying to install pending updates: Error deleting file marked for deletion"); updater.Error(e); } } #region Self Protection if (Directory.Exists(Path.Combine(pendingDir, "IPA"))) { Directory.Delete(Path.Combine(pendingDir, "IPA"), true); } if (File.Exists(Path.Combine(pendingDir, "IPA.exe"))) { File.Delete(Path.Combine(pendingDir, "IPA.exe")); if (File.Exists(Path.Combine(pendingDir, "Mono.Cecil.dll"))) { File.Delete(Path.Combine(pendingDir, "Mono.Cecil.dll")); } } #endregion try { LoneFunctions.CopyAll(new DirectoryInfo(pendingDir), new DirectoryInfo(BeatSaber.InstallPath)); } catch (Exception e) { updater.Error("While trying to install pending updates: Error copying files in"); updater.Error(e); } Directory.Delete(pendingDir, true); }