Skip to content

Commit

Permalink
VCST-1438: Fix 32/64 bit conflict when copying DLL files (#2811)
Browse files Browse the repository at this point in the history
Co-authored-by: Oleg Zhuk <[email protected]>
Co-authored-by: artem-dudarev <[email protected]>
  • Loading branch information
3 people committed Jul 3, 2024
1 parent c729ae4 commit 8bb7347
Show file tree
Hide file tree
Showing 10 changed files with 442 additions and 149 deletions.
2 changes: 2 additions & 0 deletions VirtoCommerce.Platform.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=15b5b1f1_002D457c_002D4ca6_002Db278_002D5615aedc07d3/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=auditable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=hangfire/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=postgre/@EntryIndexedValue">True</s:Boolean>
Expand Down
16 changes: 16 additions & 0 deletions src/VirtoCommerce.Platform.Core/Modularity/FileCompareResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace VirtoCommerce.Platform.Core.Modularity;

public class FileCompareResult
{
public bool NewFile { get; set; }
public bool NewDate { get; set; }

public bool SameVersion { get; set; }
public bool NewVersion { get; set; }
public bool SameOrNewVersion => SameVersion || NewVersion;

public bool CompatibleArchitecture { get; set; }
public bool SameArchitecture { get; set; }
public bool NewArchitecture { get; set; }
public bool SameOrNewArchitecture => SameArchitecture || NewArchitecture;
}
8 changes: 8 additions & 0 deletions src/VirtoCommerce.Platform.Core/Modularity/IFileCopyPolicy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Runtime.InteropServices;

namespace VirtoCommerce.Platform.Core.Modularity;

public interface IFileCopyPolicy
{
bool IsCopyRequired(Architecture environment, string sourceFilePath, string targetFilePath, out FileCompareResult result);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;
using System.Runtime.InteropServices;

namespace VirtoCommerce.Platform.Core.Modularity
{
public interface IFileMetadataProvider
{
bool Exists(string filePath);
DateTime? GetDate(string filePath);
Version GetVersion(string filePath);
Architecture? GetArchitecture(string filePath);
}
}
64 changes: 64 additions & 0 deletions src/VirtoCommerce.Platform.Modules/Local/FileCopyPolicy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System.Runtime.InteropServices;
using VirtoCommerce.Platform.Core.Modularity;

namespace VirtoCommerce.Platform.Modules.Local;

public class FileCopyPolicy : IFileCopyPolicy
{
private readonly IFileMetadataProvider _metadataProvider;

public FileCopyPolicy(IFileMetadataProvider metadataProvider)
{
_metadataProvider = metadataProvider;
}

public bool IsCopyRequired(Architecture environment, string sourceFilePath, string targetFilePath, out FileCompareResult result)
{
result = new FileCompareResult
{
NewFile = !_metadataProvider.Exists(targetFilePath),
};

CompareDates(sourceFilePath, targetFilePath, result);
CompareVersions(sourceFilePath, targetFilePath, result);
CompareArchitecture(sourceFilePath, targetFilePath, environment, result);

return result.NewFile && result.CompatibleArchitecture ||
result.NewVersion && result.SameOrNewArchitecture ||
result.NewArchitecture && result.SameOrNewVersion ||
result.NewDate && result.SameOrNewArchitecture && result.SameOrNewVersion;
}

private void CompareDates(string sourceFilePath, string targetFilePath, FileCompareResult result)
{
var sourceDate = _metadataProvider.GetDate(sourceFilePath);
var targetDate = _metadataProvider.GetDate(targetFilePath);

result.NewDate = sourceDate > targetDate;
}

private void CompareVersions(string sourceFilePath, string targetFilePath, FileCompareResult result)
{
var sourceVersion = _metadataProvider.GetVersion(sourceFilePath);
var targetVersion = _metadataProvider.GetVersion(targetFilePath);

result.SameVersion = sourceVersion == targetVersion;
result.NewVersion = targetVersion is not null && sourceVersion > targetVersion;
}

private void CompareArchitecture(string sourceFilePath, string targetFilePath, Architecture environment, FileCompareResult result)
{
var sourceArchitecture = _metadataProvider.GetArchitecture(sourceFilePath);
var targetArchitecture = _metadataProvider.GetArchitecture(targetFilePath);

result.CompatibleArchitecture = sourceArchitecture == targetArchitecture ||
sourceArchitecture == environment ||
sourceArchitecture == Architecture.X86 && environment == Architecture.X64;

if (result.CompatibleArchitecture)
{
result.SameArchitecture = sourceArchitecture == targetArchitecture;
result.NewArchitecture = sourceArchitecture == environment && targetArchitecture != environment;
}
}
}
100 changes: 100 additions & 0 deletions src/VirtoCommerce.Platform.Modules/Local/FileMetadataProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Extensions.Options;
using VirtoCommerce.Platform.Core.Modularity;

namespace VirtoCommerce.Platform.Modules.Local;

public class FileMetadataProvider : IFileMetadataProvider
{
private readonly LocalStorageModuleCatalogOptions _options;

public FileMetadataProvider(IOptions<LocalStorageModuleCatalogOptions> options)
{
_options = options.Value;
}

public bool Exists(string filePath)
{
return File.Exists(filePath);
}

public DateTime? GetDate(string filePath)
{
if (!File.Exists(filePath))
{
return null;
}

var fileInfo = new FileInfo(filePath);

return fileInfo.LastWriteTimeUtc;
}

public Version GetVersion(string filePath)
{
if (!File.Exists(filePath))
{
return null;
}

var fileVersionInfo = FileVersionInfo.GetVersionInfo(filePath);

return new Version(
fileVersionInfo.FileMajorPart,
fileVersionInfo.FileMinorPart,
fileVersionInfo.FileBuildPart,
fileVersionInfo.FilePrivatePart);
}

public Architecture? GetArchitecture(string filePath)
{
if (!_options.AssemblyFileExtensions.Any(x => filePath.EndsWith(x, StringComparison.OrdinalIgnoreCase)))
{
return null;
}

const int startPosition = 0x3C;
const int peSignature = 0x00004550;

var fileInfo = new FileInfo(filePath);
if (!fileInfo.Exists || fileInfo.Length < startPosition + sizeof(uint))
{
return null;
}

using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
using var reader = new BinaryReader(stream);

stream.Seek(startPosition, SeekOrigin.Begin);
var peOffset = reader.ReadUInt32();

if (fileInfo.Length < peOffset + sizeof(uint) + sizeof(ushort))
{
return null;
}

stream.Seek(peOffset, SeekOrigin.Begin);
var peHead = reader.ReadUInt32();

if (peHead != peSignature)
{
return null;
}

var machineType = reader.ReadUInt16();

// https://stackoverflow.com/questions/480696/how-to-find-if-a-native-dll-file-is-compiled-as-x64-or-x86
return machineType switch
{
0x8664 => Architecture.X64,
0xAA64 => Architecture.Arm64,
0x1C0 => Architecture.Arm,
0x14C => Architecture.X86,
_ => null
};
}
}
Loading

0 comments on commit 8bb7347

Please sign in to comment.