/src/Raven.Client/Extensions/WhoIsLocking.cs

https://github.com/fitzchak/ravendb · C# · 170 lines · 140 code · 20 blank · 10 comment · 13 complexity · 9b114d2e9c6f77f78250fbf203cfe3ff MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Diagnostics;
  5. using System.Runtime.InteropServices;
  6. using System.Runtime.InteropServices.ComTypes;
  7. using System.Text;
  8. using Sparrow.Platform;
  9. namespace Raven.Client.Extensions
  10. {
  11. public static class WhoIsLocking
  12. {
  13. private const int RmRebootReasonNone = 0;
  14. private const int CCH_RM_MAX_APP_NAME = 255;
  15. private const int CCH_RM_MAX_SVC_NAME = 63;
  16. public static string ThisFile(string path)
  17. {
  18. var processesUsingFiles = GetProcessesUsingFile(path);
  19. var stringBuilder = new StringBuilder();
  20. stringBuilder.Append("The following processes are locking ").Append(path).AppendLine();
  21. foreach (var processesUsingFile in processesUsingFiles)
  22. {
  23. stringBuilder.Append("\t").Append(processesUsingFile.ProcessName).Append(' ').Append(processesUsingFile.Id).
  24. AppendLine();
  25. }
  26. return stringBuilder.ToString();
  27. }
  28. public static IList<Process> GetProcessesUsingFile(string filePath)
  29. {
  30. var processes = new List<Process>();
  31. if (PlatformDetails.RunningOnPosix)
  32. return processes;
  33. // Create a restart manager session
  34. int rv;
  35. uint sessionHandle;
  36. try
  37. {
  38. rv = RmStartSession(out sessionHandle, 0, Guid.NewGuid().ToString());
  39. }
  40. catch (DllNotFoundException)
  41. {
  42. return processes;
  43. }
  44. if (rv != 0)
  45. throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to RmStartSession");
  46. try
  47. {
  48. // Let the restart manager know what files we’re interested in
  49. var pathStrings = new[]{filePath};
  50. rv = RmRegisterResources(sessionHandle,
  51. (uint) pathStrings.Length, pathStrings,
  52. 0, null, 0, null);
  53. if (rv != 0)
  54. throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to RmRegisterResources (sessionHandle=" + sessionHandle + ")");
  55. // Ask the restart manager what other applications
  56. // are using those files
  57. const int ERROR_MORE_DATA = 234;
  58. uint pnProcInfo = 0,
  59. lpdwRebootReasons = RmRebootReasonNone;
  60. rv = RmGetList(sessionHandle, out uint pnProcInfoNeeded,
  61. ref pnProcInfo, null, ref lpdwRebootReasons);
  62. if (rv == ERROR_MORE_DATA)
  63. {
  64. // Create an array to store the process results
  65. var processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded];
  66. pnProcInfo = (uint) processInfo.Length;
  67. // Get the list
  68. rv = RmGetList(sessionHandle, out pnProcInfoNeeded,
  69. ref pnProcInfo, processInfo, ref lpdwRebootReasons);
  70. if (rv == 0)
  71. {
  72. // Enumerate all of the results and add them to the
  73. // list to be returned
  74. for (int i = 0; i < pnProcInfo; i++)
  75. {
  76. try
  77. {
  78. processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId));
  79. }
  80. catch (ArgumentException)
  81. {
  82. // in case the process is no longer running
  83. }
  84. }
  85. }
  86. else
  87. throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to RmGetList (sessionHandle=" + sessionHandle + ")");
  88. }
  89. else if (rv != 0)
  90. throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to RmGetList (sessionHandle=" + sessionHandle + ")");
  91. }
  92. finally
  93. {
  94. // Close the resource manager
  95. RmEndSession(sessionHandle);
  96. }
  97. return processes;
  98. }
  99. [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
  100. private static extern int RmStartSession(
  101. out uint pSessionHandle, int dwSessionFlags, string strSessionKey);
  102. [DllImport("rstrtmgr.dll")]
  103. private static extern int RmEndSession(uint pSessionHandle);
  104. [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
  105. private static extern int RmRegisterResources(uint pSessionHandle,
  106. UInt32 nFiles, string[] rgsFilenames,
  107. UInt32 nApplications, [In] RM_UNIQUE_PROCESS[] rgApplications,
  108. UInt32 nServices, string[] rgsServiceNames);
  109. [DllImport("rstrtmgr.dll")]
  110. private static extern int RmGetList(uint dwSessionHandle,
  111. out uint pnProcInfoNeeded, ref uint pnProcInfo,
  112. [In, Out] RM_PROCESS_INFO[] rgAffectedApps,
  113. ref uint lpdwRebootReasons);
  114. #region Nested type: RM_APP_TYPE
  115. private enum RM_APP_TYPE
  116. {
  117. RmUnknownApp = 0,
  118. RmMainWindow = 1,
  119. RmOtherWindow = 2,
  120. RmService = 3,
  121. RmExplorer = 4,
  122. RmConsole = 5,
  123. RmCritical = 1000
  124. }
  125. #endregion
  126. #region Nested type: RM_PROCESS_INFO
  127. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
  128. private struct RM_PROCESS_INFO
  129. {
  130. public RM_UNIQUE_PROCESS Process;
  131. [MarshalAs(UnmanagedType.ByValTStr,
  132. SizeConst = CCH_RM_MAX_APP_NAME + 1)] public readonly string strAppName;
  133. [MarshalAs(UnmanagedType.ByValTStr,
  134. SizeConst = CCH_RM_MAX_SVC_NAME + 1)] public readonly string strServiceShortName;
  135. public readonly RM_APP_TYPE ApplicationType;
  136. public readonly uint AppStatus;
  137. public readonly uint TSSessionId;
  138. [MarshalAs(UnmanagedType.Bool)] public readonly bool bRestartable;
  139. }
  140. #endregion
  141. #region Nested type: RM_UNIQUE_PROCESS
  142. [StructLayout(LayoutKind.Sequential)]
  143. private struct RM_UNIQUE_PROCESS
  144. {
  145. public readonly int dwProcessId;
  146. public readonly FILETIME ProcessStartTime;
  147. }
  148. #endregion
  149. }
  150. }