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
{