ModernUO/Projects/UOContent/Compression/TarArchive.cs
Kamron Batman c31bf20d0e
feat: Updates to .NET 6 (#843)
* Fixes an issue with moving directories across volumes
* Removes usages of WebClient
* Removes usages of Cryptographic Providers

Note: Even though .NET 6 introduces Xoshiro RNG, there is no way to control the seed. I'll do some reconciliation of Xoshiro so it functions closer to the built in one. For the most part, it has parity though.
Benchmarks show there is nothing odd about the implementations, they are within 1ns of each other.
2021-11-13 13:38:01 -08:00

119 lines
4.3 KiB
C#
Executable file

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Server.Buffers;
namespace Server.Compression
{
public static class TarArchive
{
private const string _libArchiveWindowsUrl = @"https://www.libarchive.org/downloads/libarchive-v3.5.2-win64.zip";
private static string _pathToTar;
private static string GetPathToTar()
{
if (!Core.IsWindows || File.Exists(@"C:\Windows\system32\tar.exe"))
{
return "tar";
}
var tarPath = Path.Combine(Core.BaseDirectory, "bsdtar/bsdtar.exe");
return File.Exists(tarPath) ? tarPath : DownloadTarForWindows();
}
private static int RunTar(string arguments, string compressionProgramPath)
{
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = _pathToTar,
Arguments = arguments
}
};
if (compressionProgramPath != null)
{
var envPaths = $"{process.StartInfo.EnvironmentVariables["PATH"]}:{compressionProgramPath}";
process.StartInfo.EnvironmentVariables["PATH"] = envPaths;
}
process.Start();
process.WaitForExit();
return process.ExitCode;
}
private static string DownloadTarForWindows()
{
var tempDir = PathUtility.EnsureRandomPath(Path.GetTempPath());
var libarchiveFile = Path.Combine(tempDir, "libarchive.zip");
// This isn't called often so we don't need to optimize
using (HttpClient hc = new HttpClient())
{
var result = hc.Send(new HttpRequestMessage(HttpMethod.Get, new Uri(_libArchiveWindowsUrl)));
using var stream = result.Content.ReadAsStream();
using FileStream fs = new FileStream(libarchiveFile, FileMode.Create, FileAccess.Write, FileShare.None);
stream.CopyTo(fs);
}
ZipFile.ExtractToDirectory(libarchiveFile, tempDir);
var libArchivePath = Path.Combine(tempDir, "libarchive");
PathUtility.MoveDirectory(Path.Combine(libArchivePath, "bin"), Path.Combine(Core.BaseDirectory, "bsdtar"));
File.Delete(libarchiveFile);
return Path.Combine(Core.BaseDirectory, "bsdtar/bsdtar.exe");
}
public static bool ExtractToDirectory(
string fileNamePath,
string outputDirectory,
string compressCommand = null,
string compressionProgramPath = null
)
{
_pathToTar ??= GetPathToTar();
var useExternalCompression = compressCommand != null ? $"--use-compress-program \"{compressCommand}\" " : "";
var arguments = $"{useExternalCompression} -xf \"{fileNamePath}\" -C \"{outputDirectory}\"";
return RunTar(arguments, compressionProgramPath) == 0;
}
public static bool CreateFromPaths(
IEnumerable<string> paths,
string destinationArchiveFileName,
string relativeTo,
string compressCommand = null,
string compressionProgramPath = null
)
{
_pathToTar ??= GetPathToTar();
new FileInfo(destinationArchiveFileName).EnsureDirectory();
using var builder = new ValueStringBuilder();
var i = 0;
foreach (var path in paths)
{
builder.Append($"{(i++ > 0 ? " " : "")}\"{Path.GetRelativePath(relativeTo, path)}\"");
}
var pathsToCompress = builder.ToString();
var tarFlags = compressCommand == null ? "-acf" : "-cf";
var useExternalCompression = compressCommand != null ? $"--use-compress-program \"{compressCommand}\" " : "";
var arguments = $"{useExternalCompression}{tarFlags} \"{destinationArchiveFileName}\" -C \"{relativeTo}\" {pathsToCompress}";
return RunTar(arguments, compressionProgramPath) == 0;
}
}
}