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.

1049 lines
26 KiB

  1. /*++
  2. Copyright (C) 2000-2001 Microsoft Corporation
  3. --*/
  4. #include <wbemcomn.h>
  5. #include <reposit.h>
  6. #include <sync.h>
  7. #include <malloc.h>
  8. #include "longstg.h"
  9. #define A51_INSTRUCTION_TYPE_WRITEFILE 1
  10. #define A51_INSTRUCTION_TYPE_SETENDOFFILE 2
  11. CTempMemoryManager g_LongFileCacheManager;
  12. __int64 CWriteFileInstruction::mstatic_lNextZOrder = 0;
  13. DWORD g_dwFailureCount = 0;
  14. DWORD g_dwFailureFrequency = 0;
  15. DWORD g_dwLastFailureCheck = 0;
  16. #define FAILURE_INJECTION_CHECK_INTERVAL 10000
  17. CLongFileInstruction::CLongFileInstruction(CLongFileStagingFile* pFile)
  18. : CStageInstruction(pFile)
  19. {
  20. }
  21. CLongFileInstruction::CLongFileInstruction(CLongFileStagingFile* pFile,
  22. int nFileId, TFileOffset lStartOffset)
  23. : CStageInstruction(pFile), m_Location(nFileId, lStartOffset)
  24. {
  25. }
  26. DWORD CLongFileInstruction::ComputeSpaceForLocation()
  27. {
  28. return (sizeof(BYTE) + sizeof(m_Location.m_lStartOffset));
  29. }
  30. long CLongFileInstruction::RecoverLocation(HANDLE hFile)
  31. {
  32. DWORD dwRead;
  33. BYTE nFileId;
  34. if(!ReadFile(hFile, &nFileId, sizeof(BYTE), &dwRead, NULL))
  35. return GetLastError();
  36. m_Location.m_nFileId = nFileId;
  37. if(!ReadFile(hFile, (BYTE*)&m_Location.m_lStartOffset,
  38. sizeof m_Location.m_lStartOffset, &dwRead, NULL))
  39. {
  40. return GetLastError();
  41. }
  42. return ERROR_SUCCESS;
  43. }
  44. BYTE* CLongFileInstruction::WriteLocation(BYTE* pBuffer)
  45. {
  46. *pBuffer = (BYTE)m_Location.m_nFileId;
  47. memcpy(pBuffer + 1, (BYTE*)&m_Location.m_lStartOffset,
  48. sizeof m_Location.m_lStartOffset);
  49. return pBuffer + 1 + sizeof m_Location.m_lStartOffset;
  50. }
  51. void CLongFileInstruction::Dump()
  52. {
  53. ERRORTRACE((LOG_WBEMCORE, "File %d, Start %d, stage offset %d\n",
  54. (int)m_Location.m_nFileId, (int)m_Location.m_lStartOffset,
  55. (int)m_lStageOffset));
  56. }
  57. void CWriteFileInstruction::Dump()
  58. {
  59. ERRORTRACE((LOG_WBEMCORE, "File %d, Start %d, Len %d, stage offset %d\n",
  60. (int)m_Location.m_nFileId, (int)m_Location.m_lStartOffset,
  61. (int)m_dwLen, (int)m_lStageOffset));
  62. }
  63. void CWriteFileInstruction::MakeTopmost()
  64. {
  65. m_lZOrder = mstatic_lNextZOrder++;
  66. }
  67. DWORD CWriteFileInstruction::ComputeNeededSpace()
  68. {
  69. if (!m_bReuse)
  70. return sizeof(BYTE) + // for the type
  71. ComputeSpaceForLocation() +
  72. sizeof(DWORD) + // for the length of data
  73. m_dwLen + // for the data
  74. A51_TAIL_SIZE; // for the trailer
  75. else
  76. return sizeof(BYTE) + // for the type
  77. ComputeSpaceForLocation() +
  78. sizeof(DWORD) + // for the length of data
  79. m_dwLen; // for the data
  80. //NO TAIL if we are re-using the old write instruction as they are overwritten
  81. //by next instruction in log
  82. }
  83. TFileOffset CWriteFileInstruction::ComputeOriginalOffset()
  84. {
  85. return m_lStageOffset - sizeof(BYTE) - ComputeSpaceForLocation() -
  86. sizeof(DWORD);
  87. }
  88. long CWriteFileInstruction::Write(TFileOffset lOffset, BYTE* pBuffer)
  89. {
  90. _ASSERT(m_Location.m_lStartOffset >= 0 && m_Location.m_lStartOffset < 0x70000000, L"");
  91. //
  92. // Construct an in-memory buffer large enough for the whole thing
  93. //
  94. DWORD dwNeededSpace = ComputeNeededSpace();
  95. BYTE* pWholeBuffer = (BYTE*)TempAlloc(dwNeededSpace);
  96. if(pWholeBuffer == NULL)
  97. return ERROR_OUTOFMEMORY;
  98. CTempFreeMe vdm(pWholeBuffer, dwNeededSpace);
  99. BYTE* pCurrent = pWholeBuffer;
  100. //
  101. // Write instruction type
  102. //
  103. *pCurrent = A51_INSTRUCTION_TYPE_WRITEFILE;
  104. pCurrent++;
  105. //
  106. // Write location
  107. //
  108. pCurrent = WriteLocation(pCurrent);
  109. //
  110. // Write the length of the data for the file
  111. //
  112. memcpy(pCurrent, (void*)&m_dwLen, sizeof(DWORD));
  113. pCurrent += sizeof(DWORD);
  114. //
  115. // Write the data itself and record its offset
  116. //
  117. memcpy(pCurrent, pBuffer, m_dwLen);
  118. m_lStageOffset = lOffset + (pCurrent - pWholeBuffer);
  119. //
  120. // Write the trailer - only if this is an original instruction. In the
  121. // case of a reused instruction we ignore the tail because it had already
  122. // (probably) been overwritten
  123. //
  124. if (!m_bReuse)
  125. memset(pCurrent + m_dwLen, 0, sizeof(DWORD));
  126. //
  127. // Write it
  128. //
  129. return m_pManager->WriteInstruction(lOffset, pWholeBuffer, dwNeededSpace, m_bReuse);
  130. }
  131. long CWriteFileInstruction::RecoverData(HANDLE hFile)
  132. {
  133. //
  134. // Recover the file name first
  135. //
  136. long lRes = RecoverLocation(hFile);
  137. if(lRes != ERROR_SUCCESS)
  138. return lRes;
  139. //
  140. // Read the length of the data from the file
  141. //
  142. DWORD dwRead;
  143. if(!ReadFile(hFile, (BYTE*)&m_dwLen, sizeof(DWORD), &dwRead, NULL))
  144. return GetLastError();
  145. if(dwRead != sizeof(DWORD))
  146. return ERROR_HANDLE_EOF;
  147. //
  148. // We do not need to actually read the data from the file --- we keep it
  149. // there until it is time to flush. But we do need to skip it. At the same
  150. // time, we need to record the position in the file where this data resides
  151. //
  152. LARGE_INTEGER liFileLen;
  153. liFileLen.QuadPart = m_dwLen;
  154. LARGE_INTEGER liNewPosition;
  155. if(!SetFilePointerEx(hFile, liFileLen, &liNewPosition, FILE_CURRENT))
  156. return GetLastError();
  157. _ASSERT(liNewPosition.HighPart == 0, L"Staging file too long!");
  158. m_lStageOffset = (long)(liNewPosition.QuadPart - m_dwLen);
  159. return ERROR_SUCCESS;
  160. }
  161. void CWriteFileInstruction::GetEnd(CFileLocation* pLocation)
  162. {
  163. pLocation->m_nFileId = m_Location.m_nFileId;
  164. pLocation->m_lStartOffset = m_Location.m_lStartOffset + m_dwLen - 1;
  165. }
  166. long CWriteFileInstruction::GetData(HANDLE hFile, long lExtraOffset,
  167. DWORD dwLen, BYTE* pBuffer)
  168. {
  169. //
  170. // Lock the file
  171. //
  172. CInCritSec ics(m_pManager->GetLock());
  173. _ASSERT(m_pManager->GetFirstFreeOffset() >= m_lStageOffset,
  174. L"Instruction points to empty space in stage file");
  175. long lRes = A51ReadFromFileSync(hFile, m_lStageOffset + lExtraOffset,
  176. pBuffer, dwLen);
  177. if(lRes != ERROR_SUCCESS)
  178. {
  179. return lRes;
  180. }
  181. return ERROR_SUCCESS;
  182. }
  183. long CWriteFileInstruction::Execute()
  184. {
  185. long lRes;
  186. //
  187. // Read the data from the staging file
  188. //
  189. BYTE* pBuffer = (BYTE*)TempAlloc(m_dwLen);
  190. if(pBuffer == NULL)
  191. return ERROR_OUTOFMEMORY;
  192. CTempFreeMe tfm(pBuffer);
  193. lRes = GetData(m_pManager->GetHandle(), 0, m_dwLen, pBuffer);
  194. if(lRes != ERROR_SUCCESS)
  195. return lRes;
  196. lRes = ((CLongFileStagingFile*)m_pManager)->WriteToActualFile(
  197. m_Location.m_nFileId, m_Location.m_lStartOffset,
  198. pBuffer, m_dwLen);
  199. if(lRes != ERROR_SUCCESS)
  200. {
  201. return lRes;
  202. }
  203. return ERROR_SUCCESS;
  204. }
  205. DWORD CSetEndOfFileInstruction::ComputeNeededSpace()
  206. {
  207. return sizeof(BYTE) + // for instruction type
  208. ComputeSpaceForLocation() +
  209. A51_TAIL_SIZE; // for the trailer
  210. }
  211. long CSetEndOfFileInstruction::Write(TFileOffset lOffset)
  212. {
  213. //
  214. // Construct an in-memory buffer large enough for the whole thing
  215. //
  216. DWORD dwNeededSpace = ComputeNeededSpace();
  217. BYTE* pWholeBuffer = (BYTE*)TempAlloc(dwNeededSpace);
  218. if(pWholeBuffer == NULL)
  219. return ERROR_OUTOFMEMORY;
  220. CTempFreeMe vdm(pWholeBuffer, dwNeededSpace);
  221. BYTE* pCurrent = pWholeBuffer;
  222. //
  223. // Write the instruction type
  224. //
  225. *pCurrent = A51_INSTRUCTION_TYPE_SETENDOFFILE;
  226. pCurrent++;
  227. //
  228. // Write the file name
  229. //
  230. pCurrent = WriteLocation(pCurrent);
  231. m_lStageOffset = lOffset + (pCurrent - pWholeBuffer);
  232. //
  233. // Write the trailer
  234. //
  235. memset(pCurrent, 0, sizeof(DWORD));
  236. //
  237. // Write it
  238. //
  239. return m_pManager->WriteInstruction(lOffset, pWholeBuffer, dwNeededSpace);
  240. }
  241. long CSetEndOfFileInstruction::RecoverData(HANDLE hFile)
  242. {
  243. long lRes = RecoverLocation(hFile);
  244. if(lRes != ERROR_SUCCESS)
  245. return lRes;
  246. LARGE_INTEGER liZero;
  247. liZero.QuadPart = 0;
  248. LARGE_INTEGER liPosition;
  249. if(!SetFilePointerEx(hFile, liZero, &liPosition, FILE_CURRENT))
  250. return GetLastError();
  251. _ASSERT(liPosition.HighPart == 0, L"Staging file too long!");
  252. m_lStageOffset = (long)(liPosition.QuadPart);
  253. return ERROR_SUCCESS;
  254. }
  255. long CSetEndOfFileInstruction::Execute()
  256. {
  257. long lRes = ((CLongFileStagingFile*)m_pManager)->SetEndOfActualFile(
  258. m_Location.m_nFileId, m_Location.m_lStartOffset);
  259. return lRes;
  260. }
  261. //
  262. // CStageManager
  263. //
  264. // |
  265. //
  266. // CExecutableStageManager
  267. //
  268. // |
  269. //
  270. // CLongFileStagingFile
  271. //
  272. /////////////////////////////////////////////////////////////////////////////
  273. CLongFileStagingFile::CLongFileStagingFile(long lMaxFileSize,
  274. long lAbortTransactionFileSize)
  275. : CExecutableStageManager(lMaxFileSize, lAbortTransactionFileSize),
  276. m_mapStarts(TMap::key_compare(),
  277. TMap::allocator_type(&g_LongFileCacheManager)),
  278. m_mapEnds(TMap::key_compare(),
  279. TMap::allocator_type(&g_LongFileCacheManager))
  280. {
  281. for(int i = 0; i < A51_MAX_FILES; i++)
  282. m_aFiles[i].m_h = NULL;
  283. }
  284. CLongFileStagingFile::~CLongFileStagingFile()
  285. {
  286. }
  287. long CLongFileStagingFile::Create(LPCWSTR wszStagingFileName)
  288. {
  289. return CExecutableStageManager::Create(wszStagingFileName);
  290. };
  291. long CLongFileStagingFile::Initialize()
  292. {
  293. CInCritSec ics(&m_cs);
  294. return CExecutableStageManager::Start();
  295. };
  296. long CLongFileStagingFile::Uninitialize(DWORD dwShutDownFlags)
  297. {
  298. // do not hold the CritSec here, since the FlusherThread needs it
  299. CExecutableStageManager::Stop(dwShutDownFlags);
  300. CInCritSec ics(&m_cs);
  301. CloseAllFiles();
  302. m_mapStarts.clear();
  303. m_mapEnds.clear();
  304. return ERROR_SUCCESS;
  305. };
  306. long CLongFileStagingFile::RemoveInstructionFromMap(
  307. CStageInstruction* pRawInst)
  308. {
  309. CInCritSec ics(&m_cs);
  310. CLongFileInstruction* pInst = (CLongFileInstruction*)pRawInst;
  311. if(!pInst->IsWrite())
  312. return ERROR_SUCCESS;
  313. /*
  314. ERRORTRACE((LOG_WBEMCORE, "Remove instruction\n"));
  315. pInst->Dump();
  316. */
  317. TIterator it = m_mapStarts.find(pInst->m_Location);
  318. while(it != m_mapStarts.end() && it->second != pInst)
  319. it++;
  320. if(it == m_mapStarts.end())
  321. {
  322. return ERROR_FILE_NOT_FOUND;
  323. }
  324. it->second->Release();
  325. m_mapStarts.erase(it);
  326. CFileLocation Location;
  327. ((CWriteFileInstruction*)pInst)->GetEnd(&Location);
  328. it = m_mapEnds.find(Location);
  329. while(it != m_mapEnds.end() && it->second != pInst)
  330. it++;
  331. if(it == m_mapEnds.end())
  332. {
  333. return ERROR_FILE_NOT_FOUND;
  334. }
  335. it->second->Release();
  336. m_mapEnds.erase(it);
  337. return ERROR_SUCCESS;
  338. }
  339. void CLongFileStagingFile::FlushDataFiles()
  340. {
  341. CInCritSec ics(&m_cs);
  342. for(int i = 0; i < A51_MAX_FILES; i++)
  343. {
  344. HANDLE h = m_aFiles[i].m_h;
  345. if(h)
  346. {
  347. FlushFileBuffers(h);
  348. }
  349. }
  350. }
  351. long CLongFileStagingFile::WriteFile(int nFileId, DWORD dwStartOffset,
  352. BYTE* pBuffer, DWORD dwLen, DWORD* pdwWritten)
  353. {
  354. CInCritSec ics(&m_cs);
  355. long lRes;
  356. #ifdef DBG
  357. if(InjectFailure())
  358. {
  359. ERRORTRACE((LOG_WBEMCORE, "FAIL: File %d, offset %d, len %d\n",
  360. (int)nFileId, (int)dwStartOffset, (int)dwLen));
  361. return ERROR_SECTOR_NOT_FOUND;
  362. }
  363. #endif
  364. if(pdwWritten)
  365. *pdwWritten = dwLen;
  366. if(DoesSupportOverwrites(nFileId))
  367. {
  368. //
  369. // For this file, it is considered efficient to look for another
  370. // instruction within the same transaction. It is guaranteed that
  371. // writes within this file never intersect!
  372. //
  373. CFileLocation StartLocation;
  374. StartLocation.m_nFileId = nFileId;
  375. StartLocation.m_lStartOffset = (TFileOffset)dwStartOffset;
  376. CWriteFileInstruction* pLatestMatch = NULL;
  377. TIterator itStart = m_mapStarts.lower_bound(StartLocation);
  378. while(itStart != m_mapStarts.end()
  379. && itStart->first.m_nFileId == nFileId
  380. && itStart->first.m_lStartOffset == (TFileOffset)dwStartOffset)
  381. {
  382. CWriteFileInstruction* pInst = itStart->second;
  383. if(pInst->m_dwLen == dwLen && !pInst->IsCommitted())
  384. {
  385. //
  386. // Exact match. Compare to the other matches
  387. //
  388. if(pLatestMatch == NULL ||
  389. pInst->m_lZOrder > pLatestMatch->m_lZOrder)
  390. {
  391. pLatestMatch = pInst;
  392. }
  393. }
  394. itStart++;
  395. }
  396. if(pLatestMatch)
  397. {
  398. //
  399. // Exact match. All we need to do is overwrite the original
  400. // instruction. Of course, we also need to afjust the hash!!
  401. //
  402. pLatestMatch->SetReuseFlag();
  403. lRes = pLatestMatch->Write(pLatestMatch->ComputeOriginalOffset(),
  404. pBuffer);
  405. if(lRes)
  406. return lRes;
  407. /*
  408. ERRORTRACE((LOG_WBEMCORE, "Replaced instruction:\n"));
  409. pLatestMatch->Dump();
  410. */
  411. //
  412. // No need to make sure this instruction comes up in the Z-order!
  413. // After all, it's already topmost by selection criteria!
  414. //
  415. return ERROR_SUCCESS;
  416. }
  417. }
  418. //
  419. // No match --- add a new instruction
  420. //
  421. CWriteFileInstruction* pInst =
  422. new CWriteFileInstruction(this, nFileId, dwStartOffset, dwLen);
  423. if(pInst == NULL)
  424. return ERROR_OUTOFMEMORY;
  425. pInst->AddRef();
  426. CTemplateReleaseMe<CLongFileInstruction> rm1(pInst);
  427. DWORD dwSpaceNeeded = pInst->ComputeNeededSpace();
  428. if(!CanWriteInTransaction(dwSpaceNeeded))
  429. return ERROR_NOT_ENOUGH_QUOTA;
  430. {
  431. CInCritSec ics(&m_cs);
  432. //
  433. // Write all the data into the staging area
  434. //
  435. lRes = pInst->Write(m_lFirstFreeOffset, pBuffer);
  436. if(lRes)
  437. return lRes;
  438. m_lFirstFreeOffset += dwSpaceNeeded - A51_TAIL_SIZE;
  439. lRes = AddInstruction(pInst);
  440. }
  441. return lRes;
  442. }
  443. long CLongFileStagingFile::SetFileLength(int nFileId, DWORD dwLen)
  444. {
  445. CInCritSec ics(&m_cs);
  446. long lRes;
  447. CSetEndOfFileInstruction* pInst =
  448. new CSetEndOfFileInstruction(this, nFileId, dwLen);
  449. if(pInst == NULL)
  450. return ERROR_OUTOFMEMORY;
  451. pInst->AddRef();
  452. CTemplateReleaseMe<CSetEndOfFileInstruction> rm1(pInst);
  453. DWORD dwSpaceNeeded = pInst->ComputeNeededSpace();
  454. if(!CanWriteInTransaction(dwSpaceNeeded))
  455. return ERROR_NOT_ENOUGH_QUOTA;
  456. {
  457. CInCritSec ics(&m_cs);
  458. //
  459. // Write all the data into the staging area
  460. //
  461. lRes = pInst->Write(m_lFirstFreeOffset);
  462. if(lRes)
  463. return lRes;
  464. //
  465. // Write the new offset into the offset file
  466. //
  467. m_lFirstFreeOffset += dwSpaceNeeded - A51_TAIL_SIZE;
  468. lRes = AddInstruction(pInst);
  469. }
  470. return lRes;
  471. }
  472. long CLongFileStagingFile::AddInstructionToMap(CStageInstruction* pRawInst,
  473. CStageInstruction** ppUndoInst)
  474. {
  475. CInCritSec ics(&m_cs);
  476. if(ppUndoInst)
  477. *ppUndoInst = NULL;
  478. CLongFileInstruction* pLongInst = (CLongFileInstruction*)pRawInst;
  479. if(!pLongInst->IsWrite())
  480. return ERROR_SUCCESS;
  481. CWriteFileInstruction* pInst = (CWriteFileInstruction*)pLongInst;
  482. /*
  483. ERRORTRACE((LOG_WBEMCORE, "Add instruction\n"));
  484. pInst->Dump();
  485. */
  486. pInst->AddRef();
  487. TIterator itStart;
  488. try
  489. {
  490. itStart = m_mapStarts.insert(TValue(pInst->m_Location, pInst));
  491. }
  492. catch(...)
  493. {
  494. //
  495. // Put everything back as well as we can
  496. //
  497. pInst->Release();
  498. return ERROR_OUTOFMEMORY;
  499. }
  500. pInst->AddRef();
  501. try
  502. {
  503. CFileLocation Location;
  504. pInst->GetEnd(&Location);
  505. m_mapEnds.insert(TValue(Location, pInst));
  506. }
  507. catch(...)
  508. {
  509. //
  510. // Put everything back as well as we can
  511. //
  512. pInst->Release();
  513. m_mapStarts.erase(itStart);
  514. pInst->Release();
  515. }
  516. return ERROR_SUCCESS;
  517. }
  518. bool CLongFileStagingFile::IsStillCurrent(CStageInstruction* pRawInst)
  519. {
  520. CInCritSec ics(&m_cs);
  521. CLongFileInstruction* pInst = (CLongFileInstruction*)pRawInst;
  522. if(!pInst->IsWrite())
  523. return true;
  524. _ASSERT(m_mapStarts.find(pInst->m_Location) != m_mapStarts.end(),
  525. L"Why would we be asking about an instruction that is "
  526. "not even there?");
  527. return true;
  528. }
  529. long CLongFileStagingFile::ReadFile(int nFileId, DWORD dwStartOffset,
  530. BYTE* pBuffer, DWORD dwLen, DWORD* pdwRead)
  531. {
  532. if(pdwRead)
  533. *pdwRead = dwLen;
  534. long lRes;
  535. CInCritSec ics(&m_cs);
  536. //
  537. // Search for the file
  538. //
  539. CFileLocation StartLocation;
  540. StartLocation.m_nFileId = nFileId;
  541. StartLocation.m_lStartOffset = (TFileOffset)dwStartOffset;
  542. bool bComplete = false;
  543. CRefedPointerArray<CWriteFileInstruction> apRelevant;
  544. TIterator itStart = m_mapStarts.lower_bound(StartLocation);
  545. while(itStart != m_mapStarts.end()
  546. && itStart->first.m_nFileId == nFileId
  547. && itStart->first.m_lStartOffset <
  548. (TFileOffset)dwStartOffset + dwLen)
  549. {
  550. CWriteFileInstruction* pInst = itStart->second;
  551. if(pInst->m_Location.m_lStartOffset == dwStartOffset &&
  552. pInst->m_dwLen >= dwLen)
  553. {
  554. bComplete = true;
  555. }
  556. apRelevant.Add(pInst);
  557. itStart++;
  558. }
  559. TIterator itEnd = m_mapEnds.lower_bound(StartLocation);
  560. while(itEnd != m_mapEnds.end()
  561. && itEnd->first.m_nFileId == nFileId
  562. && itEnd->second->m_Location.m_lStartOffset <
  563. (TFileOffset)dwStartOffset)
  564. {
  565. CWriteFileInstruction* pInst = itEnd->second;
  566. if(itEnd->first.m_lStartOffset >=
  567. (TFileOffset)dwStartOffset + dwLen - 1)
  568. {
  569. //
  570. // Completely covers us!
  571. //
  572. bComplete = true;
  573. }
  574. apRelevant.Add(pInst);
  575. itEnd++;
  576. }
  577. if(!bComplete)
  578. {
  579. //
  580. // Read from the real file
  581. //
  582. lRes = A51ReadFromFileSync(m_aFiles[nFileId].m_h, dwStartOffset,
  583. pBuffer, dwLen);
  584. if(lRes != ERROR_SUCCESS)
  585. {
  586. return lRes;
  587. }
  588. }
  589. //
  590. // Now, sort all the instructions by z-order
  591. //
  592. int i = 0;
  593. while(i < apRelevant.GetSize() - 1)
  594. {
  595. CWriteFileInstruction* pInst1 = apRelevant[i];
  596. CWriteFileInstruction* pInst2 = apRelevant[i+1];
  597. if(pInst1->m_lZOrder > pInst2->m_lZOrder)
  598. {
  599. apRelevant.Swap(i, i+1);
  600. if(i > 0)
  601. i--;
  602. }
  603. else
  604. {
  605. i++;
  606. }
  607. }
  608. //
  609. // Apply them in this order
  610. //
  611. /*
  612. if(apRelevant.GetSize() > 0)
  613. {
  614. ERRORTRACE((LOG_WBEMCORE, "Using instructions to read %d bytes "
  615. "from file %d starting at %d:\n",
  616. (int)dwStartOffset, (int)nFileId, (int)dwLen));
  617. }
  618. */
  619. for(i = 0; i < apRelevant.GetSize(); i++)
  620. {
  621. CWriteFileInstruction* pInstruction = apRelevant[i];
  622. // pInstruction->Dump();
  623. long lIntersectionStart = max(pInstruction->m_Location.m_lStartOffset,
  624. dwStartOffset);
  625. long lIntersectionEnd =
  626. min(pInstruction->m_Location.m_lStartOffset + pInstruction->m_dwLen,
  627. dwStartOffset + dwLen);
  628. DWORD dwReadLen = (DWORD)(lIntersectionEnd - lIntersectionStart);
  629. long lInstructionReadOffset =
  630. lIntersectionStart - pInstruction->m_Location.m_lStartOffset;
  631. long lDestinationBufferOffset = lIntersectionStart - dwStartOffset;
  632. long lRes = pInstruction->GetData(m_hFile, lInstructionReadOffset,
  633. dwReadLen, pBuffer + lDestinationBufferOffset);
  634. if(lRes != ERROR_SUCCESS)
  635. {
  636. return lRes;
  637. }
  638. }
  639. return ERROR_SUCCESS;
  640. }
  641. long CLongFileStagingFile::GetFileLength(int nFileId, DWORD* pdwLength)
  642. {
  643. _ASSERT(pdwLength, L"Invalid parameter");
  644. *pdwLength = 0;
  645. long lRes;
  646. CInCritSec ics(&m_cs);
  647. //
  648. // Find the instruction that ends as far as we can see --- that would be
  649. // the last one in the map of Ends
  650. //
  651. CFileLocation Location;
  652. Location.m_nFileId = nFileId+1;
  653. Location.m_lStartOffset = 0;
  654. TIterator itEnd = m_mapEnds.lower_bound(Location);
  655. if(itEnd != m_mapEnds.begin())
  656. {
  657. itEnd--;
  658. if(itEnd->first.m_nFileId == nFileId)
  659. {
  660. *pdwLength = itEnd->first.m_lStartOffset+1;
  661. }
  662. }
  663. //
  664. // Now, check out the length of the actual file
  665. //
  666. BY_HANDLE_FILE_INFORMATION fi;
  667. if(!GetFileInformationByHandle(m_aFiles[nFileId].m_h, &fi))
  668. {
  669. long lRes = GetLastError();
  670. _ASSERT(lRes != ERROR_SUCCESS, L"Success from failure");
  671. return lRes;
  672. }
  673. _ASSERT(fi.nFileSizeHigh == 0, L"Free file too long");
  674. if(fi.nFileSizeLow > *pdwLength)
  675. *pdwLength = fi.nFileSizeLow;
  676. return ERROR_SUCCESS;
  677. }
  678. long CLongFileStagingFile::ConstructInstructionFromType(int nType,
  679. CStageInstruction** ppInst)
  680. {
  681. CLongFileInstruction* pInst = NULL;
  682. switch(nType)
  683. {
  684. case A51_INSTRUCTION_TYPE_WRITEFILE:
  685. pInst = new CWriteFileInstruction(this);
  686. break;
  687. case A51_INSTRUCTION_TYPE_SETENDOFFILE:
  688. pInst = new CSetEndOfFileInstruction(this);
  689. break;
  690. default:
  691. return ERROR_RXACT_INVALID_STATE;
  692. }
  693. if(pInst == NULL)
  694. return WBEM_E_OUT_OF_MEMORY;
  695. pInst->AddRef();
  696. *ppInst = pInst;
  697. return ERROR_SUCCESS;
  698. }
  699. long CLongFileStagingFile::WriteToActualFile(int nFileId,
  700. TFileOffset lFileOffset, BYTE* pBuffer, DWORD dwLen)
  701. {
  702. CInCritSec ics(&m_cs);
  703. long lRet = A51WriteToFileSync(m_aFiles[nFileId].m_h, lFileOffset,
  704. pBuffer, dwLen);
  705. // FlushFileBuffers(m_aFiles[nFileId].m_h);
  706. return lRet;
  707. }
  708. long CLongFileStagingFile::SetEndOfActualFile(int nFileId,
  709. TFileOffset lFileLength)
  710. {
  711. CInCritSec ics(&m_cs);
  712. LARGE_INTEGER liEnd;
  713. liEnd.QuadPart = lFileLength;
  714. if(!SetFilePointerEx(m_aFiles[nFileId].m_h, liEnd, NULL, FILE_BEGIN))
  715. return GetLastError();
  716. if(!SetEndOfFile(m_aFiles[nFileId].m_h))
  717. return GetLastError();
  718. return ERROR_SUCCESS;
  719. }
  720. long CLongFileStagingFile::CloseAllFiles()
  721. {
  722. CInCritSec ics(&m_cs);
  723. for(int i = 0; i < A51_MAX_FILES; i++)
  724. {
  725. if(m_aFiles[i].m_h != NULL)
  726. {
  727. CloseHandle(m_aFiles[i].m_h);
  728. }
  729. m_aFiles[i].m_h = NULL;
  730. m_aFiles[i].m_bSupportsOverwrites = false;
  731. }
  732. return ERROR_SUCCESS;
  733. }
  734. long CLongFileStagingFile::RegisterFile(int nFileId, HANDLE hFile,
  735. bool bSupportsOverwrites)
  736. {
  737. _ASSERT(nFileId < A51_MAX_FILES, L"File ID is too large");
  738. if(m_aFiles[nFileId].m_h != NULL)
  739. CloseHandle(m_aFiles[nFileId].m_h);
  740. m_aFiles[nFileId].m_h = hFile;
  741. m_aFiles[nFileId].m_bSupportsOverwrites = bSupportsOverwrites;
  742. return ERROR_SUCCESS;
  743. }
  744. bool CLongFileStagingFile::DoesSupportOverwrites(int nFileId)
  745. {
  746. return m_aFiles[nFileId].m_bSupportsOverwrites;
  747. }
  748. long CLongFileStagingFile::WriteEmpty()
  749. {
  750. _ASSERT(m_mapStarts.size() == 0 && m_mapEnds.size() == 0, L"");
  751. FlushDataFiles();
  752. return CExecutableStageManager::WriteEmpty();
  753. }
  754. bool CLongFileStagingFile::InjectFailure()
  755. {
  756. #ifdef A51_INJECT_FAILURE
  757. if(GetTickCount() > g_dwLastFailureCheck + FAILURE_INJECTION_CHECK_INTERVAL)
  758. {
  759. HKEY hKey;
  760. long lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  761. L"SOFTWARE\\Microsoft\\WBEM\\CIMOM",
  762. 0, KEY_READ | KEY_WRITE, &hKey);
  763. if(lRes)
  764. return false;
  765. CRegCloseMe cm(hKey);
  766. DWORD dwLen = sizeof(DWORD);
  767. lRes = RegQueryValueExW(hKey, L"Failure Frequency", NULL, NULL,
  768. (LPBYTE)&g_dwFailureFrequency, &dwLen);
  769. if(lRes != ERROR_SUCCESS)
  770. g_dwFailureFrequency = 0;
  771. g_dwLastFailureCheck = GetTickCount();
  772. }
  773. if(g_dwFailureFrequency && ++g_dwFailureCount == g_dwFailureFrequency)
  774. {
  775. g_dwFailureCount = 0;
  776. m_bMustFail = true;
  777. return true;
  778. }
  779. else
  780. {
  781. return false;
  782. }
  783. #else
  784. return false;
  785. #endif
  786. }
  787. void CLongFileStagingFile::Dump(FILE* f)
  788. {
  789. fprintf(f, "BEGINS:\n");
  790. TIterator itStart = m_mapStarts.begin();
  791. while(itStart != m_mapStarts.end())
  792. {
  793. CWriteFileInstruction* pInst = itStart->second;
  794. fprintf(f, "File %d (%d-%d): instruction %p\n",
  795. (int)pInst->m_Location.m_nFileId,
  796. (int)pInst->m_Location.m_lStartOffset,
  797. (int)pInst->m_Location.m_lStartOffset + pInst->m_dwLen,
  798. pInst);
  799. itStart++;
  800. }
  801. fprintf(f, "IN ORDER:\n");
  802. int nSize = m_qToWrite.size();
  803. for(int i = 0; i < nSize; i++)
  804. {
  805. CLongFileInstruction* pInstruction =
  806. (CLongFileInstruction*)m_qToWrite.front();
  807. if(pInstruction->IsWrite())
  808. {
  809. CWriteFileInstruction* pInst = (CWriteFileInstruction*)pInstruction;
  810. fprintf(f, "File %d (%d-%d): instruction %p\n",
  811. (int)pInst->m_Location.m_nFileId,
  812. (int)pInst->m_Location.m_lStartOffset,
  813. (int)pInst->m_Location.m_lStartOffset + pInst->m_dwLen,
  814. pInst);
  815. }
  816. else
  817. {
  818. CSetEndOfFileInstruction* pInst = (CSetEndOfFileInstruction*)pInstruction;
  819. fprintf(f, "Truncate file %d at %d: instruction %p\n",
  820. (int)pInst->m_Location.m_nFileId,
  821. (int)pInst->m_Location.m_lStartOffset,
  822. pInst);
  823. }
  824. m_qToWrite.pop_front();
  825. m_qToWrite.push_back(pInstruction);
  826. }
  827. }