From 99f019328a82f8f5e18b68c859fda9d3304de68f Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Fri, 4 Mar 2022 16:09:27 +0100 Subject: [PATCH 1/4] when dotnet.exe is locked, wait a little bit and try few more times --- .../tests/ProcessStartInfoTests.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs index 6f304b08989f5..074cee63de257 100644 --- a/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs +++ b/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs @@ -490,7 +490,22 @@ public void TestUserCredentialsPropertiesOnWindows() p.StartInfo.UserName = username; p.StartInfo.PasswordInClearText = password; - hasStarted = p.Start(); + int tryCount = 0; + while (true) + { + try + { + hasStarted = p.Start(); + break; + } + catch (Win32Exception ex) when (ex.NativeErrorCode == ERROR_SHARING_VIOLATION && ++tryCount < 10) + { + // for some reason the dotnet.exe is sometimes locked by some other process + // that has opened it for writing with exclusive file access + // https://github.com/dotnet/runtime/issues/65820 + Thread.Sleep(TimeSpan.FromMilliseconds(50)); + } + } if (Interop.OpenProcessToken(p.SafeHandle, 0x8u, out handle)) { @@ -1210,6 +1225,7 @@ public static TheoryData UseShellExecute private const int ERROR_SUCCESS = 0x0; private const int ERROR_FILE_NOT_FOUND = 0x2; private const int ERROR_BAD_EXE_FORMAT = 0xC1; + private const int ERROR_SHARING_VIOLATION = 0x20; [Theory] [ActiveIssue("https://github.com/dotnet/runtime/issues/34685", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] From 5d71ce7744e55d8008ca3b5e8a836482631df194 Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Fri, 4 Mar 2022 16:13:28 +0100 Subject: [PATCH 2/4] just skip this test when it's impossible to start dotnet.exe --- .../tests/ProcessStartInfoTests.cs | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs index 074cee63de257..65c8611ffc1eb 100644 --- a/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs +++ b/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs @@ -490,21 +490,13 @@ public void TestUserCredentialsPropertiesOnWindows() p.StartInfo.UserName = username; p.StartInfo.PasswordInClearText = password; - int tryCount = 0; - while (true) + try { - try - { - hasStarted = p.Start(); - break; - } - catch (Win32Exception ex) when (ex.NativeErrorCode == ERROR_SHARING_VIOLATION && ++tryCount < 10) - { - // for some reason the dotnet.exe is sometimes locked by some other process - // that has opened it for writing with exclusive file access - // https://github.com/dotnet/runtime/issues/65820 - Thread.Sleep(TimeSpan.FromMilliseconds(50)); - } + hasStarted = p.Start(); + } + catch (Win32Exception ex) when (ex.NativeErrorCode == ERROR_SHARING_VIOLATION) + { + throw new SkipTestException($"{p.StartInfo.FileName} has been locked by some other process"); } if (Interop.OpenProcessToken(p.SafeHandle, 0x8u, out handle)) From 2de90f07c51fba82bc0445fb83d3532d0f038ecc Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Mon, 25 Apr 2022 19:17:15 +0200 Subject: [PATCH 3/4] grant access to the working directory as well (hopefully to avoid access denied) --- .../tests/ProcessStartInfoTests.cs | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs index 65c8611ffc1eb..2c1f139a3ebd6 100644 --- a/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs +++ b/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs @@ -483,7 +483,7 @@ public void TestUserCredentialsPropertiesOnWindows() if (PlatformDetection.IsNotWindowsServerCore) // for this particular Windows version it fails with Attempted to perform an unauthorized operation (#46619) { // ensure the new user can access the .exe (otherwise you get Access is denied exception) - SetAccessControl(username, p.StartInfo.FileName, add: true); + SetAccessControl(username, p.StartInfo.FileName, p.StartInfo.WorkingDirectory, add: true); } p.StartInfo.LoadUserProfile = true; @@ -530,29 +530,38 @@ public void TestUserCredentialsPropertiesOnWindows() if (PlatformDetection.IsNotWindowsServerCore) { - SetAccessControl(username, p.StartInfo.FileName, add: false); // remove the access + SetAccessControl(username, p.StartInfo.FileName, p.StartInfo.WorkingDirectory, add: false); // remove the access } Assert.Equal(Interop.ExitCodes.NERR_Success, Interop.NetUserDel(null, username)); } } - private static void SetAccessControl(string userName, string filePath, bool add) + private static void SetAccessControl(string userName, string filePath, string directoryPath, bool add) { FileInfo fileInfo = new FileInfo(filePath); - FileSecurity accessControl = fileInfo.GetAccessControl(); - FileSystemAccessRule fileSystemAccessRule = new FileSystemAccessRule(userName, FileSystemRights.ReadAndExecute, AccessControlType.Allow); + FileSecurity fileSecurity = fileInfo.GetAccessControl(); + Apply(userName, fileSecurity, FileSystemRights.ReadAndExecute, add); + fileInfo.SetAccessControl(fileSecurity); - if (add) - { - accessControl.AddAccessRule(fileSystemAccessRule); - } - else + DirectoryInfo directoryInfo = new DirectoryInfo(directoryPath); + DirectorySecurity directorySecurity = directoryInfo.GetAccessControl(); + Apply(userName, directorySecurity, FileSystemRights.Read , add); + directoryInfo.SetAccessControl(directorySecurity); + + static void Apply(string userName, FileSystemSecurity accessControl, FileSystemRights rights, bool add) { - accessControl.RemoveAccessRule(fileSystemAccessRule); - } + FileSystemAccessRule fileSystemAccessRule = new FileSystemAccessRule(userName, rights, AccessControlType.Allow); - fileInfo.SetAccessControl(accessControl); + if (add) + { + accessControl.AddAccessRule(fileSystemAccessRule); + } + else + { + accessControl.RemoveAccessRule(fileSystemAccessRule); + } + } } private static List GetNamesOfUserProfiles() From 7fbbdaf1b6afd870fd7a004c527d858db81c168f Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Tue, 26 Apr 2022 12:07:44 +0200 Subject: [PATCH 4/4] handle lack of working directory specified in explicit way --- .../tests/ProcessStartInfoTests.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs index 2c1f139a3ebd6..40d5cf2ddeebd 100644 --- a/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs +++ b/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs @@ -475,15 +475,20 @@ public void TestUserCredentialsPropertiesOnWindows() bool hasStarted = false; SafeProcessHandle handle = null; Process p = null; + string workingDirectory = null; try { p = CreateProcessLong(); + workingDirectory = string.IsNullOrEmpty(p.StartInfo.WorkingDirectory) + ? Directory.GetCurrentDirectory() + : p.StartInfo.WorkingDirectory; + if (PlatformDetection.IsNotWindowsServerCore) // for this particular Windows version it fails with Attempted to perform an unauthorized operation (#46619) { // ensure the new user can access the .exe (otherwise you get Access is denied exception) - SetAccessControl(username, p.StartInfo.FileName, p.StartInfo.WorkingDirectory, add: true); + SetAccessControl(username, p.StartInfo.FileName, workingDirectory, add: true); } p.StartInfo.LoadUserProfile = true; @@ -530,7 +535,7 @@ public void TestUserCredentialsPropertiesOnWindows() if (PlatformDetection.IsNotWindowsServerCore) { - SetAccessControl(username, p.StartInfo.FileName, p.StartInfo.WorkingDirectory, add: false); // remove the access + SetAccessControl(username, p.StartInfo.FileName, workingDirectory, add: false); // remove the access } Assert.Equal(Interop.ExitCodes.NERR_Success, Interop.NetUserDel(null, username));