Skip to content

Commit 62db361

Browse files
authored
Fix some incorrect SpecialFolder entries for Unix (#68610)
* Fix incorrect SpecialFolder entries for Unix This fixes an incorrect Documents/Personal for Linux+Mac entry, incorrect Videos Mac entry, and an incorrect (Local) ApplicationData Mac entry. Fix #63214 * Don't make Unix tests assume Personal is Home * Use the same value for Mac's (Local)ApplicationData * Use NSPaths for OSX Special Folder The Apple documentation recommends to use these instead of hardcoding the paths, so the paths that had NSPath equivalents have been replaced. * Change System.Native CMakeLists to include OSX for SearchPath `a17e73466ca639388a3d89f4d6be0ab9703802fc` made OSX call the native NSearchPath functions, however a stub was initially called. This fixes it to call the native functions.
1 parent fec8aeb commit 62db361

5 files changed

Lines changed: 54 additions & 30 deletions

File tree

src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPath.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ internal enum NSSearchPathDirectory
1919
NSDocumentDirectory = 9,
2020
NSDesktopDirectory = 12,
2121
NSCachesDirectory = 13,
22+
NSApplicationSupportDirectory = 14,
2223
NSMoviesDirectory = 17,
2324
NSMusicDirectory = 18,
2425
NSPicturesDirectory = 19

src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2294,7 +2294,7 @@
22942294
</Compile>
22952295
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStatus.SetTimes.OSX.cs" />
22962296
</ItemGroup>
2297-
<ItemGroup Condition="'$(IsiOSLike)' == 'true'">
2297+
<ItemGroup Condition="'$(IsiOSLike)' == 'true' or '$(IsOSXLike)' == 'true'">
22982298
<Compile Include="$(CommonPath)Interop\OSX\System.Native\Interop.SearchPath.cs">
22992299
<Link>Common\Interop\OSX\Interop.SearchPath.cs</Link>
23002300
</Compile>

src/libraries/System.Private.CoreLib/src/System/Environment.GetFolderPathCore.Unix.cs

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
using System.Runtime.InteropServices;
1010
using System.Text;
1111
using System.Threading;
12+
#if TARGET_OSX
13+
using NSSearchPathDirectory = Interop.Sys.NSSearchPathDirectory;
14+
#endif
1215

1316
namespace System
1417
{
@@ -17,7 +20,7 @@ public static partial class Environment
1720
private static string GetFolderPathCore(SpecialFolder folder, SpecialFolderOption option)
1821
{
1922
// Get the path for the SpecialFolder
20-
string path = GetFolderPathCoreWithoutValidation(folder);
23+
string path = GetFolderPathCoreWithoutValidation(folder) ?? string.Empty;
2124
Debug.Assert(path != null);
2225

2326
// 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
4346
return path;
4447
}
4548

46-
private static string GetFolderPathCoreWithoutValidation(SpecialFolder folder)
49+
private static string? GetFolderPathCoreWithoutValidation(SpecialFolder folder)
4750
{
4851
// First handle any paths that involve only static paths, avoiding the overheads of getting user-local paths.
4952
// https://www.freedesktop.org/software/systemd/man/file-hierarchy.html
@@ -85,42 +88,54 @@ private static string GetFolderPathCoreWithoutValidation(SpecialFolder folder)
8588
switch (folder)
8689
{
8790
case SpecialFolder.UserProfile:
88-
case SpecialFolder.MyDocuments: // same value as Personal
8991
return home;
90-
case SpecialFolder.ApplicationData:
91-
return GetXdgConfig(home);
92-
case SpecialFolder.LocalApplicationData:
93-
// "$XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored."
94-
// "If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used."
95-
string? data = GetEnvironmentVariable("XDG_DATA_HOME");
96-
if (data is null || !data.StartsWith('/'))
97-
{
98-
data = Path.Combine(home, ".local", "share");
99-
}
100-
return data;
10192

102-
case SpecialFolder.Desktop:
103-
case SpecialFolder.DesktopDirectory:
104-
return ReadXdgDirectory(home, "XDG_DESKTOP_DIR", "Desktop");
10593
case SpecialFolder.Templates:
10694
return ReadXdgDirectory(home, "XDG_TEMPLATES_DIR", "Templates");
107-
case SpecialFolder.MyVideos:
108-
return ReadXdgDirectory(home, "XDG_VIDEOS_DIR", "Videos");
109-
95+
// TODO: Consider merging the OSX path with the rest of the Apple systems here:
96+
// https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Environment.iOS.cs
11097
#if TARGET_OSX
98+
case SpecialFolder.Desktop:
99+
case SpecialFolder.DesktopDirectory:
100+
return Interop.Sys.SearchPath(NSSearchPathDirectory.NSDesktopDirectory);
101+
case SpecialFolder.ApplicationData:
102+
case SpecialFolder.LocalApplicationData:
103+
return Interop.Sys.SearchPath(NSSearchPathDirectory.NSApplicationSupportDirectory);
104+
case SpecialFolder.MyDocuments: // same value as Personal
105+
return Interop.Sys.SearchPath(NSSearchPathDirectory.NSDocumentDirectory);
111106
case SpecialFolder.MyMusic:
112-
return Path.Combine(home, "Music");
107+
return Interop.Sys.SearchPath(NSSearchPathDirectory.NSMusicDirectory);
108+
case SpecialFolder.MyVideos:
109+
return Interop.Sys.SearchPath(NSSearchPathDirectory.NSMoviesDirectory);
113110
case SpecialFolder.MyPictures:
114-
return Path.Combine(home, "Pictures");
111+
return Interop.Sys.SearchPath(NSSearchPathDirectory.NSPicturesDirectory);
115112
case SpecialFolder.Fonts:
116113
return Path.Combine(home, "Library", "Fonts");
117114
case SpecialFolder.Favorites:
118115
return Path.Combine(home, "Library", "Favorites");
119116
case SpecialFolder.InternetCache:
120-
return Path.Combine(home, "Library", "Caches");
117+
return Interop.Sys.SearchPath(NSSearchPathDirectory.NSCachesDirectory);
121118
#else
119+
case SpecialFolder.Desktop:
120+
case SpecialFolder.DesktopDirectory:
121+
return ReadXdgDirectory(home, "XDG_DESKTOP_DIR", "Desktop");
122+
case SpecialFolder.ApplicationData:
123+
return GetXdgConfig(home);
124+
case SpecialFolder.LocalApplicationData:
125+
// "$XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored."
126+
// "If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used."
127+
string? data = GetEnvironmentVariable("XDG_DATA_HOME");
128+
if (data is null || !data.StartsWith('/'))
129+
{
130+
data = Path.Combine(home, ".local", "share");
131+
}
132+
return data;
133+
case SpecialFolder.MyDocuments: // same value as Personal
134+
return ReadXdgDirectory(home, "XDG_DOCUMENTS_DIR", "Documents");
122135
case SpecialFolder.MyMusic:
123136
return ReadXdgDirectory(home, "XDG_MUSIC_DIR", "Music");
137+
case SpecialFolder.MyVideos:
138+
return ReadXdgDirectory(home, "XDG_VIDEOS_DIR", "Videos");
124139
case SpecialFolder.MyPictures:
125140
return ReadXdgDirectory(home, "XDG_PICTURES_DIR", "Pictures");
126141
case SpecialFolder.Fonts:

src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -332,19 +332,21 @@ public void FailFast_ExceptionStackTrace_InnerException()
332332

333333
[Fact]
334334
[PlatformSpecific(TestPlatforms.AnyUnix | TestPlatforms.Browser)]
335-
public void GetFolderPath_Unix_PersonalExists()
335+
public void GetFolderPath_Unix_UserProfileExists()
336336
{
337-
Assert.True(Directory.Exists(Environment.GetFolderPath(Environment.SpecialFolder.Personal)));
337+
Assert.True(Directory.Exists(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)));
338338
}
339339

340340
[Fact]
341341
[PlatformSpecific(TestPlatforms.AnyUnix | TestPlatforms.Browser)] // Tests OS-specific environment
342-
public void GetFolderPath_Unix_PersonalIsHomeAndUserProfile()
342+
public void GetFolderPath_Unix_PersonalIsDocumentsAndUserProfile()
343343
{
344344
if (!PlatformDetection.IsiOS && !PlatformDetection.IstvOS && !PlatformDetection.IsMacCatalyst)
345345
{
346-
Assert.Equal(Environment.GetEnvironmentVariable("HOME"), Environment.GetFolderPath(Environment.SpecialFolder.Personal));
347-
Assert.Equal(Environment.GetEnvironmentVariable("HOME"), Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));
346+
Assert.Equal(Path.Combine(Environment.GetEnvironmentVariable("HOME"), "Documents"),
347+
Environment.GetFolderPath(Environment.SpecialFolder.Personal, Environment.SpecialFolderOption.DoNotVerify));
348+
Assert.Equal(Path.Combine(Environment.GetEnvironmentVariable("HOME"), "Documents"),
349+
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments, Environment.SpecialFolderOption.DoNotVerify));
348350
}
349351

350352
Assert.Equal(Environment.GetEnvironmentVariable("HOME"), Environment.GetFolderPath(Environment.SpecialFolder.UserProfile));
@@ -357,6 +359,7 @@ public void GetFolderPath_Unix_PersonalIsHomeAndUserProfile()
357359
[InlineData(Environment.SpecialFolder.Desktop)]
358360
[InlineData(Environment.SpecialFolder.DesktopDirectory)]
359361
[InlineData(Environment.SpecialFolder.Fonts)]
362+
[InlineData(Environment.SpecialFolder.MyDocuments)]
360363
[InlineData(Environment.SpecialFolder.MyMusic)]
361364
[InlineData(Environment.SpecialFolder.MyPictures)]
362365
[InlineData(Environment.SpecialFolder.MyVideos)]
@@ -391,7 +394,7 @@ public void GetSystemDirectory()
391394
[Theory]
392395
[PlatformSpecific(TestPlatforms.AnyUnix)] // Tests OS-specific environment
393396
[InlineData(Environment.SpecialFolder.UserProfile, Environment.SpecialFolderOption.None)]
394-
[InlineData(Environment.SpecialFolder.MyDocuments, Environment.SpecialFolderOption.None)] // MyDocuments == Personal
397+
[InlineData(Environment.SpecialFolder.MyDocuments, Environment.SpecialFolderOption.DoNotVerify)] // MyDocuments == Personal
395398
[InlineData(Environment.SpecialFolder.CommonApplicationData, Environment.SpecialFolderOption.None)]
396399
[InlineData(Environment.SpecialFolder.CommonTemplates, Environment.SpecialFolderOption.DoNotVerify)]
397400
[InlineData(Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.DoNotVerify)]

src/native/libs/System.Native/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ if (CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVO
5959
set(NATIVE_SOURCES ${NATIVE_SOURCES}
6060
pal_log.m
6161
pal_searchpath.m)
62+
elseif (CLR_CMAKE_TARGET_OSX)
63+
list (APPEND NATIVE_SOURCES
64+
pal_searchpath.m
65+
pal_console.c
66+
pal_log.c)
6267
else ()
6368
list (APPEND NATIVE_SOURCES
6469
pal_searchpath.c

0 commit comments

Comments
 (0)