From f8749f8e438b150884449ad3e2e13aed750de679 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Fri, 4 Nov 2022 01:05:28 -0700 Subject: Provide useful error message when file system operations fail Fixes 5417 --- .../Services/IFileSystem.cs | 13 +++-- src/wix/WixToolset.Core.Burn/Bundles/BurnReader.cs | 12 ++-- src/wix/WixToolset.Core.Burn/Bundles/BurnWriter.cs | 9 +-- .../Bundles/CreateBundleExeCommand.cs | 6 +- .../Inscribe/InscribeBundleCommand.cs | 4 +- .../Inscribe/InscribeBundleEngineCommand.cs | 4 +- .../Bind/AssemblyNameReader.cs | 2 +- .../Bind/BindDatabaseCommand.cs | 2 +- .../Bind/BindTransformCommand.cs | 2 +- .../Bind/FileSystemManager.cs | 5 +- .../Bind/ProcessPackageSoftwareTagsCommand.cs | 7 ++- .../Bind/UpdateFileFacadesCommand.cs | 2 +- .../Inscribe/InscribeMsiPackageCommand.cs | 10 ++-- .../Unbind/ExtractCabinetsCommand.cs | 5 +- .../Unbind/UnbindDatabaseCommand.cs | 2 +- .../Unbind/UnbindTransformCommand.cs | 2 +- .../Validate/ValidateDatabaseCommand.cs | 4 +- .../WixToolset.Core/Bind/TransferFilesCommand.cs | 12 ++-- src/wix/WixToolset.Core/CoreErrors.cs | 42 ++++++++++++++ .../ExtensibilityServices/FileSystem.cs | 66 +++++++++++++++++----- src/wix/WixToolset.Core/LayoutCreator.cs | 2 +- 21 files changed, 152 insertions(+), 61 deletions(-) create mode 100644 src/wix/WixToolset.Core/CoreErrors.cs (limited to 'src') diff --git a/src/api/wix/WixToolset.Extensibility/Services/IFileSystem.cs b/src/api/wix/WixToolset.Extensibility/Services/IFileSystem.cs index cd987555..83a44400 100644 --- a/src/api/wix/WixToolset.Extensibility/Services/IFileSystem.cs +++ b/src/api/wix/WixToolset.Extensibility/Services/IFileSystem.cs @@ -4,6 +4,7 @@ namespace WixToolset.Extensibility.Services { using System; using System.IO; + using WixToolset.Data; /// /// Abstracts basic file system operations. @@ -13,34 +14,38 @@ namespace WixToolset.Extensibility.Services /// /// Copies a file. /// + /// Optional source line number requiring the copy. /// The file to copy. /// The destination file. /// Allow hardlinks. - void CopyFile(string source, string destination, bool allowHardlink); + void CopyFile(SourceLineNumber sourceLineNumbers, string source, string destination, bool allowHardlink); /// /// Deletes a file. /// + /// Optional source line number requiring the delete. /// The file to delete. /// Indicates the file must be deleted. Default is a best effort delete. /// Maximum retry attempts. Default is 4. - void DeleteFile(string source, bool throwOnError = false, int maxRetries = 4); + void DeleteFile(SourceLineNumber sourceLineNumbers, string source, bool throwOnError = false, int maxRetries = 4); /// /// Moves a file. /// + /// Optional source line number requiring the move. /// The file to move. /// The destination file. - void MoveFile(string source, string destination); + void MoveFile(SourceLineNumber sourceLineNumbers, string source, string destination); /// /// Opens a file. /// + /// Optional source line number requiring the file. /// The file to open. /// A System.IO.FileMode value that specifies whether a file is created if one does not exist, and determines whether the contents of existing files are retained or overwritten. /// A System.IO.FileAccess value that specifies the operations that can be performed on the file. /// A System.IO.FileShare value specifying the type of access other threads have to the file. - FileStream OpenFile(string path, FileMode mode, FileAccess access, FileShare share); + FileStream OpenFile(SourceLineNumber sourceLineNumbers, string path, FileMode mode, FileAccess access, FileShare share); /// /// Executes an action and retries on any exception a few times with short pause diff --git a/src/wix/WixToolset.Core.Burn/Bundles/BurnReader.cs b/src/wix/WixToolset.Core.Burn/Bundles/BurnReader.cs index acc76a3b..d8e49397 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/BurnReader.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/BurnReader.cs @@ -56,7 +56,7 @@ namespace WixToolset.Core.Burn.Bundles /// Burn reader. public static BurnReader Open(IMessaging messaging, IFileSystem fileSystem, string fileExe) { - var binaryReader = new BinaryReader(fileSystem.OpenFile(fileExe, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete)); + var binaryReader = new BinaryReader(fileSystem.OpenFile(null, fileExe, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete)); var reader = new BurnReader(messaging, fileSystem, fileExe) { binaryReader = binaryReader, @@ -92,7 +92,7 @@ namespace WixToolset.Core.Burn.Bundles var uxContainerSlot = this.AttachedContainers[0]; this.binaryReader.BaseStream.Seek(this.UXAddress, SeekOrigin.Begin); - using (Stream tempCab = this.fileSystem.OpenFile(tempCabPath, FileMode.Create, FileAccess.Write, FileShare.Read)) + using (Stream tempCab = this.fileSystem.OpenFile(null, tempCabPath, FileMode.Create, FileAccess.Write, FileShare.Read)) { BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)uxContainerSlot.Size); } @@ -100,7 +100,7 @@ namespace WixToolset.Core.Burn.Bundles var cabinet = new Cabinet(tempCabPath); cabinet.Extract(outputDirectory); - this.fileSystem.MoveFile(manifestOriginalPath, manifestPath); + this.fileSystem.MoveFile(null, manifestOriginalPath, manifestPath); var document = new XmlDocument(); document.Load(manifestPath); @@ -117,7 +117,7 @@ namespace WixToolset.Core.Burn.Bundles var sourcePath = Path.Combine(outputDirectory, sourcePathNode.Value); var destinationPath = Path.Combine(outputDirectory, filePathNode.Value); - this.fileSystem.MoveFile(sourcePath, destinationPath); + this.fileSystem.MoveFile(null, sourcePath, destinationPath); } foreach (XmlNode payload in payloads) @@ -169,7 +169,7 @@ namespace WixToolset.Core.Burn.Bundles var tempCabPath = Path.Combine(tempDirectory, $"a{i}.cab"); this.binaryReader.BaseStream.Seek(nextAddress, SeekOrigin.Begin); - using (Stream tempCab = this.fileSystem.OpenFile(tempCabPath, FileMode.Create, FileAccess.Write, FileShare.Read)) + using (Stream tempCab = this.fileSystem.OpenFile(null, tempCabPath, FileMode.Create, FileAccess.Write, FileShare.Read)) { BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)cntnr.Size); } @@ -185,7 +185,7 @@ namespace WixToolset.Core.Burn.Bundles var sourcePath = Path.Combine(outputDirectory, (string)entry.Key); var destinationPath = Path.Combine(outputDirectory, (string)entry.Value); - this.fileSystem.MoveFile(sourcePath, destinationPath); + this.fileSystem.MoveFile(null, sourcePath, destinationPath); } return true; diff --git a/src/wix/WixToolset.Core.Burn/Bundles/BurnWriter.cs b/src/wix/WixToolset.Core.Burn/Bundles/BurnWriter.cs index f6282443..a61713f1 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/BurnWriter.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/BurnWriter.cs @@ -43,14 +43,14 @@ namespace WixToolset.Core.Burn.Bundles { var writer = new BurnWriter(messaging, fileSystem, fileExe); - using (var binaryReader = new BinaryReader(fileSystem.OpenFile(fileExe, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete))) + using (var binaryReader = new BinaryReader(fileSystem.OpenFile(null, fileExe, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete))) { writer.Initialize(binaryReader); } if (!writer.Invalid) { - writer.binaryWriter = new BinaryWriter(fileSystem.OpenFile(fileExe, FileMode.Open, FileAccess.ReadWrite, FileShare.Read | FileShare.Delete)); + writer.binaryWriter = new BinaryWriter(fileSystem.OpenFile(null, fileExe, FileMode.Open, FileAccess.ReadWrite, FileShare.Read | FileShare.Delete)); } return writer; @@ -102,12 +102,13 @@ namespace WixToolset.Core.Burn.Bundles /// /// Appends a UX or Attached container to the exe and updates the ".wixburn" section data to point to it. /// + /// Source line numbers for the container. /// File path to append to the current exe. /// Container section represented by the fileContainer. /// true if the container data is successfully appended; false otherwise - public bool AppendContainer(string fileContainer, BurnCommon.Container container) + public bool AppendContainer(SourceLineNumber sourceLineNumbers, string fileContainer, BurnCommon.Container container) { - using (var reader = this.fileSystem.OpenFile(fileContainer, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (var reader = this.fileSystem.OpenFile(sourceLineNumbers, fileContainer, FileMode.Open, FileAccess.Read, FileShare.Read)) { return this.AppendContainer(reader, reader.Length, container); } diff --git a/src/wix/WixToolset.Core.Burn/Bundles/CreateBundleExeCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/CreateBundleExeCommand.cs index 64e74bbe..f4b36ac2 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/CreateBundleExeCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/CreateBundleExeCommand.cs @@ -71,7 +71,7 @@ namespace WixToolset.Core.Burn.Bundles this.Transfer = this.BackendHelper.CreateFileTransfer(bundleTempPath, this.OutputPath, true, this.BundleSymbol.SourceLineNumbers); - this.FileSystem.CopyFile(stubFile, bundleTempPath, allowHardlink: false); + this.FileSystem.CopyFile(this.BundleSymbol.SourceLineNumbers, stubFile, bundleTempPath, allowHardlink: false); File.SetAttributes(bundleTempPath, FileAttributes.Normal); var fourPartVersion = this.GetFourPartVersion(this.BundleSymbol); @@ -88,7 +88,7 @@ namespace WixToolset.Core.Burn.Bundles writer.InitializeBundleSectionData(burnStubFile.Length, this.BundleSymbol.BundleId); // Always attach the UX container first - writer.AppendContainer(this.UXContainer.WorkingPath, BurnWriter.Container.UX); + writer.AppendContainer(this.UXContainer.SourceLineNumbers, this.UXContainer.WorkingPath, BurnWriter.Container.UX); // Now append all other attached containers foreach (var container in this.Containers) @@ -98,7 +98,7 @@ namespace WixToolset.Core.Burn.Bundles // The container was only created if it had payloads. if (!String.IsNullOrEmpty(container.WorkingPath) && BurnConstants.BurnUXContainerName != container.Id.Id) { - writer.AppendContainer(container.WorkingPath, BurnWriter.Container.Attached); + writer.AppendContainer(container.SourceLineNumbers, container.WorkingPath, BurnWriter.Container.Attached); } } } diff --git a/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleCommand.cs b/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleCommand.cs index 422ad329..2ebc9c47 100644 --- a/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleCommand.cs @@ -38,7 +38,7 @@ namespace WixToolset.Core.Burn.Inscribe using (var reader = BurnReader.Open(this.Messaging, this.FileSystem, this.InputFilePath)) { - this.FileSystem.CopyFile(this.SignedEngineFile, tempFile, allowHardlink: false); + this.FileSystem.CopyFile(null, this.SignedEngineFile, tempFile, allowHardlink: false); using (var writer = BurnWriter.Open(this.Messaging, this.FileSystem, tempFile)) { @@ -46,7 +46,7 @@ namespace WixToolset.Core.Burn.Inscribe } } - this.FileSystem.MoveFile(tempFile, this.OutputFile); + this.FileSystem.MoveFile(null, tempFile, this.OutputFile); return inscribed; } diff --git a/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleEngineCommand.cs b/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleEngineCommand.cs index 3fde859a..5eeb7061 100644 --- a/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleEngineCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleEngineCommand.cs @@ -33,7 +33,7 @@ namespace WixToolset.Core.Burn.Inscribe var tempFile = Path.Combine(this.IntermediateFolder, "bundle_engine_unsigned.exe"); using (var reader = BurnReader.Open(this.Messaging, this.FileSystem, this.InputFilePath)) - using (var writer = this.FileSystem.OpenFile(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read | FileShare.Delete)) + using (var writer = this.FileSystem.OpenFile(null, tempFile, FileMode.Create, FileAccess.Write, FileShare.Read | FileShare.Delete)) { reader.Stream.Seek(0, SeekOrigin.Begin); @@ -58,7 +58,7 @@ namespace WixToolset.Core.Burn.Inscribe // TODO: update writer with detached container signatures. } - this.FileSystem.MoveFile(tempFile, this.OutputFile); + this.FileSystem.MoveFile(null, tempFile, this.OutputFile); } } } diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/AssemblyNameReader.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/AssemblyNameReader.cs index 0bb9c389..838a6fe1 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/AssemblyNameReader.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/AssemblyNameReader.cs @@ -19,7 +19,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind { try { - using (var stream = fileSystem.OpenFile(assemblyPath, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (var stream = fileSystem.OpenFile(sourceLineNumbers, assemblyPath, FileMode.Open, FileAccess.Read, FileShare.Read)) using (var peReader = new PEReader(stream)) { var reader = peReader.GetMetadataReader(); diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs index e3d70b70..b3008d6e 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs @@ -212,7 +212,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind if (softwareTags.Any()) { - var command = new ProcessPackageSoftwareTagsCommand(section, this.WindowsInstallerBackendHelper, softwareTags, this.IntermediateFolder); + var command = new ProcessPackageSoftwareTagsCommand(section, this.WindowsInstallerBackendHelper, this.FileSystem, softwareTags, this.IntermediateFolder); command.Execute(); trackedFiles.AddRange(command.TrackedFiles); diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs index e6ab3a28..b61247a5 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs @@ -401,7 +401,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind { if (!String.IsNullOrEmpty(emptyFile)) { - using (var fileStream = this.FileSystem.OpenFile(emptyFile, FileMode.Create, FileAccess.Write, FileShare.None)) + using (var fileStream = this.FileSystem.OpenFile(null, emptyFile, FileMode.Create, FileAccess.Write, FileShare.None)) { } } diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/FileSystemManager.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/FileSystemManager.cs index 8707d5f1..e4fa279c 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/FileSystemManager.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/FileSystemManager.cs @@ -5,7 +5,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind using System; using System.Collections.Generic; using System.IO; - using System.Runtime.CompilerServices; using WixToolset.Extensibility; using WixToolset.Extensibility.Services; @@ -42,8 +41,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind return true; } - using (var firstStream = this.FileSystem.OpenFile(firstPath, FileMode.Open, FileAccess.Read, FileShare.Read)) - using (var secondStream = this.FileSystem.OpenFile(secondPath, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (var firstStream = this.FileSystem.OpenFile(null, firstPath, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (var secondStream = this.FileSystem.OpenFile(null, secondPath, FileMode.Open, FileAccess.Read, FileShare.Read)) { if (firstStream.Length != secondStream.Length) { diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessPackageSoftwareTagsCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessPackageSoftwareTagsCommand.cs index 1348f163..9fb42fbc 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessPackageSoftwareTagsCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessPackageSoftwareTagsCommand.cs @@ -15,10 +15,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind internal class ProcessPackageSoftwareTagsCommand { - public ProcessPackageSoftwareTagsCommand(IntermediateSection section, IBackendHelper backendHelper, IEnumerable softwareTags, string intermediateFolder) + public ProcessPackageSoftwareTagsCommand(IntermediateSection section, IBackendHelper backendHelper, IFileSystem fileSystem, IEnumerable softwareTags, string intermediateFolder) { this.Section = section; this.BackendHelper = backendHelper; + this.FileSystem = fileSystem; this.SoftwareTags = softwareTags; this.IntermediateFolder = intermediateFolder; } @@ -29,6 +30,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind private IBackendHelper BackendHelper { get; } + private IFileSystem FileSystem { get; } + private IEnumerable SoftwareTags { get; } public IReadOnlyCollection TrackedFiles { get; private set; } @@ -61,7 +64,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind trackedFiles.Add(this.BackendHelper.TrackFile(fileSymbol.Source.Path, TrackedFileType.Intermediate, tagRow.SourceLineNumbers)); - using (var fs = new FileStream(fileSymbol.Source.Path, FileMode.Create)) + using (var fs = this.FileSystem.OpenFile(fileSymbol.SourceLineNumbers, fileSymbol.Source.Path, FileMode.Create, FileAccess.ReadWrite, FileShare.Read)) { CreateTagFile(fs, uniqueId, packageSymbol.Name, packageSymbol.Version, tagRow.Regid, packageSymbol.Manufacturer, persistentId); } diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs index 7f764f49..b51e3a0f 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs @@ -84,7 +84,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind return; } - using (var fileStream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (var fileStream = this.FileSystem.OpenFile(facade.SourceLineNumber, fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.Read)) { if (Int32.MaxValue < fileStream.Length) { diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs index 3f0d0c51..455057f6 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs @@ -51,7 +51,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe if (!String.Equals(this.InputPath, this.OutputPath, StringComparison.OrdinalIgnoreCase)) { - this.FileSystem.CopyFile(this.InputPath, this.OutputPath, allowHardlink: false); + this.FileSystem.CopyFile(null, this.InputPath, this.OutputPath, allowHardlink: false); } var attributes = File.GetAttributes(databasePath); @@ -98,7 +98,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe Directory.CreateDirectory(hashPath); hashPath = Path.Combine(hashPath, hashFileName); - using (var fs = this.FileSystem.OpenFile(hashPath, FileMode.Create, FileAccess.Write, FileShare.None)) + using (var fs = this.FileSystem.OpenFile(null, hashPath, FileMode.Create, FileAccess.Write, FileShare.None)) { int bytesRead; var buffer = new byte[1024 * 4]; @@ -129,7 +129,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe Directory.CreateDirectory(certPath); certPath = Path.Combine(certPath, String.Concat(certificateId, ".cer")); - using (var fs = this.FileSystem.OpenFile(certPath, FileMode.Create, FileAccess.Write, FileShare.None)) + using (var fs = this.FileSystem.OpenFile(null, certPath, FileMode.Create, FileAccess.Write, FileShare.None)) { int bytesRead; var buffer = new byte[1024 * 4]; @@ -223,9 +223,9 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe var certPath = Path.Combine(this.IntermediateFolder, "MsiDigitalCertificate"); Directory.CreateDirectory(certPath); certPath = Path.Combine(certPath, String.Concat(cert2.Thumbprint, ".cer")); - this.FileSystem.DeleteFile(certPath, true); + this.FileSystem.DeleteFile(null, certPath, true); - using (var writer = new BinaryWriter(this.FileSystem.OpenFile(certPath, FileMode.Create, FileAccess.Write, FileShare.Read))) + using (var writer = new BinaryWriter(this.FileSystem.OpenFile(null, certPath, FileMode.Create, FileAccess.Write, FileShare.Read))) { writer.Write(cert2.RawData); writer.Close(); diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs index c2981b08..bfbe0339 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs @@ -97,6 +97,8 @@ namespace WixToolset.Core.WindowsInstaller.Unbind { if (null != record) { + embeddedCabinetRowsByDiskId.TryGetValue(diskId, out var cabinetMediaRow); + // since the cabinets are stored in case-sensitive streams inside the msi, but the file system is not (typically) case-sensitive, // embedded cabinets must be extracted to a canonical file name (like their diskid) to ensure extraction will always work var cabinetPath = Path.Combine(this.IntermediateFolder, "Media", diskId.ToString(CultureInfo.InvariantCulture), ".cab"); @@ -104,7 +106,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind // ensure the parent directory exists Directory.CreateDirectory(Path.GetDirectoryName(cabinetPath)); - using (var fs = this.FileSystem.OpenFile(cabinetPath, FileMode.Create, FileAccess.Write, FileShare.None)) + using (var fs = this.FileSystem.OpenFile(cabinetMediaRow.SourceLineNumbers, cabinetPath, FileMode.Create, FileAccess.Write, FileShare.None)) { int bytesRead; var buffer = new byte[4096]; @@ -115,7 +117,6 @@ namespace WixToolset.Core.WindowsInstaller.Unbind } } - embeddedCabinetRowsByDiskId.TryGetValue(diskId, out var cabinetMediaRow); cabinetPathsWithMediaRow.Add(cabinetPath, cabinetMediaRow); } else diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs index 54534e50..9ad936e4 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs @@ -206,7 +206,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind Directory.CreateDirectory(Path.Combine(this.ExportBasePath, tableName)); - using (var fs = this.FileSystem.OpenFile(source, FileMode.Create, FileAccess.Write, FileShare.None)) + using (var fs = this.FileSystem.OpenFile(null, source, FileMode.Create, FileAccess.Write, FileShare.None)) { int bytesRead; var buffer = new byte[4096]; diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTransformCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTransformCommand.cs index bb4da1ed..49759d2c 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTransformCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTransformCommand.cs @@ -327,7 +327,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind if (null == this.EmptyFile) { this.EmptyFile = Path.Combine(this.IntermediateFolder, ".empty"); - using (var fileStream = this.FileSystem.OpenFile(this.EmptyFile, FileMode.Create, FileAccess.Write, FileShare.None)) + using (var fileStream = this.FileSystem.OpenFile(null, this.EmptyFile, FileMode.Create, FileAccess.Write, FileShare.None)) { } } diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Validate/ValidateDatabaseCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Validate/ValidateDatabaseCommand.cs index 24dd9927..6996dc44 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Validate/ValidateDatabaseCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Validate/ValidateDatabaseCommand.cs @@ -71,7 +71,7 @@ namespace WixToolset.Core.WindowsInstaller.Validate var workingDatabasePath = Path.Combine(this.IntermediateFolder, workingDatabaseFilename); try { - this.FileSystem.CopyFile(this.DatabasePath, workingDatabasePath, allowHardlink: false); + this.FileSystem.CopyFile(null, this.DatabasePath, workingDatabasePath, allowHardlink: false); var attributes = File.GetAttributes(workingDatabasePath); File.SetAttributes(workingDatabasePath, attributes & ~FileAttributes.ReadOnly); @@ -81,7 +81,7 @@ namespace WixToolset.Core.WindowsInstaller.Validate } finally { - this.FileSystem.DeleteFile(workingDatabasePath); + this.FileSystem.DeleteFile(null, workingDatabasePath); } stopwatch.Stop(); diff --git a/src/wix/WixToolset.Core/Bind/TransferFilesCommand.cs b/src/wix/WixToolset.Core/Bind/TransferFilesCommand.cs index 4a0329bc..28ca6b49 100644 --- a/src/wix/WixToolset.Core/Bind/TransferFilesCommand.cs +++ b/src/wix/WixToolset.Core/Bind/TransferFilesCommand.cs @@ -53,12 +53,12 @@ namespace WixToolset.Core.Bind if (fileTransfer.Move) { this.Messaging.Write(VerboseMessages.MoveFile(fileTransfer.Source, fileTransfer.Destination)); - this.MoveFile(fileTransfer.Source, fileTransfer.Destination); + this.MoveFile(fileTransfer.SourceLineNumbers, fileTransfer.Source, fileTransfer.Destination); } else { this.Messaging.Write(VerboseMessages.CopyFile(fileTransfer.Source, fileTransfer.Destination)); - this.CopyFile(fileTransfer.Source, fileTransfer.Destination); + this.CopyFile(fileTransfer.SourceLineNumbers, fileTransfer.Source, fileTransfer.Destination); } retry = false; @@ -170,7 +170,7 @@ namespace WixToolset.Core.Bind } } - private void CopyFile(string source, string destination) + private void CopyFile(SourceLineNumber sourceLineNumbers, string source, string destination) { foreach (var extension in this.Extensions) { @@ -180,10 +180,10 @@ namespace WixToolset.Core.Bind } } - this.FileSystem.CopyFile(source, destination, allowHardlink: true); + this.FileSystem.CopyFile(sourceLineNumbers, source, destination, allowHardlink: true); } - private void MoveFile(string source, string destination) + private void MoveFile(SourceLineNumber sourceLineNumbers, string source, string destination) { foreach (var extension in this.Extensions) { @@ -193,7 +193,7 @@ namespace WixToolset.Core.Bind } } - this.FileSystem.MoveFile(source, destination); + this.FileSystem.MoveFile(sourceLineNumbers, source, destination); } private void AclReset(IEnumerable files) diff --git a/src/wix/WixToolset.Core/CoreErrors.cs b/src/wix/WixToolset.Core/CoreErrors.cs new file mode 100644 index 00000000..6dbd6c88 --- /dev/null +++ b/src/wix/WixToolset.Core/CoreErrors.cs @@ -0,0 +1,42 @@ +// 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. + +namespace WixToolset.Core +{ + using WixToolset.Data; + + internal static class CoreErrors + { + public static Message UnableToCopyFile(SourceLineNumber sourceLineNumbers, string source, string destination, string detail) + { + return Message(sourceLineNumbers, Ids.UnableToCopyFile, "Unable to copy file from: {0}, to: {1}. Error detail: {2}", source, destination, detail); + } + + public static Message UnableToDeleteFile(SourceLineNumber sourceLineNumbers, string path, string detail) + { + return Message(sourceLineNumbers, Ids.UnableToDeleteFile, "Unable to delete file: {0}. Error detail: {1}", path, detail); + } + + public static Message UnableToMoveFile(SourceLineNumber sourceLineNumbers, string source, string destination, string detail) + { + return Message(sourceLineNumbers, Ids.UnableToMoveFile, "Unable to move file from: {0}, to: {1}. Error detail: {2}", source, destination, detail); + } + + public static Message UnableToOpenFile(SourceLineNumber sourceLineNumbers, string path, string detail) + { + return Message(sourceLineNumbers, Ids.UnableToOpenFile, "Unable to open file: {0}. Error detail: {1}", path, detail); + } + + private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args) + { + return new Message(sourceLineNumber, MessageLevel.Error, (int)id, format, args); + } + + public enum Ids + { + UnableToCopyFile = 7010, + UnableToDeleteFile = 7011, + UnableToMoveFile = 7012, + UnableToOpenFile = 7013, + } // last available is 7099. 7100 is WindowsInstallerBackendWarnings. + } +} diff --git a/src/wix/WixToolset.Core/ExtensibilityServices/FileSystem.cs b/src/wix/WixToolset.Core/ExtensibilityServices/FileSystem.cs index 8cf7a872..8baee3d8 100644 --- a/src/wix/WixToolset.Core/ExtensibilityServices/FileSystem.cs +++ b/src/wix/WixToolset.Core/ExtensibilityServices/FileSystem.cs @@ -7,19 +7,34 @@ namespace WixToolset.Core.ExtensibilityServices using System.IO; using System.Runtime.InteropServices; using System.Threading; + using WixToolset.Data; using WixToolset.Extensibility.Services; internal class FileSystem : IFileSystem { - public void CopyFile(string source, string destination, bool allowHardlink) + public void CopyFile(SourceLineNumber sourceLineNumbers, string source, string destination, bool allowHardlink) { - this.EnsureDirectoryWithoutFile(destination); + try + { + this.EnsureDirectoryWithoutFile(destination); + } + catch (Exception e) + { + throw new WixException(CoreErrors.UnableToCopyFile(sourceLineNumbers, source, destination, e.Message), e); + } var hardlinked = false; if (allowHardlink) { - this.ExecuteWithRetries(() => hardlinked = CreateHardLink(destination, source, IntPtr.Zero)); + try + { + this.ExecuteWithRetries(() => hardlinked = CreateHardLink(destination, source, IntPtr.Zero)); + } + catch + { + // Catch hard-link failures and fall back to copy file. + } } if (!hardlinked) @@ -28,30 +43,48 @@ namespace WixToolset.Core.ExtensibilityServices var er = Marshal.GetLastWin32Error(); #endif - this.ExecuteWithRetries(() => File.Copy(source, destination, overwrite: true)); + try + { + this.ExecuteWithRetries(() => File.Copy(source, destination, overwrite: true)); + } + catch (Exception e) + { + throw new WixException(CoreErrors.UnableToCopyFile(sourceLineNumbers, source, destination, e.Message), e); + } } } - public void DeleteFile(string source, bool throwOnError = false, int maxRetries = 4) + public void DeleteFile(SourceLineNumber sourceLineNumbers, string source, bool throwOnError = false, int maxRetries = 4) { try { this.ExecuteWithRetries(() => File.Delete(source), maxRetries); } - catch when (!throwOnError) + catch (Exception e) { - // Do nothing on best-effort deletes. + if (throwOnError) + { + throw new WixException(CoreErrors.UnableToDeleteFile(sourceLineNumbers, source, e.Message), e); + } + // else do nothing on best-effort deletes. } } - public void MoveFile(string source, string destination) + public void MoveFile(SourceLineNumber sourceLineNumbers, string source, string destination) { - this.EnsureDirectoryWithoutFile(destination); + try + { + this.EnsureDirectoryWithoutFile(destination); - this.ExecuteWithRetries(() => File.Move(source, destination)); + this.ExecuteWithRetries(() => File.Move(source, destination)); + } + catch (Exception e) + { + throw new WixException(CoreErrors.UnableToMoveFile(sourceLineNumbers, source, destination, e.Message), e); + } } - public FileStream OpenFile(string path, FileMode mode, FileAccess access, FileShare share) + public FileStream OpenFile(SourceLineNumber sourceLineNumbers, string path, FileMode mode, FileAccess access, FileShare share) { const int maxRetries = 4; @@ -61,9 +94,16 @@ namespace WixToolset.Core.ExtensibilityServices { return File.Open(path, mode, access, share); } - catch (Exception e) when (attempt < maxRetries && (e is IOException || e is SystemException || e is Win32Exception)) + catch (Exception e) when (e is IOException || e is SystemException || e is Win32Exception) { - Thread.Sleep(250); + if (attempt < maxRetries) + { + Thread.Sleep(250); + } + else + { + throw new WixException(CoreErrors.UnableToOpenFile(sourceLineNumbers, path, e.Message), e); + } } } diff --git a/src/wix/WixToolset.Core/LayoutCreator.cs b/src/wix/WixToolset.Core/LayoutCreator.cs index c361f78a..f26b1127 100644 --- a/src/wix/WixToolset.Core/LayoutCreator.cs +++ b/src/wix/WixToolset.Core/LayoutCreator.cs @@ -114,7 +114,7 @@ namespace WixToolset.Core { this.SplitUniqueFolders(intermediateFolder, tempPath, uniqueFolders); - this.FileSystem.DeleteFile(tempPath); + this.FileSystem.DeleteFile(null, tempPath); } // Clean up empty temp folders. -- cgit v1.2.3-55-g6feb