You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
6.1 KiB

  1. #nullable enable
  2. using IPA.AntiMalware;
  3. using IPA.Config;
  4. using IPA.Utilities;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Diagnostics;
  8. using System.IO;
  9. using System.Linq;
  10. using System.Reflection;
  11. using static IPA.Logging.Logger;
  12. #if NET3
  13. using Net3_Proxy;
  14. using Path = Net3_Proxy.Path;
  15. using File = Net3_Proxy.File;
  16. using Directory = Net3_Proxy.Directory;
  17. using Array = Net3_Proxy.Array;
  18. #endif
  19. namespace IPA.Injector
  20. {
  21. internal static class Updates
  22. {
  23. private const string DeleteFileName = "$$delete";
  24. public static void InstallPendingUpdates()
  25. {
  26. InstallPendingSelfUpdates();
  27. InstallPendingModUpdates();
  28. }
  29. private static void InstallPendingSelfUpdates()
  30. {
  31. var path = Path.Combine(UnityGame.InstallPath, "IPA.exe");
  32. if (!File.Exists(path)) return;
  33. var scanResult = AntiMalwareEngine.Engine.ScanFile(new FileInfo(path));
  34. if (scanResult == ScanResult.Detected)
  35. {
  36. updater.Error("Scan of BSIPA installer found malware; not updating");
  37. return;
  38. }
  39. if (!SelfConfig.AntiMalware_.RunPartialThreatCode_ && scanResult is not ScanResult.KnownSafe and not ScanResult.NotDetected)
  40. {
  41. updater.Error("Scan of BSIPA installer returned partial threat; not updating. To allow this, enable AntiMalware.RunPartialThreatCode in the config.");
  42. return;
  43. }
  44. var ipaVersion = new Version(FileVersionInfo.GetVersionInfo(path).FileVersion);
  45. var selfVersion = Assembly.GetExecutingAssembly().GetName().Version;
  46. if (ipaVersion > selfVersion)
  47. {
  48. _ = Process.Start(new ProcessStartInfo
  49. {
  50. FileName = path,
  51. Arguments = $"\"-nw={Process.GetCurrentProcess().Id},s={string.Join(" ", Environment.GetCommandLineArgs().Skip(1).StrJP()).Replace("\\", "\\\\").Replace(",", "\\,")}\"",
  52. UseShellExecute = false
  53. });
  54. updater.Info("Updating BSIPA...");
  55. Environment.Exit(0);
  56. }
  57. }
  58. private static void InstallPendingModUpdates()
  59. {
  60. var pendingDir = Path.Combine(UnityGame.InstallPath, "IPA", "Pending");
  61. if (!Directory.Exists(pendingDir)) return;
  62. // there are pending updates, install
  63. updater.Info("Installing pending updates");
  64. var toDelete = Array.Empty<string>();
  65. var delFn = Path.Combine(pendingDir, DeleteFileName);
  66. if (File.Exists(delFn))
  67. {
  68. toDelete = File.ReadAllLines(delFn);
  69. File.Delete(delFn);
  70. }
  71. foreach (var file in toDelete)
  72. {
  73. try
  74. {
  75. File.Delete(Path.Combine(UnityGame.InstallPath, file));
  76. }
  77. catch (Exception e)
  78. {
  79. updater.Error("While trying to install pending updates: Error deleting file marked for deletion");
  80. updater.Error(e);
  81. }
  82. }
  83. #region Self Protection
  84. string path;
  85. if (Directory.Exists(path = Path.Combine(pendingDir, "IPA")))
  86. {
  87. var dirs = new Stack<string>(20);
  88. dirs.Push(path);
  89. while (dirs.Count > 0)
  90. {
  91. var currentDir = dirs.Pop();
  92. string[] subDirs;
  93. string[] files;
  94. try
  95. {
  96. subDirs = Directory.GetDirectories(currentDir);
  97. files = Directory.GetFiles(currentDir);
  98. }
  99. catch (UnauthorizedAccessException e)
  100. {
  101. updater.Error(e);
  102. continue;
  103. }
  104. catch (DirectoryNotFoundException e)
  105. {
  106. updater.Error(e);
  107. continue;
  108. }
  109. foreach (var file in files)
  110. {
  111. try
  112. {
  113. if (!Utils.GetRelativePath(file, path).Split(Path.PathSeparator).Contains("Pending"))
  114. File.Delete(file);
  115. }
  116. catch (FileNotFoundException e)
  117. {
  118. updater.Error(e);
  119. }
  120. }
  121. foreach (var str in subDirs)
  122. dirs.Push(str);
  123. }
  124. }
  125. if (File.Exists(path = Path.Combine(pendingDir, "IPA.exe")))
  126. {
  127. File.Delete(path);
  128. if (File.Exists(path = Path.Combine(pendingDir, "Mono.Cecil.dll")))
  129. File.Delete(path);
  130. }
  131. #endregion
  132. try
  133. {
  134. Utils.CopyAll(new DirectoryInfo(pendingDir), new DirectoryInfo(UnityGame.InstallPath), onCopyException: (e, f) =>
  135. {
  136. updater.Error($"Error copying file {Utils.GetRelativePath(f.FullName, pendingDir)} from Pending:");
  137. updater.Error(e);
  138. return true;
  139. });
  140. }
  141. catch (Exception e)
  142. {
  143. updater.Error("While trying to install pending updates: Error copying files in");
  144. updater.Error(e);
  145. }
  146. try
  147. {
  148. Directory.Delete(pendingDir, true);
  149. }
  150. catch (Exception e)
  151. {
  152. updater.Error("Something went wrong performing an operation that should never fail!");
  153. updater.Error(e);
  154. }
  155. }
  156. }
  157. }