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; }
private static string NewGetCurrentDirectory() { using (StringBuffer buffer = new StringBuffer(PathInternal.MaxShortPath)) { uint result = 0; while ((result = Win32Native.GetCurrentDirectoryW(buffer.CharCapacity, buffer.GetHandle())) > buffer.CharCapacity) { // Reported size is greater than the buffer size. Increase the capacity. // The size returned includes the null only if more space is needed (this case). buffer.EnsureCharCapacity(result); } if (result == 0) __Error.WinIOError(); buffer.Length = result; #if !PLATFORM_UNIX if (buffer.Contains('~')) return LongPathHelper.GetLongPathName(buffer); #endif return buffer.ToString(); } }
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 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.IsPartiallyQualified(outputBuffer), "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, 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). uint rootLength = PathInternal.GetRootLength(outputBuffer); bool isDevice = PathInternal.IsDevice(outputBuffer); StringBuffer inputBuffer = null; bool isDosUnc = false; uint 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 \\.\) inputBuffer = new StringBuffer(); inputBuffer.Append(outputBuffer); if (outputBuffer[2] == '.') { wasDotDevice = true; inputBuffer[2] = '?'; } } else { isDosUnc = IsDosUnc(outputBuffer); rootDifference = GetInputBuffer(outputBuffer, isDosUnc, out inputBuffer); } rootLength += rootDifference; uint inputLength = inputBuffer.Length; bool success = false; uint foundIndex = inputBuffer.Length - 1; while (!success) { uint result = Interop.mincore.GetLongPathNameW(inputBuffer.GetHandle(), outputBuffer.GetHandle(), 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(), outputBuffer.CharCapacity); } else { // Found the path success = true; outputBuffer.Length = result; if (foundIndex < inputLength - 1) { // It was a partial find, put the non-existent 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; if (wasDotDevice) bufferToUse[2] = '.'; string returnValue = null; int newLength = (int)(bufferToUse.Length - rootDifference); if (isDosUnc) { // Need to go from \\?\UNC\ to \\?\UN\\ bufferToUse[(uint)PathInternal.UncExtendedPathPrefix.Length - 1] = '\\'; } // We now need to strip out any added characters at the front of the string 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; }
private unsafe 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. Contract.Assert(!PathInternal.IsPartiallyQualified(outputBuffer), "should have resolved by now"); using (StringBuffer inputBuffer = new StringBuffer(outputBuffer)) { bool success = false; uint lastIndex = outputBuffer.Length - 1; uint foundIndex = lastIndex; uint rootLength = PathInternal.GetRootLength(outputBuffer); while (!success) { uint result = Win32Native.GetLongPathNameW(inputBuffer.GetHandle(), outputBuffer.GetHandle(), 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 != Win32Native.ERROR_FILE_NOT_FOUND && error != Win32Native.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); } else { // Found the path success = true; outputBuffer.Length = result; if (foundIndex < lastIndex) { // It was a partial find, put the non-existant part of the path back outputBuffer.Append(inputBuffer, foundIndex, inputBuffer.Length - foundIndex); } } } StringBuffer bufferToUse = success ? outputBuffer : inputBuffer; if (bufferToUse.SubstringEquals(originalPath)) { // Use the original path to avoid allocating return originalPath; } return bufferToUse.ToString(); } }
unsafe internal static string GetLongPathName(string path) { using (StringBuffer outputBuffer = new StringBuffer((uint)path.Length)) { uint result = 0; while ((result = Win32Native.GetLongPathNameW(path, outputBuffer.GetHandle(), outputBuffer.CharCapacity)) > outputBuffer.CharCapacity) { // Reported size (which does not include the null) is greater than the buffer size. Increase the capacity. outputBuffer.EnsureCharCapacity(result); } if (result == 0) { // Failure, get the error and throw GetErrorAndThrow(path); } outputBuffer.Length = result; return outputBuffer.ToString(); } }
/*===============================CurrentDirectory=============================== **Action: Provides a getter and setter for the current directory. The original ** current DirectoryInfo is the one from which the process was started. **Returns: The current DirectoryInfo (from the getter). Void from the setter. **Arguments: The current DirectoryInfo to which to switch to the setter. **Exceptions: ==============================================================================*/ public static String GetCurrentDirectory() { // Start with a buffer the size of MAX_PATH using (StringBuffer buffer = new StringBuffer(260)) { uint result = 0; while ((result = Win32Native.GetCurrentDirectoryW(buffer.CharCapacity, buffer.GetHandle())) > buffer.CharCapacity) { // Reported size is greater than the buffer size. Increase the capacity. // The size returned includes the null only if more space is needed (this case). buffer.EnsureCharCapacity(result); } if (result == 0) __Error.WinIOError(); buffer.Length = result; #if !PLATFORM_UNIX if (buffer.Contains('~')) return Path.GetFullPath(buffer.ToString()); #endif return buffer.ToString(); } }