PageRenderTime 43ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/tools/filemonitor.d

http://github.com/rainers/visuald
D | 266 lines | 220 code | 30 blank | 16 comment | 56 complexity | 5955c526dfab04f7e6f1b9c3b886e436 MD5 | raw file
Possible License(s): AGPL-3.0
  1. // This file is part of Visual D
  2. //
  3. // Visual D integrates the D programming language into Visual Studio
  4. // Copyright (c) 2010 by Rainer Schuetze, All Rights Reserved
  5. //
  6. // Distributed under the Boost Software License, Version 1.0.
  7. // See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt
  8. module filemonitor;
  9. //import std.c.windows.windows;
  10. import core.sys.windows.windows;
  11. //import core.sys.windows.dll;
  12. import core.stdc.stdio;
  13. import core.stdc.string;
  14. // version = msgbox;
  15. // check for @nogc support
  16. static if(!__traits(compiles, () { @nogc void fn(); }))
  17. struct nogc {};
  18. __gshared HINSTANCE g_hInst;
  19. extern(C) __gshared int _acrtused_dll;
  20. export __gshared char[260] dumpFile = [ 0 ];
  21. __gshared HANDLE hndDumpFile = INVALID_HANDLE_VALUE;
  22. __gshared HANDLE hndMutex = INVALID_HANDLE_VALUE;
  23. extern(Windows) HANDLE CreateMutexA(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCSTR lpName) nothrow @nogc;
  24. extern(Windows) BOOL ReleaseMutex(HANDLE hMutex) nothrow @nogc;
  25. version(TEST)
  26. {
  27. void main(string[]argv)
  28. {
  29. RedirectCreateFileA();
  30. auto hnd = CreateFileA("test.abc", GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, 0, null);
  31. }
  32. } else
  33. extern (Windows)
  34. BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
  35. {
  36. version(msgbox)
  37. {
  38. if(ulReason == DLL_PROCESS_ATTACH)
  39. MessageBoxA(null, "DLL_PROCESS_ATTACH", "filemonitor", MB_OK);
  40. if(ulReason == DLL_PROCESS_DETACH)
  41. MessageBoxA(null, "DLL_PROCESS_DETACH", "filemonitor", MB_OK);
  42. if(ulReason == DLL_THREAD_ATTACH)
  43. MessageBoxA(null, "DLL_THREAD_ATTACH", "filemonitor", MB_OK);
  44. if(ulReason == DLL_THREAD_DETACH)
  45. MessageBoxA(null, "DLL_THREAD_DETACH", "filemonitor", MB_OK);
  46. }
  47. g_hInst = hInstance;
  48. if(ulReason == DLL_PROCESS_ATTACH || ulReason == DLL_THREAD_ATTACH)
  49. {
  50. if (dumpFile[0]) // only execute if it was injected by pipedmd
  51. {
  52. origWriteFile = getWriteFileFunc();
  53. if(!origCreateFileA)
  54. RedirectCreateFileA();
  55. if(!origCreateFileW)
  56. RedirectCreateFileW();
  57. }
  58. }
  59. return true;
  60. }
  61. alias typeof(&CreateFileA) fnCreateFileA;
  62. alias typeof(&CreateFileW) fnCreateFileW;
  63. alias typeof(&WriteFile) fnWriteFile;
  64. __gshared fnCreateFileA origCreateFileA;
  65. __gshared fnCreateFileW origCreateFileW;
  66. __gshared fnWriteFile origWriteFile;
  67. __gshared fnCreateFileA myCF = &MyCreateFileA;
  68. alias typeof(&VirtualProtect) fnVirtualProtect;
  69. fnVirtualProtect getVirtualProtectFunc()
  70. {
  71. version(all)
  72. {
  73. HANDLE krnl = GetModuleHandleA("kernel32.dll");
  74. return cast(fnVirtualProtect) GetProcAddress(krnl, "VirtualProtect");
  75. }
  76. else
  77. {
  78. return &VirtualProtect;
  79. }
  80. }
  81. fnWriteFile getWriteFileFunc()
  82. {
  83. version(all)
  84. {
  85. HANDLE krnl = GetModuleHandleA("kernel32.dll");
  86. return cast(fnWriteFile) GetProcAddress(krnl, "WriteFile");
  87. }
  88. else
  89. {
  90. return &WriteFile;
  91. }
  92. }
  93. void RedirectCreateFileA()
  94. {
  95. version(msgbox) MessageBoxA(null, "RedirectCreateFileA", "filemonitor", MB_OK);
  96. ubyte* jmpAdr = cast(ubyte*)&CreateFileA;
  97. auto impTableEntry = cast(fnCreateFileA*) (*cast(void**)(jmpAdr + 2));
  98. origCreateFileA = *impTableEntry;
  99. DWORD oldProtect, newProtect;
  100. auto pfnVirtualProtect = getVirtualProtectFunc();
  101. pfnVirtualProtect(impTableEntry, (*impTableEntry).sizeof, PAGE_READWRITE, &oldProtect);
  102. *impTableEntry = &MyCreateFileA;
  103. pfnVirtualProtect(impTableEntry, (*impTableEntry).sizeof, oldProtect, &newProtect);
  104. }
  105. void RedirectCreateFileW()
  106. {
  107. version(msgbox) MessageBoxA(null, "RedirectCreateFileW", "filemonitor", MB_OK);
  108. ubyte* jmpAdr = cast(ubyte*)&CreateFileW;
  109. auto impTableEntry = cast(fnCreateFileW*) (*cast(void**)(jmpAdr + 2));
  110. origCreateFileW = *impTableEntry;
  111. DWORD oldProtect, newProtect;
  112. auto pfnVirtualProtect = getVirtualProtectFunc();
  113. pfnVirtualProtect(impTableEntry, (*impTableEntry).sizeof, PAGE_READWRITE, &oldProtect);
  114. *impTableEntry = &MyCreateFileW;
  115. pfnVirtualProtect(impTableEntry, (*impTableEntry).sizeof, oldProtect, &newProtect);
  116. }
  117. static if (__traits(compiles, core.sys.windows.winnt.LPCSTR))
  118. alias _LPCSTR = const(char)*; // detect SDK headers new in dmd 2.070
  119. else
  120. alias _LPCSTR = const(char*);
  121. extern(Windows) HANDLE
  122. MyCreateFileA(
  123. /*__in*/ _LPCSTR lpFileName,
  124. /*__in*/ DWORD dwDesiredAccess,
  125. /*__in*/ DWORD dwShareMode,
  126. /*__in_opt*/ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  127. /*__in*/ DWORD dwCreationDisposition,
  128. /*__in*/ DWORD dwFlagsAndAttributes,
  129. /*__in_opt*/ HANDLE hTemplateFile
  130. ) nothrow @nogc
  131. {
  132. version(msgbox) MessageBoxA(null, lpFileName, dumpFile.ptr/*"CreateFile"*/, MB_OK);
  133. // printf("CreateFileA(%s)\n", lpFileName);
  134. auto hnd = origCreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
  135. dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
  136. if(hnd != INVALID_HANDLE_VALUE && isLoggableOpen(dwDesiredAccess, dwCreationDisposition, dwFlagsAndAttributes))
  137. {
  138. if(dumpFile[0] && hndDumpFile == INVALID_HANDLE_VALUE)
  139. {
  140. hndDumpFile = origCreateFileA(dumpFile.ptr, GENERIC_WRITE, FILE_SHARE_READ, null, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, null);
  141. hndMutex = CreateMutexA(null, false, null);
  142. }
  143. if(hndDumpFile != INVALID_HANDLE_VALUE)
  144. {
  145. // combine writes to "atomic" write to avoid wrong placing of newlines
  146. if(hndMutex != INVALID_HANDLE_VALUE)
  147. WaitForSingleObject(hndMutex, INFINITE);
  148. size_t length = mystrlen(lpFileName);
  149. origWriteFile(hndDumpFile, lpFileName, length, &length, null);
  150. origWriteFile(hndDumpFile, "\n".ptr, 1, &length, null);
  151. if(hndMutex != INVALID_HANDLE_VALUE)
  152. ReleaseMutex(hndMutex);
  153. }
  154. }
  155. return hnd;
  156. }
  157. extern(Windows) HANDLE
  158. MyCreateFileW(
  159. /*__in*/ LPCWSTR lpFileName,
  160. /*__in*/ DWORD dwDesiredAccess,
  161. /*__in*/ DWORD dwShareMode,
  162. /*__in_opt*/ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  163. /*__in*/ DWORD dwCreationDisposition,
  164. /*__in*/ DWORD dwFlagsAndAttributes,
  165. /*__in_opt*/ HANDLE hTemplateFile
  166. ) nothrow @nogc
  167. {
  168. version(msgbox) MessageBoxW(null, lpFileName, "CreateFileW", MB_OK);
  169. // printf("CreateFileA(%s)\n", lpFileName);
  170. auto hnd = origCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
  171. dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
  172. if(hnd != INVALID_HANDLE_VALUE && isLoggableOpen(dwDesiredAccess, dwCreationDisposition, dwFlagsAndAttributes))
  173. {
  174. if(dumpFile[0] && hndDumpFile == INVALID_HANDLE_VALUE)
  175. {
  176. hndMutex = CreateMutexA(null, false, null);
  177. if(hndMutex != INVALID_HANDLE_VALUE)
  178. WaitForSingleObject(hndMutex, INFINITE);
  179. if(hndDumpFile == INVALID_HANDLE_VALUE)
  180. hndDumpFile = origCreateFileA(dumpFile.ptr, GENERIC_WRITE, FILE_SHARE_READ, null, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, null);
  181. ushort bom = 0xFEFF;
  182. size_t written;
  183. if(hndDumpFile != INVALID_HANDLE_VALUE)
  184. origWriteFile(hndDumpFile, &bom, 2, &written, null);
  185. if(hndMutex != INVALID_HANDLE_VALUE)
  186. ReleaseMutex(hndMutex);
  187. }
  188. if(hndDumpFile != INVALID_HANDLE_VALUE)
  189. {
  190. // combine writes to "atomic" write to avoid wrong placing of newlines
  191. if(hndMutex != INVALID_HANDLE_VALUE)
  192. WaitForSingleObject(hndMutex, INFINITE);
  193. size_t length = mystrlen(lpFileName);
  194. origWriteFile(hndDumpFile, lpFileName, 2*length, &length, null);
  195. origWriteFile(hndDumpFile, "\n".ptr, 2, &length, null);
  196. if(hndMutex != INVALID_HANDLE_VALUE)
  197. ReleaseMutex(hndMutex);
  198. }
  199. }
  200. return hnd;
  201. }
  202. bool isLoggableOpen(DWORD dwDesiredAccess, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes) nothrow @nogc
  203. {
  204. if(!(dwDesiredAccess & GENERIC_READ))
  205. return false;
  206. if(!(dwDesiredAccess & GENERIC_WRITE))
  207. return true;
  208. if(dwCreationDisposition == CREATE_ALWAYS || dwCreationDisposition == TRUNCATE_EXISTING)
  209. return false;
  210. if(dwFlagsAndAttributes & FILE_ATTRIBUTE_TEMPORARY)
  211. return false;
  212. return true;
  213. }
  214. size_t mystrlen(const(char)* str) nothrow @nogc
  215. {
  216. size_t len = 0;
  217. while(*str++)
  218. len++;
  219. return len;
  220. }
  221. size_t mystrlen(const(wchar)* str) nothrow @nogc
  222. {
  223. size_t len = 0;
  224. while(*str++)
  225. len++;
  226. return len;
  227. }
  228. ///////// shut up compiler generated GC info failing to link
  229. extern(C)
  230. {
  231. __gshared int D10TypeInfo_i6__initZ;
  232. __gshared int D10TypeInfo_v6__initZ;
  233. __gshared int D16TypeInfo_Pointer6__vtblZ;
  234. __gshared int D17TypeInfo_Function6__vtblZ;
  235. __gshared int D15TypeInfo_Struct6__vtblZ;
  236. }