Esempio n. 1
0
        private static void GetFullPathName(ReadOnlySpan <char> path, ref ValueStringBuilder builder)
        {
            // If the string starts with an extended prefix we would need to remove it from the path before we call GetFullPathName as
            // it doesn't root extended paths correctly. We don't currently resolve extended paths, so we'll just assert here.
            Debug.Assert(PathInternal.IsPartiallyQualified(path) || !PathInternal.IsExtended(path));

            uint result;

            while ((result = Interop.Kernel32.GetFullPathNameW(ref MemoryMarshal.GetReference(path), (uint)builder.Capacity, ref builder.GetPinnableReference(), IntPtr.Zero)) > builder.Capacity)
            {
                // Reported size is greater than the buffer size. Increase the capacity.
                builder.EnsureCapacity(checked ((int)result));
            }

            if (result == 0)
            {
                // Failure, get the error and throw
                int errorCode = Marshal.GetLastWin32Error();
                if (errorCode == 0)
                {
                    errorCode = Interop.Errors.ERROR_BAD_PATHNAME;
                }
                throw Win32Marshal.GetExceptionForWin32Error(errorCode, path.ToString());
            }

            builder.Length = (int)result;
        }
Esempio n. 2
0
        private unsafe string? GetServiceDisplayName(SafeServiceHandle? scmHandle, string serviceName)
        {
            var builder = new ValueStringBuilder(4096);
            int bufLen;
            while (true)
            {
                bufLen = builder.Capacity;
                fixed (char* c = builder)
                {
                    if (Interop.Advapi32.GetServiceDisplayName(scmHandle, serviceName, c, ref bufLen))
                        break;
                }

                int lastError = Marshal.GetLastWin32Error();
                if (lastError == Interop.Errors.ERROR_SERVICE_DOES_NOT_EXIST)
                {
                    return null;
                }
                else if (lastError != Interop.Errors.ERROR_INSUFFICIENT_BUFFER)
                {
                    throw new InvalidOperationException(SR.Format(SR.NoService, serviceName, _machineName), new Win32Exception(lastError));
                }

                builder.EnsureCapacity(bufLen + 1); // Does not include null
            }

            builder.Length = bufLen;
            return builder.ToString();
        }
Esempio n. 3
0
        // This is only used by RegistryKey on Windows.
        internal static string ExpandEnvironmentVariables(string name)
        {
            Debug.Assert(name != null);

            if (name.Length == 0)
            {
                return(name);
            }

            Span <char> initialBuffer = stackalloc char[128];
            var         builder       = new ValueStringBuilder(initialBuffer);

            uint length;

            while ((length = Win32Native.ExpandEnvironmentStringsW(name, ref builder.GetPinnableReference(), (uint)builder.Capacity)) > builder.Capacity)
            {
                builder.EnsureCapacity((int)length);
            }

            if (length == 0)
            {
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
            }

            // length includes the null terminator
            builder.Length = (int)length - 1;
            return(builder.ToString());
        }
Esempio n. 4
0
        // Returns a unique temporary file name, and creates a 0-byte file by that
        // name on disk.
        public static string GetTempFileName()
        {
            Span <char>        initialTempPathBuffer = stackalloc char[PathInternal.MaxShortPath];
            ValueStringBuilder tempPathBuilder       = new ValueStringBuilder(initialTempPathBuffer);

            GetTempPath(ref tempPathBuilder);

            Span <char> initialBuffer = stackalloc char[PathInternal.MaxShortPath];
            var         builder       = new ValueStringBuilder(initialBuffer);

            uint result = 0;

            while ((result = Interop.Kernel32.GetTempFileNameW(
                        ref tempPathBuilder.GetPinnableReference(), "tmp", 0, ref builder.GetPinnableReference())) > builder.Capacity)
            {
                // Reported size is greater than the buffer size. Increase the capacity.
                builder.EnsureCapacity(checked ((int)result));
            }

            tempPathBuilder.Dispose();

            if (result == 0)
            {
                throw Win32Marshal.GetExceptionForLastWin32Error();
            }

            builder.Length = (int)result;

            string path = PathHelper.Normalize(ref builder);

            builder.Dispose();
            return(path);
        }
