Use min DOS date/time when filetime not supported by cabinet
Cabinets require files use DOS date/time. Since there are limits to DOS date/time, use the minimum date/time when a file's actual DOS date/time are out of bounds. Fixes 5296
Rob Mensching committed
Mar 10, 2022 at 22:37 UTC
9337172498d263399b8c5e3795aca1897093d37b
2 files changed
+56
-3
src/libs/dutil/WixToolset.DUtil/cabcutil.cpp
+11
-3
@@ -1047,12 +1047,12 @@ static HRESULT UtcFileTimeToLocalDosDateTime(
1047
1048
if (!::FileTimeToLocalFileTime(pFileTime, &ftLocal))
1049
{
1050
- CabcExitWithLastError(hr, "Filed to convert file time to local file time.");
1050
+ CabcExitWithLastError(hr, "Failed to convert file time to local file time.");
1051
}
1052
1053
if (!::FileTimeToDosDateTime(&ftLocal, pDate, pTime))
1054
{
1055
- CabcExitWithLastError(hr, "Filed to convert file time to DOS date time.");
1055
+ CabcExitWithLastError(hr, "Failed to convert file time to DOS date time.");
1056
}
1057
1058
LExit:
@@ -1508,7 +1508,15 @@ static __callback INT_PTR DIAMONDAPI CabCGetOpenInfo(
1508
// found. This would create further problems if the file was written to the CAB without this value. Windows
1509
// Installer would then fail to extract the file.
1510
hr = UtcFileTimeToLocalDosDateTime(&fad.ftCreationTime, pdate, ptime);
1511
- CabcExitOnFailure(hr, "Filed to read a valid file time stucture on file '%s'.", pszName);
1511
+
1512
+ // If we could not convert the ftLastWriteTime or ftCreationTime to a DOS time, then set the date/time to
1513
+ // the smallest value that can be represented: midnight on 1/1/1980.
1514
+ if (FAILED(hr))
1515
+ {
1516
+ *pdate = 0;
1517
+ *ptime = 0;
1518
+ hr = S_OK;
1519
+ }
1520
}
1521
1522
iResult = CabCOpen(pszFilePlusMagic, _O_BINARY|_O_RDONLY, 0, err, pv);
src/wix/test/WixToolsetTest.CoreIntegration/CabFixture.cs
+45
@@ -49,6 +49,51 @@ namespace WixToolsetTest.CoreIntegration
49
}
50
}
51
52
+ [Fact]
53
+ public void CanCabReallyOldFiles()
54
+ {
55
+ var folder = TestData.Get(@"TestData", "SingleFileCompressed");
56
+
57
+ using (var fs = new DisposableFileSystem())
58
+ {
59
+ var baseFolder = fs.GetFolder(create: true);
60
+ var intermediateFolder = Path.Combine(baseFolder, "obj");
61
+ var msiPath = Path.Combine(baseFolder, @"bin\test.msi");
62
+ var cabPath = Path.Combine(baseFolder, @"bin\cab1.cab");
63
+
64
+ var old = new DateTime(1980, 1, 1, 0, 0, 0, DateTimeKind.Utc);
65
+ var oldTxt = Path.Combine(baseFolder, "test.txt");
66
+ File.Copy(Path.Combine(folder, "data", "test.txt"), oldTxt);
67
+ File.SetCreationTime(oldTxt, old);
68
+ File.SetLastWriteTime(oldTxt, old);
69
+ File.SetLastAccessTime(oldTxt, old);
70
+
71
+ var result = WixRunner.Execute(new[]
72
+ {
73
+ "build",
74
+ Path.Combine(folder, "Package.wxs"),
75
+ Path.Combine(folder, "PackageComponents.wxs"),
76
+ "-d", "MediaTemplateCompressionLevel",
77
+ "-loc", Path.Combine(folder, "Package.en-us.wxl"),
78
+ "-bindpath", baseFolder,
79
+ "-intermediateFolder", intermediateFolder,
80
+ "-o", msiPath
81
+ });
82
+
83
+ result.AssertSuccess();
84
+ Assert.True(File.Exists(cabPath));
85
+
86
+ var fileTable = Query.QueryDatabase(msiPath, new[] { "File" });
87
+ var fileRows = fileTable.Select(r => new FileRow(r)).OrderBy(f => f.Sequence).ToList();
88
+
89
+ Assert.Equal(new[] { 1 }, fileRows.Select(f => f.Sequence).ToArray());
90
+ WixAssert.CompareLineByLine(new[] { "test.txt" }, fileRows.Select(f => f.Name).ToArray());
91
+
92
+ var files = Query.GetCabinetFiles(cabPath);
93
+ Assert.Equal(fileRows.Select(f => f.Id).ToArray(), files.Select(f => f.Name).ToArray());
94
+ }
95
+ }
96
+
97
private class FileRow
98
{
99
public FileRow(string row)