Skip to content

Commit

Permalink
tmp
Browse files Browse the repository at this point in the history
  • Loading branch information
BinToss committed Feb 13, 2023
1 parent 1f1dc4f commit fb7a9ee
Show file tree
Hide file tree
Showing 7 changed files with 386 additions and 175 deletions.
9 changes: 4 additions & 5 deletions deadlock-dotnet-sdk/DeadLock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,8 @@ public DeadLock(bool rethrowExceptions)
/// <returns>The FileLocker object that contains a List of Process objects that are locking a file</returns>
public FileLocker FindLockingProcesses(string filePath)
{
FileLocker fileLocker = new(filePath,
return new(filePath,
NativeMethods.FindLockingProcesses(filePath, RethrowExceptions).ToList());
return fileLocker;
}

/// <summary>
Expand Down Expand Up @@ -315,7 +314,7 @@ public void UnlockEx(FileLockerEx fileLocker)
if (h.IsClosed && h.IsInvalid) continue;
try
{
h.UnlockSystemHandle();
h.CloseSourceHandle();
}
catch (Exception) when (!RethrowExceptions) { }
}
Expand Down Expand Up @@ -350,7 +349,7 @@ await Task.Run(() =>
if (h.IsClosed && h.IsInvalid) continue;
try
{
h.UnlockSystemHandle();
h.CloseSourceHandle();
}
catch (Exception) when (!RethrowExceptions) { }
}
Expand All @@ -372,7 +371,7 @@ await Task.Run(() =>
if (h.IsClosed && h.IsInvalid) continue;
try
{
h.UnlockSystemHandle();
h.CloseSourceHandle();
}
catch (Exception) when (!RethrowExceptions) { }
}
Expand Down
1 change: 0 additions & 1 deletion deadlock-dotnet-sdk/Domain/FileLockerEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ public FileLockerEx(string path, HandlesFilter filter, bool rethrowExceptions, o
/// <summary>
/// Filters for <see cref="NativeMethods.FindLockingHandles(string?, HandlesFilter)"/>
/// </summary>
/// TODO: rename to HandlesFilter
[Flags]
public enum HandlesFilter
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using Windows.Win32.Foundation;
using Windows.Win32.System.WindowsProgramming;
using static Windows.Win32.PInvoke;
using NTSTATUS = PInvoke.NTSTATUS;

// Re: StructLayout
// "C#, Visual Basic, and C++ compilers apply the Sequential layout value to structures by default."
Expand All @@ -20,8 +19,6 @@ namespace deadlock_dotnet_sdk.Domain;

internal static partial class NativeMethods
{
private static bool IsSuccessful(this NTSTATUS status) => status.Severity == NTSTATUS.SeverityCode.STATUS_SEVERITY_SUCCESS;
private static bool NT_SUCCESS(this NTSTATUS status) => status.Severity == NTSTATUS.SeverityCode.STATUS_SEVERITY_SUCCESS;
private const uint PH_LARGE_BUFFER_SIZE = int.MaxValue;
private static List<ObjectTypeInformation>? objectTypes;
private static List<ObjectTypeInformation> ObjectTypes => objectTypes ??= ObjectTypesInformationBuffer.PhEnumObjectTypes().ToList();
Expand All @@ -31,15 +28,13 @@ internal static partial class NativeMethods
/// </summary>
private static uint? GetObjectTypeNumber(string typeName)
{
Version WINDOWS_8_1 = new(6, 2);
Version WindowsVersion = Environment.OSVersion.Version;
uint objectIndex = uint.MaxValue;

for (int i = 0; i < ObjectTypes.Count; i++)
{
if (typeName.Equals(ObjectTypes[i].TypeName, StringComparison.OrdinalIgnoreCase))
{
if (WindowsVersion >= WINDOWS_8_1)
if (OperatingSystem.IsWindowsVersionAtLeast(6, 3))
objectIndex = ObjectTypes[i].TypeIndex;
else
objectIndex = (uint)(i + 2);
Expand All @@ -57,13 +52,11 @@ internal static partial class NativeMethods
/// </summary>
private static string GetObjectTypeName(int typeIndex)
{
Version WINDOWS_8_1 = new(6, 2);
Version WindowsVersion = Environment.OSVersion.Version;
string objectTypeName = "";

for (int i = 0; i < ObjectTypes.Count; i++)
{
if (WindowsVersion >= WINDOWS_8_1)
if (OperatingSystem.IsWindowsVersionAtLeast(6, 3))
{
if (typeIndex == ObjectTypes[i].TypeIndex)
objectTypeName = ObjectTypes[i].TypeName;
Expand Down Expand Up @@ -254,30 +247,28 @@ public unsafe void ReAllocate(uint lengthInBytes)
/// <exception cref="NTStatusException"></exception>
public static unsafe ObjectTypesInformationBuffer PhEnumObjectTypes()
{
NTSTATUS status;
ObjectTypesInformationBuffer buffer;
Windows.Win32.Foundation.NTSTATUS status;
using ObjectTypesInformationBuffer buffer = new(0x1000);
uint returnLength;

buffer = new(0x1000);

while ((status = NtQueryObject(
null,
OBJECT_INFORMATION_CLASS.ObjectTypesInformation,
(void*)buffer.pointer,
buffer.bytes,
&returnLength
)) == NTSTATUS.Code.STATUS_INFO_LENGTH_MISMATCH)
)) == PInvoke.NTSTATUS.Code.STATUS_INFO_LENGTH_MISMATCH)
{
// Fail if we're resizing the buffer to something very large.
if (returnLength * 1.5 > PH_LARGE_BUFFER_SIZE)
throw new NTStatusException(NTSTATUS.Code.STATUS_INSUFFICIENT_RESOURCES);
throw new NTStatusException(PInvoke.NTSTATUS.Code.STATUS_INSUFFICIENT_RESOURCES);

buffer.ReAllocate((uint)(returnLength * 1.5));
}

if (!status.NT_SUCCESS())
if (!status.IsSuccessful)
{
buffer.Dispose();
// Dispose(or DisposeAsync) is called even if an exception occurs
throw new NTStatusException(status);
}

Expand All @@ -300,7 +291,7 @@ public unsafe uint PhGetObjectTypeNumber(string typeName)

if (string.Equals(typeNameSr, typeName, StringComparison.OrdinalIgnoreCase))
{
if (Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version >= new Version(6, 3))
if (OperatingSystem.IsWindowsVersionAtLeast(6, 3))
{
objectIndex = objectType->TypeIndex;
break;
Expand All @@ -315,7 +306,6 @@ public unsafe uint PhGetObjectTypeNumber(string typeName)
objectType = PH_NEXT_OBJECT_TYPE(objectType);
}
}

return objectIndex;
}

Expand All @@ -329,7 +319,7 @@ public unsafe uint PhGetObjectTypeNumber(string typeName)

for (i = 0; i < NumberOfTypes; i++)
{
if (OperatingSystem.IsWindowsVersionAtLeast(6, 2))
if (OperatingSystem.IsWindowsVersionAtLeast(6, 3))
{
if (TypeIndex == objectType->TypeIndex)
{
Expand Down
108 changes: 53 additions & 55 deletions deadlock-dotnet-sdk/Domain/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Windows.Win32.System.RestartManager;
using Windows.Win32.System.WindowsProgramming;
using static deadlock_dotnet_sdk.Domain.FileLockerEx;
using static deadlock_dotnet_sdk.Domain.NativeMethods;
using static Windows.Win32.PInvoke;
using NTSTATUS = PInvoke.NTSTATUS;
using Win32Exception = System.ComponentModel.Win32Exception;
Expand Down Expand Up @@ -40,85 +41,82 @@ internal static partial class NativeMethods
/// <param name="path">Path to the file</param>
/// <param name="rethrowExceptions">True if inner exceptions should be rethrown, otherwise false</param>
/// <returns>A collection of processes that are locking a file</returns>
internal static IEnumerable<Process> FindLockingProcesses(string path, bool rethrowExceptions)
internal static unsafe IEnumerable<Process> FindLockingProcesses(string path, bool rethrowExceptions)
{
unsafe
using (PWSTR key = new((char*)Marshal.StringToHGlobalUni(Guid.NewGuid().ToString())))
{
using (PWSTR key = new((char*)Marshal.StringToHGlobalUni(Guid.NewGuid().ToString())))
List<Process> processes = new();

// todo: new RmStartSession overload in CsWin32_NativeMethods.cs which can throw a StartSessionException derived from System.ComponentModel.Win32Exception
// Why? <c>new Win32Exception()</c> will get the last PInvoke error code in addition to the system's message for that Win32ErrorCode.
uint res = RmStartSession(out var handle, 0, key);
if (res != 0)
{
List<Process> processes = new();
throw new StartSessionException();
}

// todo: new RmStartSession overload in CsWin32_NativeMethods.cs which can throw a StartSessionException derived from System.ComponentModel.Win32Exception
// Why? <c>new Win32Exception()</c> will get the last PInvoke error code in addition to the system's message for that Win32ErrorCode.
uint res = RmStartSession(out var handle, 0, key);
if (res != 0)
{
throw new StartSessionException();
}
try
{
const int errorMoreData = 234;
uint pnProcInfo = 0;
uint lpdwRebootReasons = RmRebootReasonNone;

string[] resources = { path };

try
// "using" blocks have hidden "finally" blocks which are executed before exceptions leave this context.
using (PWSTR pResources = (char*)Marshal.StringToHGlobalUni(path))
{
const int errorMoreData = 234;
uint pnProcInfo = 0;
uint lpdwRebootReasons = RmRebootReasonNone;
res = RmRegisterResources(handle, new Span<PWSTR>(new PWSTR[] { pResources }), rgApplications: new(), new());

string[] resources = { path };
if (res != 0)
{
throw new RegisterResourceException();
}

res = RmGetList(handle, out var pnProcInfoNeeded, ref pnProcInfo, null, out lpdwRebootReasons);

// "using" blocks have hidden "finally" blocks which are executed before exceptions leave this context.
using (PWSTR pResources = (char*)Marshal.StringToHGlobalUni(path))
if (res == errorMoreData)
{
res = RmRegisterResources(handle, new Span<PWSTR>(new PWSTR[] { pResources }), rgApplications: new(), new());
ReadOnlySpan<RM_PROCESS_INFO> processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded];
pnProcInfo = pnProcInfoNeeded;

if (res != 0)
fixed (RM_PROCESS_INFO* pProcessInfo = processInfo)
{
throw new RegisterResourceException();
res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, pProcessInfo, out lpdwRebootReasons);
}

res = RmGetList(handle, out var pnProcInfoNeeded, ref pnProcInfo, null, out lpdwRebootReasons);

if (res == errorMoreData)
if (res == 0)
{
ReadOnlySpan<RM_PROCESS_INFO> processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded];
pnProcInfo = pnProcInfoNeeded;
processes = new List<Process>((int)pnProcInfo);

fixed (RM_PROCESS_INFO* pProcessInfo = processInfo)
{
res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, pProcessInfo, out lpdwRebootReasons);
}
if (res == 0)
for (int i = 0; i < pnProcInfo; i++)
{
processes = new List<Process>((int)pnProcInfo);

for (int i = 0; i < pnProcInfo; i++)
try
{
try
{
processes.Add(Process.GetProcessById((int)processInfo[i].Process.dwProcessId));
}
catch (ArgumentException)
{
if (rethrowExceptions) throw;
}
processes.Add(Process.GetProcessById((int)processInfo[i].Process.dwProcessId));
}
catch (ArgumentException)
{
if (rethrowExceptions) throw;
}
}
else
{
throw new RmListException();
}
}
else if (res != 0)
else
{
throw new UnauthorizedAccessException();
throw new RmListException();
}
}
else if (res != 0)
{
throw new UnauthorizedAccessException();
}
}
finally
{
_ = RmEndSession(handle);
}

return processes;
}
finally
{
_ = RmEndSession(handle);
}

return processes;
}
}

Expand Down
Loading

0 comments on commit fb7a9ee

Please sign in to comment.