2009-11-22 Miguel de Icaza <miguel@novell.com>
authorMiguel de Icaza <miguel@gnome.org>
Mon, 23 Nov 2009 03:44:51 +0000 (03:44 -0000)
committerMiguel de Icaza <miguel@gnome.org>
Mon, 23 Nov 2009 03:44:51 +0000 (03:44 -0000)
* Directory.cs: Added new IEnumerable methods to Directory.

* MonoIO.cs: Surface a high level FindFirst/FindNext API to
implement the various enumerable APIs.

svn path=/trunk/mcs/; revision=146698

mcs/class/corlib/System.IO/ChangeLog
mcs/class/corlib/System.IO/Directory.cs
mcs/class/corlib/System.IO/MonoIO.cs

index 047276e40a81404ec0ee427d1af913b75d760354..31ab45d4a8258cec3464d413437f0a5422f11e4a 100644 (file)
@@ -1,3 +1,10 @@
+2009-11-22  Miguel de Icaza  <miguel@novell.com>
+
+       * Directory.cs: Added new IEnumerable methods to Directory.
+
+       * MonoIO.cs: Surface a high level FindFirst/FindNext API to
+       implement the various enumerable APIs.
+
 2009-11-13  Marek Safar <marek.safar@gmail.com>
 
        * UnmanagedMemoryAccessor.cs: Finished.
index 15d9215734ef4db4290552e987757a57b615d28b..24c695b64f53406be8d4981250dc9e0e1857fda8 100644 (file)
@@ -467,14 +467,12 @@ namespace System.IO
                                throw new ArgumentException ("Path contains invalid chars");
                }
 
-               private static string [] GetFileSystemEntries (string path, string searchPattern, FileAttributes mask, FileAttributes attrs)
+               // Does the common validation, searchPattern has already been checked for not-null
+               static string ValidateDirectoryListing (string path, string searchPattern, out bool stop)
                {
-                       if (path == null || searchPattern == null)
-                               throw new ArgumentNullException ();
+                       if (path == null)
+                               throw new ArgumentNullException ("path");
 
-                       if (searchPattern.Length == 0)
-                               return new string [] {};
-                       
                        if (path.Trim ().Length == 0)
                                throw new ArgumentException ("The Path does not have a valid format");
 
@@ -495,7 +493,8 @@ namespace System.IO
                                if (error == MonoIOError.ERROR_SUCCESS) {
                                        MonoIOError file_error;
                                        if (MonoIO.ExistsFile (wildpath, out file_error)) {
-                                               return new string [] { wildpath };
+                                               stop = true;
+                                               return wildpath;
                                        }
                                }
 
@@ -511,14 +510,86 @@ namespace System.IO
                                throw new ArgumentException ("Path is invalid", "path");
                        }
 
-                       string path_with_pattern = Path.Combine (wildpath, searchPattern);
+                       stop = false;
+                       return Path.Combine (wildpath, searchPattern);
+               }
+               
+               private static string [] GetFileSystemEntries (string path, string searchPattern, FileAttributes mask, FileAttributes attrs)
+               {
+                       if (searchPattern == null)
+                               throw new ArgumentNullException ("searchPattern");
+                       if (searchPattern.Length == 0)
+                               return new string [] {};
+                       bool stop;
+                       string path_with_pattern = ValidateDirectoryListing (path, searchPattern, out stop);
+                       if (stop)
+                               return new string [] { path_with_pattern };
+
+                       MonoIOError error;
                        string [] result = MonoIO.GetFileSystemEntries (path, path_with_pattern, (int) attrs, (int) mask, out error);
                        if (error != 0)
-                               throw MonoIO.GetException (wildpath, error);
+                               throw MonoIO.GetException (Path.GetDirectoryName (Path.Combine (path, searchPattern)), error);
                        
                        return result;
                }
 
+#if NET_4_0
+               public static System.Collections.Generic.IEnumerable<string> EnumerateDirectories(string path, string searchPattern, SearchOption searchOption)
+               {
+                       if (searchPattern == null)
+                               throw new ArgumentNullException ("searchPattern");
+
+                       if (searchPattern.Length == 0)
+                               yield break;
+
+                       if (searchOption != SearchOption.TopDirectoryOnly && searchOption != SearchOption.AllDirectories)
+                               throw new ArgumentOutOfRangeException ("searchoption");
+
+                       bool stop;
+                       string path_with_pattern = ValidateDirectoryListing (path, searchPattern, out stop);
+                       if (stop){
+                               yield return path_with_pattern;
+                               yield break;
+                       }
+                       
+                       IntPtr handle;
+                       int error;
+
+                       // Do not follow symlinks (ReparsePoint), need to check if Windows has different semantics
+                       // the loop is possible, but not sure if the MS version deals with this:
+                       // http://blogs.msdn.com/oldnewthing/archive/2004/12/27/332704.aspx
+                       
+                       string s = MonoIO.FindFirst (path, path_with_pattern, (int) FileAttributes.Directory, (int) (FileAttributes.Directory|FileAttributes.ReparsePoint), out error, out handle);
+                       if (s == null)
+                               yield break;
+                       if (error != 0)
+                               throw MonoIO.GetException (Path.GetDirectoryName (Path.Combine (path, searchPattern)), (MonoIOError) error);
+
+                       try {
+                               yield return s;
+                               
+                               while ((s = MonoIO.FindNext (handle, out error)) != null){
+                                       yield return s;
+                                       if (searchOption == SearchOption.AllDirectories)
+                                               foreach (string child in EnumerateDirectories (s, searchPattern, SearchOption.AllDirectories))
+                                                       yield return child;
+                               }
+                       } finally {
+                               MonoIO.FindClose (handle);
+                       }
+               }
+
+               public static System.Collections.Generic.IEnumerable<string> EnumerateDirectories (string path, string searchPattern)
+               {
+                       return EnumerateDirectories (path, searchPattern, SearchOption.TopDirectoryOnly);
+               }
+
+               public static System.Collections.Generic.IEnumerable<string> EnumerateDirectories (string path)
+               {
+                       return EnumerateDirectories (path, "*", SearchOption.TopDirectoryOnly);
+               }
+#endif
+
 #if !NET_2_1 || MONOTOUCH
                [MonoNotSupported ("DirectorySecurity isn't implemented")]
                public static DirectorySecurity GetAccessControl (string path, AccessControlSections includeSections)
index 0dbd3d67570414b4ef9735761f3b46732affacfe..7d1d83d75b9c7e1d5bd0259bbd20c65e35354bdc 100644 (file)
@@ -210,6 +210,18 @@ namespace System.IO
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                public extern static MonoFileType GetFileType (IntPtr handle, out MonoIOError error);
 
+               //
+               // Find file methods
+               //
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               public extern static string FindFirst (string path, string pattern, int attrs, int mask, out int error, out IntPtr handle);
+               
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               public extern static string FindNext (IntPtr handle, out int error);
+               
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               public extern static int FindClose (IntPtr handle);
+               
                public static bool Exists (string path, out MonoIOError error)
                {
                        FileAttributes attrs = GetFileAttributes (path,