diff options
Diffstat (limited to 'src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs')
-rw-r--r-- | src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs new file mode 100644 index 00000000..df1ccecf --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs | |||
@@ -0,0 +1,122 @@ | |||
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.Core.Cab; | ||
10 | using WixToolset.Core.Bind; | ||
11 | using WixToolset.Data; | ||
12 | using WixToolset.Extensibility; | ||
13 | |||
14 | public class CabinetResolver | ||
15 | { | ||
16 | public CabinetResolver(string cabCachePath, IEnumerable<IWindowsInstallerBackendExtension> backendExtensions) | ||
17 | { | ||
18 | this.CabCachePath = cabCachePath; | ||
19 | |||
20 | this.BackendExtensions = backendExtensions; | ||
21 | } | ||
22 | |||
23 | private string CabCachePath { get; } | ||
24 | |||
25 | private IEnumerable<IWindowsInstallerBackendExtension> BackendExtensions { get; } | ||
26 | |||
27 | public ResolvedCabinet ResolveCabinet(string cabinetPath, IEnumerable<FileFacade> fileFacades) | ||
28 | { | ||
29 | var filesWithPath = fileFacades.Select(f => new BindFileWithPath() { Id = f.File.File, Path = f.WixFile.Source }).ToList(); | ||
30 | |||
31 | ResolvedCabinet resolved = null; | ||
32 | |||
33 | foreach (var extension in this.BackendExtensions) | ||
34 | { | ||
35 | resolved = extension.ResolveCabinet(cabinetPath, filesWithPath); | ||
36 | |||
37 | if (null != resolved) | ||
38 | { | ||
39 | return resolved; | ||
40 | } | ||
41 | } | ||
42 | |||
43 | // By default cabinet should be built and moved to the suggested location. | ||
44 | resolved = new ResolvedCabinet() { BuildOption = CabinetBuildOption.BuildAndMove, Path = cabinetPath }; | ||
45 | |||
46 | // If a cabinet cache path was provided, change the location for the cabinet | ||
47 | // to be built to and check if there is a cabinet that can be reused. | ||
48 | if (!String.IsNullOrEmpty(this.CabCachePath)) | ||
49 | { | ||
50 | string cabinetName = Path.GetFileName(cabinetPath); | ||
51 | resolved.Path = Path.Combine(this.CabCachePath, cabinetName); | ||
52 | |||
53 | if (CheckFileExists(resolved.Path)) | ||
54 | { | ||
55 | // Assume that none of the following are true: | ||
56 | // 1. any files are added or removed | ||
57 | // 2. order of files changed or names changed | ||
58 | // 3. modified time changed | ||
59 | bool cabinetValid = true; | ||
60 | |||
61 | // Need to force garbage collection of WixEnumerateCab to ensure the handle | ||
62 | // associated with it is closed before it is reused. | ||
63 | using (var wixEnumerateCab = new WixEnumerateCab()) | ||
64 | { | ||
65 | List<CabinetFileInfo> fileList = wixEnumerateCab.Enumerate(resolved.Path); | ||
66 | |||
67 | if (filesWithPath.Count() != fileList.Count) | ||
68 | { | ||
69 | cabinetValid = false; | ||
70 | } | ||
71 | else | ||
72 | { | ||
73 | int i = 0; | ||
74 | foreach (BindFileWithPath file in filesWithPath) | ||
75 | { | ||
76 | // First check that the file identifiers match because that is quick and easy. | ||
77 | CabinetFileInfo cabFileInfo = fileList[i]; | ||
78 | cabinetValid = (cabFileInfo.FileId == file.Id); | ||
79 | if (cabinetValid) | ||
80 | { | ||
81 | // Still valid so ensure the file sizes are the same. | ||
82 | FileInfo fileInfo = new FileInfo(file.Path); | ||
83 | cabinetValid = (cabFileInfo.Size == fileInfo.Length); | ||
84 | if (cabinetValid) | ||
85 | { | ||
86 | // Still valid so ensure the source time stamp hasn't changed. Thus we need | ||
87 | // to convert the source file time stamp into a cabinet compatible data/time. | ||
88 | Native.CabInterop.DateTimeToCabDateAndTime(fileInfo.LastWriteTime, out var sourceCabDate, out var sourceCabTime); | ||
89 | cabinetValid = (cabFileInfo.Date == sourceCabDate && cabFileInfo.Time == sourceCabTime); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | if (!cabinetValid) | ||
94 | { | ||
95 | break; | ||
96 | } | ||
97 | |||
98 | i++; | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | |||
103 | resolved.BuildOption = cabinetValid ? CabinetBuildOption.Copy : CabinetBuildOption.BuildAndCopy; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | return resolved; | ||
108 | } | ||
109 | |||
110 | private static bool CheckFileExists(string path) | ||
111 | { | ||
112 | try | ||
113 | { | ||
114 | return File.Exists(path); | ||
115 | } | ||
116 | catch (ArgumentException) | ||
117 | { | ||
118 | throw new WixException(WixErrors.IllegalCharactersInPath(path)); | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | } | ||