Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 1dca9c4

Browse files
committed
Address PR feedback
- Added PersistedFiles.GetTempFeatureDirectory and used it from MemoryMappedFiles (can't be used well from Pipes due to assembly layering) - Added directory existence check in Pipes before creating the directory structure - Recreate the pipes path when needed if it's deleted during the execution of the app (maps is already doing this)
1 parent 8abcb39 commit 1dca9c4

File tree

5 files changed

+70
-24
lines changed

5 files changed

+70
-24
lines changed

src/Common/src/System/IO/PersistedFiles.Unix.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,26 @@ namespace System.IO
77
{
88
internal static partial class PersistedFiles
99
{
10+
private static string s_tempProductDirectory;
1011
private static string s_userProductDirectory;
1112

13+
/// <summary>
14+
/// Get the location of where to store temporary files for a particular aspect of the framework,
15+
/// such as "maps".
16+
/// </summary>
17+
/// <param name="featureName">The directory name for the feature</param>
18+
/// <returns>A path within the temp directory for storing temporary files related to the feature.</returns>
19+
internal static string GetTempFeatureDirectory(string featureName)
20+
{
21+
string path = s_tempProductDirectory;
22+
if (path == null)
23+
{
24+
s_tempProductDirectory = path = Path.Combine(Path.GetTempPath(), TopLevelHiddenDirectory, SecondLevelDirectory);
25+
}
26+
27+
return Path.Combine(path, featureName);
28+
}
29+
1230
/// <summary>
1331
/// Get the location of where to persist information for a particular aspect of the framework,
1432
/// such as "cryptography".

src/System.IO.MemoryMappedFiles/src/Resources/Strings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,4 +216,7 @@
216216
<data name="PlatformNotSupported_NamedMaps" xml:space="preserve">
217217
<value>Named maps are not supported.</value>
218218
</data>
219+
<data name="PersistedFiles_NoHomeDirectory" xml:space="preserve">
220+
<value>The home directory of the current user could not be determined.</value>
221+
</data>
219222
</root>

src/System.IO.MemoryMappedFiles/src/System.IO.MemoryMappedFiles.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,9 @@
201201
<Compile Include="$(CommonPath)\System\IO\PersistedFiles.Names.Unix.cs">
202202
<Link>Common\System\IO\PersistedFiles.Names.Unix.cs</Link>
203203
</Compile>
204+
<Compile Include="$(CommonPath)\System\IO\PersistedFiles.Unix.cs">
205+
<Link>Common\System\IO\PersistedFiles.Unix.cs</Link>
206+
</Compile>
204207
</ItemGroup>
205208
<!-- Resource files -->
206209
<ItemGroup>

src/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedFile.Unix.BackingObject_File.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,6 @@ private static FileStream CreateSharedBackingObject(Interop.libc.MemoryMappedPro
3838
// ---- PAL layer ends here ----
3939
// -----------------------------
4040

41-
private static readonly string s_tempMapsDirectory = Path.Combine(
42-
Path.GetTempPath(),
43-
PersistedFiles.TopLevelHiddenDirectory,
44-
PersistedFiles.SecondLevelDirectory,
45-
"maps");
41+
private static readonly string s_tempMapsDirectory = PersistedFiles.GetTempFeatureDirectory("maps");
4642
}
4743
}

src/System.IO.Pipes/src/System/IO/Pipes/PipeStream.Unix.cs

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ internal static string GetPipePath(string serverName, string pipeName)
3737
}
3838

3939
// Return the pipe path
40-
return Path.Combine(GetPipeDirectoryPath(), pipeName);
40+
return Path.Combine(EnsurePipeDirectoryPath(), pipeName);
4141
}
4242

4343
/// <summary>Throws an exception if the supplied handle does not represent a valid pipe.</summary>
@@ -228,31 +228,57 @@ public virtual PipeTransmissionMode ReadMode
228228

229229
private static string s_pipeDirectoryPath;
230230