Esempio n. 5
0
        internal static int PrependDevicePathChars(ref ValueStringBuilder content, bool isDosUnc, ref ValueStringBuilder buffer)
        {
            int length = content.Length;

            length += isDosUnc
                ? PathInternal.UncExtendedPrefixLength - PathInternal.UncPrefixLength
                : PathInternal.DevicePrefixLength;

            buffer.EnsureCapacity(length + 1);
            buffer.Length = 0;

            if (isDosUnc)
            {
                // Is a \\Server\Share, put \\?\UNC\ in the front
                buffer.Append(PathInternal.UncExtendedPathPrefix);

                // Copy Server\Share\... over to the buffer
                buffer.Append(content.AsSpan(PathInternal.UncPrefixLength));

                // Return the prefix difference
                return(PathInternal.UncExtendedPrefixLength - PathInternal.UncPrefixLength);
            }
            else
            {
                // Not an UNC, put the \\?\ prefix in front, then the original string
                buffer.Append(PathInternal.ExtendedPathPrefix);
                buffer.Append(content.AsSpan());
                return(PathInternal.DevicePrefixLength);
            }
        }
Esempio n. 6
0
        public unsafe string GetRaw()
        {
            string variable = Variable;

            if (variable == null)
            {
                throw new ArgumentNullException(nameof(variable));
            }

            Span <char>        stack  = stackalloc char[128];
            ValueStringBuilder buffer = new ValueStringBuilder(stack);

            uint returnValue;

            while ((returnValue = Raw.GetEnvironmentVariable(variable, buffer.RawChars)) > buffer.Capacity)
            {
                buffer.EnsureCapacity((int)returnValue);
            }

            if (returnValue == 0)
            {
                return(null);
            }

            buffer.Length = (int)returnValue;
            return(buffer.ToString());
        }
Esempio n. 7
0
        public void EnsureCapacity_IfBufferTimesTwoWins()
        {
            Span <char> initialBuffer = stackalloc char[32];
            var         builder       = new ValueStringBuilder(initialBuffer);

            builder.EnsureCapacity(33);

            Assert.Equal(64, builder.Capacity);
        }
Esempio n. 8
0
        public static unsafe string Combine(params string[] paths)
        {
            if (paths == null)
            {
                throw new ArgumentNullException(nameof(paths));
            }
            int capacity = 0;
            int num      = 0;

            for (int index = 0; index < paths.Length; ++index)
            {
                if (paths[index] == null)
                {
                    throw new ArgumentNullException(nameof(paths));
                }
                if (paths[index].Length != 0)
                {
                    if (Path.IsPathRooted(paths[index]))
                    {
                        num      = index;
                        capacity = paths[index].Length;
                    }
                    else
                    {
                        capacity += paths[index].Length;
                    }
                    if (!PathInternal.IsDirectorySeparator(paths[index][paths[index].Length - 1]))
                    {
                        ++capacity;
                    }
                }
            }
            // ISSUE: untyped stack allocation
            ValueStringBuilder valueStringBuilder = new ValueStringBuilder(new Span <char>((void *)__untypedstackalloc(new IntPtr(520)), 260));

            valueStringBuilder.EnsureCapacity(capacity);
            for (int index = num; index < paths.Length; ++index)
            {
                if (paths[index].Length != 0)
                {
                    if (valueStringBuilder.Length == 0)
                    {
                        valueStringBuilder.Append(paths[index]);
                    }
                    else
                    {
                        if (!PathInternal.IsDirectorySeparator(valueStringBuilder[valueStringBuilder.Length - 1]))
                        {
                            valueStringBuilder.Append('\\');
                        }
                        valueStringBuilder.Append(paths[index]);
                    }
                }
            }
            return(valueStringBuilder.ToString());
        }
        public void EnsureCapacityTest()
        {
            Span <char> buffer = stackalloc char[4];

            using ValueStringBuilder sb = new ValueStringBuilder(buffer);

            sb.EnsureCapacity(32);
            Assert.True(sb.Capacity >= 32);
            Assert.AreEqual(0, sb.Length);
        }
