UnauthorizedAccessException with getDirectories - c#

Hello everyone I currently got subdirectories I wanted through this call:
foreach (DirectoryInfo dir in parent)
{
try
{
subDirectories = dir.GetDirectories().Where(d => d.Exists == true).ToArray();
}
catch(UnauthorizedAccessException e)
{
Console.WriteLine(e.Message);
}
foreach (DirectoryInfo subdir in subDirectories)
{
Console.WriteLine(subdir);
var temp = new List<DirectoryInfo>();
temp = subdir.GetDirectories("*", SearchOption.AllDirectories).Where(d => reg.IsMatch(d.Name)).Where((d => !d.FullName.EndsWith("TESTS"))).Where(d => !(d.GetDirectories().Length == 0 && d.GetFiles().Length == 0)).Where(d => d.GetFiles().Length > 3).ToList();
candidates.AddRange(temp);
}
}
foreach(DirectoryInfo dir in candidates)
{
Console.WriteLine(dir);
}
so now my issue is that my final list called candidates I get nothing because im getting an access issue due to one of the folders called lost+found in my subdirectories folder in the try block. I tried using try and catch to handle the exception so I could keep doing my checks I actually dont care about this folder and im trying to just ignore it but I'm not sure how to go about ignoring it out of my get directories search any thoughts? I already tried doing a filter with .where to ignore any folder that contained the folder name but that didnt work either it just stopped my program at the folder name.

I have the same question (ResourceContext.GetForCurrentView call exception) about this exception (UnauthorizedAccessException), and this link gives an answer to the reason why this happens:
http://www.blackwasp.co.uk/FolderRecursion.aspx
Short quote:
... Key amongst these is that some of the folders that you attempt to
read could be configured so that the current user may not access them.
Rather than ignoring folders to which you have restricted access, the
method throws an UnauthorizedAccessException. However, we can
circumvent this problem by creating our own recursive folder search
code. ...
solution:
private static void ShowAllFoldersUnder(string path, int indent)
{
try
{
foreach (string folder in Directory.GetDirectories(path))
{
Console.WriteLine("{0}{1}", new string(' ', indent), Path.GetFileName(folder));
ShowAllFoldersUnder(folder, indent + 2);
}
}
catch (UnauthorizedAccessException) { }
}

You can use recursion like Microsoft explains: link.

Related

Get the exception folder to a listbox C#

