Skip to main content
2 of 5
edited tags
dfhwze
  • 14.2k
  • 3
  • 40
  • 101

Validate (Possible) File/Directory Path

I am working on a "comprehensive" library for use in my internal applications and I have created a working method (as far as all of my testing has shown thus far) to ensure that a file/directory path is - or, at least, could be - legitimate and should be accessible to any user of the same application. NOTE: These are all internal systems not intended for public use or consumption.

I've tried to pull together bits of information/code I've found that address certain aspects of the issue into a "single" method, part of which involves converting an individual user's mapped drives to full UNC paths (U:\PublicFolder\SomeFile.txt becomes \\SERVERNAME\Share\PublicFolder\SomeFile.txt). On the other hand, if the drive is a local, physical drive on the user's machine, I don't want to convert that to UNC (\\COMPUTERNAME\C$\SomeFolder\SomeFile.txt), but instead retain the absolute path to the local drive (C:\SomeFolder\SomeFile.txt) to prevent issues with access privileges. This is what I've come up with, but I'm wondering if this code is a bit too ambitious or overly contrived.

Public Enum PathType
    File
    Directory
End Enum

Public Shared Function GetRealPath(ByVal file As IO.FileInfo) As String
    Return GetRealPath(file.FullName, PathType.File)
End Function

Public Shared Function GetRealPath(ByVal folder As IO.DirectoryInfo) As String
    Return GetRealPath(folder.FullName, PathType.Directory)
End Function

Public Shared Function GetRealPath(ByVal filePath As String, ByVal pathType As PathType) As String
    Dim FullPath As String = String.Empty

    If filePath Is Nothing OrElse String.IsNullOrEmpty(filePath) Then
        Throw New ArgumentNullException("No path specified")
    Else
        If filePath.IndexOfAny(IO.Path.GetInvalidPathChars) >= 0 Then
            Throw New ArgumentException("The specified path '" & filePath & "' is invalid")
        Else
            If pathType = PathType.File Then
                Try
                    Dim TempFile As New IO.FileInfo(filePath)

                    If TempFile.Name.IndexOfAny(Path.GetInvalidFileNameChars) >= 0 Then
                        Throw New ArgumentException("The specified file name '" & filePath & "' is invalid")
                    End If

                    TempFile = Nothing
                Catch ex As Exception
                    Throw New ArgumentException("The specified file name '" & filePath & "' is invalid", ex)
                End Try
            End If

            ' The path should not contain any invalid characters. Start trying to populate the FullPath variable.
            If IO.Path.IsPathRooted(filePath) Then
                FullPath = filePath
            Else
                Try
                    FullPath = IO.Path.GetFullPath(filePath)
                Catch ex As Exception
                    Throw New ArgumentException("The specified path '" & filePath & "' is invalid", ex)
                End Try
            End If

            If Not FullPath.StartsWith("\\") Then
                Dim PathRoot As String = IO.Path.GetPathRoot(FullPath)

                If PathRoot Is Nothing OrElse String.IsNullOrEmpty(PathRoot) Then
                    FullPath = String.Empty
                    Throw New ArgumentException("The specified path '" & filePath & "' is invalid")
                Else
                    If Not IO.Directory.GetLogicalDrives.Contains(PathRoot) Then
                        FullPath = String.Empty
                        Throw New ArgumentException("The specified path '" & filePath & "' is invalid. Drive '" & PathRoot & "' does not exist.")
                    Else
                        Dim CurrentDrive As New System.IO.DriveInfo(PathRoot)

                        If CurrentDrive.DriveType = DriveType.Network Then
                            Using HKCU As Microsoft.Win32.RegistryKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Network\" & FullPath(0))
                                If Not HKCU Is Nothing Then
                                    FullPath = HKCU.GetValue("RemotePath").ToString() & FullPath.Remove(0, 2).ToString()
                                End If
                            End Using
                        ElseIf Not CurrentDrive.DriveType = DriveType.NoRootDirectory AndAlso Not CurrentDrive.DriveType = DriveType.Unknown Then
                            Dim SubstPath As String = String.Empty

                            If IsSubstPath(FullPath, SubstPath) Then
                                FullPath = SubstPath
                            End If
                        Else
                            FullPath = String.Empty
                            Throw New ArgumentException("The specified path '" & filePath & "' is invalid. Drive '" & CurrentDrive.Name & "' does not exist.")
                        End If
                    End If
                End If
            End If
        End If
    End If

    Return FullPath
End Function

<DllImport("kernel32.dll", SetLastError:=True)>
Private Shared Function QueryDosDevice(ByVal lpDeviceName As String, ByVal lpTargetPath As System.Text.StringBuilder, ByVal ucchMax As Integer) As UInteger
End Function

Private Shared Function IsSubstPath(ByVal pathToTest As String, <Out> ByRef realPath As String) As Boolean
    Dim PathInformation As System.Text.StringBuilder = New System.Text.StringBuilder(250)
    Dim DriveLetter As String = Nothing
    Dim WinApiResult As UInteger = 0

    realPath = Nothing

    Try
        ' Get the drive letter of the path
        DriveLetter = IO.Path.GetPathRoot(pathToTest).Replace("\\", "")
    Catch ex As ArgumentException
        Return False
    End Try

    WinApiResult = QueryDosDevice(DriveLetter, PathInformation, 250)

    If WinApiResult = 0 Then
        ' For debugging
        Dim LastWinError As Integer = Marshal.GetLastWin32Error()

        Return False
    End If

    ' If drive is SUBST'ed, the result will be in the format of "\??\C:\RealPath\".
    If PathInformation.ToString().StartsWith("\??\") Then
        Dim RealRoot As String = PathInformation.ToString().Remove(0, 4)

        RealRoot += If(PathInformation.ToString().EndsWith("\"), "", "\")
        realPath = IO.Path.Combine(RealRoot, pathToTest.Replace(IO.Path.GetPathRoot(pathToTest), ""))

        Return True
    End If

    realPath = pathToTest
    Return False
End Function
```