summaryrefslogtreecommitdiff
path: root/src/mscorlib/corefx/Interop/Unix/System.Native/Interop.GetCwd.cs
blob: 724e3423424aad2a0c5cf887fe437419fff798ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
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)
                    {
                        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);
        }
    }
}