Esempio n. 10
0
        public void EnsureCapacity_IfRequestedCapacityWins()
        {
            // Note: constants used here may be dependent on minimal buffer size
            // the ArrayPool is able to return.
            Span <char> initialBuffer = stackalloc char[32];
            var         builder       = new ValueStringBuilder(initialBuffer);

            builder.EnsureCapacity(65);

            Assert.Equal(128, builder.Capacity);
        }
Esempio n. 11
0
        public void EnsureCapacity_NoAllocIfNotNeeded()
        {
            // Note: constants used here may be dependent on minimal buffer size
            // the ArrayPool is able to return.
            Span <char> initialBuffer = stackalloc char[64];
            var         builder       = new ValueStringBuilder(initialBuffer);

            builder.EnsureCapacity(16);

            Assert.Equal(64, builder.Capacity);
        }
Esempio n. 12
0
        public static string Join(params string[] paths)
        {
            if (paths == null)
            {
                throw new ArgumentNullException(nameof(paths));
            }

            if (paths.Length == 0)
            {
                return(string.Empty);
            }

            int maxSize = 0;

            foreach (string path in paths)
            {
                maxSize += path?.Length ?? 0;
            }
            maxSize += paths.Length - 1;

            Span <char> initialBuffer = stackalloc char[260];    // MaxShortPath on Windows
            var         builder       = new ValueStringBuilder(initialBuffer);

            builder.EnsureCapacity(maxSize);

            for (int i = 0; i < paths.Length; i++)
            {
                if ((paths[i]?.Length ?? 0) == 0)
                {
                    continue;
                }

                string path = paths[i];

                if (builder.Length == 0)
                {
                    builder.Append(path);
                }
                else
                {
                    if (!PathInternal.IsDirectorySeparator(builder[builder.Length - 1]) && !PathInternal.IsDirectorySeparator(path[0]))
                    {
                        builder.Append(PathInternal.DirectorySeparatorChar);
                    }

                    builder.Append(path);
                }
            }

            return(builder.ToString());
        }
Esempio n. 13
0
        private static void GetTempPath(ref ValueStringBuilder builder)
        {
            uint result;

            while ((result = Interop.Kernel32.GetTempPathW(builder.Capacity, ref builder.GetPinnableReference())) > builder.Capacity)
            {
                // Reported size is greater than the buffer size. Increase the capacity.
                builder.EnsureCapacity(checked ((int)result));
            }

            if (result == 0)
            {
                throw Win32Marshal.GetExceptionForLastWin32Error();
            }

            builder.Length = (int)result;
        }
Esempio n. 14
0
        private static void GetUserName(ref ValueStringBuilder builder)
        {
            uint size = 0;

            while (Interop.Secur32.GetUserNameExW(Interop.Secur32.NameSamCompatible, ref builder.GetPinnableReference(), ref size) == Interop.BOOLEAN.FALSE)
            {
                if (Marshal.GetLastWin32Error() == Interop.Errors.ERROR_MORE_DATA)
                {
                    builder.EnsureCapacity(checked ((int)size));
                }
                else
                {
                    builder.Length = 0;
                    return;
                }
            }

            builder.Length = (int)size;
        }
Esempio n. 15
0
        public static unsafe string Join([Nullable(new byte[] { 1, 2 })] params string[] paths)
        {
            if (paths == null)
            {
                throw new ArgumentNullException(nameof(paths));
            }
            if (paths.Length == 0)
            {
                return(string.Empty);
            }
            int num = 0;

            foreach (string path in paths)
            {
                num += path != null ? path.Length : 0;
            }
            int capacity = num + (paths.Length - 1);
            // ISSUE: untyped stack allocation
            ValueStringBuilder valueStringBuilder = new ValueStringBuilder(new Span <char>((void *)__untypedstackalloc(new IntPtr(520)), 260));

            valueStringBuilder.EnsureCapacity(capacity);
            for (int index = 0; index < paths.Length; ++index)
            {
                string path = paths[index];
                if (path != null && path.Length != 0)
                {
                    if (valueStringBuilder.Length == 0)
                    {
                        valueStringBuilder.Append(path);
                    }
                    else
                    {
                        if (!PathInternal.IsDirectorySeparator(valueStringBuilder[valueStringBuilder.Length - 1]) && !PathInternal.IsDirectorySeparator(path[0]))
                        {
                            valueStringBuilder.Append('\\');
                        }
                        valueStringBuilder.Append(path);
                    }
                }
            }
            return(valueStringBuilder.ToString());
        }
