internal static string NormalizePath(string path)
        {
            ErrorUtilities.VerifyThrowArgumentLength(path, "path");
            int           errorCode = 0;
            int           num2      = NativeMethodsShared.MAX_PATH;
            StringBuilder buffer    = new StringBuilder(num2 + 1);
            int           num3      = NativeMethodsShared.GetFullPathName(path, buffer.Capacity, buffer, IntPtr.Zero);

            errorCode = Marshal.GetLastWin32Error();
            if (num3 > num2)
            {
                num2      = num3;
                buffer    = new StringBuilder(num2 + 1);
                num3      = NativeMethodsShared.GetFullPathName(path, buffer.Capacity, buffer, IntPtr.Zero);
                errorCode = Marshal.GetLastWin32Error();
                ErrorUtilities.VerifyThrow((num3 + 1) < buffer.Capacity, "Final buffer capacity should be sufficient for full path name and null terminator.");
            }
            if (num3 <= 0)
            {
                errorCode = -2147024896 | errorCode;
                Marshal.ThrowExceptionForHR(errorCode);
                return(null);
            }
            string message = buffer.ToString();

            if (message.Length >= 260)
            {
                throw new PathTooLongException(message);
            }
            message = Path.Combine(message, string.Empty);
            if (message.StartsWith(@"\\", StringComparison.OrdinalIgnoreCase))
            {
                int num4 = 2;
                while (num4 < message.Length)
                {
                    char ch = message[num4];
                    if (ch.Equals('\\'))
                    {
                        num4++;
                        break;
                    }
                    num4++;
                }
                if ((num4 == message.Length) || (message.IndexOf(@"\\?\globalroot", StringComparison.OrdinalIgnoreCase) != -1))
                {
                    message = Path.GetFullPath(message);
                }
            }
            if (string.Equals(message, path, StringComparison.Ordinal))
            {
                message = path;
            }
            return(message);
        }
Exemple #2
0
        /// <summary>
        /// Gets the canonicalized full path of the provided path.
        /// Path.GetFullPath The pre .Net 4.6.2 implementation of Path.GetFullPath is slow and creates strings in its work.
        /// Therefore MSBuild has its own implementation on full framework.
        /// Guidance for use: call this on all paths accepted through public entry
        /// points that need normalization. After that point, only verify the path
        /// is rooted, using ErrorUtilities.VerifyThrowPathRooted.
        /// ASSUMES INPUT IS ALREADY UNESCAPED.
        /// </summary>
        internal static string NormalizePath(string path)
        {
            ErrorUtilities.VerifyThrowArgumentLength(path, "path");

#if FEATURE_LEGACY_GETFULLPATH
            if (NativeMethodsShared.IsWindows)
            {
                int errorCode = 0; // 0 == success in Win32

#if _DEBUG
                // Just to make sure and exercise the code that sets the correct buffer size
                // we'll start out with it deliberately too small
                int lenDir = 1;
#else
                int lenDir = MaxPath;
#endif
                unsafe
                {
                    char *finalBuffer = stackalloc char[lenDir + 1]; // One extra for the null terminator

                    int length = NativeMethodsShared.GetFullPathName(path, lenDir + 1, finalBuffer, IntPtr.Zero);
                    errorCode = Marshal.GetLastWin32Error();

                    // If the length returned from GetFullPathName is greater than the length of the buffer we've
                    // allocated, then reallocate the buffer with the correct size, and repeat the call
                    if (length > lenDir)
                    {
                        lenDir = length;
                        char *tempBuffer = stackalloc char[lenDir];
                        finalBuffer = tempBuffer;
                        length      = NativeMethodsShared.GetFullPathName(path, lenDir, finalBuffer, IntPtr.Zero);
                        errorCode   = Marshal.GetLastWin32Error();
                        // If we find that the length returned from GetFullPathName is longer than the buffer capacity, then
                        // something very strange is going on!
                        ErrorUtilities.VerifyThrow(
                            length <= lenDir,
                            "Final buffer capacity should be sufficient for full path name and null terminator.");
                    }

                    if (length > 0)
                    {
                        // In order to prevent people from taking advantage of our ability to extend beyond MaxPath
                        // since it is unlikely that the CLR fix will be a complete removal of maxpath madness
                        // we reluctantly have to restrict things here.
                        if (length >= MaxPath)
                        {
                            throw new PathTooLongException();
                        }

                        // Avoid creating new strings unnecessarily
                        string finalFullPath = AreStringsEqual(finalBuffer, length, path)
                            ? path
                            : new string(
                            finalBuffer,
                            startIndex : 0,
                            length : length);

                        // We really don't care about extensions here, but Path.HasExtension provides a great way to
                        // invoke the CLR's invalid path checks (these are independent of path length)
                        Path.HasExtension(finalFullPath);

                        if (finalFullPath.StartsWith(@"\\", StringComparison.Ordinal))
                        {
                            // If we detect we are a UNC path then we need to use the regular get full path in order to do the correct checks for UNC formatting
                            // and security checks for strings like \\?\GlobalRoot
                            int startIndex = 2;
                            while (startIndex < finalFullPath.Length)
                            {
                                if (finalFullPath[startIndex] == '\\')
                                {
                                    startIndex++;
                                    break;
                                }
                                else
                                {
                                    startIndex++;
                                }
                            }

                            /*
                             * From Path.cs in the CLR
                             *
                             * Throw an ArgumentException for paths like \\, \\server, \\server\
                             * This check can only be properly done after normalizing, so
                             \\foo\.. will be properly rejected.  Also, reject \\?\GLOBALROOT\
                             * (an internal kernel path) because it provides aliases for drives.
                             *
                             * throw new ArgumentException(Environment.GetResourceString("Arg_PathIllegalUNC"));
                             *
                             * // Check for \\?\Globalroot, an internal mechanism to the kernel
                             * // that provides aliases for drives and other undocumented stuff.
                             * // The kernel team won't even describe the full set of what
                             * // is available here - we don't want managed apps mucking
                             * // with this for security reasons.
                             */
                            if (startIndex == finalFullPath.Length || finalFullPath.IndexOf(@"\\?\globalroot", PathComparison) != -1)
                            {
                                finalFullPath = Path.GetFullPath(finalFullPath);
                            }
                        }

                        return(finalFullPath);
                    }
                }

                NativeMethodsShared.ThrowExceptionForErrorCode(errorCode);
                return(null);
            }
#endif
            return(FixFilePath(Path.GetFullPath(path)));
        }