cmake_minimum_required (VERSION 3.14)
+project(corehost)
+
include(../settings.cmake)
include(../functions.cmake)
add_subdirectory(cli)
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
+using System.ComponentModel;
using System.IO;
using System.IO.MemoryMappedFiles;
+using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
/// hash value embedded in default apphost executable in a place where the path to the app binary should be stored.
/// </summary>
private const string AppBinaryPathPlaceholder = "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2";
- private readonly static byte[] AppBinaryPathPlaceholderSearchValue = Encoding.UTF8.GetBytes(AppBinaryPathPlaceholder);
+ private static readonly byte[] AppBinaryPathPlaceholderSearchValue = Encoding.UTF8.GetBytes(AppBinaryPathPlaceholder);
/// <summary>
/// Create an AppHost with embedded configuration of app binary location
}
BinaryUtils.CopyFile(appHostSourceFilePath, appHostDestinationFilePath);
+
bool appHostIsPEImage = false;
void RewriteAppHost()
}
void UpdateResources()
- {
+ {
if (assemblyToCopyResorcesFrom != null && appHostIsPEImage)
{
if (ResourceUpdater.IsSupportedOS())
try
{
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ var filePermissionOctal = Convert.ToInt32("755", 8); // -rwxr-xr-x
+ const int EINTR = 4;
+ int chmodReturnCode = 0;
+
+ do
+ {
+ chmodReturnCode = chmod(appHostDestinationFilePath, filePermissionOctal);
+ }
+ while (chmodReturnCode == -1 && Marshal.GetLastWin32Error() == EINTR);
+
+ if (chmodReturnCode == -1)
+ {
+ throw new Win32Exception(Marshal.GetLastWin32Error(), $"Could not set file permission {filePermissionOctal} for {appHostDestinationFilePath}.");
+ }
+ }
+
RetryUtil.RetryOnIOError(RewriteAppHost);
RetryUtil.RetryOnWin32Error(UpdateResources);
};
// Re-write the destination apphost with the proper contents.
- RetryUtil.RetryOnIOError(() =>
+ RetryUtil.RetryOnIOError(() =>
BinaryUtils.SearchAndReplace(appHostPath,
bundleHeaderPlaceholder,
- BitConverter.GetBytes(bundleHeaderOffset),
- pad0s:false));
+ BitConverter.GetBytes(bundleHeaderOffset),
+ pad0s: false));
// Memory-mapped write does not updating last write time
- RetryUtil.RetryOnIOError(() =>
+ RetryUtil.RetryOnIOError(() =>
File.SetLastWriteTimeUtc(appHostPath, DateTime.UtcNow));
}
return headerOffset != 0;
}
+
+ [DllImport("libc", SetLastError = true)]
+ private static extern int chmod(string pathname, int mode);
}
}
<TestInfraTargetFramework>netcoreapp3.0</TestInfraTargetFramework>
</PropertyGroup>
+ <PropertyGroup>
+ <TargetOSTrait Condition="'$(OSGroup)' == 'Windows_NT'">nonwindowstests</TargetOSTrait>
+ <TargetOSTrait Condition="'$(OSGroup)' == 'Linux'">nonlinuxtests</TargetOSTrait>
+ <TargetOSTrait Condition="'$(OSGroup)' == 'OSX'">nonosxtests</TargetOSTrait>
+ <TargetOSTrait Condition="'$(OSGroup)' == 'FreeBSD'">nonfreebsdtests</TargetOSTrait>
+ <TargetOSTrait Condition="'$(OSGroup)' == 'NetBSD'">nonnetbsdtests</TargetOSTrait>
+
+ <TestRunnerAdditionalArguments Condition="'$(TargetOSTrait)' != ''">-notrait category=$(TargetOSTrait)</TestRunnerAdditionalArguments>
+ </PropertyGroup>
+
</Project>
</ItemGroup>
<ItemGroup>
- <PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="2.1.0" />
- <PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="2.1.0" />
+ <PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="$(MicrosoftDotNetPlatformAbstractionsPackageVersion)" />
<PackageReference Include="Microsoft.Win32.Registry" Version="4.3.0" />
</ItemGroup>
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
using System;
using System.IO;
using System.Linq;
+using System.Reflection;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Text;
using FluentAssertions;
using Xunit;
}
}
+ [Fact]
+ [PlatformSpecific(TestPlatforms.AnyUnix)]
+ public void ItGeneratesExecutableImage()
+ {
+ using (TestDirectory testDirectory = TestDirectory.Create())
+ {
+ string sourceAppHostMock = PrepareAppHostMockFile(testDirectory);
+ string destinationFilePath = Path.Combine(testDirectory.Path, "DestinationAppHost.exe.mock");
+ string appBinaryFilePath = "Test/App/Binary/Path.dll";
+
+ chmod(sourceAppHostMock, Convert.ToInt32("444", 8)) // make it readonly: -r--r--r--
+ .Should()
+ .NotBe(-1);
+
+ GetLastError()
+ .Should()
+ .NotBe(4); // EINTR
+
+ GetFilePermissionValue(sourceAppHostMock)
+ .Should()
+ .Be(Convert.ToInt32("444", 8));
+
+ HostWriter.CreateAppHost(
+ sourceAppHostMock,
+ destinationFilePath,
+ appBinaryFilePath,
+ windowsGraphicalUserInterface: true);
+
+ GetFilePermissionValue(destinationFilePath)
+ .Should()
+ .Be(Convert.ToInt32("755", 8));
+ }
+
+ int GetLastError() => Marshal.GetLastWin32Error();
+ }
+
private string PrepareAppHostMockFile(TestDirectory testDirectory, Action<byte[]> customize = null)
{
// For now we're testing the AppHost on Windows PE files only.
0, 112, 2, 0, 0, 4, 0, 0, 0, 0, 0, 0, 3, 0, 96, 193, 0, 0, 24,
0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0 };
+ [DllImport("libc", SetLastError = true)]
+ private static extern int chmod(string pathname, int mode);
+
+ private static int GetFilePermissionValue(string path)
+ {
+ var modeValue = CoreFxFileStatusProvider.GetFileMode(path);
+
+ // st_mode is typically a 16-bits value, high 4 bits are filetype and low 12
+ // bits are permission. we will clear first 20 bits (a byte and a nibble) with
+ // the following mask:
+ modeValue &= 0x1ff;
+
+ modeValue
+ .Should()
+ .BeInRange(0, 511);
+
+ return modeValue;
+ }
+
+ private static class CoreFxFileStatusProvider
+ {
+ private static FieldInfo s_fileSystem_fileStatusField, s_fileStatus_fileStatusField, s_fileStatusModeField;
+
+ static CoreFxFileStatusProvider()
+ {
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ try
+ {
+ s_fileSystem_fileStatusField = typeof(FileSystemInfo).GetField("_fileStatus", BindingFlags.NonPublic | BindingFlags.Instance);
+ s_fileStatus_fileStatusField = s_fileSystem_fileStatusField.FieldType.GetField("_fileStatus", BindingFlags.NonPublic | BindingFlags.Instance);
+ s_fileStatusModeField = s_fileStatus_fileStatusField.FieldType.GetField("Mode", BindingFlags.NonPublic | BindingFlags.Instance);
+ }
+ catch (Exception ex)
+ {
+ throw new Exception("Cannot setup _fileStatus via private reflection from CoreFX. Verify if the FileSystem._fileStatus._fileStatus.Mode chain is intact in CoreFX, otherwise adjust this implementation", ex);
+ }
+ }
+ }
+
+ public static int GetFileMode(string path)
+ {
+ try
+ {
+ var fileInfo = new FileInfo(path);
+ _ = fileInfo.IsReadOnly; // this is to implicitly initialize FileInfo -> FileSystem -> fielStatus instance
+
+ return (int)s_fileStatusModeField.GetValue(
+ s_fileStatus_fileStatusField.GetValue(
+ s_fileSystem_fileStatusField.GetValue(fileInfo)));
+ }
+ catch (Exception ex)
+ {
+ throw new Exception("Cannot get stat (2) st_mode via private reflection from CoreFX. Verify if the FileSystem._fileStatus.Initialize logic is exercised via FileInfo.IsReadOnly in CoreFX, otherwise adjust this implementation.", ex);
+ }
+ }
+ }
+
private class TestDirectory : IDisposable
{
public string Path { get; private set; }
}
}
}
-}
\ No newline at end of file
+}
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
-using Microsoft.DotNet.InternalAbstractions;
namespace Microsoft.DotNet.Cli.Build.Framework
{
public Command WithUserProfile(string userprofile)
{
string userDir;
- if (InternalAbstractions.RuntimeEnvironment.OperatingSystemPlatform == Platform.Windows)
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
userDir = "USERPROFILE";
}
bool success = exitCode == 0;
string msgExpectedToFail = "";
- if (fExpectedToFail) {
+ if (fExpectedToFail)
+ {
success = !success;
msgExpectedToFail = "failed as expected and ";
}
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="4.19.4" />
- <PackageReference Include="System.Runtime.Serialization.Primitives" Version="4.1.1" />
- <PackageReference Include="xunit" Version="2.2.0" />
- <PackageReference Include="System.Runtime.InteropServices.RuntimeInformation" Version="4.0.0" />
- <PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.0" />
+ <PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="$(MicrosoftDotNetPlatformAbstractionsPackageVersion)" />
+ <PackageReference Include="Microsoft.DotNet.XUnitExtensions" Version="$(MicrosoftDotNetXUnitExtensionsPackageVersion)" />
+ <PackageReference Include="xunit.core" Version="$(XUnitPackageVersion)" ExcludeAssets="build" />
</ItemGroup>
</Project>