231-
private static string GetPipeDirectoryPath()
231+
private static string EnsurePipeDirectoryPath()
232232
{
233-
string path = s_pipeDirectoryPath;
234-
if (path == null)
233+
const string PipesFeatureName = "pipes";
234+
235+
// Ideally this would simply use PersistedFiles.GetTempFeatureDirectory(PipesFeatureName) and then
236+
// Directory.CreateDirectory to ensure it exists. But this assembly doesn't reference System.IO.FileSystem.
237+
// As such, we'd be calling GetTempFeatureDirectory, only to then need to parse it in order
238+
// to create each of the individual directories as part of the path. We instead access the named portions
239+
// of the path directly and do the building of the path and directory structure manually.
240+
241+
// First ensure we know what the full path should be, e.g. /tmp/.dotnet/corefx/pipes/
242+
string fullPath = s_pipeDirectoryPath;
243+
string tempPath = null;
244+
if (fullPath == null)
235245
{
236-
// Create the pipes temporary directory, e.g. "/tmp/.dotnet/corefx/pipes".
237-
// We don't have access to Directory.CreateDirectory (which handles creating
238-
// all levels of the directory full path specified), so we create each nested
239-
// level individually (though we assume that the temp path already exists).
240-
241-
path = Path.GetTempPath();
246+
tempPath = Path.GetTempPath();
247+
fullPath = Path.Combine(tempPath, PersistedFiles.TopLevelHiddenDirectory, PersistedFiles.SecondLevelDirectory, PipesFeatureName);
248+
s_pipeDirectoryPath = fullPath;
249+
}
242250

243-
path = Path.Combine(path, PersistedFiles.TopLevelHiddenDirectory);
244-
CreateDirectory(path);
251+
// Then create the directory if it doesn't already exist. If we get any error back from stat,
252+
// just proceed to build up the directory, failing in the CreateDirectory calls if there's some
253+
// problem. Similarly, it's possible stat succeeds but the path is a file rather than directory; we'll
254+
// call that success for now and let this fail later when the code tries to create a file in this "directory"
255+
// (we don't want to overwrite/delete whatever that unknown file may be, and this is similar to other cases
256+
// we can't control where the file system is manipulated concurrently with and separately from this code).
257+
Interop.Sys.FileStatus ignored;
258+
bool pathExists = Interop.Sys.Stat(fullPath, out ignored) == 0;
259+
if (!pathExists)
260+
{
261+
// We need to build up the directory manually. Ensure we have the temp directory in which
262+
// we'll create the structure, e.g. /tmp/
263+
if (tempPath == null)
264+
{
265+
tempPath = Path.GetTempPath();
266+
}
267+
Debug.Assert(Interop.Sys.Stat(tempPath, out ignored) == 0, "Path.GetTempPath() directory could not be accessed");
245268

246-
path = Path.Combine(path, PersistedFiles.SecondLevelDirectory);
247-
CreateDirectory(path);
269+
// Create /tmp/.dotnet/ if it doesn't exist.
270+
string partialPath = Path.Combine(tempPath, PersistedFiles.TopLevelHiddenDirectory);
271+
CreateDirectory(partialPath);
248272

249-
const string PipesFeatureName = "pipes";
250-
path = Path.Combine(path, PipesFeatureName);
251-
CreateDirectory(path);
273+
// Create /tmp/.dotnet/corefx/ if it doesn't exist
274+
partialPath = Path.Combine(partialPath, PersistedFiles.SecondLevelDirectory);
275+
CreateDirectory(partialPath);
252276

253-
s_pipeDirectoryPath = path;
277+
// Create /tmp/.dotnet/corefx/pipes/ if it doesn't exist
278+
CreateDirectory(fullPath);
254279
}
255-
return path;
280+
281+
return fullPath;
256282
}
257283

258284
private static void CreateDirectory(string directoryPath)

0 commit comments

Comments
 (0)