diff --git a/AsarSharp/AsarCreator.cs b/AsarSharp/AsarCreator.cs
index 9b1276f..804f69f 100644
--- a/AsarSharp/AsarCreator.cs
+++ b/AsarSharp/AsarCreator.cs
@@ -73,22 +73,26 @@ namespace AsarSharp
filesystem.InsertFile(filename, shouldUnpack, file, placeholder);
break;
case FileType.Link:
- throw new NotImplementedException();
+ throw new NotSupportedException($"Packing symlinks is not supported: '{filename}'");
}
}
- private bool ShouldUnpackPath(string relativePath)
+ ///
+ /// Matches the directory path (relative to the archive root) against the unpack regex.
+ ///
+ private bool ShouldUnpackPath(string relativeParentPath)
{
- return _options?.Unpack?.IsMatch(relativePath) == true;
+ return _options?.Unpack?.IsMatch(relativeParentPath) == true;
}
private void InsertsDone(Filesystem filesystem, List files)
{
- Directory.CreateDirectory(
- Path.GetDirectoryName(_destPath)
- ?? throw new InvalidOperationException());
+ string dir = Path.GetDirectoryName(_destPath);
+ if (!string.IsNullOrEmpty(dir))
+ Directory.CreateDirectory(dir);
+
Disk.WriteFileSystem(_destPath, filesystem,
- new Disk.FilesystemFilesAndLinks { Files = files, Links = null }, _metadata);
+ new Disk.FilesystemFilesAndLinks { Files = files }, _metadata);
}
}
}
diff --git a/AsarSharp/AsarExtractor.cs b/AsarSharp/AsarExtractor.cs
index 96aca5d..29ba9d9 100644
--- a/AsarSharp/AsarExtractor.cs
+++ b/AsarSharp/AsarExtractor.cs
@@ -159,13 +159,6 @@ namespace AsarSharp
FilesystemEntry file, HashSet dirCache)
{
var linkSrcPath = Extensions.GetDirectoryName(Path.Combine(dest, file.Link));
- var linkDestPath = Extensions.GetDirectoryName(destFilename);
- var relativeLinkPath = Extensions.GetRelativePath(linkDestPath, linkSrcPath);
-
- try { File.Delete(destFilename); }
- catch { /* ignore — failing to remove an existing link is non-fatal */ }
-
- var linkTo = Path.Combine(relativeLinkPath, Path.GetFileName(file.Link));
if (!Extensions.IsPathInside(dest, linkSrcPath))
{
@@ -173,6 +166,12 @@ namespace AsarSharp
$"{fullPath}: file \"{file.Link}\" links out of the package to \"{linkSrcPath}\"");
}
+ try { File.Delete(destFilename); }
+ catch (Exception e) when (e is IOException || e is UnauthorizedAccessException)
+ {
+ // Nothing to replace, or the old entry is locked; the copy below reports the real failure.
+ }
+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var targetPath = Path.Combine(linkSrcPath, Path.GetFileName(file.Link));
@@ -189,8 +188,10 @@ namespace AsarSharp
}
else
{
+ var linkDestPath = Extensions.GetDirectoryName(destFilename);
+ var relativeLinkPath = Extensions.GetRelativePath(linkDestPath, linkSrcPath);
EnsureParentDir(destFilename, dirCache);
- Extensions.CreateSymbolicLink(linkTo, destFilename);
+ Extensions.CreateSymbolicLink(Path.Combine(relativeLinkPath, Path.GetFileName(file.Link)), destFilename);
}
}
}
diff --git a/AsarSharp/AsarFileSystem/Disk.cs b/AsarSharp/AsarFileSystem/Disk.cs
index d83e11a..509fc5e 100644
--- a/AsarSharp/AsarFileSystem/Disk.cs
+++ b/AsarSharp/AsarFileSystem/Disk.cs
@@ -12,8 +12,6 @@ namespace AsarSharp.AsarFileSystem
public static class Disk
{
private const int StreamBufferSize = 1024 * 1024;
- private static readonly ConcurrentDictionary _filesystemCache =
- new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase);
public class ArchiveHeader
{
@@ -25,7 +23,6 @@ namespace AsarSharp.AsarFileSystem
public class FilesystemFilesAndLinks
{
public List Files { get; set; } = new List();
- public List Links { get; set; } = new List();
}
public class BasicFileInfo
@@ -42,14 +39,14 @@ namespace AsarSharp.AsarFileSystem
65536, FileOptions.SequentialScan))
{
byte[] sizeBuf = new byte[8];
- if (fs.Read(sizeBuf, 0, 8) != 8)
+ if (fs.ReadFull(sizeBuf, 0, 8) != 8)
throw new Exception("Unable to read header size");
var sizePickle = Pickle.CreateFromBuffer(sizeBuf);
var size = sizePickle.CreateIterator().ReadUInt32();
var headerBuf = new byte[size];
- if (fs.Read(headerBuf, 0, (int)size) != size)
+ if (fs.ReadFull(headerBuf, 0, (int)size) != size)
throw new Exception("Unable to read header");
var headerPickle = Pickle.CreateFromBuffer(headerBuf);
@@ -65,62 +62,28 @@ namespace AsarSharp.AsarFileSystem
}
}
+ ///
+ /// Reads the header fresh every time: an archive is repacked in place during a patch run,
+ /// so a cached header would hand out stale offsets on the next read of the same path.
+ ///
public static Filesystem ReadFilesystemSync(string archivePath)
{
- return _filesystemCache.GetOrAdd(archivePath, key =>
- {
- var header = ReadArchiveHeaderSync(key);
- var filesystem = new Filesystem(key);
- filesystem.SetHeader(header.Header, header.HeaderSize);
- return filesystem;
- });
- }
-
- public static byte[] ReadFileSync(Filesystem filesystem, string filename, FilesystemEntry info)
- {
- if (!info.IsFile || !info.Size.HasValue)
- throw new ArgumentException("Entry is not a file", nameof(info));
-
- long size = info.Size.Value;
- byte[] buffer = new byte[size];
-
- if (size <= 0) return buffer;
-
- if (info.Unpacked == true)
- {
- string filePath = Path.Combine($"{filesystem.GetRootPath()}.unpacked", filename);
- return File.ReadAllBytes(filePath);
- }
-
- using (var fs = new FileStream(filesystem.GetRootPath(), FileMode.Open, FileAccess.Read,
- FileShare.Read, 65536, FileOptions.RandomAccess))
- {
- long offset = 8 + filesystem.GetHeaderSize() + long.Parse(info.Offset);
- fs.Position = offset;
- int bytesRead = fs.Read(buffer, 0, (int)size);
- if (bytesRead != size)
- throw new Exception($"Failed to read entire file, got {bytesRead} bytes instead of {size}");
- }
-
- return buffer;
+ var header = ReadArchiveHeaderSync(archivePath);
+ var filesystem = new Filesystem(archivePath);
+ filesystem.SetHeader(header.Header, header.HeaderSize);
+ return filesystem;
}
#endregion
- public static bool UncacheFilesystem(string archivePath)
- {
- return _filesystemCache.TryRemove(archivePath, out _);
- }
-
- public static void UncacheAll()
- {
- _filesystemCache.Clear();
- }
-
public static void CopyFile(string dest, string rootPath, string filename)
{
- if (dest == null || rootPath == null || filename == null)
- throw new ArgumentNullException();
+ if (dest == null)
+ throw new ArgumentNullException(nameof(dest));
+ if (rootPath == null)
+ throw new ArgumentNullException(nameof(rootPath));
+ if (filename == null)
+ throw new ArgumentNullException(nameof(filename));
string normalizedDestRoot = Path.GetFullPath(dest)
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
@@ -192,6 +155,18 @@ namespace AsarSharp.AsarFileSystem
var patchedSizePickle = Pickle.CreateEmpty();
patchedSizePickle.WriteUInt32((uint)patchedPickle.GetTotalSize());
+ // The rewrite lands on top of the placeholder header, so it must be exactly as
+ // long. Placeholder hashes are the same width as real ones, so this holds unless
+ // a file changed size between crawl and write - which would silently shred the
+ // payload that follows.
+ if (patchedPickle.GetTotalSize() != headerPickle.GetTotalSize() ||
+ patchedSizePickle.GetTotalSize() != sizePickleSize)
+ {
+ throw new InvalidOperationException(
+ "ASAR header changed size while packing (a source file was modified mid-build). " +
+ "Aborting rather than writing a corrupt archive.");
+ }
+
fs.Position = 0;
patchedSizePickle.WriteTo(fs);
patchedPickle.WriteTo(fs);
diff --git a/AsarSharp/AsarFileSystem/FileSystem.cs b/AsarSharp/AsarFileSystem/FileSystem.cs
index e577c4e..0410245 100644
--- a/AsarSharp/AsarFileSystem/FileSystem.cs
+++ b/AsarSharp/AsarFileSystem/FileSystem.cs
@@ -33,7 +33,7 @@ namespace AsarSharp.AsarFileSystem
_headerSize = headerSize;
}
- public FilesystemEntry SearchNodeFromDirectory(string p)
+ public FilesystemEntry SearchNodeFromDirectory(string p, bool create = true)
{
FilesystemEntry json = _header;
@@ -59,12 +59,31 @@ namespace AsarSharp.AsarFileSystem
string seg = p.Substring(start, segLen);
if (!json.IsDirectory)
- throw new Exception($"Unexpected directory state while traversing: {p}");
+ {
+ if (create)
+ throw new Exception($"Unexpected directory state while traversing: {p}");
+ return null;
+ }
+
+ if (json.Files == null)
+ {
+ if (create)
+ json.Files = new Dictionary(StringComparer.Ordinal);
+ else
+ return null;
+ }
if (!json.Files.TryGetValue(seg, out var child))
{
- child = new FilesystemEntry { Files = new Dictionary(StringComparer.Ordinal) };
- json.Files[seg] = child;
+ if (create)
+ {
+ child = new FilesystemEntry { Files = new Dictionary(StringComparer.Ordinal) };
+ json.Files[seg] = child;
+ }
+ else
+ {
+ return null;
+ }
}
json = child;
start = end + 1;
@@ -81,7 +100,7 @@ namespace AsarSharp.AsarFileSystem
string name = Path.GetFileName(rel);
string dir = Extensions.GetDirectoryName(rel);
- var parent = SearchNodeFromDirectory(dir);
+ var parent = SearchNodeFromDirectory(dir, true);
if (parent.Files == null)
parent.Files = new Dictionary(StringComparer.Ordinal);
@@ -111,18 +130,23 @@ namespace AsarSharp.AsarFileSystem
}
}
- public FilesystemEntry GetNode(string p, bool followLinks = true)
+ public FilesystemEntry GetNode(string p, bool followLinks = true, int linkDepth = 0)
{
+ if (linkDepth > 40)
+ throw new Exception($"Symlink loop detected at {p}");
+
p = p.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);
- FilesystemEntry node = SearchNodeFromDirectory(Extensions.GetDirectoryName(p));
+ FilesystemEntry node = SearchNodeFromDirectory(Extensions.GetDirectoryName(p), false);
+ if (node == null)
+ return null;
string name = Path.GetFileName(p);
if (node.IsLink && followLinks)
- return GetNode(Path.Combine(node.Link, name));
+ return GetNode(Path.Combine(node.Link, name), followLinks, linkDepth + 1);
if (!string.IsNullOrEmpty(name))
{
- if (node.IsDirectory && node.Files.TryGetValue(name, out var entry))
+ if (node.IsDirectory && node.Files != null && node.Files.TryGetValue(name, out var entry))
return entry;
return null;
}
@@ -130,16 +154,17 @@ namespace AsarSharp.AsarFileSystem
return node;
}
- public FilesystemEntry GetFile(string p, bool followLinks = true)
+ public FilesystemEntry GetFile(string p, bool followLinks = true, int linkDepth = 0)
{
- FilesystemEntry info = GetNode(p, followLinks);
+ if (linkDepth > 40)
+ throw new Exception($"Symlink loop detected at {p}");
+
+ FilesystemEntry info = GetNode(p, followLinks, linkDepth);
if (info == null) throw new Exception($"\"{p}\" was not found in this archive");
- if (info.IsLink && followLinks) return GetFile(info.Link, followLinks);
+ if (info.IsLink && followLinks) return GetFile(info.Link, followLinks, linkDepth + 1);
return info;
}
- public static string ReadLink(string path) => throw new NotImplementedException();
-
#region Writing
public FilesystemEntry SearchNodeFromPath(string p)
@@ -159,7 +184,7 @@ namespace AsarSharp.AsarFileSystem
public void InsertFile(string path, bool shouldUnpack, CrawledFileType file,
IntegrityHelper.FileIntegrity precomputedIntegrity = null)
{
- var (dirNode, _) = SearchNodeFromPathWithParent(Path.GetDirectoryName(path) ?? path);
+ var (dirNode, _) = SearchNodeFromPathWithParent(path);
var node = SearchNodeFromPath(path);
long size;
diff --git a/AsarSharp/AsarFileSystem/FileSystemCrawler.cs b/AsarSharp/AsarFileSystem/FileSystemCrawler.cs
index a4ee35e..6bf5ea9 100644
--- a/AsarSharp/AsarFileSystem/FileSystemCrawler.cs
+++ b/AsarSharp/AsarFileSystem/FileSystemCrawler.cs
@@ -9,13 +9,6 @@ namespace AsarSharp.AsarFileSystem
{
public FileType Type { get; set; }
public FileSystemInfo Stat { get; set; }
- public TransformedFile Transformed { get; set; }
- }
-
- public class TransformedFile
- {
- public string Path { get; set; }
- public FileSystemInfo Stat { get; set; }
}
public enum FileType
@@ -36,7 +29,7 @@ namespace AsarSharp.AsarFileSystem
}
catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException)
{
- return null;
+ throw new IOException($"Failed to read attributes for '{filename}'", ex);
}
bool isDirectory = (attributes & FileAttributes.Directory) == FileAttributes.Directory;
@@ -59,7 +52,6 @@ namespace AsarSharp.AsarFileSystem
foreach (var fullPath in CrawlIterative(dir))
{
var type = DetermineFileType(fullPath);
- if (type == null) continue;
metadata[fullPath] = type;
if (type.Type == FileType.Link) links.Add(fullPath);
filenames.Add(fullPath);
@@ -77,7 +69,8 @@ namespace AsarSharp.AsarFileSystem
{
if (string.Equals(filename, link, StringComparison.OrdinalIgnoreCase)) continue;
- if (filename.StartsWith(link, StringComparison.OrdinalIgnoreCase))
+ // Require a separator after the prefix so "…/foobar" does not match link "…/foo".
+ if (filename.StartsWith(link + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase))
{
string rel = Extensions.GetRelativePath(link, fileDir);
if (!rel.StartsWith("..", StringComparison.Ordinal))
@@ -120,7 +113,7 @@ namespace AsarSharp.AsarFileSystem
foreach (var entry in entries)
{
result.Add(entry.FullName);
- if (entry is DirectoryInfo subDir)
+ if (entry is DirectoryInfo subDir && (subDir.Attributes & FileAttributes.ReparsePoint) == 0)
stack.Push(subDir);
}
}
diff --git a/AsarSharp/Integrity/IntegrityHelper.cs b/AsarSharp/Integrity/IntegrityHelper.cs
index f6c5302..fb76582 100644
--- a/AsarSharp/Integrity/IntegrityHelper.cs
+++ b/AsarSharp/Integrity/IntegrityHelper.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
+using AsarSharp.Utils;
using Newtonsoft.Json;
namespace AsarSharp.Integrity
@@ -60,7 +61,9 @@ namespace AsarSharp.Integrity
var blockHashes = new List(estimatedBlockCount);
int bytesRead;
- while ((bytesRead = fileStream.Read(reusableBuffer, 0, reusableBuffer.Length)) > 0)
+ // ReadFull, not Read: a short read would hash a partial block and produce
+ // integrity blocks Electron rejects.
+ while ((bytesRead = fileStream.ReadFull(reusableBuffer, 0, reusableBuffer.Length)) > 0)
{
blockHashes.Add(ToLowerHex(blockHash.ComputeHash(reusableBuffer, 0, bytesRead)));
fileHash.AppendData(reusableBuffer, 0, bytesRead);
diff --git a/AsarSharp/PickleTools/Pickle.cs b/AsarSharp/PickleTools/Pickle.cs
index c192a8f..b02e72a 100644
--- a/AsarSharp/PickleTools/Pickle.cs
+++ b/AsarSharp/PickleTools/Pickle.cs
@@ -28,16 +28,18 @@ namespace AsarSharp.PickleTools
{
if (buffer != null)
{
+ if (buffer.Length < SIZE_UINT32)
+ throw new ArgumentException("Buffer is too small.", nameof(buffer));
+
_header = buffer;
- _headerSize = buffer.Length - GetPayloadSize();
+ int payloadSize = GetPayloadSize();
+ if (payloadSize > buffer.Length)
+ throw new ArgumentException("Payload size exceeds buffer length.", nameof(buffer));
+
+ _headerSize = buffer.Length - payloadSize;
_capacityAfterHeader = CAPACITY_READ_ONLY;
_writeOffset = 0;
- if (_headerSize > buffer.Length)
- {
- _headerSize = 0;
- }
-
if (_headerSize != AlignInt(_headerSize, SIZE_UINT32))
{
_headerSize = 0;
@@ -86,7 +88,7 @@ namespace AsarSharp.PickleTools
}
- public bool WriteBool(bool value) => WriteInt(value ? 1 : 0);
+
public bool WriteInt(int value)
{
@@ -121,74 +123,7 @@ namespace AsarSharp.PickleTools
return true;
}
- public bool WriteInt64(long value)
- {
- const int dataLength = SIZE_INT64;
- int newSize = _writeOffset + dataLength;
- if (newSize > _capacityAfterHeader)
- {
- Resize(Math.Max((int)_capacityAfterHeader * 2, newSize));
- }
-
- WriteInt64LE(value, _headerSize + _writeOffset);
- SetPayloadSize(newSize);
- _writeOffset = newSize;
- return true;
- }
-
-
- public bool WriteUInt64(ulong value)
- {
- const int dataLength = SIZE_UINT64;
- int newSize = _writeOffset + dataLength;
-
- if (newSize > _capacityAfterHeader)
- {
- Resize(Math.Max((int)_capacityAfterHeader * 2, newSize));
- }
-
- WriteUInt64LE(value, _headerSize + _writeOffset);
- SetPayloadSize(newSize);
- _writeOffset = newSize;
- return true;
- }
-
- public bool WriteFloat(float value)
- {
- const int dataLength = SIZE_FLOAT;
- int newSize = _writeOffset + dataLength;
-
- if (newSize > _capacityAfterHeader)
- {
- Resize(Math.Max((int)_capacityAfterHeader * 2, newSize));
- }
-
- int bits = BitConverter.ToInt32(BitConverter.GetBytes(value), 0);
- WriteInt32LE(bits, _headerSize + _writeOffset);
-
- SetPayloadSize(newSize);
- _writeOffset = newSize;
- return true;
- }
-
- public bool WriteDouble(double value)
- {
- const int dataLength = SIZE_DOUBLE;
- int newSize = _writeOffset + dataLength;
-
- if (newSize > _capacityAfterHeader)
- {
- Resize(Math.Max((int)_capacityAfterHeader * 2, newSize));
- }
-
- long bits = BitConverter.DoubleToInt64Bits(value);
- WriteInt64LE(bits, _headerSize + _writeOffset);
-
- SetPayloadSize(newSize);
- _writeOffset = newSize;
- return true;
- }
public bool WriteString(string value)
{
@@ -226,7 +161,13 @@ namespace AsarSharp.PickleTools
WriteUInt32LE((uint)payloadSize, 0);
}
- public int GetPayloadSize() => (int)ReadUInt32LE(0);
+ public int GetPayloadSize()
+ {
+ uint size = ReadUInt32LE(0);
+ if (size > int.MaxValue)
+ throw new InvalidOperationException("Payload size exceeds maximum allowed (2GB).");
+ return (int)size;
+ }
private void Resize(int newCapacity)
{
@@ -275,29 +216,7 @@ namespace AsarSharp.PickleTools
_header[offset + 3] = (byte)(value >> 24);
}
- private void WriteInt64LE(long value, int offset)
- {
- _header[offset] = (byte)value;
- _header[offset + 1] = (byte)(value >> 8);
- _header[offset + 2] = (byte)(value >> 16);
- _header[offset + 3] = (byte)(value >> 24);
- _header[offset + 4] = (byte)(value >> 32);
- _header[offset + 5] = (byte)(value >> 40);
- _header[offset + 6] = (byte)(value >> 48);
- _header[offset + 7] = (byte)(value >> 56);
- }
- private void WriteUInt64LE(ulong value, int offset)
- {
- _header[offset] = (byte)value;
- _header[offset + 1] = (byte)(value >> 8);
- _header[offset + 2] = (byte)(value >> 16);
- _header[offset + 3] = (byte)(value >> 24);
- _header[offset + 4] = (byte)(value >> 32);
- _header[offset + 5] = (byte)(value >> 40);
- _header[offset + 6] = (byte)(value >> 48);
- _header[offset + 7] = (byte)(value >> 56);
- }
#endregion
diff --git a/AsarSharp/PickleTools/PickleIterator.cs b/AsarSharp/PickleTools/PickleIterator.cs
index 11d069a..95647e7 100644
--- a/AsarSharp/PickleTools/PickleIterator.cs
+++ b/AsarSharp/PickleTools/PickleIterator.cs
@@ -18,10 +18,7 @@ namespace AsarSharp.PickleTools
_endIndex = pickle.GetPayloadSize();
}
- public bool ReadBool()
- {
- return ReadInt() != 0;
- }
+
public int ReadInt()
{
@@ -33,25 +30,7 @@ namespace AsarSharp.PickleTools
return ReadBytes(Pickle.SIZE_UINT32, BitConverter.ToUInt32);
}
- public long ReadInt64()
- {
- return ReadBytes(Pickle.SIZE_INT64, BitConverter.ToInt64);
- }
- public ulong ReadUInt64()
- {
- return ReadBytes(Pickle.SIZE_UINT64, BitConverter.ToUInt64);
- }
-
- public float ReadFloat()
- {
- return ReadBytes(Pickle.SIZE_FLOAT, BitConverter.ToSingle);
- }
-
- public double ReadDouble()
- {
- return ReadBytes(Pickle.SIZE_DOUBLE, BitConverter.ToDouble);
- }
public string ReadString()
{
@@ -75,7 +54,7 @@ namespace AsarSharp.PickleTools
private int GetReadPayloadOffsetAndAdvance(int length)
{
- if (length > _endIndex - _readIndex)
+ if (length < 0 || length > _endIndex - _readIndex)
{
_readIndex = _endIndex;
throw new InvalidOperationException($"Failed to read data with length of {length}");
diff --git a/AsarSharp/Utils/Extensions.cs b/AsarSharp/Utils/Extensions.cs
index 3abaf5f..34dad7f 100644
--- a/AsarSharp/Utils/Extensions.cs
+++ b/AsarSharp/Utils/Extensions.cs
@@ -5,8 +5,30 @@ using System.Text;
namespace AsarSharp.Utils
{
- internal static class Extensions
+ public static class Extensions
{
+ ///
+ /// Fills bytes. Stream.Read may legally return fewer than
+ /// asked for; treating a short read as EOF corrupts header parsing and block hashes.
+ /// Returns the bytes actually read, which is less than count only at end of stream.
+ ///
+ public static int ReadFull(this Stream stream, byte[] buffer, int offset, int count)
+ {
+ int total = 0;
+ while (total < count)
+ {
+ int read = stream.Read(buffer, offset + total, count - total);
+ if (read <= 0)
+ {
+ break;
+ }
+
+ total += read;
+ }
+
+ return total;
+ }
+
///
/// Compute path relative to .
/// Fast common-case (path is inside relativeTo): plain prefix-strip.
@@ -170,19 +192,7 @@ namespace AsarSharp.Utils
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return;
- var process = new System.Diagnostics.Process
- {
- StartInfo = new System.Diagnostics.ProcessStartInfo
- {
- FileName = "chmod",
- Arguments = $"{permission} \"{filePath}\"",
- UseShellExecute = false,
- RedirectStandardOutput = true,
- CreateNoWindow = true
- }
- };
- process.Start();
- process.WaitForExit();
+ RunTool("chmod", $"{permission} \"{filePath}\"");
}
@@ -190,32 +200,41 @@ namespace AsarSharp.Utils
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
- NativeMethods.CreateSymbolicLink(linkPath, linkTarget,
+ bool success = NativeMethods.CreateSymbolicLink(linkPath, linkTarget,
Directory.Exists(linkTarget)
? NativeMethods.SymLinkFlag.Directory
: NativeMethods.SymLinkFlag.File);
+ if (!success)
+ throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
return;
}
- var process = new System.Diagnostics.Process
- {
- StartInfo = new System.Diagnostics.ProcessStartInfo
- {
- FileName = "ln",
- Arguments = $"-s \"{linkTarget}\" \"{linkPath}\"",
- UseShellExecute = false,
- RedirectStandardOutput = true,
- CreateNoWindow = true
- }
- };
- process.Start();
- process.WaitForExit();
+ RunTool("ln", $"-s \"{linkTarget}\" \"{linkPath}\"");
}
-
public static bool IsWindowsPlatform()
{
- return Environment.OSVersion.Platform == PlatformID.Win32NT;
+ return RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
+ }
+
+ private static void RunTool(string fileName, string arguments)
+ {
+ using (var process = new System.Diagnostics.Process
+ {
+ StartInfo = new System.Diagnostics.ProcessStartInfo
+ {
+ FileName = fileName,
+ Arguments = arguments,
+ UseShellExecute = false,
+ CreateNoWindow = true
+ }
+ })
+ {
+ process.Start();
+ process.WaitForExit();
+ if (process.ExitCode != 0)
+ throw new InvalidOperationException($"Tool {fileName} failed with exit code {process.ExitCode}.");
+ }
}
}
}