I'm creating a method to handle directory and file exceptions.
I have listed all the directories and subdirectories of the C: \ Users \ folder
listBox1.Items.AddRange(Directory.GetDirectories("C:\\Users\\", "*", SearchOption.AllDirectories));
Some folders are protected by windows, and when you run a command for those folders it gives us an exception.
If there is any possible, How can I save the folder that returned the exception to a listbox when the exception happens? thanks
If you catch the Exception the Message will tell you the folder that threw the exception in the format of
Access to the path 'C:\Users\SomeFolder' is denied.
you just need to remove the static text, the simplest way is(you maybe able to find a more stylish way to do this, but you get the idea):
try
{
listBox1.Items.AddRange(Directory.GetDirectories("C:\\Users\\", "*", SearchOption.AllDirectories));
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
SomeListBox.Items.Add(ex.Message.Replace("Access to the path '", "").Replace("' is denied.", ""));
}
EDIT: if you want to traverse all the folders and keep going you might want to take a look at recursion. you could slightly modify the above code to make it a function.
void getDirectories(string path)
{
try
{
string[] directories = Directory.GetDirectories(path, "*", SearchOption.TopDirectoryOnly);
listBox1.Items.AddRange(directories);
foreach(string directory in directories)
{
getDirectories(directory);
}
}
catch (Exception ex)
{
//MessageBox.Show(ex.Message);
SomeListBox.Items.Add(ex.Message.Replace("Access to the path '", "").Replace("' is denied.", ""));
}
}
In case you want all folders with exceptions:
You can use the method with the following call:
List<DirectoryInfo> list = GetDirectories(new DirectoryInfo(#"root directory"), 0, 2);
I've implemented a max level, because in a deep structure it could take a long time before the search is done. If you don't need it, just remove the unnecessary lines of code ;)
List<DirectoryInfo> GetDirectories(DirectoryInfo di, int level, int maxLevel)
{
List<DirectoryInfo> exceptionList = new List<DirectoryInfo>();
foreach (DirectoryInfo directoryInfo in di.GetDirectories("*", SearchOption.TopDirectoryOnly))
{
try
{
DirectorySecurity directorySecurity = directoryInfo.GetAccessControl();
if (level + 1 < maxLevel)
{
exceptionList.AddRange(GetDirectories(directoryInfo, level + 1, maxLevel));
}
}
catch (UnauthorizedAccessException)
{
exceptionList.Add(directoryInfo);
}
}
return exceptionList;
}

How to get all the paths of exe in my computer with c#

Yes there any way by which i can get the paths of exe? I mean suppose i have 20 exes in my local disk c i want to get the paths of the exe like "C:\myexe.exe or it can be C:\dir\myexe.exe"
string getpathforexe[] = themethord;
foreach(string printvalue in getpathforexe)
{
messagebox.show(printvalue.tostring());
}
so what will be themethord?
What you essentially need is a safe, recursive, .exe search functions on a root folder, and you can apply it anywhere.
Something like this:
public static List<string> GetAllAccessibleFiles(string path, string searchPattern) {
List<string> dirPathList = new List<string>();
try {
string[] childFilePaths = Directory.GetFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
dirPathList.AddRange(childFilePaths);
foreach (string childDirPath in Directory.GetDirectories(path)) { //foreach child directory, do recursive search
List<string> grandChildDirPath = GetAllAccessibleFiles(childDirPath, searchPattern);
if (grandChildDirPath != null && grandChildDirPath.Count > 0) //this child directory has children and nothing has gone wrong
dirPathList.AddRange(grandChildDirPath); //add the grandchildren to the list
}
return dirPathList; //return the whole list found at this level
} catch (UnauthorizedAccessException ex){
//Do something if necessary
return null; //something has gone wrong, return null
}
}
Be careful of a couple of things:
Not all directories are accessible. When you try to access an unaccessible directory, you would get UnauthorizedAccessException
By using recursive search, you want your search result to be failed only on the directory where you have no access right.
Nevertheless, if you apply this to all your folders, likely you will take very long time. It is best to apply it to particular folders which you want to search for .exe files.
Explanations:
In the function, given a path, if first lists the files in the directory top folder:
string[] childFilePaths = Directory.GetFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
dirPathList.AddRange(childFilePaths);
If any of your files matches your search pattern, you add those files. Then next you check each folder consisted in your path directory:
foreach (string childDirPath in Directory.GetDirectories(path)) { //foreach child directory, do recursive search
List<string> grandChildDirPath = GetAllAccessibleFiles(childDirPath, searchPattern);
if (grandChildDirPath != null && grandChildDirPath.Count > 0) //this child directory has children and nothing has gone wrong
dirPathList.AddRange(grandChildDirPath); //add the grandchildren to the list
}
If any of the directory consists of any child folders, do recursive search to the children directories, and add the results together in the dirPathList and finally returns it:
return dirPathList; //return the whole list found at this level
Then you could get all the files with ".exe".
And in the catch, you probably want to check for the unauthorized access Exception:
catch (UnauthorizedAccessException ex){
//Do something
return null; //something has gone wrong, return null
}
You use it like this:
List<string> exefiles = YourClassNameWhoHasTheMethod.GetAllAccessibleFiles(testfolder, "*.exe"));
For example, you could test it with Recycle Bin like this:
string rbin = #"C:\$Recycle.Bin";
List<string> files = GetAllAccessibleFiles(rbin, "*.exe");
And these are what I get for the files:
C:\$Recycle.Bin\S-1-5-21-3161714743-1342575415-982792061-1001\$IYFMY6V.exe
C:\$Recycle.Bin\S-1-5-21-3161714743-1342575415-982792061-1001\$RYFMY6V.exe

Continue Foreach Loop On Error

