/// <summary> /// Harvest a payload. /// </summary> /// <param name="path">The path of the payload.</param> /// <returns>A harvested payload.</returns> public Wix.RemotePayload HarvestRemotePayload(string path) { if (null == path) { throw new ArgumentNullException("path"); } if (!File.Exists(path)) { throw new WixException(HarvesterErrors.FileNotFound(path)); } Wix.RemotePayload remotePayload; switch (this.packageType) { case WixBundlePackageType.Exe: remotePayload = new Wix.ExePackagePayload(); break; case WixBundlePackageType.Msu: remotePayload = new Wix.MsuPackagePayload(); break; default: throw new NotImplementedException(); } var payloadSymbol = new WixBundlePayloadSymbol { SourceFile = new IntermediateFieldPathValue { Path = path }, }; this.payloadHarvester.HarvestStandardInformation(payloadSymbol); if (payloadSymbol.FileSize.HasValue) { remotePayload.Size = payloadSymbol.FileSize.Value; } remotePayload.Hash = payloadSymbol.Hash; if (!String.IsNullOrEmpty(payloadSymbol.Version)) { remotePayload.Version = payloadSymbol.Version; } if (!String.IsNullOrEmpty(payloadSymbol.Description)) { remotePayload.Description = payloadSymbol.Description; } if (!String.IsNullOrEmpty(payloadSymbol.DisplayName)) { remotePayload.ProductName = payloadSymbol.DisplayName; } return(remotePayload); }
private void UpdatePayloadPackagingType(WixBundlePayloadSymbol payload) { if (!payload.Packaging.HasValue || PackagingType.Unknown == payload.Packaging) { if (!payload.Compressed.HasValue) { payload.Packaging = this.DefaultPackaging; } else if (payload.Compressed.Value) { payload.Packaging = PackagingType.Embedded; } else { payload.Packaging = PackagingType.External; } } // Embedded payloads that are not assigned a container already are placed in the default attached // container. if (PackagingType.Embedded == payload.Packaging && String.IsNullOrEmpty(payload.ContainerRef)) { payload.ContainerRef = BurnConstants.BurnDefaultAttachedContainerName; } }
private void WritePayloadInfo(XmlTextWriter writer, WixBundlePayloadSymbol payloadSymbol, string packageId) { writer.WriteStartElement("WixPayloadProperties"); if (!String.IsNullOrEmpty(packageId)) { writer.WriteAttributeString("Package", packageId); } writer.WriteAttributeString("Payload", payloadSymbol.Id.Id); if (!String.IsNullOrEmpty(payloadSymbol.ContainerRef)) { writer.WriteAttributeString("Container", payloadSymbol.ContainerRef); } writer.WriteAttributeString("Name", payloadSymbol.Name); writer.WriteAttributeString("Size", payloadSymbol.FileSize.Value.ToString(CultureInfo.InvariantCulture)); if (!String.IsNullOrEmpty(payloadSymbol.DownloadUrl)) { writer.WriteAttributeString("DownloadUrl", payloadSymbol.DownloadUrl); } writer.WriteEndElement(); }
private void ImportExternalCabinetAsPayloads(Database db, WixBundlePayloadSymbol packagePayload, ISet <string> payloadNames) { if (db.TableExists("Media")) { using (var view = db.OpenExecuteView("SELECT `Cabinet` FROM `Media`")) { foreach (var cabinetRecord in view.Records) { var cabinet = cabinetRecord.GetString(1); if (!String.IsNullOrEmpty(cabinet) && !cabinet.StartsWith("#", StringComparison.Ordinal)) { // If we didn't find the Payload as an existing child of the package, we need to // add it. We expect the file to exist on-disk in the same relative location as // the MSI expects to find it... var cabinetName = Path.Combine(Path.GetDirectoryName(packagePayload.Name), cabinet); if (!payloadNames.Contains(cabinetName)) { var generatedId = this.BackendHelper.GenerateIdentifier("cab", packagePayload.Id.Id, cabinet); var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, cabinet, "Cabinet", this.Facade.PackageSymbol.SourceLineNumbers); this.Section.AddSymbol(new WixGroupSymbol(this.Facade.PackageSymbol.SourceLineNumbers) { ParentType = ComplexReferenceParentType.Package, ParentId = this.Facade.PackageId, ChildType = ComplexReferenceChildType.Payload, ChildId = generatedId }); this.Section.AddSymbol(new WixBundlePayloadSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId)) { Name = cabinetName, SourceFile = new IntermediateFieldPathValue { Path = payloadSourceFile }, Compressed = packagePayload.Compressed, UnresolvedSourceFile = cabinetName, ContainerRef = packagePayload.ContainerRef, ContentFile = true, DownloadUrl = packagePayload.DownloadUrl, Packaging = packagePayload.Packaging, ParentPackagePayloadRef = packagePayload.Id.Id, }); } } } } } }
private void WriteBurnManifestPayloadAttributes(XmlTextWriter writer, WixBundlePayloadSymbol payload, bool embeddedOnly, Dictionary <string, WixBundlePayloadSymbol> allPayloads) { Debug.Assert(!embeddedOnly || PackagingType.Embedded == payload.Packaging); writer.WriteAttributeString("Id", payload.Id.Id); writer.WriteAttributeString("FilePath", payload.Name); writer.WriteAttributeString("FileSize", payload.FileSize.Value.ToString(CultureInfo.InvariantCulture)); writer.WriteAttributeString("Hash", payload.Hash); if (payload.LayoutOnly) { writer.WriteAttributeString("LayoutOnly", "yes"); } switch (payload.Packaging) { case PackagingType.Embedded: // this means it's in a container. if (!String.IsNullOrEmpty(payload.DownloadUrl)) { this.Messaging.Write(WarningMessages.DownloadUrlNotSupportedForEmbeddedPayloads(payload.SourceLineNumbers, payload.Id.Id)); } writer.WriteAttributeString("Packaging", "embedded"); writer.WriteAttributeString("SourcePath", payload.EmbeddedId); if (BurnConstants.BurnUXContainerName != payload.ContainerRef) { writer.WriteAttributeString("Container", payload.ContainerRef); } break; case PackagingType.External: var packageId = payload.ParentPackagePayloadRef; var parentUrl = payload.ParentPackagePayloadRef == null ? null : allPayloads[payload.ParentPackagePayloadRef].DownloadUrl; var resolvedUrl = this.ResolveUrl(payload.DownloadUrl, parentUrl, packageId, payload.Id.Id, payload.Name); if (!String.IsNullOrEmpty(resolvedUrl)) { writer.WriteAttributeString("DownloadUrl", resolvedUrl); } else if (!String.IsNullOrEmpty(payload.DownloadUrl)) { writer.WriteAttributeString("DownloadUrl", payload.DownloadUrl); } writer.WriteAttributeString("Packaging", "external"); writer.WriteAttributeString("SourcePath", payload.Name); break; } }
private void UpdatePayloadFileInformation(WixBundlePayloadSymbol payload, IntermediateFieldPathValue sourceFile) { var fileInfo = new FileInfo(sourceFile.Path); if (null != fileInfo) { payload.FileSize = fileInfo.Length; payload.Hash = BundleHashAlgorithm.Hash(fileInfo); } else { payload.FileSize = 0; } }
private void UpdatePayloadFileInformation(WixBundlePayloadSymbol payload, string filePath) { var fileInfo = new FileInfo(filePath); if (null != fileInfo) { payload.FileSize = fileInfo.Length; payload.Hash = BundleHashAlgorithm.Hash(fileInfo); } else { payload.FileSize = 0; } }
/// <inheritdoc /> public bool HarvestStandardInformation(WixBundlePayloadSymbol payload) { var filePath = payload.SourceFile?.Path; if (String.IsNullOrEmpty(filePath)) { return(false); } this.UpdatePayloadFileInformation(payload, filePath); this.UpdatePayloadVersionInformation(payload, filePath); return(true); }
private void WriteBurnManifestUXPayload(XmlTextWriter writer, WixBundlePayloadSymbol payload) { Debug.Assert(PackagingType.Embedded == payload.Packaging); Debug.Assert(BurnConstants.BurnUXContainerName == payload.ContainerRef); writer.WriteStartElement("Payload"); // TODO: The engine should be updated to not require FileSize, Hash, or Packaging for UX payloads since the values are never used. writer.WriteAttributeString("Id", payload.Id.Id); writer.WriteAttributeString("FilePath", payload.Name); writer.WriteAttributeString("FileSize", payload.FileSize.Value.ToString(CultureInfo.InvariantCulture)); writer.WriteAttributeString("Hash", payload.Hash); writer.WriteAttributeString("Packaging", "embedded"); writer.WriteAttributeString("SourcePath", payload.EmbeddedId); writer.WriteEndElement(); }
private void UpdatePayloadFileInformation(WixBundlePayloadSymbol payload, IntermediateFieldPathValue sourceFile) { var fileInfo = new FileInfo(sourceFile.Path); if (null != fileInfo) { payload.FileSize = (int)fileInfo.Length; payload.Hash = BundleHashAlgorithm.Hash(fileInfo); // Try to get the certificate if the payload is a signed file and we're not suppressing signature validation. if (payload.EnableSignatureValidation) { X509Certificate2 certificate = null; try { certificate = new X509Certificate2(fileInfo.FullName); } catch (CryptographicException) // we don't care about non-signed files. { } // If there is a certificate, remember its hashed public key identifier and thumbprint. if (null != certificate) { byte[] publicKeyIdentifierHash = new byte[128]; uint publicKeyIdentifierHashSize = (uint)publicKeyIdentifierHash.Length; Native.NativeMethods.HashPublicKeyInfo(certificate.Handle, publicKeyIdentifierHash, ref publicKeyIdentifierHashSize); var sb = new StringBuilder(((int)publicKeyIdentifierHashSize + 1) * 2); for (var i = 0; i < publicKeyIdentifierHashSize; ++i) { sb.AppendFormat("{0:X2}", publicKeyIdentifierHash[i]); } payload.PublicKey = sb.ToString(); payload.Thumbprint = certificate.Thumbprint; } } } else { payload.FileSize = 0; } }
private void UpdatePayloadVersionInformation(WixBundlePayloadSymbol payload, IntermediateFieldPathValue sourceFile) { var versionInfo = FileVersionInfo.GetVersionInfo(sourceFile.Path); if (null != versionInfo) { // Use the fixed version info block for the file since the resource text may not be a dotted quad. var version = new Version(versionInfo.ProductMajorPart, versionInfo.ProductMinorPart, versionInfo.ProductBuildPart, versionInfo.ProductPrivatePart); if (ProcessPayloadsCommand.EmptyVersion != version) { payload.Version = version.ToString(); } payload.Description = versionInfo.FileDescription; payload.DisplayName = versionInfo.ProductName; } }
public WixBundlePayloadSymbol CreatePayloadSymbol(ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType = ComplexReferenceChildType.Unknown, string previousId = null) { WixBundlePayloadSymbol symbol = null; if (parentType == ComplexReferenceParentType.Container && parentId == BurnConstants.BurnUXContainerName) { if (this.Compressed == YesNoDefaultType.No) { this.Core.Write(WarningMessages.UxPayloadsOnlySupportEmbedding(this.SourceLineNumbers, this.SourceFile)); } if (!String.IsNullOrEmpty(this.DownloadUrl)) { this.Core.Write(WarningMessages.DownloadUrlNotSupportedForBAPayloads(this.SourceLineNumbers, this.Id.Id)); } this.Compressed = YesNoDefaultType.Yes; this.DownloadUrl = null; } if (!this.Core.EncounteredError) { symbol = this.Core.AddSymbol(new WixBundlePayloadSymbol(this.SourceLineNumbers, this.Id) { Name = String.IsNullOrEmpty(this.Name) ? Path.GetFileName(this.SourceFile) : this.Name, SourceFile = new IntermediateFieldPathValue { Path = this.SourceFile }, DownloadUrl = this.DownloadUrl, Compressed = (this.Compressed == YesNoDefaultType.Yes) ? true : (this.Compressed == YesNoDefaultType.No) ? (bool?)false : null, UnresolvedSourceFile = this.SourceFile, // duplicate of sourceFile but in a string column so it won't get resolved to a full path during binding. DisplayName = this.ProductName, Description = this.Description, Hash = this.Hash, FileSize = this.Size, Version = this.Version, }); this.Core.CreateGroupAndOrderingRows(this.SourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Payload, symbol.Id.Id, previousType, previousId); } return(symbol); }
private void ImportExternalCabinetAsPayloads(Dtf.Database db, WixBundlePayloadSymbol packagePayload, ISet <string> payloadNames) { if (db.Tables.Contains("Media")) { foreach (var cabinet in db.ExecuteStringQuery("SELECT `Cabinet` FROM `Media`")) { if (!String.IsNullOrEmpty(cabinet) && !cabinet.StartsWith("#", StringComparison.Ordinal)) { // If we didn't find the Payload as an existing child of the package, we need to // add it. We expect the file to exist on-disk in the same relative location as // the MSI expects to find it... var cabinetName = Path.Combine(Path.GetDirectoryName(packagePayload.Name), cabinet); if (!payloadNames.Contains(cabinetName)) { var generatedId = Common.GenerateIdentifier("cab", packagePayload.Id.Id, cabinet); var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, cabinet, "Cabinet", this.Facade.PackageSymbol.SourceLineNumbers, BindStage.Normal); this.Section.AddSymbol(new WixBundlePayloadSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Private, generatedId)) { Name = cabinetName, SourceFile = new IntermediateFieldPathValue { Path = payloadSourceFile }, Compressed = packagePayload.Compressed, UnresolvedSourceFile = cabinetName, PackageRef = packagePayload.PackageRef, ContainerRef = packagePayload.ContainerRef, ContentFile = true, EnableSignatureValidation = packagePayload.EnableSignatureValidation, Packaging = packagePayload.Packaging, ParentPackagePayloadRef = packagePayload.Id.Id, }); } } } } }
private void WriteBurnManifestPayloadAttributes(XmlTextWriter writer, WixBundlePayloadSymbol payload, bool embeddedOnly, Dictionary <string, WixBundlePayloadSymbol> allPayloads) { Debug.Assert(!embeddedOnly || PackagingType.Embedded == payload.Packaging); writer.WriteAttributeString("Id", payload.Id.Id); writer.WriteAttributeString("FilePath", payload.Name); writer.WriteAttributeString("FileSize", payload.FileSize.Value.ToString(CultureInfo.InvariantCulture)); writer.WriteAttributeString("Hash", payload.Hash); if (payload.LayoutOnly) { writer.WriteAttributeString("LayoutOnly", "yes"); } switch (payload.Packaging) { case PackagingType.Embedded: // this means it's in a container. writer.WriteAttributeString("Packaging", "embedded"); writer.WriteAttributeString("SourcePath", payload.EmbeddedId); if (BurnConstants.BurnUXContainerName != payload.ContainerRef) { writer.WriteAttributeString("Container", payload.ContainerRef); } break; case PackagingType.External: if (!String.IsNullOrEmpty(payload.DownloadUrl)) { writer.WriteAttributeString("DownloadUrl", payload.DownloadUrl); } writer.WriteAttributeString("Packaging", "external"); writer.WriteAttributeString("SourcePath", payload.Name); break; } }
private void ProcessPatchXml(WixBundlePayloadSymbol packagePayload, WixBundleMspPackageSymbol mspPackage, string sourcePath) { var uniqueTargetCodes = new HashSet <string>(); var patchXml = Dtf.Installer.ExtractPatchXmlData(sourcePath); var doc = new XmlDocument(); doc.LoadXml(patchXml); var nsmgr = new XmlNamespaceManager(doc.NameTable); nsmgr.AddNamespace("p", "http://www.microsoft.com/msi/patch_applicability.xsd"); // Determine target ProductCodes and/or UpgradeCodes. foreach (XmlNode node in doc.SelectNodes("/p:MsiPatch/p:TargetProduct", nsmgr)) { // If this patch targets a product code, this is the best case. var targetCodeElement = node.SelectSingleNode("p:TargetProductCode", nsmgr); var attributes = WixBundlePatchTargetCodeAttributes.None; if (ProcessMspPackageCommand.TargetsCode(targetCodeElement)) { attributes = WixBundlePatchTargetCodeAttributes.TargetsProductCode; } else // maybe targets an upgrade code? { targetCodeElement = node.SelectSingleNode("p:UpgradeCode", nsmgr); if (ProcessMspPackageCommand.TargetsCode(targetCodeElement)) { attributes = WixBundlePatchTargetCodeAttributes.TargetsUpgradeCode; } else // this patch targets an unknown number of products { mspPackage.Attributes |= WixBundleMspPackageAttributes.TargetUnspecified; } } var targetCode = targetCodeElement.InnerText; if (uniqueTargetCodes.Add(targetCode)) { this.Section.AddSymbol(new WixBundlePatchTargetCodeSymbol(packagePayload.SourceLineNumbers) { PackageRef = packagePayload.Id.Id, TargetCode = targetCode, Attributes = attributes }); } } // Suppress patch sequence data for improved performance. var root = doc.DocumentElement; foreach (XmlNode node in root.SelectNodes("p:SequenceData", nsmgr)) { root.RemoveChild(node); } // Save the XML as compact as possible. using (var writer = new StringWriter()) { var settings = new XmlWriterSettings() { Encoding = ProcessMspPackageCommand.XmlOutputEncoding, Indent = false, NewLineChars = String.Empty, NewLineHandling = NewLineHandling.Replace, }; using (var xmlWriter = XmlWriter.Create(writer, settings)) { doc.WriteTo(xmlWriter); } mspPackage.PatchXml = writer.ToString(); } }
private long ImportExternalFileAsPayloadsAndReturnInstallSize(Dtf.Database db, WixBundlePayloadSymbol packagePayload, bool longNamesInImage, bool compressed, ISet <string> payloadNames) { long size = 0; if (db.Tables.Contains("Component") && db.Tables.Contains("Directory") && db.Tables.Contains("File")) { var directories = new Dictionary <string, IResolvedDirectory>(); // Load up the directory hash table so we will be able to resolve source paths // for files in the MSI database. using (var view = db.OpenView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`")) { view.Execute(); while (true) { using (var record = view.Fetch()) { if (null == record) { break; } var sourceName = Common.GetName(record.GetString(3), true, longNamesInImage); var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(record.GetString(2), sourceName); directories.Add(record.GetString(1), resolvedDirectory); } } } // Resolve the source paths to external files and add each file size to the total // install size of the package. using (var view = db.OpenView("SELECT `Directory_`, `File`, `FileName`, `File`.`Attributes`, `FileSize` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_`")) { view.Execute(); while (true) { using (var record = view.Fetch()) { if (null == record) { break; } // If the file is explicitly uncompressed or the MSI is uncompressed and the file is not // explicitly marked compressed then this is an external file. var compressionBit = record.GetInteger(4); if (WindowsInstallerConstants.MsidbFileAttributesNoncompressed == (compressionBit & WindowsInstallerConstants.MsidbFileAttributesNoncompressed) || (!compressed && 0 == (compressionBit & WindowsInstallerConstants.MsidbFileAttributesCompressed))) { string fileSourcePath = this.PathResolver.GetFileSourcePath(directories, record.GetString(1), record.GetString(3), compressed, longNamesInImage); var name = Path.Combine(Path.GetDirectoryName(packagePayload.Name), fileSourcePath); if (!payloadNames.Contains(name)) { var generatedId = Common.GenerateIdentifier("f", packagePayload.Id.Id, record.GetString(2)); var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, fileSourcePath, "File", this.Facade.PackageSymbol.SourceLineNumbers); this.Section.AddSymbol(new WixBundlePayloadSymbol(this.Facade.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId)) { Name = name, SourceFile = new IntermediateFieldPathValue { Path = payloadSourceFile }, Compressed = packagePayload.Compressed, UnresolvedSourceFile = name, PackageRef = packagePayload.PackageRef, ContainerRef = packagePayload.ContainerRef, ContentFile = true, Packaging = packagePayload.Packaging, ParentPackagePayloadRef = packagePayload.Id.Id, }); } } size += record.GetInteger(5); } } } } return(size); }