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.

463 lines
11 KiB

  1. #include <wbemcomn.h>
  2. #include "a51tools.h"
  3. #include "objheap.h"
  4. #include "index.h"
  5. #define ROSWELL_OFFSET_FORMAT_STRING L"%d"
  6. #define ROSWELL_HEAPALLOC_TYPE_BUSY 0xA51A51A5
  7. long CObjectHeap::Initialize(CAbstractFileSource * pAbstractSource,
  8. WCHAR * wszObjHeapName,
  9. WCHAR * wszBaseName,
  10. DWORD dwBaseNameLen)
  11. {
  12. CInCritSec ics(&m_cs);
  13. if (m_bInit)
  14. return ERROR_SUCCESS;
  15. long lRes;
  16. lRes = m_Heap.Initialize(pAbstractSource, wszObjHeapName);
  17. if(lRes != ERROR_SUCCESS)
  18. return lRes;
  19. lRes = m_Index.Initialize(dwBaseNameLen, wszBaseName, pAbstractSource);
  20. if(lRes != ERROR_SUCCESS)
  21. return lRes;
  22. m_bInit = TRUE;
  23. return lRes;
  24. }
  25. long CObjectHeap::Uninitialize(DWORD dwShutDownFlags)
  26. {
  27. CInCritSec ics(&m_cs);
  28. if (!m_bInit)
  29. return ERROR_SUCCESS;
  30. m_Index.Shutdown(dwShutDownFlags);
  31. m_Heap.Uninitialize();
  32. m_bInit = FALSE;
  33. return ERROR_SUCCESS;
  34. }
  35. void CObjectHeap::InvalidateCache()
  36. {
  37. m_Index.InvalidateCache();
  38. m_Heap.InvalidateCache();
  39. }
  40. long CObjectHeap::FindClose(HANDLE hFileEnum)
  41. {
  42. return m_Index.FindClose(hFileEnum);
  43. }
  44. long CObjectHeap::FindFirst(LPCWSTR wszPrefix,
  45. WIN32_FIND_DATAW* pfd,
  46. void** ppHandle)
  47. {
  48. return m_Index.FindFirst(wszPrefix,pfd,ppHandle);
  49. }
  50. long CObjectHeap::FindNext(void* pHandle, WIN32_FIND_DATAW* pfd)
  51. {
  52. return m_Index.FindNext(pHandle,pfd);
  53. }
  54. long CObjectHeap::GetIndexFileName(LPCWSTR wszFilePath, LPWSTR wszIndexFileName)
  55. {
  56. WIN32_FIND_DATAW wfd;
  57. HANDLE hSearch = NULL;
  58. long lRes = m_pIndex->FindFirst(wszFilePath, &wfd, NULL);
  59. if(lRes != ERROR_SUCCESS)
  60. {
  61. if(lRes == ERROR_PATH_NOT_FOUND)
  62. lRes = ERROR_FILE_NOT_FOUND;
  63. return lRes;
  64. }
  65. // m_pIndex->FindClose(hSearch);
  66. wcscpy(wszIndexFileName, wfd.cFileName);
  67. return ERROR_SUCCESS;
  68. }
  69. long CObjectHeap::GetFileInfo(LPCWSTR wszFilePath, TOffset* pnOffset,
  70. DWORD* pdwLength)
  71. {
  72. CFileName wszIndexFileName;
  73. if(wszIndexFileName == NULL)
  74. return ERROR_OUTOFMEMORY;
  75. long lRes = GetIndexFileName(wszFilePath, wszIndexFileName);
  76. if(lRes != ERROR_SUCCESS)
  77. return lRes;
  78. return ParseInfoFromIndexFile(wszIndexFileName, pnOffset, pdwLength);
  79. }
  80. long CObjectHeap::ParseInfoFromIndexFile(LPCWSTR wszIndexFileName,
  81. TOffset* pnOffset, DWORD* pdwLength)
  82. {
  83. WCHAR* pDot = wcschr(wszIndexFileName, L'.');
  84. if(pDot == NULL)
  85. return ERROR_INVALID_PARAMETER;
  86. WCHAR* pwc = pDot+1;
  87. *pnOffset = 0;
  88. while(*pwc && *pwc != L'.')
  89. {
  90. *pnOffset = (*pnOffset * 10) + (*pwc - '0');
  91. pwc++;
  92. }
  93. if(*pwc != L'.')
  94. return ERROR_INVALID_PARAMETER;
  95. pwc++;
  96. *pdwLength = 0;
  97. while(*pwc && *pwc != L'.')
  98. {
  99. *pdwLength = (*pdwLength * 10) + (*pwc - '0');
  100. pwc++;
  101. }
  102. return ERROR_SUCCESS;
  103. }
  104. long CObjectHeap::CreateIndexFile(LPCWSTR wszFilePath, TOffset nOffset,
  105. DWORD dwLength)
  106. {
  107. //
  108. // Simply append the numbers to the file path
  109. //
  110. CFileName wszIndexFilePath;
  111. if(wszIndexFilePath == NULL)
  112. return ERROR_OUTOFMEMORY;
  113. swprintf(wszIndexFilePath, L"%s." ROSWELL_OFFSET_FORMAT_STRING L".%d",
  114. wszFilePath, nOffset, dwLength);
  115. return CreateZeroLengthFile(wszIndexFilePath);
  116. }
  117. long CObjectHeap::DeleteIndexFile(LPCWSTR wszFilePath, LPCWSTR wszIndexFileName)
  118. {
  119. //
  120. // Construct the full path to the index file by concatenating the directory
  121. // of the original file with the name
  122. //
  123. CFileName wszIndexFilePath;
  124. if(wszIndexFilePath == NULL)
  125. return ERROR_OUTOFMEMORY;
  126. WCHAR* pwcLastSlash = wcsrchr(wszFilePath, L'\\');
  127. if(pwcLastSlash == NULL)
  128. return ERROR_INVALID_PARAMETER;
  129. int nPrefixLen = (pwcLastSlash - wszFilePath + 1);
  130. memcpy(wszIndexFilePath, wszFilePath, nPrefixLen * sizeof(WCHAR));
  131. wcscpy(wszIndexFilePath + nPrefixLen, wszIndexFileName);
  132. return DeleteZeroLengthFile(wszIndexFilePath);
  133. }
  134. long CObjectHeap::CreateZeroLengthFile(LPCWSTR wszFilePath)
  135. {
  136. // TBD: use staging file, use more efficient API
  137. return m_pIndex->Create(wszFilePath);
  138. }
  139. long CObjectHeap::DeleteZeroLengthFile(LPCWSTR wszFilePath)
  140. {
  141. // TBD: use staging file, use more efficient API
  142. return m_pIndex->Delete(wszFilePath);
  143. }
  144. DWORD CObjectHeap::GetAllocationHeaderLength()
  145. {
  146. return sizeof(DWORD) // length
  147. + sizeof(DWORD); // type
  148. }
  149. long CObjectHeap::WriteAllocation(TOffset nOffset, DWORD dwDataLength,
  150. BYTE* pData)
  151. {
  152. //
  153. // Prepare a buffer with the complete allocation
  154. //
  155. DWORD dwAllocationLength = dwDataLength + GetAllocationHeaderLength();
  156. BYTE* pAllocation = (BYTE*)TempAlloc(dwAllocationLength);
  157. if(pAllocation == NULL)
  158. return ERROR_OUTOFMEMORY;
  159. CTempFreeMe tfm(pAllocation);
  160. memcpy(pAllocation, &dwDataLength, sizeof(DWORD));
  161. DWORD dwType = ROSWELL_HEAPALLOC_TYPE_BUSY;
  162. memcpy(pAllocation + sizeof(DWORD), &dwType, sizeof(DWORD));
  163. memcpy(pAllocation + GetAllocationHeaderLength(), pData, dwDataLength);
  164. return m_pHeap->WriteBytes(nOffset, pAllocation, dwAllocationLength);
  165. }
  166. long CObjectHeap::ReadAllocation(TOffset nOffset, DWORD dwDataLength,
  167. BYTE* pBuffer)
  168. {
  169. //
  170. // Prepare a buffer with the complete allocation
  171. //
  172. DWORD dwAllocationLength = dwDataLength + GetAllocationHeaderLength();
  173. BYTE* pAllocation = (BYTE*)TempAlloc(dwAllocationLength);
  174. if(pAllocation == NULL)
  175. return ERROR_OUTOFMEMORY;
  176. CTempFreeMe tfm(pAllocation);
  177. long lRes = m_pHeap->ReadBytes(nOffset, pAllocation, dwAllocationLength);
  178. if(lRes != ERROR_SUCCESS)
  179. return lRes;
  180. //
  181. // Sanity checks
  182. //
  183. _ASSERT(!memcmp(pAllocation, &dwDataLength, sizeof(DWORD)),
  184. L"Allocation size in conflict with the index size");
  185. DWORD dwType = ROSWELL_HEAPALLOC_TYPE_BUSY;
  186. _ASSERT(!memcmp(pAllocation + sizeof(DWORD), &dwType, sizeof(DWORD)),
  187. L"Allocation type is not BUSY");
  188. memcpy(pBuffer, pAllocation + GetAllocationHeaderLength(), dwDataLength);
  189. return ERROR_SUCCESS;
  190. }
  191. long CObjectHeap::WriteFile(LPCWSTR wszFilePath, DWORD dwBufferLen,
  192. BYTE* pBuffer)
  193. {
  194. CInCritSec ics(&m_cs);
  195. if (!m_bInit)
  196. return -1;
  197. long lRes;
  198. if(dwBufferLen == 0)
  199. {
  200. //
  201. // We do not use the heap for 0-length files, we create them directly
  202. //
  203. return CreateZeroLengthFile(wszFilePath);
  204. }
  205. //
  206. // Now, check if this file already exists
  207. //
  208. CFileName wszIndexFileName;
  209. if(wszIndexFileName == NULL)
  210. return ERROR_OUTOFMEMORY;
  211. lRes = GetIndexFileName(wszFilePath, wszIndexFileName);
  212. if(lRes != ERROR_FILE_NOT_FOUND && lRes != ERROR_SUCCESS)
  213. return lRes;
  214. if(lRes == ERROR_SUCCESS)
  215. {
  216. //
  217. // Already there. Check if we can simply update it
  218. //
  219. TOffset nOffset;
  220. DWORD dwOldLength;
  221. lRes = ParseInfoFromIndexFile(wszIndexFileName, &nOffset, &dwOldLength);
  222. if(lRes != ERROR_SUCCESS)
  223. return lRes;
  224. if(dwOldLength >= dwBufferLen)
  225. {
  226. //
  227. // Enough space in place --- just write the data and update the
  228. // length
  229. //
  230. lRes = WriteAllocation(nOffset, dwBufferLen, pBuffer);
  231. if(lRes != ERROR_SUCCESS)
  232. return lRes;
  233. if(dwOldLength != dwBufferLen)
  234. {
  235. //
  236. // The length has changed --- first of all, mark the rest of
  237. // the block as free
  238. //
  239. lRes = m_pHeap->FreeAllocation(
  240. nOffset + GetAllocationHeaderLength() + dwBufferLen,
  241. dwOldLength - dwBufferLen);
  242. if(lRes != ERROR_SUCCESS)
  243. return lRes;
  244. //
  245. // Now, delete the old index file and create a new one (the
  246. // length has changed
  247. //
  248. lRes = DeleteIndexFile(wszFilePath, wszIndexFileName);
  249. if(lRes != ERROR_SUCCESS)
  250. return lRes;
  251. lRes = CreateIndexFile(wszFilePath, nOffset, dwBufferLen);
  252. if(lRes != ERROR_SUCCESS)
  253. return lRes;
  254. }
  255. return ERROR_SUCCESS;
  256. }
  257. else
  258. {
  259. //
  260. // Doesn't fit. Erase it
  261. //
  262. lRes = m_pHeap->FreeAllocation(nOffset,
  263. GetAllocationHeaderLength() + dwOldLength);
  264. if(lRes != ERROR_SUCCESS)
  265. return lRes;
  266. lRes = DeleteIndexFile(wszFilePath, wszIndexFileName);
  267. if(lRes != ERROR_SUCCESS)
  268. return lRes;
  269. }
  270. }
  271. //
  272. // Either it wasn't there, or we have cleaned it up. Insert it now
  273. //
  274. TOffset nOffset;
  275. lRes = m_pHeap->Allocate(dwBufferLen + GetAllocationHeaderLength(),
  276. &nOffset);
  277. if(lRes != ERROR_SUCCESS)
  278. return lRes;
  279. lRes = WriteAllocation(nOffset, dwBufferLen, pBuffer);
  280. if(lRes != ERROR_SUCCESS)
  281. return lRes;
  282. lRes = CreateIndexFile(wszFilePath, nOffset, dwBufferLen);
  283. if(lRes != ERROR_SUCCESS)
  284. return lRes;
  285. return ERROR_SUCCESS;
  286. }
  287. long CObjectHeap::ReadFile(LPCWSTR wszFilePath, DWORD* pdwLength,
  288. BYTE** ppBuffer)
  289. {
  290. CInCritSec ics(&m_cs);
  291. if (!m_bInit)
  292. return -1;
  293. long lRes;
  294. //
  295. // TBD: deal with filepath being the path to the index file instead of the
  296. // theoretical file path --- this can happen if people FindFirstFile it
  297. //
  298. //
  299. // Find the file
  300. //
  301. TOffset nOffset;
  302. lRes = GetFileInfo(wszFilePath, &nOffset, pdwLength);
  303. if(lRes != ERROR_SUCCESS)
  304. return lRes;
  305. //
  306. // Read the allocation
  307. //
  308. *ppBuffer = (BYTE*)TempAlloc(*pdwLength);
  309. if(*ppBuffer == NULL)
  310. return ERROR_OUTOFMEMORY;
  311. lRes = ReadAllocation(nOffset, *pdwLength, *ppBuffer);
  312. if(lRes != ERROR_SUCCESS)
  313. {
  314. TempFree(*ppBuffer);
  315. return lRes;
  316. }
  317. return ERROR_SUCCESS;
  318. }
  319. long CObjectHeap::DeleteFile(LPCWSTR wszFilePath)
  320. {
  321. CInCritSec ics(&m_cs);
  322. if (!m_bInit)
  323. return -1;
  324. //
  325. // Find the index file
  326. //
  327. CFileName wszIndexFileName;
  328. if(wszIndexFileName == NULL)
  329. return ERROR_OUTOFMEMORY;
  330. long lRes = GetIndexFileName(wszFilePath, wszIndexFileName);
  331. if(lRes != ERROR_SUCCESS)
  332. return lRes;
  333. //
  334. // Delete the allocation
  335. //
  336. TOffset nOffset;
  337. DWORD dwLength;
  338. lRes = ParseInfoFromIndexFile(wszIndexFileName, &nOffset, &dwLength);
  339. if(lRes == ERROR_INVALID_PARAMETER)
  340. {
  341. //
  342. // Not an index file --- must be a zero-length one
  343. //
  344. return DeleteZeroLengthFile(wszFilePath);
  345. }
  346. lRes = m_pHeap->FreeAllocation(nOffset,
  347. dwLength + GetAllocationHeaderLength());
  348. if(lRes != ERROR_SUCCESS)
  349. return lRes;
  350. //
  351. // Delete the index itself
  352. //
  353. lRes = DeleteIndexFile(wszFilePath, wszIndexFileName);
  354. if(lRes != ERROR_SUCCESS)
  355. return lRes;
  356. return ERROR_SUCCESS;
  357. }