Source code of Windows XP (NT5)
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.

645 lines
14 KiB

  1. /*++
  2. Copyright (C) 2000-2001 Microsoft Corporation
  3. --*/
  4. #include <windows.h>
  5. #include <stdio.h>
  6. #include <wbemcomn.h>
  7. #include "a51tools.h"
  8. __int64 g_nCurrentTime = 1;
  9. __int64 g_nReadFailures = 0;
  10. __int64 g_nWriteFailures = 0;
  11. //
  12. // FILE_ATTRIBUTE_NOT_CONTENT_INDEXED is not actually supported on CreateFile,
  13. // contrary to the docs. However, also contrary to the docs, it is inherited
  14. // from the parent directory
  15. //
  16. #define A51_FILE_CREATION_FLAGS 0 //FILE_ATTRIBUTE_NOT_CONTENT_INDEXED
  17. CTempMemoryManager g_Manager;
  18. void* TempAlloc(DWORD dwLen)
  19. {
  20. return g_Manager.Allocate(dwLen);
  21. }
  22. void TempFree(void* p, DWORD dwLen)
  23. {
  24. g_Manager.Free(p, dwLen);
  25. }
  26. void* TempAlloc(CTempMemoryManager& Manager, DWORD dwLen)
  27. {
  28. return Manager.Allocate(dwLen);
  29. }
  30. void TempFree(CTempMemoryManager& Manager, void* p, DWORD dwLen)
  31. {
  32. Manager.Free(p, dwLen);
  33. }
  34. HANDLE g_hLastEvent = NULL;
  35. CCritSec g_csEvents;
  36. HANDLE A51GetNewEvent()
  37. {
  38. {
  39. CInCritSec ics(&g_csEvents);
  40. if(g_hLastEvent)
  41. {
  42. HANDLE h = g_hLastEvent;
  43. g_hLastEvent = NULL;
  44. return h;
  45. }
  46. }
  47. return CreateEvent(NULL, TRUE, FALSE, NULL);
  48. }
  49. void A51ReturnEvent(HANDLE hEvent)
  50. {
  51. {
  52. CInCritSec ics(&g_csEvents);
  53. if(g_hLastEvent == NULL)
  54. {
  55. g_hLastEvent = hEvent;
  56. return;
  57. }
  58. }
  59. CloseHandle(hEvent);
  60. }
  61. HRESULT A51TranslateErrorCode(long lRes)
  62. {
  63. if (SUCCEEDED(lRes))
  64. return WBEM_S_NO_ERROR;
  65. switch(lRes)
  66. {
  67. case ERROR_FILE_NOT_FOUND:
  68. case ERROR_PATH_NOT_FOUND:
  69. return WBEM_E_NOT_FOUND;
  70. case ERROR_OUTOFMEMORY:
  71. return WBEM_E_OUT_OF_MEMORY;
  72. case ERROR_NOT_ENOUGH_QUOTA:
  73. case ERROR_DISK_FULL:
  74. return WBEM_E_OUT_OF_DISK_SPACE;
  75. default:
  76. return WBEM_E_FAILED;
  77. }
  78. }
  79. long __stdcall EnsureDirectory(LPCWSTR wszPath, LPSECURITY_ATTRIBUTES pSA)
  80. {
  81. if(!CreateDirectoryW(wszPath, NULL))
  82. {
  83. long lRes = GetLastError();
  84. if(lRes != ERROR_ALREADY_EXISTS)
  85. return lRes;
  86. else
  87. return ERROR_SUCCESS;
  88. }
  89. else
  90. return ERROR_SUCCESS;
  91. }
  92. long __stdcall EnsureDirectoryRecursiveForFile(LPWSTR wszPath,
  93. LPSECURITY_ATTRIBUTES pSA);
  94. long __stdcall EnsureDirectoryForFile(LPCWSTR wszPath, LPSECURITY_ATTRIBUTES pSA)
  95. {
  96. //
  97. // Make a copy, since we will be messing with it
  98. //
  99. CFileName wszNewPath;
  100. if (wszNewPath == NULL)
  101. return ERROR_OUTOFMEMORY;
  102. wcscpy(wszNewPath, wszPath);
  103. return EnsureDirectoryRecursiveForFile(wszNewPath, pSA);
  104. }
  105. long __stdcall EnsureDirectoryRecursiveForFile(LPWSTR wszPath,
  106. LPSECURITY_ATTRIBUTES pSA)
  107. {
  108. long lRes;
  109. //
  110. // Find the last backslash and remove
  111. //
  112. WCHAR* pwcLastSlash = wcsrchr(wszPath, L'\\');
  113. if(pwcLastSlash == NULL)
  114. return ERROR_BAD_PATHNAME;
  115. *pwcLastSlash = 0;
  116. //
  117. // Try to create it
  118. //
  119. if(!CreateDirectoryW(wszPath, pSA))
  120. {
  121. //
  122. // Call ourselves recursively --- to create our parents
  123. //
  124. lRes = EnsureDirectoryRecursiveForFile(wszPath, pSA);
  125. if(lRes != ERROR_SUCCESS)
  126. {
  127. *pwcLastSlash = L'\\';
  128. return lRes;
  129. }
  130. //
  131. // Try again
  132. //
  133. BOOL bRes = CreateDirectoryW(wszPath, pSA);
  134. *pwcLastSlash = L'\\';
  135. if(bRes)
  136. return ERROR_SUCCESS;
  137. else
  138. return GetLastError();
  139. }
  140. else
  141. {
  142. *pwcLastSlash = L'\\';
  143. return ERROR_SUCCESS;
  144. }
  145. }
  146. inline WCHAR HexDigit(BYTE b)
  147. {
  148. if(b < 10)
  149. return L'0' + b;
  150. else
  151. return L'A' + b - 10;
  152. }
  153. bool A51Hash(LPCWSTR wszName, LPWSTR wszHash)
  154. {
  155. //
  156. // Have to upper-case everything
  157. //
  158. DWORD dwBufferSize = wcslen(wszName)*2+2;
  159. LPWSTR wszBuffer = (WCHAR*)TempAlloc(dwBufferSize);
  160. if (wszBuffer == NULL)
  161. return false;
  162. CTempFreeMe vdm(wszBuffer, dwBufferSize);
  163. wbem_wcsupr(wszBuffer, wszName);
  164. BYTE RawHash[16];
  165. MD5::Transform((void*)wszBuffer, wcslen(wszBuffer)*2, RawHash);
  166. WCHAR* pwc = wszHash;
  167. for(int i = 0; i < 16; i++)
  168. {
  169. *(pwc++) = HexDigit(RawHash[i]/16);
  170. *(pwc++) = HexDigit(RawHash[i]%16);
  171. }
  172. *pwc = 0;
  173. return true;
  174. }
  175. long A51WriteFile(LPCWSTR wszFullPath, DWORD dwLen, BYTE* pBuffer)
  176. {
  177. long lRes;
  178. A51TRACE(( "Create file %S\n", wszFullPath));
  179. //
  180. // Create the right file
  181. //
  182. HANDLE hFile = CreateFileW(wszFullPath, GENERIC_WRITE, 0,
  183. NULL, CREATE_ALWAYS, A51_FILE_CREATION_FLAGS, NULL);
  184. if(hFile == INVALID_HANDLE_VALUE)
  185. {
  186. lRes = GetLastError();
  187. if(lRes == ERROR_PATH_NOT_FOUND)
  188. {
  189. lRes = EnsureDirectoryForFile(wszFullPath, NULL);
  190. if(lRes != ERROR_SUCCESS)
  191. return lRes;
  192. hFile = CreateFileW(wszFullPath, GENERIC_WRITE, 0,
  193. NULL, CREATE_ALWAYS, A51_FILE_CREATION_FLAGS, NULL);
  194. if(hFile == INVALID_HANDLE_VALUE)
  195. {
  196. lRes = GetLastError();
  197. _ASSERT(lRes != ERROR_SUCCESS, L"success error code from fail");
  198. return lRes;
  199. }
  200. }
  201. else
  202. return lRes;
  203. }
  204. CCloseMe cm(hFile);
  205. //
  206. // Write it and close
  207. //
  208. if(!WriteFile(hFile, pBuffer, dwLen, &dwLen, NULL))
  209. {
  210. lRes = GetLastError();
  211. _ASSERT(lRes != ERROR_SUCCESS, L"success error code from fail");
  212. return lRes;
  213. }
  214. return ERROR_SUCCESS;
  215. }
  216. long A51DeleteFile(LPCWSTR wszFullPath)
  217. {
  218. A51TRACE(("Delete file %S\n", wszFullPath));
  219. //
  220. // Delete the right file
  221. //
  222. if(!DeleteFileW(wszFullPath))
  223. return GetLastError();
  224. return ERROR_SUCCESS;
  225. }
  226. long A51WriteToFileAsync(HANDLE hFile, long lStartingOffset, BYTE* pBuffer,
  227. DWORD dwBufferLen, OVERLAPPED* pov)
  228. {
  229. pov->Offset = lStartingOffset;
  230. pov->OffsetHigh = 0;
  231. pov->hEvent = A51GetNewEvent();
  232. BOOL bRes;
  233. DWORD dwWritten;
  234. while(!(bRes = WriteFile(hFile, pBuffer, dwBufferLen, &dwWritten, pov)) &&
  235. (GetLastError() == ERROR_INVALID_USER_BUFFER ||
  236. GetLastError() == ERROR_NOT_ENOUGH_MEMORY))
  237. {
  238. //
  239. // Out of buffer-space --- wait a bit and retry
  240. //
  241. g_nWriteFailures++;
  242. Sleep(16);
  243. }
  244. if(!bRes)
  245. {
  246. long lRes = GetLastError();
  247. if(lRes == ERROR_IO_PENDING)
  248. // perfect!
  249. return ERROR_SUCCESS;
  250. else
  251. {
  252. A51ReturnEvent(pov->hEvent);
  253. pov->hEvent = NULL;
  254. return lRes;
  255. }
  256. }
  257. else
  258. {
  259. //
  260. // Succeeded synchronously --- clean up and return
  261. //
  262. A51ReturnEvent(pov->hEvent);
  263. pov->hEvent = NULL;
  264. if(dwWritten != dwBufferLen)
  265. return ERROR_OUTOFMEMORY;
  266. else
  267. return ERROR_SUCCESS;
  268. }
  269. }
  270. long A51WriteToFileSync(HANDLE hFile, long lStartingOffset, BYTE* pBuffer,
  271. DWORD dwBufferLen)
  272. {
  273. OVERLAPPED ov;
  274. long lRes = A51WriteToFileAsync(hFile, lStartingOffset, pBuffer,
  275. dwBufferLen, &ov);
  276. if(lRes != ERROR_SUCCESS)
  277. return lRes;
  278. if(ov.hEvent)
  279. {
  280. CReturnMe rm(ov.hEvent);
  281. //
  282. // Wait for completion
  283. //
  284. DWORD dwWritten;
  285. if(!GetOverlappedResult(hFile, &ov, &dwWritten, TRUE))
  286. return GetLastError();
  287. if(dwWritten != dwBufferLen)
  288. return ERROR_OUTOFMEMORY;
  289. }
  290. return ERROR_SUCCESS;
  291. }
  292. long A51ReadFromFileAsync(HANDLE hFile, long lStartingOffset, BYTE* pBuffer,
  293. DWORD dwBufferLen, OVERLAPPED* pov)
  294. {
  295. long lRes;
  296. pov->Offset = lStartingOffset;
  297. pov->OffsetHigh = 0;
  298. pov->hEvent = A51GetNewEvent();
  299. BOOL bRes;
  300. DWORD dwRead;
  301. while(!(bRes = ReadFile(hFile, pBuffer, dwBufferLen, &dwRead, pov)) &&
  302. (GetLastError() == ERROR_INVALID_USER_BUFFER ||
  303. GetLastError() == ERROR_NOT_ENOUGH_MEMORY))
  304. {
  305. //
  306. // Out of buffer-space --- wait a bit and retry
  307. //
  308. g_nReadFailures++;
  309. Sleep(16);
  310. }
  311. if(!bRes)
  312. {
  313. if(GetLastError() == ERROR_IO_PENDING)
  314. // perfect!
  315. return ERROR_SUCCESS;
  316. else
  317. {
  318. lRes = GetLastError();
  319. _ASSERT(lRes != ERROR_SUCCESS, L"Success returned on failure");
  320. A51ReturnEvent(pov->hEvent);
  321. pov->hEvent = NULL;
  322. if(lRes == ERROR_HANDLE_EOF)
  323. lRes = ERROR_SUCCESS;
  324. return lRes;
  325. }
  326. }
  327. else
  328. {
  329. //
  330. // Succeeded synchronously --- clean up and return
  331. //
  332. A51ReturnEvent(pov->hEvent);
  333. pov->hEvent = NULL;
  334. return ERROR_SUCCESS;
  335. }
  336. }
  337. long A51ReadFromFileSync(HANDLE hFile, long lStartingOffset, BYTE* pBuffer,
  338. DWORD dwBufferLen)
  339. {
  340. OVERLAPPED ov;
  341. long lRes = A51ReadFromFileAsync(hFile, lStartingOffset, pBuffer,
  342. dwBufferLen, &ov);
  343. if(lRes != ERROR_SUCCESS)
  344. return lRes;
  345. if(ov.hEvent)
  346. {
  347. CReturnMe rm(ov.hEvent);
  348. //
  349. // Wait for completion
  350. //
  351. DWORD dwRead = 0;
  352. if(!GetOverlappedResult(hFile, &ov, &dwRead, TRUE))
  353. {
  354. lRes = GetLastError();
  355. _ASSERT(lRes != ERROR_SUCCESS, L"Success returned on failure");
  356. if(lRes == ERROR_HANDLE_EOF)
  357. lRes = ERROR_SUCCESS;
  358. return lRes;
  359. }
  360. }
  361. return ERROR_SUCCESS;
  362. }
  363. long RemoveDirectoryRecursive(LPCWSTR wszDirectoryPath, bool bAbortOnFiles);
  364. long A51RemoveDirectory(LPCWSTR wszFullPath, bool bAbortOnFiles)
  365. {
  366. long lRes = RemoveDirectoryRecursive(wszFullPath, bAbortOnFiles);
  367. if(lRes == ERROR_PATH_NOT_FOUND || lRes == ERROR_FILE_NOT_FOUND)
  368. return ERROR_FILE_NOT_FOUND;
  369. else
  370. return lRes;
  371. }
  372. long RemoveDirectoryRecursive(LPCWSTR wszDirectoryPath, bool bAbortOnFiles)
  373. {
  374. long lRes;
  375. //
  376. // Try removing it right away
  377. //
  378. if(!RemoveDirectoryW(wszDirectoryPath))
  379. {
  380. long lRes = GetLastError();
  381. if(lRes == ERROR_PATH_NOT_FOUND || lRes == ERROR_FILE_NOT_FOUND)
  382. return ERROR_FILE_NOT_FOUND;
  383. else if(lRes != ERROR_DIR_NOT_EMPTY && lRes != ERROR_SHARING_VIOLATION)
  384. return lRes;
  385. }
  386. else
  387. return ERROR_SUCCESS;
  388. //
  389. // Not empty (or at least we are not sure it is empty) --- enumerate
  390. // everything
  391. //
  392. CFileName wszMap;
  393. if (wszMap == NULL)
  394. return ERROR_OUTOFMEMORY;
  395. wcscpy(wszMap, wszDirectoryPath);
  396. wcscat(wszMap, L"\\*");
  397. CFileName wszChild;
  398. if (wszChild == NULL)
  399. return ERROR_OUTOFMEMORY;
  400. wcscpy(wszChild, wszDirectoryPath);
  401. wcscat(wszChild, L"\\");
  402. long lChildLen = wcslen(wszChild);
  403. WIN32_FIND_DATAW fd;
  404. HANDLE hSearch = FindFirstFileW(wszMap, &fd);
  405. if(hSearch == INVALID_HANDLE_VALUE)
  406. return ERROR_DIR_NOT_EMPTY;
  407. do
  408. {
  409. if(fd.cFileName[0] == L'.')
  410. continue;
  411. if((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  412. {
  413. if(bAbortOnFiles)
  414. {
  415. // There is a file --- give up
  416. FindClose(hSearch);
  417. return ERROR_DIR_NOT_EMPTY;
  418. }
  419. else
  420. {
  421. wcscpy(wszChild + lChildLen, fd.cFileName);
  422. if(!DeleteFileW(wszChild))
  423. {
  424. FindClose(hSearch);
  425. return GetLastError();
  426. }
  427. }
  428. }
  429. else
  430. {
  431. wcscpy(wszChild + lChildLen, fd.cFileName);
  432. lRes = RemoveDirectoryRecursive(wszChild, bAbortOnFiles);
  433. if(lRes != ERROR_SUCCESS && lRes != ERROR_FILE_NOT_FOUND)
  434. {
  435. FindClose(hSearch);
  436. return lRes;
  437. }
  438. }
  439. }
  440. while(FindNextFileW(hSearch, &fd));
  441. FindClose(hSearch);
  442. //
  443. // And try again
  444. //
  445. if(!RemoveDirectoryW(wszDirectoryPath))
  446. {
  447. long lRes = GetLastError();
  448. if(lRes == ERROR_PATH_NOT_FOUND || lRes == ERROR_FILE_NOT_FOUND)
  449. return ERROR_FILE_NOT_FOUND;
  450. else if(lRes == ERROR_SHARING_VIOLATION)
  451. return ERROR_SUCCESS;
  452. else
  453. return lRes;
  454. }
  455. return ERROR_SUCCESS;
  456. }
  457. CRITICAL_SECTION g_csLog;
  458. char* g_szText = NULL;
  459. long g_lTextLen = 0;
  460. WCHAR g_wszLogFilename[MAX_PATH] = L"";
  461. void A51Trace(LPCSTR szFormat, ...)
  462. {
  463. if((g_wszLogFilename[0] == 0) || (g_szText == NULL))
  464. {
  465. InitializeCriticalSection(&g_csLog);
  466. delete g_szText;
  467. g_wszLogFilename[0] = 0;
  468. g_szText = NULL;
  469. HKEY hKey;
  470. long lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  471. L"SOFTWARE\\Microsoft\\WBEM\\CIMOM",
  472. 0, KEY_READ, &hKey);
  473. if(lRes)
  474. {
  475. wcscpy(g_wszLogFilename, L"c:\\a51.log");
  476. }
  477. else
  478. {
  479. DWORD dwLen = MAX_PATH;
  480. CFileName wszTmp;
  481. if (wszTmp == 0)
  482. {
  483. wcscpy(g_wszLogFilename, L"c:\\a51.log");
  484. RegCloseKey(hKey);
  485. }
  486. else
  487. {
  488. lRes = RegQueryValueExW(hKey, L"Logging Directory", NULL, NULL,
  489. (LPBYTE)(wchar_t*)wszTmp, &dwLen);
  490. RegCloseKey(hKey);
  491. if(lRes)
  492. {
  493. wcscpy(g_wszLogFilename, L"c:\\a51.log");
  494. }
  495. else
  496. {
  497. if (ExpandEnvironmentStringsW(wszTmp,g_wszLogFilename,MAX_PATH) == 0)
  498. {
  499. wcscpy(g_wszLogFilename, L"c:\\a51.log");
  500. }
  501. else
  502. {
  503. if (g_wszLogFilename[wcslen(g_wszLogFilename)] == L'\\')
  504. {
  505. wcscat(g_wszLogFilename, L"a51.log");
  506. }
  507. else
  508. {
  509. wcscat(g_wszLogFilename, L"\\a51.log");
  510. }
  511. }
  512. }
  513. }
  514. }
  515. g_szText = new char[3000000];
  516. if (g_szText == NULL)
  517. return;
  518. }
  519. EnterCriticalSection(&g_csLog);
  520. char szBuffer[256];
  521. va_list argptr;
  522. va_start(argptr, szFormat);
  523. vsprintf(szBuffer, szFormat, argptr);
  524. long lLen = strlen(szBuffer);
  525. if(g_lTextLen + lLen > 2900000)
  526. A51TraceFlush();
  527. strcpy(g_szText + g_lTextLen, szBuffer);
  528. g_lTextLen += lLen;
  529. LeaveCriticalSection(&g_csLog);
  530. }
  531. void A51TraceFlush()
  532. {
  533. FILE* fLog = NULL;
  534. fLog = _wfopen(g_wszLogFilename, L"a");
  535. if(fLog)
  536. {
  537. fwrite(g_szText, 1, g_lTextLen, fLog);
  538. g_lTextLen = 0;
  539. // fflush(fLog);
  540. fclose(fLog);
  541. }
  542. }