Esempio n. 16
0
        public unsafe string GetRawInline()
        {
            string variable = Variable;

            if (variable == null)
            {
                throw new ArgumentNullException(nameof(variable));
            }

            Span <char>        stack  = stackalloc char[128];
            ValueStringBuilder buffer = new ValueStringBuilder(stack);

            uint returnValue;

            fixed(char *v = variable)
            {
                while (true)
                {
                    fixed(char *b = buffer)
                    {
                        if ((returnValue = Raw.GetEnvironmentVariableW(v, b, (uint)buffer.Capacity))
                            <= buffer.Capacity)
                        {
                            break;
                        }
                        else
                        {
                            buffer.EnsureCapacity((int)returnValue);
                        }
                    }
                }
                ;
            }

            if (returnValue == 0)
            {
                return(null);
            }

            buffer.Length = (int)returnValue;
            return(buffer.ToString());
        }
Esempio n. 17
0
        private static string ExpandEnvironmentVariablesCore(string name)
        {
            Span <char> initialBuffer = stackalloc char[128];
            var         builder       = new ValueStringBuilder(initialBuffer);

            uint length;

            while ((length = Interop.Kernel32.ExpandEnvironmentStrings(name, ref builder.GetPinnableReference(), (uint)builder.Capacity)) > builder.Capacity)
            {
                builder.EnsureCapacity((int)length);
            }

            if (length == 0)
            {
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
            }

            // length includes the null terminator
            builder.Length = (int)length - 1;
            return(builder.ToString());
        }
Esempio n. 18
0
        public static string Combine(params string[] paths)
        {
            if (paths == null)
            {
                throw new ArgumentNullException(nameof(paths));
            }

            int maxSize        = 0;
            int firstComponent = 0;

            // We have two passes, the first calculates how large a buffer to allocate and does some precondition
            // checks on the paths passed in.  The second actually does the combination.

            for (int i = 0; i < paths.Length; i++)
            {
                if (paths[i] == null)
                {
                    throw new ArgumentNullException(nameof(paths));
                }

                if (paths[i].Length == 0)
                {
                    continue;
                }

                if (IsPathRooted(paths[i]))
                {
                    firstComponent = i;
                    maxSize        = paths[i].Length;
                }
                else
                {
                    maxSize += paths[i].Length;
                }

                char ch = paths[i][paths[i].Length - 1];
                if (!PathInternal.IsDirectorySeparator(ch))
                {
                    maxSize++;
                }
            }

            Span <char> initialBuffer = stackalloc char[260];    // MaxShortPath on Windows
            var         builder       = new ValueStringBuilder(initialBuffer);

            builder.EnsureCapacity(maxSize);

            for (int i = firstComponent; i < paths.Length; i++)
            {
                if (paths[i].Length == 0)
                {
                    continue;
                }

                if (builder.Length == 0)
                {
                    builder.Append(paths[i]);
                }
                else
                {
                    char ch = builder[builder.Length - 1];
                    if (!PathInternal.IsDirectorySeparator(ch))
                    {
                        builder.Append(PathInternal.DirectorySeparatorChar);
                    }

                    builder.Append(paths[i]);
                }
            }

            return(builder.ToString());
        }
