diff options
| author | Rob Mensching <rob@firegiant.com> | 2017-10-14 16:12:07 -0700 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2017-10-14 16:12:07 -0700 |
| commit | dbde9e7104b907bbbaea17e21247d8cafc8b3a4c (patch) | |
| tree | 0f5fbbb6fe12c6b2e5e622a0e18ce4c5b4eb2b96 /src/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs | |
| parent | fbf986eb97f68396797a89fc7d40dec07b775440 (diff) | |
| download | wix-dbde9e7104b907bbbaea17e21247d8cafc8b3a4c.tar.gz wix-dbde9e7104b907bbbaea17e21247d8cafc8b3a4c.tar.bz2 wix-dbde9e7104b907bbbaea17e21247d8cafc8b3a4c.zip | |
Massive refactoring to introduce the concept of IBackend
Diffstat (limited to 'src/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs')
| -rw-r--r-- | src/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/src/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs new file mode 100644 index 00000000..229e75b4 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs | |||
| @@ -0,0 +1,146 @@ | |||
| 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.Unbind | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.Collections; | ||
| 7 | using System.Collections.Specialized; | ||
| 8 | using System.Globalization; | ||
| 9 | using System.IO; | ||
| 10 | using WixToolset.Core.Cab; | ||
| 11 | using WixToolset.Data; | ||
| 12 | using WixToolset.Data.Rows; | ||
| 13 | using WixToolset.Msi; | ||
| 14 | |||
| 15 | internal class ExtractCabinetsCommand | ||
| 16 | { | ||
| 17 | public ExtractCabinetsCommand(Output output, Database database, string inputFilePath, string exportBasePath, string intermediateFolder) | ||
| 18 | { | ||
| 19 | this.Output = output; | ||
| 20 | this.Database = database; | ||
| 21 | this.InputFilePath = inputFilePath; | ||
| 22 | this.ExportBasePath = exportBasePath; | ||
| 23 | this.IntermediateFolder = intermediateFolder; | ||
| 24 | } | ||
| 25 | |||
| 26 | private Output Output { get; } | ||
| 27 | |||
| 28 | private Database Database { get; } | ||
| 29 | |||
| 30 | private string InputFilePath { get; } | ||
| 31 | |||
| 32 | private string ExportBasePath { get; } | ||
| 33 | |||
| 34 | private string IntermediateFolder { get; } | ||
| 35 | |||
| 36 | public void Execute() | ||
| 37 | { | ||
| 38 | string databaseBasePath = Path.GetDirectoryName(this.InputFilePath); | ||
| 39 | StringCollection cabinetFiles = new StringCollection(); | ||
| 40 | SortedList embeddedCabinets = new SortedList(); | ||
| 41 | |||
| 42 | // index all of the cabinet files | ||
| 43 | if (OutputType.Module == this.Output.Type) | ||
| 44 | { | ||
| 45 | embeddedCabinets.Add(0, "MergeModule.CABinet"); | ||
| 46 | } | ||
| 47 | else if (null != this.Output.Tables["Media"]) | ||
| 48 | { | ||
| 49 | foreach (MediaRow mediaRow in this.Output.Tables["Media"].Rows) | ||
| 50 | { | ||
| 51 | if (null != mediaRow.Cabinet) | ||
| 52 | { | ||
| 53 | if (OutputType.Product == this.Output.Type || | ||
| 54 | (OutputType.Transform == this.Output.Type && RowOperation.Add == mediaRow.Operation)) | ||
| 55 | { | ||
| 56 | if (mediaRow.Cabinet.StartsWith("#", StringComparison.Ordinal)) | ||
| 57 | { | ||
| 58 | embeddedCabinets.Add(mediaRow.DiskId, mediaRow.Cabinet.Substring(1)); | ||
| 59 | } | ||
| 60 | else | ||
| 61 | { | ||
| 62 | cabinetFiles.Add(Path.Combine(databaseBasePath, mediaRow.Cabinet)); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | } | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | // extract the embedded cabinet files from the database | ||
| 70 | if (0 < embeddedCabinets.Count) | ||
| 71 | { | ||
| 72 | using (View streamsView = this.Database.OpenView("SELECT `Data` FROM `_Streams` WHERE `Name` = ?")) | ||
| 73 | { | ||
| 74 | foreach (int diskId in embeddedCabinets.Keys) | ||
| 75 | { | ||
| 76 | using (Record record = new Record(1)) | ||
| 77 | { | ||
| 78 | record.SetString(1, (string)embeddedCabinets[diskId]); | ||
| 79 | streamsView.Execute(record); | ||
| 80 | } | ||
| 81 | |||
| 82 | using (Record record = streamsView.Fetch()) | ||
| 83 | { | ||
| 84 | if (null != record) | ||
| 85 | { | ||
| 86 | // since the cabinets are stored in case-sensitive streams inside the msi, but the file system is not case-sensitive, | ||
| 87 | // embedded cabinets must be extracted to a canonical file name (like their diskid) to ensure extraction will always work | ||
| 88 | string cabinetFile = Path.Combine(this.IntermediateFolder, String.Concat("Media", Path.DirectorySeparatorChar, diskId.ToString(CultureInfo.InvariantCulture), ".cab")); | ||
| 89 | |||
| 90 | // ensure the parent directory exists | ||
| 91 | System.IO.Directory.CreateDirectory(Path.GetDirectoryName(cabinetFile)); | ||
| 92 | |||
| 93 | using (FileStream fs = System.IO.File.Create(cabinetFile)) | ||
| 94 | { | ||
| 95 | int bytesRead; | ||
| 96 | byte[] buffer = new byte[512]; | ||
| 97 | |||
| 98 | while (0 != (bytesRead = record.GetStream(1, buffer, buffer.Length))) | ||
| 99 | { | ||
| 100 | fs.Write(buffer, 0, bytesRead); | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | cabinetFiles.Add(cabinetFile); | ||
| 105 | } | ||
| 106 | else | ||
| 107 | { | ||
| 108 | // TODO: warning about missing embedded cabinet | ||
| 109 | } | ||
| 110 | } | ||
| 111 | } | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | // extract the cabinet files | ||
| 116 | if (0 < cabinetFiles.Count) | ||
| 117 | { | ||
| 118 | string fileDirectory = Path.Combine(this.ExportBasePath, "File"); | ||
| 119 | |||
| 120 | // delete the directory and its files to prevent cab extraction due to an existing file | ||
| 121 | if (Directory.Exists(fileDirectory)) | ||
| 122 | { | ||
| 123 | Directory.Delete(fileDirectory, true); | ||
| 124 | } | ||
| 125 | |||
| 126 | // ensure the directory exists or extraction will fail | ||
| 127 | Directory.CreateDirectory(fileDirectory); | ||
| 128 | |||
| 129 | foreach (string cabinetFile in cabinetFiles) | ||
| 130 | { | ||
| 131 | using (var extractCab = new WixExtractCab()) | ||
| 132 | { | ||
| 133 | try | ||
| 134 | { | ||
| 135 | extractCab.Extract(cabinetFile, fileDirectory); | ||
| 136 | } | ||
| 137 | catch (FileNotFoundException) | ||
| 138 | { | ||
| 139 | throw new WixException(WixErrors.FileNotFound(new SourceLineNumber(this.InputFilePath), cabinetFile)); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | } | ||
| 143 | } | ||
| 144 | } | ||
| 145 | } | ||
| 146 | } | ||
