|
|
1.1 ! root 1: // Taken from: https://github.com/Walkman100/FileLocks ! 2: using System; ! 3: using System.Collections.Generic; ! 4: using System.IO; ! 5: using System.Runtime.CompilerServices; ! 6: using System.Runtime.ConstrainedExecution; ! 7: using System.Runtime.InteropServices; ! 8: using System.Security.Permissions; ! 9: using System.Text; ! 10: using System.Threading; ! 11: using Microsoft.Win32.SafeHandles; ! 12: using System.Diagnostics; ! 13: using System.Linq; ! 14: ! 15: namespace CleanFlashCommon { ! 16: public static class HandleUtil { ! 17: ! 18: private static Dictionary<string, string> deviceMap; ! 19: private const string networkDevicePrefix = "\\Device\\LanmanRedirector\\"; ! 20: private const int MAX_PATH = 260; ! 21: private const int handleTypeTokenCount = 27; ! 22: private static readonly string[] handleTypeTokens = new string[] { ! 23: "", "", "Directory", "SymbolicLink", "Token", ! 24: "Process", "Thread", "Unknown7", "Event", "EventPair", "Mutant", ! 25: "Unknown11", "Semaphore", "Timer", "Profile", "WindowStation", ! 26: "Desktop", "Section", "Key", "Port", "WaitablePort", ! 27: "Unknown21", "Unknown22", "Unknown23", "Unknown24", ! 28: "IoCompletion", "File" ! 29: }; ! 30: ! 31: internal enum NT_STATUS { ! 32: STATUS_SUCCESS = 0x00000000, ! 33: STATUS_BUFFER_OVERFLOW = unchecked((int)0x80000005L), ! 34: STATUS_INFO_LENGTH_MISMATCH = unchecked((int)0xC0000004L) ! 35: } ! 36: ! 37: internal enum SYSTEM_INFORMATION_CLASS { ! 38: SystemBasicInformation = 0, ! 39: SystemPerformanceInformation = 2, ! 40: SystemTimeOfDayInformation = 3, ! 41: SystemProcessInformation = 5, ! 42: SystemProcessorPerformanceInformation = 8, ! 43: SystemHandleInformation = 16, ! 44: SystemInterruptInformation = 23, ! 45: SystemExceptionInformation = 33, ! 46: SystemRegistryQuotaInformation = 37, ! 47: SystemLookasideInformation = 45 ! 48: } ! 49: ! 50: internal enum OBJECT_INFORMATION_CLASS { ! 51: ObjectBasicInformation = 0, ! 52: ObjectNameInformation = 1, ! 53: ObjectTypeInformation = 2, ! 54: ObjectAllTypesInformation = 3, ! 55: ObjectHandleInformation = 4 ! 56: } ! 57: ! 58: [Flags] ! 59: internal enum ProcessAccessRights { ! 60: PROCESS_DUP_HANDLE = 0x00000040 ! 61: } ! 62: ! 63: [Flags] ! 64: internal enum DuplicateHandleOptions { ! 65: DUPLICATE_CLOSE_SOURCE = 0x1, ! 66: DUPLICATE_SAME_ACCESS = 0x2 ! 67: } ! 68: ! 69: private enum SystemHandleType { ! 70: OB_TYPE_UNKNOWN = 0, ! 71: OB_TYPE_TYPE = 1, ! 72: OB_TYPE_DIRECTORY, ! 73: OB_TYPE_SYMBOLIC_LINK, ! 74: OB_TYPE_TOKEN, ! 75: OB_TYPE_PROCESS, ! 76: OB_TYPE_THREAD, ! 77: OB_TYPE_UNKNOWN_7, ! 78: OB_TYPE_EVENT, ! 79: OB_TYPE_EVENT_PAIR, ! 80: OB_TYPE_MUTANT, ! 81: OB_TYPE_UNKNOWN_11, ! 82: OB_TYPE_SEMAPHORE, ! 83: OB_TYPE_TIMER, ! 84: OB_TYPE_PROFILE, ! 85: OB_TYPE_WINDOW_STATION, ! 86: OB_TYPE_DESKTOP, ! 87: OB_TYPE_SECTION, ! 88: OB_TYPE_KEY, ! 89: OB_TYPE_PORT, ! 90: OB_TYPE_WAITABLE_PORT, ! 91: OB_TYPE_UNKNOWN_21, ! 92: OB_TYPE_UNKNOWN_22, ! 93: OB_TYPE_UNKNOWN_23, ! 94: OB_TYPE_UNKNOWN_24, ! 95: OB_TYPE_IO_COMPLETION, ! 96: OB_TYPE_FILE ! 97: }; ! 98: ! 99: [StructLayout(LayoutKind.Sequential)] ! 100: private struct SYSTEM_HANDLE_ENTRY { ! 101: public int OwnerPid; ! 102: public byte ObjectType; ! 103: public byte HandleFlags; ! 104: public short HandleValue; ! 105: public int ObjectPointer; ! 106: public int AccessMask; ! 107: } ! 108: ! 109: [DllImport("ntdll.dll")] ! 110: internal static extern NT_STATUS NtQuerySystemInformation( ! 111: [In] SYSTEM_INFORMATION_CLASS SystemInformationClass, ! 112: [In] IntPtr SystemInformation, ! 113: [In] int SystemInformationLength, ! 114: [Out] out int ReturnLength); ! 115: ! 116: [DllImport("ntdll.dll")] ! 117: internal static extern NT_STATUS NtQueryObject( ! 118: [In] IntPtr Handle, ! 119: [In] OBJECT_INFORMATION_CLASS ObjectInformationClass, ! 120: [In] IntPtr ObjectInformation, ! 121: [In] int ObjectInformationLength, ! 122: [Out] out int ReturnLength); ! 123: ! 124: [DllImport("kernel32.dll", SetLastError = true)] ! 125: internal static extern SafeProcessHandle OpenProcess( ! 126: [In] ProcessAccessRights dwDesiredAccess, ! 127: [In, MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, ! 128: [In] int dwProcessId); ! 129: ! 130: [DllImport("kernel32.dll", SetLastError = true)] ! 131: [return: MarshalAs(UnmanagedType.Bool)] ! 132: internal static extern bool DuplicateHandle( ! 133: [In] IntPtr hSourceProcessHandle, ! 134: [In] IntPtr hSourceHandle, ! 135: [In] IntPtr hTargetProcessHandle, ! 136: [Out] out SafeObjectHandle lpTargetHandle, ! 137: [In] int dwDesiredAccess, ! 138: [In, MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, ! 139: [In] DuplicateHandleOptions dwOptions); ! 140: ! 141: [DllImport("kernel32.dll")] ! 142: internal static extern IntPtr GetCurrentProcess(); ! 143: ! 144: [DllImport("kernel32.dll", SetLastError = true)] ! 145: internal static extern int GetProcessId( ! 146: [In] IntPtr Process); ! 147: ! 148: [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] ! 149: [DllImport("kernel32.dll", SetLastError = true)] ! 150: [return: MarshalAs(UnmanagedType.Bool)] ! 151: internal static extern bool CloseHandle( ! 152: [In] IntPtr hObject); ! 153: ! 154: [DllImport("kernel32.dll", SetLastError = true)] ! 155: internal static extern int QueryDosDevice( ! 156: [In] string lpDeviceName, ! 157: [Out] StringBuilder lpTargetPath, ! 158: [In] int ucchMax); ! 159: ! 160: [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] ! 161: internal sealed class SafeObjectHandle : SafeHandleZeroOrMinusOneIsInvalid { ! 162: private SafeObjectHandle() : base(true) { } ! 163: ! 164: internal SafeObjectHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle) { ! 165: base.SetHandle(preexistingHandle); ! 166: } ! 167: ! 168: protected override bool ReleaseHandle() { ! 169: return CloseHandle(base.handle); ! 170: } ! 171: } ! 172: ! 173: [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] ! 174: internal sealed class SafeProcessHandle : SafeHandleZeroOrMinusOneIsInvalid { ! 175: private SafeProcessHandle() ! 176: : base(true) { } ! 177: ! 178: internal SafeProcessHandle(IntPtr preexistingHandle, bool ownsHandle) ! 179: : base(ownsHandle) { ! 180: base.SetHandle(preexistingHandle); ! 181: } ! 182: ! 183: protected override bool ReleaseHandle() { ! 184: return CloseHandle(base.handle); ! 185: } ! 186: } ! 187: ! 188: private sealed class OpenFiles : IEnumerable<string> { ! 189: private readonly int processId; ! 190: ! 191: internal OpenFiles(int processId) { ! 192: this.processId = processId; ! 193: } ! 194: ! 195: public IEnumerator<string> GetEnumerator() { ! 196: NT_STATUS ret; ! 197: int length = 0x10000; ! 198: // Loop, probing for required memory. ! 199: ! 200: do { ! 201: IntPtr ptr = IntPtr.Zero; ! 202: RuntimeHelpers.PrepareConstrainedRegions(); ! 203: ! 204: try { ! 205: RuntimeHelpers.PrepareConstrainedRegions(); ! 206: ! 207: try { } finally { ! 208: // CER guarantees that the address of the allocated ! 209: // memory is actually assigned to ptr if an ! 210: // asynchronous exception occurs. ! 211: ptr = Marshal.AllocHGlobal(length); ! 212: } ! 213: ! 214: ret = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemHandleInformation, ptr, length, out int returnLength); ! 215: ! 216: if (ret == NT_STATUS.STATUS_INFO_LENGTH_MISMATCH) { ! 217: // Round required memory up to the nearest 64KB boundary. ! 218: length = (returnLength + 0xffff) & ~0xffff; ! 219: } else if (ret == NT_STATUS.STATUS_SUCCESS) { ! 220: int handleCount = Marshal.ReadInt32(ptr); ! 221: int offset = sizeof(int); ! 222: int size = Marshal.SizeOf(typeof(SYSTEM_HANDLE_ENTRY)); ! 223: ! 224: for (int i = 0; i < handleCount; i++) { ! 225: SYSTEM_HANDLE_ENTRY handleEntry = (SYSTEM_HANDLE_ENTRY) Marshal.PtrToStructure((IntPtr)((int)ptr + offset), typeof(SYSTEM_HANDLE_ENTRY)); ! 226: ! 227: if (handleEntry.OwnerPid == processId) { ! 228: IntPtr handle = (IntPtr) handleEntry.HandleValue; ! 229: SystemHandleType handleType; ! 230: ! 231: if (GetHandleType(handle, handleEntry.OwnerPid, out handleType) && handleType == SystemHandleType.OB_TYPE_FILE) { ! 232: if (GetFileNameFromHandle(handle, handleEntry.OwnerPid, out string devicePath)) { ! 233: if (ConvertDevicePathToDosPath(devicePath, out string dosPath)) { ! 234: if (File.Exists(dosPath)) { ! 235: yield return dosPath; ! 236: } else if (Directory.Exists(dosPath)) { ! 237: yield return dosPath; ! 238: } ! 239: } ! 240: } ! 241: } ! 242: } ! 243: ! 244: offset += size; ! 245: } ! 246: } ! 247: } finally { ! 248: // CER guarantees that the allocated memory is freed, ! 249: // if an asynchronous exception occurs. ! 250: Marshal.FreeHGlobal(ptr); ! 251: } ! 252: } while (ret == NT_STATUS.STATUS_INFO_LENGTH_MISMATCH); ! 253: } ! 254: ! 255: System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { ! 256: return GetEnumerator(); ! 257: } ! 258: } ! 259: ! 260: private class FileNameFromHandleState : IDisposable { ! 261: private readonly ManualResetEvent _mr; ! 262: public IntPtr Handle { get; } ! 263: public string FileName { get; set; } ! 264: public bool RetValue { get; set; } ! 265: ! 266: public FileNameFromHandleState(IntPtr handle) { ! 267: _mr = new ManualResetEvent(false); ! 268: this.Handle = handle; ! 269: } ! 270: ! 271: public bool WaitOne(int wait) { ! 272: return _mr.WaitOne(wait, false); ! 273: } ! 274: ! 275: public void Set() { ! 276: try { ! 277: _mr.Set(); ! 278: } catch { } ! 279: } ! 280: ! 281: public void Dispose() { ! 282: if (_mr != null) { ! 283: _mr.Close(); ! 284: } ! 285: } ! 286: } ! 287: ! 288: private static bool GetFileNameFromHandle(IntPtr handle, out string fileName) { ! 289: IntPtr ptr = IntPtr.Zero; ! 290: RuntimeHelpers.PrepareConstrainedRegions(); ! 291: ! 292: try { ! 293: int length = 0x200; // 512 bytes ! 294: RuntimeHelpers.PrepareConstrainedRegions(); ! 295: ! 296: try { } finally { ! 297: // CER guarantees the assignment of the allocated ! 298: // memory address to ptr, if an ansynchronous exception ! 299: // occurs. ! 300: ptr = Marshal.AllocHGlobal(length); ! 301: } ! 302: ! 303: NT_STATUS ret = NtQueryObject(handle, OBJECT_INFORMATION_CLASS.ObjectNameInformation, ptr, length, out length); ! 304: ! 305: if (ret == NT_STATUS.STATUS_BUFFER_OVERFLOW) { ! 306: RuntimeHelpers.PrepareConstrainedRegions(); ! 307: try { } finally { ! 308: // CER guarantees that the previous allocation is freed, ! 309: // and that the newly allocated memory address is ! 310: // assigned to ptr if an asynchronous exception occurs. ! 311: Marshal.FreeHGlobal(ptr); ! 312: ptr = Marshal.AllocHGlobal(length); ! 313: } ! 314: ret = NtQueryObject(handle, OBJECT_INFORMATION_CLASS.ObjectNameInformation, ptr, length, out length); ! 315: } ! 316: if (ret == NT_STATUS.STATUS_SUCCESS) { ! 317: fileName = Marshal.PtrToStringUni((IntPtr)((int)ptr + 8), (length - 9) / 2); ! 318: return fileName.Length != 0; ! 319: } ! 320: } finally { ! 321: // CER guarantees that the allocated memory is freed, ! 322: // if an asynchronous exception occurs. ! 323: Marshal.FreeHGlobal(ptr); ! 324: } ! 325: ! 326: fileName = string.Empty; ! 327: return false; ! 328: } ! 329: private static void GetFileNameFromHandle(object state) { ! 330: FileNameFromHandleState s = (FileNameFromHandleState)state; ! 331: ! 332: s.RetValue = GetFileNameFromHandle(s.Handle, out string fileName); ! 333: s.FileName = fileName; ! 334: s.Set(); ! 335: } ! 336: ! 337: private static bool GetFileNameFromHandle(IntPtr handle, out string fileName, int wait) { ! 338: using (FileNameFromHandleState f = new FileNameFromHandleState(handle)) { ! 339: ThreadPool.QueueUserWorkItem(new WaitCallback(GetFileNameFromHandle), f); ! 340: ! 341: if (f.WaitOne(wait)) { ! 342: fileName = f.FileName; ! 343: return f.RetValue; ! 344: } else { ! 345: fileName = string.Empty; ! 346: return false; ! 347: } ! 348: } ! 349: } ! 350: ! 351: private static bool GetFileNameFromHandle(IntPtr handle, int processId, out string fileName) { ! 352: IntPtr currentProcess = GetCurrentProcess(); ! 353: bool remote = processId != GetProcessId(currentProcess); ! 354: SafeProcessHandle processHandle = null; ! 355: SafeObjectHandle objectHandle = null; ! 356: ! 357: try { ! 358: if (remote) { ! 359: processHandle = OpenProcess(ProcessAccessRights.PROCESS_DUP_HANDLE, true, processId); ! 360: if (DuplicateHandle(processHandle.DangerousGetHandle(), handle, currentProcess, out objectHandle, 0, false, DuplicateHandleOptions.DUPLICATE_SAME_ACCESS)) { ! 361: handle = objectHandle.DangerousGetHandle(); ! 362: } ! 363: } ! 364: ! 365: return GetFileNameFromHandle(handle, out fileName, 200); ! 366: } finally { ! 367: if (remote) { ! 368: if (processHandle != null) { ! 369: processHandle.Close(); ! 370: } ! 371: ! 372: if (objectHandle != null) { ! 373: objectHandle.Close(); ! 374: } ! 375: } ! 376: } ! 377: } ! 378: ! 379: private static string GetHandleTypeToken(IntPtr handle) { ! 380: NtQueryObject(handle, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, IntPtr.Zero, 0, out int length); ! 381: IntPtr ptr = IntPtr.Zero; ! 382: RuntimeHelpers.PrepareConstrainedRegions(); ! 383: ! 384: try { ! 385: RuntimeHelpers.PrepareConstrainedRegions(); ! 386: ! 387: try { } finally { ! 388: if (length >= 0) { ! 389: ptr = Marshal.AllocHGlobal(length); ! 390: } ! 391: } ! 392: ! 393: if (NtQueryObject(handle, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, ptr, length, out length) == NT_STATUS.STATUS_SUCCESS) { ! 394: return Marshal.PtrToStringUni((IntPtr)((int)ptr + 0x60)); ! 395: } ! 396: ! 397: } finally { ! 398: Marshal.FreeHGlobal(ptr); ! 399: } ! 400: ! 401: return string.Empty; ! 402: } ! 403: ! 404: private static string GetHandleTypeToken(IntPtr handle, int processId) { ! 405: IntPtr currentProcess = GetCurrentProcess(); ! 406: bool remote = processId != GetProcessId(currentProcess); ! 407: SafeProcessHandle processHandle = null; ! 408: SafeObjectHandle objectHandle = null; ! 409: ! 410: try { ! 411: if (remote) { ! 412: processHandle = OpenProcess(ProcessAccessRights.PROCESS_DUP_HANDLE, true, processId); ! 413: if (DuplicateHandle(processHandle.DangerousGetHandle(), handle, currentProcess, out objectHandle, 0, false, DuplicateHandleOptions.DUPLICATE_SAME_ACCESS)) { ! 414: handle = objectHandle.DangerousGetHandle(); ! 415: } ! 416: } ! 417: ! 418: return GetHandleTypeToken(handle); ! 419: } finally { ! 420: if (remote) { ! 421: if (processHandle != null) { ! 422: processHandle.Close(); ! 423: } ! 424: ! 425: if (objectHandle != null) { ! 426: objectHandle.Close(); ! 427: } ! 428: } ! 429: } ! 430: } ! 431: ! 432: private static bool GetHandleTypeFromToken(string token, out SystemHandleType handleType) { ! 433: for (int i = 1; i < handleTypeTokenCount; i++) { ! 434: if (handleTypeTokens[i] == token) { ! 435: handleType = (SystemHandleType) i; ! 436: return true; ! 437: } ! 438: } ! 439: ! 440: handleType = SystemHandleType.OB_TYPE_UNKNOWN; ! 441: return false; ! 442: } ! 443: ! 444: private static bool GetHandleType(IntPtr handle, int processId, out SystemHandleType handleType) { ! 445: string token = GetHandleTypeToken(handle, processId); ! 446: return GetHandleTypeFromToken(token, out handleType); ! 447: } ! 448: ! 449: private static bool ConvertDevicePathToDosPath(string devicePath, out string dosPath) { ! 450: EnsureDeviceMap(); ! 451: int i = devicePath.Length; ! 452: ! 453: while (i > 0 && (i = devicePath.LastIndexOf('\\', i - 1)) != -1) { ! 454: if (deviceMap.TryGetValue(devicePath.Substring(0, i), out string drive)) { ! 455: dosPath = string.Concat(drive, devicePath.Substring(i)); ! 456: return dosPath.Length != 0; ! 457: } ! 458: } ! 459: ! 460: dosPath = string.Empty; ! 461: return false; ! 462: } ! 463: ! 464: private static void EnsureDeviceMap() { ! 465: if (deviceMap == null) { ! 466: Dictionary<string, string> localDeviceMap = BuildDeviceMap(); ! 467: Interlocked.CompareExchange(ref deviceMap, localDeviceMap, null); ! 468: } ! 469: } ! 470: ! 471: private static Dictionary<string, string> BuildDeviceMap() { ! 472: string[] logicalDrives = Environment.GetLogicalDrives(); ! 473: Dictionary<string, string> localDeviceMap = new Dictionary<string, string>(logicalDrives.Length); ! 474: StringBuilder lpTargetPath = new StringBuilder(MAX_PATH); ! 475: ! 476: foreach (string drive in logicalDrives) { ! 477: string lpDeviceName = drive.Substring(0, 2); ! 478: QueryDosDevice(lpDeviceName, lpTargetPath, MAX_PATH); ! 479: localDeviceMap.Add(NormalizeDeviceName(lpTargetPath.ToString()), lpDeviceName); ! 480: } ! 481: ! 482: localDeviceMap.Add(networkDevicePrefix.Substring(0, networkDevicePrefix.Length - 1), "\\"); ! 483: return localDeviceMap; ! 484: } ! 485: ! 486: private static string NormalizeDeviceName(string deviceName) { ! 487: if (string.Compare(deviceName, 0, networkDevicePrefix, 0, networkDevicePrefix.Length, StringComparison.InvariantCulture) == 0) { ! 488: string shareName = deviceName.Substring(deviceName.IndexOf('\\', networkDevicePrefix.Length) + 1); ! 489: return string.Concat(networkDevicePrefix, shareName); ! 490: } ! 491: ! 492: return deviceName; ! 493: } ! 494: ! 495: /// <summary> ! 496: /// Gets the open files enumerator. ! 497: /// </summary> ! 498: /// <param name="processId">The process id.</param> ! 499: /// <returns></returns> ! 500: public static IEnumerable<string> GetOpenFilesEnumerator(int processId) { ! 501: return new OpenFiles(processId); ! 502: } ! 503: ! 504: public static List<Process> GetProcessesUsingFile(string fName) { ! 505: List<Process> result = new List<Process>(); ! 506: foreach (Process p in Process.GetProcesses()) { ! 507: try { ! 508: if (GetOpenFilesEnumerator(p.Id).Contains(fName)) { ! 509: result.Add(p); ! 510: } ! 511: } catch { } // Some processes will fail. ! 512: } ! 513: return result; ! 514: } ! 515: ! 516: public static void KillProcessesUsingFile(string fName) { ! 517: foreach (Process process in GetProcessesUsingFile(fName).OrderBy(o => o.StartTime)) { ! 518: try { ! 519: process.Kill(); ! 520: process.WaitForExit(); ! 521: } catch { ! 522: // Oh well... ! 523: } ! 524: } ! 525: } ! 526: } ! 527: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.