@joebigelow / wix-1 / commits / 93371724

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)