Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access to the path 'd:\$RECYCLE.BIN\S-1-5-21-494745725-312220573-749543506-41600' is denied

Tags:

c#

I am new to C# . I have a text box where i enter the file to search and a 'search' button. on clock of search i want it to populate the files in the folder but i get the above error. Below is my code:

string[] directories = Directory.GetDirectories(@"d:\",
                                              "*",
                                              SearchOption.AllDirectories);
string file = textBox1.Text;
DataGrid dg = new DataGrid();

{
    var files = new List<string>();
     foreach (DriveInfo d in DriveInfo.GetDrives().Where(x => x.IsReady))
        {
        try
        {
            files.AddRange(Directory.GetFiles(d.RootDirectory.FullName,  file , SearchOption.AllDirectories));
        }
        catch(Exception ex)
        {
            MessageBox.Show("the  exception is " + ex.ToString());
            //Logger.Log(e.Message); // Log it and move on
        }
}

Please help me resolve it . Thanks

like image 294
Santhosh Rajoo Avatar asked Oct 19 '22 19:10

Santhosh Rajoo


2 Answers

The most important rule when searching on a folder which potentially contains inaccessible subfolder is:

Do NOT use SearchOption.AllDirectories!

Use SearchOption.TopDirectoryOnly instead, combined with recursive search for all the accessible directories.

Using SearchOption.AllDirectories, one access violation will break your entire loop even before any file/directory is processed. But if you use SearchOption.TopDirectoryOnly, you only skip what is inaccessible.

There is more difficult way to use Directory.GetAccessControl() per child directory check to see if you have an access to a Directory before hand (this option is rather hard though - I don't really recommend this unless you know exactly how the access system works).

For recursive search, I have this code implemented for my own use:

public static List<string> GetAllAccessibleDirectories(string path, string searchPattern) {
    List<string> dirPathList = new List<string>();
    try {
        List<string> childDirPathList = Directory.GetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly).ToList(); //use TopDirectoryOnly
        if (childDirPathList == null || childDirPathList.Count <= 0) //this directory has no child
            return null;
        foreach (string childDirPath in childDirPathList) { //foreach child directory, do recursive search
            dirPathList.Add(childDirPath); //add the path
            List<string> grandChildDirPath = GetAllAccessibleDirectories(childDirPath, searchPattern);
            if (grandChildDirPath != null && grandChildDirPath.Count > 0) //this child directory has children and nothing has gone wrong
                dirPathList.AddRange(grandChildDirPath.ToArray()); //add the grandchildren to the list
        }
        return dirPathList; //return the whole list found at this level
    } catch {
        return null; //something has gone wrong, return null
    }
}

This is how you call it

List<string> accessibleDirs = GetAllAccessibleDirectories(myrootpath, "*");

Then, you only need to search/add the files among all accessible directories.

Note: this question is quite classical though. I believe there are some other better solutions out there too.

And in case there are some directories which you particularly want to avoid after you get all your accessible directories, you could also filter the List result by LINQ using part of the directory's name as keyword (i.e. Recycle.Bins).

like image 96
Ian Avatar answered Oct 22 '22 00:10

Ian


As Ian has specified in his post, do not use recursive file listing (Directory.GetFiles(path, searchPattern, SearchOption.AllDirectories)) in case like yours, since the first exception will stop further processing.

Also, to somewhat alleviate such issues and for better results in general, you should run this program as an Administrator. This can be done by right-clicking your application in windows explorer, and then checking Run this program as an administrator option on Compatibility tab.

Also, you should use code like below to do your search, so the intermediate exceptions do not stop further searching.

static void Main(string[] args) {
    string fileToFind = "*.jpg";
    var files = new List<string>();

    foreach (DriveInfo d in DriveInfo.GetDrives().Where(x => x.IsReady))
        files.AddRange(FindDirectory(fileToFind, d.RootDirectory.FullName));
}

/// <summary>
/// This function returns the full file path of the matches it finds. 
///   1. It does not do any parameter validation 
///   2. It searches recursively
///   3. It eats up any error that occurs when requesting files and directories within the specified path
///   4. Supports specifying wildcards in the fileToFind parameter.
/// </summary>
/// <param name="fileToFind">Name of the file to search, without the path</param>
/// <param name="path">The path under which the file needs to be searched</param>
/// <returns>Enumeration of all valid full file paths matching the file</returns>
public static IEnumerable<string> FindDirectory(string fileToFind, string path) {

    // Check if "path" directly contains "fileToFind"
    string[] files = null;
    try {
        files = Directory.GetFiles(path, fileToFind);
    } catch { }

    if (files != null) {
        foreach (var file in files)
            yield return file;
    }


    // Check all sub-directories of "path" to see if they contain "fileToFInd"
    string[] subDirs = null;
    try {
        subDirs = Directory.GetDirectories(path);
    } catch { }

    if (subDirs == null)
        yield break;

    foreach (var subDir in subDirs)
        foreach (var foundFile in FindDirectory(fileToFind, subDir))
            yield return foundFile;
}
like image 43
Vikhram Avatar answered Oct 21 '22 22:10

Vikhram