diff --git a/src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPath.iOS.cs b/src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPath.iOS.cs
new file mode 100644
index 0000000000000..8d73184ca4d50
--- /dev/null
+++ b/src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPath.iOS.cs
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ internal static partial class Sys
+ {
+ [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_SearchPath_TempDirectory")]
+ internal static extern string SearchPathTempDirectory();
+ }
+}
diff --git a/src/libraries/Native/Unix/System.Native/entrypoints.c b/src/libraries/Native/Unix/System.Native/entrypoints.c
index c8b678ec08340..b3ae64f96f91e 100644
--- a/src/libraries/Native/Unix/System.Native/entrypoints.c
+++ b/src/libraries/Native/Unix/System.Native/entrypoints.c
@@ -218,6 +218,7 @@ static const Entry s_sysNative[] =
DllImportEntry(SystemNative_GetOSArchitecture)
DllImportEntry(SystemNative_GetProcessArchitecture)
DllImportEntry(SystemNative_SearchPath)
+ DllImportEntry(SystemNative_SearchPath_TempDirectory)
DllImportEntry(SystemNative_RegisterForSigChld)
DllImportEntry(SystemNative_SetDelayedSigChildConsoleConfigurationHandler)
DllImportEntry(SystemNative_SetTerminalInvalidationHandler)
diff --git a/src/libraries/Native/Unix/System.Native/pal_searchpath.c b/src/libraries/Native/Unix/System.Native/pal_searchpath.c
index fbf3d903df01c..de8037dc1a295 100644
--- a/src/libraries/Native/Unix/System.Native/pal_searchpath.c
+++ b/src/libraries/Native/Unix/System.Native/pal_searchpath.c
@@ -10,3 +10,9 @@ const char* SystemNative_SearchPath(int32_t folderId)
__builtin_unreachable();
return NULL;
}
+
+const char* SystemNative_SearchPath_TempDirectory()
+{
+ __builtin_unreachable();
+ return NULL;
+}
diff --git a/src/libraries/Native/Unix/System.Native/pal_searchpath.h b/src/libraries/Native/Unix/System.Native/pal_searchpath.h
index e2de05d8c8860..cdb872914624c 100644
--- a/src/libraries/Native/Unix/System.Native/pal_searchpath.h
+++ b/src/libraries/Native/Unix/System.Native/pal_searchpath.h
@@ -7,3 +7,5 @@
#include "pal_types.h"
PALEXPORT const char* SystemNative_SearchPath(int32_t folderId);
+
+PALEXPORT const char* SystemNative_SearchPath_TempDirectory(void);
diff --git a/src/libraries/Native/Unix/System.Native/pal_searchpath.m b/src/libraries/Native/Unix/System.Native/pal_searchpath.m
index 2e96041f3dda8..231c508c527ca 100644
--- a/src/libraries/Native/Unix/System.Native/pal_searchpath.m
+++ b/src/libraries/Native/Unix/System.Native/pal_searchpath.m
@@ -11,3 +11,10 @@
const char* path = [[url path] UTF8String];
return path == NULL ? NULL : strdup (path);
}
+
+const char* SystemNative_SearchPath_TempDirectory()
+{
+ NSString* tempPath = NSTemporaryDirectory();
+ const char *path = [tempPath UTF8String];
+ return path == NULL ? NULL : strdup (path);
+}
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 5a1593f032c69..e72c543d58080 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
@@ -2112,6 +2112,8 @@
+
+
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.NoniOS.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.NoniOS.cs
new file mode 100644
index 0000000000000..b2a9a4b06a083
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.NoniOS.cs
@@ -0,0 +1,10 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.IO
+{
+ public static partial class Path
+ {
+ private static string DefaultTempPath => "/tmp/";
+ }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.cs
index 61786ad757a43..f3ec19941c21b 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.cs
@@ -80,7 +80,6 @@ private static string RemoveLongPathPrefix(string path)
public static string GetTempPath()
{
const string TempEnvVar = "TMPDIR";
- const string DefaultTempPath = "/tmp/";
// Get the temp path from the TMPDIR environment variable.
// If it's not set, just return the default path.
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.iOS.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.iOS.cs
new file mode 100644
index 0000000000000..c1c4a7047eec5
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.iOS.cs
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+
+namespace System.IO
+{
+ public static partial class Path
+ {
+ private static string? s_defaultTempPath;
+
+ private static string DefaultTempPath =>
+ s_defaultTempPath ?? (s_defaultTempPath = Interop.Sys.SearchPathTempDirectory()) ??
+ throw new InvalidOperationException();
+ }
+}
diff --git a/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs b/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs
index f019b1eb11a02..f2b35eb6c2cdf 100644
--- a/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs
+++ b/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs
@@ -330,6 +330,13 @@ public void FailFast_ExceptionStackTrace_InnerException()
}
}
+ [Fact]
+ [PlatformSpecific(TestPlatforms.AnyUnix | TestPlatforms.Browser)]
+ public void GetFolderPath_Unix_PersonalExists()
+ {
+ Assert.True(Directory.Exists(Environment.GetFolderPath(Environment.SpecialFolder.Personal)));
+ }
+
[Fact]
[PlatformSpecific(TestPlatforms.AnyUnix | TestPlatforms.Browser)] // Tests OS-specific environment
public void GetFolderPath_Unix_PersonalIsHomeAndUserProfile()
@@ -339,7 +346,11 @@ public void GetFolderPath_Unix_PersonalIsHomeAndUserProfile()
Assert.Equal(Environment.GetEnvironmentVariable("HOME"), Environment.GetFolderPath(Environment.SpecialFolder.Personal));
Assert.Equal(Environment.GetEnvironmentVariable("HOME"), Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));
}
- Assert.Equal(Environment.GetEnvironmentVariable("HOME"), Environment.GetFolderPath(Environment.SpecialFolder.UserProfile));
+ // tvOS effectively doesn't have a HOME
+ if (!PlatformDetection.IstvOS)
+ {
+ Assert.Equal(Environment.GetEnvironmentVariable("HOME"), Environment.GetFolderPath(Environment.SpecialFolder.UserProfile));
+ }
}
[Theory]
diff --git a/src/libraries/sendtohelixhelp.proj b/src/libraries/sendtohelixhelp.proj
index 14cf90630710d..14ea741c8c595 100644
--- a/src/libraries/sendtohelixhelp.proj
+++ b/src/libraries/sendtohelixhelp.proj
@@ -294,7 +294,7 @@
$(AppleTestTarget)
-
+
false
diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
index 1878cb4ed7c05..7aa4413aad70d 100644
--- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -271,6 +271,9 @@
Common\Interop\OSX\Interop.SearchPath.cs
+
+ Common\Interop\OSX\Interop.SearchPath.iOS.cs
+
diff --git a/src/mono/System.Private.CoreLib/src/System/Environment.iOS.cs b/src/mono/System.Private.CoreLib/src/System/Environment.iOS.cs
index 1a95bdc408f1c..01ceb05bba7dc 100644
--- a/src/mono/System.Private.CoreLib/src/System/Environment.iOS.cs
+++ b/src/mono/System.Private.CoreLib/src/System/Environment.iOS.cs
@@ -36,18 +36,14 @@ private static string GetFolderPathCore(SpecialFolder folder, SpecialFolderOptio
{
switch (folder)
{
- // TODO: fix for tvOS (https://github.com/dotnet/runtime/issues/34007)
- // The "normal" NSDocumentDirectory is a read-only directory on tvOS
- // and that breaks a lot of assumptions in the runtime and the BCL
-
case SpecialFolder.Personal:
case SpecialFolder.LocalApplicationData:
- return Interop.Sys.SearchPath(NSSearchPathDirectory.NSDocumentDirectory);
+ return CombineDocumentDirectory(string.Empty);
case SpecialFolder.ApplicationData:
// note: at first glance that looked like a good place to return NSLibraryDirectory
// but it would break isolated storage for existing applications
- return CombineSearchPath(NSSearchPathDirectory.NSDocumentDirectory, ".config");
+ return CombineDocumentDirectory(".config");
case SpecialFolder.Resources:
return Interop.Sys.SearchPath(NSSearchPathDirectory.NSLibraryDirectory); // older (8.2 and previous) would return String.Empty
@@ -63,7 +59,7 @@ private static string GetFolderPathCore(SpecialFolder folder, SpecialFolderOptio
return Path.Combine(GetFolderPathCore(SpecialFolder.Personal, SpecialFolderOption.None), "Pictures");
case SpecialFolder.Templates:
- return CombineSearchPath(NSSearchPathDirectory.NSDocumentDirectory, "Templates");
+ return CombineDocumentDirectory("Templates");
case SpecialFolder.MyVideos:
return Path.Combine(GetFolderPathCore(SpecialFolder.Personal, SpecialFolderOption.None), "Videos");
@@ -72,7 +68,7 @@ private static string GetFolderPathCore(SpecialFolder folder, SpecialFolderOptio
return "/usr/share/templates";
case SpecialFolder.Fonts:
- return CombineSearchPath(NSSearchPathDirectory.NSDocumentDirectory, ".fonts");
+ return CombineDocumentDirectory(".fonts");
case SpecialFolder.Favorites:
return CombineSearchPath(NSSearchPathDirectory.NSLibraryDirectory, "Favorites");
@@ -100,6 +96,23 @@ static string CombineSearchPath(NSSearchPathDirectory searchPath, string subdire
Path.Combine(path, subdirectory) :
string.Empty;
}
+
+ static string CombineDocumentDirectory(string subdirectory)
+ {
+#if TARGET_TVOS
+ string? path = CombineSearchPath(NSSearchPathDirectory.NSLibraryDirectory, Path.Combine("Caches", "Documents", subdirectory));
+ // Special version of CombineSearchPath which creates the path if needed.
+ // This isn't needed for "real" search paths which always exist, but on tvOS
+ // the base path is really a subdirectory we define rather than an OS directory.
+ // In order to not treat Directory.Exists(SpecialFolder.ApplicationData) differently
+ // on tvOS, guarantee that it exists by creating it here
+ if (!Directory.Exists (path))
+ Directory.CreateDirectory (path);
+#else
+ string? path = CombineSearchPath(NSSearchPathDirectory.NSDocumentDirectory, subdirectory);
+#endif
+ return path;
+ }
}
}
}