diff options
Diffstat (limited to '')
5 files changed, 184 insertions, 0 deletions
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs index 28b95810..5b5221fa 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs | |||
| @@ -345,6 +345,17 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
| 345 | } | 345 | } |
| 346 | } | 346 | } |
| 347 | 347 | ||
| 348 | if (SectionType.Product == section.Type) | ||
| 349 | { | ||
| 350 | var command = new ValidateWindowsInstallerProductConstraints(this.Messaging, section); | ||
| 351 | command.Execute(); | ||
| 352 | |||
| 353 | if (this.Messaging.EncounteredError) | ||
| 354 | { | ||
| 355 | return null; | ||
| 356 | } | ||
| 357 | } | ||
| 358 | |||
| 348 | // Set generated component guids and validate all guids. | 359 | // Set generated component guids and validate all guids. |
| 349 | { | 360 | { |
| 350 | var command = new FinalizeComponentGuids(this.Messaging, this.WindowsInstallerBackendHelper, this.PathResolver, section, platform); | 361 | var command = new FinalizeComponentGuids(this.Messaging, this.WindowsInstallerBackendHelper, this.PathResolver, section, platform); |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ValidateWindowsInstallerProductConstraints.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ValidateWindowsInstallerProductConstraints.cs new file mode 100644 index 00000000..87e18a36 --- /dev/null +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ValidateWindowsInstallerProductConstraints.cs | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | // 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. | ||
| 2 | |||
| 3 | namespace WixToolset.Core.WindowsInstaller.Bind | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.Collections.Generic; | ||
| 7 | using System.IO; | ||
| 8 | using System.Linq; | ||
| 9 | using WixToolset.Data; | ||
| 10 | using WixToolset.Data.Symbols; | ||
| 11 | using WixToolset.Extensibility.Data; | ||
| 12 | using WixToolset.Extensibility.Services; | ||
| 13 | |||
| 14 | /// <summary> | ||
| 15 | /// Set the guids for components with generatable guids and validate all are appropriately unique. | ||
| 16 | /// </summary> | ||
| 17 | internal class ValidateWindowsInstallerProductConstraints | ||
| 18 | { | ||
| 19 | private const int MaximumAllowedComponentsInMsi = 65536; | ||
| 20 | private const int MaximumAllowedFeatureDepthInMsi = 16; | ||
| 21 | |||
| 22 | internal ValidateWindowsInstallerProductConstraints(IMessaging messaging, IntermediateSection section) | ||
| 23 | { | ||
| 24 | this.Messaging = messaging; | ||
| 25 | this.Section = section; | ||
| 26 | } | ||
| 27 | |||
| 28 | private IMessaging Messaging { get; } | ||
| 29 | |||
| 30 | private IntermediateSection Section { get; } | ||
| 31 | |||
| 32 | public void Execute() | ||
| 33 | { | ||
| 34 | var componentCount = this.Section.Symbols.OfType<ComponentSymbol>().Count(); | ||
| 35 | var featuresWithParent = this.Section.Symbols.OfType<FeatureSymbol>().ToDictionary(f => f.Id.Id, f => f.ParentFeatureRef); | ||
| 36 | var featuresWithDepth = new Dictionary<string, int>(); | ||
| 37 | |||
| 38 | if (componentCount > MaximumAllowedComponentsInMsi) | ||
| 39 | { | ||
| 40 | this.Messaging.Write(WindowsInstallerBackendErrors.ExceededMaximumAllowedComponentsInMsi(MaximumAllowedComponentsInMsi, componentCount)); | ||
| 41 | } | ||
| 42 | |||
| 43 | foreach (var featureSymbol in this.Section.Symbols.OfType<FeatureSymbol>()) | ||
| 44 | { | ||
| 45 | var featureDepth = CalculateFeaturesDepth(featureSymbol.Id.Id, featuresWithParent, featuresWithDepth); | ||
| 46 | |||
| 47 | if (featureDepth > MaximumAllowedFeatureDepthInMsi) | ||
| 48 | { | ||
| 49 | this.Messaging.Write(WindowsInstallerBackendErrors.ExceededMaximumAllowedFeatureDepthInMsi(featureSymbol.SourceLineNumbers, MaximumAllowedFeatureDepthInMsi, featureSymbol.Id.Id, featureDepth)); | ||
| 50 | } | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | private static int CalculateFeaturesDepth(string id, Dictionary<string, string> featuresWithParent, Dictionary<string, int> featuresWithDepth) | ||
| 55 | { | ||
| 56 | if (featuresWithDepth.TryGetValue(id, out var featureDepth)) | ||
| 57 | { | ||
| 58 | return featureDepth; | ||
| 59 | } | ||
| 60 | |||
| 61 | var parentId = featuresWithParent[id]; | ||
| 62 | if (!String.IsNullOrEmpty(parentId)) | ||
| 63 | { | ||
| 64 | var parentDepth = CalculateFeaturesDepth(parentId, featuresWithParent, featuresWithDepth); | ||
| 65 | |||
| 66 | featureDepth = parentDepth + 1; | ||
| 67 | } | ||
| 68 | else | ||
| 69 | { | ||
| 70 | featureDepth = 1; | ||
| 71 | } | ||
| 72 | |||
| 73 | featuresWithDepth.Add(id, featureDepth); | ||
| 74 | |||
| 75 | return featureDepth; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | } | ||
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerBackendErrors.cs b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerBackendErrors.cs index 57b7181b..4f7cf5dc 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerBackendErrors.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerBackendErrors.cs | |||
| @@ -14,6 +14,16 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 14 | return Message(sourceLineNumbers, Ids.CannotLoadWixoutAsTransform, "Could not load wixout file as a transform{1}", additionalDetail); | 14 | return Message(sourceLineNumbers, Ids.CannotLoadWixoutAsTransform, "Could not load wixout file as a transform{1}", additionalDetail); |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | internal static Message ExceededMaximumAllowedComponentsInMsi(int maximumAllowedComponentsInMsi, int componentCount) | ||
| 18 | { | ||
| 19 | return Message(null, Ids.ExceededMaximumAllowedComponentsInMsi, "Maximum number of Components allowed in an MSI was exceeded. An MSI cannot contain more than {0} Components. The MSI contains {1} Components.", maximumAllowedComponentsInMsi, componentCount); | ||
| 20 | } | ||
| 21 | |||
| 22 | internal static Message ExceededMaximumAllowedFeatureDepthInMsi(SourceLineNumber sourceLineNumbers, int maximumAllowedFeatureDepthInMsi, string featureId, int featureDepth) | ||
| 23 | { | ||
| 24 | return Message(sourceLineNumbers, Ids.ExceededMaximumAllowedFeatureDepthInMsi, "Maximum depth of the Feature tree allowed in an MSI was exceeded. An MSI does not support a Feature tree with depth greater than {0}. The Feature '{1}' is at depth {2}.", maximumAllowedFeatureDepthInMsi, featureId, featureDepth); | ||
| 25 | } | ||
| 26 | |||
| 17 | public static Message InvalidModuleVersion(SourceLineNumber originalLineNumber, string version) | 27 | public static Message InvalidModuleVersion(SourceLineNumber originalLineNumber, string version) |
| 18 | { | 28 | { |
| 19 | return Message(originalLineNumber, Ids.InvalidModuleVersion, "The Module/@Version was not be able to be used as a four-part version. A valid four-part version has a max value of \"65535.65535.65535.65535\" and must be all numeric.", version); | 29 | return Message(originalLineNumber, Ids.InvalidModuleVersion, "The Module/@Version was not be able to be used as a four-part version. A valid four-part version has a max value of \"65535.65535.65535.65535\" and must be all numeric.", version); |
| @@ -28,6 +38,8 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 28 | { | 38 | { |
| 29 | CannotLoadWixoutAsTransform = 7500, | 39 | CannotLoadWixoutAsTransform = 7500, |
| 30 | InvalidModuleVersion = 7501, | 40 | InvalidModuleVersion = 7501, |
| 41 | ExceededMaximumAllowedComponentsInMsi = 7502, | ||
| 42 | ExceededMaximumAllowedFeatureDepthInMsi = 7503, | ||
| 31 | } // last available is 7999. 8000 is BurnBackendErrors. | 43 | } // last available is 7999. 8000 is BurnBackendErrors. |
| 32 | } | 44 | } |
| 33 | } | 45 | } |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/FeatureFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/FeatureFixture.cs index f70db559..d23e37f6 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/FeatureFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/FeatureFixture.cs | |||
| @@ -32,6 +32,8 @@ namespace WixToolsetTest.CoreIntegration | |||
| 32 | "-o", msiPath | 32 | "-o", msiPath |
| 33 | }); | 33 | }); |
| 34 | 34 | ||
| 35 | Assert.Equal(267, result.ExitCode); | ||
| 36 | |||
| 35 | var errors = result.Messages.Where(m => m.Level == MessageLevel.Error); | 37 | var errors = result.Messages.Where(m => m.Level == MessageLevel.Error); |
| 36 | Assert.Equal(new[] | 38 | Assert.Equal(new[] |
| 37 | { | 39 | { |
| @@ -39,5 +41,36 @@ namespace WixToolsetTest.CoreIntegration | |||
| 39 | }, errors.Select(e => e.Id).ToArray()); | 41 | }, errors.Select(e => e.Id).ToArray()); |
| 40 | } | 42 | } |
| 41 | } | 43 | } |
| 44 | |||
| 45 | [Fact] | ||
| 46 | public void CannotBuildMsiWithTooLargeFeatureDepth() | ||
| 47 | { | ||
| 48 | var folder = TestData.Get(@"TestData"); | ||
| 49 | |||
| 50 | using (var fs = new DisposableFileSystem()) | ||
| 51 | { | ||
| 52 | var baseFolder = fs.GetFolder(); | ||
| 53 | var intermediateFolder = Path.Combine(baseFolder, "obj"); | ||
| 54 | var msiPath = Path.Combine(baseFolder, @"bin\test.msi"); | ||
| 55 | |||
| 56 | var result = WixRunner.Execute(new[] | ||
| 57 | { | ||
| 58 | "build", | ||
| 59 | Path.Combine(folder, "Feature", "PackageWithExcessiveFeatureDepth.wxs"), | ||
| 60 | "-bindpath", Path.Combine(folder, "SingleFile", "data"), | ||
| 61 | "-intermediateFolder", intermediateFolder, | ||
| 62 | "-o", msiPath | ||
| 63 | }); | ||
| 64 | |||
| 65 | Assert.Equal(7503, result.ExitCode); | ||
| 66 | |||
| 67 | var errors = result.Messages.Where(m => m.Level == MessageLevel.Error); | ||
| 68 | Assert.Equal(new[] | ||
| 69 | { | ||
| 70 | 7503 | ||
| 71 | }, errors.Select(e => e.Id).ToArray()); | ||
| 72 | Assert.Equal("Maximum depth of the Feature tree allowed in an MSI was exceeded. An MSI does not support a Feature tree with depth greater than 16. The Feature 'Depth17' is at depth 17.", errors.Single().ToString()); | ||
| 73 | } | ||
| 74 | } | ||
| 42 | } | 75 | } |
| 43 | } | 76 | } |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Feature/PackageWithExcessiveFeatureDepth.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Feature/PackageWithExcessiveFeatureDepth.wxs new file mode 100644 index 00000000..fd90389b --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Feature/PackageWithExcessiveFeatureDepth.wxs | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
| 2 | <Package Name="PackageWithExcessiveFeatureDepth" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="12E4699F-E774-4D05-8A01-5BDD41BBA127"> | ||
| 3 | <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." /> | ||
| 4 | |||
| 5 | <Feature Id="Depth1"> | ||
| 6 | <Feature Id="Depth2"> | ||
| 7 | <Feature Id="Depth3"> | ||
| 8 | <Feature Id="Depth4"> | ||
| 9 | <Feature Id="Depth5"> | ||
| 10 | <Feature Id="Depth6"> | ||
| 11 | <Feature Id="Depth7"> | ||
| 12 | <Feature Id="Depth8"> | ||
| 13 | <Feature Id="Depth9"> | ||
| 14 | <Feature Id="Depth10"> | ||
| 15 | <Feature Id="Depth11"> | ||
| 16 | <Feature Id="Depth12"> | ||
| 17 | <Feature Id="Depth13"> | ||
| 18 | <Feature Id="Depth14"> | ||
| 19 | <Feature Id="Depth15"> | ||
| 20 | <Feature Id="Depth16"> | ||
| 21 | <Feature Id="Depth17"> | ||
| 22 | <Component Directory="INSTALLFOLDER"> | ||
| 23 | <File Source="test.txt" /> | ||
| 24 | </Component> | ||
| 25 | </Feature> | ||
| 26 | </Feature> | ||
| 27 | </Feature> | ||
| 28 | </Feature> | ||
| 29 | </Feature> | ||
| 30 | </Feature> | ||
| 31 | </Feature> | ||
| 32 | </Feature> | ||
| 33 | </Feature> | ||
| 34 | </Feature> | ||
| 35 | </Feature> | ||
| 36 | </Feature> | ||
| 37 | </Feature> | ||
| 38 | </Feature> | ||
| 39 | </Feature> | ||
| 40 | </Feature> | ||
| 41 | </Feature> | ||
| 42 | </Package> | ||
| 43 | |||
| 44 | |||
| 45 | <Fragment> | ||
| 46 | <StandardDirectory Id="ProgramFiles6432Folder"> | ||
| 47 | <Directory Id="INSTALLFOLDER" Name="PackageMissingFeatureComponentMapping" /> | ||
| 48 | </StandardDirectory> | ||
| 49 | </Fragment> | ||
| 50 | </Wix> | ||
