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.

649 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 (lRes == ERROR_SUCCESS)
  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. case ERROR_NOT_ENOUGH_MEMORY:
  72. return WBEM_E_OUT_OF_MEMORY;
  73. case ERROR_NOT_ENOUGH_QUOTA:
  74. case ERROR_DISK_FULL:
  75. return WBEM_E_OUT_OF_DISK_SPACE;
  76. case ERROR_SERVER_SHUTDOWN_IN_PROGRESS:
  77. return WBEM_E_SHUTTING_DOWN;
  78. default:
  79. return WBEM_E_FAILED;
  80. }
  81. }
  82. long __stdcall EnsureDirectory(LPCWSTR wszPath, LPSECURITY_ATTRIBUTES pSA)
  83. {
  84. if(!CreateDirectoryW(wszPath, NULL))
  85. {
  86. long lRes = GetLastError();
  87. if(lRes != ERROR_ALREADY_EXISTS)
  88. return lRes;
  89. else
  90. return ERROR_SUCCESS;
  91. }
  92. else
  93. return ERROR_SUCCESS;
  94. }
  95. long __stdcall EnsureDirectoryRecursiveForFile(LPWSTR wszPath,
  96. LPSECURITY_ATTRIBUTES pSA);
  97. long __stdcall EnsureDirectoryForFile(LPCWSTR wszPath, LPSECURITY_ATTRIBUTES pSA)
  98. {
  99. //
  100. // Make a copy, since we will be messing with it
  101. //
  102. CFileName wszNewPath;
  103. if (wszNewPath == NULL)
  104. return ERROR_OUTOFMEMORY;
  105. wcscpy(wszNewPath, wszPath);
  106. return EnsureDirectoryRecursiveForFile(wszNewPath, pSA);
  107. }
  108. long __stdcall EnsureDirectoryRecursiveForFile(LPWSTR wszPath,
  109. LPSECURITY_ATTRIBUTES pSA)
  110. {
  111. long lRes;
  112. //
  113. // Find the last backslash and remove
  114. //
  115. WCHAR* pwcLastSlash = wcsrchr(wszPath, L'\\');
  116. if(pwcLastSlash == NULL)
  117. return ERROR_BAD_PATHNAME;
  118. *pwcLastSlash = 0;
  119. //
  120. // Try to create it
  121. //
  122. if(!CreateDirectoryW(wszPath, pSA))
  123. {
  124. //
  125. // Call ourselves recursively --- to create our parents
  126. //
  127. lRes = EnsureDirectoryRecursiveForFile(wszPath, pSA);
  128. if(lRes != ERROR_SUCCESS)
  129. {
  130. *pwcLastSlash = L'\\';
  131. return lRes;
  132. }
  133. //
  134. // Try again
  135. //
  136. BOOL bRes = CreateDirectoryW(wszPath, pSA);
  137. *pwcLastSlash = L'\\';
  138. if(bRes)
  139. return ERROR_SUCCESS;
  140. else
  141. return GetLastError();
  142. }
  143. else
  144. {
  145. *pwcLastSlash = L'\\';
  146. return ERROR_SUCCESS;
  147. }
  148. }
  149. static WCHAR g_HexDigit[] =
  150. { L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', L'8', L'9',
  151. L'A', L'B', L'C', L'D', L'E', L'F'
  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++) = g_HexDigit[RawHash[i]/16];
  170. *(pwc++) = g_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. 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. 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. }