I want to continue my code when error comes up , but i dont know how ...
here's my code :
foreach(string path in Directory.GetDirectories(#"C:\", "*.*", SearchOption.AllDirectories)
{
Console.WriteLine(path);
}
And the error comes on foreach(string path in Directory.GetDirectories(#"C:\", "*.*", SearchOption.AllDirectories) and i don't know how to continue this loop
and the error :
Unauthorized access
And even i run my code as Administrator this error comes up again
Thanks,
The best is to use recursive search and not using SearchOption.AllDirectories, but rather SearchOption.TopDirectoryOnly
If you use 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.
Thus, to do it, you can create a method which receives a directory path as input. And in that method, if the input directory have child directory(ies) (see Directory.GetDirectories(string path) method, you call the method again for each child directory (recursive call) before you process all the files in the directory. Else, get the files (see Directory.GetFiles) in the directory and process them immediately.
Then for the method above, one way is to prevent the code crash when you cannot access certain file/directory is by using try-catch block for each child directory reading and file reading. This way, if one file/folder cannot be accessed, your code will still be running, finding the processing the next file/directory.
Alternatively, you can 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).
Edit (code added):
Something like this will do:
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
}
}
And to call it, you can do something like this
string rootpath = #"C:\DummyRootFolder";
List<string> dirList = GetAllAccessibleDirectories(rootpath, "*.*"); //you get all accessible directories here
In the dirList you will get all the directories that you search for, and if there is access violation along the way, it will only affects sub-directories search due to the try-catch block.
Note that the rootpath is excluded in the method. But if you want to add it to the list too, you could simply do
dirList.Insert(0, path); //do this after you get dirList
There are also more complicated ways of doing this by using Directory.GetAccessControl and PermissionSet
Hope it may clarify.
According to the documentation, you should look at EnumerateDirectories for performance reasons:
https://msdn.microsoft.com/en-us/library/c1sez4sc(v=vs.110).aspx
Also, it appears that this question has already been answered before:
Directory.EnumerateFiles => UnauthorizedAccessException
Hope this helps!
How about this:
foreach (string path in Directory.GetDirectories(#"C:\", "*.*", SearchOption.AllDirectories)) {
try {
Console.WriteLine(path);
} catch (Exception ex) {
Console.WriteLine("Unable to access directories in path: " + path);
}
}

Access to the path 'c:\$Recycle.Bin\S-1-5-18' is denied

I have this code to copy all files from source-directory, F:\, to destination-directory.
public void Copy(string sourceDir, string targetDir)
{
//Exception occurs at this line.
string[] files = System.IO.Directory.GetFiles(sourceDir, "*.jpg",
SearchOption.AllDirectories);
foreach (string srcPath in files)
{
File.Copy(srcPath, srcPath.Replace(sourceDir, targetDir), true);
}
}
and getting an exception.
If I omit SearchOption.AllDirectories and it works but only copies files from F:\
Use following function instead of System.IO.Directory.GetFiles:
IEnumerable<String> GetAllFiles(string path, string searchPattern)
{
return System.IO.Directory.EnumerateFiles(path, searchPattern).Union(
System.IO.Directory.EnumerateDirectories(path).SelectMany(d =>
{
try
{
return GetAllFiles(d,searchPattern);
}
catch (UnauthorizedAccessException e)
{
return Enumerable.Empty<String>();
}
}));
}
File system objects are subject to security. Some file system objects are secured in such a way that they can only be accessed by certain users. You are encountering a file to which the user executing the code does not have sufficient rights to access.
The reason that you don't have access rights for this particular folder is to protect the security of the different users on the system. The folder in question is the recycle bin on that drive. And each different user has their own private recycle bin, that only they have permission to access. If anybody could access any other user's recycle bin, then users would be able to read each other's files, a clear violation of the system's security policy.
Perhaps the simplest way around this is to skip hidden folders at the root level of the drive. That simple change would be enough to solve your problem because you surely don't want to copy recycle bins.
That folder is a secure system folder (your bin, each drive has its own bin). Just place your file.copy into a try catch statement and ignore/log all the failures. That way you will only copy actual files and skip system files/folders.
If you really want to avoid the try catch statement. Use the fileinfo and directory info classes to figure out which folders/files are of the system and will throw an exception.
This should do the trick:
private IEnumerable<string> RecursiveFileSearch(string path, string pattern, ICollection<string> filePathCollector = null)
{
try
{
filePathCollector = filePathCollector ?? new LinkedList<string>();
var matchingFilePaths = Directory.GetFiles(path, pattern);
foreach(var matchingFile in matchingFilePaths)
{
filePathCollector.Add(matchingFile);
}
var subDirectories = Directory.EnumerateDirectories(path);
foreach (var subDirectory in subDirectories)
{
RecursiveFileSearch(subDirectory, pattern, filePathCollector);
}
return filePathCollector;
}
catch (Exception error)
{
bool isIgnorableError = error is PathTooLongException ||
error is UnauthorizedAccessException;
if (isIgnorableError)
{
return Enumerable.Empty<string>();
}
throw error;
}
}

How to delete files while Traversing folder tree

I am not sure if I am doing this correctly or if my logic is correct.
I am trying to go down a folder structure delete files older than a certain number of days, this part I have correctly implemented, delete empty folders.
Can all this be done in one loop?
Where do I do the folder delete?
I want to delete empty folders up to 3 or 4 level down.
private static void TraverseTree(System.IO.DirectoryInfo folder, double days)
{
Stack<string> dirs = new Stack<string>();
if (!folder.Exists)
throw new ArgumentException();
dirs.Push(folder.FullName);
while (dirs.Count > 0)
{
string currentDir = dirs.Pop();
string[] subDirs;
try
{
subDirs = System.IO.Directory.GetDirectories(currentDir);
}
// An UnauthorizedAccessException exception will be thrown if we do not have
// discovery permission on a folder or file. It may or may not be acceptable
// to ignore the exception and continue enumerating the remaining files and
// folders. It is also possible (but unlikely) that a DirectoryNotFound exception
// will be raised. This will happen if currentDir has been deleted by
// another application or thread after our call to Directory.Exists. The
// choice of which exceptions to catch depends entirely on the specific task
// you are intending to perform and also on how much you know with certainty
// about the systems on which this code will run.
catch (UnauthorizedAccessException e)
{
Console.WriteLine(e.Message);
continue;
}
catch (System.IO.DirectoryNotFoundException e)
{
Console.WriteLine(e.Message);
continue;
}
string[] files = null;
try
{
files = System.IO.Directory.GetFiles(currentDir);
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine(e.Message);
continue;
}
catch (System.IO.DirectoryNotFoundException e)
{
Console.WriteLine(e.Message);
continue;
}
// Perform the required action on each file here.
// Modify this block to perform your required task.
foreach (string file in files)
{
try
{
// Perform whatever action is required in your scenario.
System.IO.FileInfo fi = new System.IO.FileInfo(file);
Console.WriteLine("{0}: {1}, {2}", fi.Name, fi.Length, fi.CreationTime);
// Delete old files
if (fi.LastWriteTime < DateTime.Now.AddDays(-days))
fi.Delete();
}
catch (System.IO.FileNotFoundException e)
{
// If file was deleted by a separate application
// or thread since the call to TraverseTree()
// then just continue.
Console.WriteLine(e.Message);
continue;
}
}
// Push the subdirectories onto the stack for traversal.
// This could also be done before handing the files.
foreach (string str in subDirs)
dirs.Push(str);
}
}
Code is from MSDN.
A recursive approach would probably be cleaner.
private static void DeleteOldFilesAndFolders(string path)
{
foreach (string directory in System.IO.Directory.GetDirectories(path))
{
DeleteOldFilesAndFolders(directory);
// If the directory is empty and old, delete it here.
}
foreach (string file in System.IO.Directory.GetFiles(path))
{
// Check the file's age and delete it if it's old.
}
}
Something that I notice about your code is that the dozens of lines of "mechanism" for walking the tree structure completely overwhelms the two lines of code that actually do the work. That makes it hard to read, understand, change, debug and maintain this code.
Here's what I would do instead.
You have only three high-level operations in your program: (1) get all the files, (2) filter to find the ones to delete, (3) delete each file. So write a program which does each of those in one statement.
For the first operation, I would factor out the mechanism above into its own function: a function which implements, say, IEnumerable, and all it does is keeps on yielding out information about files. It doesn't do anything with them; its only purpose is to keep spitting out file infos.
Once you have that mechanism then you can start writing queries on top of that sequence to attain the second operation. The third operation then follows directly from the second.
In short, the main line of your program should look something like this:
var allFiles = TraverseFolder(folder);
var filesToDelete = from file in allFiles where IsOld(file) select file;
foreach(var fileToDelete in filesToDelete) Delete(fileToDelete);
Is that clear?
There is almost the same question here:
How to delete all files and folders in a directory?
This is delete by name, but you could check other properties.
Here is a more general solution to the problem which gives you a file system walker implemented non-recursively as IEnumerable.
for which your solution can probably be implemented as:
List<string> directoriesToDelete = new List<string>();
DirectoryWalker walker = new DirectoryWalker(#"C:\pathToSource\src",
dir => {
if (Directory.GetFileSystemEntries(dir).Length == 0) {
directoriesToDelete.Add(dir);
return false;
}
return true;
},
file => {
if (FileIsTooOld(file)) {
return true;
}
return false;
}
);
foreach (string file in walker)
File.Delete(file);
foreach (string dir in directoriesToDelete)
Directory.Delete(dir);
I enhanced John's solution, implementing missing code, error handling and checks:
/* Given a directory path and a datetime,
* recursively delete all files and directories contained in such directory
* (given directory included) that are younger than the given date.
*/
private bool DeleteDirectoryTree(string dir, DateTime keepFilesYoungerThan)
{
//checks
if (String.IsNullOrEmpty(dir) || !Directory.Exists(dir))
return false;
//recurse on children directories
foreach (string childDir in Directory.GetDirectories(dir))
DeleteDirectoryTree(childDir, keepFilesYoungerThan);
//loop on children files
foreach (string file in Directory.GetFiles(dir))
{
//calculate file datetime
DateTime fileDT = new DateTime(Math.Max(File.GetCreationTime(file).Ticks, File.GetLastWriteTime(file).Ticks));
//if file is old, delete it
if (fileDT <= keepFilesYoungerThan)
try
{
File.Delete(file);
Log("Deleted file " + file);
}
catch (Exception e)
{
LogError("Could not delete file " + file + ", cause: " + e.Message);
}
}
//if this directory is empty, delete it
if (!Directory.EnumerateFileSystemEntries(dir).Any())
try
{
Directory.Delete(dir);
Log("Deleted directory " + dir);
}
catch (Exception e)
{
LogError("Could not delete directory " + dir + ", cause: " + e.Message);
}
return true;
}

Categories