Search code examples
vb.netskipcontinueresume

How to skip directory or file when UnauthorizedAccessException


I am writing an application which checks the computer for viruses from a specific path(including system paths, such as the Windows directory, Program Files, Application Data, etc)

The user will click a button "Start scan", will begin checking of system files(including Windows/ProgramFiles directories) for viruses, comparing files to MD5 hashes from a text files named "viruslist.txt"

However, I am having some issues with UnauthorizedAccessException errors. The application will stop when it detects a file which cannot be accessed.

I want the application to skip the denied files and move on to the next file in the specific path.

My code is as it follows: Backgroundworker Do Work code:

    Try
        For Each file As String In IO.Directory.EnumerateFiles(FolderBrowserDialog3.SelectedPath, IO.SearchOption.AllDirectories).Union(IO.Directory.EnumerateFiles(FolderBrowserDialog4.SelectedPath, "*", IO.SearchOption.AllDirectories))
            Try
                Dim scanbox As New TextBox
                Dim read As String = My.Computer.FileSystem.ReadAllText(System.AppDomain.CurrentDomain.BaseDirectory & "viruslist.txt")
                scanbox.Text = read.ToString
                Dim md5 As MD5CryptoServiceProvider = New MD5CryptoServiceProvider
                Dim f As FileStream = New FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
                f = New FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
                md5.ComputeHash(f)
                Dim hash As Byte() = md5.Hash
                Dim buff As StringBuilder = New StringBuilder
                Dim hashByte As Byte
                For Each hashByte In hash
                    buff.Append(String.Format("{0:X2}", hashByte))
                Next

                If scanbox.Text.Contains(buff.ToString) Then

                    AddListItem2(ListBox2, "" & file & "")
                End If
            Catch ex As Exception
            End Try
            '   SetLabelText_ThreadSafe(Me.Label1, "" & file & "")
            If (BackgroundWorker1.CancellationPending = True) Then

                e.Cancel = True
                Exit For
            End If
            SetLabelText_ThreadSafe(Me.Labelscannedfiles, file & "")
            int = int + 1
            SetLabelText_ThreadSafe(Me.Label2, int & " Out Of " & filecount & "")
            Dim pct As Integer = (int / filecount * 100)
            BackgroundWorker1.ReportProgress(pct)
        Next file
  Catch ex as unauthorizedaccessexception

Also, the button code(start scan):

 FolderBrowserDialog3.SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.Windows)

        Try
            For Each strDir As String In
                System.IO.Directory.GetDirectories(FolderBrowserDialog3.SelectedPath)

                For Each strFile As String In System.IO.Directory.GetFiles(strDir)



                Next
            Next
        Catch ex As Exception

Listbox2- used to display detected infected objects. I've tried the following:

  • Changing the app's manifest to "requireAdministrator" and "highestavailable" ;
  • Disabling UAC .

Nothing worked so far!

UPDATE Thanks to JQSOFT for providing the solution to my issue. The below solution will surely help a lot of people who have the same issue I had. This question has been solved.


Solution

  • Here's some points.

    'Set this to True in the Cancel button...
    Private cancel As Boolean
    
    Sub New()
        InitializeComponent()
        '...
    
        BackgroundWorker1.WorkerReportsProgress = True
        BackgroundWorker1.WorkerSupportsCancellation = True
    End Sub
    

    Use this iterator function to get the authorized files and folders:

    Private Iterator Function IterateFolders(startDir As String, 
                                             includeFiles As Boolean, 
                                             includeSubDir As Boolean) As IEnumerable(Of String)
        Try
            For Each dirName In Directory.EnumerateDirectories(startDir)
                Yield dirName
    
                Try
                    If includeFiles Then
                        For Each fileName In Directory.EnumerateFiles(startDir)
                            Yield fileName
                        Next
                    End If
    
                    If includeSubDir Then
                        For Each subDir In IterateFolders(dirName, includeFiles, includeSubDir)
                            Yield subDir
                        Next
                    End If
                Catch ex As UnauthorizedAccessException
                Catch ex As Exception
                End Try
            Next
        Catch ex As UnauthorizedAccessException
        Catch ex As Exception
        End Try
    End Function
    

    The start scan button

    Private Sub Scan_Click(sender As Object, e As EventArgs) Handles Scan.Click
        If BackgroundWorker1.IsBusy Then Return
        Using fbd As New FolderBrowserDialog
            If fbd.ShowDialog = DialogResult.OK Then
                cancel = False
                '...
                BackgroundWorker1.RunWorkerAsync(fbd.SelectedPath)
            End If
        End Using
    End Sub
    

    The BackgroundWorker events:

    Private Sub BackgroundWorker1_DoWork(sender As Object,
                                         e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        Dim dir = e.Argument.ToString
    
        For Each file In IterateFolders(dir, True, True).
                Where(Function(f) IO.File.Exists(f)) '<- To get the files only.
            If cancel Then
                e.Cancel = True
                Return
            End If
    
            Try
    
                Dim b As Boolean = False
    
                Using md5 As New MD5CryptoServiceProvider,
                    f As FileStream = New FileStream(file, 
                                                 FileMode.Open, 
                                                 FileAccess.Read, 
                                                 FileShare.Read, 8192)
    
                    md5.ComputeHash(f)
    
                    Dim hash As Byte() = md5.Hash
                    Dim buff As New StringBuilder
                    Dim hashByte As Byte
    
                    For Each hashByte In hash
                        buff.Append(String.Format("{0:X2}", hashByte))
                    Next
    
                    b = IO.File.ReadLines("...FullPathOf\viruslist.txt").
                    Any(Function(x) x = buff.ToString)
                End Using
    
                'The main thread...
                Invoke(New Action(Sub()
                                        If b Then ListBox2.Items.Add(file)
                                        Labelscannedfiles.Text = ....
                                        Label2.Text = $"{int} Out of {filecount}"
                                  End Sub))
    
                'Code to update the progress here...
            Catch ex As IOException
            Catch ex As Exception
            End Try
        Next
    End Sub
    
    Private Sub BackgroundWorker1_ProgressChanged(sender As Object,
                                                  e As ProgressChangedEventArgs) _
                                                  Handles BackgroundWorker1.ProgressChanged
        'Update the progress...
    End Sub
    
    Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object,
                                                     e As RunWorkerCompletedEventArgs) _
                                                     Handles BackgroundWorker1.RunWorkerCompleted
        If e.Error IsNot Nothing Then
            'An error occurred
        ElseIf e.Cancelled Then
            'Operation canceled...
        Else
            'On success ....
        End If
    End Sub