diff --git a/src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPath.cs b/src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPath.cs index 89681a69c5ed89..ccb15a00227595 100644 --- a/src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPath.cs +++ b/src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPath.cs @@ -19,6 +19,7 @@ internal enum NSSearchPathDirectory NSDocumentDirectory = 9, NSDesktopDirectory = 12, NSCachesDirectory = 13, + NSApplicationSupportDirectory = 14, NSMoviesDirectory = 17, NSMusicDirectory = 18, NSPicturesDirectory = 19 diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index b12227e70d57b2..a3e339de38b52b 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -2292,7 +2292,7 @@ - + Common\Interop\OSX\Interop.SearchPath.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.GetFolderPathCore.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.GetFolderPathCore.Unix.cs index 7990febb5a11bb..1ec8fd1af28cb1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.GetFolderPathCore.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.GetFolderPathCore.Unix.cs @@ -9,6 +9,9 @@ using System.Runtime.InteropServices; using System.Text; using System.Threading; +#if TARGET_OSX +using NSSearchPathDirectory = Interop.Sys.NSSearchPathDirectory; +#endif namespace System { @@ -17,7 +20,7 @@ public static partial class Environment private static string GetFolderPathCore(SpecialFolder folder, SpecialFolderOption option) { // Get the path for the SpecialFolder - string path = GetFolderPathCoreWithoutValidation(folder); + string path = GetFolderPathCoreWithoutValidation(folder) ?? string.Empty; Debug.Assert(path != null); // If we didn't get one, or if we got one but we're not supposed to verify it, @@ -43,7 +46,7 @@ private static string GetFolderPathCore(SpecialFolder folder, SpecialFolderOptio return path; } - private static string GetFolderPathCoreWithoutValidation(SpecialFolder folder) + private static string? GetFolderPathCoreWithoutValidation(SpecialFolder folder) { // First handle any paths that involve only static paths, avoiding the overheads of getting user-local paths. // https://www.freedesktop.org/software/systemd/man/file-hierarchy.html @@ -85,42 +88,54 @@ private static string GetFolderPathCoreWithoutValidation(SpecialFolder folder) switch (folder) { case SpecialFolder.UserProfile: - case SpecialFolder.MyDocuments: // same value as Personal return home; - case SpecialFolder.ApplicationData: - return GetXdgConfig(home); - case SpecialFolder.LocalApplicationData: - // "$XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored." - // "If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used." - string? data = GetEnvironmentVariable("XDG_DATA_HOME"); - if (data is null || !data.StartsWith('/')) - { - data = Path.Combine(home, ".local", "share"); - } - return data; - case SpecialFolder.Desktop: - case SpecialFolder.DesktopDirectory: - return ReadXdgDirectory(home, "XDG_DESKTOP_DIR", "Desktop"); case SpecialFolder.Templates: return ReadXdgDirectory(home, "XDG_TEMPLATES_DIR", "Templates"); - case SpecialFolder.MyVideos: - return ReadXdgDirectory(home, "XDG_VIDEOS_DIR", "Videos"); - + // TODO: Consider merging the OSX path with the rest of the Apple systems here: + // https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Environment.iOS.cs #if TARGET_OSX + case SpecialFolder.Desktop: + case SpecialFolder.DesktopDirectory: + return Interop.Sys.SearchPath(NSSearchPathDirectory.NSDesktopDirectory); + case SpecialFolder.ApplicationData: + case SpecialFolder.LocalApplicationData: + return Interop.Sys.SearchPath(NSSearchPathDirectory.NSApplicationSupportDirectory); + case SpecialFolder.MyDocuments: // same value as Personal + return Interop.Sys.SearchPath(NSSearchPathDirectory.NSDocumentDirectory); case SpecialFolder.MyMusic: - return Path.Combine(home, "Music"); + return Interop.Sys.SearchPath(NSSearchPathDirectory.NSMusicDirectory); + case SpecialFolder.MyVideos: + return Interop.Sys.SearchPath(NSSearchPathDirectory.NSMoviesDirectory); case SpecialFolder.MyPictures: - return Path.Combine(home, "Pictures"); + return Interop.Sys.SearchPath(NSSearchPathDirectory.NSPicturesDirectory); case SpecialFolder.Fonts: return Path.Combine(home, "Library", "Fonts"); case SpecialFolder.Favorites: return Path.Combine(home, "Library", "Favorites"); case SpecialFolder.InternetCache: - return Path.Combine(home, "Library", "Caches"); + return Interop.Sys.SearchPath(NSSearchPathDirectory.NSCachesDirectory); #else + case SpecialFolder.Desktop: + case SpecialFolder.DesktopDirectory: + return ReadXdgDirectory(home, "XDG_DESKTOP_DIR", "Desktop"); + case SpecialFolder.ApplicationData: + return GetXdgConfig(home); + case SpecialFolder.LocalApplicationData: + // "$XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored." + // "If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used." + string? data = GetEnvironmentVariable("XDG_DATA_HOME"); + if (data is null || !data.StartsWith('/')) + { + data = Path.Combine(home, ".local", "share"); + } + return data; + case SpecialFolder.MyDocuments: // same value as Personal + return ReadXdgDirectory(home, "XDG_DOCUMENTS_DIR", "Documents"); case SpecialFolder.MyMusic: return ReadXdgDirectory(home, "XDG_MUSIC_DIR", "Music"); + case SpecialFolder.MyVideos: + return ReadXdgDirectory(home, "XDG_VIDEOS_DIR", "Videos"); case SpecialFolder.MyPictures: return ReadXdgDirectory(home, "XDG_PICTURES_DIR", "Pictures"); case SpecialFolder.Fonts: diff --git a/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs b/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs index 416c58590016dd..3c82cfe0032833 100644 --- a/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs +++ b/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs @@ -332,19 +332,21 @@ public void FailFast_ExceptionStackTrace_InnerException() [Fact] [PlatformSpecific(TestPlatforms.AnyUnix | TestPlatforms.Browser)] - public void GetFolderPath_Unix_PersonalExists() + public void GetFolderPath_Unix_UserProfileExists() { - Assert.True(Directory.Exists(Environment.GetFolderPath(Environment.SpecialFolder.Personal))); + Assert.True(Directory.Exists(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile))); } [Fact] [PlatformSpecific(TestPlatforms.AnyUnix | TestPlatforms.Browser)] // Tests OS-specific environment - public void GetFolderPath_Unix_PersonalIsHomeAndUserProfile() + public void GetFolderPath_Unix_PersonalIsDocumentsAndUserProfile() { if (!PlatformDetection.IsiOS && !PlatformDetection.IstvOS && !PlatformDetection.IsMacCatalyst) { - Assert.Equal(Environment.GetEnvironmentVariable("HOME"), Environment.GetFolderPath(Environment.SpecialFolder.Personal)); - Assert.Equal(Environment.GetEnvironmentVariable("HOME"), Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)); + Assert.Equal(Path.Combine(Environment.GetEnvironmentVariable("HOME"), "Documents"), + Environment.GetFolderPath(Environment.SpecialFolder.Personal, Environment.SpecialFolderOption.DoNotVerify)); + Assert.Equal(Path.Combine(Environment.GetEnvironmentVariable("HOME"), "Documents"), + Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments, Environment.SpecialFolderOption.DoNotVerify)); } Assert.Equal(Environment.GetEnvironmentVariable("HOME"), Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)); @@ -357,6 +359,7 @@ public void GetFolderPath_Unix_PersonalIsHomeAndUserProfile() [InlineData(Environment.SpecialFolder.Desktop)] [InlineData(Environment.SpecialFolder.DesktopDirectory)] [InlineData(Environment.SpecialFolder.Fonts)] + [InlineData(Environment.SpecialFolder.MyDocuments)] [InlineData(Environment.SpecialFolder.MyMusic)] [InlineData(Environment.SpecialFolder.MyPictures)] [InlineData(Environment.SpecialFolder.MyVideos)] @@ -391,7 +394,7 @@ public void GetSystemDirectory() [Theory] [PlatformSpecific(TestPlatforms.AnyUnix)] // Tests OS-specific environment [InlineData(Environment.SpecialFolder.UserProfile, Environment.SpecialFolderOption.None)] - [InlineData(Environment.SpecialFolder.MyDocuments, Environment.SpecialFolderOption.None)] // MyDocuments == Personal + [InlineData(Environment.SpecialFolder.MyDocuments, Environment.SpecialFolderOption.DoNotVerify)] // MyDocuments == Personal [InlineData(Environment.SpecialFolder.CommonApplicationData, Environment.SpecialFolderOption.None)] [InlineData(Environment.SpecialFolder.CommonTemplates, Environment.SpecialFolderOption.DoNotVerify)] [InlineData(Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.DoNotVerify)] diff --git a/src/native/libs/System.Native/CMakeLists.txt b/src/native/libs/System.Native/CMakeLists.txt index b4d97039824319..a6358bafed498c 100644 --- a/src/native/libs/System.Native/CMakeLists.txt +++ b/src/native/libs/System.Native/CMakeLists.txt @@ -59,6 +59,11 @@ if (CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVO set(NATIVE_SOURCES ${NATIVE_SOURCES} pal_log.m pal_searchpath.m) +elseif (CLR_CMAKE_TARGET_OSX) + list (APPEND NATIVE_SOURCES + pal_searchpath.m + pal_console.c + pal_log.c) else () list (APPEND NATIVE_SOURCES pal_searchpath.c