fix(launcher): harden updater crash recovery
This commit is contained in:
parent
2d2a5b5046
commit
1955ca8ab5
27 changed files with 2714 additions and 544 deletions
|
|
@ -503,7 +503,9 @@ public sealed class ClientVersionStore
|
|||
.Where(path => !string.Equals(
|
||||
path,
|
||||
"install.json",
|
||||
StringComparison.OrdinalIgnoreCase))
|
||||
OperatingSystem.IsWindows()
|
||||
? StringComparison.OrdinalIgnoreCase
|
||||
: StringComparison.Ordinal))
|
||||
.OrderBy(path => path, StringComparer.Ordinal)
|
||||
.ToArray();
|
||||
string[] recordedFiles = record.Files
|
||||
|
|
@ -809,13 +811,43 @@ public sealed class ClientVersionStore
|
|||
".client-staging-*",
|
||||
SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
string suffix = Path.GetFileName(path)[".client-staging-".Length..];
|
||||
if (Guid.TryParseExact(suffix, "N", out _))
|
||||
if (HasCanonicalGuidName(
|
||||
Path.GetFileName(path),
|
||||
".client-staging-",
|
||||
string.Empty))
|
||||
{
|
||||
SafeZipExtractor.TryDeleteDirectory(path);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string path in Directory.EnumerateDirectories(
|
||||
AppDirectory,
|
||||
".client-corrupt-*",
|
||||
SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
if (HasCanonicalGuidName(
|
||||
Path.GetFileName(path),
|
||||
".client-corrupt-",
|
||||
string.Empty))
|
||||
{
|
||||
SafeZipExtractor.TryDeleteDirectory(path);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string path in Directory.EnumerateFiles(
|
||||
AppDirectory,
|
||||
".client-download-*.zip",
|
||||
SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
if (HasCanonicalGuidName(
|
||||
Path.GetFileName(path),
|
||||
".client-download-",
|
||||
".zip"))
|
||||
{
|
||||
VerifiedArtifactDownloader.TryDelete(path);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string path in Directory.EnumerateFiles(
|
||||
AppDirectory,
|
||||
".current*.tmp",
|
||||
|
|
@ -825,20 +857,43 @@ public sealed class ClientVersionStore
|
|||
string[] parts = fileName.Split('.');
|
||||
if (parts.Length >= 4
|
||||
&& string.Equals(parts[^1], "tmp", StringComparison.Ordinal)
|
||||
&& Guid.TryParseExact(parts[^2], "N", out _))
|
||||
&& Guid.TryParseExact(parts[^2], "N", out Guid parsed)
|
||||
&& string.Equals(
|
||||
parsed.ToString("N"),
|
||||
parts[^2],
|
||||
StringComparison.Ordinal))
|
||||
{
|
||||
VerifiedArtifactDownloader.TryDelete(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool HasCanonicalGuidName(
|
||||
string fileName,
|
||||
string prefix,
|
||||
string suffix)
|
||||
{
|
||||
if (!fileName.StartsWith(prefix, StringComparison.Ordinal)
|
||||
|| !fileName.EndsWith(suffix, StringComparison.Ordinal)
|
||||
|| fileName.Length != prefix.Length + 32 + suffix.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string value = fileName.Substring(prefix.Length, 32);
|
||||
return Guid.TryParseExact(value, "N", out Guid parsed)
|
||||
&& string.Equals(parsed.ToString("N"), value, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private void RequireOwnedStagingPath(string path)
|
||||
{
|
||||
string parent = Path.GetDirectoryName(path) ?? string.Empty;
|
||||
string fileName = Path.GetFileName(path);
|
||||
if (!PathsEqual(parent, AppDirectory)
|
||||
|| !fileName.StartsWith(".client-staging-", StringComparison.Ordinal)
|
||||
|| !Guid.TryParseExact(fileName[".client-staging-".Length..], "N", out _))
|
||||
|| !HasCanonicalGuidName(
|
||||
fileName,
|
||||
".client-staging-",
|
||||
string.Empty))
|
||||
{
|
||||
throw new LauncherUpdateException(
|
||||
"The client extraction path is not an owned LA10 staging directory.");
|
||||
|
|
@ -901,7 +956,7 @@ public sealed class ClientVersionStore
|
|||
&& !part.Any(character =>
|
||||
char.IsControl(character)
|
||||
|| character is '<' or '>' or '"' or '|' or '?' or '*')
|
||||
&& !IsWindowsDeviceName(part));
|
||||
&& !PortablePathRules.IsWindowsDeviceName(part));
|
||||
}
|
||||
|
||||
internal static string ResolveContained(string root, string relative)
|
||||
|
|
@ -929,19 +984,6 @@ public sealed class ClientVersionStore
|
|||
return path;
|
||||
}
|
||||
|
||||
private static bool IsWindowsDeviceName(string segment)
|
||||
{
|
||||
string stem = segment.Split('.')[0];
|
||||
return stem.Equals("CON", StringComparison.OrdinalIgnoreCase)
|
||||
|| stem.Equals("PRN", StringComparison.OrdinalIgnoreCase)
|
||||
|| stem.Equals("AUX", StringComparison.OrdinalIgnoreCase)
|
||||
|| stem.Equals("NUL", StringComparison.OrdinalIgnoreCase)
|
||||
|| (stem.Length == 4
|
||||
&& (stem.StartsWith("COM", StringComparison.OrdinalIgnoreCase)
|
||||
|| stem.StartsWith("LPT", StringComparison.OrdinalIgnoreCase))
|
||||
&& stem[3] is >= '1' and <= '9');
|
||||
}
|
||||
|
||||
private static bool PathsEqual(string left, string right) =>
|
||||
string.Equals(
|
||||
Path.TrimEndingDirectorySeparator(Path.GetFullPath(left)),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue