From 323f62d3d0f4b73db5fde8977e2540194c6de006 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Tue, 2 Nov 2021 17:47:46 -0500 Subject: Follow up for multiple attached container support * validate cContainers * use previous embeddedid format and use intermediate folder when extracting attached containers * remove special cases for 0 byte containers in BurnCommon classes and Insignia * don't hardcode max containers * reduce properties in BurnCommon * add e2e test #6144 --- src/burn/engine/section.cpp | 24 ++++--- src/burn/stub/StubSection.cpp | 3 +- .../ContainerTests/BundleA/BundleA.wixproj | 19 +++++ .../TestData/ContainerTests/BundleA/BundleA.wxs | 17 +++++ .../ContainerTests/PackageA/PackageA.wixproj | 10 +++ .../ContainerTests/PackageB/PackageB.wixproj | 10 +++ .../burn/WixToolsetTest.BurnE2E/ContainerTests.cs | 29 ++++++++ .../WixToolset.Core.Burn/Bind/BindBundleCommand.cs | 4 +- src/wix/WixToolset.Core.Burn/BundleBackend.cs | 2 +- src/wix/WixToolset.Core.Burn/Bundles/BurnCommon.cs | 61 ++++++++--------- src/wix/WixToolset.Core.Burn/Bundles/BurnReader.cs | 24 ++++--- src/wix/WixToolset.Core.Burn/Bundles/BurnWriter.cs | 80 ++++++++++++++-------- .../Inscribe/InscribeBundleCommand.cs | 17 +---- .../WixToolset.Core.TestPackage/BundleExtractor.cs | 42 +++++++----- .../ExtractBAContainerResult.cs | 6 ++ .../BundleFixture.cs | 8 ++- .../ContainerFixture.cs | 58 +++++++++------- .../PackagePayloadFixture.cs | 3 +- .../PayloadFixture.cs | 17 +++-- 19 files changed, 276 insertions(+), 158 deletions(-) create mode 100644 src/test/burn/TestData/ContainerTests/BundleA/BundleA.wixproj create mode 100644 src/test/burn/TestData/ContainerTests/BundleA/BundleA.wxs create mode 100644 src/test/burn/TestData/ContainerTests/PackageA/PackageA.wixproj create mode 100644 src/test/burn/TestData/ContainerTests/PackageB/PackageB.wixproj create mode 100644 src/test/burn/WixToolsetTest.BurnE2E/ContainerTests.cs (limited to 'src') diff --git a/src/burn/engine/section.cpp b/src/burn/engine/section.cpp index 1fd6cce4..a9c7927e 100644 --- a/src/burn/engine/section.cpp +++ b/src/burn/engine/section.cpp @@ -26,7 +26,7 @@ typedef struct _BURN_SECTION_HEADER DWORD dwFormat; DWORD cContainers; - DWORD rgcbContainers[116]; + DWORD rgcbContainers[1]; } BURN_SECTION_HEADER; static HRESULT VerifySectionMatchesMemoryPEHeader( @@ -53,6 +53,7 @@ extern "C" HRESULT SectionInitialize( IMAGE_SECTION_HEADER sectionHeader = { }; DWORD_PTR dwOriginalChecksumAndSignatureOffset = 0; BURN_SECTION_HEADER* pBurnSectionHeader = NULL; + DWORD cMaxContainers = 0; pSection->hEngineFile = hEngineFile; ExitOnInvalidHandleWithLastError(pSection->hEngineFile, hr, "Failed to open handle to engine process path."); @@ -142,8 +143,7 @@ extern "C" HRESULT SectionInitialize( } if (sizeof(IMAGE_SECTION_HEADER) > cbRead) { - hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); - ExitOnRootFailure(hr, "Failed to read complete image section header, index: %u", i); + ExitWithRootFailure(hr, E_INVALIDDATA, "Failed to read complete image section header, index: %u", i); } // compare header name @@ -156,8 +156,7 @@ extern "C" HRESULT SectionInitialize( // fail if we hit the end if (i + 1 >= ntHeader.FileHeader.NumberOfSections) { - hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); - ExitOnRootFailure(hr, "Failed to find Burn section."); + ExitWithRootFailure(hr, E_INVALIDDATA, "Failed to find Burn section."); } } @@ -168,8 +167,7 @@ extern "C" HRESULT SectionInitialize( // check size of section if (sizeof(BURN_SECTION_HEADER) > sectionHeader.SizeOfRawData) { - hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); - ExitOnRootFailure(hr, "Failed to read section info, data to short: %u", sectionHeader.SizeOfRawData); + ExitWithRootFailure(hr, E_INVALIDDATA, "Failed to read section info, data too short: %u", sectionHeader.SizeOfRawData); } // allocate buffer for section info @@ -193,15 +191,19 @@ extern "C" HRESULT SectionInitialize( } else if (sectionHeader.SizeOfRawData > cbRead) { - hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); - ExitOnRootFailure(hr, "Failed to read complete section info."); + ExitWithRootFailure(hr, E_INVALIDDATA, "Failed to read complete section info."); } // validate version of section info if (BURN_SECTION_VERSION != pBurnSectionHeader->dwVersion) { - hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); - ExitOnRootFailure(hr, "Failed to read section info, unsupported version: %08x", pBurnSectionHeader->dwVersion); + ExitWithRootFailure(hr, E_INVALIDDATA, "Failed to read section info, unsupported version: %08x", pBurnSectionHeader->dwVersion); + } + + cMaxContainers = (sectionHeader.SizeOfRawData - offsetof(BURN_SECTION_HEADER, rgcbContainers)) / sizeof(DWORD); + if (cMaxContainers < pBurnSectionHeader->cContainers) + { + ExitWithRootFailure(hr, E_INVALIDDATA, "Invalid section info, cContainers too large: %u", pBurnSectionHeader->cContainers); } hr = FileSizeByHandle(pSection->hSourceEngineFile, &llSize); diff --git a/src/burn/stub/StubSection.cpp b/src/burn/stub/StubSection.cpp index 01b4b576..2191a138 100644 --- a/src/burn/stub/StubSection.cpp +++ b/src/burn/stub/StubSection.cpp @@ -18,5 +18,6 @@ static DWORD dwOriginalSignatureSize = 0; static DWORD dwContainerFormat = 1; static DWORD dwContainerCount = 0; -static DWORD qwAttachedContainerSizes[116]; // Including UX container +// (512 (minimum section size) - 48 (size of above data)) / 4 (size of DWORD) +static DWORD qwAttachedContainerSizes[116]; #pragma data_seg(pop) diff --git a/src/test/burn/TestData/ContainerTests/BundleA/BundleA.wixproj b/src/test/burn/TestData/ContainerTests/BundleA/BundleA.wixproj new file mode 100644 index 00000000..1c2f1651 --- /dev/null +++ b/src/test/burn/TestData/ContainerTests/BundleA/BundleA.wixproj @@ -0,0 +1,19 @@ + + + + Bundle + {16798DF3-C365-410D-B376-E63A961E4822} + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/ContainerTests/BundleA/BundleA.wxs b/src/test/burn/TestData/ContainerTests/BundleA/BundleA.wxs new file mode 100644 index 00000000..7933eca5 --- /dev/null +++ b/src/test/burn/TestData/ContainerTests/BundleA/BundleA.wxs @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/test/burn/TestData/ContainerTests/PackageA/PackageA.wixproj b/src/test/burn/TestData/ContainerTests/PackageA/PackageA.wixproj new file mode 100644 index 00000000..67dfd894 --- /dev/null +++ b/src/test/burn/TestData/ContainerTests/PackageA/PackageA.wixproj @@ -0,0 +1,10 @@ + + + + a + {D452A40D-27B2-41A1-A103-4FD5744B548E} + + + + + \ No newline at end of file diff --git a/src/test/burn/TestData/ContainerTests/PackageB/PackageB.wixproj b/src/test/burn/TestData/ContainerTests/PackageB/PackageB.wixproj new file mode 100644 index 00000000..6ef92662 --- /dev/null +++ b/src/test/burn/TestData/ContainerTests/PackageB/PackageB.wixproj @@ -0,0 +1,10 @@ + + + + b + {EB8E7A16-9855-4019-90D6-F5A242A75250} + + + + + \ No newline at end of file diff --git a/src/test/burn/WixToolsetTest.BurnE2E/ContainerTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/ContainerTests.cs new file mode 100644 index 00000000..cd6beaa9 --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/ContainerTests.cs @@ -0,0 +1,29 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.BurnE2E +{ + using Xunit; + using Xunit.Abstractions; + + public class ContainerTests : BurnE2ETests + { + public ContainerTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public void CanSupportMultipleAttachedContainers() + { + var packageA = this.CreatePackageInstaller("PackageA"); + var packageB = this.CreatePackageInstaller("PackageB"); + var bundleA = this.CreateBundleInstaller("BundleA"); + + packageA.VerifyInstalled(false); + packageB.VerifyInstalled(false); + + bundleA.Install(); + bundleA.VerifyRegisteredAndInPackageCache(); + + packageA.VerifyInstalled(true); + packageB.VerifyInstalled(true); + } + } +} diff --git a/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs b/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs index a60d3ddf..cd00232a 100644 --- a/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs @@ -296,13 +296,15 @@ namespace WixToolset.Core.Burn } // Give the embedded payloads without an embedded id yet an embedded id. + var payloadIndex = 0; foreach (var payload in payloadSymbols.Values) { Debug.Assert(PackagingType.Unknown != payload.Packaging); if (PackagingType.Embedded == payload.Packaging && String.IsNullOrEmpty(payload.EmbeddedId)) { - payload.EmbeddedId = Guid.NewGuid().ToString("N"); + payload.EmbeddedId = String.Format(CultureInfo.InvariantCulture, BurnCommon.BurnAuthoredContainerEmbeddedIdFormat, payloadIndex); + ++payloadIndex; } } } diff --git a/src/wix/WixToolset.Core.Burn/BundleBackend.cs b/src/wix/WixToolset.Core.Burn/BundleBackend.cs index 83572cda..518b77c8 100644 --- a/src/wix/WixToolset.Core.Burn/BundleBackend.cs +++ b/src/wix/WixToolset.Core.Burn/BundleBackend.cs @@ -67,7 +67,7 @@ namespace WixToolset.Core.Burn using (var reader = BurnReader.Open(messaging, context.InputFilePath)) { reader.ExtractUXContainer(uxExtractPath, context.IntermediateFolder); - reader.ExtractAttachedContainers(context.ExportBasePath); + reader.ExtractAttachedContainers(context.ExportBasePath, context.IntermediateFolder); } return null; diff --git a/src/wix/WixToolset.Core.Burn/Bundles/BurnCommon.cs b/src/wix/WixToolset.Core.Burn/Bundles/BurnCommon.cs index 6a9d7950..27fad5b3 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/BurnCommon.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/BurnCommon.cs @@ -20,6 +20,7 @@ namespace WixToolset.Core.Burn.Bundles { public const string BurnNamespace = "http://wixtoolset.org/schemas/v4/2008/Burn"; public const string BurnUXContainerEmbeddedIdFormat = "u{0}"; + public const string BurnAuthoredContainerEmbeddedIdFormat = "a{0}"; public const string BADataFileName = "BootstrapperApplicationData.xml"; public const string BADataNamespace = "http://wixtoolset.org/schemas/v4/BootstrapperApplicationData"; @@ -79,12 +80,11 @@ namespace WixToolset.Core.Burn.Bundles protected const UInt32 BURN_SECTION_OFFSET_COUNT = 44; protected const UInt32 BURN_SECTION_OFFSET_UXSIZE = 48; protected const UInt32 BURN_SECTION_OFFSET_ATTACHEDCONTAINERSIZE0 = 52; + protected const UInt32 BURN_SECTION_MIN_SIZE = BURN_SECTION_OFFSET_ATTACHEDCONTAINERSIZE0; protected const UInt32 BURN_SECTION_MAGIC = 0x00f14300; protected const UInt32 BURN_SECTION_VERSION = 0x00000003; protected const UInt32 BURN_SECTION_COMPATIBLE_VERSION = 0x00000002; - protected const UInt32 BURN_SECTION_SIZE = 512; - protected const UInt32 BURN_SECTION_MAX_ATTACHEDCONTAINER_COUNT = (BURN_SECTION_SIZE - BURN_SECTION_OFFSET_ATTACHEDCONTAINERSIZE0) / sizeof(UInt32); protected string fileExe; protected UInt32 peOffset = UInt32.MaxValue; @@ -94,6 +94,8 @@ namespace WixToolset.Core.Burn.Bundles protected UInt32 certificateTableSignatureOffset; protected UInt32 certificateTableSignatureSize; protected UInt32 wixburnDataOffset = UInt32.MaxValue; + protected UInt32 wixburnRawDataSize; + protected UInt32 wixburnMaxContainers; // TODO: does this enum exist in another form somewhere? /// @@ -127,9 +129,7 @@ namespace WixToolset.Core.Burn.Bundles public UInt32 OriginalSignatureOffset { get; protected set; } public UInt32 OriginalSignatureSize { get; protected set; } public UInt32 EngineSize { get; protected set; } - public UInt32 ContainerCount { get; protected set; } - public UInt32 UXAddress { get; protected set; } - public UInt32 UXSize { get; protected set; } + public UInt32 UXAddress { get { return this.StubSize; } } public List AttachedContainers { get; protected set; } protected IMessaging Messaging { get; } @@ -180,9 +180,7 @@ namespace WixToolset.Core.Burn.Bundles } reader.BaseStream.Seek(this.wixburnDataOffset, SeekOrigin.Begin); - List manifest = new List(); - manifest.AddRange(reader.ReadBytes((int)BURN_SECTION_SIZE)); - byte[] bytes = manifest.ToArray(); + byte[] bytes = reader.ReadBytes((int)this.wixburnRawDataSize); UInt32 uint32 = 0; uint32 = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_MAGIC); @@ -211,40 +209,37 @@ namespace WixToolset.Core.Burn.Bundles this.OriginalSignatureOffset = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_ORIGINALSIGNATUREOFFSET); this.OriginalSignatureSize = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_ORIGINALSIGNATURESIZE); - this.ContainerCount = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_COUNT); - if (BURN_SECTION_MAX_ATTACHEDCONTAINER_COUNT < this.ContainerCount) + uint containerCount = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_COUNT); + uint uxSize = 0; + if (this.wixburnMaxContainers < containerCount) { this.Messaging.Write(ErrorMessages.InvalidBundle(this.fileExe)); return false; } - this.UXAddress = this.StubSize; - this.UXSize = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_UXSIZE); + else if (containerCount > 0) + { + this.AttachedContainers.Clear(); + for (uint i = 0; i < containerCount; ++i) + { + uint sizeOffset = BURN_SECTION_OFFSET_UXSIZE + (i * 4); + uint size = BurnCommon.ReadUInt32(bytes, sizeOffset); + this.AttachedContainers.Add(new ContainerSlot(size)); + } + uxSize = this.AttachedContainers[0].Size; + } // If there is an original signature use that to determine the engine size. if (0 < this.OriginalSignatureOffset) { this.EngineSize = this.OriginalSignatureOffset + this.OriginalSignatureSize; } - else if (0 < this.SignatureOffset && 2 > this.ContainerCount) // if there is a signature and no attached containers, use the current signature. + else if (0 < this.SignatureOffset && 2 > containerCount) // if there is a signature and no attached containers, use the current signature. { this.EngineSize = this.SignatureOffset + this.SignatureSize; } else // just use the stub and UX container as the size of the engine. { - this.EngineSize = this.StubSize + this.UXSize; - } - - this.AttachedContainers.Clear(); - uint nextAddress = this.EngineSize; - if (this.ContainerCount > 1) - { - for (uint i = 0; i < (this.ContainerCount - 1 /* Excluding UX */); ++i) - { - uint sizeOffset = BURN_SECTION_OFFSET_ATTACHEDCONTAINERSIZE0 + (i * 4); - uint size = BurnCommon.ReadUInt32(bytes, sizeOffset); - this.AttachedContainers.Add(new ContainerSlot(nextAddress, size)); - nextAddress += size; - } + this.EngineSize = this.UXAddress + uxSize; } return true; @@ -288,13 +283,17 @@ namespace WixToolset.Core.Burn.Bundles return false; } - // We need 512 bytes for the manifest header - if (BURN_SECTION_SIZE > BurnCommon.ReadUInt32(bytes, IMAGE_SECTION_HEADER_OFFSET_SIZEOFRAWDATA)) + this.wixburnRawDataSize = BurnCommon.ReadUInt32(bytes, IMAGE_SECTION_HEADER_OFFSET_SIZEOFRAWDATA); + + // we need 52 bytes for the manifest header, which is always going to fit in + // the smallest alignment (512 bytes), but just to be paranoid... + if (BURN_SECTION_MIN_SIZE > this.wixburnRawDataSize) { this.Messaging.Write(ErrorMessages.StubWixburnSectionTooSmall(this.fileExe)); return false; } + this.wixburnMaxContainers = (this.wixburnRawDataSize - BURN_SECTION_OFFSET_UXSIZE) / sizeof(UInt32); this.wixburnDataOffset = BurnCommon.ReadUInt32(bytes, IMAGE_SECTION_HEADER_OFFSET_POINTERTORAWDATA); } @@ -404,13 +403,11 @@ namespace WixToolset.Core.Burn.Bundles internal struct ContainerSlot { - public ContainerSlot(uint address, uint size) : this() + public ContainerSlot(uint size) : this() { - this.Address = address; this.Size = size; } - public uint Address { get; set; } public uint Size { get; set; } } } diff --git a/src/wix/WixToolset.Core.Burn/Bundles/BurnReader.cs b/src/wix/WixToolset.Core.Burn/Bundles/BurnReader.cs index e3fd9f51..575252b0 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/BurnReader.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/BurnReader.cs @@ -78,7 +78,7 @@ namespace WixToolset.Core.Burn.Bundles public bool ExtractUXContainer(string outputDirectory, string tempDirectory) { // No UX container to extract - if (this.UXAddress == 0 || this.UXSize == 0) + if (this.AttachedContainers.Count == 0) { return false; } @@ -92,11 +92,12 @@ namespace WixToolset.Core.Burn.Bundles string tempCabPath = Path.Combine(tempDirectory, "ux.cab"); string manifestOriginalPath = Path.Combine(outputDirectory, "0"); string manifestPath = Path.Combine(outputDirectory, "manifest.xml"); + var uxContainerSlot = this.AttachedContainers[0]; this.binaryReader.BaseStream.Seek(this.UXAddress, SeekOrigin.Begin); using (Stream tempCab = File.Open(tempCabPath, FileMode.Create, FileAccess.Write)) { - BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)this.UXSize); + BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)uxContainerSlot.Size); } var cabinet = new Cabinet(tempCabPath); @@ -152,14 +153,15 @@ namespace WixToolset.Core.Burn.Bundles } /// - /// Gets the attached container from the exe and extracts its contents to the output directory. + /// Gets each non-UX attached container from the exe and extracts its contents to the output directory. /// /// Directory to write extracted files to. + /// Scratch directory. /// True if successful, false otherwise - public bool ExtractAttachedContainers(string outputDirectory) + public bool ExtractAttachedContainers(string outputDirectory, string tempDirectory) { - // No attached container to extract - if (this.AttachedContainers.Count == 0) + // No attached containers to extract + if (this.AttachedContainers.Count < 2) { return false; } @@ -170,11 +172,13 @@ namespace WixToolset.Core.Burn.Bundles } Directory.CreateDirectory(outputDirectory); - foreach (ContainerSlot cntnr in this.AttachedContainers) + uint nextAddress = this.EngineSize; + for (int i = 1; i < this.AttachedContainers.Count; i++) { - string tempCabPath = Path.GetTempFileName(); + ContainerSlot cntnr = this.AttachedContainers[i]; + string tempCabPath = Path.Combine(tempDirectory, $"a{i}.cab"); - this.binaryReader.BaseStream.Seek(cntnr.Address, SeekOrigin.Begin); + this.binaryReader.BaseStream.Seek(nextAddress, SeekOrigin.Begin); using (Stream tempCab = File.Open(tempCabPath, FileMode.Create, FileAccess.Write)) { BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)cntnr.Size); @@ -182,6 +186,8 @@ namespace WixToolset.Core.Burn.Bundles var cabinet = new Cabinet(tempCabPath); cabinet.Extract(outputDirectory); + + nextAddress += cntnr.Size; } foreach (DictionaryEntry entry in this.attachedContainerPayloadNames) diff --git a/src/wix/WixToolset.Core.Burn/Bundles/BurnWriter.cs b/src/wix/WixToolset.Core.Burn/Bundles/BurnWriter.cs index c6419ba9..46835974 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/BurnWriter.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/BurnWriter.cs @@ -91,9 +91,9 @@ namespace WixToolset.Core.Burn.Bundles this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_ORIGINALSIGNATUREOFFSET, 0); this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_ORIGINALSIGNATURESIZE, 0); this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_FORMAT, 1); // Hard-coded to CAB for now. + this.AttachedContainers.Clear(); this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_COUNT, 0); - this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_UXSIZE, 0); - for (uint i = BURN_SECTION_OFFSET_ATTACHEDCONTAINERSIZE0; i < BURN_SECTION_SIZE; i += sizeof(UInt32)) + for (uint i = BURN_SECTION_OFFSET_UXSIZE; i < this.wixburnMaxContainers; i += sizeof(UInt32)) { this.WriteToBurnSectionOffset(i, 0); } @@ -118,6 +118,39 @@ namespace WixToolset.Core.Burn.Bundles } } + /// + /// Appends the non-UX attached containers from the reader to this bundle. + /// + /// The source bundle. + /// true if the container data is successfully appended; false otherwise. + public bool ReattachContainers(BurnReader reader) + { + if (this.AttachedContainers.Count == 0 || reader.AttachedContainers.Count < 2) + { + return false; + } + + this.RememberThenResetSignature(); + + var uxContainerSlot = this.AttachedContainers[0]; + this.AttachedContainers.Clear(); + this.AttachedContainers.Add(uxContainerSlot); + + uint nextAddress = this.EngineSize; + for (int i = 1; i < reader.AttachedContainers.Count; i++) + { + ContainerSlot cntnr = reader.AttachedContainers[i]; + + reader.Stream.Seek(nextAddress, SeekOrigin.Begin); + // TODO: verify that the size in the section data is 0 or the same size. + this.AppendContainer(reader.Stream, cntnr.Size, BurnCommon.Container.Attached); + + nextAddress += cntnr.Size; + } + + return true; + } + /// /// Appends a UX or Attached container to the exe and updates the ".wixburn" section data to point to it. /// @@ -127,38 +160,23 @@ namespace WixToolset.Core.Burn.Bundles /// true if the container data is successfully appended; false otherwise public bool AppendContainer(Stream containerStream, long containerSize, BurnCommon.Container container) { - UInt32 burnSectionCount = 0; - UInt32 burnSectionOffsetSize = 0; - - if (containerSize == 0) - { - return false; - } + uint containerCount = (uint)this.AttachedContainers.Count; + uint burnSectionOffsetSize = BURN_SECTION_OFFSET_UXSIZE + (containerCount * sizeof(UInt32)); + var containerSlot = new ContainerSlot((uint)containerSize); switch (container) { case Container.UX: - burnSectionCount = 1; - burnSectionOffsetSize = BURN_SECTION_OFFSET_UXSIZE; - // TODO: verify that the size in the section data is 0 or the same size. - this.EngineSize += (uint)containerSize; - this.UXSize = (uint)containerSize; - break; - - case Container.Attached: - // TODO: verify that the size in the section data is 0 or the same size. - uint nextAddress = this.EngineSize; - foreach (ContainerSlot cntnr in this.AttachedContainers) + if (containerCount != 0) { - if (cntnr.Address >= nextAddress) - { - nextAddress = cntnr.Address + cntnr.Size; - } + Debug.Assert(false); + return false; } - this.AttachedContainers.Add(new ContainerSlot(nextAddress, (uint)containerSize)); - burnSectionCount = 1 + (uint)this.AttachedContainers.Count; - burnSectionOffsetSize = BURN_SECTION_OFFSET_UXSIZE + ((uint)this.AttachedContainers.Count * 4); + this.EngineSize += containerSlot.Size; + break; + + case Container.Attached: break; default: @@ -166,7 +184,9 @@ namespace WixToolset.Core.Burn.Bundles return false; } - return this.AppendContainer(containerStream, (UInt32)containerSize, burnSectionOffsetSize, burnSectionCount); + this.AttachedContainers.Add(containerSlot); + ++containerCount; + return this.AppendContainer(containerStream, containerSlot.Size, burnSectionOffsetSize, containerCount); } public void RememberThenResetSignature() @@ -225,10 +245,10 @@ namespace WixToolset.Core.Burn.Bundles { return false; } - if (burnSectionOffsetSize > (BURN_SECTION_SIZE - sizeof(UInt32))) + if (burnSectionOffsetSize > (this.wixburnRawDataSize - sizeof(UInt32))) { this.invalidBundle = true; - this.Messaging.Write(BurnBackendErrors.TooManyAttachedContainers(BURN_SECTION_MAX_ATTACHEDCONTAINER_COUNT)); + this.Messaging.Write(BurnBackendErrors.TooManyAttachedContainers(this.wixburnMaxContainers)); return false; } diff --git a/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleCommand.cs b/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleCommand.cs index 17030dd3..f835fd3a 100644 --- a/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleCommand.cs @@ -31,22 +31,7 @@ namespace WixToolset.Core.Burn.Inscribe FileSystem.CopyFile(this.Context.SignedEngineFile, tempFile, allowHardlink: false); using (BurnWriter writer = BurnWriter.Open(this.Messaging, tempFile)) { - if (reader.Version != writer.Version) - { - this.Messaging.Write(BurnBackendErrors.IncompatibleWixBurnSection(this.Context.InputFilePath, reader.Version)); - } - - writer.AttachedContainers.Clear(); - writer.RememberThenResetSignature(); - foreach (ContainerSlot cntnr in reader.AttachedContainers) - { - if (cntnr.Size > 0) - { - reader.Stream.Seek(cntnr.Address, SeekOrigin.Begin); - writer.AppendContainer(reader.Stream, cntnr.Size, BurnCommon.Container.Attached); - inscribed = true; - } - } + inscribed = writer.ReattachContainers(reader); } } diff --git a/src/wix/WixToolset.Core.TestPackage/BundleExtractor.cs b/src/wix/WixToolset.Core.TestPackage/BundleExtractor.cs index affe8c17..bd13a9b2 100644 --- a/src/wix/WixToolset.Core.TestPackage/BundleExtractor.cs +++ b/src/wix/WixToolset.Core.TestPackage/BundleExtractor.cs @@ -21,44 +21,48 @@ namespace WixToolset.Core.TestPackage /// Temp path for extraction. /// public static ExtractBAContainerResult ExtractBAContainer(IMessaging messaging, string bundleFilePath, string destinationFolderPath, string tempFolderPath) + { + return ExtractAllContainers(messaging, bundleFilePath, destinationFolderPath, null, tempFolderPath); + } + + /// + /// Extracts the BA container. + /// + /// + /// Path to the bundle. + /// Path to extract BA to. + /// Path to extract other attached containers to. + /// Temp path for extraction. + /// + public static ExtractBAContainerResult ExtractAllContainers(IMessaging messaging, string bundleFilePath, string baFolderPath, string otherContainersFolderPath, string tempFolderPath) { var result = new ExtractBAContainerResult(); Directory.CreateDirectory(tempFolderPath); using (var burnReader = BurnReader.Open(messaging, bundleFilePath)) { - result.Success = burnReader.ExtractUXContainer(destinationFolderPath, tempFolderPath); + result.Success = burnReader.ExtractUXContainer(baFolderPath, tempFolderPath); + + if (otherContainersFolderPath != null) + { + result.AttachedContainersSuccess = burnReader.ExtractAttachedContainers(otherContainersFolderPath, tempFolderPath); + } } if (result.Success) { - result.ManifestDocument = LoadBurnManifest(destinationFolderPath); + result.ManifestDocument = LoadBurnManifest(baFolderPath); result.ManifestNamespaceManager = GetBurnNamespaceManager(result.ManifestDocument, "burn"); - result.BADataDocument = LoadBAData(destinationFolderPath); + result.BADataDocument = LoadBAData(baFolderPath); result.BADataNamespaceManager = GetBADataNamespaceManager(result.BADataDocument, "ba"); - result.BundleExtensionDataDocument = LoadBundleExtensionData(destinationFolderPath); + result.BundleExtensionDataDocument = LoadBundleExtensionData(baFolderPath); result.BundleExtensionDataNamespaceManager = GetBundleExtensionDataNamespaceManager(result.BundleExtensionDataDocument, "be"); } return result; } - /// - /// Extracts the attached container. - /// - /// - /// Path to the bundle. - /// Path to extract to. - /// True if there was an attached container. - public static bool ExtractAttachedContainers(IMessaging messaging, string bundleFilePath, string destinationFolderPath) - { - using (var burnReader = BurnReader.Open(messaging, bundleFilePath)) - { - return burnReader.ExtractAttachedContainers(destinationFolderPath); - } - } - /// /// Gets an for BootstrapperApplicationData.xml with the given prefix assigned to the root namespace. /// diff --git a/src/wix/WixToolset.Core.TestPackage/ExtractBAContainerResult.cs b/src/wix/WixToolset.Core.TestPackage/ExtractBAContainerResult.cs index 277861ff..65528fe0 100644 --- a/src/wix/WixToolset.Core.TestPackage/ExtractBAContainerResult.cs +++ b/src/wix/WixToolset.Core.TestPackage/ExtractBAContainerResult.cs @@ -46,6 +46,11 @@ namespace WixToolset.Core.TestPackage /// public bool Success { get; set; } + /// + /// Whether attached containers extraction succeeded. + /// + public bool? AttachedContainersSuccess { get; set; } + /// /// /// @@ -53,6 +58,7 @@ namespace WixToolset.Core.TestPackage public ExtractBAContainerResult AssertSuccess() { Assert.True(this.Success); + Assert.True(!this.AttachedContainersSuccess.HasValue || this.AttachedContainersSuccess.Value); return this; } diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/BundleFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/BundleFixture.cs index 3491def9..10d9a39a 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/BundleFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/BundleFixture.cs @@ -125,8 +125,8 @@ namespace WixToolsetTest.CoreIntegration var msiPayloads = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Payload[@Id='test.msi']"); var msiPayload = (XmlNode)Assert.Single(msiPayloads); - Assert.Equal("", - msiPayload.GetTestXml(new Dictionary>() { { "Payload", new List { "FileSize", "Hash", "SourcePath" } } })); + Assert.Equal("", + msiPayload.GetTestXml(new Dictionary>() { { "Payload", new List { "FileSize", "Hash" } } })); } var manifestResource = new Resource(ResourceType.Manifest, "#1", 1033); @@ -156,6 +156,7 @@ namespace WixToolsetTest.CoreIntegration var exePath = Path.Combine(baseFolder, @"bin\test.exe"); var pdbPath = Path.Combine(baseFolder, @"bin\test.wixpdb"); var baFolderPath = Path.Combine(baseFolder, "ba"); + var attachedFolderPath = Path.Combine(baseFolder, "attached"); var extractFolderPath = Path.Combine(baseFolder, "extract"); var result = WixRunner.Execute(false, new[] // TODO: go back to elevating warnings as errors. @@ -186,6 +187,9 @@ namespace WixToolsetTest.CoreIntegration "" + "true/pmPerMonitorV2, PerMonitor" + "", actualManifestData); + + var extractResult = BundleExtractor.ExtractAllContainers(null, exePath, baFolderPath, attachedFolderPath, extractFolderPath); + extractResult.AssertSuccess(); } } diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/ContainerFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/ContainerFixture.cs index 6e6f44be..482a6edd 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/ContainerFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/ContainerFixture.cs @@ -49,11 +49,11 @@ namespace WixToolsetTest.CoreIntegration var payloads = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Payload"); Assert.Equal(4, payloads.Count); - var ignoreAttributes = new Dictionary> { { "Payload", new List { "FileSize", "Hash", "SourcePath" } } }; - Assert.Equal(@"", payloads[0].GetTestXml(ignoreAttributes)); - Assert.Equal(@"", payloads[1].GetTestXml(ignoreAttributes)); - Assert.Equal(@"", payloads[2].GetTestXml(ignoreAttributes)); - Assert.Equal(@"", payloads[3].GetTestXml(ignoreAttributes)); + var ignoreAttributes = new Dictionary> { { "Payload", new List { "FileSize", "Hash" } } }; + Assert.Equal(@"", payloads[0].GetTestXml(ignoreAttributes)); + Assert.Equal(@"", payloads[1].GetTestXml(ignoreAttributes)); + Assert.Equal(@"", payloads[2].GetTestXml(ignoreAttributes)); + Assert.Equal(@"", payloads[3].GetTestXml(ignoreAttributes)); } } @@ -93,11 +93,11 @@ namespace WixToolsetTest.CoreIntegration var payloads = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Payload"); Assert.Equal(4, payloads.Count); - var ignoreAttributes = new Dictionary> { { "Payload", new List { "FileSize", "Hash", "SourcePath" } } }; - Assert.Equal(@"", payloads[0].GetTestXml(ignoreAttributes)); - Assert.Equal(@"", payloads[1].GetTestXml(ignoreAttributes)); - Assert.Equal(@"", payloads[2].GetTestXml(ignoreAttributes)); - Assert.Equal(@"", payloads[3].GetTestXml(ignoreAttributes)); + var ignoreAttributes = new Dictionary> { { "Payload", new List { "FileSize", "Hash" } } }; + Assert.Equal(@"", payloads[0].GetTestXml(ignoreAttributes)); + Assert.Equal(@"", payloads[1].GetTestXml(ignoreAttributes)); + Assert.Equal(@"", payloads[2].GetTestXml(ignoreAttributes)); + Assert.Equal(@"", payloads[3].GetTestXml(ignoreAttributes)); } } @@ -203,14 +203,14 @@ namespace WixToolsetTest.CoreIntegration var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath); extractResult.AssertSuccess(); - var ignoreAttributes = new Dictionary> { { "Payload", new List { "FileSize", "Hash", "SourcePath" } } }; + var ignoreAttributes = new Dictionary> { { "Payload", new List { "FileSize", "Hash" } } }; var payloads = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Payload[@Id='SharedPayload']") .Cast() .Select(e => e.GetTestXml(ignoreAttributes)) .ToArray(); WixAssert.CompareLineByLine(new string[] { - "", + "", }, payloads); } } @@ -227,8 +227,8 @@ namespace WixToolsetTest.CoreIntegration var binFolder = Path.Combine(baseFolder, "bin"); var bundlePath = Path.Combine(binFolder, "test.exe"); var baFolderPath = Path.Combine(baseFolder, "ba"); + var attachedFolderPath = Path.Combine(baseFolder, "attached"); var extractFolderPath = Path.Combine(baseFolder, "extract"); - var tempFolderPath = Path.Combine(baseFolder, "temp"); this.BuildMsis(folder, intermediateFolder, binFolder); @@ -243,19 +243,27 @@ namespace WixToolsetTest.CoreIntegration "-o", bundlePath }); - Assert.Equal(0, result.ExitCode); + result.AssertSuccess(); Assert.True(File.Exists(bundlePath)); - Directory.CreateDirectory(tempFolderPath); - using (var burnReader = BurnReader.Open(null, bundlePath)) - { - // Extract the BA because that loads the payload target paths from the manifest - Assert.True(burnReader.ExtractUXContainer(baFolderPath, tempFolderPath)); - Assert.True(burnReader.ExtractAttachedContainers(extractFolderPath)); - } + var extractResult = BundleExtractor.ExtractAllContainers(null, bundlePath, baFolderPath, attachedFolderPath, extractFolderPath); + extractResult.AssertSuccess(); - Assert.True(File.Exists(Path.Combine(extractFolderPath, "FirstX64", "FirstX64.msi")), "Expected extracted container to contain FirstX64.msi"); - Assert.True(File.Exists(Path.Combine(extractFolderPath, "WixAttachedContainer", "FirstX86.msi")), "Expected extracted container to contain FirstX86.msi"); + Assert.True(File.Exists(Path.Combine(attachedFolderPath, "FirstX64", "FirstX64.msi")), "Expected extracted container to contain FirstX64.msi"); + Assert.True(File.Exists(Path.Combine(attachedFolderPath, "WixAttachedContainer", "FirstX86.msi")), "Expected extracted container to contain FirstX86.msi"); + + var ignoreAttributes = new Dictionary> { { "Payload", new List { "FileSize", "Hash" } } }; + var payloads = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Payload") + .Cast() + .Select(e => e.GetTestXml(ignoreAttributes)) + .ToArray(); + WixAssert.CompareLineByLine(new string[] + { + "", + "", + "", + "", + }, payloads); } } @@ -297,14 +305,14 @@ namespace WixToolsetTest.CoreIntegration var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath); extractResult.AssertSuccess(); - var ignoreAttributes = new Dictionary> { { "Payload", new List { "FileSize", "Hash", "SourcePath" } } }; + var ignoreAttributes = new Dictionary> { { "Payload", new List { "FileSize", "Hash" } } }; var payloads = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Payload[@Id='SharedPayload']") .Cast() .Select(e => e.GetTestXml(ignoreAttributes)) .ToArray(); WixAssert.CompareLineByLine(new string[] { - "", + "", }, payloads); } } diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs index cbd1f32f..6b2d8bfa 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs @@ -46,14 +46,13 @@ namespace WixToolsetTest.CoreIntegration var ignoreAttributesByElementName = new Dictionary> { { "ExePackage", new List { "CacheId", "InstallSize", "Size" } }, - { "Payload", new List { "SourcePath" } }, }; Assert.Equal(1, exePackageElements.Count); Assert.Equal("", exePackageElements[0].GetTestXml(ignoreAttributesByElementName)); var payloadElements = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Payload[@Id='burn.exe']"); Assert.Equal(1, payloadElements.Count); - Assert.Equal("", payloadElements[0].GetTestXml(ignoreAttributesByElementName)); + Assert.Equal("", payloadElements[0].GetTestXml()); } } diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/PayloadFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/PayloadFixture.cs index 1e6fd0e3..cb35976a 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/PayloadFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/PayloadFixture.cs @@ -189,15 +189,14 @@ namespace WixToolsetTest.CoreIntegration .Cast() .Select(e => e.GetTestXml(ignoreAttributesByElementName)) .ToArray(); - - var ignoreAttributes = new Dictionary> { { "Payload", new List { "FileSize", "Hash"} } }; - var ignoreAttributesWithSrc = new Dictionary> { { "Payload", new List { "FileSize", "Hash", "SourcePath" } } }; - Assert.Equal(5, payloads.Length); - Assert.Equal(@"", payloads[0].GetTestXml(ignoreAttributesWithSrc)); - Assert.Equal(@"", payloads[1].GetTestXml(ignoreAttributes)); - Assert.Equal(@"", payloads[2].GetTestXml(ignoreAttributes)); - Assert.Equal(@"", payloads[3].GetTestXml(ignoreAttributes)); - Assert.Equal(@"", payloads[4].GetTestXml(ignoreAttributes)); + WixAssert.CompareLineByLine(new string[] + { + "", + "", + "", + @"", + @"", + }, payloads); var containers = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Container") .Cast() -- cgit v1.2.3-55-g6feb