Leaked source code of windows server 2003
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.

986 lines
26 KiB

  1. #include "nt.h"
  2. #include "ntdef.h"
  3. #include "ntrtl.h"
  4. #include "nturtl.h"
  5. #include "stdio.h"
  6. #include "sxs-rtl.h"
  7. #undef INVALID_HANDLE_VALUE
  8. #include "windows.h"
  9. #include "environment.h"
  10. #include "manifestcooked.h"
  11. #include "assemblygac.h"
  12. #include "bcl_common.h"
  13. #include "bcl_w32unicodeinlinestringbuffer.h"
  14. #include "search.h"
  15. //
  16. // Crypto stack
  17. //
  18. #include "hashers.h"
  19. #include "digesters.h"
  20. CEnv::StatusCode
  21. FsCopyFileWithHashGeneration(
  22. const CEnv::CConstantUnicodeStringPair &Source,
  23. const CEnv::CConstantUnicodeStringPair &Target,
  24. CHashObject &HashObjectTarget,
  25. CDigestMethod &DigestMethod
  26. )
  27. {
  28. CEnv::StatusCode Result;
  29. CEnv::CByteRegion TempAllocation(NULL, 0);
  30. HANDLE SourceHandle = INVALID_HANDLE_VALUE;
  31. HANDLE TargetHandle = INVALID_HANDLE_VALUE;
  32. SIZE_T cbDidRead, cbOffset;
  33. //
  34. // Force initialization of the hasher and digester.
  35. //
  36. HashObjectTarget.Initialize();
  37. DigestMethod.Initialize(HashObjectTarget);
  38. //
  39. // Snag some memory to perform the copies
  40. //
  41. Result = CEnv::AllocateHeap(2048, TempAllocation, NULL);
  42. if (CEnv::DidFail(Result))
  43. goto Exit;
  44. //
  45. // Obtain handles for both files
  46. //
  47. Result = CEnv::GetFileHandle(&SourceHandle, Source, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING);
  48. if (CEnv::DidFail(Result))
  49. goto Exit;
  50. Result = CEnv::GetFileHandle(&TargetHandle, Target, GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS);
  51. if (CEnv::DidFail(Result))
  52. goto Exit;
  53. //
  54. // Now spin through the file reading blocks, digesting them.
  55. //
  56. cbOffset = 0;
  57. do
  58. {
  59. Result = CEnv::ReadFile(SourceHandle, TempAllocation, cbDidRead);
  60. if (CEnv::DidFail(Result))
  61. goto Exit;
  62. if (cbDidRead == 0)
  63. break;
  64. Result = DigestMethod.DigestExtent(HashObjectTarget, cbOffset, TempAllocation);
  65. if (CEnv::DidFail(Result))
  66. goto Exit;
  67. cbOffset += cbDidRead;
  68. Result = CEnv::WriteFile(TargetHandle, TempAllocation, cbDidRead);
  69. if (CEnv::DidFail(Result))
  70. goto Exit;
  71. }
  72. while (true);
  73. //
  74. // Ok, we're done.
  75. //
  76. Exit:
  77. if (TempAllocation.GetPointer())
  78. CEnv::FreeHeap(TempAllocation.GetPointer(), NULL);
  79. if (SourceHandle != INVALID_HANDLE_VALUE)
  80. CEnv::CloseHandle(SourceHandle);
  81. if (TargetHandle != INVALID_HANDLE_VALUE)
  82. CEnv::CloseHandle(TargetHandle);
  83. return Result;
  84. }
  85. COSAssemblyCache*
  86. CDotNetSxsAssemblyCache::CreateSelf(
  87. ULONG ulFlags,
  88. const GUID *pCacheIdent
  89. )
  90. {
  91. CDotNetSxsAssemblyCache *pAllocation = NULL;
  92. CEnv::StatusCode status;
  93. if (!pCacheIdent || (*pCacheIdent != CacheIdentifier))
  94. return NULL;
  95. status = CEnv::AllocateHeap(sizeof(CDotNetSxsAssemblyCache), (PVOID*)&pAllocation, NULL);
  96. if (CEnv::DidFail(status))
  97. return NULL;
  98. pAllocation->CDotNetSxsAssemblyCache::CDotNetSxsAssemblyCache(ulFlags);
  99. return pAllocation;
  100. }
  101. CDotNetSxsAssemblyCache::CDotNetSxsAssemblyCache(
  102. ULONG ulFlags
  103. )
  104. {
  105. }
  106. CDotNetSxsAssemblyCache::~CDotNetSxsAssemblyCache()
  107. {
  108. }
  109. CEnv::StatusCode
  110. CDotNetSxsAssemblyCache::IdentityToTargetPath(
  111. const CAssemblyIdentity& Ident,
  112. CEnv::CStringBuffer &PathSegment
  113. )
  114. {
  115. typedef CEnv::CConstantUnicodeStringPair CStringPair;
  116. enum {
  117. Identity_ProcArch = 0,
  118. Identity_Name,
  119. Identity_PublicKeyToken,
  120. Identity_Version,
  121. Identity_Language,
  122. };
  123. static const struct {
  124. CStringPair Namespace;
  125. CStringPair Name;
  126. CStringPair DefaultValue;
  127. } PathComponents[] = {
  128. { CStringPair(), CStringPair(L"processorArchitecture", NUMBER_OF(L"processorArchitecture") - 1), CStringPair(L"data", 4) },
  129. { CStringPair(), CStringPair(L"name", NUMBER_OF(L"name") - 1), CStringPair() },
  130. { CStringPair(), CStringPair(L"publicKeyToken", NUMBER_OF(L"publicKeyToken") - 1), CStringPair(L"no-public-key-token", NUMBER_OF(L"no-public-key-token") - 1) },
  131. { CStringPair(), CStringPair(L"version", NUMBER_OF(L"version") - 1), CStringPair(L"0.0.0.0", 7) },
  132. { CStringPair(), CStringPair(L"language", NUMBER_OF(L"language") - 1), CStringPair(L"x-ww", 4) },
  133. };
  134. CEnv::StatusCode Result = CEnv::SuccessCode;
  135. CStringPair FoundComponents[NUMBER_OF(PathComponents) * 2];
  136. SIZE_T i;
  137. PathSegment.Clear();
  138. //
  139. // Look for these identity components in order
  140. //
  141. for (i = 0; i < NUMBER_OF(PathComponents); i++)
  142. {
  143. Result = Ident.FindAttribute(PathComponents[i].Namespace, PathComponents[i].Name, FoundComponents[2*i]);
  144. if (Result == CEnv::NotFound)
  145. {
  146. FoundComponents[2*i] = PathComponents[i].DefaultValue;
  147. }
  148. else if (CEnv::DidFail(Result))
  149. {
  150. goto Exit;
  151. }
  152. FoundComponents[2*i+1].SetPointerAndCount(L"_", 1);
  153. }
  154. //
  155. // Meddle with the 'name' string to ensure that it falls under the filesystem limits
  156. //
  157. // TODO: Fix name string
  158. //
  159. if (!PathSegment.Assign(NUMBER_OF(FoundComponents), FoundComponents))
  160. {
  161. //
  162. // I think we need to fix the string APIs such that on win32 they return lasterror
  163. // rather than returning BOOL all the time - it'd make transitioning into the RTL
  164. // much easier...
  165. //
  166. Result = CEnv::OutOfMemory;
  167. PathSegment.Clear();
  168. goto Exit;
  169. }
  170. Result = CEnv::SuccessCode;
  171. Exit:
  172. return Result;
  173. }
  174. CEnv::StatusCode
  175. CDotNetSxsAssemblyCache::Initialize()
  176. {
  177. this->m_WindowsDirectory = CEnv::StringFrom(USER_SHARED_DATA->NtSystemRoot);
  178. return CEnv::SuccessCode;
  179. }
  180. CEnv::StatusCode
  181. CDotNetSxsAssemblyCache::EnsurePathsAvailable()
  182. {
  183. CEnv::CConstantUnicodeStringPair PathBuilder[3] = {
  184. m_WindowsDirectory,
  185. s_BaseDirectory,
  186. s_ManifestsPath
  187. };
  188. CEnv::StatusCode Result = CEnv::SuccessCode;
  189. //
  190. // Ensure that the WinSxS store is available:
  191. // {windir}\{winsxs2}
  192. // {windir}\{winsxs2}\{manifests}
  193. //
  194. // This call has the side-effect of building all three levels.
  195. //
  196. if (CEnv::DidFail(Result = CEnv::CreateDirectory(3, PathBuilder)))
  197. goto Exit;
  198. Result = CEnv::SuccessCode;
  199. Exit:
  200. return Result;
  201. }
  202. /*
  203. Installation has these phases:
  204. - Create mandatory directories in the store
  205. - Store path
  206. - Manifests
  207. - Create the target assembly identity
  208. - If the target assembly is a policy
  209. - Write the .policy file into the right place
  210. - Notify the store metadata manager about the new policy
  211. - Done
  212. - If the target assembly is not already installed
  213. - Create '%storeroot%\%asmpath%-temp' to store files
  214. - Stream files into install target path, validating hashes
  215. - Rename path to remove -temp marker
  216. - Place the .manifest
  217. - Notify the store metadata manager about the new manifest
  218. - Done
  219. - If the target assembly is already installed
  220. - Notify the store metadata manager about another reference
  221. - Done
  222. Unless:
  223. - If the "refresh" flag is set, then the bits are copied in again
  224. */
  225. CEnv::StatusCode
  226. CDotNetSxsAssemblyCache::InstallAssembly(
  227. ULONG Flags,
  228. PMANIFEST_COOKED_DATA ManifestData,
  229. const CEnv::CConstantUnicodeStringPair &FilePath
  230. )
  231. {
  232. CEnv::StatusCode Result = CEnv::SuccessCode;
  233. CNtEnvironment::StatusCode NtResult;
  234. CEnv::CStringBuffer FirstFile, SecondFile;
  235. CAssemblyIdentity ThisIdentity;
  236. //
  237. // First, let's ensure that the required directories are present
  238. //
  239. if (CEnv::DidFail(Result = EnsurePathsAvailable()))
  240. goto Exit;
  241. //
  242. // Now let's stage the files in question into an installtemp location, validating as we
  243. // copy. We will never store the actual manifest, we will only store the solidified blob
  244. // that we got after parsing and cooking it. But first, let's turn that set of identity
  245. // values into an actual identity...
  246. //
  247. // Result = ThisIdentity.C
  248. Result = CEnv::SuccessCode;
  249. Exit:
  250. return Result;
  251. }
  252. CEnv::StatusCode
  253. CDotNetSxsAssemblyCache::UninstallAssembly(
  254. ULONG Flags,
  255. PMANIFEST_COOKED_DATA ManifestData,
  256. UninstallResult & Result
  257. )
  258. {
  259. return STATUS_NOT_IMPLEMENTED;
  260. }
  261. const GUID CDotNetSxsAssemblyCache::CacheIdentifier = { /* 37e3c37d-667f-4aee-8dab-a0d117acfa68 */
  262. 0x37e3c37d,
  263. 0x667f,
  264. 0x4aee,
  265. {0x8d, 0xab, 0xa0, 0xd1, 0x17, 0xac, 0xfa, 0x68}
  266. };
  267. const CEnv::CConstantUnicodeStringPair CDotNetSxsAssemblyCache::s_PoliciesPath(L"Policies", 8);
  268. const CEnv::CConstantUnicodeStringPair CDotNetSxsAssemblyCache::s_ManifestsPath(L"Manifests", 9);
  269. const CEnv::CConstantUnicodeStringPair CDotNetSxsAssemblyCache::s_InstallTemp(L"InstallTemp", 11);
  270. const CEnv::CConstantUnicodeStringPair CDotNetSxsAssemblyCache::s_BaseDirectory(L"WinSxS2", 7);
  271. //
  272. // Assembly identity stuff - should get split into another file
  273. //
  274. CAssemblyIdentity::CAssemblyIdentity()
  275. : m_cIdentityValues(0), m_IdentityValues(NULL), m_fFrozen(false),
  276. m_fSorted(true), m_fHashDirtyV1(true), m_fHashDirtyV2(true),
  277. m_ulHashV1(0), m_cAvailableIdentitySlots(0)
  278. {
  279. ZeroMemory(m_IdentityShaHash, sizeof(m_IdentityShaHash));
  280. }
  281. CAssemblyIdentity::~CAssemblyIdentity()
  282. {
  283. DeleteAllValues();
  284. }
  285. CEnv::StatusCode
  286. CAssemblyIdentity::DeleteAllValues()
  287. {
  288. //
  289. // Let's keep the table around, just because that's handy
  290. //
  291. if (m_IdentityValues != NULL)
  292. {
  293. for (SIZE_T c = 0; c < m_cIdentityValues; c++)
  294. {
  295. CEnv::FreeHeap(m_IdentityValues[c], NULL);
  296. m_IdentityValues[c] = NULL;
  297. }
  298. m_cIdentityValues = 0;
  299. }
  300. this->m_fHashDirtyV1 = this->m_fHashDirtyV2 = true;
  301. this->m_ulHashV1 = 0;
  302. return CEnv::SuccessCode;
  303. }
  304. CEnv::StatusCode
  305. CAssemblyIdentity::SetAttribute(
  306. const CStringPair &Namespace,
  307. const CStringPair &Name,
  308. const CStringPair &Value,
  309. bool fReplace
  310. )
  311. {
  312. CEnv::StatusCode Result;
  313. SIZE_T cIndex;
  314. //
  315. // If looking for this value had some other problem aside from not being found,
  316. // then exit.
  317. //
  318. Result = this->InternalFindValue(Namespace, Name, cIndex);
  319. if (CEnv::DidFail(Result) && (Result != CEnv::NotFound))
  320. goto Exit;
  321. //
  322. // Easy - create a new attribute to hold this value.
  323. //
  324. if (Result == CEnv::NotFound)
  325. {
  326. CIdentityValue *NewValue = NULL;
  327. SIZE_T c;
  328. if (CEnv::DidFail(Result = this->InternalAllocateValue(Namespace, Name, Value, NewValue)))
  329. goto Exit;
  330. //
  331. // After we've allocated one, go insert it into the table. If that failed,
  332. // the clean up and exit
  333. //
  334. if (CEnv::DidFail(Result = this->InternalInsertValue(NewValue)))
  335. {
  336. this->InternalDestroyValue(NewValue);
  337. goto Exit;
  338. }
  339. }
  340. else
  341. {
  342. CIdentityValue *ThisValue = m_IdentityValues[cIndex];
  343. const SIZE_T cbRequiredSize = ((Namespace.GetCount() + Name.GetCount() + Value.GetCount()) * sizeof(WCHAR)) + sizeof(CIdentityValue);
  344. ASSERT(ThisValue != NULL);
  345. //
  346. // Spiffy, there's enough space in the existing value to hold the data from
  347. // the input value.
  348. //
  349. if (cbRequiredSize < ThisValue->cbAllocationSize)
  350. {
  351. if (CEnv::DidFail(Result = ThisValue->WriteValues(Namespace, Name, Value)))
  352. goto Exit;
  353. }
  354. //
  355. // Bah, have to reallocate this entry
  356. //
  357. else
  358. {
  359. CIdentityValue *NewValue = NULL;
  360. if (CEnv::DidFail(Result = this->InternalAllocateValue(Namespace, Name, Value, NewValue)))
  361. goto Exit;
  362. m_IdentityValues[cIndex] = NewValue;
  363. NewValue = NULL;
  364. if (CEnv::DidFail(Result = this->InternalDestroyValue(ThisValue)))
  365. goto Exit;
  366. }
  367. }
  368. //
  369. // Now clear all the relevant flags
  370. //
  371. this->m_fHashDirtyV1 = this->m_fHashDirtyV2 = true;
  372. this->m_fSorted = false;
  373. Result = CEnv::SuccessCode;
  374. Exit:
  375. return Result;
  376. }
  377. CEnv::StatusCode
  378. CAssemblyIdentity::DeleteAttribute(
  379. const CStringPair &Namespace,
  380. const CStringPair &Name
  381. )
  382. {
  383. SIZE_T cIndex;
  384. CEnv::StatusCode Result;
  385. CIdentityValue *Victim = NULL;
  386. //
  387. // InternalFindValue will return NotFound if it didn't find it.
  388. //
  389. if (CEnv::DidFail(Result = this->InternalFindValue(Namespace, Name, cIndex)))
  390. goto Exit;
  391. //
  392. // Remember the one we found, clear its slot, delete the allocation
  393. //
  394. Victim = m_IdentityValues[cIndex];
  395. m_IdentityValues[cIndex] = NULL;
  396. //
  397. // And clear the state flags before we delete it
  398. //
  399. this->m_fHashDirtyV1 = this->m_fHashDirtyV2 = true;
  400. this->m_fSorted = false;
  401. if (CEnv::DidFail(Result = this->InternalDestroyValue(Victim)))
  402. goto Exit;
  403. Result = CEnv::SuccessCode;
  404. Exit:
  405. return Result;
  406. }
  407. CEnv::StatusCode
  408. CAssemblyIdentity::CIdentityValue::WriteValues(
  409. const CStringPair & InNamespace,
  410. const CStringPair & InName,
  411. const CStringPair & InValue
  412. )
  413. {
  414. PWSTR pwszWriteCursor = (PWSTR)(this + 1);
  415. const SIZE_T cRequired = ((InNamespace.GetCount() + InName.GetCount() + InValue.GetCount()) * sizeof(WCHAR)) * sizeof(*this);
  416. if (cRequired < this->cbAllocationSize)
  417. {
  418. return CEnv::NotEnoughBuffer;
  419. }
  420. this->HashV1Valid = false;
  421. this->HashV1 = 0;
  422. this->Namespace.SetPointerAndCount(pwszWriteCursor, InNamespace.GetCount());
  423. memcpy(pwszWriteCursor, InNamespace.GetPointer(), InNamespace.GetCount() * sizeof(WCHAR));
  424. pwszWriteCursor += InNamespace.GetCount();
  425. this->Name.SetPointerAndCount(pwszWriteCursor, InName.GetCount());
  426. memcpy(pwszWriteCursor, InName.GetPointer(), InName.GetCount() * sizeof(WCHAR));
  427. pwszWriteCursor += InName.GetCount();
  428. this->Value.SetPointerAndCount(pwszWriteCursor, InValue.GetCount());
  429. memcpy(pwszWriteCursor, InValue.GetPointer(), InValue.GetCount() * sizeof(WCHAR));
  430. return CEnv::SuccessCode;
  431. }
  432. CEnv::StatusCode
  433. CAssemblyIdentity::CIdentityValue::Compare(
  434. const CAssemblyIdentity::CIdentityValue& Other,
  435. int &iResult
  436. ) const
  437. {
  438. CEnv::StatusCode Result;
  439. int iMyResult = 0;
  440. iResult = -1;
  441. //
  442. // this == this
  443. //
  444. if (this == &Other)
  445. {
  446. iResult = 0;
  447. return CEnv::SuccessCode;
  448. }
  449. //
  450. // Namespace first, then name.
  451. //
  452. if (CEnv::DidFail(Result = CEnv::CompareStrings(this->Namespace, Other.Namespace, iMyResult)))
  453. goto Exit;
  454. //
  455. // Only bother if the namespaces match
  456. //
  457. if (iMyResult == 0)
  458. {
  459. if (CEnv::DidFail(Result = CEnv::CompareStringsCaseInsensitive(this->Name, Other.Name, iMyResult)))
  460. goto Exit;
  461. }
  462. iResult = iMyResult;
  463. Result = CEnv::SuccessCode;
  464. Exit:
  465. return Result;
  466. }
  467. CEnv::StatusCode
  468. CAssemblyIdentity::InternalDestroyValue(
  469. CIdentityValue *Victim
  470. )
  471. {
  472. //
  473. // This just calls heapfree on the attribute
  474. //
  475. return CEnv::FreeHeap((PVOID)Victim, NULL);
  476. }
  477. CEnv::StatusCode
  478. CAssemblyIdentity::InternalAllocateValue(
  479. const CStringPair &Namespace,
  480. const CStringPair &Name,
  481. const CStringPair &Value,
  482. CAssemblyIdentity::CIdentityValue* &pCreated
  483. )
  484. {
  485. const SIZE_T cbRequired = ((Namespace.GetCount() + Name.GetCount() + Value.GetCount()) * sizeof(WCHAR)) + sizeof(CIdentityValue);
  486. CIdentityValue *pTempCreated = NULL;
  487. CEnv::StatusCode Result;
  488. pCreated = NULL;
  489. if (CEnv::DidFail(Result = CEnv::AllocateHeap(cbRequired, (PVOID*)&pTempCreated, NULL)))
  490. goto Exit;
  491. if (CEnv::DidFail(Result = pTempCreated->WriteValues(Namespace, Name, Value)))
  492. goto Exit;
  493. pCreated = pTempCreated;
  494. pTempCreated = NULL;
  495. Result = CEnv::SuccessCode;
  496. Exit:
  497. if (pTempCreated)
  498. {
  499. CEnv::FreeHeap(pTempCreated, NULL);
  500. }
  501. return Result;
  502. }
  503. //
  504. // Non-const version can sort.
  505. //
  506. CEnv::StatusCode
  507. CAssemblyIdentity::InternalFindValue(
  508. const CStringPair & Namespace,
  509. const CStringPair & Name,
  510. SIZE_T &cIndex
  511. )
  512. {
  513. CEnv::StatusCode Result;
  514. cIndex = -1;
  515. if (!this->m_fSorted)
  516. {
  517. if (CEnv::DidFail(Result = this->SortIdentityAttributes()))
  518. goto Exit;
  519. }
  520. //
  521. // Use the built-in searcher on the const one.
  522. //
  523. Result = (const_cast<const CAssemblyIdentity&>(*this)).InternalFindValue(Namespace, Name, cIndex);
  524. Exit:
  525. return Result;
  526. }
  527. CEnv::StatusCode
  528. CAssemblyIdentity::FindAttribute(
  529. const CStringPair & Namespace,
  530. const CStringPair & Name,
  531. CStringPair & Value
  532. )
  533. {
  534. CEnv::StatusCode Result;
  535. SIZE_T cIndex;
  536. Value.SetPointerAndCount(NULL, 0);
  537. Result = this->InternalFindValue(Namespace, Name, cIndex);
  538. if (!CEnv::DidFail(Result))
  539. {
  540. Value = this->m_IdentityValues[cIndex]->Value;
  541. Result = CEnv::SuccessCode;
  542. }
  543. return Result;
  544. }
  545. CEnv::StatusCode
  546. CAssemblyIdentity::FindAttribute(
  547. const CStringPair &Namespace,
  548. const CStringPair &Name,
  549. CStringPair& Value
  550. ) const
  551. {
  552. CEnv::StatusCode Result;
  553. SIZE_T cIndex;
  554. Value.SetPointerAndCount(NULL, 0);
  555. Result = this->InternalFindValue(Namespace, Name, cIndex);
  556. if (!CEnv::DidFail(Result))
  557. {
  558. Value = this->m_IdentityValues[cIndex]->Value;
  559. Result = CEnv::SuccessCode;
  560. }
  561. return Result;
  562. }
  563. CEnv::StatusCode
  564. CAssemblyIdentity::InternalFindValue(
  565. const CStringPair &Namespace,
  566. const CStringPair &Name,
  567. SIZE_T &cIndex
  568. ) const
  569. {
  570. CEnv::StatusCode Result;
  571. SIZE_T cLow, cHigh;
  572. CIdentityValue ComparisonDump;
  573. cIndex = -1;
  574. ComparisonDump.Namespace = Namespace;
  575. ComparisonDump.Name = Name;
  576. if (!this->m_fSorted)
  577. {
  578. //
  579. // Ick, linear search.
  580. //
  581. for (cLow = 0; cLow < this->m_cIdentityValues; cLow++)
  582. {
  583. int iResult = 0;
  584. CIdentityValue *pFound = this->m_IdentityValues[cLow];
  585. //
  586. // Possible to have holes in the const linear-search version
  587. //
  588. if (!pFound)
  589. continue;
  590. if (CEnv::DidFail(Result = pFound->Compare(ComparisonDump, iResult)))
  591. goto Exit;
  592. if (iResult == 0)
  593. {
  594. cIndex = cLow;
  595. Result = CEnv::SuccessCode;
  596. goto Exit;
  597. }
  598. }
  599. }
  600. else
  601. {
  602. //
  603. // We're doing our own bsearch here.
  604. //
  605. cLow = 0;
  606. cHigh = this->m_cIdentityValues;
  607. while (cLow < cHigh)
  608. {
  609. SIZE_T cMiddle = (cHigh - cLow) / 2;
  610. int iResult = 0;
  611. CIdentityValue *pFound = this->m_IdentityValues[cMiddle];
  612. //
  613. // The sorting should have reorganized the attributes so NULL slots
  614. // were past the number of in-use identity values.
  615. //
  616. ASSERT(pFound != NULL);
  617. if (CEnv::DidFail(Result = pFound->Compare(ComparisonDump, iResult)))
  618. goto Exit;
  619. if (iResult == 0)
  620. {
  621. cIndex = cMiddle;
  622. Result = CEnv::SuccessCode;
  623. goto Exit;
  624. }
  625. else if (iResult < 0)
  626. {
  627. cHigh = cMiddle;
  628. continue;
  629. }
  630. else if (iResult > 0)
  631. {
  632. cLow = cMiddle;
  633. continue;
  634. }
  635. }
  636. }
  637. Result = CEnv::NotFound;
  638. Exit:
  639. return Result;
  640. }
  641. #define ASSEMBLY_IDENTITY_TABLE_EXPANDO_FACTOR (20)
  642. CEnv::StatusCode
  643. CAssemblyIdentity::Freeze()
  644. {
  645. CEnv::StatusCode Result;
  646. if (m_fFrozen)
  647. return CEnv::SuccessCode;
  648. if (CEnv::DidFail(Result = SortIdentityAttributes()))
  649. return Result;
  650. if (CEnv::DidFail(Result = RegenerateHash()))
  651. return Result;
  652. m_fFrozen = true;
  653. return CEnv::SuccessCode;
  654. }
  655. CEnv::StatusCode
  656. CAssemblyIdentity::RegenerateHash()
  657. {
  658. return CEnv::NotImplemented;
  659. }
  660. CEnv::StatusCode
  661. CAssemblyIdentity::InternalInsertValue(
  662. CAssemblyIdentity::CIdentityValue * NewValue
  663. )
  664. {
  665. CEnv::StatusCode Result;
  666. //
  667. // If the number of values is the same as the available slots, then we
  668. // have to expand the internal table.
  669. //
  670. if (m_cIdentityValues == m_cAvailableIdentitySlots)
  671. {
  672. //
  673. // Simple logic - increase by 20 slots each time
  674. //
  675. CIdentityValue** ppNewTable = NULL;
  676. CIdentityValue** ppOldTable = m_IdentityValues;
  677. const SIZE_T cNewSlots = m_cAvailableIdentitySlots + ASSEMBLY_IDENTITY_TABLE_EXPANDO_FACTOR;
  678. const SIZE_T cbRequired = sizeof(CIdentityValue*) * cNewSlots;
  679. if (CEnv::DidFail(Result = CEnv::AllocateHeap(cbRequired, (PVOID*)&ppNewTable, NULL)))
  680. goto Exit;
  681. //
  682. // Pointers make this easy
  683. //
  684. if (ppOldTable)
  685. {
  686. memcpy(ppNewTable, ppOldTable, sizeof(CIdentityValue*) * m_cAvailableIdentitySlots);
  687. }
  688. //
  689. // Clear out the data in these slots
  690. //
  691. for (SIZE_T i = m_cAvailableIdentitySlots; i < cNewSlots; i++)
  692. {
  693. ppNewTable[i] = NULL;
  694. }
  695. m_IdentityValues = ppNewTable;
  696. m_cAvailableIdentitySlots = cNewSlots;
  697. //
  698. // Free the old table
  699. //
  700. if (ppOldTable)
  701. {
  702. CEnv::FreeHeap((PVOID)ppOldTable, NULL);
  703. }
  704. }
  705. ASSERT(m_IdentityValues != NULL);
  706. ASSERT(m_cIdentityValues < m_cAvailableIdentitySlots);
  707. m_IdentityValues[m_cIdentityValues++] = NewValue;
  708. Result = CEnv::SuccessCode;
  709. Exit:
  710. return Result;
  711. }
  712. int __cdecl
  713. CAssemblyIdentity::SortingCallback(
  714. const CAssemblyIdentity::CIdentityValue **left,
  715. const CAssemblyIdentity::CIdentityValue **right
  716. )
  717. {
  718. const CIdentityValue *pLeft = *left;
  719. const CIdentityValue *pRight = *right;
  720. CEnv::StatusCode Result = CEnv::SuccessCode;
  721. int iResult = 0;
  722. //
  723. // Percolate NULL slots towards the 'end'
  724. //
  725. if (!left && !right)
  726. {
  727. return 0;
  728. }
  729. else if (!left && right)
  730. {
  731. return 1;
  732. }
  733. else if (left && !right)
  734. {
  735. return -1;
  736. }
  737. ASSERT(pLeft && pRight);
  738. Result = pLeft->Compare(*pRight, iResult);
  739. ASSERT(!CEnv::DidFail(Result));
  740. return iResult;
  741. }
  742. CEnv::StatusCode
  743. CAssemblyIdentity::SortIdentityAttributes()
  744. {
  745. CEnv::StatusCode Result;
  746. if (this->m_cIdentityValues == 0)
  747. {
  748. m_fSorted = true;
  749. }
  750. if (m_fSorted)
  751. {
  752. return CEnv::SuccessCode;
  753. }
  754. qsort(
  755. this->m_IdentityValues,
  756. this->m_cAvailableIdentitySlots,
  757. sizeof(this->m_IdentityValues[0]),
  758. (int (__cdecl*)(const void*, const void*))SortingCallback
  759. );
  760. //
  761. // Sorted now, but we've invalidated the hash of the overall object.
  762. //
  763. m_fSorted = true;
  764. m_fHashDirtyV1 = m_fHashDirtyV2 = true;
  765. return CEnv::SuccessCode;
  766. }
  767. /*
  768. class CAssemblyIdentity
  769. {
  770. public:
  771. typedef CEnv::CConstantUnicodeStringPair CStringPair;
  772. CAssemblyIdentity();
  773. ~CAssemblyIdentity();
  774. CEnv::StatusCode SetAttribute(const CStringPair &Namespace, const CStringPair &Name, const CStringPair &Value, bool fReplace = true);
  775. CEnv::StatusCode SetAttribute(const CStringPair &Name, const CStringPair& Value, bool fReplace = true) { return SetAttribute(CStringPair(), Name, Value, fReplace); }
  776. CEnv::StatusCode DeleteAttribute(const CStringPair &Namespace, const CStringPair &Name);
  777. //
  778. // The const version will do a linear or a bsearch depending on the sorted state. The non-const
  779. // version will sort the internal attribute list first if necessary before looking up the value
  780. //
  781. CEnv::StatusCode FindAttribute(const CStringPair &Namespace, const CStringPair &Name, CStringPair& Value) const;
  782. CEnv::StatusCode FindAttribute(const CStringPair &Namespace, const CStringPair &Name, CStringPair& Value);
  783. unsigned long IdentityHash() const;
  784. unsigned long IdentityHash();
  785. unsigned long long IdentityHashV2() const;
  786. unsigned long long IdentityHashV2();
  787. //
  788. // Maintainence stuff
  789. //
  790. CEnv::StatusCode Freeze();
  791. CEnv::StatusCode DeleteAllValues();
  792. static CEnv::StatusCode ConstructFromCookedData(
  793. CAssemblyIdentity& Target,
  794. PMANIFEST_COOKED_IDENTITY IdentityData
  795. );
  796. protected:
  797. //
  798. // This is an all-in-one allocation blob
  799. //
  800. typedef struct {
  801. CStringPair Namespace;
  802. CStringPair Name;
  803. CStringPair Value;
  804. } CIdentityValue;
  805. SIZE_T m_cIdentityValues;
  806. CIdentityValue** m_IdentityValues;
  807. bool m_fFrozen;
  808. bool m_fSorted;
  809. bool m_fHashDirty;
  810. CEnv::StatusCode RegenerateHash();
  811. CEnv::StatusCode SortIdentityAttributes();
  812. int SortingCallback(const CIdentityValue *left, const CIdentityValue *right);
  813. };
  814. */