Exemple #1
0
        private static void GetFullPathName(string path, StringBuffer fullPath)
        {
            // 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.IsRelative(path) || !PathInternal.IsExtended(path));

            // Historically we would skip leading spaces *only* if the path started with a drive " C:" or a UNC " \\"
            int startIndex = PathInternal.PathStartSkip(path);

            fixed(char *pathStart = path)
            {
                uint result = 0;

                while ((result = Interop.mincore.GetFullPathNameW(pathStart + startIndex, (uint)fullPath.CharCapacity, fullPath.GetHandle(), IntPtr.Zero)) > fullPath.CharCapacity)
                {
                    // Reported size (which does not include the null) is greater than the buffer size. Increase the capacity.
                    fullPath.EnsureCharCapacity(result);
                }

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

                fullPath.Length = result;
            }
        }
Exemple #2
0
        private StringBuilder GetFullPathName(string path)
        {
            // Historically we would skip leading spaces *only* if the path started with a drive " C:" or a UNC " \\"
            int startIndex = PathInternal.PathStartSkip(path);
            int capacity   = path.Length;

            if (PathInternal.IsRelative(path))
            {
                // If the initial path is relative the final path will likely be no more than the current directory length (which can only
                // be MaxPath) so we'll pick that as a reasonable start.
                capacity += PathInternal.MaxShortPath;
            }
            else
            {
                // 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.IsExtended(path));
            }

            StringBuilder outputBuffer = this.GetOutputBuffer(capacity);

            fixed(char *pathStart = path)
            {
                int result = 0;

                while ((result = Interop.mincore.GetFullPathNameW(pathStart + startIndex, outputBuffer.Capacity + 1, outputBuffer, IntPtr.Zero)) > outputBuffer.Capacity)
                {
                    // Reported size (which does not include the null) is greater than the buffer size. Increase the capacity.
                    outputBuffer.Capacity = result;
                }

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

            return(outputBuffer);
        }
Exemple #3
0
        private static string TryExpandShortFileName(StringBuffer outputBuffer, 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 like crazy we'll create only one input array and modify the contents with embedded nulls.

            Debug.Assert(!PathInternal.IsRelative(outputBuffer), "should have resolved by now");
            Debug.Assert(!PathInternal.IsExtended(outputBuffer), "expanding short names expects normal paths");

            // Add the extended prefix before expanding to allow growth over MAX_PATH
            StringBuffer inputBuffer = null;
            ulong        rootLength  = PathInternal.GetRootLength(outputBuffer);
            bool         isUnc       = IsUnc(outputBuffer);

            ulong rootDifference = GetInputBuffer(outputBuffer, isUnc, out inputBuffer);

            rootLength += rootDifference;
            ulong inputLength = inputBuffer.Length;

            bool  success    = false;
            ulong foundIndex = inputBuffer.Length - 1;

            while (!success)
            {
                uint result = Interop.mincore.GetLongPathNameW(inputBuffer.GetHandle(), outputBuffer.GetHandle(), (uint)outputBuffer.CharCapacity);

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

                if (result == 0)
                {
                    // Look to see if we couldn't find the file
                    int error = Marshal.GetLastWin32Error();
                    if (error != Interop.mincore.Errors.ERROR_FILE_NOT_FOUND && error != Interop.mincore.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 && inputBuffer[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
                        inputBuffer[foundIndex] = '\0';
                    }
                }
                else if (result > outputBuffer.CharCapacity)
                {
                    // Not enough space. The result count for this API does not include the null terminator.
                    outputBuffer.EnsureCharCapacity(result);
                    result = Interop.mincore.GetLongPathNameW(inputBuffer.GetHandle(), outputBuffer.GetHandle(), (uint)outputBuffer.CharCapacity);
                }
                else
                {
                    // Found the path
                    success             = true;
                    outputBuffer.Length = result;
                    if (foundIndex < inputLength - 1)
                    {
                        // It was a partial find, put the non-existant part of the path back
                        outputBuffer.Append(inputBuffer, foundIndex, inputBuffer.Length - foundIndex);
                    }
                }
            }

            // Strip out the prefix and return the string
            StringBuffer bufferToUse = success ? outputBuffer : inputBuffer;
            string       returnValue = null;

            int newLength = (int)(bufferToUse.Length - rootDifference);

            if (isUnc)
            {
                // Need to go from \\?\UNC\ to \\?\UN\\
                bufferToUse[(ulong)PathInternal.UncExtendedPathPrefix.Length - 1] = '\\';
            }

            if (bufferToUse.SubstringEquals(originalPath, rootDifference, newLength))
            {
                // Use the original path to avoid allocating
                returnValue = originalPath;
            }
            else
            {
                returnValue = bufferToUse.Substring(rootDifference, newLength);
            }

            inputBuffer.Dispose();
            return(returnValue);
        }