Example #1
0
 internal static string GetLongFilePath(string path)
 {
     if (path != null)
     {
         int longPathName   = NativeMethodsShared.GetLongPathName(path, (StringBuilder)null, 0);
         int lastWin32Error = Marshal.GetLastWin32Error();
         if (longPathName > 0)
         {
             StringBuilder fullpath = new StringBuilder(longPathName);
             longPathName   = NativeMethodsShared.GetLongPathName(path, fullpath, longPathName);
             lastWin32Error = Marshal.GetLastWin32Error();
             if (longPathName > 0)
             {
                 path = fullpath.ToString();
             }
         }
         if (longPathName == 0 && lastWin32Error != 0)
         {
             NativeMethodsShared.ThrowExceptionForErrorCode(lastWin32Error);
         }
     }
     return(path);
 }
Example #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)));
        }