diff --git a/src/Microsoft.DotNet.Arcade.Sdk/tools/Workarounds.targets b/src/Microsoft.DotNet.Arcade.Sdk/tools/Workarounds.targets index b45e3018635..5a6f851dcbd 100644 --- a/src/Microsoft.DotNet.Arcade.Sdk/tools/Workarounds.targets +++ b/src/Microsoft.DotNet.Arcade.Sdk/tools/Workarounds.targets @@ -1,5 +1,5 @@ - + + + + + + + + + + sb.Capacity) + { + sb = new StringBuilder((int)len); + len = GetFinalPathNameByHandleW(handle, sb, (uint)sb.Capacity, VOLUME_NAME_DOS); + if (len == 0) + { + return true; + } + } + + // Strip the extended-length prefix (\\?\ or \\?\UNC\) that + // GetFinalPathNameByHandle prepends. + string canonical = sb.ToString(); + if (canonical.StartsWith(@"\\?\UNC\", StringComparison.Ordinal)) + { + // UNC path: no drive letter to splice, leave unchanged. + return true; + } + if (canonical.StartsWith(@"\\?\", StringComparison.Ordinal)) + { + canonical = canonical.Substring(4); + } + + // Only adopt the canonical drive letter when the rest of the path is + // otherwise identical (case-insensitively). This rejects any structural + // change from symlink/junction resolution, which GetFinalPathNameByHandle + // performs but the child's Environment.ProcessPath (GetModuleFileNameW) + // does not - keeping both sides' salts in agreement. + // NetCoreSdkRoot carries a trailing directory separator, but + // GetFinalPathNameByHandle returns the path without one, so compare with + // trailing separators trimmed off both sides. + string canonicalTrimmed = canonical.TrimEnd('\\', '/'); + string sdkRootTrimmed = SdkRoot.TrimEnd('\\', '/'); + if (canonical.Length >= 2 && canonical[1] == ':' && + string.Equals(canonicalTrimmed, sdkRootTrimmed, StringComparison.OrdinalIgnoreCase)) + { + char canonicalDrive = canonical[0]; + if (canonicalDrive != SdkRoot[0]) + { + Result = canonicalDrive + SdkRoot.Substring(1); + // High importance so the (temporary) workaround leaves clear evidence in CI logs. + Log.LogMessage( + MessageImportance.High, + "Normalized NetCoreSdkRoot drive casing '{0}' -> '{1}' to match Environment.ProcessPath (#14026 workaround).", + SdkRoot[0], + canonicalDrive); + } + } + } + finally + { + CloseHandle(handle); + } + } + catch (Exception ex) + { + // Swallow: a casing mismatch is the only thing we're trying to fix, and + // we must not regress builds where this best-effort probe cannot run. + Log.LogMessage(MessageImportance.Low, "NormalizeSdkRootDriveCasing skipped: {0}", ex.Message); + } + + return true; + } +} +]]> + + + + + + + + +