I'm trying to iterate over the items on my start menu, but I keep receiving the UnauthorizedAccessException. I'm the directory's owner and my user is an administrator.
Here's my method (it's in a dll project):
// root = C:\Users\Fernando\AppData\Roaming\Microsoft\Windows\Start Menu
private void walkDirectoryTree(DirectoryInfo root) {
try {
FileInfo[] files = root.GetFiles("*.*");
foreach (FileInfo file in files) {
records.Add(new Record {Path = file.FullName});
}
DirectoryInfo[] subDirectories = root.GetDirectories();
foreach (DirectoryInfo subDirectory in subDirectories) {
walkDirectoryTree(subDirectory);
}
} catch (UnauthorizedAccessException e) {
// do some logging stuff
throw; //for debugging
}
}
The code fail when it starts to iterate over the subdirectories. What else should I do? I've already tried to create the manifest file, but it didn't work.
Another point (if is relevant): I'm just running some unit tests with visual studio (which is executed as administrator).
Based on your description, it appears there is a directory to which your user does not have access when running with UAC enabled. There is nothing inherently wrong with your code and the behavior in that situation is by design. There is nothing you can do in your code to get around the fact that your account doesn't have access to those directories in the context it is currently running.
What you'll need to do is account for the directory you don't have access to. The best way is probably by adding a few extension methods. For example
public static FileInfo[] GetFilesSafe(this DirectoryRoot root, string path) {
try {
return root.GetFiles(path);
} catch ( UnauthorizedAccessException ) {
return new FileInfo[0];
}
}
Related
I'm trying to create a program that runs through all the drives on a pc and lists the files.
I have 9 drives in my pc and the program runs fine and lists files on all of them except on the drive from which I'm running the program from. (Doesn't matter which drive.)
I have a recursive function that takes all the files and directories it finds and compiles a list.
The function runs fine on all other drives but for the one from which I'm running the program from it says Could not find file 'D:\CreateFileList.deps.json'. and then crashes into catch() for that drive.
Here's the part of the code that does that.
static void DirSearch(string sDir, string file)
{
try
{
// Get files from root of the drive
if ( firstPass == 1 )
{
foreach (string f in Directory.GetFiles(sDir))
{
if (CheckExclusion(f))
{
WriteToFile(f, file);
}
}
firstPass = 0;
}
// Get files recursively
foreach (string d in Directory.GetDirectories(sDir))
{
if (CheckExclusion(d))
{
foreach (string f in Directory.GetFiles(d))
{
if (CheckExclusion(f))
{
WriteToFile(f, file);
}
}
}
DirSearch(d, file);
}
}
catch (System.Exception excpt)
{
Console.WriteLine(excpt.Message);
}
}
Obviously this file is not at the root of the drive but in the same directory as the .exe file.
Does anyone have any idea what might be wrong? Do I have some settings wrong or includes or what?
You need to look at the actual exception being returned. It will give you a hint as to what is happening.
For example if the OS is throwing UnauthorizedAccessException your process is not running as admin and will not be allowed to look at the directory/files.
You need to handle (catch) each of the exceptions listed at Directory.GetDirectories in your try catch.
By handling all (or just the most likely) exceptions, you will be able to have a working program.
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.
So I've been building a reusable class that will handle recursion and copy directory one, to another directory. The folder structure is:
Root (D:\Arrigotti)
Source (C:\inetpub\wwwroot)
Destination (D:\Arrigotti\Backup)
Archive (D:\Arrigotti\Archive)
Those are the critical areas, for the example code I'm going to leave out some validation / error handling for simplicity sake.
public static class FileSystem
{
public static void CopyDirectory(string source, string destination)
{
DirectoryInfo directory = new DirectoryInfo(source);
DirectoryInfo[] directories = directory.GetDirectories();
foreach(DirectoryInfo dir in directories)
{
Console.WriteLine(#"Found Directory: {0}", dir.FullName);
if(Directory.Exists(Path.Combine(destination, dir.Name)))
{
Console.WriteLine(#"Attempting to write directory...");
Directory.CreateDirectory(Path.Combine(destination, dir.Name));
Console.WriteLine(#"Created Directory: {0}", dir.Name);
}
CopyDirectory(dir.FullName, Path.Combine(destination, dir.Name));
FileInfo[] files = dir.GetFiles();
foreach(FileInfo file in files)
{
Console.WriteLine(#"Found: {0}", file.FullName);
Console.WriteLine(#"Attempting to copy...");
file.CopyTo(Path.Combine(destination, file.Name), true);
}
}
}
}
Which I believe that part is quite accurate and working. However, my problem stems in my call.
public static class Backup
{
public static void Save()
{
string[] drives = Directory.GetLogicalDrives();
foreach(string drive in drives)
{
DriveInfo diagnose = new DriveInfo(drive);
if(diagnose.VolumeLabel == #"Backup" && diagnose.DriveType == DriveType.Fixed)
{
CopyDirectory(
ConfigurationManager.AppSettings[#"Source"],
ConfigurationManager.AppSettings[#"Destination"]);
}
}
}
}
The code is running it looks like smooth sailing at this point, it completes five out of the hundred directories of web-sites it is copying then it randomly throws an exception (I left error handling out, for simplicity but this is the error.)
IOException: The device is not ready.
It randomly stops reading and writing
I'm not entirely sure why this would occur, any advice would be terrific.
I would recommend just using the built-in FileSystem.CopyDirectory method, which handles directory copying properly without custom code.
Using the built in method is definitely more appropriate here
Microsoft.VisualBasic.FileIO.FileSystem.CopyDirectory(source,destination,true);
However, that is not the heart of the issue. The problem is when each drive is inspected. Specifically, the request for .VolumeLabel on the DirectoryInfo. You can read some background on the issue at the MSDN: http://msdn.microsoft.com/en-us/library/system.io.driveinfo.volumelabel(v=vs.110).aspx
What it breaks down to is that if a drive is examined, it has to be ready. Sometimes it is not ready and when it is accessed at that point, you get an exception
IOException - An I/O error occurred (for example, a disk error or a drive was not ready).
To remedy this, make sure that the drive is ready when accessed with diagnose.isReady
public static void Save()
{
string[] drives = Directory.GetLogicalDrives();
foreach(string drive in drives)
{
DriveInfo diagnose = new DriveInfo(drive);
if(diagnose.IsReady && diagnose.VolumeLabel == #"Backup" && diagnose.DriveType == DriveType.Fixed)
^^Make sure the drive is ready before examining properties
{
CopyDirectory(
ConfigurationManager.AppSettings[#"Source"],
ConfigurationManager.AppSettings[#"Destination"]);
}
}
}
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;
}
}
I am writing a Software that can delete Temporary files, Prefetch data, files in Recent folder and so on. My problem is I can delete files from Temp folder successfully, but when I try for Recent folder, an exception is thrown, "Access to path...is denied".
PS: According to some other questions, I have set File attributes to normal, but still no luck. Please help me on this issue. For your better understand, I put some code here:
public Boolean CleanRecentData()
{
isAllClean = true;
String SysRecentPath = System.Environment.GetEnvironmentVariable("USERPROFILE") + "\\Recent";
DirectoryInfo SysRecDir = new DirectoryInfo(SysRecentPath);
File.SetAttributes(SysRecentPath, FileAttributes.Normal);
foreach (FileInfo fi in SysRecDir.GetFiles()) //Access Denied
//Exception is thrown here
{
try
{
fi.Delete();
}
catch (Exception ex)
{
recentLogLines.AppendLine(ex.Message);
isAllClean = false;
}
}
foreach (DirectoryInfo dir in SysRecDir.GetDirectories())
{
try
{
dir.Delete(true);
}
catch (Exception ex)
{
recentLogLines.AppendLine(ex.Message);
isAllClean = false;
}
}
return isAllClean;
}
Are you able to access the Recent folder via Windows Explorer?
You could go ahead and change the permissions in your system, but NOT in your users systems.
Therefore you could handle this exception condition in two ways.
You need to check if you have file access before accessing, using FileIOPermission but this might be redundant and wasteful if you are doing it on too many files.
Just try to open the file and put your effort into a good exception handler if it fails
Reference