System.IO.IOException when searching UNC path.
Closed this issue · 10 comments
Your code looks very impressive and I am trying to incorporate it, but I seem to have hit a snag with searching a UNC path. The code works great on the local file system, but I get the below error when using a UNC path. Any thoughts on how to avoid this?
My code:
try
{
List<FileInfo> files = FileSearcher.GetFilesFast(path, pattern);
foreach (FileInfo File in files)
{
Console.WriteLine("{0}", File.FullName);
}
}
catch (IOException) { }
The error:
C:\Users\dso\source\repos\SharpDir\SharpDir\bin\Debug>SharpDir.exe \\10.10.10.10\c$\ notepad.exe
Unhandled Exception: System.AggregateException: One or more errors occurred. ---> System.IO.IOException: The symbolic link cannot be followed because its type is disabled.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileSystemEnumerableIterator`1.CommonInit()
at System.IO.FileSystemEnumerableIterator`1..ctor(String path, String originalUserPath, String searchPattern, SearchOption searchOption, SearchResultHandler`1 resultHandler, Boolean checkHost)
at System.IO.DirectoryInfo.InternalGetDirectories(String searchPattern, SearchOption searchOption)
at System.IO.DirectoryInfo.GetDirectories()
at FastSearchLibrary.FileSearcher.GetFiles(String folder, String pattern)
at FastSearchLibrary.FileSearcher.<>c__DisplayClass31_0.<GetFilesFast>b__1(DirectoryInfo dir)
at System.Linq.Parallel.ForAllOperator`1.ForAllEnumerator`1.MoveNext(TInput& currentElement, Int32& currentKey)
at System.Linq.Parallel.ForAllSpoolingTask`2.SpoolingWork()
at System.Linq.Parallel.SpoolingTaskBase.Work()
at System.Linq.Parallel.QueryTask.BaseWork(Object unused)
at System.Linq.Parallel.QueryTask.<>c.<.cctor>b__10_0(Object o)
at System.Threading.Tasks.Task.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
--- End of inner exception stack trace ---
at System.Linq.Parallel.QueryTaskGroupState.QueryEnd(Boolean userInitiatedDispose)
at System.Linq.Parallel.SpoolingTask.SpoolForAll[TInputOutput,TIgnoreKey](QueryTaskGroupState groupState, PartitionedStream`2 partitions, TaskScheduler taskScheduler)
at System.Linq.Parallel.DefaultMergeHelper`2.System.Linq.Parallel.IMergeHelper<TInputOutput>.Execute()
at System.Linq.Parallel.MergeExecutor`1.Execute()
at System.Linq.Parallel.MergeExecutor`1.Execute[TKey](PartitionedStream`2 partitions, Boolean ignoreOutput, ParallelMergeOptions options, TaskScheduler taskScheduler, Boolean isOrdered, CancellationState cancellationState, Int32 queryId)
at System.Linq.Parallel.PartitionedStreamMerger`1.Receive[TKey](PartitionedStream`2 partitionedStream)
at System.Linq.Parallel.ForAllOperator`1.WrapPartitionedStream[TKey](PartitionedStream`2 inputStream, IPartitionedStreamRecipient`1 recipient, Boolean preferStriping, QuerySettings settings)
at System.Linq.Parallel.UnaryQueryOperator`2.UnaryQueryOperatorResults.ChildResultsRecipient.Receive[TKey](PartitionedStream`2 inputStream)
at System.Linq.Parallel.ListQueryResults`1.GivePartitionedStream(IPartitionedStreamRecipient`1 recipient)
at System.Linq.Parallel.UnaryQueryOperator`2.UnaryQueryOperatorResults.GivePartitionedStream(IPartitionedStreamRecipient`1 recipient)
at System.Linq.Parallel.QueryOperator`1.GetOpenedEnumerator(Nullable`1 mergeOptions, Boolean suppressOrder, Boolean forEffect, QuerySettings querySettings)
at System.Linq.Parallel.ForAllOperator`1.RunSynchronously()
at System.Linq.ParallelEnumerable.ForAll[TSource](ParallelQuery`1 source, Action`1 action)
at FastSearchLibrary.FileSearcher.GetFilesFast(String folder, String pattern)
at SharpDir.Main(String[] args) in C:\Users\dso\source\repos\SharpDir\SharpDir\SharpDir.cs:line 26
Hello.
Thank you for good estimation. I'm glad that my work wasn't in vain.
I have tested this library only on local computer.
Search alghoritm uses .NET Framework GetFiles() method of DirectoryInfo class.
Most probably, problem is connected with it.
I was searching possible reason and its solution a little and that is what I have found: https://stackoverflow.com/questions/35510378/get-files-using-unc-path
https://stackoverflow.com/questions/2352197/how-do-i-access-a-network-drive-through-the-usual-system-io-classes
I suppose that problem consists in backslashes in path. You probably should experiment with them a little.
The code connects just fine and begins searching but dies when it gets to "Documents and Settings".
If problem is in .NET Framework classes, most probably we will not be able to do anything as library is based on them. Therefore, it is necessary to check it.
So try to launch this code to determine whether you get any errors:
string path = "Documents and Settings"; // Path where you get this error
DirectoryInfo dirInfo = new DirectoryInfo(path);
FileInfo[] files = dirInfo.GetFiles("*", SearchOption.AllDirectories);
Yep, it dies on "\10.10.10.10\c$\Documents and Settings" as I expected, but works great on "\10.10.10.10\c$\Python27".
C:\Users\dso\source\repos\SharpDir\SharpDir\bin\Release>SharpDir.exe
Unhandled Exception: System.UnauthorizedAccessException: Access to the path '\\10.10.10.10\c$\Documents and Settings' is denied.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileSystemEnumerableIterator`1.CommonInit()
at System.IO.FileSystemEnumerableIterator`1..ctor(String path, String originalUserPath, String searchPattern, SearchOption searchOption, SearchResultHandler`1 resultHandler, Boolean checkHost)
at System.IO.DirectoryInfo.InternalGetFiles(String searchPattern, SearchOption searchOption)
at System.IO.DirectoryInfo.GetFiles(String searchPattern, SearchOption searchOption)
at SharpDir.Main(String[] args) in C:\Users\dso\source\repos\SharpDir\SharpDir\SharpDir.cs:line 33
C:\Users\dso\source\repos\SharpDir\SharpDir\bin\Release>SharpDir.exe
\\10.10.10.10\c$\Python27\Lib\site-packages\easy_install.py
\\10.10.10.10\c$\Python27\Lib\site-packages\easy_install.pyc
\\10.10.10.10\c$\Python27\Lib\site-packages\ipaddress.py
\\10.10.10.10\c$\Python27\Lib\site-packages\ipaddress.pyc
\\10.10.10.10\c$\Python27\Lib\site-packages\six.py
\\10.10.10.10\c$\Python27\Lib\site-packages\six.pyc
\\10.10.10.10\c$\Python27\Lib\site-packages\_cffi_backend.pyd
\\10.10.10.10\c$\Python27\Lib\site-packages\asn1crypto\algos.py
\\10.10.10.10\c$\Python27\Lib\site-packages\asn1crypto\algos.pyc
</snip>
Yes, standard means of .NET Framework don't allow to suppress UnauthorizedAccessException, but this library does.
Could you try to check this method? As it processes UnauthorizedAccessException, we can figure out what real exception is. And what is target .NET Framework version in your program?
static public List<FileInfo> GetFiles(string folder, string pattern = "*")
{
DirectoryInfo dirInfo = null;
DirectoryInfo[] directories = null;
try
{
dirInfo = new DirectoryInfo(folder);
directories = dirInfo.GetDirectories();
if (directories.Length == 0)
return new List<FileInfo>(dirInfo.GetFiles(pattern));
}
catch (UnauthorizedAccessException ex)
{
return new List<FileInfo>();
}
catch (DirectoryNotFoundException ex)
{
return new List<FileInfo>();
}
List<FileInfo> result = new List<FileInfo>();
foreach (var d in directories)
{
result.AddRange(GetFiles(d.FullName, pattern));
}
try
{
result.AddRange(dirInfo.GetFiles(pattern));
}
catch (UnauthorizedAccessException ex)
{
}
catch (PathTooLongException ex)
{
}
catch (DirectoryNotFoundException ex)
{
}
return result;
}
// using:
string path = "<path>";
List<FileInfo> result = GetFiles(path);
Symbolic link error when the code gets to "Documents and Settings" during its loop.
C:\Users\dso\source\repos\SharpDir\SharpDir\bin\Debug>SharpDir.exe \\10.10.10.10\C$ notepad.exe
Unhandled Exception: System.IO.IOException: The symbolic link cannot be followed because its type is disabled.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileSystemEnumerableIterator`1.CommonInit()
at System.IO.FileSystemEnumerableIterator`1..ctor(String path, String originalUserPath, String searchPattern, SearchOption searchOption, SearchResultHandler`1 resultHandler, Boolean checkHost)
at System.IO.DirectoryInfo.InternalGetDirectories(String searchPattern, SearchOption searchOption)
at System.IO.DirectoryInfo.GetDirectories()
at SharpDir.GetFiles(String folder, String pattern) in C:\Users\dso\source\repos\SharpDir\SharpDir\SharpDir.cs:line 60
at SharpDir.GetFiles(String folder, String pattern) in C:\Users\dso\source\repos\SharpDir\SharpDir\SharpDir.cs:line 78
at SharpDir.GetFiles(String folder, String pattern) in C:\Users\dso\source\repos\SharpDir\SharpDir\SharpDir.cs:line 78
at SharpDir.Main(String[] args) in C:\Users\dso\source\repos\SharpDir\SharpDir\SharpDir.cs:line 32
Direct access of the "Documents and Settings" folder results in no error being returned.
C:\Users\dso\source\repos\SharpDir\SharpDir\bin\Debug>SharpDir.exe "\\10.10.10.10\c$\Documents and Settings" notepad.exe
Accessing the python folder directly works as expected.
C:\Users\dso\source\repos\SharpDir\SharpDir\bin\Debug>SharpDir.exe "\\10.10.10.10\c$\Python27" scapy.1
\\10.10.10.10\c$\Python27\share\man\man1\scapy.1
I guess you may either to read what symbolic links are and how to enable them or use code that will suppress all IO exceptions.
About first variant, it is one of link I found on this topic: https://blogs.msdn.microsoft.com/junfeng/2012/05/07/the-symbolic-link-cannot-be-followed-because-its-type-is-disabled
But if you do not want to delve into all the details we can use the second way. As you understand, it is complicated to add processing of IOException to each place where it can arise. So, as I consider, more expedient to extract all code you use and add exception processing to it.
As I noticed, you used static method FileSearcher.GetFilesFast(),
so I extracted all its code with appropriate dependencies and added IOException processing. If you use only static method that gets conventional pattern, not delegate, it will be enough.
public static List<FileInfo> GetFiles(string folder, string pattern = "*")
{
DirectoryInfo dirInfo = null;
DirectoryInfo[] directories = null;
try
{
dirInfo = new DirectoryInfo(folder);
directories = dirInfo.GetDirectories();
if (directories.Length == 0)
return new List<FileInfo>(dirInfo.GetFiles(pattern));
}
catch (UnauthorizedAccessException ex)
{
return new List<FileInfo>();
}
catch (DirectoryNotFoundException ex)
{
return new List<FileInfo>();
}
List<FileInfo> result = new List<FileInfo>();
foreach (var d in directories)
{
result.AddRange(GetFiles(d.FullName, pattern));
}
try
{
result.AddRange(dirInfo.GetFiles(pattern));
}
catch (UnauthorizedAccessException ex)
{
}
catch (PathTooLongException ex)
{
}
catch (IOException ex)
{
}
return result;
}
public static List<DirectoryInfo> GetStartDirectories(string folder, ConcurrentBag<FileInfo> files, string pattern)
{
DirectoryInfo dirInfo = null;
DirectoryInfo[] directories = null;
try
{
dirInfo = new DirectoryInfo(folder);
directories = dirInfo.GetDirectories();
foreach (var f in dirInfo.GetFiles(pattern))
{
files.Add(f);
}
if (directories.Length > 1)
return new List<DirectoryInfo>(directories);
if (directories.Length == 0)
return new List<DirectoryInfo>();
}
catch (UnauthorizedAccessException ex)
{
return new List<DirectoryInfo>();
}
catch (PathTooLongException ex)
{
return new List<DirectoryInfo>();
}
catch (IOException ex)
{
return new List<DirectoryInfo>();
}
return GetStartDirectories(directories[0].FullName, files, pattern);
}
public static List<FileInfo> GetFilesFast(string folder, string pattern = "*")
{
ConcurrentBag<FileInfo> files = new ConcurrentBag<FileInfo>();
List<DirectoryInfo> startDirs = GetStartDirectories(folder, files, pattern);
startDirs.AsParallel().ForAll((d) =>
{
GetStartDirectories(d.FullName, files, pattern).AsParallel().ForAll((dir) =>
{
GetFiles(dir.FullName, pattern).ForEach((f) => files.Add(f));
});
});
return files.ToList();
}
//using
List<FileInfo> files = GetFilesFast("<path>", "<pattern>");
Awesome, your code worked!!! Thanks for all the help!
You are welcome.
I think, if you need any other functionality of library, you can download source code and replace string catch (DirectoryNotFoundException ex)
on catch (IOException ex)
in all places in all files. It's possible to use IDE or some advanced text editor for this purpose. Then you need to compile source code and you will get your unique version of library.
But currently, code, that I placed above, will work without library.
Great thanks! I really appreciate your help!