diff --git a/src/installer/corehost/CMakeLists.txt b/src/installer/corehost/CMakeLists.txt index 85f683241925720a8fc94490a564d73f3101b283..2b8473f47e9eb7b1bfaa59d8397408fe3aa9eb36 100644 --- a/src/installer/corehost/CMakeLists.txt +++ b/src/installer/corehost/CMakeLists.txt @@ -1,5 +1,7 @@ cmake_minimum_required (VERSION 3.14) +project(corehost) + include(../settings.cmake) include(../functions.cmake) add_subdirectory(cli) diff --git a/src/installer/managed/Microsoft.NET.HostModel/AppHost/HostWriter.cs b/src/installer/managed/Microsoft.NET.HostModel/AppHost/HostWriter.cs index 9922c6103c6dae9625ce62aae327be88d5109593..3215ed415b3b2869a6c4d728be4ee19a6fe8412a 100644 --- a/src/installer/managed/Microsoft.NET.HostModel/AppHost/HostWriter.cs +++ b/src/installer/managed/Microsoft.NET.HostModel/AppHost/HostWriter.cs @@ -2,8 +2,10 @@ // 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; @@ -19,7 +21,7 @@ public static class HostWriter /// hash value embedded in default apphost executable in a place where the path to the app binary should be stored. /// private const string AppBinaryPathPlaceholder = "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2"; - private readonly static byte[] AppBinaryPathPlaceholderSearchValue = Encoding.UTF8.GetBytes(AppBinaryPathPlaceholder); + private static readonly byte[] AppBinaryPathPlaceholderSearchValue = Encoding.UTF8.GetBytes(AppBinaryPathPlaceholder); /// /// Create an AppHost with embedded configuration of app binary location @@ -43,6 +45,7 @@ public static class HostWriter } BinaryUtils.CopyFile(appHostSourceFilePath, appHostDestinationFilePath); + bool appHostIsPEImage = false; void RewriteAppHost() @@ -70,7 +73,7 @@ void RewriteAppHost() } void UpdateResources() - { + { if (assemblyToCopyResorcesFrom != null && appHostIsPEImage) { if (ResourceUpdater.IsSupportedOS()) @@ -89,6 +92,24 @@ void UpdateResources() 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); @@ -133,14 +154,14 @@ void 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)); } @@ -183,5 +204,8 @@ void FindBundleHeader() return headerOffset != 0; } + + [DllImport("libc", SetLastError = true)] + private static extern int chmod(string pathname, int mode); } } diff --git a/src/installer/test/Directory.Build.props b/src/installer/test/Directory.Build.props index 4b971c5b5b9b59ae732b0d68ebc2ebcd727da755..b3eaee01f0db5526c89eb71fc392a275f3825d78 100644 --- a/src/installer/test/Directory.Build.props +++ b/src/installer/test/Directory.Build.props @@ -12,4 +12,14 @@ netcoreapp3.0 + + nonwindowstests + nonlinuxtests + nonosxtests + nonfreebsdtests + nonnetbsdtests + + -notrait category=$(TargetOSTrait) + + diff --git a/src/installer/test/HostActivation.Tests/HostActivation.Tests.csproj b/src/installer/test/HostActivation.Tests/HostActivation.Tests.csproj index 76c372036eafb03ec92af1e9037621613ada8dbe..47fbf5659a81da1ede3c1354f0ae3c3fa6190baa 100644 --- a/src/installer/test/HostActivation.Tests/HostActivation.Tests.csproj +++ b/src/installer/test/HostActivation.Tests/HostActivation.Tests.csproj @@ -21,9 +21,8 @@ - - + diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.AppHost.Tests/AppHostUpdateTests.cs b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.AppHost.Tests/AppHostUpdateTests.cs index aaf2ae7e452187baf4ad9f21629364fac9c4ffb7..a48ea53931957121796664aa9a842eb673d88c29 100644 --- a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.AppHost.Tests/AppHostUpdateTests.cs +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.AppHost.Tests/AppHostUpdateTests.cs @@ -1,7 +1,13 @@ +// 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; @@ -160,6 +166,42 @@ public void ItFailsToSetGUISubsystemWithWrongDefault() } } + [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 customize = null) { // For now we're testing the AppHost on Windows PE files only. @@ -206,6 +248,64 @@ private string PrepareAppHostMockFile(TestDirectory testDirectory, Action 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; } @@ -233,4 +333,4 @@ public void Dispose() } } } -} \ No newline at end of file +} diff --git a/src/installer/test/TestUtils/Command.cs b/src/installer/test/TestUtils/Command.cs index b818c2bdd768c922cb6b86851275779c1f7509f0..47ef88d77ebb8ed3e60265106db3b00d6003fa3e 100644 --- a/src/installer/test/TestUtils/Command.cs +++ b/src/installer/test/TestUtils/Command.cs @@ -10,7 +10,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; -using Microsoft.DotNet.InternalAbstractions; namespace Microsoft.DotNet.Cli.Build.Framework { @@ -251,7 +250,7 @@ public Command WorkingDirectory(string projectDirectory) public Command WithUserProfile(string userprofile) { string userDir; - if (InternalAbstractions.RuntimeEnvironment.OperatingSystemPlatform == Platform.Windows) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { userDir = "USERPROFILE"; } @@ -383,7 +382,8 @@ private void ReportExecEnd(int exitCode, bool fExpectedToFail) bool success = exitCode == 0; string msgExpectedToFail = ""; - if (fExpectedToFail) { + if (fExpectedToFail) + { success = !success; msgExpectedToFail = "failed as expected and "; } diff --git a/src/installer/test/TestUtils/TestUtils.csproj b/src/installer/test/TestUtils/TestUtils.csproj index c8513a057972e0e2970f0d6674ee471cb1bad759..a608e308e1398bde252682ac71e6ac9bb4a0f909 100644 --- a/src/installer/test/TestUtils/TestUtils.csproj +++ b/src/installer/test/TestUtils/TestUtils.csproj @@ -13,10 +13,9 @@ - - - - + + +