|
|
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.