@joebigelow / wix-1 / commits / 581c320e

Warn when an MSI or cabinet installed by an MSI is too large

Fixes 6408

Rob Mensching committed Mar 16, 2022 at 10:30 UTC 581c320e04949300d6c3bee71fb5fc1a557f9263
6 files changed +65 -11
src/api/wix/WixToolset.Data/WarningMessages.cs
+11
@@ -673,6 +673,16 @@ namespace WixToolset.Data
673 return Message(null, Ids.InvalidEnvironmentVariable, "The {0} environment variable is set to an invalid value of '{1}'. The default value '{2}' will be used instead.", environmentVariable, value, defaultValue);
674 }
675
676 + public static Message WindowsInstallerFileTooLarge(SourceLineNumber sourceLineNumbers, string path, string fileDescription)
677 + {
678 + if (String.IsNullOrEmpty(fileDescription))
679 + {
680 + fileDescription = "MSI or cabinet";
681 + }
682 +
683 + return Message(sourceLineNumbers, Ids.WindowsInstallerFileTooLarge, "The Windows Installer does not support {0} files larger than 2GB in size. Reduce the size or number of files embedded in '{1}' or the installation will likely fail with an unexpected error.", fileDescription, path);
684 + }
685 +
686 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)
687 {
688 return new Message(sourceLineNumber, MessageLevel.Warning, (int)id, format, args);
@@ -809,6 +819,7 @@ namespace WixToolset.Data
819 DetectConditionRecommended = 1153,
820 CollidingModularizationTypes = 1156,
821 InvalidEnvironmentVariable = 1157,
822 + WindowsInstallerFileTooLarge = 1158,
823 UnavailableBundleConditionVariable = 1159,
824 }
825 }
src/wix/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs
+20
@@ -63,6 +63,8 @@ namespace WixToolset.Core.Burn.Bundles
63 var compressed = false;
64 try
65 {
66 + this.CheckIfWindowsInstallerFileTooLarge(packagePayload.SourceLineNumbers, sourcePath, "MSI");
67 +
68 using (var db = new Database(sourcePath, OpenDatabase.ReadOnly))
69 {
70 // Read data out of the msi database...
@@ -397,6 +399,8 @@ namespace WixToolset.Core.Burn.Bundles
399 Packaging = packagePayload.Packaging,
400 ParentPackagePayloadRef = packagePayload.Id.Id,
401 });
402 +
403 + this.CheckIfWindowsInstallerFileTooLarge(this.Facade.PackageSymbol.SourceLineNumbers, payloadSourceFile, "cabinet");
404 }
405 }
406 }
@@ -546,6 +550,22 @@ namespace WixToolset.Core.Burn.Bundles
550 return resolvedPath;
551 }
552
553 + private void CheckIfWindowsInstallerFileTooLarge(SourceLineNumber sourceLineNumber, string path, string description)
554 + {
555 + // Best effort check to see if the file is too large for the Windows Installer.
556 + try
557 + {
558 + var fi = new FileInfo(path);
559 + if (fi.Length > Int32.MaxValue)
560 + {
561 + this.Messaging.Write(WarningMessages.WindowsInstallerFileTooLarge(sourceLineNumber, path, description));
562 + }
563 + }
564 + catch
565 + {
566 + }
567 + }
568 +
569 private static string GetProperty(View view, string property)
570 {
571 using (var queryRecord = new Record(1))
src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
+13
@@ -513,6 +513,19 @@ namespace WixToolset.Core.WindowsInstaller.Bind
513 trackedFiles.AddRange(command.TrackedFiles);
514 }
515
516 + // Best effort check to see if the MSI file is too large for the Windows Installer.
517 + try
518 + {
519 + var fi = new FileInfo(this.OutputPath);
520 + if (fi.Length > Int32.MaxValue)
521 + {
522 + this.Messaging.Write(WarningMessages.WindowsInstallerFileTooLarge(null, this.OutputPath, "MSI"));
523 + }
524 + }
525 + catch
526 + {
527 + }
528 +
529 var trackedInputFiles = this.TrackInputFiles(data, trackedFiles);
530 trackedFiles.AddRange(trackedInputFiles);
531
src/wix/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs
+12 -1
@@ -165,7 +165,18 @@ namespace WixToolset.Core.WindowsInstaller.Bind
165 var cab = new Cabinet(cabinetPath);
166 cab.Compress(files, cabinetWorkItem.CompressionLevel, maxCabinetSize, cabinetWorkItem.MaxThreshold);
167
168 - // TODO: Handle newCabNamesCallBackAddress from compression.
168 + // Best effort check to see if the cabinet is too large for the Windows Installer.
169 + try
170 + {
171 + var fi = new FileInfo(cabinetPath);
172 + if (fi.Length > Int32.MaxValue)
173 + {
174 + this.Messaging.Write(WarningMessages.WindowsInstallerFileTooLarge(cabinetWorkItem.SourceLineNumber, cabinetPath, "cabinet"));
175 + }
176 + }
177 + catch
178 + {
179 + }
180 }
181 }
182 }
src/wix/WixToolset.Core.WindowsInstaller/Bind/CabinetWorkItem.cs
+8 -9
@@ -14,22 +14,27 @@ namespace WixToolset.Core.WindowsInstaller.Bind
14 /// <summary>
15 /// Instantiate a new CabinetWorkItem.
16 /// </summary>
17 + /// <param name="sourceLineNumber">Source line number that requires the cabinet creation.</param>
18 /// <param name="fileFacades">The collection of files in this cabinet.</param>
19 /// <param name="cabinetFile">The cabinet file.</param>
20 /// <param name="maxThreshold">Maximum threshold for each cabinet.</param>
21 /// <param name="compressionLevel">The compression level of the cabinet.</param>
22 /// <param name="modularizationSuffix">Modularization suffix used when building a Merge Module.</param>
22 - /// <!--<param name="binderFileManager">The binder file manager.</param>-->
23 - public CabinetWorkItem(IEnumerable<IFileFacade> fileFacades, string cabinetFile, int maxThreshold, CompressionLevel compressionLevel, string modularizationSuffix /*, BinderFileManager binderFileManager*/)
23 + public CabinetWorkItem(SourceLineNumber sourceLineNumber, string cabinetFile, IEnumerable<IFileFacade> fileFacades, int maxThreshold, CompressionLevel compressionLevel, string modularizationSuffix)
24 {
25 + this.SourceLineNumber = sourceLineNumber;
26 this.CabinetFile = cabinetFile;
27 this.CompressionLevel = compressionLevel;
28 this.ModularizationSuffix = modularizationSuffix;
29 this.FileFacades = fileFacades;
29 - //this.BinderFileManager = binderFileManager;
30 this.MaxThreshold = maxThreshold;
31 }
32
33 + /// <summary>
34 + /// Source line that requires the cabinet creation.
35 + /// </summary>
36 + public SourceLineNumber SourceLineNumber { get; }
37 +
38 /// <summary>
39 /// Gets the cabinet file.
40 /// </summary>
@@ -53,12 +58,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
58 /// <value>The collection of files in this cabinet.</value>
59 public IEnumerable<IFileFacade> FileFacades { get; }
60
56 - // <summary>
57 - // Gets the binder file manager.
58 - // </summary>
59 - // <value>The binder file manager.</value>
60 - //public BinderFileManager BinderFileManager { get; private set; }
61 -
61 /// <summary>
62 /// Gets the max threshold.
63 /// </summary>
src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs
+1 -1
@@ -190,7 +190,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
190 if (CabinetBuildOption.BuildAndCopy == resolvedCabinet.BuildOption || CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption)
191 {
192 // Default to the threshold for best smartcabbing (makes smallest cabinet).
193 - cabinetWorkItem = new CabinetWorkItem(fileFacades, resolvedCabinet.Path, maxThreshold: 0, compressionLevel, this.ModularizationSuffix /*, this.FileManager*/);
193 + cabinetWorkItem = new CabinetWorkItem(mediaSymbol.SourceLineNumbers, resolvedCabinet.Path, fileFacades, maxThreshold: 0, compressionLevel: compressionLevel, modularizationSuffix: this.ModularizationSuffix);
194 }
195 else // reuse the cabinet from the cabinet cache.
196 {