| File: Microsoft\VisualBasic\Helpers\FileSystemUtils.vb | Web Access |
| Project: src\winforms\src\Microsoft.VisualBasic.Forms\src\Microsoft.VisualBasic.Forms.vbproj (Microsoft.VisualBasic.Forms) |
' Licensed to the .NET Foundation under one or more agreements. ' The .NET Foundation licenses this file to you under the MIT license. Imports System.IO Imports System.Security Imports VbUtils = Microsoft.VisualBasic.CompilerServices.ExceptionUtils Namespace Microsoft.VisualBasic.CompilerServices ''' <summary> ''' Internal utilities from Microsoft.VisualBasic.FileIO.FileSystem. ''' </summary> Friend NotInheritable Class FileSystemUtils ''' <summary> ''' Returns the given path in long format (v.s 8.3 format) if the path exists. ''' </summary> ''' <param name="fullPath">The path to resolve to long format.</param> ''' <returns>The given path in long format if the path exists.</returns> ''' <remarks> ''' GetLongPathName is a PInvoke call and requires unmanaged code permission. ''' Use <see cref="DirectoryInfo.GetFiles"/> and <see cref="DirectoryInfo.GetDirectories"/> (which call FindFirstFile) so that we always have permission. '''</remarks> Private Shared Function GetLongPath(fullPath As String) As String Debug.Assert(Not String.IsNullOrEmpty(fullPath) AndAlso IO.Path.IsPathRooted(fullPath), "Must be full path") Try ' If root path, return itself. UNC path do not recognize 8.3 format in root path, so this is fine. If IsRoot(fullPath) Then Return fullPath End If ' DirectoryInfo.GetFiles and GetDirectories call FindFirstFile which resolves 8.3 path. ' Get the DirectoryInfo (user must have code permission or access permission). Dim dInfo As New DirectoryInfo(FileIO.FileSystem.GetParentPath(fullPath)) If IO.File.Exists(fullPath) Then Debug.Assert(dInfo.GetFiles(IO.Path.GetFileName(fullPath)).Length = 1, "Must found exactly 1") Return dInfo.GetFiles(IO.Path.GetFileName(fullPath))(0).FullName ElseIf IO.Directory.Exists(fullPath) Then Debug.Assert(dInfo.GetDirectories(IO.Path.GetFileName(fullPath)).Length = 1, "Must found exactly 1") Return dInfo.GetDirectories(IO.Path.GetFileName(fullPath))(0).FullName Else ' Path does not exist, cannot resolve. Return fullPath End If Catch ex As Exception ' Ignore these type of exceptions and return FullPath. These type of exceptions should either be caught by calling functions ' or indicate that caller does not have enough permission and should get back the 8.3 path. If TypeOf ex Is ArgumentException OrElse TypeOf ex Is ArgumentNullException OrElse TypeOf ex Is PathTooLongException OrElse TypeOf ex Is NotSupportedException OrElse TypeOf ex Is DirectoryNotFoundException OrElse TypeOf ex Is SecurityException OrElse TypeOf ex Is UnauthorizedAccessException Then Debug.Assert(Not (TypeOf ex Is ArgumentException OrElse TypeOf ex Is ArgumentNullException OrElse TypeOf ex Is PathTooLongException OrElse TypeOf ex Is NotSupportedException), "These exceptions should be caught above") Return fullPath Else Throw End If End Try End Function ''' <summary> ''' Checks if the full path is a root path. ''' </summary> ''' <param name="path">The path to check.</param> ''' <returns><see langword="True"/> if FullPath is a root path, <see langword="False"/> otherwise.</returns> ''' <remarks> ''' IO.Path.GetPathRoot: C: -> C:, C:\ -> C:\, \\machine\share -> \\machine\share, ''' BUT \\machine\share\ -> \\machine\share (No separator here). ''' Therefore, remove any separators at the end to have correct result. ''' </remarks> Private Shared Function IsRoot(path As String) As Boolean ' This function accepts a relative path since GetParentPath will call this, ' and GetParentPath accept relative paths. If Not IO.Path.IsPathRooted(path) Then Return False End If path = path.TrimEnd(IO.Path.DirectorySeparatorChar, IO.Path.AltDirectorySeparatorChar) Return String.Equals(path, IO.Path.GetPathRoot(path), StringComparison.OrdinalIgnoreCase) End Function ''' <summary> ''' Removes all directory separators at the end of a path. ''' </summary> ''' <param name="path">a full or relative path.</param> ''' <returns>If Path is a root path, the same value. Otherwise, removes any directory separators at the end.</returns> ''' <remarks>We decided not to return path with separators at the end.</remarks> Private Shared Function RemoveEndingSeparator(path As String) As String If IO.Path.IsPathRooted(path) Then ' If the path is rooted, attempt to check if it is a root path. ' Note: IO.Path.GetPathRoot: C: -> C:, C:\ -> C:\, \\myshare\mydir -> \\myshare\mydir ' BUT \\myshare\mydir\ -> \\myshare\mydir!!! This function will remove the ending separator of ' \\myshare\mydir\ as well. Do not use IsRoot here. If path.Equals(IO.Path.GetPathRoot(path), StringComparison.OrdinalIgnoreCase) Then Return path End If End If ' Otherwise, remove all separators at the end. Return path.TrimEnd(IO.Path.DirectorySeparatorChar, IO.Path.AltDirectorySeparatorChar) End Function ''' <summary> ''' Throw <see cref="ArgumentException "/> if the file path ends with a separator. ''' </summary> ''' <param name="path">The file path.</param> ''' <param name="paramName">The parameter name to include in <see cref="ArgumentException "/> .</param> Friend Shared Sub CheckFilePathTrailingSeparator(path As String, paramName As String) ' Check for argument null If String.IsNullOrEmpty(path) Then Throw VbUtils.GetArgumentNullException(paramName) End If If path.EndsWith(IO.Path.DirectorySeparatorChar, StringComparison.Ordinal) Or path.EndsWith(IO.Path.AltDirectorySeparatorChar, StringComparison.Ordinal) Then Throw VbUtils.GetArgumentExceptionWithArgName(paramName, SR.IO_FilePathException) End If End Sub ''' <summary> ''' Normalize the path, but throw exception if the path ends with separator. ''' </summary> ''' <param name="path">The input path.</param> ''' <param name="paramName">The parameter name to include in the ''' exception if one is raised. ''' </param> ''' <returns>The normalized path.</returns> Friend Shared Function NormalizeFilePath( path As String, paramName As String) As String CheckFilePathTrailingSeparator(path, paramName) Return NormalizePath(path) End Function ''' <summary> ''' Get full path, get long format, and remove any pending separator. ''' </summary> ''' <param name="path">The path to be normalized.</param> ''' <returns>The normalized path.</returns> ''' <exception cref="Path.GetFullPath"> ''' <see cref="Path.GetFullPath"/> for possible exceptions. ''' </exception> ''' <remarks> ''' Keep this function since we might change the implementation / behavior later. ''' </remarks> Friend Shared Function NormalizePath(path As String) As String Return GetLongPath(RemoveEndingSeparator(IO.Path.GetFullPath(path))) End Function End Class End Namespace