Esempio n. 19
0
        internal static string TryExpandShortFileName(ref ValueStringBuilder outputBuilder, string?originalPath)
        {
            // We guarantee we'll expand short names for paths that only partially exist. As such, we need to find the part of the path that actually does exist. To
            // avoid allocating a lot we'll create only one input array and modify the contents with embedded nulls.

            Debug.Assert(!PathInternal.IsPartiallyQualified(outputBuilder.AsSpan()), "should have resolved by now");

            // We'll have one of a few cases by now (the normalized path will have already:
            //
            //  1. Dos path (C:\)
            //  2. Dos UNC (\\Server\Share)
            //  3. Dos device path (\\.\C:\, \\?\C:\)
            //
            // We want to put the extended syntax on the front if it doesn't already have it (for long path support and speed), which may mean switching from \\.\.
            //
            // Note that we will never get \??\ here as GetFullPathName() does not recognize \??\ and will return it as C:\??\ (or whatever the current drive is).

            int  rootLength = PathInternal.GetRootLength(outputBuilder.AsSpan());
            bool isDevice   = PathInternal.IsDevice(outputBuilder.AsSpan());

            // As this is a corner case we're not going to add a stackalloc here to keep the stack pressure down.
            var inputBuilder = new ValueStringBuilder();

            bool isDosUnc       = false;
            int  rootDifference = 0;
            bool wasDotDevice   = false;

            // Add the extended prefix before expanding to allow growth over MAX_PATH
            if (isDevice)
            {
                // We have one of the following (\\?\ or \\.\)
                inputBuilder.Append(outputBuilder.AsSpan());

                if (outputBuilder[2] == '.')
                {
                    wasDotDevice    = true;
                    inputBuilder[2] = '?';
                }
            }
            else
            {
                isDosUnc       = !PathInternal.IsDevice(outputBuilder.AsSpan()) && outputBuilder.Length > 1 && outputBuilder[0] == '\\' && outputBuilder[1] == '\\';
                rootDifference = PrependDevicePathChars(ref outputBuilder, isDosUnc, ref inputBuilder);
            }

            rootLength += rootDifference;
            int inputLength = inputBuilder.Length;

            bool success    = false;
            int  foundIndex = inputBuilder.Length - 1;

            while (!success)
            {
                uint result = Interop.Kernel32.GetLongPathNameW(
                    ref inputBuilder.GetPinnableReference(terminate: true), ref outputBuilder.GetPinnableReference(), (uint)outputBuilder.Capacity);

                // Replace any temporary null we added
                if (inputBuilder[foundIndex] == '\0')
                {
                    inputBuilder[foundIndex] = '\\';
                }

                if (result == 0)
                {
                    // Look to see if we couldn't find the file
                    int error = Marshal.GetLastWin32Error();
                    if (error != Interop.Errors.ERROR_FILE_NOT_FOUND && error != Interop.Errors.ERROR_PATH_NOT_FOUND)
                    {
                        // Some other failure, give up
                        break;
                    }

                    // We couldn't find the path at the given index, start looking further back in the string.
                    foundIndex--;

                    for (; foundIndex > rootLength && inputBuilder[foundIndex] != '\\'; foundIndex--)
                    {
                        ;
                    }
                    if (foundIndex == rootLength)
                    {
                        // Can't trim the path back any further
                        break;
                    }
                    else
                    {
                        // Temporarily set a null in the string to get Windows to look further up the path
                        inputBuilder[foundIndex] = '\0';
                    }
                }
                else if (result > outputBuilder.Capacity)
                {
                    // Not enough space. The result count for this API does not include the null terminator.
                    outputBuilder.EnsureCapacity(checked ((int)result));
                }
                else
                {
                    // Found the path
                    success = true;
                    outputBuilder.Length = checked ((int)result);
                    if (foundIndex < inputLength - 1)
                    {
                        // It was a partial find, put the non-existent part of the path back
                        outputBuilder.Append(inputBuilder.AsSpan(foundIndex, inputBuilder.Length - foundIndex));
                    }
                }
            }

            // If we were able to expand the path, use it, otherwise use the original full path result
            ref ValueStringBuilder builderToUse = ref (success ? ref outputBuilder : ref inputBuilder);