diff --git a/FeedBuilder/FileSystemEnumerator.cs b/FeedBuilder/FileSystemEnumerator.cs
index fd7e3877..e47c3eae 100644
--- a/FeedBuilder/FileSystemEnumerator.cs
+++ b/FeedBuilder/FileSystemEnumerator.cs
@@ -1,121 +1,18 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Runtime.ConstrainedExecution;
-using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Text.RegularExpressions;
-using FeedBuilder.Win32;
-using Microsoft.Win32.SafeHandles;
namespace FeedBuilder
{
- namespace Win32
- {
- ///
- /// Structure that maps to WIN32_FIND_DATA
- ///
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
- internal sealed class FindData
- {
- public int fileAttributes;
- public int creationTime_lowDateTime;
- public int creationTime_highDateTime;
- public int lastAccessTime_lowDateTime;
- public int lastAccessTime_highDateTime;
- public int lastWriteTime_lowDateTime;
- public int lastWriteTime_highDateTime;
- public int nFileSizeHigh;
- public int nFileSizeLow;
- public int dwReserved0;
- public int dwReserved1;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
- public String fileName;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
- public String alternateFileName;
- }
-
- ///
- /// SafeHandle class for holding find handles
- ///
- internal sealed class SafeFindHandle : SafeHandleMinusOneIsInvalid
- {
- ///
- /// Constructor
- ///
- public SafeFindHandle() : base(true) { }
-
- ///
- /// Release the find handle
- ///
- /// true if the handle was released
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- protected override bool ReleaseHandle()
- {
- return SafeNativeMethods.FindClose(handle);
- }
- }
-
- ///
- /// Wrapper for P/Invoke methods used by FileSystemEnumerator
- ///
- [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
- internal static class SafeNativeMethods
- {
- [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
- public static extern SafeFindHandle FindFirstFile(String fileName, [In, Out] FindData findFileData);
-
- [DllImport("kernel32", CharSet = CharSet.Auto)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool FindNextFile(SafeFindHandle hFindFile, [In, Out] FindData lpFindFileData);
-
- [DllImport("kernel32", CharSet = CharSet.Auto)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool FindClose(IntPtr hFindFile);
- }
- }
-
///
/// File system enumerator. This class provides an easy to use, efficient mechanism for searching a list of
/// directories for files matching a list of file specifications. The search is done incrementally as matches
/// are consumed, so the overhead before processing the first match is always kept to a minimum.
///
- public sealed class FileSystemEnumerator : IDisposable
+ public sealed class FileSystemEnumerator
{
- ///
- /// Information that's kept in our stack for simulated recursion
- ///
- private struct SearchInfo
- {
- ///
- /// Find handle returned by FindFirstFile
- ///
- public readonly SafeFindHandle Handle;
-
- ///
- /// Path that was searched to yield the find handle.
- ///
- public readonly string Path;
-
- ///
- /// Constructor
- ///
- /// Find handle returned by FindFirstFile.
- /// Path corresponding to find handle.
- public SearchInfo(SafeFindHandle h, string p)
- {
- Handle = h;
- Path = p;
- }
- }
-
- ///
- /// Stack of open scopes. This is a member (instead of a local variable)
- /// to allow Dispose to close any open find handles if the object is disposed
- /// before the enumeration is completed.
- ///
- private readonly Stack m_scopes;
-
///
/// Array of paths to be searched.
///
@@ -131,22 +28,6 @@ public SearchInfo(SafeFindHandle h, string p)
///
private readonly bool m_includeSubDirs;
- #region IDisposable implementation
-
- ///
- /// IDisposable.Dispose
- ///
- public void Dispose()
- {
- while (m_scopes.Count > 0)
- {
- SearchInfo si = m_scopes.Pop();
- si.Handle.Close();
- }
- }
-
- #endregion
-
///
/// Constructor.
///
@@ -155,14 +36,12 @@ public void Dispose()
/// If true, subdirectories are searched.
public FileSystemEnumerator(string pathsToSearch, string fileTypesToMatch, bool includeSubDirs)
{
- m_scopes = new Stack();
-
// check for nulls
if (null == pathsToSearch) throw new ArgumentNullException("pathsToSearch");
if (null == fileTypesToMatch) throw new ArgumentNullException("fileTypesToMatch");
// make sure spec doesn't contain invalid characters
- if (fileTypesToMatch.IndexOfAny(new[] { ':', '<', '>', '/', '\\' }) >= 0) throw new ArgumentException("invalid cahracters in wildcard pattern", "fileTypesToMatch");
+ if (fileTypesToMatch.IndexOfAny(new[] { ':', '<', '>', '/', '\\' }) >= 0) throw new ArgumentException("Invalid characters in wildcard pattern", "fileTypesToMatch");
m_includeSubDirs = includeSubDirs;
m_paths = pathsToSearch.Split(new[] { ';', ',' });
@@ -177,6 +56,36 @@ public FileSystemEnumerator(string pathsToSearch, string fileTypesToMatch, bool
}
}
+ private IEnumerable ProcessFiles(string folderPath)
+ {
+ foreach (var file in Directory.GetFiles(folderPath))
+ {
+ string fileName = Path.GetFileName(file);
+ foreach (Regex fileSpec in m_fileSpecs)
+ {
+ // if this spec matches, return this file's info
+ if (fileSpec.IsMatch(fileName))
+ {
+ yield return new FileInfo(file);
+ break;
+ }
+ }
+ }
+ }
+
+ private IEnumerable ProcessSubdirectories(string folderPath)
+ {
+ // check security - ensure that caller has rights to read this directory
+ new FileIOPermission(FileIOPermissionAccess.PathDiscovery, Path.Combine(folderPath, ".")).Demand();
+ foreach (var d in Directory.GetDirectories(folderPath))
+ {
+ new FileIOPermission(FileIOPermissionAccess.PathDiscovery, Path.Combine(d, ".")).Demand();
+ yield return d;
+ foreach (var sd in ProcessSubdirectories(d))
+ yield return sd;
+ }
+ }
+
///
/// Get an enumerator that returns all of the files that match the wildcards that
/// are in any of the directories to be searched.
@@ -192,71 +101,23 @@ public IEnumerable Matches()
{
string path = rootPath.Trim();
- // we "recurse" into a new directory by jumping to this spot
- top:
-
// check security - ensure that caller has rights to read this directory
new FileIOPermission(FileIOPermissionAccess.PathDiscovery, Path.Combine(path, ".")).Demand();
- // now that security is checked, go read the directory
- FindData findData = new FindData();
- SafeFindHandle handle = SafeNativeMethods.FindFirstFile(Path.Combine(path, "*"), findData);
- m_scopes.Push(new SearchInfo(handle, path));
- bool restart = false;
+ foreach (var fi in ProcessFiles(path))
+ yield return fi;
- // we "return" from a sub-directory by jumping to this spot
- restart:
- // ReSharper disable InvertIf
- if (!handle.IsInvalid)
+ if (m_includeSubDirs)
{
- // ReSharper restore InvertIf
- do
- {
- // if we restarted the loop (unwound a recursion), fetch the next match
- if (restart)
- {
- restart = false;
- continue;
- }
- // don't match . or ..
- if (findData.fileName.Equals(@".") || findData.fileName.Equals(@"..")) continue;
-
- if ((findData.fileAttributes & (int)FileAttributes.Directory) != 0)
- {
- if (m_includeSubDirs)
- {
- // it's a directory - recurse into it
- path = Path.Combine(path, findData.fileName);
- goto top;
- }
- }
- else
- {
- // it's a file, see if any of the filespecs matches it
- foreach (Regex fileSpec in m_fileSpecs)
- {
- // if this spec matches, return this file's info
- if (fileSpec.IsMatch(findData.fileName)) yield return new FileInfo(Path.Combine(path, findData.fileName));
- }
- }
- } while (SafeNativeMethods.FindNextFile(handle, findData));
-
- // close this find handle
- handle.Close();
-
- // unwind the stack - are we still in a recursion?
- m_scopes.Pop();
- if (m_scopes.Count > 0)
+ foreach (var d in ProcessSubdirectories(path))
{
- SearchInfo si = m_scopes.Peek();
- handle = si.Handle;
- path = si.Path;
- restart = true;
- goto restart;
+ foreach (var fi in ProcessFiles(d))
+ yield return fi;
}
}
}
}
}
}
+