diff --git a/src/installer/pkg/sfx/bundle/osx_resources/pt-br.lproj/conclusion.html b/src/installer/pkg/sfx/bundle/osx_resources/pt-br.lproj/conclusion.html
index e16c4b3148bcd4..af3bf5fd20ea09 100644
--- a/src/installer/pkg/sfx/bundle/osx_resources/pt-br.lproj/conclusion.html
+++ b/src/installer/pkg/sfx/bundle/osx_resources/pt-br.lproj/conclusion.html
@@ -5,7 +5,7 @@
-
The following was installed at /usr/local/share/dotnet
+
The following was installed
diff --git a/src/installer/pkg/sfx/installers/dotnet-host.proj b/src/installer/pkg/sfx/installers/dotnet-host.proj
index 953b0f4f8522f9..184770cb8c6089 100644
--- a/src/installer/pkg/sfx/installers/dotnet-host.proj
+++ b/src/installer/pkg/sfx/installers/dotnet-host.proj
@@ -4,6 +4,7 @@
true
dotnet-host
dotnet-host-internal
+
/
Host
NetCore.SharedHost
true
@@ -11,21 +12,27 @@
sharedhost
Dotnet_CLI_SharedHost
HostSrc
+
afterInstallExecute
false
true
sharedhost
false
-
osx_scripts/host
+
osx_scripts/host
The .NET Shared Host.
-
$(MSBuildThisFileDirectory)rpm_scripts/host
-
$(RpmScriptsDirectory)/after_install.sh
-
$(RpmScriptsDirectory)/after_remove.sh
+
+
{FD6988BF-5CCB-4202-3752-072442B1070B}
+
{97C9F490-5379-6902-7B80-D2723CA59D95}
+
{181630A5-53EA-4D70-E563-06F64946DE38}
+
+
+
+
@@ -35,21 +42,37 @@
+
+ <_DestinationPath>$(OutputPath)
+ <_DestinationPath Condition="'$(BuildRpmPackage)' == 'true'">$(OutputPath)usr/share/dotnet/
+ <_UsrBinPath>$(OutputPath)usr/bin/
+
+
+
+
+
+ Destination="$(_DestinationPath)dotnet$(ExeSuffix)" />
+ Destination="$(_DestinationPath)ThirdPartyNotices.txt" />
+
+
+
+
@@ -71,11 +94,43 @@
-
-
+
+
+ <_MacOSIntermediatesPath>$(IntermediateOutputPath)macos/
+
+ $(_MacOSIntermediatesPath)scripts
+
+
+ <_MacOSScript Include="$(MacOSScriptsTemplateDirectory)/*" Destination="$(MacOSScriptsDirectory)/%(FileName)%(Extension)"/>
+
+
+
+
+ <_UnameMachineRegex>$(InstallerTargetArchitecture)
+ <_UnameMachineRegex Condition="'$(InstallerTargetArchitecture)' == 'arm64'">arm64|aarch64
+ <_UnameMachineRegex Condition="'$(InstallerTargetArchitecture)' == 'x64'">amd64|x86_64
+ <_MacOSScriptsTemplateProperties>InstallerTargetArchitecture=$(InstallerTargetArchitecture);UnameMachineRegex=$(_UnameMachineRegex)
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/installer/pkg/sfx/installers/dotnet-hostfxr.proj b/src/installer/pkg/sfx/installers/dotnet-hostfxr.proj
index 2c5fa5d8188867..b9eb792a38fade 100644
--- a/src/installer/pkg/sfx/installers/dotnet-hostfxr.proj
+++ b/src/installer/pkg/sfx/installers/dotnet-hostfxr.proj
@@ -14,7 +14,6 @@
HostFxrSrc
true
hostfxr
- osx_scripts/hostfxr
The .NET HostFxr
diff --git a/src/installer/pkg/sfx/installers/host.wxs b/src/installer/pkg/sfx/installers/host.wxs
index 773246beb70f1a..6ff59fa6c29c83 100644
--- a/src/installer/pkg/sfx/installers/host.wxs
+++ b/src/installer/pkg/sfx/installers/host.wxs
@@ -24,8 +24,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NOT NON_NATIVE_ARCHITECTURE
+
+
+
-
+
@@ -47,6 +68,16 @@
+
+
+
+
-
-
+
+
+
+
+ NON_NATIVE_ARCHITECTURE
+
+
+
\ No newline at end of file
diff --git a/src/installer/pkg/sfx/installers/osx_scripts/host/postinstall b/src/installer/pkg/sfx/installers/osx_scripts/host/postinstall
index 531cb93fd382fc..3eba436d925092 100755
--- a/src/installer/pkg/sfx/installers/osx_scripts/host/postinstall
+++ b/src/installer/pkg/sfx/installers/osx_scripts/host/postinstall
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
#
# Licensed to the .NET Foundation under one or more agreements.
# The .NET Foundation licenses this file to you under the MIT license.
@@ -6,13 +6,23 @@
PACKAGE=$1
INSTALL_DESTINATION=$2
+[ "${InstallerTargetArchitecture}" == "x64" ] && X64_INSTALL_DESTINATION=$2 || X64_INSTALL_DESTINATION=$2/x64
# A temporary fix for the permissions issue(s)
chmod 755 $INSTALL_DESTINATION/dotnet
-# Add the installation directory to the system-wide paths
-# But first create the directory if it doesn't exist
-mkdir -p /etc/paths.d
-echo $INSTALL_DESTINATION | tee /etc/paths.d/dotnet
+mkdir -p /etc/dotnet
+# set install_location (legacy location) to x64 location (regardless of wether or not we're installing x64)
+echo $X64_INSTALL_DESTINATION | tee /etc/dotnet/install_location
+# set install_location_arch to point to this installed location
+echo $INSTALL_DESTINATION | tee /etc/dotnet/install_location_${InstallerTargetArchitecture}
+
+# if we're running on the native architecture
+if [[ "$(uname -m)" =~ ${UnameMachineRegex} && "$(sysctl -i -n sysctl.proc_translated)" != "1" ]]; then
+ # Add the installation directory to the system-wide paths
+ # But first create the directory if it doesn't exist
+ mkdir -p /etc/paths.d
+ echo $INSTALL_DESTINATION | tee /etc/paths.d/dotnet
+fi
exit 0
diff --git a/src/installer/pkg/sfx/installers/osx_scripts/hostfxr/postinstall b/src/installer/pkg/sfx/installers/osx_scripts/hostfxr/postinstall
deleted file mode 100755
index 2d0ceb82786936..00000000000000
--- a/src/installer/pkg/sfx/installers/osx_scripts/hostfxr/postinstall
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/sh
-#
-# Licensed to the .NET Foundation under one or more agreements.
-# The .NET Foundation licenses this file to you under the MIT license.
-#
-
-PACKAGE=$1
-INSTALL_DESTINATION=$2
-
-# A temporary fix for the permissions issue(s)
-chmod 755 $INSTALL_DESTINATION/dotnet
-
-# Add the installation directory to the system-wide paths
-echo $INSTALL_DESTINATION | tee /etc/paths.d/dotnet
-
-exit 0
diff --git a/src/installer/prepare-artifacts.proj b/src/installer/prepare-artifacts.proj
index 159125bc2d03d5..228c234ae4ff0e 100644
--- a/src/installer/prepare-artifacts.proj
+++ b/src/installer/prepare-artifacts.proj
@@ -122,6 +122,10 @@
$(InstallersRelativePath)workloads/$(SdkBandVersion)/%(Filename)%(Extension)
true
+
+
+
+
diff --git a/src/installer/tests/Assets/TestProjects/AppWithSubDirs/Program.cs b/src/installer/tests/Assets/TestProjects/AppWithSubDirs/Program.cs
index c1a31dec98665a..0a5d0149fff216 100644
--- a/src/installer/tests/Assets/TestProjects/AppWithSubDirs/Program.cs
+++ b/src/installer/tests/Assets/TestProjects/AppWithSubDirs/Program.cs
@@ -12,6 +12,21 @@ public static void Main(string[] args)
{
string baseDir = Path.Combine(AppContext.BaseDirectory, "Sentence");
+ // singlefile app redirects a number of known internal PInvokes to their implementations
+ // which are statically linked into the host.
+ // Use of File IO, Console APIs and the like uses and tests those mechanisms extensively.
+ //
+ // There are also two PInvokes in the hostpolicy itself. Test them here.
+ // We are not looking for a success, just that we can get to these methods -
+ // we should not see errors like "Unable to find an entry point".
+ try
+ {
+ new System.Runtime.Loader.AssemblyDependencyResolver("qwerty");
+ }
+ catch (InvalidOperationException ex) when (ex.Message.Contains("Failed to locate managed application"))
+ {
+ }
+
string Part(string dir="", string subdir="", string subsubdir="")
{
return File.ReadAllText(Path.Combine(baseDir, dir, subdir, subsubdir, "word"));
diff --git a/src/installer/tests/HostActivation.Tests/FrameworkResolution/DotNetCliExtensions.cs b/src/installer/tests/HostActivation.Tests/FrameworkResolution/DotNetCliExtensions.cs
index 5a8830556f54b6..6f637a1f586907 100644
--- a/src/installer/tests/HostActivation.Tests/FrameworkResolution/DotNetCliExtensions.cs
+++ b/src/installer/tests/HostActivation.Tests/FrameworkResolution/DotNetCliExtensions.cs
@@ -77,7 +77,7 @@ public DotNetFramework RuntimeConfig(Action
runtimeConfigCustomiz
{
string runtimeConfigPath = Path.Combine(_path, _name + ".runtimeconfig.json");
_backup.Backup(runtimeConfigPath);
- RuntimeConfig runtimeConfig = HostActivation.RuntimeConfig.FromFile(runtimeConfigPath);
+ RuntimeConfig runtimeConfig = Test.RuntimeConfig.FromFile(runtimeConfigPath);
runtimeConfigCustomizer(runtimeConfig);
runtimeConfig.Save();
diff --git a/src/installer/tests/HostActivation.Tests/HostActivation.Tests.csproj b/src/installer/tests/HostActivation.Tests/HostActivation.Tests.csproj
index 55c14ce9d5a6b5..9724d3326e75a0 100644
--- a/src/installer/tests/HostActivation.Tests/HostActivation.Tests.csproj
+++ b/src/installer/tests/HostActivation.Tests/HostActivation.Tests.csproj
@@ -5,7 +5,6 @@
HostActivation.Tests
HostActivation.Tests
true
- $(DefineConstants);WINDOWS
ha
true
@@ -17,7 +16,6 @@
-
diff --git a/src/installer/tests/HostActivation.Tests/InstallLocationCommandResultExtensions.cs b/src/installer/tests/HostActivation.Tests/InstallLocationCommandResultExtensions.cs
index c85b7d3e56cc5d..c4a8438d8117e4 100644
--- a/src/installer/tests/HostActivation.Tests/InstallLocationCommandResultExtensions.cs
+++ b/src/installer/tests/HostActivation.Tests/InstallLocationCommandResultExtensions.cs
@@ -3,6 +3,7 @@
using System;
+using System.IO;
using System.Runtime.InteropServices;
using FluentAssertions;
using Microsoft.DotNet.Cli.Build.Framework;
@@ -45,14 +46,14 @@ public static AndConstraint HaveUsedGlobalInstallLocati
return assertion.HaveStdErrContaining($"Using global installation location [{installLocation}]");
}
- public static AndConstraint HaveFoundDefaultInstallLocationInConfigFile(this CommandResultAssertions assertion, string installLocation)
+ public static AndConstraint HaveLookedForDefaultInstallLocation(this CommandResultAssertions assertion, string installLocationPath)
{
- return assertion.HaveStdErrContaining($"Found install location path '{installLocation}'.");
+ return assertion.HaveStdErrContaining($"Looking for install_location file in '{Path.Combine(installLocationPath, "install_location")}'.");
}
- public static AndConstraint HaveFoundArchSpecificInstallLocationInConfigFile(this CommandResultAssertions assertion, string installLocation, string arch)
+ public static AndConstraint HaveLookedForArchitectureSpecificInstallLocation(this CommandResultAssertions assertion, string installLocationPath, string architecture)
{
- return assertion.HaveStdErrContaining($"Found architecture-specific install location path: '{installLocation}' ('{arch}').");
+ return assertion.HaveStdErrContaining($"Looking for architecture specific install_location file in '{Path.Combine(installLocationPath, "install_location_" + architecture.ToLowerInvariant())}'.");
}
}
}
diff --git a/src/installer/tests/HostActivation.Tests/MultiArchInstallLocation.cs b/src/installer/tests/HostActivation.Tests/MultiArchInstallLocation.cs
index 120b899cff451b..3829a30e682e09 100644
--- a/src/installer/tests/HostActivation.Tests/MultiArchInstallLocation.cs
+++ b/src/installer/tests/HostActivation.Tests/MultiArchInstallLocation.cs
@@ -71,6 +71,31 @@ public void EnvironmentVariable_ArchSpecificDotnetRootIsUsedOverDotnetRoot()
.And.NotHaveStdErrContaining("Using environment variable DOTNET_ROOT=");
}
+ [Fact]
+ public void EnvironmentVariable_DotNetRootIsUsedOverInstallLocationIfSet()
+ {
+ var fixture = sharedTestState.PortableAppFixture
+ .Copy();
+
+ var appExe = fixture.TestProject.AppExe;
+ var arch = fixture.RepoDirProvider.BuildArchitecture.ToUpper();
+ var dotnet = fixture.BuiltDotnet.BinPath;
+
+ using (var registeredInstallLocationOverride = new RegisteredInstallLocationOverride(appExe))
+ {
+ registeredInstallLocationOverride.SetInstallLocation((arch, "some/install/location"));
+
+ Command.Create(appExe)
+ .EnableTracingAndCaptureOutputs()
+ .ApplyRegisteredInstallLocationOverride(registeredInstallLocationOverride)
+ .DotNetRoot(dotnet, arch)
+ .Execute()
+ .Should().Pass()
+ .And.HaveUsedDotNetRootInstallLocation(dotnet, fixture.CurrentRid, arch)
+ .And.NotHaveStdErrContaining("Using global install location");
+ }
+ }
+
[Fact]
public void EnvironmentVariable_DotnetRootPathDoesNotExist()
{
@@ -122,7 +147,6 @@ public void EnvironmentVariable_DotnetRootPathExistsButHasNoHost()
}
[Fact]
- [SkipOnPlatform(TestPlatforms.Windows, "This test targets the install_location config file which is only used on Linux and macOS.")]
public void InstallLocationFile_ArchSpecificLocationIsPickedFirst()
{
var fixture = sharedTestState.PortableAppFixture
@@ -142,40 +166,19 @@ public void InstallLocationFile_ArchSpecificLocationIsPickedFirst()
(arch2, path2)
});
- Command.Create(appExe)
+ CommandResult result = Command.Create(appExe)
.EnableTracingAndCaptureOutputs()
.ApplyRegisteredInstallLocationOverride(registeredInstallLocationOverride)
.DotNetRoot(null)
- .Execute()
- .Should().HaveFoundDefaultInstallLocationInConfigFile(path1)
- .And.HaveFoundArchSpecificInstallLocationInConfigFile(path1, arch1)
- .And.HaveFoundArchSpecificInstallLocationInConfigFile(path2, arch2)
- .And.HaveUsedGlobalInstallLocation(path2);
- }
- }
+ .Execute();
- [Fact]
- [SkipOnPlatform(TestPlatforms.Windows, "This test targets the install_location config file which is only used on Linux and macOS.")]
- public void InstallLocationFile_OnlyFirstLineMayNotSpecifyArchitecture()
- {
- var fixture = sharedTestState.PortableAppFixture
- .Copy();
+ if (!OperatingSystem.IsWindows())
+ {
+ result.Should()
+ .HaveLookedForArchitectureSpecificInstallLocation(registeredInstallLocationOverride.PathValueOverride, arch2);
+ }
- var appExe = fixture.TestProject.AppExe;
- using (var registeredInstallLocationOverride = new RegisteredInstallLocationOverride(appExe))
- {
- registeredInstallLocationOverride.SetInstallLocation(new (string, string)[] {
- (string.Empty, "a/b/c"),
- (string.Empty, "x/y/z"),
- });
- Command.Create(appExe)
- .EnableTracingAndCaptureOutputs()
- .ApplyRegisteredInstallLocationOverride(registeredInstallLocationOverride)
- .DotNetRoot(null)
- .Execute()
- .Should().HaveFoundDefaultInstallLocationInConfigFile("a/b/c")
- .And.HaveStdErrContaining($"Only the first line in '{registeredInstallLocationOverride.PathValueOverride}' may not have an architecture prefix.")
- .And.HaveUsedConfigFileInstallLocation("a/b/c");
+ result.Should().HaveUsedGlobalInstallLocation(path2);
}
}
@@ -200,7 +203,7 @@ public void InstallLocationFile_ReallyLongInstallPathIsParsedCorrectly()
.ApplyRegisteredInstallLocationOverride(registeredInstallLocationOverride)
.DotNetRoot(null)
.Execute()
- .Should().HaveFoundDefaultInstallLocationInConfigFile(reallyLongPath)
+ .Should().HaveLookedForDefaultInstallLocation(registeredInstallLocationOverride.PathValueOverride)
.And.HaveUsedConfigFileInstallLocation(reallyLongPath);
}
}
@@ -218,16 +221,15 @@ public void InstallLocationFile_MissingFile()
{
Directory.CreateDirectory(testArtifactsPath);
- string directory = Path.Combine(testArtifactsPath, "installLocationOverride");
- Directory.CreateDirectory(directory);
- string nonExistentLocationFile = Path.Combine(directory, "install_location");
+ string installLocationDirectory = Path.Combine(testArtifactsPath, "installLocationOverride");
+ Directory.CreateDirectory(installLocationDirectory);
string defaultInstallLocation = Path.Combine(testArtifactsPath, "defaultInstallLocation");
Command.Create(appExe)
.CaptureStdErr()
.EnvironmentVariable(
- Constants.TestOnlyEnvironmentVariables.InstallLocationFilePath,
- nonExistentLocationFile)
+ Constants.TestOnlyEnvironmentVariables.InstallLocationPath,
+ installLocationDirectory)
.EnvironmentVariable(
Constants.TestOnlyEnvironmentVariables.DefaultInstallPath,
defaultInstallLocation)
diff --git a/src/installer/tests/HostActivation.Tests/NativeHostApis.cs b/src/installer/tests/HostActivation.Tests/NativeHostApis.cs
index aaabf8e571bcd2..d9feb540d70bce 100644
--- a/src/installer/tests/HostActivation.Tests/NativeHostApis.cs
+++ b/src/installer/tests/HostActivation.Tests/NativeHostApis.cs
@@ -461,6 +461,52 @@ public void Hostfxr_get_dotnet_environment_info_with_multilevel_lookup_only()
}
}
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Windows)] // Multi-level lookup is only supported on Windows.
+ public void Hostfxr_get_dotnet_environment_info_with_multilevel_lookup_only_self_register_program_files()
+ {
+ var f = new SdkResolutionFixture(sharedTestState);
+
+ string expectedFrameworkNames = string.Join(';', new[]
+ {
+ "HostFxr.Test.A",
+ "HostFxr.Test.A",
+ "HostFxr.Test.B",
+ });
+
+ string expectedFrameworkVersions = string.Join(';', new[]
+ {
+ "1.2.3",
+ "3.0.0",
+ "5.6.7-A",
+ });
+
+ string expectedFrameworkPaths = string.Join(';', new[]
+ {
+ Path.Combine(f.ProgramFilesGlobalFrameworksDir, "HostFxr.Test.A"),
+ Path.Combine(f.ProgramFilesGlobalFrameworksDir, "HostFxr.Test.A"),
+ Path.Combine(f.ProgramFilesGlobalFrameworksDir, "HostFxr.Test.B"),
+ });
+
+ using (TestOnlyProductBehavior.Enable(f.Dotnet.GreatestVersionHostFxrFilePath))
+ {
+ // We pass f.WorkingDir so that we don't resolve dotnet_dir to the global installation
+ // in the native side.
+ f.Dotnet.Exec(f.AppDll, new[] { "hostfxr_get_dotnet_environment_info", f.WorkingDir })
+ .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_PROGRAM_FILES", f.ProgramFiles)
+ // Test with a self-registered path the same as ProgramFiles, with a trailing slash. Expect this to be de-duped
+ .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_SELF_REGISTERED", Path.Combine(f.ProgramFiles, "dotnet") + Path.DirectorySeparatorChar)
+ .CaptureStdOut()
+ .CaptureStdErr()
+ .Execute()
+ .Should().Pass()
+ .And.HaveStdOutContaining("hostfxr_get_dotnet_environment_info:Success")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info framework names:[{expectedFrameworkNames}]")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info framework versions:[{expectedFrameworkVersions}]")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info framework paths:[{expectedFrameworkPaths}]");
+ }
+ }
+
[Fact]
public void Hostfxr_get_dotnet_environment_info_global_install_path()
{
diff --git a/src/installer/tests/HostActivation.Tests/NativeHosting/Nethost.cs b/src/installer/tests/HostActivation.Tests/NativeHosting/Nethost.cs
index 0af2ce34774127..792bf4faf6f8f6 100644
--- a/src/installer/tests/HostActivation.Tests/NativeHosting/Nethost.cs
+++ b/src/installer/tests/HostActivation.Tests/NativeHosting/Nethost.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using HostActivation.Tests;
using Microsoft.DotNet.Cli.Build.Framework;
using System;
using System.IO;
@@ -88,6 +89,7 @@ public void GetHostFxrPath_DotNetRootParameter(bool explicitLoad, bool useAssemb
}
[Theory]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/61131", TestPlatforms.OSX)]
[InlineData(true, false, true, false)]
[InlineData(true, false, true, true)]
[InlineData(true, false, false, false)]
@@ -179,6 +181,7 @@ public void GetHostFxrPath_HostFxrAlreadyLoaded()
}
[Theory]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/61131", TestPlatforms.OSX)]
[SkipOnPlatform(TestPlatforms.Windows, "This test targets the install_location config file which is only used on Linux and macOS.")]
[InlineData("{0}", false, true)]
[InlineData("{0}\n", false, true)]
@@ -216,12 +219,21 @@ public void GetHostFxrPath_InstallLocationFile(string value, bool shouldUseArchS
.DotNetRoot(null)
.Execute();
- result.Should().HaveStdErrContaining($"Looking for install_location file in '{registeredInstallLocationOverride.PathValueOverride}'.");
+ if (shouldUseArchSpecificInstallLocation)
+ {
+ result.Should().HaveLookedForArchitectureSpecificInstallLocation(
+ registeredInstallLocationOverride.PathValueOverride,
+ sharedState.RepoDirectories.BuildArchitecture);
+ }
+ else
+ {
+ result.Should().HaveLookedForDefaultInstallLocation(registeredInstallLocationOverride.PathValueOverride);
+ }
if (shouldPass)
{
result.Should().Pass()
- .And.HaveStdErrContaining($"Using install location '{installLocation}'.")
+ .And.HaveUsedConfigFileInstallLocation(installLocation)
.And.HaveStdOutContaining($"hostfxr_path: {sharedState.HostFxrPath}".ToLower());
}
else
@@ -235,35 +247,7 @@ public void GetHostFxrPath_InstallLocationFile(string value, bool shouldUseArchS
}
[Fact]
- [SkipOnPlatform(TestPlatforms.Windows, "This test targets the install_location config file which is only used on Linux and macOS.")]
- public void GetHostFxrPath_GlobalInstallation_HasMoreThanOneDefaultInstallationPath()
- {
- string installLocation = Path.Combine(sharedState.ValidInstallRoot, "dotnet");
- using (var registeredInstallLocationOverride = new RegisteredInstallLocationOverride(sharedState.NethostPath))
- {
- registeredInstallLocationOverride.SetInstallLocation(new (string, string)[] {
- (string.Empty, installLocation), (string.Empty, installLocation)
- });
-
- CommandResult result = Command.Create(sharedState.NativeHostPath, GetHostFxrPath)
- .EnableTracingAndCaptureOutputs()
- .ApplyRegisteredInstallLocationOverride(registeredInstallLocationOverride)
- .EnvironmentVariable( // Redirect the default install location to an invalid location so that it doesn't cause the test to pass
- Constants.TestOnlyEnvironmentVariables.DefaultInstallPath,
- sharedState.InvalidInstallRoot)
- .DotNetRoot(null)
- .Execute();
-
- result.Should().Pass()
- .And.HaveStdErrContaining($"Looking for install_location file in '{registeredInstallLocationOverride.PathValueOverride}'.")
- .And.HaveStdErrContaining($"Found install location path '{installLocation}'.")
- .And.HaveStdErrContaining($"Only the first line in '{registeredInstallLocationOverride.PathValueOverride}' may not have an architecture prefix.")
- .And.HaveStdErrContaining($"Using install location '{installLocation}'.")
- .And.HaveStdOutContaining($"hostfxr_path: {sharedState.HostFxrPath}".ToLower());
- }
- }
-
- [Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/61131", TestPlatforms.OSX)]
[SkipOnPlatform(TestPlatforms.Windows, "This test targets the install_location config file which is only used on Linux and macOS.")]
public void GetHostFxrPath_GlobalInstallation_HasNoDefaultInstallationPath()
{
@@ -285,14 +269,16 @@ public void GetHostFxrPath_GlobalInstallation_HasNoDefaultInstallationPath()
.Execute();
result.Should().Pass()
- .And.HaveStdErrContaining($"Looking for install_location file in '{registeredInstallLocationOverride.PathValueOverride}'.")
- .And.HaveStdErrContaining($"Found architecture-specific install location path: '{installLocation}' ('{sharedState.RepoDirectories.BuildArchitecture.ToLower()}').")
- .And.HaveStdErrContaining($"Using install location '{installLocation}'.")
+ .And.HaveLookedForArchitectureSpecificInstallLocation(
+ registeredInstallLocationOverride.PathValueOverride,
+ sharedState.RepoDirectories.BuildArchitecture)
+ .And.HaveUsedConfigFileInstallLocation(installLocation)
.And.HaveStdOutContaining($"hostfxr_path: {sharedState.HostFxrPath}".ToLower());
}
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/61131", TestPlatforms.OSX)]
[SkipOnPlatform(TestPlatforms.Windows, "This test targets the install_location config file which is only used on Linux and macOS.")]
public void GetHostFxrPath_GlobalInstallation_ArchitectureSpecificPathIsPickedOverDefaultPath()
{
@@ -314,10 +300,10 @@ public void GetHostFxrPath_GlobalInstallation_ArchitectureSpecificPathIsPickedOv
.Execute();
result.Should().Pass()
- .And.HaveStdErrContaining($"Looking for install_location file in '{registeredInstallLocationOverride.PathValueOverride}'.")
- .And.HaveStdErrContaining($"Found install location path '{installLocation}/a/b/c'.")
- .And.HaveStdErrContaining($"Found architecture-specific install location path: '{installLocation}' ('{sharedState.RepoDirectories.BuildArchitecture.ToLower()}').")
- .And.HaveStdErrContaining($"Using install location '{installLocation}'.")
+ .And.HaveLookedForArchitectureSpecificInstallLocation(
+ registeredInstallLocationOverride.PathValueOverride,
+ sharedState.RepoDirectories.BuildArchitecture)
+ .And.HaveUsedConfigFileInstallLocation(installLocation)
.And.HaveStdOutContaining($"hostfxr_path: {sharedState.HostFxrPath}".ToLower());
}
}
diff --git a/src/installer/tests/HostActivation.Tests/PortableAppActivation.cs b/src/installer/tests/HostActivation.Tests/PortableAppActivation.cs
index 4b1b28e32f3ee2..b0b52d901efd2c 100644
--- a/src/installer/tests/HostActivation.Tests/PortableAppActivation.cs
+++ b/src/installer/tests/HostActivation.Tests/PortableAppActivation.cs
@@ -526,7 +526,7 @@ public void AppHost_GUI_FrameworkDependent_MissingRuntimeFramework_ErrorReported
.MultilevelLookup(false)
.Start();
- WaitForPopupFromProcess(command.Process);
+ WindowsUtils.WaitForPopupFromProcess(command.Process);
command.Process.Kill();
var result = command.WaitForExit(true)
@@ -559,7 +559,7 @@ public void AppHost_GUI_MissingRuntime_ErrorReportedInDialog()
.MultilevelLookup(false)
.Start();
- WaitForPopupFromProcess(command.Process);
+ WindowsUtils.WaitForPopupFromProcess(command.Process);
command.Process.Kill();
var expectedErrorCode = Constants.ErrorCode.CoreHostLibMissingFailure.ToString("x");
@@ -590,7 +590,7 @@ public void AppHost_GUI_NoCustomErrorWriter_FrameworkMissing_ErrorReportedInDial
Directory.CreateDirectory(dotnetWithMockHostFxr);
string expectedErrorCode = Constants.ErrorCode.FrameworkMissingFailure.ToString("x");
- var dotnetBuilder = new DotNetBuilder(dotnetWithMockHostFxr, sharedTestState.RepoDirectories.BuiltDotnet, "hostfxrFrameworkMissingFailure")
+ var dotnetBuilder = new DotNetBuilder(dotnetWithMockHostFxr, sharedTestState.RepoDirectories.BuiltDotnet, "mockhostfxrFrameworkMissingFailure")
.RemoveHostFxr()
.AddMockHostFxr(new Version(2, 2, 0));
var dotnet = dotnetBuilder.Build();
@@ -601,7 +601,7 @@ public void AppHost_GUI_NoCustomErrorWriter_FrameworkMissing_ErrorReportedInDial
.MultilevelLookup(false)
.Start();
- WaitForPopupFromProcess(command.Process);
+ WindowsUtils.WaitForPopupFromProcess(command.Process);
command.Process.Kill();
command.WaitForExit(true)
@@ -689,50 +689,6 @@ private string CreateAStore(TestProjectFixture testProjectFixture)
return storeoutputDirectory;
}
-#if WINDOWS
- private delegate bool EnumThreadWindowsDelegate(IntPtr hWnd, IntPtr lParam);
-
- [DllImport("user32.dll")]
- private static extern bool EnumThreadWindows(int dwThreadId, EnumThreadWindowsDelegate plfn, IntPtr lParam);
-
- private IntPtr WaitForPopupFromProcess(Process process, int timeout = 60000)
- {
- IntPtr windowHandle = IntPtr.Zero;
- int timeRemaining = timeout;
- while (timeRemaining > 0)
- {
- foreach (ProcessThread thread in process.Threads)
- {
- // We take the last window we find. There really should only be one at most anyways.
- EnumThreadWindows(thread.Id,
- (hWnd, lParam) => {
- windowHandle = hWnd;
- return true;
- },
- IntPtr.Zero);
- }
-
- if (windowHandle != IntPtr.Zero)
- {
- break;
- }
-
- System.Threading.Thread.Sleep(100);
- timeRemaining -= 100;
- }
-
- // Do not fail if the window could be detected, sometimes the check is fragile and doesn't work.
- // Not worth the trouble trying to figure out why (only happens rarely in the CI system).
- // We will rely on product tracing in the failure case.
- return windowHandle;
- }
-#else
- private IntPtr WaitForPopupFromProcess(Process process, int timeout = 60000)
- {
- throw new PlatformNotSupportedException();
- }
-#endif
-
public class SharedTestState : IDisposable
{
public TestProjectFixture PortableAppFixture_Built { get; }
diff --git a/src/installer/tests/HostActivation.Tests/RegisteredInstallLocationOverride.cs b/src/installer/tests/HostActivation.Tests/RegisteredInstallLocationOverride.cs
index d37cfafe649537..fcb29470d9eeb0 100644
--- a/src/installer/tests/HostActivation.Tests/RegisteredInstallLocationOverride.cs
+++ b/src/installer/tests/HostActivation.Tests/RegisteredInstallLocationOverride.cs
@@ -56,10 +56,11 @@ public RegisteredInstallLocationOverride(string productBinaryPath)
// On Linux/macOS the install location is registered in a file which is normally
// located in /etc/dotnet/install_location
// So we need to redirect it to a different place here.
- string directory = Path.Combine(TestArtifact.TestArtifactsPath, "installLocationOverride");
+ string directory = Path.Combine(TestArtifact.TestArtifactsPath, "installLocationOverride" + Process.GetCurrentProcess().Id.ToString());
+ if (Directory.Exists(directory))
+ Directory.Delete(directory, true);
Directory.CreateDirectory(directory);
- PathValueOverride = Path.Combine(directory, "install_location." + Process.GetCurrentProcess().Id.ToString());
- File.WriteAllText(PathValueOverride, "");
+ PathValueOverride = directory;
}
}
@@ -78,9 +79,12 @@ public void SetInstallLocation(params (string Architecture, string Path)[] locat
}
else
{
- File.WriteAllText(PathValueOverride, string.Join(Environment.NewLine,
- locations.Select(l => string.Format("{0}{1}",
- (!string.IsNullOrWhiteSpace(l.Architecture) ? l.Architecture + "=" : ""), l.Path))));
+ foreach (var location in locations)
+ {
+ string installLocationFileName = "install_location" +
+ (!string.IsNullOrWhiteSpace(location.Architecture) ? ("_" + location.Architecture) : string.Empty);
+ File.WriteAllText(Path.Combine(PathValueOverride, installLocationFileName), location.Path);
+ }
}
}
@@ -127,7 +131,7 @@ public static Command ApplyRegisteredInstallLocationOverride(
else
{
return command.EnvironmentVariable(
- Constants.TestOnlyEnvironmentVariables.InstallLocationFilePath,
+ Constants.TestOnlyEnvironmentVariables.InstallLocationPath,
registeredInstallLocationOverride.PathValueOverride);
}
}
diff --git a/src/installer/tests/HostActivation.Tests/StartupHooks.cs b/src/installer/tests/HostActivation.Tests/StartupHooks.cs
index a0533a60fd4772..3e1685356167f9 100644
--- a/src/installer/tests/HostActivation.Tests/StartupHooks.cs
+++ b/src/installer/tests/HostActivation.Tests/StartupHooks.cs
@@ -13,6 +13,7 @@ public class StartupHooks : IClassFixture
{
private SharedTestState sharedTestState;
private string startupHookVarName = "DOTNET_STARTUP_HOOKS";
+ private string startupHookRuntimeConfigName = "STARTUP_HOOKS";
private string startupHookSupport = "System.StartupHookProvider.IsSupported";
public StartupHooks(StartupHooks.SharedTestState fixture)
@@ -105,6 +106,64 @@ public void Muxer_activation_of_Multiple_StartupHooks_Succeeds()
.And.HaveStdOutContaining("Hello World");
}
+ [Fact]
+ public void Muxer_activation_of_RuntimeConfig_StartupHook_Succeeds()
+ {
+ var fixture = sharedTestState.PortableAppFixture.Copy();
+ var dotnet = fixture.BuiltDotnet;
+ var appDll = fixture.TestProject.AppDll;
+
+ var startupHookFixture = sharedTestState.StartupHookFixture.Copy();
+ var startupHookDll = startupHookFixture.TestProject.AppDll;
+
+ RuntimeConfig.FromFile(fixture.TestProject.RuntimeConfigJson)
+ .WithProperty(startupHookRuntimeConfigName, startupHookDll)
+ .Save();
+
+ // RuntimeConfig defined startup hook
+ dotnet.Exec(appDll)
+ .CaptureStdOut()
+ .CaptureStdErr()
+ .Execute()
+ .Should().Pass()
+ .And.HaveStdOutContaining("Hello from startup hook!")
+ .And.HaveStdOutContaining("Hello World");
+ }
+
+ [Fact]
+ public void Muxer_activation_of_RuntimeConfig_And_Environment_StartupHooks_SucceedsInExpectedOrder()
+ {
+ var fixture = sharedTestState.PortableAppFixture.Copy();
+ var dotnet = fixture.BuiltDotnet;
+ var appDll = fixture.TestProject.AppDll;
+
+ var startupHookFixture = sharedTestState.StartupHookFixture.Copy();
+ var startupHookDll = startupHookFixture.TestProject.AppDll;
+
+ RuntimeConfig.FromFile(fixture.TestProject.RuntimeConfigJson)
+ .WithProperty(startupHookRuntimeConfigName, startupHookDll)
+ .Save();
+
+ var startupHook2Fixture = sharedTestState.StartupHookWithDependencyFixture.Copy();
+ var startupHook2Dll = startupHook2Fixture.TestProject.AppDll;
+
+ // include any char to counter output from other threads such as in #57243
+ const string wildcardPattern = @"[\r\n\s.]*";
+
+ // RuntimeConfig and Environment startup hooks in expected order
+ dotnet.Exec(appDll)
+ .EnvironmentVariable(startupHookVarName, startupHook2Dll)
+ .CaptureStdOut()
+ .CaptureStdErr()
+ .Execute()
+ .Should().Pass()
+ .And.HaveStdOutMatching("Hello from startup hook with dependency!" +
+ wildcardPattern +
+ "Hello from startup hook!" +
+ wildcardPattern +
+ "Hello World");
+ }
+
// Empty startup hook variable
[Fact]
public void Muxer_activation_of_Empty_StartupHook_Variable_Succeeds()
diff --git a/src/installer/tests/Microsoft.DotNet.CoreSetup.Packaging.Tests/Microsoft.DotNet.CoreSetup.Packaging.Tests.csproj b/src/installer/tests/Microsoft.DotNet.CoreSetup.Packaging.Tests/Microsoft.DotNet.CoreSetup.Packaging.Tests.csproj
index 8dcef20c22dea9..73a3fda2b55fd4 100644
--- a/src/installer/tests/Microsoft.DotNet.CoreSetup.Packaging.Tests/Microsoft.DotNet.CoreSetup.Packaging.Tests.csproj
+++ b/src/installer/tests/Microsoft.DotNet.CoreSetup.Packaging.Tests/Microsoft.DotNet.CoreSetup.Packaging.Tests.csproj
@@ -7,7 +7,7 @@
-
+
diff --git a/src/installer/tests/Microsoft.DotNet.CoreSetup.Packaging.Tests/NETCoreTests.cs b/src/installer/tests/Microsoft.DotNet.CoreSetup.Packaging.Tests/NETCoreTests.cs
index 65d19d7983c413..cda507f61480de 100644
--- a/src/installer/tests/Microsoft.DotNet.CoreSetup.Packaging.Tests/NETCoreTests.cs
+++ b/src/installer/tests/Microsoft.DotNet.CoreSetup.Packaging.Tests/NETCoreTests.cs
@@ -18,7 +18,7 @@ public void NETCoreTargetingPackIsValid()
"Microsoft.NETCore.App.Ref"))
{
// Allow no targeting pack in case this is a servicing build.
- // This condition should be tightened: https://github.com/dotnet/core-setup/issues/8830
+ // This condition should be tightened: https://github.com/dotnet/runtime/issues/3836
if (tester == null)
{
return;
diff --git a/src/installer/tests/Microsoft.DotNet.CoreSetup.Packaging.Tests/NuGetArtifactTester.cs b/src/installer/tests/Microsoft.DotNet.CoreSetup.Packaging.Tests/NuGetArtifactTester.cs
index 4af9206f6b3513..292e3522d961e1 100644
--- a/src/installer/tests/Microsoft.DotNet.CoreSetup.Packaging.Tests/NuGetArtifactTester.cs
+++ b/src/installer/tests/Microsoft.DotNet.CoreSetup.Packaging.Tests/NuGetArtifactTester.cs
@@ -41,10 +41,7 @@ public static NuGetArtifactTester OpenOrNull(
"Shipping",
$"{id}.{dirs.MicrosoftNETCoreAppVersion}.nupkg");
- // If the nuspec exists, the nupkg should exist.
- Assert.True(File.Exists(nupkgPath));
-
- return new NuGetArtifactTester(nupkgPath);
+ return File.Exists(nupkgPath) ? new NuGetArtifactTester(nupkgPath) : null;
}
public PackageIdentity Identity { get; }
diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleTestBase.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleTestBase.cs
index 18aba06f6d9786..669b300cb838ad 100644
--- a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleTestBase.cs
+++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleTestBase.cs
@@ -25,7 +25,7 @@ public static string UseSingleFileSelfContainedHost(TestProjectFixture testFixtu
var publishedHostPath = BundleHelper.GetHostPath(testFixture);
HostWriter.CreateAppHost(singleFileHost,
publishedHostPath,
- BundleHelper.GetAppPath(testFixture));
+ BundleHelper.GetAppName(testFixture));
return publishedHostPath;
}
@@ -37,7 +37,7 @@ public static string UseFrameworkDependentHost(TestProjectFixture testFixture)
var publishedHostPath = BundleHelper.GetHostPath(testFixture);
HostWriter.CreateAppHost(appHost,
publishedHostPath,
- BundleHelper.GetAppPath(testFixture));
+ BundleHelper.GetAppName(testFixture));
return publishedHostPath;
}
diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundledAppWithSubDirs.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundledAppWithSubDirs.cs
index 66212592138151..9442777b7a5fdc 100644
--- a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundledAppWithSubDirs.cs
+++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundledAppWithSubDirs.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
+using System.IO;
using BundleTests.Helpers;
using Microsoft.DotNet.Cli.Build.Framework;
using Microsoft.DotNet.CoreSetup.Test;
@@ -22,9 +23,7 @@ public BundledAppWithSubDirs(SharedTestState fixture)
private void RunTheApp(string path, TestProjectFixture fixture)
{
Command.Create(path)
- .EnvironmentVariable("COREHOST_TRACE", "1")
- .CaptureStdErr()
- .CaptureStdOut()
+ .EnableTracingAndCaptureOutputs()
.EnvironmentVariable("DOTNET_ROOT", fixture.BuiltDotnet.BinPath)
.EnvironmentVariable("DOTNET_ROOT(x86)", fixture.BuiltDotnet.BinPath)
.EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0")
@@ -52,6 +51,47 @@ public void Bundled_Framework_dependent_App_Run_Succeeds(BundleOptions options)
RunTheApp(singleFile, fixture);
}
+ [InlineData(BundleOptions.None)]
+ [InlineData(BundleOptions.BundleNativeBinaries)]
+ [InlineData(BundleOptions.BundleAllContent)]
+ [Theory]
+ [PlatformSpecific(TestPlatforms.Windows)] // GUI app host is only supported on Windows.
+ public void Bundled_Framework_dependent_App_GUI_DownlevelHostFxr_ErrorDialog(BundleOptions options)
+ {
+ var fixture = sharedTestState.TestFrameworkDependentFixture.Copy();
+ UseFrameworkDependentHost(fixture);
+ var singleFile = BundleHelper.BundleApp(fixture, options);
+ AppHostExtensions.SetWindowsGraphicalUserInterfaceBit(singleFile);
+
+ string dotnetWithMockHostFxr = SharedFramework.CalculateUniqueTestDirectory(Path.Combine(TestArtifact.TestArtifactsPath, "bundleErrors"));
+ using (new TestArtifact(dotnetWithMockHostFxr))
+ {
+ Directory.CreateDirectory(dotnetWithMockHostFxr);
+ string expectedErrorCode = Constants.ErrorCode.BundleExtractionFailure.ToString("x");
+
+ var dotnetBuilder = new DotNetBuilder(dotnetWithMockHostFxr, sharedTestState.RepoDirectories.BuiltDotnet, "mockhostfxrBundleVersionFailure")
+ .RemoveHostFxr()
+ .AddMockHostFxr(new Version(5, 0, 0));
+ var dotnet = dotnetBuilder.Build();
+
+ Command command = Command.Create(singleFile)
+ .EnableTracingAndCaptureOutputs()
+ .DotNetRoot(dotnet.BinPath, sharedTestState.RepoDirectories.BuildArchitecture)
+ .MultilevelLookup(false)
+ .Start();
+
+ WindowsUtils.WaitForPopupFromProcess(command.Process);
+ command.Process.Kill();
+
+ command
+ .WaitForExit(true)
+ .Should().Fail()
+ .And.HaveStdErrContaining("Bundle header version compatibility check failed.")
+ .And.HaveStdErrContaining($"Showing error dialog for application: '{Path.GetFileName(singleFile)}' - error code: 0x{expectedErrorCode}")
+ .And.HaveStdErrContaining("apphost_version=");
+ }
+ }
+
[InlineData(BundleOptions.None)]
[InlineData(BundleOptions.BundleNativeBinaries)]
[InlineData(BundleOptions.BundleAllContent)]
diff --git a/src/installer/tests/TestUtils/Command.cs b/src/installer/tests/TestUtils/Command.cs
index 3c3e5607dde90a..91f85be3584324 100644
--- a/src/installer/tests/TestUtils/Command.cs
+++ b/src/installer/tests/TestUtils/Command.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
@@ -120,7 +121,7 @@ private static bool ShouldUseCmd(string executable)
}
else
{
- // Search the path to see if we can find it
+ // Search the path to see if we can find it
foreach (var path in System.Environment.GetEnvironmentVariable("PATH").Split(Path.PathSeparator))
{
var candidate = Path.Combine(path, executable + ".exe");
@@ -196,7 +197,20 @@ public Command Start()
ReportExecBegin();
- Process.Start();
+ // Retry if we hit ETXTBSY due to Linux race
+ // https://github.com/dotnet/runtime/issues/58964
+ for (int i = 0; ; i++)
+ {
+ try
+ {
+ Process.Start();
+ break;
+ }
+ catch (Win32Exception e) when (i < 4 && e.Message.Contains("Text file busy"))
+ {
+ Thread.Sleep(i * 20);
+ }
+ }
if (Process.StartInfo.RedirectStandardOutput)
{
diff --git a/src/installer/tests/HostActivation.Tests/CommandExtensions.cs b/src/installer/tests/TestUtils/CommandExtensions.cs
similarity index 81%
rename from src/installer/tests/HostActivation.Tests/CommandExtensions.cs
rename to src/installer/tests/TestUtils/CommandExtensions.cs
index d8460c1368bdb5..38c4cbff3ba448 100644
--- a/src/installer/tests/HostActivation.Tests/CommandExtensions.cs
+++ b/src/installer/tests/TestUtils/CommandExtensions.cs
@@ -2,10 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.DotNet.Cli.Build.Framework;
+using Microsoft.DotNet.CoreSetup.Test;
using System;
using System.IO;
-namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
+namespace Microsoft.DotNet.CoreSetup.Test
{
public static class CommandExtensions
{
@@ -38,11 +39,11 @@ public static Command EnableTracingAndCaptureOutputs(this Command command)
public static Command DotNetRoot(this Command command, string dotNetRoot, string architecture = null)
{
if (!string.IsNullOrEmpty(architecture))
- return command.EnvironmentVariable($"DOTNET_ROOT_{architecture.ToUpper()}", dotNetRoot);
+ return command.EnvironmentVariable(Constants.DotnetRoot.ArchitectureEnvironmentVariablePrefix + architecture.ToUpper(), dotNetRoot);
return command
- .EnvironmentVariable("DOTNET_ROOT", dotNetRoot)
- .EnvironmentVariable("DOTNET_ROOT(x86)", dotNetRoot);
+ .EnvironmentVariable(Constants.DotnetRoot.EnvironmentVariable, dotNetRoot)
+ .EnvironmentVariable(Constants.DotnetRoot.WindowsX86EnvironmentVariable, dotNetRoot);
}
public static Command MultilevelLookup(this Command command, bool enable)
diff --git a/src/installer/tests/HostActivation.Tests/Constants.cs b/src/installer/tests/TestUtils/Constants.cs
similarity index 86%
rename from src/installer/tests/HostActivation.Tests/Constants.cs
rename to src/installer/tests/TestUtils/Constants.cs
index f7e743aa99aa38..e36df4bd2cdb39 100644
--- a/src/installer/tests/HostActivation.Tests/Constants.cs
+++ b/src/installer/tests/TestUtils/Constants.cs
@@ -1,9 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
+namespace Microsoft.DotNet.CoreSetup.Test
{
- internal static class Constants
+ public static class Constants
{
public const string MicrosoftNETCoreApp = "Microsoft.NETCore.App";
@@ -53,7 +53,7 @@ public static class TestOnlyEnvironmentVariables
public const string DefaultInstallPath = "_DOTNET_TEST_DEFAULT_INSTALL_PATH";
public const string RegistryPath = "_DOTNET_TEST_REGISTRY_PATH";
public const string GloballyRegisteredPath = "_DOTNET_TEST_GLOBALLY_REGISTERED_PATH";
- public const string InstallLocationFilePath = "_DOTNET_TEST_INSTALL_LOCATION_FILE_PATH";
+ public const string InstallLocationPath = "_DOTNET_TEST_INSTALL_LOCATION_PATH";
}
public static class RuntimeId
@@ -72,6 +72,13 @@ public static class HostTracing
public const string TraceFileEnvironmentVariable = "COREHOST_TRACEFILE";
}
+ public static class DotnetRoot
+ {
+ public const string EnvironmentVariable = "DOTNET_ROOT";
+ public const string WindowsX86EnvironmentVariable = "DOTNET_ROOT(x86)";
+ public const string ArchitectureEnvironmentVariablePrefix = "DOTNET_ROOT_";
+ }
+
public static class ErrorCode
{
public const int InvalidArgFailure = unchecked((int)0x80008081);
@@ -81,6 +88,7 @@ public static class ErrorCode
public const int LibHostInvalidArgs = unchecked((int)0x80008092);
public const int AppArgNotRunnable = unchecked((int)0x80008094);
public const int FrameworkMissingFailure = unchecked((int)0x80008096);
+ public const int BundleExtractionFailure = unchecked((int)0x8000809f);
public const int COMPlusException = unchecked((int)0xe0434352);
public const int SIGABRT = 134;
diff --git a/src/installer/tests/HostActivation.Tests/DotNetBuilder.cs b/src/installer/tests/TestUtils/DotNetBuilder.cs
similarity index 95%
rename from src/installer/tests/HostActivation.Tests/DotNetBuilder.cs
rename to src/installer/tests/TestUtils/DotNetBuilder.cs
index 0a8d54559e2275..d4cb58340ca6ed 100644
--- a/src/installer/tests/HostActivation.Tests/DotNetBuilder.cs
+++ b/src/installer/tests/TestUtils/DotNetBuilder.cs
@@ -5,7 +5,7 @@
using System;
using System.IO;
-namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
+namespace Microsoft.DotNet.CoreSetup.Test
{
///
/// Helper class for creating a mock version of a dotnet installation
@@ -68,16 +68,19 @@ public DotNetBuilder AddMicrosoftNETCoreAppFrameworkMockHostPolicy(string versio
/// Use a mock version of HostFxr.
///
/// Version to add
- ///
- /// Currently, the only mock version of HostFxr that we have is mockhostfxr_2_2.
- ///
public DotNetBuilder AddMockHostFxr(Version version)
{
string hostfxrPath = Path.Combine(_path, "host", "fxr", version.ToString());
Directory.CreateDirectory(hostfxrPath);
- bool hasCustomErrorWriter = version.Major >= 3;
- string mockHostFxrFileName = RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform(hasCustomErrorWriter ? "mockhostfxr" : "mockhostfxr_2_2");
+ string mockHostFxrFileNameBase = version switch
+ {
+ { Major: 2, Minor: 2 } => "mockhostfxr_2_2",
+ { Major: 5, Minor: 0 } => "mockhostfxr_5_0",
+ _ => throw new InvalidOperationException($"Unsupported version {version} of mockhostfxr.")
+ };
+
+ string mockHostFxrFileName = RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform(mockHostFxrFileNameBase);
File.Copy(
Path.Combine(_repoDirectories.Artifacts, "corehost_test", mockHostFxrFileName),
Path.Combine(hostfxrPath, RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("hostfxr")),
diff --git a/src/installer/tests/TestUtils/FileUtils.cs b/src/installer/tests/TestUtils/FileUtils.cs
index 8da68f684734bf..a66ead73e0b026 100644
--- a/src/installer/tests/TestUtils/FileUtils.cs
+++ b/src/installer/tests/TestUtils/FileUtils.cs
@@ -5,7 +5,7 @@
using System.IO;
using System.IO.MemoryMappedFiles;
-namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
+namespace Microsoft.DotNet.CoreSetup.Test
{
public static class FileUtils
{
diff --git a/src/installer/tests/HostActivation.Tests/NetCoreAppBuilder.cs b/src/installer/tests/TestUtils/NetCoreAppBuilder.cs
similarity index 99%
rename from src/installer/tests/HostActivation.Tests/NetCoreAppBuilder.cs
rename to src/installer/tests/TestUtils/NetCoreAppBuilder.cs
index ba5e101558c29d..f4909cde996799 100644
--- a/src/installer/tests/HostActivation.Tests/NetCoreAppBuilder.cs
+++ b/src/installer/tests/TestUtils/NetCoreAppBuilder.cs
@@ -7,7 +7,7 @@
using System.IO;
using System.Linq;
-namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
+namespace Microsoft.DotNet.CoreSetup.Test
{
public class NetCoreAppBuilder
{
diff --git a/src/installer/tests/HostActivation.Tests/RuntimeConfig.cs b/src/installer/tests/TestUtils/RuntimeConfig.cs
similarity index 99%
rename from src/installer/tests/HostActivation.Tests/RuntimeConfig.cs
rename to src/installer/tests/TestUtils/RuntimeConfig.cs
index eaa95cb2dcced0..2a8418f4713280 100644
--- a/src/installer/tests/HostActivation.Tests/RuntimeConfig.cs
+++ b/src/installer/tests/TestUtils/RuntimeConfig.cs
@@ -8,7 +8,7 @@
using System.IO;
using System.Linq;
-namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
+namespace Microsoft.DotNet.CoreSetup.Test
{
public class RuntimeConfig
{
diff --git a/src/installer/tests/HostActivation.Tests/SharedFramework.cs b/src/installer/tests/TestUtils/SharedFramework.cs
similarity index 99%
rename from src/installer/tests/HostActivation.Tests/SharedFramework.cs
rename to src/installer/tests/TestUtils/SharedFramework.cs
index a887b2bf65160a..408cf58f37b4e1 100644
--- a/src/installer/tests/HostActivation.Tests/SharedFramework.cs
+++ b/src/installer/tests/TestUtils/SharedFramework.cs
@@ -10,7 +10,7 @@ namespace Microsoft.DotNet.CoreSetup.Test
///
/// Helper class for creating, modifying and cleaning up shared frameworks
///
- internal static class SharedFramework
+ public static class SharedFramework
{
private static readonly Mutex id_mutex = new Mutex();
diff --git a/src/installer/tests/TestUtils/TestArtifact.cs b/src/installer/tests/TestUtils/TestArtifact.cs
index 8483e4c88f7a8a..e1ca67416377ee 100644
--- a/src/installer/tests/TestUtils/TestArtifact.cs
+++ b/src/installer/tests/TestUtils/TestArtifact.cs
@@ -3,7 +3,6 @@
#nullable enable
-using Microsoft.DotNet.CoreSetup.Test.HostActivation;
using System;
using System.Collections.Generic;
using System.Diagnostics;
diff --git a/src/installer/tests/TestUtils/TestUtils.csproj b/src/installer/tests/TestUtils/TestUtils.csproj
index 35cb3e19e9d77a..1ca28978738f78 100644
--- a/src/installer/tests/TestUtils/TestUtils.csproj
+++ b/src/installer/tests/TestUtils/TestUtils.csproj
@@ -15,6 +15,8 @@
+
+
diff --git a/src/installer/tests/TestUtils/WindowsUtils.cs b/src/installer/tests/TestUtils/WindowsUtils.cs
new file mode 100644
index 00000000000000..aff4c1fef8297b
--- /dev/null
+++ b/src/installer/tests/TestUtils/WindowsUtils.cs
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+
+namespace Microsoft.DotNet.CoreSetup.Test
+{
+ public static class WindowsUtils
+ {
+ private delegate bool EnumThreadWindowsDelegate(IntPtr hWnd, IntPtr lParam);
+
+ [DllImport("user32.dll")]
+ private static extern bool EnumThreadWindows(int dwThreadId, EnumThreadWindowsDelegate plfn, IntPtr lParam);
+
+ public static IntPtr WaitForPopupFromProcess(Process process, int timeout = 60000)
+ {
+ if (!OperatingSystem.IsWindows())
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ IntPtr windowHandle = IntPtr.Zero;
+ int timeRemaining = timeout;
+ while (timeRemaining > 0)
+ {
+ foreach (ProcessThread thread in process.Threads)
+ {
+ // We take the last window we find. There really should only be one at most anyways.
+ EnumThreadWindows(thread.Id,
+ (hWnd, lParam) => {
+ windowHandle = hWnd;
+ return true;
+ },
+ IntPtr.Zero);
+ }
+
+ if (windowHandle != IntPtr.Zero)
+ {
+ break;
+ }
+
+ System.Threading.Thread.Sleep(100);
+ timeRemaining -= 100;
+ }
+
+ // Do not fail if the window could be detected, sometimes the check is fragile and doesn't work.
+ // Not worth the trouble trying to figure out why (only happens rarely in the CI system).
+ // We will rely on product tracing in the failure case.
+ return windowHandle;
+ }
+ }
+}
diff --git a/src/libraries/Common/src/Internal/Cryptography/HashProviderCng.cs b/src/libraries/Common/src/Internal/Cryptography/HashProviderCng.cs
index 3b864790b25252..c905ca1bd6996e 100644
--- a/src/libraries/Common/src/Internal/Cryptography/HashProviderCng.cs
+++ b/src/libraries/Common/src/Internal/Cryptography/HashProviderCng.cs
@@ -127,10 +127,15 @@ public override void Reset()
{
if (_reusable && !_running)
return;
+
DestroyHash();
+ BCryptCreateHashFlags flags = _reusable ?
+ BCryptCreateHashFlags.BCRYPT_HASH_REUSABLE_FLAG :
+ BCryptCreateHashFlags.None;
+
SafeBCryptHashHandle hHash;
- NTSTATUS ntStatus = Interop.BCrypt.BCryptCreateHash(_hAlgorithm, out hHash, IntPtr.Zero, 0, _key, _key == null ? 0 : _key.Length, BCryptCreateHashFlags.None);
+ NTSTATUS ntStatus = Interop.BCrypt.BCryptCreateHash(_hAlgorithm, out hHash, IntPtr.Zero, 0, _key, _key == null ? 0 : _key.Length, flags);
if (ntStatus != NTSTATUS.STATUS_SUCCESS)
throw Interop.BCrypt.CreateCryptographicException(ntStatus);
diff --git a/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ldap.cs b/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ldap.cs
index f38bb375b347e5..7fbaf9cc32eab8 100644
--- a/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ldap.cs
+++ b/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ldap.cs
@@ -136,8 +136,9 @@ static Ldap()
[DllImport(Libraries.OpenLdap, EntryPoint = "ldap_set_option", CharSet = CharSet.Ansi)]
public static extern int ldap_set_option_referral([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref LdapReferralCallback outValue);
+ // Note that ldap_start_tls_s has a different signature across Windows LDAP and OpenLDAP
[DllImport(Libraries.OpenLdap, EntryPoint = "ldap_start_tls_s", CharSet = CharSet.Ansi)]
- public static extern int ldap_start_tls(ConnectionHandle ldapHandle, ref int ServerReturnValue, ref IntPtr Message, IntPtr ServerControls, IntPtr ClientControls);
+ public static extern int ldap_start_tls(ConnectionHandle ldapHandle, IntPtr serverControls, IntPtr clientControls);
[DllImport(Libraries.OpenLdap, EntryPoint = "ldap_parse_result", CharSet = CharSet.Ansi)]
public static extern int ldap_parse_result([In] ConnectionHandle ldapHandle, [In] IntPtr result, ref int serverError, ref IntPtr dn, ref IntPtr message, ref IntPtr referral, ref IntPtr control, byte freeIt);
diff --git a/src/libraries/Common/src/Interop/OSX/Interop.libproc.cs b/src/libraries/Common/src/Interop/OSX/Interop.libproc.cs
index fd4b968c132ea8..af75653dd2f3c4 100644
--- a/src/libraries/Common/src/Interop/OSX/Interop.libproc.cs
+++ b/src/libraries/Common/src/Interop/OSX/Interop.libproc.cs
@@ -25,6 +25,9 @@ internal static partial class libproc
// Constants from sys\resource.h
private const int RUSAGE_INFO_V3 = 3;
+ // Constants from sys/errno.h
+ private const int EPERM = 1;
+
// Defines from proc_info.h
internal enum ThreadRunState
{
@@ -120,7 +123,14 @@ internal static unsafe int[] proc_listallpids()
{
// Get the number of processes currently running to know how much data to allocate
int numProcesses = proc_listallpids(null, 0);
- if (numProcesses <= 0)
+ if (numProcesses == 0 && Marshal.GetLastPInvokeError() == EPERM)
+ {
+ // An app running in App Sandbox does not have permissions to list other running processes
+ // and so the `proc_listallpids` function returns 0 and sets errno to 1. As a fallback
+ // we return at least an array with the PID of the current process which we always know.
+ return new[] { Environment.ProcessId };
+ }
+ else if (numProcesses <= 0)
{
throw new Win32Exception(SR.CantGetAllPids);
}
diff --git a/src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPath.iOS.cs b/src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPath.iOS.cs
new file mode 100644
index 00000000000000..8d73184ca4d50a
--- /dev/null
+++ b/src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPath.iOS.cs
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ internal static partial class Sys
+ {
+ [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_SearchPath_TempDirectory")]
+ internal static extern string SearchPathTempDirectory();
+ }
+}
diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.PosixFAllocate.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.FAllocate.cs
similarity index 63%
rename from src/libraries/Common/src/Interop/Unix/System.Native/Interop.PosixFAllocate.cs
rename to src/libraries/Common/src/Interop/Unix/System.Native/Interop.FAllocate.cs
index 2866ed38935bdf..71155e0f35e67e 100644
--- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.PosixFAllocate.cs
+++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.FAllocate.cs
@@ -9,9 +9,9 @@ internal static partial class Interop
internal static partial class Sys
{
///
- /// Returns -1 on ENOSPC, -2 on EFBIG. On success or ignorable error, 0 is returned.
+ /// Returns -1 on error, 0 on success.
///
- [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_PosixFAllocate", SetLastError = false)]
- internal static extern int PosixFAllocate(SafeFileHandle fd, long offset, long length);
+ [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_FAllocate", SetLastError = true)]
+ internal static extern int FAllocate(SafeFileHandle fd, long offset, long length);
}
}
diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetEnv.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetEnv.cs
new file mode 100644
index 00000000000000..d83d6700b51622
--- /dev/null
+++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetEnv.cs
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ internal unsafe partial class Sys
+ {
+ [DllImport(Interop.Libraries.SystemNative, EntryPoint = "SystemNative_GetEnv")]
+ internal static extern unsafe IntPtr GetEnv(string name);
+ }
+}
\ No newline at end of file
diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetEnviron.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetEnviron.cs
new file mode 100644
index 00000000000000..abe8ff0e1916ec
--- /dev/null
+++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetEnviron.cs
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ internal unsafe partial class Sys
+ {
+ [DllImport(Interop.Libraries.SystemNative, EntryPoint = "SystemNative_GetEnviron")]
+ internal static extern unsafe IntPtr GetEnviron();
+
+ [DllImport(Interop.Libraries.SystemNative, EntryPoint = "SystemNative_FreeEnviron")]
+ internal static extern unsafe void FreeEnviron(IntPtr environ);
+ }
+}
\ No newline at end of file
diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs
index 15d6aa3c2f147a..fbd95d485e8415 100644
--- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs
+++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs
@@ -80,6 +80,7 @@ private static DriveType GetDriveType(string fileSystemName)
// This list is based primarily on "man fs", "man mount", "mntent.h", "/proc/filesystems", coreutils "stat.c",
// and "wiki.debian.org/FileSystem". It can be extended over time as we find additional file systems that should
// be recognized as a particular drive type.
+ // Keep this in sync with the UnixFileSystemTypes enum in Interop.UnixFileSystemTypes.cs
switch (fileSystemName)
{
case "cddafs":
diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.UnixFileSystemTypes.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.UnixFileSystemTypes.cs
index 892e5ccaaed336..d86dcfbe4e59ae 100644
--- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.UnixFileSystemTypes.cs
+++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.UnixFileSystemTypes.cs
@@ -28,6 +28,7 @@ internal enum UnixFileSystemTypes : long
befs = 0x42465331,
bdevfs = 0x62646576,
bfs = 0x1BADFACE,
+ bpf_fs = 0xCAFE4A11,
binfmt_misc = 0x42494E4D,
bootfs = 0xA56D3FF9,
btrfs = 0x9123683E,
@@ -53,6 +54,7 @@ internal enum UnixFileSystemTypes : long
ext2 = 0xEF53,
ext3 = 0xEF53,
ext4 = 0xEF53,
+ f2fs = 0xF2F52010,
fat = 0x4006,
fd = 0xF00D1E,
fhgfs = 0x19830326,
@@ -122,6 +124,7 @@ internal enum UnixFileSystemTypes : long
sysv2 = 0x012FF7B6,
sysv4 = 0x012FF7B5,
tmpfs = 0x01021994,
+ tracefs = 0x74726163,
ubifs = 0x24051905,
udf = 0x15013346,
ufs = 0x00011954,
diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs
index 924c2da14d4b59..4e82a6faf507e9 100644
--- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs
+++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs
@@ -105,18 +105,28 @@ internal static unsafe SafeEvpPKeyHandle DecodePkcs8PrivateKey(
}
[DllImport(Libraries.CryptoNative)]
- private static extern int CryptoNative_GetPkcs8PrivateKeySize(IntPtr pkey);
+ private static extern int CryptoNative_GetPkcs8PrivateKeySize(IntPtr pkey, out int p8size);
private static int GetPkcs8PrivateKeySize(IntPtr pkey)
{
- int ret = CryptoNative_GetPkcs8PrivateKeySize(pkey);
+ const int Success = 1;
+ const int Error = -1;
+ const int MissingPrivateKey = -2;
- if (ret < 0)
+ int ret = CryptoNative_GetPkcs8PrivateKeySize(pkey, out int p8size);
+
+ switch (ret)
{
- throw CreateOpenSslCryptographicException();
+ case Success:
+ return p8size;
+ case Error:
+ throw CreateOpenSslCryptographicException();
+ case MissingPrivateKey:
+ throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
+ default:
+ Debug.Fail($"Unexpected return '{ret}' value from {nameof(CryptoNative_GetPkcs8PrivateKeySize)}.");
+ throw new CryptographicException();
}
-
- return ret;
}
[DllImport(Libraries.CryptoNative)]
diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs
index 73a9d32bb45c84..ae608c372778c9 100644
--- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs
+++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs
@@ -59,7 +59,7 @@ internal static SafeSslHandle AllocateSslContext(SslProtocols protocols, SafeX50
throw CreateSslException(SR.net_allocate_ssl_context_failed);
}
- if (!Interop.Ssl.Tls13Supported)
+ if (!Interop.Ssl.Capabilities.Tls13Supported)
{
if (protocols != SslProtocols.None &&
CipherSuitesPolicyPal.WantsTls13(protocols))
diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs
index 29154b77da6325..64db5a15147a4c 100644
--- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs
+++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs
@@ -141,9 +141,13 @@ internal static partial class Ssl
}
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_Tls13Supported")]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool Tls13SupportedImpl();
- internal static readonly bool Tls13Supported = Tls13SupportedImpl();
+ private static extern int Tls13SupportedImpl();
+
+ internal static class Capabilities
+ {
+ // needs separate type (separate static cctor) to be sure OpenSSL is initialized.
+ internal static readonly bool Tls13Supported = Tls13SupportedImpl() != 0;
+ }
internal static SafeSharedX509NameStackHandle SslGetClientCAList(SafeSslHandle ssl)
{
diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FileOperations.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FileOperations.cs
index cc4896c1c52e48..c43b4fd19d21d2 100644
--- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FileOperations.cs
+++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FileOperations.cs
@@ -23,7 +23,8 @@ internal static partial class FileOperations
internal const int FILE_FLAG_OVERLAPPED = 0x40000000;
internal const int FILE_LIST_DIRECTORY = 0x0001;
- }
+ internal const int FILE_WRITE_ATTRIBUTES = 0x100;
+ }
}
}
diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.REPARSE_DATA_BUFFER.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.REPARSE_DATA_BUFFER.cs
index 3bcb9162d57bfc..123ac9235b9fdc 100644
--- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.REPARSE_DATA_BUFFER.cs
+++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.REPARSE_DATA_BUFFER.cs
@@ -14,24 +14,29 @@ internal static partial class Kernel32
internal const uint SYMLINK_FLAG_RELATIVE = 1;
// https://msdn.microsoft.com/library/windows/hardware/ff552012.aspx
- // We don't need all the struct fields; omitting the rest.
[StructLayout(LayoutKind.Sequential)]
- internal unsafe struct REPARSE_DATA_BUFFER
+ internal unsafe struct SymbolicLinkReparseBuffer
{
internal uint ReparseTag;
internal ushort ReparseDataLength;
internal ushort Reserved;
- internal SymbolicLinkReparseBuffer ReparseBufferSymbolicLink;
+ internal ushort SubstituteNameOffset;
+ internal ushort SubstituteNameLength;
+ internal ushort PrintNameOffset;
+ internal ushort PrintNameLength;
+ internal uint Flags;
+ }
- [StructLayout(LayoutKind.Sequential)]
- internal struct SymbolicLinkReparseBuffer
- {
- internal ushort SubstituteNameOffset;
- internal ushort SubstituteNameLength;
- internal ushort PrintNameOffset;
- internal ushort PrintNameLength;
- internal uint Flags;
- }
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct MountPointReparseBuffer
+ {
+ public uint ReparseTag;
+ public ushort ReparseDataLength;
+ public ushort Reserved;
+ public ushort SubstituteNameOffset;
+ public ushort SubstituteNameLength;
+ public ushort PrintNameOffset;
+ public ushort PrintNameLength;
}
}
}
diff --git a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs
index 1b86a149072899..463de2572b2b3f 100644
--- a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs
+++ b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs
@@ -109,6 +109,7 @@ internal static partial class WinHttp
public const uint WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 = 0x00000080;
public const uint WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 = 0x00000200;
public const uint WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2 = 0x00000800;
+ public const uint WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_3 = 0x00002000;
public const uint SECURITY_FLAG_IGNORE_UNKNOWN_CA = 0x00000100;
public const uint SECURITY_FLAG_IGNORE_CERT_DATE_INVALID = 0x00002000;
@@ -167,6 +168,7 @@ internal static partial class WinHttp
public const uint WINHTTP_OPTION_TCP_KEEPALIVE = 152;
public const uint WINHTTP_OPTION_STREAM_ERROR_CODE = 159;
+ public const uint WINHTTP_OPTION_REQUIRE_STREAM_END = 160;
public enum WINHTTP_WEB_SOCKET_BUFFER_TYPE
{
diff --git a/src/libraries/Common/src/Roslyn/GetBestTypeByMetadataName.cs b/src/libraries/Common/src/Roslyn/GetBestTypeByMetadataName.cs
new file mode 100644
index 00000000000000..c86d7f2e00ebc4
--- /dev/null
+++ b/src/libraries/Common/src/Roslyn/GetBestTypeByMetadataName.cs
@@ -0,0 +1,138 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.CodeAnalysis;
+
+namespace Microsoft.CodeAnalysis.DotnetRuntime.Extensions
+{
+ internal static class RoslynExtensions
+ {
+ // Copied from: https://github.com/dotnet/roslyn/blob/main/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/CompilationExtensions.cs
+ ///
+ /// Gets a type by its metadata name to use for code analysis within a . This method
+ /// attempts to find the "best" symbol to use for code analysis, which is the symbol matching the first of the
+ /// following rules.
+ ///
+ ///
+ /// -
+ /// If only one type with the given name is found within the compilation and its referenced assemblies, that
+ /// type is returned regardless of accessibility.
+ ///
+ /// -
+ /// If the current defines the symbol, that symbol is returned.
+ ///
+ /// -
+ /// If exactly one referenced assembly defines the symbol in a manner that makes it visible to the current
+ /// , that symbol is returned.
+ ///
+ /// -
+ /// Otherwise, this method returns .
+ ///
+ ///
+ ///
+ /// The to consider for analysis.
+ /// The fully-qualified metadata type name to find.
+ /// The symbol to use for code analysis; otherwise, .
+ public static INamedTypeSymbol? GetBestTypeByMetadataName(this Compilation compilation, string fullyQualifiedMetadataName)
+ {
+ // Try to get the unique type with this name, ignoring accessibility
+ var type = compilation.GetTypeByMetadataName(fullyQualifiedMetadataName);
+
+ // Otherwise, try to get the unique type with this name originally defined in 'compilation'
+ type ??= compilation.Assembly.GetTypeByMetadataName(fullyQualifiedMetadataName);
+
+ // Otherwise, try to get the unique accessible type with this name from a reference
+ if (type is null)
+ {
+ foreach (var module in compilation.Assembly.Modules)
+ {
+ foreach (var referencedAssembly in module.ReferencedAssemblySymbols)
+ {
+ var currentType = referencedAssembly.GetTypeByMetadataName(fullyQualifiedMetadataName);
+ if (currentType is null)
+ continue;
+
+ switch (currentType.GetResultantVisibility())
+ {
+ case SymbolVisibility.Public:
+ case SymbolVisibility.Internal when referencedAssembly.GivesAccessTo(compilation.Assembly):
+ break;
+
+ default:
+ continue;
+ }
+
+ if (type is object)
+ {
+ // Multiple visible types with the same metadata name are present
+ return null;
+ }
+
+ type = currentType;
+ }
+ }
+ }
+
+ return type;
+ }
+
+ // copied from https://github.com/dotnet/roslyn/blob/main/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions.cs
+ private static SymbolVisibility GetResultantVisibility(this ISymbol symbol)
+ {
+ // Start by assuming it's visible.
+ SymbolVisibility visibility = SymbolVisibility.Public;
+
+ switch (symbol.Kind)
+ {
+ case SymbolKind.Alias:
+ // Aliases are uber private. They're only visible in the same file that they
+ // were declared in.
+ return SymbolVisibility.Private;
+
+ case SymbolKind.Parameter:
+ // Parameters are only as visible as their containing symbol
+ return GetResultantVisibility(symbol.ContainingSymbol);
+
+ case SymbolKind.TypeParameter:
+ // Type Parameters are private.
+ return SymbolVisibility.Private;
+ }
+
+ while (symbol != null && symbol.Kind != SymbolKind.Namespace)
+ {
+ switch (symbol.DeclaredAccessibility)
+ {
+ // If we see anything private, then the symbol is private.
+ case Accessibility.NotApplicable:
+ case Accessibility.Private:
+ return SymbolVisibility.Private;
+
+ // If we see anything internal, then knock it down from public to
+ // internal.
+ case Accessibility.Internal:
+ case Accessibility.ProtectedAndInternal:
+ visibility = SymbolVisibility.Internal;
+ break;
+
+ // For anything else (Public, Protected, ProtectedOrInternal), the
+ // symbol stays at the level we've gotten so far.
+ }
+
+ symbol = symbol.ContainingSymbol;
+ }
+
+ return visibility;
+ }
+
+ // Copied from: https://github.com/dotnet/roslyn/blob/main/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolVisibility.cs
+#pragma warning disable CA1027 // Mark enums with FlagsAttribute
+ private enum SymbolVisibility
+#pragma warning restore CA1027 // Mark enums with FlagsAttribute
+ {
+ Public = 0,
+ Internal = 1,
+ Private = 2,
+ Friend = Internal,
+ }
+ }
+}
diff --git a/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs b/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs
index 4928270b06f170..23b1d5959aced5 100644
--- a/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs
+++ b/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs
@@ -48,10 +48,10 @@ public static Project CreateTestProject(IEnumerable? references, bool
}
return new AdhocWorkspace()
- .AddSolution(SolutionInfo.Create(SolutionId.CreateNewId(), VersionStamp.Create()))
- .AddProject("Test", "test.dll", "C#")
- .WithMetadataReferences(refs)
- .WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary).WithNullableContextOptions(NullableContextOptions.Enable));
+ .AddSolution(SolutionInfo.Create(SolutionId.CreateNewId(), VersionStamp.Create()))
+ .AddProject("Test", "test.dll", "C#")
+ .WithMetadataReferences(refs)
+ .WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary).WithNullableContextOptions(NullableContextOptions.Enable));
}
public static Task CommitChanges(this Project proj, params string[] ignorables)
@@ -141,23 +141,44 @@ public static TextSpan MakeSpan(string text, int spanNum)
/// Runs a Roslyn generator over a set of source files.
///
public static async Task<(ImmutableArray, ImmutableArray)> RunGenerator(
+#if ROSLYN4_0_OR_GREATER
+ IIncrementalGenerator generator,
+#else
ISourceGenerator generator,
+#endif
IEnumerable? references,
IEnumerable sources,
- AnalyzerConfigOptionsProvider? optionsProvider = null,
bool includeBaseReferences = true,
CancellationToken cancellationToken = default)
{
Project proj = CreateTestProject(references, includeBaseReferences);
-
proj = proj.WithDocuments(sources);
-
Assert.True(proj.Solution.Workspace.TryApplyChanges(proj.Solution));
-
Compilation? comp = await proj!.GetCompilationAsync(CancellationToken.None).ConfigureAwait(false);
+ return RunGenerator(comp!, generator, cancellationToken);
+ }
- CSharpGeneratorDriver cgd = CSharpGeneratorDriver.Create(new[] { generator }, optionsProvider: optionsProvider);
- GeneratorDriver gd = cgd.RunGenerators(comp!, cancellationToken);
+ ///
+ /// Runs a Roslyn generator given a Compilation.
+ ///
+ public static (ImmutableArray, ImmutableArray) RunGenerator(
+ Compilation compilation,
+#if ROSLYN4_0_OR_GREATER
+ IIncrementalGenerator generator,
+#else
+ ISourceGenerator generator,
+#endif
+ CancellationToken cancellationToken = default)
+ {
+#if ROSLYN4_0_OR_GREATER
+ // workaround https://github.com/dotnet/roslyn/pull/55866. We can remove "LangVersion=Preview" when we get a Roslyn build with that change.
+ CSharpParseOptions options = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview);
+ CSharpGeneratorDriver cgd = CSharpGeneratorDriver.Create(new[] { generator.AsSourceGenerator() }, parseOptions: options);
+#else
+ CSharpGeneratorDriver cgd = CSharpGeneratorDriver.Create(new[] { generator });
+#endif
+
+ GeneratorDriver gd = cgd.RunGenerators(compilation, cancellationToken);
GeneratorDriverRunResult r = gd.GetRunResult();
return (r.Results[0].Diagnostics, r.Results[0].GeneratedSources);
diff --git a/src/libraries/Common/tests/System/Net/EnterpriseTests/setup/linuxclient/Dockerfile b/src/libraries/Common/tests/System/Net/EnterpriseTests/setup/linuxclient/Dockerfile
index 8bb94ba8aa9924..853582e7bcf3c1 100644
--- a/src/libraries/Common/tests/System/Net/EnterpriseTests/setup/linuxclient/Dockerfile
+++ b/src/libraries/Common/tests/System/Net/EnterpriseTests/setup/linuxclient/Dockerfile
@@ -1,31 +1,12 @@
-# Switch to mcr.microsoft.com/dotnet-buildtools/prereqs ubuntu 18.04 images when they are fixed
-FROM ubuntu:18.04
+FROM mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-20211022152710-047508b
# Prevents dialog prompting when installing packages
ARG DEBIAN_FRONTEND=noninteractive
-# This 'RUN' step can be removed once dotnet-buildtools/prereqs image is fixed
-#
-# Makes the image capable of building and running tests in dotnet-runtime repo.
-# Add retries to apt-get since the ubuntu package servers have had errors lately such as:
-# "E: Failed to fetch http://archive.ubuntu.com/ubuntu/pool/main/p/publicsuffix/publicsuffix_20180223.1310-1_all.deb Undetermined Error [IP: 91.189.88.31 80]"
-ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1
-RUN echo "APT::Acquire::Retries \"10\";" > /etc/apt/apt.conf.d/80-retries && \
- apt-get update && \
- apt-get install -y --no-install-recommends apt-transport-https ca-certificates gnupg software-properties-common wget && \
- wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | apt-key add - && \
- apt-add-repository 'deb https://apt.kitware.com/ubuntu/ bionic main' && \
- wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key 2>/dev/null | apt-key add - && \
- apt-add-repository 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main' && \
- apt-get update && \
- apt-get install -y --no-install-recommends cmake llvm-9 clang-9 lldb-6.0 liblldb-6.0-dev libunwind8 libunwind-dev gettext libicu-dev liblttng-ust-dev libssl-dev libnuma-dev libkrb5-dev locales && \
- locale-gen en_US.UTF-8 && \
- update-locale LANG=en_US.UTF-8
-
# Install Kerberos, NTLM, and diagnostic tools
COPY ./common/krb5.conf /etc/krb5.conf
RUN apt-get update && \
- apt-get install -y --no-install-recommends krb5-user gss-ntlmssp iputils-ping dnsutils nano curl
+ apt-get install -y --no-install-recommends krb5-user gss-ntlmssp iputils-ping dnsutils nano
# Set environment variable to turn on enterprise tests
ENV DOTNET_RUNTIME_ENTERPRISETESTS_ENABLED 1
diff --git a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackStream.cs b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackStream.cs
index 958cb2abc1e156..346098414b39bd 100644
--- a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackStream.cs
+++ b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackStream.cs
@@ -20,10 +20,10 @@ internal sealed class Http3LoopbackStream : IDisposable
private const int MaximumVarIntBytes = 8;
private const long VarIntMax = (1L << 62) - 1;
- private const long DataFrame = 0x0;
- private const long HeadersFrame = 0x1;
- private const long SettingsFrame = 0x4;
- private const long GoAwayFrame = 0x7;
+ public const long DataFrame = 0x0;
+ public const long HeadersFrame = 0x1;
+ public const long SettingsFrame = 0x4;
+ public const long GoAwayFrame = 0x7;
public const long ControlStream = 0x0;
public const long PushStream = 0x1;
diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs
index 41718d37eb869e..7d0a476dd1a951 100644
--- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs
+++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs
@@ -203,7 +203,7 @@ public static IEnumerable
diff --git a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.OverlappedValueTaskSource.Windows.cs b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.OverlappedValueTaskSource.Windows.cs
index 9f689b161bbd00..c2eab851bd60e2 100644
--- a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.OverlappedValueTaskSource.Windows.cs
+++ b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.OverlappedValueTaskSource.Windows.cs
@@ -86,8 +86,11 @@ internal static Exception GetIOError(int errorCode, string? path)
_bufferSize = memory.Length;
_memoryHandle = memory.Pin();
_overlapped = _fileHandle.ThreadPoolBinding!.AllocateNativeOverlapped(_preallocatedOverlapped);
- _overlapped->OffsetLow = (int)fileOffset;
- _overlapped->OffsetHigh = (int)(fileOffset >> 32);
+ if (_fileHandle.CanSeek)
+ {
+ _overlapped->OffsetLow = (int)fileOffset;
+ _overlapped->OffsetHigh = (int)(fileOffset >> 32);
+ }
return _overlapped;
}
diff --git a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs
index ee1def85b9e024..266fd93e5082da 100644
--- a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs
+++ b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs
@@ -16,6 +16,7 @@ public sealed partial class SafeFileHandle : SafeHandleZeroOrMinusOneIsInvalid
// not using bool? as it's not thread safe
private volatile NullableBool _canSeek = NullableBool.Undefined;
+ private volatile NullableBool _supportsRandomAccess = NullableBool.Undefined;
private bool _deleteOnClose;
private bool _isLocked;
@@ -33,6 +34,25 @@ private SafeFileHandle(bool ownsHandle)
internal bool CanSeek => !IsClosed && GetCanSeek();
+ internal bool SupportsRandomAccess
+ {
+ get
+ {
+ NullableBool supportsRandomAccess = _supportsRandomAccess;
+ if (supportsRandomAccess == NullableBool.Undefined)
+ {
+ _supportsRandomAccess = supportsRandomAccess = GetCanSeek() ? NullableBool.True : NullableBool.False;
+ }
+
+ return supportsRandomAccess == NullableBool.True;
+ }
+ set
+ {
+ Debug.Assert(value == false); // We should only use the setter to disable random access.
+ _supportsRandomAccess = value ? NullableBool.True : NullableBool.False;
+ }
+ }
+
internal ThreadPoolBoundHandle? ThreadPoolBinding => null;
internal void EnsureThreadPoolBindingInitialized() { /* nop */ }
@@ -121,17 +141,6 @@ private static bool DirectoryExists(string fullPath)
protected override bool ReleaseHandle()
{
- // When the SafeFileHandle was opened, we likely issued an flock on the created descriptor in order to add
- // an advisory lock. This lock should be removed via closing the file descriptor, but close can be
- // interrupted, and we don't retry closes. As such, we could end up leaving the file locked,
- // which could prevent subsequent usage of the file until this process dies. To avoid that, we proactively
- // try to release the lock before we close the handle.
- if (_isLocked)
- {
- Interop.Sys.FLock(handle, Interop.Sys.LockOperations.LOCK_UN); // ignore any errors
- _isLocked = false;
- }
-
// If DeleteOnClose was requested when constructed, delete the file now.
// (Unix doesn't directly support DeleteOnClose, so we mimic it here.)
if (_deleteOnClose)
@@ -143,6 +152,17 @@ protected override bool ReleaseHandle()
Interop.Sys.Unlink(_path); // ignore errors; it's valid that the path may no longer exist
}
+ // When the SafeFileHandle was opened, we likely issued an flock on the created descriptor in order to add
+ // an advisory lock. This lock should be removed via closing the file descriptor, but close can be
+ // interrupted, and we don't retry closes. As such, we could end up leaving the file locked,
+ // which could prevent subsequent usage of the file until this process dies. To avoid that, we proactively
+ // try to release the lock before we close the handle.
+ if (_isLocked)
+ {
+ Interop.Sys.FLock(handle, Interop.Sys.LockOperations.LOCK_UN); // ignore any errors
+ _isLocked = false;
+ }
+
// Close the descriptor. Although close is documented to potentially fail with EINTR, we never want
// to retry, as the descriptor could actually have been closed, been subsequently reassigned, and
// be in use elsewhere in the process. Instead, we simply check whether the call was successful.
@@ -274,7 +294,6 @@ private static Interop.Sys.OpenFlags PreOpenConfigurationFromOptions(FileMode mo
private void Init(string path, FileMode mode, FileAccess access, FileShare share, FileOptions options, long preallocationSize)
{
IsAsync = (options & FileOptions.Asynchronous) != 0;
- _deleteOnClose = (options & FileOptions.DeleteOnClose) != 0;
// Lock the file if requested via FileShare. This is only advisory locking. FileShare.None implies an exclusive
// lock on the file and all other modes use a shared lock. While this is not as granular as Windows, not mandatory,
@@ -293,6 +312,10 @@ private void Init(string path, FileMode mode, FileAccess access, FileShare share
}
}
+ // Enable DeleteOnClose when we've succesfully locked the file.
+ // On Windows, the locking happens atomically as part of opening the file.
+ _deleteOnClose = (options & FileOptions.DeleteOnClose) != 0;
+
// These provide hints around how the file will be accessed. Specifying both RandomAccess
// and Sequential together doesn't make sense as they are two competing options on the same spectrum,
// so if both are specified, we prefer RandomAccess (behavior on Windows is unspecified if both are provided).
@@ -323,20 +346,24 @@ private void Init(string path, FileMode mode, FileAccess access, FileShare share
}
}
- // If preallocationSize has been provided for a creatable and writeable file
- if (FileStreamHelpers.ShouldPreallocate(preallocationSize, access, mode))
+ if (preallocationSize > 0 && Interop.Sys.FAllocate(this, 0, preallocationSize) < 0)
{
- int fallocateResult = Interop.Sys.PosixFAllocate(this, 0, preallocationSize);
- if (fallocateResult != 0)
+ Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo();
+
+ // Only throw for errors that indicate there is not enough space.
+ if (errorInfo.Error == Interop.Error.EFBIG ||
+ errorInfo.Error == Interop.Error.ENOSPC)
{
Dispose();
- Interop.Sys.Unlink(path!); // remove the file to mimic Windows behaviour (atomic operation)
- Debug.Assert(fallocateResult == -1 || fallocateResult == -2);
- throw new IOException(SR.Format(
- fallocateResult == -1 ? SR.IO_DiskFull_Path_AllocationSize : SR.IO_FileTooLarge_Path_AllocationSize,
- path,
- preallocationSize));
+ // Delete the file we've created.
+ Debug.Assert(mode == FileMode.Create || mode == FileMode.CreateNew);
+ Interop.Sys.Unlink(path!);
+
+ throw new IOException(SR.Format(errorInfo.Error == Interop.Error.EFBIG
+ ? SR.IO_FileTooLarge_Path_AllocationSize
+ : SR.IO_DiskFull_Path_AllocationSize,
+ path, preallocationSize));
}
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs
index a7c4751a094786..3352f0194e73b9 100644
--- a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs
+++ b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs
@@ -34,7 +34,7 @@ internal static unsafe SafeFileHandle Open(string fullPath, FileMode mode, FileA
// of converting DOS to NT file paths (RtlDosPathNameToRelativeNtPathName_U_WithStatus is not documented)
SafeFileHandle fileHandle = CreateFile(fullPath, mode, access, share, options);
- if (FileStreamHelpers.ShouldPreallocate(preallocationSize, access, mode))
+ if (preallocationSize > 0)
{
Preallocate(fullPath, preallocationSize, fileHandle);
}
@@ -121,19 +121,19 @@ private static unsafe void Preallocate(string fullPath, long preallocationSize,
{
int errorCode = Marshal.GetLastPInvokeError();
- // we try to mimic the atomic NtCreateFile here:
- // if preallocation fails, close the handle and delete the file
- fileHandle.Dispose();
- Interop.Kernel32.DeleteFile(fullPath);
-
- switch (errorCode)
+ // Only throw for errors that indicate there is not enough space.
+ if (errorCode == Interop.Errors.ERROR_DISK_FULL ||
+ errorCode == Interop.Errors.ERROR_FILE_TOO_LARGE)
{
- case Interop.Errors.ERROR_DISK_FULL:
- throw new IOException(SR.Format(SR.IO_DiskFull_Path_AllocationSize, fullPath, preallocationSize));
- case Interop.Errors.ERROR_FILE_TOO_LARGE:
- throw new IOException(SR.Format(SR.IO_FileTooLarge_Path_AllocationSize, fullPath, preallocationSize));
- default:
- throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
+ fileHandle.Dispose();
+
+ // Delete the file we've created.
+ Interop.Kernel32.DeleteFile(fullPath);
+
+ throw new IOException(SR.Format(errorCode == Interop.Errors.ERROR_DISK_FULL
+ ? SR.IO_DiskFull_Path_AllocationSize
+ : SR.IO_FileTooLarge_Path_AllocationSize,
+ fullPath, preallocationSize));
}
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
index 6cd99cac9c9531..cb95472d7f96d3 100644
--- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
+++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
@@ -528,6 +528,9 @@
Type passed must be an interface.
+
+ Object must be of type NFloat.
+
Type must be a Pointer.
@@ -1092,6 +1095,12 @@
Append access can be requested only in write-only mode.
+
+ Preallocation size can be requested only in write mode.
+
+
+ Preallocation size can be requested only for new files.
+
Type of argument is not compatible with the generic comparer.
@@ -2659,9 +2668,6 @@
BindHandle for ThreadPool failed on this handle.
-
- The link's file system entry type is inconsistent with that of its target: {0}
-
The file '{0}' already exists.
diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index 5a1593f032c69a..ce942ea7e85696 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -2029,8 +2029,8 @@
Common\Interop\Unix\System.Native\Interop.PosixFAdvise.cs
-
- Common\Interop\Unix\System.Native\Interop.PosixFAllocate.cs
+
+ Common\Interop\Unix\System.Native\Interop.FAllocate.cs
Common\Interop\Unix\System.Native\Interop.PRead.cs
@@ -2098,7 +2098,7 @@
-
+
@@ -2112,6 +2112,8 @@
+
+
@@ -2155,14 +2157,15 @@
Link="Common\Interop\Linux\Interop.ProcFsStat.TryReadStatusFile.cs" />
-
-
+
+
@@ -2325,4 +2328,4 @@
-
\ No newline at end of file
+
diff --git a/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs b/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs
index c8b5fcba415f5e..94760aa0ef991c 100644
--- a/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs
@@ -1,7 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Collections.Generic;
+using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics.Tracing;
using System.IO;
using System.Reflection;
@@ -30,5 +33,52 @@ private static string GetBaseDirectoryCore()
return directory;
}
+
+ internal static void LogSwitchValues(RuntimeEventSource ev)
+ {
+ if (s_switches is not null)
+ {
+ lock (s_switches)
+ {
+ foreach (KeyValuePair kvp in s_switches)
+ {
+ // Convert bool to int because it's cheaper to log (no boxing)
+ ev.LogAppContextSwitch(kvp.Key, kvp.Value ? 1 : 0);
+ }
+ }
+ }
+
+ if (s_dataStore is not null)
+ {
+ lock (s_dataStore)
+ {
+ if (s_switches is not null)
+ {
+ lock (s_switches)
+ {
+ LogDataStore(ev, s_switches);
+ }
+ }
+ else
+ {
+ LogDataStore(ev, null);
+ }
+
+ static void LogDataStore(RuntimeEventSource ev, Dictionary? switches)
+ {
+ Debug.Assert(s_dataStore is not null);
+ foreach (KeyValuePair kvp in s_dataStore)
+ {
+ if (kvp.Value is string s &&
+ bool.TryParse(s, out bool isEnabled) &&
+ switches?.ContainsKey(kvp.Key) != true)
+ {
+ ev.LogAppContextSwitch(kvp.Key, isEnabled ? 1 : 0);
+ }
+ }
+ }
+ }
+ }
+ }
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Byte.cs b/src/libraries/System.Private.CoreLib/src/System/Byte.cs
index 3d5b448159a63d..cbf21d307d636e 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Byte.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Byte.cs
@@ -285,11 +285,11 @@ object IConvertible.ToType(Type type, IFormatProvider? provider)
// IAdditionOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IAdditionOperators.operator +(byte left, byte right)
=> (byte)(left + right);
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked byte IAdditionOperators.operator +(byte left, byte right)
// => checked((byte)(left + right));
@@ -297,30 +297,30 @@ object IConvertible.ToType(Type type, IFormatProvider? provider)
// IAdditiveIdentity
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IAdditiveIdentity.AdditiveIdentity => 0;
//
// IBinaryInteger
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IBinaryInteger.LeadingZeroCount(byte value)
=> (byte)(BitOperations.LeadingZeroCount(value) - 24);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IBinaryInteger.PopCount(byte value)
=> (byte)BitOperations.PopCount(value);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IBinaryInteger.RotateLeft(byte value, int rotateAmount)
=> (byte)((value << (rotateAmount & 7)) | (value >> ((8 - rotateAmount) & 7)));
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IBinaryInteger.RotateRight(byte value, int rotateAmount)
=> (byte)((value >> (rotateAmount & 7)) | (value << ((8 - rotateAmount) & 7)));
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IBinaryInteger.TrailingZeroCount(byte value)
=> (byte)(BitOperations.TrailingZeroCount(value << 24) - 24);
@@ -328,11 +328,11 @@ static byte IBinaryInteger.TrailingZeroCount(byte value)
// IBinaryNumber
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IBinaryNumber.IsPow2(byte value)
=> BitOperations.IsPow2((uint)value);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IBinaryNumber.Log2(byte value)
=> (byte)BitOperations.Log2(value);
@@ -340,19 +340,19 @@ static byte IBinaryNumber.Log2(byte value)
// IBitwiseOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IBitwiseOperators.operator &(byte left, byte right)
=> (byte)(left & right);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IBitwiseOperators.operator |(byte left, byte right)
=> (byte)(left | right);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IBitwiseOperators.operator ^(byte left, byte right)
=> (byte)(left ^ right);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IBitwiseOperators.operator ~(byte value)
=> (byte)(~value);
@@ -360,19 +360,19 @@ static byte IBinaryNumber.Log2(byte value)
// IComparisonOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IComparisonOperators.operator <(byte left, byte right)
=> left < right;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IComparisonOperators.operator <=(byte left, byte right)
=> left <= right;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IComparisonOperators.operator >(byte left, byte right)
=> left > right;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IComparisonOperators.operator >=(byte left, byte right)
=> left >= right;
@@ -380,11 +380,11 @@ static byte IBinaryNumber.Log2(byte value)
// IDecrementOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IDecrementOperators.operator --(byte value)
=> --value;
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked byte IDecrementOperators.operator --(byte value)
// => checked(--value);
@@ -392,11 +392,11 @@ static byte IBinaryNumber.Log2(byte value)
// IDivisionOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IDivisionOperators.operator /(byte left, byte right)
=> (byte)(left / right);
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked byte IDivisionOperators.operator /(byte left, byte right)
// => checked((byte)(left / right));
@@ -404,11 +404,11 @@ static byte IBinaryNumber.Log2(byte value)
// IEqualityOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IEqualityOperators.operator ==(byte left, byte right)
=> left == right;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IEqualityOperators.operator !=(byte left, byte right)
=> left != right;
@@ -416,11 +416,11 @@ static byte IBinaryNumber.Log2(byte value)
// IIncrementOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IIncrementOperators.operator ++(byte value)
=> ++value;
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked byte IIncrementOperators.operator ++(byte value)
// => checked(++value);
@@ -428,21 +428,21 @@ static byte IBinaryNumber.Log2(byte value)
// IMinMaxValue
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IMinMaxValue.MinValue => MinValue;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IMinMaxValue.MaxValue => MaxValue;
//
// IModulusOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IModulusOperators.operator %(byte left, byte right)
=> (byte)(left % right);
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked byte IModulusOperators.operator %(byte left, byte right)
// => checked((byte)(left % right));
@@ -450,18 +450,18 @@ static byte IBinaryNumber.Log2(byte value)
// IMultiplicativeIdentity
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IMultiplicativeIdentity.MultiplicativeIdentity => 1;
//
// IMultiplyOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IMultiplyOperators.operator *(byte left, byte right)
=> (byte)(left * right);
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked byte IMultiplyOperators.operator *(byte left, byte right)
// => checked((byte)(left * right));
@@ -469,21 +469,21 @@ static byte IBinaryNumber.Log2(byte value)
// INumber
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte INumber.One => 1;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte INumber.Zero => 0;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte INumber.Abs(byte value)
=> value;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte INumber.Clamp(byte value, byte min, byte max)
=> Math.Clamp(value, min, max);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static byte INumber.Create(TOther value)
{
@@ -550,7 +550,7 @@ static byte INumber.Create(TOther value)
}
}
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static byte INumber.CreateSaturating(TOther value)
{
@@ -637,7 +637,7 @@ static byte INumber.CreateSaturating(TOther value)
}
}
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static byte INumber.CreateTruncating(TOther value)
{
@@ -704,31 +704,31 @@ static byte INumber.CreateTruncating(TOther value)
}
}
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static (byte Quotient, byte Remainder) INumber.DivRem(byte left, byte right)
=> Math.DivRem(left, right);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte INumber.Max(byte x, byte y)
=> Math.Max(x, y);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte INumber.Min(byte x, byte y)
=> Math.Min(x, y);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte INumber.Parse(string s, NumberStyles style, IFormatProvider? provider)
=> Parse(s, style, provider);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte INumber.Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider)
=> Parse(s, style, provider);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte INumber.Sign(byte value)
=> (byte)((value == 0) ? 0 : 1);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool INumber.TryCreate(TOther value, out byte result)
{
@@ -914,11 +914,11 @@ static bool INumber.TryCreate(TOther value, out byte result)
}
}
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool INumber.TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out byte result)
=> TryParse(s, style, provider, out result);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool INumber.TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out byte result)
=> TryParse(s, style, provider, out result);
@@ -926,11 +926,11 @@ static bool INumber.TryParse(ReadOnlySpan s, NumberStyles style, IFo
// IParseable
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IParseable.Parse(string s, IFormatProvider? provider)
=> Parse(s, provider);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IParseable.TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out byte result)
=> TryParse(s, NumberStyles.Integer, provider, out result);
@@ -938,15 +938,15 @@ static bool IParseable.TryParse([NotNullWhen(true)] string? s, IFormatProv
// IShiftOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IShiftOperators.operator <<(byte value, int shiftAmount)
=> (byte)(value << shiftAmount);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IShiftOperators.operator >>(byte value, int shiftAmount)
=> (byte)(value >> shiftAmount);
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static byte IShiftOperators.operator >>>(byte value, int shiftAmount)
// => (byte)(value >> shiftAmount);
@@ -954,11 +954,11 @@ static bool IParseable.TryParse([NotNullWhen(true)] string? s, IFormatProv
// ISpanParseable
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte ISpanParseable.Parse(ReadOnlySpan s, IFormatProvider? provider)
=> Parse(s, NumberStyles.Integer, provider);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool ISpanParseable.TryParse(ReadOnlySpan s, IFormatProvider? provider, out byte result)
=> TryParse(s, NumberStyles.Integer, provider, out result);
@@ -966,11 +966,11 @@ static bool ISpanParseable.TryParse(ReadOnlySpan s, IFormatProvider?
// ISubtractionOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte ISubtractionOperators.operator -(byte left, byte right)
=> (byte)(left - right);
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked byte ISubtractionOperators.operator -(byte left, byte right)
// => checked((byte)(left - right));
@@ -978,11 +978,11 @@ static bool ISpanParseable.TryParse(ReadOnlySpan s, IFormatProvider?
// IUnaryNegationOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IUnaryNegationOperators.operator -(byte value)
=> (byte)(-value);
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked byte IUnaryNegationOperators.operator -(byte value)
// => checked((byte)(-value));
@@ -990,11 +990,11 @@ static bool ISpanParseable.TryParse(ReadOnlySpan s, IFormatProvider?
// IUnaryPlusOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IUnaryPlusOperators.operator +(byte value)
=> (byte)(+value);
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked byte IUnaryPlusOperators.operator +(byte value)
// => checked((byte)(+value));
#endif // FEATURE_GENERIC_MATH
diff --git a/src/libraries/System.Private.CoreLib/src/System/Char.cs b/src/libraries/System.Private.CoreLib/src/System/Char.cs
index 26ff3399fe10ed..497b60b5d3449b 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Char.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Char.cs
@@ -1065,11 +1065,11 @@ public static int ConvertToUtf32(string s, int index)
// IAdditionOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IAdditionOperators.operator +(char left, char right)
=> (char)(left + right);
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked char IAdditionOperators.operator +(char left, char right)
// => checked((char)(left + right));
@@ -1077,30 +1077,30 @@ public static int ConvertToUtf32(string s, int index)
// IAdditiveIdentity
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IAdditiveIdentity.AdditiveIdentity => (char)0;
//
// IBinaryInteger
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IBinaryInteger.LeadingZeroCount(char value)
=> (char)(BitOperations.LeadingZeroCount(value) - 16);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IBinaryInteger.PopCount(char value)
=> (char)BitOperations.PopCount(value);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IBinaryInteger.RotateLeft(char value, int rotateAmount)
=> (char)((value << (rotateAmount & 15)) | (value >> ((16 - rotateAmount) & 15)));
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IBinaryInteger.RotateRight(char value, int rotateAmount)
=> (char)((value >> (rotateAmount & 15)) | (value << ((16 - rotateAmount) & 15)));
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IBinaryInteger.TrailingZeroCount(char value)
=> (char)(BitOperations.TrailingZeroCount(value << 16) - 16);
@@ -1108,11 +1108,11 @@ static char IBinaryInteger.TrailingZeroCount(char value)
// IBinaryNumber
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IBinaryNumber.IsPow2(char value)
=> BitOperations.IsPow2((uint)value);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IBinaryNumber.Log2(char value)
=> (char)BitOperations.Log2(value);
@@ -1120,19 +1120,19 @@ static char IBinaryNumber.Log2(char value)
// IBitwiseOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IBitwiseOperators.operator &(char left, char right)
=> (char)(left & right);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IBitwiseOperators.operator |(char left, char right)
=> (char)(left | right);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IBitwiseOperators.operator ^(char left, char right)
=> (char)(left ^ right);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IBitwiseOperators.operator ~(char value)
=> (char)(~value);
@@ -1140,19 +1140,19 @@ static char IBinaryNumber.Log2(char value)
// IComparisonOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IComparisonOperators.operator <(char left, char right)
=> left < right;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IComparisonOperators.operator <=(char left, char right)
=> left <= right;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IComparisonOperators.operator >(char left, char right)
=> left > right;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IComparisonOperators.operator >=(char left, char right)
=> left >= right;
@@ -1160,11 +1160,11 @@ static char IBinaryNumber.Log2(char value)
// IDecrementOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IDecrementOperators.operator --(char value)
=> --value;
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked char IDecrementOperators.operator --(char value)
// => checked(--value);
@@ -1172,11 +1172,11 @@ static char IBinaryNumber.Log2(char value)
// IDivisionOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IDivisionOperators.operator /(char left, char right)
=> (char)(left / right);
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked char IDivisionOperators.operator /(char left, char right)
// => checked((char)(left / right));
@@ -1184,11 +1184,11 @@ static char IBinaryNumber.Log2(char value)
// IEqualityOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IEqualityOperators.operator ==(char left, char right)
=> left == right;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IEqualityOperators.operator !=(char left, char right)
=> left != right;
@@ -1196,11 +1196,11 @@ static char IBinaryNumber.Log2(char value)
// IIncrementOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IIncrementOperators.operator ++(char value)
=> ++value;
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked char IIncrementOperators.operator ++(char value)
// => checked(++value);
@@ -1208,21 +1208,21 @@ static char IBinaryNumber.Log2(char value)
// IMinMaxValue
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IMinMaxValue.MinValue => MinValue;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IMinMaxValue.MaxValue => MaxValue;
//
// IModulusOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IModulusOperators.operator %(char left, char right)
=> (char)(left % right);
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked char IModulusOperators.operator %(char left, char right)
// => checked((char)(left % right));
@@ -1230,18 +1230,18 @@ static char IBinaryNumber.Log2(char value)
// IMultiplicativeIdentity
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IMultiplicativeIdentity.MultiplicativeIdentity => (char)1;
//
// IMultiplyOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IMultiplyOperators.operator *(char left, char right)
=> (char)(left * right);
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked char IMultiplyOperators.operator *(char left, char right)
// => checked((char)(left * right));
@@ -1249,21 +1249,21 @@ static char IBinaryNumber.Log2(char value)
// INumber
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char INumber.One => (char)1;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char INumber.Zero => (char)0;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char INumber.Abs(char value)
=> value;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char INumber.Clamp(char value, char min, char max)
=> (char)Math.Clamp(value, min, max);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static char INumber.Create(TOther value)
{
@@ -1330,7 +1330,7 @@ static char INumber.Create(TOther value)
}
}
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static char INumber.CreateSaturating(TOther value)
{
@@ -1414,7 +1414,7 @@ static char INumber.CreateSaturating(TOther value)
}
}
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static char INumber.CreateTruncating(TOther value)
{
@@ -1481,23 +1481,23 @@ static char INumber.CreateTruncating(TOther value)
}
}
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static (char Quotient, char Remainder) INumber.DivRem(char left, char right)
=> ((char, char))Math.DivRem(left, right);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char INumber.Max(char x, char y)
=> (char)Math.Max(x, y);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char INumber.Min(char x, char y)
=> (char)Math.Min(x, y);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char INumber.Parse(string s, NumberStyles style, IFormatProvider? provider)
=> Parse(s);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char INumber.Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider)
{
if (s.Length != 1)
@@ -1507,11 +1507,11 @@ static char INumber.Parse(ReadOnlySpan s, NumberStyles style, IForma
return s[0];
}
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char INumber.Sign(char value)
=> (char)((value == 0) ? 0 : 1);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool INumber.TryCreate(TOther value, out char result)
{
@@ -1689,11 +1689,11 @@ static bool INumber.TryCreate(TOther value, out char result)
}
}
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool INumber.TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out char result)
=> TryParse(s, out result);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool INumber.TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out char result)
{
if (s.Length != 1)
@@ -1709,11 +1709,11 @@ static bool INumber.TryParse(ReadOnlySpan s, NumberStyles style, IFo
// IParseable
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IParseable.Parse(string s, IFormatProvider? provider)
=> Parse(s);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IParseable.TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out char result)
=> TryParse(s, out result);
@@ -1721,15 +1721,15 @@ static bool IParseable.TryParse([NotNullWhen(true)] string? s, IFormatProv
// IShiftOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IShiftOperators.operator <<(char value, int shiftAmount)
=> (char)(value << shiftAmount);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IShiftOperators.operator >>(char value, int shiftAmount)
=> (char)(value >> shiftAmount);
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static char IShiftOperators.operator >>>(char value, int shiftAmount)
// => (char)(value >> shiftAmount);
@@ -1737,7 +1737,7 @@ static bool IParseable.TryParse([NotNullWhen(true)] string? s, IFormatProv
// ISpanParseable
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char ISpanParseable.Parse(ReadOnlySpan s, IFormatProvider? provider)
{
if (s.Length != 1)
@@ -1747,7 +1747,7 @@ static char ISpanParseable.Parse(ReadOnlySpan s, IFormatProvider? pr
return s[0];
}
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool ISpanParseable.TryParse(ReadOnlySpan s, IFormatProvider? provider, out char result)
{
if (s.Length != 1)
@@ -1763,11 +1763,11 @@ static bool ISpanParseable.TryParse(ReadOnlySpan s, IFormatProvider?
// ISubtractionOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char ISubtractionOperators.operator -(char left, char right)
=> (char)(left - right);
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked char ISubtractionOperators.operator -(char left, char right)
// => checked((char)(left - right));
@@ -1775,11 +1775,11 @@ static bool ISpanParseable.TryParse(ReadOnlySpan s, IFormatProvider?
// IUnaryNegationOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IUnaryNegationOperators.operator -(char value)
=> (char)(-value);
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked char IUnaryNegationOperators.operator -(char value)
// => checked((char)(-value));
@@ -1787,11 +1787,11 @@ static bool ISpanParseable.TryParse(ReadOnlySpan s, IFormatProvider?
// IUnaryPlusOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static char IUnaryPlusOperators.operator +(char value)
=> (char)(+value);
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked char IUnaryPlusOperators.operator +(char value)
// => checked((char)(+value));
#endif // FEATURE_GENERIC_MATH
diff --git a/src/libraries/System.Private.CoreLib/src/System/DateOnly.cs b/src/libraries/System.Private.CoreLib/src/System/DateOnly.cs
index 7e64638fa51031..955ecb17b79c34 100644
--- a/src/libraries/System.Private.CoreLib/src/System/DateOnly.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/DateOnly.cs
@@ -817,15 +817,13 @@ public string ToString(string? format, IFormatProvider? provider)
return DateTimeFormat.TryFormat(GetEquivalentDateTime(), destination, out charsWritten, format, provider);
default:
- charsWritten = 0;
- return false;
+ throw new FormatException(SR.Argument_BadFormatSpecifier);
}
}
if (!DateTimeFormat.IsValidCustomDateFormat(format, throwOnError: false))
{
- charsWritten = 0;
- return false;
+ throw new FormatException(SR.Format(SR.Format_DateTimeOnlyContainsNoneDateParts, format.ToString(), nameof(DateOnly)));
}
return DateTimeFormat.TryFormat(GetEquivalentDateTime(), destination, out charsWritten, format, provider);
@@ -836,19 +834,19 @@ public string ToString(string? format, IFormatProvider? provider)
// IComparisonOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IComparisonOperators.operator <(DateOnly left, DateOnly right)
=> left < right;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IComparisonOperators.operator <=(DateOnly left, DateOnly right)
=> left <= right;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IComparisonOperators.operator >(DateOnly left, DateOnly right)
=> left > right;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IComparisonOperators.operator >=(DateOnly left, DateOnly right)
=> left >= right;
@@ -856,11 +854,11 @@ public string ToString(string? format, IFormatProvider? provider)
// IEqualityOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IEqualityOperators.operator ==(DateOnly left, DateOnly right)
=> left == right;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IEqualityOperators.operator !=(DateOnly left, DateOnly right)
=> left != right;
@@ -868,21 +866,21 @@ public string ToString(string? format, IFormatProvider? provider)
// IMinMaxValue
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static DateOnly IMinMaxValue.MinValue => MinValue;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static DateOnly IMinMaxValue.MaxValue => MaxValue;
//
// IParseable
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static DateOnly IParseable.Parse(string s, IFormatProvider? provider)
=> Parse(s, provider, DateTimeStyles.None);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IParseable.TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out DateOnly result)
=> TryParse(s, provider, DateTimeStyles.None, out result);
@@ -890,11 +888,11 @@ static bool IParseable.TryParse([NotNullWhen(true)] string? s, IFormat
// ISpanParseable
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static DateOnly ISpanParseable.Parse(ReadOnlySpan s, IFormatProvider? provider)
=> Parse(s, provider, DateTimeStyles.None);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool ISpanParseable.TryParse(ReadOnlySpan s, IFormatProvider? provider, out DateOnly result)
=> TryParse(s, provider, DateTimeStyles.None, out result);
#endif // FEATURE_GENERIC_MATH
diff --git a/src/libraries/System.Private.CoreLib/src/System/DateTime.cs b/src/libraries/System.Private.CoreLib/src/System/DateTime.cs
index 1d0235268a14ec..5017c7c49cceca 100644
--- a/src/libraries/System.Private.CoreLib/src/System/DateTime.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/DateTime.cs
@@ -1521,11 +1521,11 @@ internal static bool TryCreate(int year, int month, int day, int hour, int minut
// IAdditionOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static DateTime IAdditionOperators.operator +(DateTime left, TimeSpan right)
=> left + right;
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked DateTime IAdditionOperators.operator +(DateTime left, TimeSpan right)
// => checked(left + right);
@@ -1533,7 +1533,7 @@ internal static bool TryCreate(int year, int month, int day, int hour, int minut
// IAdditiveIdentity
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static TimeSpan IAdditiveIdentity.AdditiveIdentity
=> default;
@@ -1541,19 +1541,19 @@ static TimeSpan IAdditiveIdentity.AdditiveIdentity
// IComparisonOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IComparisonOperators.operator <(DateTime left, DateTime right)
=> left < right;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IComparisonOperators.operator <=(DateTime left, DateTime right)
=> left <= right;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IComparisonOperators.operator >(DateTime left, DateTime right)
=> left > right;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IComparisonOperators.operator >=(DateTime left, DateTime right)
=> left >= right;
@@ -1561,11 +1561,11 @@ static TimeSpan IAdditiveIdentity.AdditiveIdentity
// IEqualityOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IEqualityOperators.operator ==(DateTime left, DateTime right)
=> left == right;
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IEqualityOperators.operator !=(DateTime left, DateTime right)
=> left != right;
@@ -1573,21 +1573,21 @@ static TimeSpan IAdditiveIdentity