trying to write a small windows application for my company. the part i am stuck at the moment is trying to search the computer for ".myox" files (or say any file type). Below pasted is the code i have worked out. I am an amateur programmer trying to get started with coding. The issue am having at the moment with the code below is its skipping almost all locations on the computer with the exception coming up as "access denied". I have run the VS as admin, and i am an admin on the computer as well. Not sure what i am missing, but if someone can point me in the right direction, that would be amazing.
private void FindAllFiles()
{
int drvCount;
int drvSearchCount = 0;
DriveInfo[] allDrives = DriveInfo.GetDrives();
drvCount = allDrives.Count();
foreach (DriveInfo dr in allDrives)
{
lbAllFiles.Items.Clear();
drvSearchCount++;
//removable drives
if (!dr.IsReady)
break;
foreach (string dir in Directory.GetDirectories(dr.ToString()))
{
try
{
foreach (string files in Directory.GetFiles(dir, "*.myox"))
{
lbAllFiles.Items.Add(files);
}
}
catch (Exception Error)
{
}
}
if (drvSearchCount == drvCount)
break;
}
MessageBox.Show("Done searching your computer");
}
Thanks in Advance.
-Manu
I see few "potential" issues and will list them below.
First is that you're doing this on main ( UI ) thread which will block whole application giving you no feedback about current state. You can use Thread to get rid of this problem. Outcome from this operation will produce another issue which is accessing lbAllFiles because ( as i think ) it's part of the UI. You can easily get rid of this problem making a List<string> that can be filled during FindAllFiles operation and then assigned into lbAllFiles.Items.
Second issue is :
foreach (string files in Directory.GetFiles(dir, "*.myox"))
{
lbAllFiles.Items.Add(files);
}
Directory.GetFiles(...) will return only the files that are matching your pattern parameter so you can simply do :
var files = Directory.GetFiles(dir, "*.myox");
if ( files != null && files.Length > 0 )
lblAllFiles.Items.AddRange(files);
And finaly to get ( or check ) permission you can Demand() permissions as I've posted in the comment :
foreach (string dir in Directory.GetDirectories(dr.ToString()))
{
FileIOPermission permission = new FileIOPermission(FileIOPermissionAccess.Read, dir);
try
{
permission.Demand();
var files = Directory.GetFiles(dir, "*.myox");
if ( files != null && files.Length > 0 )
lblAllFiles.Items.AddRange(files);
}
catch (Exception Error)
{
}
}
Let me know if that helped you. If not I'll try to update my answer with another solution.
One thing i noticed in your code, is that you're not navigating through ALL directories and sub-directories. For that, where you call the GetDirectories function, not only send the path, but use the enumerator Alldirectories:
foreach (string dir in Directory.GetDirectories(dr.ToString(),System.IO.SearchOption.AllDirectories))
Related
I'm writing a simple desktop application to copy files from one PC to another. Having trouble with the Windows 10 reparse points, specifically My Music. I thought was going to get away with one simple line of code:
ZipFile.CreateFromDirectory(documentsFolder, docSavePath + #"\Documents.zip", CompressionLevel.Optimal, false);
But not so, it crashes on the My Music folder. I've also tried a bunch of different ways of doing this, all with the same result - access denied. Can copying and/or zipping the Documents folder really be this hard? I doubt it, I'm just missing something. I tried elevating privileges and that didn't work, either. Anyone have an example of how to do this?
I was able figure out how to check for the ReparsePoint attribute, which was relatively easy, but then had to piece together how to loop through all the files and add them to the ZipArchive. The credit for the RecurseDirectory goes to this answer.
Then I added in what I learned about the reparse file attributes.
private void documentBackup(string docSavePath)
{
if (File.Exists(docSavePath + #"\Documents.zip")) File.Delete(docSavePath + #"\Documents.zip");
using (ZipArchive docZip = ZipFile.Open(docSavePath + "\\Documents.zip", ZipArchiveMode.Create))
{
foreach (FileInfo goodFile in RecurseDirectory(documentsFolder))
{
var destination = Path.Combine(goodFile.DirectoryName, goodFile.Name).Substring(documentsFolder.ToString().Length + 1);
docZip.CreateEntryFromFile(Path.Combine(goodFile.Directory.ToString(), goodFile.Name), destination);
}
}
}
public IEnumerable<FileInfo> RecurseDirectory(string path, List<FileInfo> currentData = null)
{
if (currentData == null)
currentData = new List<FileInfo>();
var directory = new DirectoryInfo(path);
foreach (var file in directory.GetFiles())
currentData.Add(file);
foreach (var d in directory.GetDirectories())
{
if ((d.Attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint)
{
continue;
}
else
{
RecurseDirectory(d.FullName, currentData);
}
}
return currentData;
}
It takes longer than I'd like to run - but after looking at this dang problem for days I'm just happy it works!
I am currently writing a program in C# that will copy all user profile files to an external device (in this case, my home server).
When my code iterates through my files and folders, it throws an UnauthorizedAccessException.
I have Googled this and searched StackOverflow, but I am unable to find a clear solution that doesn't involve terminating my process. The idea is that it should copy the files and folders that have read permissions.
I had this when I first started, but I easily fixed it by limiting what directories I would backup (though I would prefer a full backup).
Here is my code:
FileInfo f = new FileInfo(_configuration.Destination);
if (!f.Directory.Exists)
{
f.Directory.Create();
}
string[] backupDirectories = new string[]
{
"Desktop",
"Documents",
"Downloads",
"Favorites",
"Links",
"Pictures",
"Saved Games",
"Searches",
"Videos",
".git",
".android",
".IdealC15",
".nuget",
".oracle_jre_usage",
".vs",
"Contacts"
};
foreach (string dirPath in backupDirectories)
{
DirectoryInfo dirInfo = new DirectoryInfo(_path + "\\" + dirPath);
if (dirInfo.Exists)
{
foreach (string dirP in Directory.GetDirectories(dirInfo.FullName, "*", SearchOption.AllDirectories))
{
DirectoryInfo dirI = new DirectoryInfo(dirP);
if (dirI.Exists)
{
string dir = dirP.Replace(_path, _configuration.Destination);
try
{
Directory.CreateDirectory(dir);
textBox2.Invoke((MethodInvoker) delegate
{
textBox2.AppendText("Create Directory: " + dir + Environment.NewLine);
});
} catch (Exception e)
{
textBox2.Invoke((MethodInvoker) delegate
{
textBox2.AppendText("Could NOT Create Directory: " + dir + Environment.NewLine);
});
continue;
}
foreach (FileInfo theFile in dirInfo.GetFiles("*", SearchOption.AllDirectories))
{
string newPath = theFile.FullName;
string file = newPath.Replace(_path, _configuration.Destination);
try
{
File.Copy(newPath, file, true);
textBox2.Invoke((MethodInvoker) delegate
{
textBox2.AppendText("Create File: " + file + Environment.NewLine);
});
} catch (Exception ex)
{
textBox2.Invoke((MethodInvoker) delegate
{
textBox2.AppendText("Could NOT Create File: " + file + Environment.NewLine);
});
}
}
}
}
}
}
I apologise if the code is messy, but I will describe sort of what it is doing. The first bit checks if the backup folder exists on the external drive.
The second part says what folders I need to backup (if you're able to fix this and make it backup all directories with permissions, please help me in doing so).
The first loop starts the iteration for each of the backupDirectories. The second loop starts the iteration for each of the directories in the backup directory. The third loop starts the iteration for each of the folders in the backup directory.
The exception is thrown at Directory.GetDirectories(dirInfo.FullName, "*", SearchOption.AllDirectories), and it is trying to access C:\Users\MyName\Documents\My Music. Attempting to access it in explorer does give me a permissions error, though it isn't listed in explorer when I try going to "Documents" (I am in Windows 10 Pro).
As I recommended, since the Operating System authority is higher than the application, it is likely that you cannot do more than what the Operating System would allow you to do (that is to access or not to access certain folder).
Thus, folders' accessibility is best solved in the Operating System level.
But you could still do two things in the program level to minimize the damage when you search for the items.
To use Directory.AccessControl to know the access level of a directory before you do any query on it. This is not so easy, and there are elaborated answers about this here and also here.
To minimize the damage made by unauthorized access issues by using SearchOption.TopDirectoryOnly instead of SearchOption.AllDirectories, combined with recursive search for all the accessible directories. This is how you can code it
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
}
}
The function above minimize the damage caused by the unauthorized access only to the sub-directories which have the issue. All other accessible directories can be returned.
The folder C:\Users contain 3 subfolders :
C:\Users\hacen
C:\Users\_rafi_000
C:\Users\Public
However, when I call :
DirSearch(#"C:\Users\", "*.jpg");
It outputs all jpg filenames from Public and hacen, but not from _rafi_000 which is the folder of current user.
Here is the function :
static void DirSearch(string dir, string pattern)
{
try
{
foreach (string f in Directory.GetFiles(dir, pattern))
{
Console.WriteLine(f);
}
foreach (string d in Directory.GetDirectories(dir))
{
DirSearch(d, pattern);
}
}
catch (System.Exception ex)
{
//MessageBox.Show(ex.Message);
}
}
EDIT:
I tried with the code below and it works. So it isn't an access denied problem :
DirSearch("C:\Users\_rafi_000\","*.jpg");
What I noticed so far is that unlike other subfolders, the folder _rafi_000 cannot be ranamed when I press F2
Would this work?
void DirSearch(string dir, "*.JPG")
{
foreach (string f in Directory.GetFiles(dir, "*.JPG"))
{
Console.WriteLine(f);
}
foreach (string d in Directory.GetDirectories(dir))
{
DirSearch(d);
}
}
Could be related to where the jpg are stored and how reparse points work in later windows version.
I suggest looking at:
Directory Searching: http://msdn.microsoft.com/en-us/library/bb513869.aspx
Reparse Point Info: http://msdn.microsoft.com/en-us/library/aa365503(VS.85).aspx
I ran your code and it works fine in windows XP:
C:\Users\hacen\bar.jpg
C:\Users\Public\bar1.jpg
C:\Users\_rafi_000\bar2.jpg
Your code is correct.
Perhaps Process Monitor can help?
If the code is fine, it must be something else. I understand that you can run the code directly against the directory which is causing you a problem (which is surprising) - but I think Process Mon could help.
I am currently developing a C# application to search a file in the computer. The GUI has two text fields: one for input(the name for the file to be searched) and one for displaying the path to the file (if it's found).
Now, the problem is that my application is skipping my logical C: drive. Here is some piece of code:
foreach (string s in Directory.GetLogicalDrives() )
{
if (list.Count == 0)
{
foreach (string f in Directory.GetFiles(s, file))
{
textBox2.Text = f;
list.Add(f);
}
if (list.Count == 0)
{
search(s);
}
}
}
And the search method:
private void search(string sDir)
{
try
{
foreach (string d in Directory.GetDirectories(sDir))
{
if (list.Count == 0)
{
Console.WriteLine(d);
foreach (string f in Directory.GetFiles(d, file))
{
textBox2.Text = f;
list.Add(f);
}
if (list.Count == 0)
{
search(d);
}
}
}
}
catch (System.Exception excpt)
{
Console.WriteLine(excpt.Message);
}
}
Here is some output:
C:\$Recycle.Bin
C:\$Recycle.Bin\S-1-5-21-1794489696-3002174507-1726058468-1000
C:\Config.Msi
C:\de cautat
C:\de cautat\database
C:\de cautat\fut_bot
C:\de cautat\helper
C:\de cautat\images
C:\de cautat\itemiinfo
C:\de cautat\JSONs
C:\de cautat\JSONs\PLAYER
C:\de cautat\JSONs\USER
C:\de cautat\requests
C:\Documents and Settings
A first chance exception of type 'System.UnauthorizedAccessException' occurred in mscorlib.dll
Access to the path 'C:\Documents and Settings' is denied.
D:\$RECYCLE.BIN
D:\$RECYCLE.BIN\S-1-5-21-1794489696-3002174507-1726058468-1000
D:\$RECYCLE.BIN\S-1-5-21-2637989945-465084399-3498881169-1000
etc
Can anyone help me and tell what is the problem when accesing those folders? Thanks!
Note: I am using Microsoft Visual Studio 2010 on Windows 7 x64 (.NET Framework 2.0).
The problem is you are hitting a folder you do not have read privileges to. You will need to either run your program as administrator or will need to have it skip over files and folders you do not have read rights to. Using Directory.EnumerateFiles will let you simplify your code and it should not try to open folders it does not have read rights to.
foreach (string s in Directory.GetLogicalDrives())
{
if (list.Count == 0)
{
foreach (string f in Directory.EnumerateFiles(s, file, SerchOption.AllDirectories))
{
try
{
textBox2.Text = f;
list.Add(f);
}
catch (System.Exception excpt)
{
Console.WriteLine(excpt.Message);
}
}
}
}
Move your try catch into the foreach (string d in Directory.GetDirectories(sDir)) loop so it continues to process on error.
I know it's an old thread, but it ranked quite high in Google, so I thought I would clarify a free things for others that stumble across it..
First of all: the programme cannot access C:\Documents and Settings because it doesn't exist on a windows 7. It's a symbolic link without any actual content except a pointer. But the programme doesn't know that since it sees it as a regular directory. That is why it fails...
I would wrap the whole thing in a try, catch (without any action in the catch part)..
Hope it helps someone from trying any of the proposed answers..
My function is pretty much a standard search function... I've included it below.
In the function I have 1 line of code responsible for weeding out Repart NTFS points.
if (attributes.ToString().IndexOf("ReparsePoint") == -1)
The problem is now I am getting an error
Access to the path 'c:\System Volume Information' is denied.
I debugged the code and the only attributes at run time for this directory are :
System.IO.FileAttributes.Hidden
| System.IO.FileAttributes.System
| System.IO.FileAttributes.Directory
I'm executing this code on a windows 2008 server machine, any ideas what I can do to cure this failing?
public void DirSearch(string sDir)
{
foreach (string d in Directory.GetDirectories(sDir))
{
DirectoryInfo dInfo = new DirectoryInfo(d);
FileAttributes attributes = dInfo.Attributes;
if (attributes.ToString().IndexOf("ReparsePoint") == -1)
{
foreach (string f in Directory.GetFiles(d, searchString))
{
//lstFilesFound.Items.Add(f);
ListViewItem lvi;
ListViewItem.ListViewSubItem lvsi;
lvi = new ListViewItem();
lvi.Text = f;
lvi.ImageIndex = 1;
lvi.Tag = "tag";
lvsi = new ListViewItem.ListViewSubItem();
lvsi.Text = "sub bugger";
lvi.SubItems.Add(lvsi);
lvsi = new ListViewItem.ListViewSubItem();
lvsi.Text = d;//"C:\\Users\\Administrator\\Downloads\\MediaMonkey.GOLD.EDITION.v.3.0.2.1134.[Darkside].[Demonoid].[Grim.Reaper]";
lvi.SubItems.Add(lvsi);
listView1.Items.Add(lvi);
}
DirSearch(d);
}
}
}
I'm not sure what the answer to the question is, but please change your attribute check to use proper bitwise operations!
if (attributes.ToString().IndexOf("ReparsePoint") == -1)
... is much more correctly written as ...
if ((attributes & FileAttributes.ReparsePoint) == 0)
Nobody has permission to access System Volume Information except the SYSTEM account. So either change the permissions on the directory. Or much, much better catch the exception and go on.
Once you get past permissions, and really want to test for junction points, this class provides testing for, creating and deleting of junction points through the use of DeviceIoControl kernel32 call and analysis of the reparse point.