diff options
Diffstat (limited to 'src/mscorlib/shared/Interop/Unix/System.Native/Interop.GetCwd.cs')
-rw-r--r-- | src/mscorlib/shared/Interop/Unix/System.Native/Interop.GetCwd.cs | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/src/mscorlib/shared/Interop/Unix/System.Native/Interop.GetCwd.cs b/src/mscorlib/shared/Interop/Unix/System.Native/Interop.GetCwd.cs new file mode 100644 index 0000000000..a27a35c9f5 --- /dev/null +++ b/src/mscorlib/shared/Interop/Unix/System.Native/Interop.GetCwd.cs @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Sys + { + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetCwd", SetLastError = true)] + private static unsafe extern byte* GetCwd(byte* buffer, int bufferLength); + + internal static unsafe string GetCwd() + { + const int StackLimit = 256; + + // First try to get the path into a buffer on the stack + byte* stackBuf = stackalloc byte[StackLimit]; + string result = GetCwdHelper(stackBuf, StackLimit); + if (result != null) + { + return result; + } + + // If that was too small, try increasing large buffer sizes + // until we get one that works or until we hit MaxPath. + int maxPath = Interop.Sys.MaxPath; + if (StackLimit < maxPath) + { + int bufferSize = StackLimit; + do + { + checked { bufferSize *= 2; } + var buf = new byte[Math.Min(bufferSize, maxPath)]; + fixed (byte* ptr = &buf[0]) + { + result = GetCwdHelper(ptr, buf.Length); + if (result != null) + { + return result; + } + } + } + while (bufferSize < maxPath); + } + + // If we couldn't get the cwd with a MaxPath-sized buffer, something's wrong. + throw Interop.GetExceptionForIoErrno(new ErrorInfo(Interop.Error.ENAMETOOLONG)); + } + + private static unsafe string GetCwdHelper(byte* ptr, int bufferSize) + { + // Call the real getcwd + byte* result = GetCwd(ptr, bufferSize); + + // If it returned non-null, the null-terminated path is in the buffer + if (result != null) + { + return Marshal.PtrToStringAnsi((IntPtr)ptr); + } + + // Otherwise, if it failed due to the buffer being too small, return null; + // for anything else, throw. + ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo(); + if (errorInfo.Error == Interop.Error.ERANGE) + { + return null; + } + throw Interop.GetExceptionForIoErrno(errorInfo); + } + } +} |