diff --git a/src/wix/WixToolset.Core.Burn/Bind/ProcessBundleSoftwareTagsCommand.cs b/src/wix/WixToolset.Core.Burn/Bind/ProcessBundleSoftwareTagsCommand.cs index 5231e0bed..70b98222f 100644 --- a/src/wix/WixToolset.Core.Burn/Bind/ProcessBundleSoftwareTagsCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bind/ProcessBundleSoftwareTagsCommand.cs @@ -69,7 +69,7 @@ private static IEnumerable CollectPackageTags(IntermediateSection s { var payload = payloadSymbolsById[msiPackage.PayloadRef]; - using (var db = new Database(payload.SourceFile.Path, OpenDatabase.ReadOnly)) + using (var db = Database.OpenAsReadOnly(payload.SourceFile.Path)) { if (db.TableExists("SoftwareIdentificationTag")) { diff --git a/src/wix/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs index d6cf1cfd7..0b78c5455 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs @@ -164,7 +164,7 @@ public WixBundleHarvestedMsiPackageSymbol HarvestPackage() this.CheckIfWindowsInstallerFileTooLarge(this.PackagePayload.SourceLineNumbers, sourcePath, "MSI"); - using (var db = new Database(sourcePath, OpenDatabase.ReadOnly)) + using (var db = Database.OpenAsReadOnly(sourcePath)) { // Read data out of the msi database... using (var sumInfo = new SummaryInformation(db)) diff --git a/src/wix/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs index b889c2ce1..8d1e9c392 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs @@ -98,7 +98,7 @@ private WixBundleHarvestedMspPackageSymbol HarvestPackage() try { - using (var db = new Database(sourcePath, OpenDatabase.ReadOnly | OpenDatabase.OpenPatchFile)) + using (var db = Database.OpenAsReadOnly(sourcePath, asPatch: true)) { // Read data out of the msp database... using (var sumInfo = new SummaryInformation(db)) diff --git a/src/wix/WixToolset.Core.Native/LongPathUtil.cs b/src/wix/WixToolset.Core.Native/LongPathUtil.cs new file mode 100644 index 000000000..c24f1736b --- /dev/null +++ b/src/wix/WixToolset.Core.Native/LongPathUtil.cs @@ -0,0 +1,78 @@ +// 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.Native +{ + using System.IO; + using System.Runtime.InteropServices; + using System.Text; + + internal static class PathUtil + { + private const int MaxPath = 260; + private const string LongPathPrefix = @"\\?\"; + + public static bool CreateOrGetShortPath(string path, out string shortPath) + { + var fileCreated = false; + + // The file must exist so we can get its short path. + if (!File.Exists(path)) + { + using (File.Create(path)) + { + } + + fileCreated = true; + } + + // Use the short path to avoid issues with long paths in the MSI API. + shortPath = GetShortPath(path); + + return fileCreated; + } + + public static string GetPrefixedLongPath(string path) + { + if (path.Length > MaxPath && !path.StartsWith(LongPathPrefix)) + { + path = LongPathPrefix + path; + } + + return path; + } + + public static string GetShortPath(string longPath) + { + var path = GetPrefixedLongPath(longPath); + + var buffer = new StringBuilder(MaxPath); // start with MAX_PATH. + + var result = GetShortPathName(path, buffer, (uint)buffer.Capacity); + + // If result > buffer.Capacity, reallocate and call again (even though we're usually using short names to avoid long path) + // so the short path result is still going to end up too long for APIs requiring a short path. + if (result > buffer.Capacity) + { + buffer = new StringBuilder((int)result); + + result = GetShortPathName(path, buffer, (uint)buffer.Capacity); + } + + // If we succeeded, return the short path without the prefix. + if (result > 0) + { + path = buffer.ToString(); + + if (path.StartsWith(LongPathPrefix)) + { + path = path.Substring(LongPathPrefix.Length); + } + } + + return path; + } + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern uint GetShortPathName(string lpszLongPath, StringBuilder lpszShortPath, uint cchBuffer); + } +} diff --git a/src/wix/WixToolset.Core.Native/Msi/Database.cs b/src/wix/WixToolset.Core.Native/Msi/Database.cs index 18e5066d8..33eb8de65 100644 --- a/src/wix/WixToolset.Core.Native/Msi/Database.cs +++ b/src/wix/WixToolset.Core.Native/Msi/Database.cs @@ -18,13 +18,14 @@ public sealed class Database : MsiHandle /// /// Path to the database to be opened. /// Persist mode to use when opening the database. - public Database(string path, OpenDatabase type) + private Database(string path, OpenDatabase type) { var error = MsiInterop.MsiOpenDatabase(path, (IntPtr)type, out var handle); if (0 != error) { throw new MsiException(error); } + this.Handle = handle; } @@ -33,15 +34,90 @@ public Database(string path, OpenDatabase type) /// public static int MsiMaxStreamNameLength => MsiInterop.MsiMaxStreamNameLength; + /// + /// Creates a new with the specified path. + /// + /// Path of database to be created. + /// Indicates whether the database should be opened as a patch file. + public static Database Create(string path, bool asPatch = false) + { + var fileCreated = false; + var mode = OpenDatabase.CreateDirect; + + if (asPatch) + { + mode |= OpenDatabase.OpenPatchFile; + } + + try + { + fileCreated = PathUtil.CreateOrGetShortPath(path, out var shortPath); + + return new Database(shortPath, mode); + } + catch // cleanup on error if we created the short path file. + { + if (fileCreated) + { + File.Delete(path); + } + + throw; + } + } + + /// + /// Opens an existing with the specified path. + /// + /// Path of database to open. + /// Indicates whether to open the database in transaction mode. + /// Indicates whether the database should be opened as a patch file. + public static Database Open(string path, bool transact = false, bool asPatch = false) + { + var mode = transact ? OpenDatabase.Transact : OpenDatabase.Direct; + + if (asPatch) + { + mode |= OpenDatabase.OpenPatchFile; + } + + // Use the short path to avoid issues with long paths in the MSI API. + var shortPath = PathUtil.GetShortPath(path); + + return new Database(shortPath, mode); + } + + /// + /// Opens an existing with the specified path. + /// + /// Path of database to open. + /// Indicates whether the database should be opened as a patch file. + public static Database OpenAsReadOnly(string path, bool asPatch = false) + { + var mode = OpenDatabase.ReadOnly; + + if (asPatch) + { + mode |= OpenDatabase.OpenPatchFile; + } + + // Use the short path to avoid issues with long paths in the MSI API. + var shortPath = PathUtil.GetShortPath(path); + + return new Database(shortPath, mode); + } + /// /// Apply a transform to the MSI. /// /// Path to transform to apply. public void ApplyTransform(string transformFile) { + var shortTransformFile = PathUtil.GetShortPath(transformFile); + // get the curret validation bits var conditions = TransformErrorConditions.None; - using (var summaryInfo = new SummaryInformation(transformFile)) + using (var summaryInfo = new SummaryInformation(shortTransformFile)) { try { @@ -64,7 +140,9 @@ public void ApplyTransform(string transformFile) /// Specifies the error conditions that are to be suppressed. public void ApplyTransform(string transformFile, TransformErrorConditions errorConditions) { - var error = MsiInterop.MsiDatabaseApplyTransform(this.Handle, transformFile, errorConditions); + var shortTransformFile = PathUtil.GetShortPath(transformFile); + + var error = MsiInterop.MsiDatabaseApplyTransform(this.Handle, shortTransformFile, errorConditions); if (0 != error) { throw new MsiException(error); @@ -118,7 +196,9 @@ public void Commit() /// shows which properties should be validated to verify that this transform can be applied to the database. public void CreateTransformSummaryInfo(Database referenceDatabase, string transformFile, TransformErrorConditions errorConditions, TransformValidations validations) { - var error = MsiInterop.MsiCreateTransformSummaryInfo(this.Handle, referenceDatabase.Handle, transformFile, errorConditions, validations); + var shortTransformFile = PathUtil.GetShortPath(transformFile); + + var error = MsiInterop.MsiCreateTransformSummaryInfo(this.Handle, referenceDatabase.Handle, shortTransformFile, errorConditions, validations); if (0 != error) { throw new MsiException(error); @@ -136,7 +216,9 @@ public void Import(string idtPath) var folderPath = Path.GetFullPath(Path.GetDirectoryName(idtPath)); var fileName = Path.GetFileName(idtPath); - var error = MsiInterop.MsiDatabaseImport(this.Handle, folderPath, fileName); + var shortFolderPath = PathUtil.GetShortPath(folderPath); + + var error = MsiInterop.MsiDatabaseImport(this.Handle, shortFolderPath, fileName); if (1627 == error) // ERROR_FUNCTION_FAILED { throw new WixInvalidIdtException(idtPath); @@ -160,7 +242,9 @@ public void Export(string tableName, string folderPath, string fileName) folderPath = Environment.CurrentDirectory; } - var error = MsiInterop.MsiDatabaseExport(this.Handle, tableName, folderPath, fileName); + var shortFolderPath = PathUtil.GetShortPath(folderPath); + + var error = MsiInterop.MsiDatabaseExport(this.Handle, tableName, shortFolderPath, fileName); if (0 != error) { throw new MsiException(error); @@ -176,13 +260,29 @@ public void Export(string tableName, string folderPath, string fileName) /// there are no differences between the two databases. public bool GenerateTransform(Database referenceDatabase, string transformFile) { - var error = MsiInterop.MsiDatabaseGenerateTransform(this.Handle, referenceDatabase.Handle, transformFile, 0, 0); - if (0 != error && 0xE8 != error) // ERROR_NO_DATA(0xE8) means no differences were found + var fileCreated = false; + + try { - throw new MsiException(error); + fileCreated = PathUtil.CreateOrGetShortPath(transformFile, out var shortTransformFile); + + var error = MsiInterop.MsiDatabaseGenerateTransform(this.Handle, referenceDatabase.Handle, shortTransformFile, 0, 0); + if (0 != error && 0xE8 != error) // ERROR_NO_DATA(0xE8) means no differences were found + { + throw new MsiException(error); + } + + return (0xE8 != error); } + catch // Cleanup on error + { + if (fileCreated) + { + File.Delete(transformFile); + } - return (0xE8 != error); + throw; + } } /// diff --git a/src/wix/WixToolset.Core.Native/Msi/Installer.cs b/src/wix/WixToolset.Core.Native/Msi/Installer.cs index b2c2c6307..147454695 100644 --- a/src/wix/WixToolset.Core.Native/Msi/Installer.cs +++ b/src/wix/WixToolset.Core.Native/Msi/Installer.cs @@ -34,11 +34,13 @@ public static string ExtractPatchXml(string path) var buffer = new StringBuilder(65535); var size = buffer.Capacity; - var error = MsiInterop.MsiExtractPatchXMLData(path, 0, buffer, ref size); + var shortPath = PathUtil.GetShortPath(path); + + var error = MsiInterop.MsiExtractPatchXMLData(shortPath, 0, buffer, ref size); if (234 == error) { buffer.EnsureCapacity(++size); - error = MsiInterop.MsiExtractPatchXMLData(path, 0, buffer, ref size); + error = MsiInterop.MsiExtractPatchXMLData(shortPath, 0, buffer, ref size); } if (error != 0) @@ -57,8 +59,12 @@ public static string ExtractPatchXml(string path) /// Int array that receives the returned file hash information. public static void GetFileHash(string filePath, int options, out int[] hash) { - var hashInterop = new MSIFILEHASHINFO(); - hashInterop.FileHashInfoSize = 20; + var hashInterop = new MSIFILEHASHINFO + { + FileHashInfoSize = 20 + }; + + filePath = PathUtil.GetPrefixedLongPath(filePath); var error = MsiInterop.MsiGetFileHash(filePath, Convert.ToUInt32(options), hashInterop); if (0 != error) @@ -76,9 +82,9 @@ public static void GetFileHash(string filePath, int options, out int[] hash) } /// - /// Returns the version string and language string in the format that the installer - /// expects to find them in the database. If you just want version information, set - /// lpLangBuf and pcchLangBuf to zero. If you just want language information, set + /// Returns the version string and language string in the format that the installer + /// expects to find them in the database. If you just want version information, set + /// lpLangBuf and pcchLangBuf to zero. If you just want language information, set /// lpVersionBuf and pcchVersionBuf to zero. /// /// Specifies the path to the file. @@ -91,6 +97,8 @@ public static void GetFileVersion(string filePath, out string version, out strin var versionBuffer = new StringBuilder(versionLength); var languageBuffer = new StringBuilder(languageLength); + filePath = PathUtil.GetPrefixedLongPath(filePath); + var error = MsiInterop.MsiGetFileVersion(filePath, versionBuffer, ref versionLength, languageBuffer, ref languageLength); if (234 == error) { diff --git a/src/wix/WixToolset.Core.Native/Msi/OpenDatabase.cs b/src/wix/WixToolset.Core.Native/Msi/OpenDatabase.cs index 18a78f778..6d0226d29 100644 --- a/src/wix/WixToolset.Core.Native/Msi/OpenDatabase.cs +++ b/src/wix/WixToolset.Core.Native/Msi/OpenDatabase.cs @@ -1,4 +1,4 @@ -// 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. +// 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.Native.Msi { diff --git a/src/wix/WixToolset.Core.Native/Msi/SummaryInformation.cs b/src/wix/WixToolset.Core.Native/Msi/SummaryInformation.cs index 3b3dea0f2..3eed1274e 100644 --- a/src/wix/WixToolset.Core.Native/Msi/SummaryInformation.cs +++ b/src/wix/WixToolset.Core.Native/Msi/SummaryInformation.cs @@ -220,8 +220,10 @@ public SummaryInformation(string databaseFile) throw new ArgumentNullException(nameof(databaseFile)); } + var shortDatabaseFile = PathUtil.GetShortPath(databaseFile); + var handle = IntPtr.Zero; - var error = MsiInterop.MsiGetSummaryInformation(IntPtr.Zero, databaseFile, 0, ref handle); + var error = MsiInterop.MsiGetSummaryInformation(IntPtr.Zero, shortDatabaseFile, 0, ref handle); if (0 != error) { throw new MsiException(error); diff --git a/src/wix/WixToolset.Core.Native/WindowsInstallerValidator.cs b/src/wix/WixToolset.Core.Native/WindowsInstallerValidator.cs index 7978304ae..434b08872 100644 --- a/src/wix/WixToolset.Core.Native/WindowsInstallerValidator.cs +++ b/src/wix/WixToolset.Core.Native/WindowsInstallerValidator.cs @@ -93,7 +93,7 @@ private void RunValidations() try { - using (var database = new Database(this.DatabasePath, OpenDatabase.Direct)) + using (var database = Database.Open(this.DatabasePath)) { var propertyTableExists = database.TableExists("Property"); string productCode = null; @@ -130,7 +130,7 @@ private void RunValidations() try { - using (var cubeDatabase = new Database(findCubeFile.Path, OpenDatabase.ReadOnly)) + using (var cubeDatabase = Database.OpenAsReadOnly(findCubeFile.Path)) { try { diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs index b37c7b952..71dc48816 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs @@ -413,8 +413,8 @@ public void Execute() Directory.CreateDirectory(Path.GetDirectoryName(this.OutputPath)); // create the transform file - using (var targetDatabase = new Database(targetDatabaseFile, OpenDatabase.ReadOnly)) - using (var updatedDatabase = new Database(updatedDatabaseFile, OpenDatabase.ReadOnly)) + using (var targetDatabase = Database.OpenAsReadOnly(targetDatabaseFile)) + using (var updatedDatabase = Database.OpenAsReadOnly(updatedDatabaseFile)) { if (updatedDatabase.GenerateTransform(targetDatabase, this.OutputPath)) { diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs index 94ed0afc6..117923e55 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs @@ -90,7 +90,7 @@ private IReadOnlyCollection CreateFacadesForMergeModuleFiles(WixMe try { // read the module's File table to get its FileMediaInformation entries and gather any other information needed from the module. - using (var db = new Database(wixMergeRow.SourceFile, OpenDatabase.ReadOnly)) + using (var db = Database.OpenAsReadOnly(wixMergeRow.SourceFile)) { if (db.TableExists("File") && db.TableExists("Component")) { diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs index 361f797dd..a248dbd59 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs @@ -81,20 +81,13 @@ public void Execute() var idtFolder = Path.Combine(baseDirectory, IdtsSubFolder); - var type = OpenDatabase.CreateDirect; - - if (OutputType.Patch == this.Data.Type) - { - type |= OpenDatabase.OpenPatchFile; - } - try { Directory.CreateDirectory(Path.GetDirectoryName(this.OutputPath)); Directory.CreateDirectory(idtFolder); - using (var db = new Database(this.OutputPath, type)) + using (var db = Database.Create(this.OutputPath, asPatch: OutputType.Patch == this.Data.Type)) { // If we're not using the default codepage, import a new one into our // database before we add any tables (or the tables would be added diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs index 5f21f496e..71a2e367d 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs @@ -223,7 +223,7 @@ public void Execute() return; } - using (var db = new Database(this.OutputPath, OpenDatabase.Direct)) + using (var db = Database.Open(this.OutputPath)) { // Suppress individual actions. foreach (var suppressAction in this.Section.Symbols.OfType()) diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs index c5f198f89..ff7c65793 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs @@ -64,7 +64,7 @@ public void Execute() var mediaRows = this.Section.Symbols.OfType().ToDictionary(t => t.DiskId); - using (var db = new Database(this.DatabasePath, OpenDatabase.ReadOnly)) + using (var db = Database.OpenAsReadOnly(this.DatabasePath)) { using (var directoryView = db.OpenExecuteView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`")) { diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs index 52d2146c0..75e536c2e 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs @@ -76,7 +76,8 @@ private void UpdateFileFacadesInParallel(IEnumerable facades) var assemblySymbols = this.Section.Symbols.OfType().ToDictionary(t => t.Id.Id); Parallel.ForEach(facades, - new ParallelOptions{ + new ParallelOptions + { CancellationToken = this.CancellationToken, MaxDegreeOfParallelism = this.ThreadCount }, diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs index 455057f67..344cccb8e 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs @@ -61,7 +61,7 @@ public bool Execute() return shouldCommit; } - using (var database = new Database(databasePath, OpenDatabase.Transact)) + using (var database = Database.Open(databasePath, transact: true)) { // Just use the English codepage, because the tables we're importing only have binary streams / MSI identifiers / other non-localizable content var codepage = 1252; diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs index cfa532698..dce0d4888 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs @@ -86,7 +86,7 @@ public WindowsInstallerData Execute() { if (this.Database == null) { - database = new Database(this.DatabasePath, OpenDatabase.ReadOnly); + database = Database.OpenAsReadOnly(this.DatabasePath); this.Database = database; } diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTransformCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTransformCommand.cs index 8846739a4..cc83af725 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTransformCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTransformCommand.cs @@ -263,7 +263,7 @@ private void PopulateTransformFromView(string schemaDatabasePath, WindowsInstall private Database ApplyTransformToSchemaDatabase(string schemaDatabasePath, TransformErrorConditions transformConditions) { - var msiDatabase = new Database(schemaDatabasePath, OpenDatabase.Transact); + var msiDatabase = Database.Open(schemaDatabasePath, transact: true); try { diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/LongPathFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/LongPathFixture.cs new file mode 100644 index 000000000..2cada64d1 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/LongPathFixture.cs @@ -0,0 +1,89 @@ +// 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 WixToolsetTest.CoreIntegration +{ + using System.IO; + using System.Linq; + using WixInternal.Core.TestPackage; + using WixInternal.TestSupport; + using WixToolset.Data; + using WixToolset.Data.Symbols; + using Xunit; + + public class LongPathFixture + { + [Fact] + public void TestLongPathSupport() + { + var testDataFolder = TestData.Get(@"TestData", "SingleFile"); + + using (var fs = new DisposableFileSystem()) + { + var folder = fs.GetFolder(); + + while (folder.Length < 500) + { + folder = Path.Combine(folder, new string('z', 100)); + } + + CopyDirectory(testDataFolder, folder); + + var baseFolder = fs.GetFolder(); + + while (baseFolder.Length < 500) + { + baseFolder = Path.Combine(baseFolder, new string('a', 100)); + } + + var intermediateFolder = Path.Combine(baseFolder, "obj"); + + var result = WixRunner.Execute( + [ + "build", + Path.Combine(folder, "Package.wxs"), + Path.Combine(folder, "PackageComponents.wxs"), + "-loc", Path.Combine(folder, "Package.en-us.wxl"), + "-bindpath", Path.Combine(folder, "data"), + "-intermediateFolder", intermediateFolder, + "-o", Path.Combine(baseFolder, "bin", "test.msi") + ]); + + result.AssertSuccess(); + + Assert.True(File.Exists(Path.Combine(baseFolder, "bin", "test.msi"))); + Assert.True(File.Exists(Path.Combine(baseFolder, "bin", "test.wixpdb"))); + Assert.True(File.Exists(Path.Combine(baseFolder, "bin", "PFiles", "Example Corporation MsiPackage", "test.txt"))); + + var intermediate = Intermediate.Load(Path.Combine(baseFolder, "bin", "test.wixpdb")); + + var section = intermediate.Sections.Single(); + + var fileSymbol = section.Symbols.OfType().First(); + WixAssert.StringEqual(Path.Combine(folder, @"data\test.txt"), fileSymbol[FileSymbolFields.Source].AsPath().Path); + WixAssert.StringEqual(@"test.txt", fileSymbol[FileSymbolFields.Source].PreviousValue.AsPath().Path); + } + } + + private static void CopyDirectory(string sourceFolder, string targetFolder) + { + // Ensure the target directory exists + Directory.CreateDirectory(targetFolder); + + // Copy all files + foreach (var file in Directory.GetFiles(sourceFolder)) + { + var targetFile = Path.Combine(targetFolder, Path.GetFileName(file)); + + File.Copy(file, targetFile); + } + + // Recursively copy subdirectories + foreach (var subFolder in Directory.GetDirectories(sourceFolder)) + { + var targetSubFolder = Path.Combine(targetFolder, Path.GetFileName(subFolder)); + + CopyDirectory(subFolder, targetSubFolder); + } + } + } +} diff --git a/src/wix/wixnative/wixnative.manifest b/src/wix/wixnative/wixnative.manifest new file mode 100644 index 000000000..ce288e895 --- /dev/null +++ b/src/wix/wixnative/wixnative.manifest @@ -0,0 +1,9 @@ + + + + WiX Toolset Native + + true + + + diff --git a/src/wix/wixnative/wixnative.vcxproj b/src/wix/wixnative/wixnative.vcxproj index e4474bb1a..c4e05a623 100644 --- a/src/wix/wixnative/wixnative.vcxproj +++ b/src/wix/wixnative/wixnative.vcxproj @@ -55,6 +55,9 @@ + + +