aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs')
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs122
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
3namespace 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}