Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

403 lines
10 KiB

  1. #include "StdAfx.h"
  2. #include "MonitorThread.h"
  3. #include <Folders.h>
  4. namespace nsMonitorThread
  5. {
  6. _bstr_t __stdcall GetLogFolder(LPCTSTR pszLog);
  7. bool __stdcall OpenFile(LPCTSTR pszFile, HANDLE& hFile, FILETIME ftFile, bool bDontCheckLastWriteTime = false);
  8. bool __stdcall IsLastWriteTimeUpdated(HANDLE hFile, FILETIME& ftFile);
  9. void __stdcall DisplayFile(HANDLE hFile);
  10. bool __stdcall CheckBeginTime(LPCTSTR pszFile, FILETIME ftFile, bool& bNeedCheckMonitorBeginTime);
  11. }
  12. using namespace nsMonitorThread;
  13. //---------------------------------------------------------------------------
  14. // MonitorThread Class
  15. //---------------------------------------------------------------------------
  16. // Constructor
  17. CMonitorThread::CMonitorThread() :
  18. m_strMigrationLog(GetMigrationLogPath()),
  19. m_hMigrationLog(INVALID_HANDLE_VALUE),
  20. m_strDispatchLog(GetDispatchLogPath()),
  21. m_hDispatchLog(INVALID_HANDLE_VALUE),
  22. m_bDontNeedCheckMonitorBeginTime(FALSE)
  23. {
  24. FILETIME ft;
  25. SYSTEMTIME st;
  26. GetSystemTime(&st);
  27. if (SystemTimeToFileTime(&st, &ft))
  28. {
  29. m_ftMigrationLogLastWriteTime = ft;
  30. m_ftDispatchLogLastWriteTime = ft;
  31. m_ftMonitorBeginTime = ft;
  32. }
  33. else
  34. {
  35. m_ftMigrationLogLastWriteTime.dwLowDateTime = 0;
  36. m_ftMigrationLogLastWriteTime.dwHighDateTime = 0;
  37. m_ftDispatchLogLastWriteTime.dwLowDateTime = 0;
  38. m_ftDispatchLogLastWriteTime.dwHighDateTime = 0;
  39. m_ftMonitorBeginTime.dwLowDateTime = 0;
  40. m_ftMonitorBeginTime.dwHighDateTime = 0;
  41. }
  42. }
  43. // Destructor
  44. CMonitorThread::~CMonitorThread()
  45. {
  46. }
  47. // Start Method
  48. void CMonitorThread::Start()
  49. {
  50. CThread::StartThread();
  51. }
  52. // Stop Method
  53. void CMonitorThread::Stop()
  54. {
  55. CThread::StopThread();
  56. }
  57. // Run Method
  58. void CMonitorThread::Run()
  59. {
  60. try
  61. {
  62. // position file pointer at end of dispatch log as this log is always appended to
  63. ProcessDispatchLog(true); // binitialize is true, bCheckModifyTime is default to true
  64. _bstr_t strMigration = GetLogFolder(m_strMigrationLog);
  65. _bstr_t strDispatch = GetLogFolder(m_strDispatchLog);
  66. HANDLE hHandles[3] = { StopEvent(), NULL, NULL };
  67. // obtain change notification handle for migration log folder
  68. // note that an invalid handle value is returned if the folder does not exist
  69. HANDLE hMigrationChange = INVALID_HANDLE_VALUE;
  70. HANDLE hDispatchChange = INVALID_HANDLE_VALUE;
  71. do
  72. {
  73. hMigrationChange = FindFirstChangeNotification(strMigration, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_LAST_WRITE);
  74. if (hMigrationChange != INVALID_HANDLE_VALUE)
  75. {
  76. break;
  77. }
  78. }
  79. while (WaitForSingleObject(hHandles[0], 1000) == WAIT_TIMEOUT);
  80. // if valid change notification handle then...
  81. if (hMigrationChange != INVALID_HANDLE_VALUE)
  82. {
  83. DWORD dwHandleCount = 2;
  84. hHandles[1] = hMigrationChange;
  85. // until stop event is signaled...
  86. for (bool bWait = true; bWait;)
  87. {
  88. // if change notification handle for dispatch log has not been obtained...
  89. if (hDispatchChange == INVALID_HANDLE_VALUE)
  90. {
  91. hDispatchChange = FindFirstChangeNotification(strDispatch, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_LAST_WRITE);
  92. if (hDispatchChange != INVALID_HANDLE_VALUE)
  93. {
  94. dwHandleCount = 3;
  95. hHandles[1] = hDispatchChange;
  96. hHandles[2] = hMigrationChange;
  97. }
  98. }
  99. // process signaled event
  100. switch (WaitForMultipleObjects(dwHandleCount, hHandles, FALSE, INFINITE))
  101. {
  102. case WAIT_OBJECT_0:
  103. {
  104. bWait = false;
  105. break;
  106. }
  107. case WAIT_OBJECT_0 + 1:
  108. {
  109. if (dwHandleCount == 2)
  110. {
  111. ProcessMigrationLog();
  112. FindNextChangeNotification(hMigrationChange);
  113. }
  114. else
  115. {
  116. ProcessDispatchLog(); // use default parameter values
  117. FindNextChangeNotification(hDispatchChange);
  118. }
  119. break;
  120. }
  121. case WAIT_OBJECT_0 + 2:
  122. {
  123. ProcessMigrationLog();
  124. FindNextChangeNotification(hMigrationChange);
  125. break;
  126. }
  127. default:
  128. {
  129. bWait = false;
  130. break;
  131. }
  132. }
  133. }
  134. }
  135. // close change notification handles
  136. if (hDispatchChange != INVALID_HANDLE_VALUE)
  137. {
  138. FindCloseChangeNotification(hDispatchChange);
  139. }
  140. if (hMigrationChange != INVALID_HANDLE_VALUE)
  141. {
  142. FindCloseChangeNotification(hMigrationChange);
  143. }
  144. // process logs one last time to display end of logs
  145. ProcessDispatchLog(false, false); // bInitialize is false, bCheckModifyTime is false
  146. ProcessMigrationLog(false);
  147. // close file handles
  148. if (m_hDispatchLog != INVALID_HANDLE_VALUE)
  149. {
  150. CloseHandle(m_hDispatchLog);
  151. }
  152. if (m_hMigrationLog != INVALID_HANDLE_VALUE)
  153. {
  154. CloseHandle(m_hMigrationLog);
  155. }
  156. }
  157. catch (...)
  158. {
  159. ;
  160. }
  161. }
  162. // ProcessMigrationLog Method
  163. void CMonitorThread::ProcessMigrationLog(bool bCheckModifyTime)
  164. {
  165. // first make sure that the last written time of the file is greater than the monitor start time, so
  166. // we can be certain that we are actually reading the most recent log file.
  167. if(m_bDontNeedCheckMonitorBeginTime || CheckBeginTime(m_strMigrationLog, m_ftMonitorBeginTime, m_bDontNeedCheckMonitorBeginTime))
  168. {
  169. if (OpenFile(m_strMigrationLog, m_hMigrationLog, m_ftMigrationLogLastWriteTime))
  170. {
  171. if(bCheckModifyTime)
  172. {
  173. if (IsLastWriteTimeUpdated(m_hMigrationLog, m_ftMigrationLogLastWriteTime))
  174. {
  175. DisplayFile(m_hMigrationLog);
  176. }
  177. }
  178. else
  179. {
  180. DisplayFile(m_hMigrationLog);
  181. }
  182. }
  183. }
  184. }
  185. // ProcessDispatchLog Method
  186. void CMonitorThread::ProcessDispatchLog(bool bInitialize, bool bCheckModifyTime)
  187. {
  188. if (OpenFile(m_strDispatchLog, m_hDispatchLog, m_ftDispatchLogLastWriteTime, bInitialize))
  189. {
  190. if (bInitialize)
  191. {
  192. SetFilePointer(m_hDispatchLog, 0, NULL, FILE_END);
  193. }
  194. if(bCheckModifyTime)
  195. {
  196. if (IsLastWriteTimeUpdated(m_hDispatchLog, m_ftDispatchLogLastWriteTime))
  197. {
  198. DisplayFile(m_hDispatchLog);
  199. }
  200. }
  201. else
  202. {
  203. DisplayFile(m_hDispatchLog);
  204. }
  205. }
  206. }
  207. namespace nsMonitorThread
  208. {
  209. _bstr_t __stdcall GetLogFolder(LPCTSTR pszLog)
  210. {
  211. _TCHAR szPath[_MAX_PATH];
  212. _TCHAR szDrive[_MAX_DRIVE];
  213. _TCHAR szDir[_MAX_DIR];
  214. if (pszLog)
  215. {
  216. _tsplitpath(pszLog, szDrive, szDir, NULL, NULL);
  217. _tmakepath(szPath, szDrive, szDir, NULL, NULL);
  218. }
  219. else
  220. {
  221. szPath[0] = _T('\0');
  222. }
  223. return szPath;
  224. }
  225. bool __stdcall OpenFile(LPCTSTR pszFile, HANDLE& hFile, FILETIME ftFile, bool bDontCheckLastWriteTime)
  226. {
  227. HANDLE h = hFile;
  228. if (h == INVALID_HANDLE_VALUE)
  229. {
  230. h = CreateFile(
  231. pszFile,
  232. GENERIC_READ,
  233. FILE_SHARE_READ|FILE_SHARE_WRITE,
  234. NULL,
  235. OPEN_EXISTING,
  236. FILE_ATTRIBUTE_NORMAL,
  237. NULL
  238. );
  239. if (h != INVALID_HANDLE_VALUE)
  240. {
  241. FILETIME ft = ftFile;
  242. if (bDontCheckLastWriteTime || IsLastWriteTimeUpdated(h, ft))
  243. {
  244. _TCHAR ch;
  245. DWORD cb;
  246. if (ReadFile(h, &ch, sizeof(ch), &cb, NULL) && (cb >= sizeof(ch)))
  247. {
  248. if (ch != _T('\xFEFF'))
  249. {
  250. SetFilePointer(h, 0, NULL, FILE_BEGIN);
  251. }
  252. hFile = h;
  253. }
  254. else
  255. {
  256. CloseHandle(h);
  257. }
  258. }
  259. else
  260. {
  261. CloseHandle(h);
  262. }
  263. }
  264. }
  265. return (hFile != INVALID_HANDLE_VALUE);
  266. }
  267. bool __stdcall IsLastWriteTimeUpdated(HANDLE hFile, FILETIME& ftFile)
  268. {
  269. bool bUpdated = false;
  270. BY_HANDLE_FILE_INFORMATION bhfi;
  271. if (GetFileInformationByHandle(hFile, &bhfi))
  272. {
  273. if (CompareFileTime(&bhfi.ftLastWriteTime, &ftFile) > 0)
  274. {
  275. ftFile = bhfi.ftLastWriteTime;
  276. bUpdated = true;
  277. }
  278. }
  279. return bUpdated;
  280. }
  281. void __stdcall DisplayFile(HANDLE hFile)
  282. {
  283. HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
  284. DWORD dwBytesRead;
  285. DWORD dwCharsWritten;
  286. _TCHAR szBuffer[1024];
  287. while (ReadFile(hFile, szBuffer, sizeof(szBuffer), &dwBytesRead, NULL) && (dwBytesRead > 0))
  288. {
  289. WriteConsole(hStdOut, szBuffer, dwBytesRead / sizeof(_TCHAR), &dwCharsWritten, NULL);
  290. }
  291. }
  292. bool __stdcall CheckBeginTime(LPCTSTR pszFile, FILETIME ftFile, bool& bDontNeedCheckMonitorBeginTime)
  293. {
  294. bool bLatestFile = false;
  295. HANDLE h = INVALID_HANDLE_VALUE;
  296. // Make sure that the monitor open the correct log file, not the old one
  297. h = CreateFile(
  298. pszFile,
  299. 0,
  300. FILE_SHARE_READ|FILE_SHARE_WRITE,
  301. NULL,
  302. OPEN_EXISTING,
  303. FILE_ATTRIBUTE_NORMAL,
  304. NULL
  305. );
  306. // if we fail to get the file handle, we will treat the file as not the newest one
  307. if(h != INVALID_HANDLE_VALUE)
  308. {
  309. // compare the monitor begin time with the last write time of the log file
  310. bLatestFile = IsLastWriteTimeUpdated(h, ftFile);
  311. CloseHandle(h);
  312. // mark the bDontNeedCheckMonitorBeginTime, so we don't have to go through this next time
  313. bDontNeedCheckMonitorBeginTime = bLatestFile;
  314. }
  315. return bLatestFile;
  316. }
  317. }