Skip to content
/ wix Public

Commit 164ea64

Browse files
committed
Fix anonymous Directory Id generation to be consistent
Fixes 7861
1 parent 130bbb7 commit 164ea64

File tree

5 files changed

+120
-40
lines changed

5 files changed

+120
-40
lines changed

src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ public WindowsInstallerData Execute()
6262

6363
private void AddSectionToData()
6464
{
65-
var cellsByTableAndRowId = new Dictionary<string, List<WixCustomTableCellSymbol>>();
65+
var directoryRowsById = new Dictionary<string, Row>(StringComparer.Ordinal);
66+
var cellsByTableAndRowId = new Dictionary<string, List<WixCustomTableCellSymbol>>(StringComparer.Ordinal);
6667

6768
foreach (var symbol in this.Section.Symbols)
6869
{
@@ -107,7 +108,7 @@ private void AddSectionToData()
107108
break;
108109

109110
case SymbolDefinitionType.Directory:
110-
this.AddDirectorySymbol((DirectorySymbol)symbol);
111+
this.AddDirectorySymbol((DirectorySymbol)symbol, directoryRowsById);
111112
break;
112113

113114
case SymbolDefinitionType.DuplicateFile:
@@ -497,9 +498,9 @@ private void AddDialogSymbol(DialogSymbol symbol)
497498
this.Data.EnsureTable(this.TableDefinitions["ListBox"]);
498499
}
499500

500-
private void AddDirectorySymbol(DirectorySymbol symbol)
501+
private void AddDirectorySymbol(DirectorySymbol symbol, Dictionary<string, Row> directoryRowsById)
501502
{
502-
(var name, var parentDir) = this.AddDirectorySubdirectories(symbol);
503+
(var name, var parentDir) = this.AddDirectorySubdirectories(symbol, directoryRowsById);
503504

504505
var shortName = symbol.ShortName;
505506
var sourceShortname = symbol.SourceShortName;
@@ -524,10 +525,7 @@ private void AddDirectorySymbol(DirectorySymbol symbol)
524525

525526
var defaultDir = String.IsNullOrEmpty(sourceName) || sourceName == targetName ? targetName : targetName + ":" + sourceName;
526527

527-
var row = this.CreateRow(symbol, "Directory");
528-
row[0] = symbol.Id.Id;
529-
row[1] = parentDir;
530-
row[2] = defaultDir;
528+
this.CreateOrAddDirectoryRow(directoryRowsById, symbol, symbol.Id.Id, parentDir, defaultDir);
531529

532530
if (OutputType.Module == this.Data.Type)
533531
{
@@ -1146,7 +1144,7 @@ private void AddWixActionSymbol(WixActionSymbol symbol)
11461144
}
11471145
else
11481146
{
1149-
var after = (null == symbol.Before);
1147+
var after = null == symbol.Before;
11501148
row[2] = after ? symbol.After : symbol.Before;
11511149
row[3] = after ? 1 : 0;
11521150
}
@@ -1271,7 +1269,7 @@ private void AddWixModuleSymbol(WixModuleSymbol symbol)
12711269
}
12721270
}
12731271

1274-
private void AddWixPackageSymbol(WixPackageSymbol symbol)
1272+
private void AddWixPackageSymbol(WixPackageSymbol _)
12751273
{
12761274
// TODO: Remove the following from the compiler and do it here instead.
12771275
//this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "Manufacturer"), manufacturer, false, false, false, true);
@@ -1319,11 +1317,10 @@ private void EnsureModuleIgnoredTable(IntermediateSymbol symbol, string ignoredT
13191317
}
13201318
}
13211319

