main
cs 132 lines 4.92 KB
Raw
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.Native;
10 using WixToolset.Data;
11 using WixToolset.Extensibility;
12 using WixToolset.Extensibility.Data;
13 using WixToolset.Extensibility.Services;
14
15 internal class CabinetResolver
16 {
17 public CabinetResolver(IServiceProvider serviceProvider, string cabCachePath, IEnumerable<IWindowsInstallerBackendBinderExtension> backendExtensions)
18 {
19 this.ServiceProvider = serviceProvider;
20
21 this.CabCachePath = cabCachePath;
22
23 this.BackendExtensions = backendExtensions;
24 }
25
26 private IServiceProvider ServiceProvider { get; }
27
28 private string CabCachePath { get; }
29
30 private IEnumerable<IWindowsInstallerBackendBinderExtension> BackendExtensions { get; }
31
32 public IResolvedCabinet ResolveCabinet(string cabinetPath, IEnumerable<IFileFacade> fileFacades)
33 {
34 var filesWithPath = fileFacades.Select(this.CreateBindFileWithPath).ToList();
35
36 IResolvedCabinet resolved = null;
37
38 foreach (var extension in this.BackendExtensions)
39 {
40 resolved = extension.ResolveCabinet(cabinetPath, filesWithPath);
41
42 if (null != resolved)
43 {
44 return resolved;
45 }
46 }
47
48 // By default cabinet should be built and moved to the suggested location.
49 resolved = this.ServiceProvider.GetService<IResolvedCabinet>();
50 resolved.BuildOption = CabinetBuildOption.BuildAndMove;
51 resolved.Path = cabinetPath;
52
53 // If a cabinet cache path was provided, change the location for the cabinet
54 // to be built to and check if there is a cabinet that can be reused.
55 if (!String.IsNullOrEmpty(this.CabCachePath))
56 {
57 var cabinetName = Path.GetFileName(cabinetPath);
58 resolved.Path = Path.Combine(this.CabCachePath, cabinetName);
59
60 if (CheckFileExists(resolved.Path))
61 {
62 // Assume that none of the following are true:
63 // 1. any files are added or removed
64 // 2. order of files changed or names changed
65 // 3. modified time changed
66 var cabinetValid = true;
67
68 var cabinet = new Cabinet(resolved.Path);
69 var fileList = cabinet.Enumerate();
70
71 if (filesWithPath.Count() != fileList.Count)
72 {
73 cabinetValid = false;
74 }
75 else
76 {
77 var i = 0;
78 foreach (var file in filesWithPath)
79 {
80 // First check that the file identifiers match because that is quick and easy.
81 var cabFileInfo = fileList[i];
82 cabinetValid = (cabFileInfo.FileId == file.Id);
83 if (cabinetValid)
84 {
85 // Still valid so ensure the file sizes are the same.
86 var fileInfo = new FileInfo(file.Path);
87 cabinetValid = (cabFileInfo.Size == fileInfo.Length);
88 if (cabinetValid)
89 {
90 // Still valid so ensure the source time stamp hasn't changed.
91 cabinetValid = cabFileInfo.SameAsDateTime(fileInfo.LastWriteTime);
92 }
93 }
94
95 if (!cabinetValid)
96 {
97 break;
98 }
99
100 i++;
101 }
102 }
103
104 resolved.BuildOption = cabinetValid ? CabinetBuildOption.Copy : CabinetBuildOption.BuildAndCopy;
105 }
106 }
107
108 return resolved;
109 }
110
111 private IBindFileWithPath CreateBindFileWithPath(IFileFacade facade)
112 {
113 var result = this.ServiceProvider.GetService<IBindFileWithPath>();
114 result.Id = facade.Id;
115 result.Path = facade.SourcePath;
116
117 return result;
118 }
119
120 private static bool CheckFileExists(string path)
121 {
122 try
123 {
124 return File.Exists(path);
125 }
126 catch (ArgumentException)
127 {
128 throw new WixException(ErrorMessages.IllegalCharactersInPath(path));
129 }
130 }
131 }
132 }