Resolved Check a folder path to see if the user can open it

aaaron

Well-known member
Joined
Jan 23, 2011
Messages
216
Programming Experience
10+
I'm making a file explorer from a KnownFolder Guids list

I can get the paths of the ones that have paths.

So, I can eliminate the one that do not.

But I want to eliminate the folder nodes with paths that the user can't access.

I need to check something of the folder path that tells me the user can open it.

I tried checking FileVersionInfo but that does not work for folders.

Maybe something that causes an exception if it comes that.
 
Solution
Depends on what kind of access you want. For example Directory.GetAccessControl(path) throws UnauthorizedAccess exception in some cases, but even if it doesn't you may not be able to use GetFiles without getting same exception. Further reading the access control can be complicated also. You may be able to list files, but not write in same location too.
KnownFolder Guids list
Why guids? Isn't this covered by Environment.SpecialFolder Enum (System)
Depends on what kind of access you want. For example Directory.GetAccessControl(path) throws UnauthorizedAccess exception in some cases, but even if it doesn't you may not be able to use GetFiles without getting same exception. Further reading the access control can be complicated also. You may be able to list files, but not write in same location too.
KnownFolder Guids list
Why guids? Isn't this covered by Environment.SpecialFolder Enum (System)
 
Solution
This code seems to be accurate to detect if GetFiles is possible:
VB.NET:
Public Shared Function CurrentUserCanListDirectory(info As IO.DirectoryInfo) As Boolean
    Try
        Dim acl = info.GetAccessControl()
        Dim accessRules = acl.GetAccessRules(True, True, GetType(SecurityIdentifier))
        If accessRules Is Nothing Then Return False
        Dim allow = False
        Dim deny = False

        For Each rule As FileSystemAccessRule In accessRules
            If (rule.FileSystemRights And FileSystemRights.ListDirectory) <> FileSystemRights.ListDirectory Then Continue For

            If rule.AccessControlType = AccessControlType.Allow Then
                allow = True
            ElseIf rule.AccessControlType = AccessControlType.Deny Then
                deny = True
            End If
        Next

        Return allow AndAlso Not deny
    Catch ex As Exception
        Return False
    End Try
End Function
 
I had already done something using GetDirectories and GetFles that seem to work but this looks much more knowledgeable so I'll use it.

I'll have to run yours a few times to get a better feel of how often it uses the Catch code compared to mine. Bet it's better.

Thanks (again)
 
Last edited:
JohnH,

After I saw your first post I generated the below sub.

Public Shared Function CurrentUserCanListDirectory(specialDirPath As String) As Boolean
Dim dSecurity As Security.AccessControl.DirectorySecurity = dInfo.GetAccessControl()
Try
Dim dInfo As DirectoryInfo = New DirectoryInfo(specialDirPath)
Catch ex As Exception
Return False
End Try
Try
Dim w1 As String() = IO.Directory.GetDirectories(specialDirPath)
Catch ex As Exception
Return False
End Try
Try
Dim w1 As String() = IO.Directory.GetFiles(specialDirPath)
Catch ex As Exception
Return False
End Try
Return True
End Function

After your second post it occurred to me to check to see if they produced the same list of OK filenames.

So I ran first with one and then with the other. Something like 60,00 filenames.

They produced the same list except for files in <User>.AppData\Local\

I figure the difference is because the files in AppData\Local changed between runs.

So I ran a much smaller test checking lapsed time.

The nice sophisticated one took 0.057 seconds

While my brut force one took 0.013 seconds.

Anyway, I thought it was interesting and that you'd want to know.
 
Last edited:
I would expect to try and not fail a GetFiles for a single directory to be faster than inspecting the rights for that directory and then GetFiles, but I would also expect doing GetFiles for all directories of interest to be slower than just inspecting rights for those directories. If you don't always get all files for all directories, but want to know which directories to list as "valid" before GetFiles, then it would make sense to inspect first.

Not sure what you mean by different files, CurrentUserCanListDirectory returns true for the LocalApplicationData directory for me.
 
Not sure what you mean by different files, CurrentUserCanListDirectory returns true for the LocalApplicationData directory for me.

I checked the entire tree of folders and their files, including my profile which includes AppData\Local and copied into a file the names of any that passed.

I did this using one sub then the other.

Then compared the two files and displayed the names of files that are not in both list. This showed that each list (i.e. each sub allowed) had a collection of files from AppData\Local that the other did not . Mostly from a Temp folder.
 
Last edited:
I tested with this code for the LocalApplicationData directory and didn't detect any discrepancy.
VB.NET:
Sub ListFilesRecursive(dir As IO.DirectoryInfo)
    If CurrentUserCanListDirectory(dir) Then
        Try
            Dim f = dir.GetFiles
            For Each subdirectory In dir.GetDirectories
                ListFilesRecursive(subdirectory)
            Next
        Catch ex As UnauthorizedAccessException
            'unexpected
            Debug.WriteLine($"failed listing anyway: {dir.FullName}")
        End Try
    Else
        Try
            Dim f = dir.GetFiles
            For Each subdirectory In dir.GetDirectories
                ListFilesRecursive(subdirectory)
            Next
            Debug.WriteLine($"listing allowed anyway: {dir.FullName}")
        Catch ex As UnauthorizedAccessException
            'expected
        End Try
    End If
End Sub
 
Back
Top