1322-
private (string, string) AddDirectorySubdirectories(DirectorySymbol symbol)
1320+
private (string, string) AddDirectorySubdirectories(DirectorySymbol symbol, Dictionary<string, Row> directoryRowsById)
13231321
{
13241322
var directory = symbol.Name.Trim(PathSeparatorChars);
13251323
var parentDir = symbol.ParentDirectoryRef ?? (symbol.Id.Id == "TARGETDIR" ? null : "TARGETDIR");
1326-
var directoryRows = this.Data.TryGetTable("Directory", out var table) ? table.Rows.ToDictionary(row => row.FieldAsString(0)) : new Dictionary<string, Row>();
13271324

13281325
var start = 0;
13291326
var end = directory.IndexOfAny(PathSeparatorChars);
@@ -1337,18 +1334,11 @@ private void EnsureModuleIgnoredTable(IntermediateSymbol symbol, string ignoredT
13371334
{
13381335
path = Path.Combine(path, subdirectoryName);
13391336

1340-
var id = this.BackendHelper.GenerateIdentifier("d", symbol.ParentDirectoryRef, path);
1337+
var id = this.BackendHelper.GenerateIdentifier("d", symbol.ParentDirectoryRef, path, /*shortName:*/ null, /*sourceName:*/ null, /*shortSourceName:*/ null);
13411338
var shortnameSubdirectory = this.BackendHelper.IsValidShortFilename(subdirectoryName, false) ? null : this.CreateShortName(subdirectoryName, false, "Directory", symbol.ParentDirectoryRef);
1339+
var defaultDir = CreateMsiFilename(shortnameSubdirectory, subdirectoryName);
13421340

1343-
if (!directoryRows.ContainsKey(id))
1344-
{
1345-
var subdirectoryRow = this.CreateRow(symbol, "Directory");
1346-
subdirectoryRow[0] = id;
1347-
subdirectoryRow[1] = parentDir;
1348-
subdirectoryRow[2] = CreateMsiFilename(shortnameSubdirectory, subdirectoryName);
1349-
1350-
directoryRows.Add(id, subdirectoryRow);
1351-
}
1341+
this.CreateOrAddDirectoryRow(directoryRowsById, symbol, id, parentDir, defaultDir);
13521342

13531343
parentDir = id;
13541344
}
@@ -1362,6 +1352,25 @@ private void EnsureModuleIgnoredTable(IntermediateSymbol symbol, string ignoredT
13621352
return (name, parentDir);
13631353
}
13641354

1355+
private Row CreateOrAddDirectoryRow(Dictionary<string, Row> directoryRowsById, DirectorySymbol symbol, string id, string parentDir, string defaultDir)
1356+
{
1357+
if (!directoryRowsById.TryGetValue(id, out var directoryRow))
1358+
{
1359+
directoryRow = this.CreateRow(symbol, "Directory");
1360+
directoryRow[0] = id;
1361+
directoryRow[1] = parentDir;
1362+
directoryRow[2] = defaultDir;
1363+
1364+
directoryRowsById.Add(id, directoryRow);
1365+
}
1366+
else if (directoryRow.FieldAsString(1) != parentDir || directoryRow.FieldAsString(2) != defaultDir)
1367+
{
1368+
throw new WixException(WindowsInstallerBackendErrors.UnexpectedAnonymousDirectoryCollision(symbol.SourceLineNumbers, symbol.Id.Id, parentDir, defaultDir, directoryRow.SourceLineNumbers, directoryRow.FieldAsString(1), directoryRow.FieldAsString(2)));
1369+
}
1370+
1371+
return directoryRow;
1372+
}
1373+
13651374
private void EnsureRequiredTables()
13661375
{
13671376
// check for missing table and add them or display an error as appropriate
@@ -1412,7 +1421,7 @@ private void ReportIllegalTables()
14121421
"Upgrade" == table.Name ||
14131422
"WixMerge" == table.Name)
14141423
{
1415-
foreach (Row row in table.Rows)
1424+
foreach (var row in table.Rows)
14161425
{
14171426
this.Messaging.Write(ErrorMessages.UnexpectedTableInMergeModule(row.SourceLineNumbers, table.Name));
14181427
}
@@ -1609,8 +1618,10 @@ private string CreateShortName(string longName, bool keepExtension, params strin
16091618
longName = longName.ToLowerInvariant();
16101619

16111620
// collect all the data
1612-
var strings = new List<string>(1 + args.Length);
1613-
strings.Add(longName);
1621+
var strings = new List<string>(1 + args.Length)
1622+
{
1623+
longName
1624+
};
16141625
strings.AddRange(args);
16151626

16161627
// prepare for hashing
@@ -1625,8 +1636,10 @@ private string CreateShortName(string longName, bool keepExtension, params strin
16251636
}
16261637

16271638
// generate the short file/directory name without an extension
1628-
var shortName = new StringBuilder(Convert.ToBase64String(hash));
1629-
shortName.Length = 8;
1639+
var shortName = new StringBuilder(Convert.ToBase64String(hash))
1640+
{
1641+
Length = 8
1642+
};
16301643
shortName.Replace('+', '-').Replace('/', '_');
16311644

16321645
if (keepExtension)

src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerBackendErrors.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ public static Message InvalidWindowsInstallerWixpdbForValidation(string wixpdbPa
3939
return Message(null, Ids.InvalidWindowsInstallerWixpdbForValidation, "The validation .wixpdb file: {0} was not from a Windows Installer database build (.msi or .msm). Verify that the output type was actually an MSI Package or Merge Module.", wixpdbPath);
4040
}
4141

42+
public static Message UnexpectedAnonymousDirectoryCollision(SourceLineNumber sourceLineNumbers, string id, string parentDir, string defaultDir, SourceLineNumber existingSourceLineNumbers, string existingParentDir, string existingDefaultDir)
43+
{
44+
return Message(sourceLineNumbers, Ids.UnexpectedAnonymousDirectoryCollision, "This should not happen. The first directory id '{0}' uses parent directory '{1}' with DefaultDir '{2}'. The colliding directory uses parent directory '{3}' with DefaultDir '{4}' from line: {5}", id, parentDir, defaultDir, existingParentDir, existingDefaultDir, existingSourceLineNumbers.ToString());
45+
}
46+
4247
public static Message UnknownDecompileType(string decompileType, string filePath)
4348
{
4449
return Message(null, Ids.UnknownDecompileType, "Unknown decompile type '{0}' from input: {1}", decompileType, filePath);
@@ -65,6 +70,7 @@ public enum Ids
6570
UnknownDecompileType = 7504,
6671
UnknownValidationTargetFileExtension = 7505,
6772
InvalidWindowsInstallerWixpdbForValidation = 7506,
73+
UnexpectedAnonymousDirectoryCollision = 7507,
6874
} // last available is 7999. 8000 is BurnBackendErrors.
6975
}
7076
}

src/wix/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,45 @@ public void CanGet64bitProgramFiles6432Folder()
162162
}
163163
}
164164

