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.

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