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

Commit 9f89acb

Browse files
committed
Merge pull request #2248 from stephentoub/path_unix
Implement System.IO.Path on Unix
2 parents 1b1ab18 + 7938a0e commit 9f89acb

File tree

36 files changed

+858
-482
lines changed

36 files changed

+858
-482
lines changed

src/Common/src/Interop/Unix/libc/Interop.getcwd.cs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,66 @@ internal static partial class Interop
1010
{
1111
internal static partial class libc
1212
{
13+
internal static unsafe string getcwd()
14+
{
15+
const int StackLimit = 256;
16+
17+
// First try to get the path into a buffer on the stack
18+
byte* stackBuf = stackalloc byte[StackLimit];
19+
string result = getcwd(stackBuf, StackLimit);
20+
if (result != null)
21+
{
22+
return result;
23+
}
24+
25+
// If that was too small, try increasing large buffer sizes
26+
// until we get one that works or until we hit MaxPath.
27+
int maxPath = Interop.libc.MaxPath;
28+
if (StackLimit < maxPath)
29+
{
30+
int bufferSize = StackLimit;
31+
do
32+
{
33+
checked { bufferSize *= 2; }
34+
var buf = new byte[Math.Min(bufferSize, maxPath)];
35+
fixed (byte* ptr = buf)
36+
{
37+
result = getcwd(ptr, buf.Length);
38+
if (result != null)
39+
{
40+
return result;
41+
}
42+
}
43+
}
44+
while (bufferSize < maxPath);
45+
}
46+
47+
// If we couldn't get the cwd with a MaxPath-sized buffer, something's wrong.
48+
throw Interop.GetExceptionForIoErrno(Interop.Errors.ENAMETOOLONG);
49+
}
50+
51+
private static unsafe string getcwd(byte* ptr, int bufferSize)
52+
{
53+
// Call the real getcwd
54+
byte* result = getcwd(ptr, (size_t)bufferSize);
55+
56+
// If it returned non-null, the null-terminated path is in the buffer
57+
if (result != null)
58+
{
59+
return Marshal.PtrToStringAnsi((IntPtr)ptr);
60+
}
61+
62+
// Otherwise, if it failed due to the buffer being too small, return null;
63+
// for anything else, throw.
64+
int errno = Marshal.GetLastWin32Error();
65+
if (errno == Interop.Errors.ERANGE)
66+
{
67+
return null;
68+
}
69+
throw Interop.GetExceptionForIoErrno(errno);
70+
}
71+
1372
[DllImport(Libraries.Libc, SetLastError = true)]
14-
internal static extern unsafe byte* getcwd(byte* buf, size_t bufSize);
73+
private static extern unsafe byte* getcwd(byte* buf, size_t bufSize);
1574
}
1675
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System.Runtime.InteropServices;
5+
6+
internal static partial class Interop
7+
{
8+
internal static partial class libc
9+
{
10+
[DllImport(Libraries.Libc, SetLastError = true)]
11+
internal static extern int mkstemps(byte[] template, int suffixlen);
12+
}
13+
}

src/Common/src/Interop/Unix/libc/Interop.pathconf.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,21 @@ internal static partial class Interop
88
{
99
internal static partial class libc
1010
{
11+
/// <summary>The maximum path length for the system. -1 if it hasn't yet been initialized.</summary>
12+
private static int s_maxPath = -1;
13+
/// <summary>The maximum name length for the system. -1 if it hasn't yet been initialized.</summary>
14+
private static int s_maxName = -1;
15+
16+
internal static int MaxPath
17+
{
18+
get { return Interop.libc.GetPathConfValue(ref s_maxPath, Interop.libc.PathConfNames._PC_PATH_MAX, Interop.libc.DEFAULT_PC_PATH_MAX); }
19+
}
20+
21+
internal static int MaxName
22+
{
23+
get { return Interop.libc.GetPathConfValue(ref s_maxName, Interop.libc.PathConfNames._PC_NAME_MAX, Interop.libc.DEFAULT_PC_NAME_MAX); }
24+
}
25+
1126
/// <summary>
1227
/// Gets a pathconf value by name. If the cached value is less than zero (meaning not yet initialized),
1328
/// pathconf is used to retrieve the value, which is then stored into the field.
@@ -16,13 +31,14 @@ internal static partial class libc
1631
/// <param name="cachedValue">The field used to cache the pathconf value.</param>
1732
/// <param name="pathConfName">The name of the pathconf value.</param>
1833
/// <param name="defaultValue">The default value to use in case pathconf fails.</param>
19-
internal static void GetPathConfValue(ref int cachedValue, int pathConfName, int defaultValue)
34+
private static int GetPathConfValue(ref int cachedValue, int pathConfName, int defaultValue)
2035
{
2136
if (cachedValue < 0) // benign race condition on cached value
2237
{
2338
int result = Interop.libc.pathconf("/", pathConfName);
2439
cachedValue = result >= 0 ? result : defaultValue;
2540
}
41+
return cachedValue;
2642
}
2743

2844
[DllImport(Libraries.Libc, SetLastError = true)]

src/Common/src/Interop/Unix/libcrypto/Interop.Initialization.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Microsoft. All rights reserved.
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

4+
using System;
45
using System.Runtime.InteropServices;
56
using System.Security.Cryptography;
67

@@ -15,7 +16,13 @@ static libcrypto()
1516
{
1617
if (Interop.libcoreclr.EnsureOpenSslInitialized() != 0)
1718
{
18-
throw new CryptographicException();
19+
// Ideally this would be a CryptographicException, but we use
20+
// OpenSSL in libraries lower than System.Security.Cryptography.
21+
// It's not a big deal, though: this will already be wrapped in a
22+
// TypeLoadException, and this failing means something is very
23+
// wrong with the system's configuration and any code using
24+
// these libraries will be unable to operate correctly.
25+
throw new InvalidOperationException();
1926
}
2027

2128
// Load the SHA-2 hash algorithms, and anything else not in the default

src/Common/tests/System/Diagnostics/AssertWithCallerAttributes.cs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -578,17 +578,20 @@ public static async Task<T> ThrowsAsync<T>(string paramName, Func<Task> testCode
578578
catch (Exception e) { throw WrapException(e, path, line); }
579579
}
580580

581-
public static void True(bool condition,
581+
public static void True(bool condition, string userMessage = null,
582582
[CallerFilePath] string path = null, [CallerLineNumber] int line = 0)
583583
{
584-
try { Xunit.Assert.True(condition); }
585-
catch (Exception e) { throw WrapException(e, path, line); }
586-
}
587-
588-
public static void True(bool condition, string userMessage,
589-
[CallerFilePath] string path = null, [CallerLineNumber] int line = 0)
590-
{
591-
try { Xunit.Assert.True(condition, userMessage); }
584+
try
585+
{
586+
if (userMessage == null)
587+
{
588+
Xunit.Assert.True(condition);
589+
}
590+
else
591+
{
592+
Xunit.Assert.True(condition, userMessage);
593+
}
594+
}
592595
catch (Exception e) { throw WrapException(e, path, line); }
593596
}
594597

src/System.Console/src/Resources/Strings.resx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@
160160
<value>Could not find a part of the path '{0}'.</value>
161161
</data>
162162
<data name="IO_PathTooLong" xml:space="preserve">
163-
<value>The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.</value>
163+
<value>The specified file name or path is too long, or a component of the specified path is too long.</value>
164164
</data>
165165
<data name="UnauthorizedAccess_IODenied_NoPathName" xml:space="preserve">
166166
<value>Access to the path is denied.</value>

src/System.Diagnostics.Debug/src/Resources/Strings.resx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,6 @@
166166
<value>The file '{0}' already exists.</value>
167167
</data>
168168
<data name="IO_PathTooLong" xml:space="preserve">
169-
<value>The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.</value>
169+
<value>The specified file name or path is too long, or a component of the specified path is too long.</value>
170170
</data>
171171
</root>

src/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,7 @@ private void SetWorkingSetLimitsCore(IntPtr? newMin, IntPtr? newMax, out IntPtr
146146
private static string GetExePath()
147147
{
148148
// Determine the maximum size of a path
149-
int maxPath = -1;
150-
Interop.libc.GetPathConfValue(ref maxPath, Interop.libc.PathConfNames._PC_PATH_MAX, Interop.libc.DEFAULT_PC_PATH_MAX);
149+
int maxPath = Interop.libc.MaxPath;
151150

152151
// Start small with a buffer allocation, and grow only up to the max path
153152
for (int pathLen = 256; pathLen < maxPath; pathLen *= 2)

src/System.IO.FileSystem.DriveInfo/src/Resources/Strings.resx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@
157157
<value>Could not find a part of the path '{0}'.</value>
158158
</data>
159159
<data name="IO_PathTooLong" xml:space="preserve">
160-
<value>The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.</value>
160+
<value>The specified file name or path is too long, or a component of the specified path is too long.</value>
161161
</data>
162162
<data name="IO_SharingViolation_File" xml:space="preserve">
163163
<value>The process cannot access the file '{0}' because it is being used by another process.</value>

src/System.IO.FileSystem.Watcher/src/Resources/Strings.resx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@
142142
<value>Specified file length was too large for the file system.</value>
143143
</data>
144144
<data name="IO_PathTooLong" xml:space="preserve">
145-
<value>The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.</value>
145+
<value>The specified file name or path is too long, or a component of the specified path is too long.</value>
146146
</data>
147147
<data name="IO_PathNotFound_NoPathName" xml:space="preserve">
148148
<value>Could not find a part of the path.</value>

0 commit comments

Comments
 (0)