165+
[Fact]
166+
public void CanGetAnonymousDirectories()
167+
{
168+
var folder = TestData.Get("TestData");
169+
170+
using (var fs = new DisposableFileSystem())
171+
{
172+
var baseFolder = fs.GetFolder();
173+
var intermediateFolder = Path.Combine(baseFolder, "obj");
174+
var wixlibPath = Path.Combine(baseFolder, "bin", "test.msi");
175+
176+
var result = WixRunner.Execute(
177+
[
178+
"build",
179+
"-arch", "x64",
180+
Path.Combine(folder, "Directory", "AnonymousDirectories.wxs"),
181+
"-bindpath", Path.Combine(folder, "SingleFile", "data"),
182+
"-intermediateFolder", intermediateFolder,
183+
"-o", wixlibPath
184+
]);
185+
186+
result.AssertSuccess();
187+
188+
var pdb = WindowsInstallerData.Load(Path.Combine(baseFolder, "bin", "test.wixpdb"));
189+
var directoryRows = pdb.Tables["Directory"].Rows;
190+
191+
var dirs = directoryRows.Select(d => d.ToString()).OrderBy(s => s).ToArray();
192+
WixAssert.CompareLineByLine(
193+
[
194+
@"DesktopFolder/TARGETDIR/Desktop",
195+
@"dHKac23vLoBC5fFrqxqAIybMFOj0/DesktopFolder/a",
196+
@"dKom2ks4onBH9RsYLDhjge71s7s8/dlvpu0ovv8DWWVrdCVSYzDfsibzg/c",
197+
@"dlvpu0ovv8DWWVrdCVSYzDfsibzg/dHKac23vLoBC5fFrqxqAIybMFOj0/b",
198+
@"SomeFolder/TARGETDIR/fef2brvc|Some Folder",
199+
@"TARGETDIR//SourceDir"
200+
], dirs);
201+
}
202+
}
203+
165204
[Fact]
166205
public void CanGetDefaultName()
167206
{
@@ -293,9 +332,9 @@ public void CanGetWithMultiNestedSubdirectory()
293332
var directoryRows = data.Tables["Directory"].Rows;
294333
WixAssert.CompareLineByLine(new[]
295334
{
296-
"d4EceYatXTyy8HXPt5B6DT9Rj.wE:ProgramFilesFolder:u7-b4gch|Example Corporation",
297-
"dSJ1pgiASlW7kJTu0wqsGBklJsS0:d4EceYatXTyy8HXPt5B6DT9Rj.wE:vjj-gxay|Test Product",
298-
"BinFolder:dSJ1pgiASlW7kJTu0wqsGBklJsS0:bin",
335+
"dwGveZhe5wcMbbRyRAkRwm2sqnE4:ProgramFilesFolder:u7-b4gch|Example Corporation",
336+
"d8kPFuRMPxdOxfpYS0O8azlhLUpY:dwGveZhe5wcMbbRyRAkRwm2sqnE4:vjj-gxay|Test Product",
337+
"BinFolder:d8kPFuRMPxdOxfpYS0O8azlhLUpY:bin",
299338
"ProgramFilesFolder:TARGETDIR:PFiles",
300339
"TARGETDIR::SourceDir"
301340
}, directoryRows.Select(r => r.FieldAsString(0) + ":" + r.FieldAsString(1) + ":" + r.FieldAsString(2)).ToArray());
@@ -386,9 +425,9 @@ public void CanFindRedundantSubdirectoryInSecondSection()
386425
var directoryRows = data.Tables["Directory"].Rows;
387426
WixAssert.CompareLineByLine(new[]
388427
{
389-
@"d1nVb5_zcCwRCz7i2YXNAofGRmfc:ProgramFilesFolder:a",
390-
@"dijlG.bNicFgvj1_DujiGg9EBGrQ:d1nVb5_zcCwRCz7i2YXNAofGRmfc:b",
391-
@"dKO7wPCF.XLmq6KnqybHHgcBBqtU:dijlG.bNicFgvj1_DujiGg9EBGrQ:c",
428+
@"dKO7wPCF.XLmq6KnqybHHgcBBqtU:dvFwapipzsdDBjHbM5DUi_2llN.k:c",
429+
@"dvFwapipzsdDBjHbM5DUi_2llN.k:dyJuT.V6E4sWuHVv3CZiBNvrX2Lo:b",
430+
@"dyJuT.V6E4sWuHVv3CZiBNvrX2Lo:ProgramFilesFolder:a",
392431
"ProgramFilesFolder:TARGETDIR:PFiles",
393432
"TARGETDIR::SourceDir"
394433
}, directoryRows.Select(r => r.FieldAsString(0) + ":" + r.FieldAsString(1) + ":" + r.FieldAsString(2)).OrderBy(s => s).ToArray());

src/wix/test/WixToolsetTest.CoreIntegration/LanguageFixture.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,13 @@ public void CanBuildWithDefaultProductLanguage()
5656

5757
var data = WindowsInstallerData.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"));
5858
var directoryRows = data.Tables["Directory"].Rows;
59-
WixAssert.CompareLineByLine(new[]
60-
{
61-
"d4EceYatXTyy8HXPt5B6DT9Rj.wE:u7-b4gch|Example Corporation",
62-
"INSTALLFOLDER:oekcr5lq|MsiPackage",
63-
"ProgramFilesFolder:PFiles",
64-
"TARGETDIR:SourceDir"
65-
}, directoryRows.Select(r => r.FieldAsString(0) + ":" + r.FieldAsString(2)).ToArray());
59+
WixAssert.CompareLineByLine(
60+
[
61+
"dwGveZhe5wcMbbRyRAkRwm2sqnE4:ProgramFilesFolder:u7-b4gch|Example Corporation",
62+
"INSTALLFOLDER:dwGveZhe5wcMbbRyRAkRwm2sqnE4:oekcr5lq|MsiPackage",
63+
"ProgramFilesFolder:TARGETDIR:PFiles",
64+
"TARGETDIR::SourceDir"
65+
], [.. directoryRows.Select(r => r.FieldAsString(0) + ":" + r.FieldAsString(1) + ":" + r.FieldAsString(2))]);
6666
}
6767
}
6868

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3+
<Package Id="WixToolsetTest.TestPackage" Name="~RedundantSubdirectories" Version="1.0.0.0" Manufacturer="Example Corporation" Compressed="no">
4+
<ComponentGroupRef Id="Files" />
5+
6+
<Directory Id="SomeFolder" Name="Some Folder" />
7+
</Package>
8+
9+
<Fragment>
10+
<ComponentGroup Id="Files">
11+
<Component Directory="SomeFolder">
12+
<File Source="test.txt" KeyPath="yes">
13+
<Shortcut Id="Shortcut1" Name="Test Shortcut" Directory="DesktopFolder" Subdirectory="a\b\c" Advertise="yes" />
14+
</File>
15+
16+
<RemoveFolder Id="RemoveAFolder" Directory="DesktopFolder" Subdirectory="a" On="uninstall" />
17+
<RemoveFolder Id="RemoveBFolder" Directory="DesktopFolder" Subdirectory="a\b" On="uninstall" />
18+
<RemoveFolder Id="RemoveCFolder" Directory="DesktopFolder" Subdirectory="a\b\c" On="uninstall" />
19+
</Component>
20+
</ComponentGroup>
21+
</Fragment>
22+
</Wix>

0 commit comments

Comments
 (0)