diff --git a/src/Cli/dotnet/StatInterop.cs b/src/Cli/dotnet/StatInterop.cs deleted file mode 100644 index b902bb81a70a..000000000000 --- a/src/Cli/dotnet/StatInterop.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Microsoft.DotNet.Cli -{ - // https://github.com/dotnet/runtime/blob/main/src/libraries/Common/src/Interop/Unix/System.Native/Interop.Stat.cs - - internal static class StatInterop - { - // Even though csc will by default use a sequential layout, a CS0649 warning as error - // is produced for un-assigned fields when no StructLayout is specified. - // - // Explicitly saying Sequential disables that warning/error for consumers which only - // use Stat in debug builds. - [StructLayout(LayoutKind.Sequential)] - internal struct FileStatus - { - internal FileStatusFlags Flags; - internal int Mode; - internal uint Uid; - internal uint Gid; - internal long Size; - internal long ATime; - internal long ATimeNsec; - internal long MTime; - internal long MTimeNsec; - internal long CTime; - internal long CTimeNsec; - internal long BirthTime; - internal long BirthTimeNsec; - internal long Dev; - internal long RDev; - internal long Ino; - internal uint UserFlags; - } - - [Flags] - internal enum Permissions - { - Mask = S_IRWXU | S_IRWXG | S_IRWXO, - - S_IRWXU = S_IRUSR | S_IWUSR | S_IXUSR, - S_IRUSR = 0x100, - S_IWUSR = 0x80, - S_IXUSR = 0x40, - - S_IRWXG = S_IRGRP | S_IWGRP | S_IXGRP, - S_IRGRP = 0x20, - S_IWGRP = 0x10, - S_IXGRP = 0x8, - - S_IRWXO = S_IROTH | S_IWOTH | S_IXOTH, - S_IROTH = 0x4, - S_IWOTH = 0x2, - S_IXOTH = 0x1, - - S_IXUGO = S_IXUSR | S_IXGRP | S_IXOTH, - } - - [Flags] - internal enum FileStatusFlags - { - None = 0, - HasBirthTime = 1, - } - - [DllImport("libSystem.Native", EntryPoint = "SystemNative_LStat", SetLastError = true)] - internal static extern int LStat(string path, out FileStatus output); - } -} diff --git a/src/Resolvers/Microsoft.DotNet.NativeWrapper/EnvironmentProvider.cs b/src/Resolvers/Microsoft.DotNet.NativeWrapper/EnvironmentProvider.cs index 96c203cc3f4d..360bc71f0b4b 100644 --- a/src/Resolvers/Microsoft.DotNet.NativeWrapper/EnvironmentProvider.cs +++ b/src/Resolvers/Microsoft.DotNet.NativeWrapper/EnvironmentProvider.cs @@ -59,7 +59,7 @@ private IEnumerable SearchPaths } string? dotnetExe; -#if NETCOREAPP +#if NET // The dotnet executable is loading only the .NET version of this code so there is no point checking // the current process path on .NET Framework. We are expected to find dotnet on PATH. dotnetExe = _getCurrentProcessPath(); @@ -70,12 +70,41 @@ private IEnumerable SearchPaths { string? dotnetExeFromPath = GetCommandPath(Constants.DotNet); - if (dotnetExeFromPath != null && !Interop.RunningOnWindows) +#if NET + if (dotnetExeFromPath != null && !OperatingSystem.IsWindows()) { // e.g. on Linux the 'dotnet' command from PATH is a symlink so we need to // resolve it to get the actual path to the binary - dotnetExeFromPath = Interop.Unix.realpath(dotnetExeFromPath) ?? dotnetExeFromPath; + dotnetExeFromPath = GetRealPath(dotnetExeFromPath); + + static string GetRealPath(string path) + { + FileInfo fileInfo = new FileInfo(path); + if (fileInfo.LinkTarget != null) + { + var resolved = fileInfo.ResolveLinkTarget(true); + return resolved?.Exists is true ? resolved.FullName : path; + } + + string invariantPart = string.Empty; + DirectoryInfo? parentDirectory = fileInfo.Directory; + while (parentDirectory is not null) + { + invariantPart = path[parentDirectory.FullName.Length..]; + if (parentDirectory.LinkTarget != null) + { + var resolved = parentDirectory.ResolveLinkTarget(true); + if (resolved?.Exists is true) + return Path.Join(resolved.FullName, invariantPart); + } + + parentDirectory = parentDirectory.Parent; + } + + return path; + } } +#endif if (!string.IsNullOrWhiteSpace(dotnetExeFromPath)) { @@ -86,7 +115,7 @@ private IEnumerable SearchPaths log?.Invoke($"GetDotnetExeDirectory: dotnet command path not found. Using current process"); log?.Invoke($"GetDotnetExeDirectory: Path variable: {_getEnvironmentVariable(Constants.PATH)}"); -#if !NETCOREAPP +#if !NET // If we failed to find dotnet on PATH, we revert to the old behavior of returning the current process // path. This is really an error state but we're keeping the contract of always returning a non-empty // path for backward compatibility. @@ -123,7 +152,7 @@ private IEnumerable SearchPaths private static string? GetCurrentProcessPath() { string? currentProcessPath; -#if NET6_0_OR_GREATER +#if NET currentProcessPath = Environment.ProcessPath; #else currentProcessPath = Process.GetCurrentProcess().MainModule.FileName; diff --git a/src/Resolvers/Microsoft.DotNet.NativeWrapper/Interop.cs b/src/Resolvers/Microsoft.DotNet.NativeWrapper/Interop.cs index 3ce65639989e..7ffb6f3882a6 100644 --- a/src/Resolvers/Microsoft.DotNet.NativeWrapper/Interop.cs +++ b/src/Resolvers/Microsoft.DotNet.NativeWrapper/Interop.cs @@ -28,7 +28,7 @@ static Interop() } // MSBuild SDK resolvers are required to be AnyCPU, but we have a native dependency and .NETFramework does not - // have a built-in facility for dynamically loading user native dlls for the appropriate platform. We therefore + // have a built-in facility for dynamically loading user native dlls for the appropriate platform. We therefore // preload the version with the correct architecture (from a corresponding sub-folder relative to us) on static // construction so that subsequent P/Invokes can find it. private static void PreloadWindowsLibrary(string dllFileName) @@ -179,20 +179,6 @@ internal delegate void hostfxr_get_available_sdks_result_fn( internal static extern int hostfxr_get_available_sdks( string? exe_dir, hostfxr_get_available_sdks_result_fn result); - - [DllImport("libc", CharSet = UTF8, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr realpath(string path, IntPtr buffer); - - [DllImport("libc", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] - private static extern void free(IntPtr ptr); - - public static string? realpath(string path) - { - var ptr = realpath(path, IntPtr.Zero); - var result = PtrToStringUTF8(ptr); - free(ptr); - return result; - } } } }