internal static IEnumerable <string> GetVolumePathNamesForVolumeName(string volumeName) { return(StringBufferCache.CachedBufferInvoke((buffer) => { uint returnLength = 0; // GetLogicalDriveStringsPrivate takes the buffer count in TCHARs, which is 2 bytes for Unicode (WCHAR) while (!Private.GetVolumePathNamesForVolumeNameW(volumeName, buffer, (uint)buffer.CharCapacity, ref returnLength)) { int lastError = Marshal.GetLastWin32Error(); switch (lastError) { case WinError.ERROR_MORE_DATA: buffer.EnsureCharCapacity(returnLength); break; default: throw GetIoExceptionForError(lastError, volumeName); } } buffer.Length = returnLength; return buffer.Split('\0'); })); }
internal static string BufferInvoke(Func <StringBuffer, uint> invoker, string value = null, Func <int, bool> shouldThrow = null) { return(StringBufferCache.CachedBufferInvoke(Paths.MaxPath, (buffer) => { uint returnValue = 0; while ((returnValue = invoker(buffer)) > (uint)buffer.CharCapacity) { // Need more room for the output string buffer.EnsureCharCapacity(returnValue); } if (returnValue == 0) { // Failed int error = Marshal.GetLastWin32Error(); if (shouldThrow != null && !shouldThrow(error)) { return null; } throw GetIoExceptionForError(error, value); } buffer.Length = returnValue; return buffer.ToString(); })); }
internal static string GetVolumeNameForVolumeMountPoint(string volumeMountPoint) { volumeMountPoint = Paths.AddTrailingSeparator(volumeMountPoint); // MSDN claims 50 is "reasonable", let's go double. return(StringBufferCache.CachedBufferInvoke(100, (volumeName) => { if (!Private.GetVolumeNameForVolumeMountPointW(volumeMountPoint, volumeName, (uint)volumeName.CharCapacity)) { int lastError = Marshal.GetLastWin32Error(); throw GetIoExceptionForError(lastError, volumeMountPoint); } volumeName.SetLengthToFirstNull(); return volumeName.ToString(); })); }
internal static IEnumerable <string> GetLogicalDriveStrings() { return(StringBufferCache.CachedBufferInvoke((buffer) => { uint result = 0; // GetLogicalDriveStringsPrivate takes the buffer count in TCHARs, which is 2 bytes for Unicode (WCHAR) while ((result = Private.GetLogicalDriveStringsW((uint)buffer.CharCapacity, buffer)) > (uint)buffer.CharCapacity) { buffer.EnsureCharCapacity(result); } if (result == 0) { int lastError = Marshal.GetLastWin32Error(); throw GetIoExceptionForError(lastError); } buffer.Length = result; return buffer.Split('\0'); })); }
internal static string GetVolumePathName(string path) { // Most paths are mounted at the root, 50 should handle the canonical (guid) root return(StringBufferCache.CachedBufferInvoke(50, (volumePathName) => { while (!Private.GetVolumePathNameW(path, volumePathName, (uint)volumePathName.CharCapacity)) { int lastError = Marshal.GetLastWin32Error(); switch (lastError) { case WinError.ERROR_FILENAME_EXCED_RANGE: volumePathName.EnsureCharCapacity(volumePathName.CharCapacity * 2); break; default: throw GetIoExceptionForError(lastError, path); } } volumePathName.SetLengthToFirstNull(); return volumePathName.ToString(); })); }
internal static string BufferPathInvoke(string path, Func <string, StringBuffer, uint> invoker, bool utilizeExtendedSyntax = true) { if (path == null) { return(null); } string originalPath = path; bool hadExtendedPrefix = Paths.IsExtended(path); bool addedExtendedPrefix = false; if (utilizeExtendedSyntax && !hadExtendedPrefix && (path.Length > Paths.MaxPath)) { path = Paths.AddExtendedPrefix(path); addedExtendedPrefix = true; } return(StringBufferCache.CachedBufferInvoke(Paths.MaxPath, (buffer) => { uint returnValue = 0; while ((returnValue = invoker(path, buffer)) > (uint)buffer.CharCapacity) { // Need more room for the output string buffer.EnsureCharCapacity(returnValue); } if (returnValue == 0) { // Failed int error = Marshal.GetLastWin32Error(); throw GetIoExceptionForError(error, originalPath); } buffer.Length = returnValue; uint startIndex = 0; if (addedExtendedPrefix && buffer.StartsWithOrdinal(Paths.ExtendedPathPrefix)) { // Remove the prefix if (buffer.StartsWithOrdinal(Paths.ExtendedUncPrefix)) { // UNC, need to convert from \\?\UNC\ to \\. startIndex = (uint)Paths.ExtendedUncPrefix.Length - 2; buffer[startIndex] = Paths.DirectorySeparator; } else { startIndex = (uint)Paths.ExtendedPathPrefix.Length; } } // If the string did not change, return the original (to cut back on identical string pressure) if (buffer.SubStringEquals(originalPath, startIndex: startIndex)) { return originalPath; } else { return buffer.SubString(startIndex: startIndex); } })); }