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; } }
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); }
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); }