Merge pull request #485 from mtausig/master
[mono.git] / mcs / class / corlib / System.IO / DirectoryInfo.cs
index b8372743871c76db932c9d8dcd6193040edb293c..c6ec35c77ed2ac07ba747633cbaefc75d2966f9d 100644 (file)
 //
 
 using System.Collections;
+using System.Collections.Generic;
 using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
+using System.Security;
 using System.Text;
-#if NET_2_0
+#if !MOONLIGHT
 using System.Security.AccessControl;
 #endif
 
 namespace System.IO {
        
        [Serializable]
-#if NET_2_0
        [ComVisible (true)]
-#endif
        public sealed class DirectoryInfo : FileSystemInfo {
 
                private string current;
                private string parent;
        
-               public DirectoryInfo (string path)
+#if MOONLIGHT
+               internal DirectoryInfo ()
+               {
+               }
+#endif
+               public DirectoryInfo (string path) : this (path, false)
+               {
+               }
+
+               internal DirectoryInfo (string path, bool simpleOriginalPath)
                {
                        CheckPath (path);
 
+                       SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
+
                        FullPath = Path.GetFullPath (path);
-                       OriginalPath = path;
+                       if (simpleOriginalPath)
+                               OriginalPath = Path.GetFileName (path);
+                       else
+                               OriginalPath = path;
+
+                       Initialize ();
+               }
+
+               private DirectoryInfo (SerializationInfo info, StreamingContext context)
+                       : base (info, context)
+               {
+                       Initialize ();
+               }
 
+               void Initialize ()
+               {
                        int len = FullPath.Length - 1;
                        if ((len > 1) && (FullPath [len] == Path.DirectorySeparatorChar))
                                len--;
@@ -117,28 +143,33 @@ namespace System.IO {
 
                // creational methods
 
-               public void Create () {
+               public void Create ()
+               {
                        Directory.CreateDirectory (FullPath);
                }
 
-               public DirectoryInfo CreateSubdirectory (string name) {
-                       CheckPath (name);
-                       
-                       string path = Path.Combine (FullPath, name);
-                       Directory.CreateDirectory (path);
+               public DirectoryInfo CreateSubdirectory (string path)
+               {
+                       CheckPath (path);
 
+                       path = Path.Combine (FullPath, path);
+                       Directory.CreateDirectory (path);
                        return new DirectoryInfo (path);
                }
 
                // directory listing methods
 
-               public FileInfo [] GetFiles () {
+               public FileInfo [] GetFiles ()
+               {
                        return GetFiles ("*");
                }
 
-               public FileInfo [] GetFiles (string pattern)
+               public FileInfo [] GetFiles (string searchPattern)
                {
-                       string [] names = Directory.GetFiles (FullPath, pattern);
+                       if (searchPattern == null)
+                               throw new ArgumentNullException ("searchPattern");
+
+                       string [] names = Directory.GetFiles (FullPath, searchPattern);
 
                        FileInfo[] infos = new FileInfo [names.Length];
                        int i = 0;
@@ -148,13 +179,17 @@ namespace System.IO {
                        return infos;
                }
 
-               public DirectoryInfo [] GetDirectories () {
+               public DirectoryInfo [] GetDirectories ()
+               {
                        return GetDirectories ("*");
                }
 
-               public DirectoryInfo [] GetDirectories (string pattern)
+               public DirectoryInfo [] GetDirectories (string searchPattern)
                {
-                       string [] names = Directory.GetDirectories (FullPath, pattern);
+                       if (searchPattern == null)
+                               throw new ArgumentNullException ("searchPattern");
+
+                       string [] names = Directory.GetDirectories (FullPath, searchPattern);
 
                        DirectoryInfo[] infos = new DirectoryInfo [names.Length];
                        int i = 0;
@@ -164,67 +199,128 @@ namespace System.IO {
                        return infos;
                }
 
-               public FileSystemInfo [] GetFileSystemInfos () {
+               public FileSystemInfo [] GetFileSystemInfos ()
+               {
                        return GetFileSystemInfos ("*");
                }
 
-               public FileSystemInfo [] GetFileSystemInfos (string pattern)
+               public FileSystemInfo [] GetFileSystemInfos (string searchPattern)
                {
-                       string[] dirs = Directory.GetDirectories (FullPath, pattern);
-                       string[] files = Directory.GetFiles (FullPath, pattern);
+                       return GetFileSystemInfos (searchPattern, SearchOption.TopDirectoryOnly);
+               }
 
-                       FileSystemInfo[] infos = new FileSystemInfo [dirs.Length + files.Length];
-                       int i = 0;
-                       foreach (string dir in dirs)
-                               infos [i++] = new DirectoryInfo (dir);
-                       foreach (string file in files)
-                               infos [i++] = new FileInfo (file);
+#if NET_4_0
+               public
+#endif
+               FileSystemInfo [] GetFileSystemInfos (string searchPattern, SearchOption searchOption)
+               {
+                       if (searchPattern == null)
+                               throw new ArgumentNullException ("searchPattern");
+                       if (searchOption != SearchOption.TopDirectoryOnly && searchOption != SearchOption.AllDirectories)
+                               throw new ArgumentOutOfRangeException ("searchOption", "Must be TopDirectoryOnly or AllDirectories");
+                       if (!Directory.Exists (FullPath))
+                               throw new IOException ("Invalid directory");
+
+                       List<FileSystemInfo> infos = new List<FileSystemInfo> ();
+                       InternalGetFileSystemInfos (searchPattern, searchOption, infos);
+                       return infos.ToArray ();
+               }
 
-                       return infos;
+               void InternalGetFileSystemInfos (string searchPattern, SearchOption searchOption, List<FileSystemInfo> infos)
+               {
+                       // UnauthorizedAccessExceptions might happen here and break everything for SearchOption.AllDirectories
+                       string [] dirs = Directory.GetDirectories (FullPath, searchPattern);
+                       string [] files = Directory.GetFiles (FullPath, searchPattern);
+
+                       Array.ForEach<string> (dirs, (dir) => { infos.Add (new DirectoryInfo (dir)); });
+                       Array.ForEach<string> (files, (file) => { infos.Add (new FileInfo (file)); });
+                       if (dirs.Length == 0 || searchOption == SearchOption.TopDirectoryOnly)
+                               return;
+
+                       foreach (string dir in dirs) {
+                               DirectoryInfo dinfo = new DirectoryInfo (dir);
+                               dinfo.InternalGetFileSystemInfos (searchPattern, searchOption, infos);
+                       }
                }
 
                // directory management methods
 
-               public override void Delete () {
+               public override void Delete ()
+               {
                        Delete (false);
                }
 
-               public void Delete (bool recurse) {
-                       Directory.Delete (FullPath, recurse);
+               public void Delete (bool recursive)
+               {
+                       Directory.Delete (FullPath, recursive);
                }
 
-               public void MoveTo (string dest) {
-                       Directory.Move (FullPath, Path.GetFullPath (dest));
+               public void MoveTo (string destDirName)
+               {
+                       if (destDirName == null)
+                               throw new ArgumentNullException ("destDirName");
+                       if (destDirName.Length == 0)
+                               throw new ArgumentException ("An empty file name is not valid.", "destDirName");
+
+                       Directory.Move (FullPath, Path.GetFullPath (destDirName));
                }
 
-               public override string ToString () {
+               public override string ToString ()
+               {
                        return OriginalPath;
                }
-#if NET_2_0
-               // additional search methods
 
-               [MonoTODO ("AllDirectories isn't implemented")]
-               public DirectoryInfo[] GetDirectories (string pattern, SearchOption searchOption)
+#if !MOONLIGHT
+               public DirectoryInfo[] GetDirectories (string searchPattern, SearchOption searchOption)
                {
-                       switch (searchOption) {
-                       case SearchOption.TopDirectoryOnly:
-                               return GetDirectories (pattern);
-                       case SearchOption.AllDirectories:
-                               throw new NotImplementedException ();
-                       default:
-                               string msg = Locale.GetText ("Invalid enum value '{0}' for '{1}'.", searchOption, "SearchOption");
-                               throw new ArgumentOutOfRangeException ("searchOption", msg);
+                   //NULL-check of searchPattern is done in Directory.GetDirectories
+                       string [] names = Directory.GetDirectories (FullPath, searchPattern, searchOption);
+                       //Convert the names to DirectoryInfo instances
+                       DirectoryInfo[] infos = new DirectoryInfo [names.Length];
+                       for (int i = 0; i<names.Length; ++i){
+                               string name = names[i];
+                               infos [i] = new DirectoryInfo (name);
                        }
+                       return infos;
                }       
 
-               [MonoTODO ("AllDirectories isn't implemented")]
-               public FileInfo[] GetFiles (string pattern, SearchOption searchOption)
+               internal int GetFilesSubdirs (ArrayList l, string pattern)
+               {
+                       int count;
+                       FileInfo [] thisdir = null;
+
+                       try {
+                               thisdir = GetFiles (pattern);
+                       } catch (System.UnauthorizedAccessException){
+                               return 0;
+                       }
+                       
+                       count = thisdir.Length;
+                       l.Add (thisdir);
+
+                       foreach (DirectoryInfo subdir in GetDirectories ()){
+                               count += subdir.GetFilesSubdirs (l, pattern);
+                       }
+                       return count;
+               }
+               
+               public FileInfo[] GetFiles (string searchPattern, SearchOption searchOption)
                {
                        switch (searchOption) {
                        case SearchOption.TopDirectoryOnly:
-                               return GetFiles (pattern);
-                       case SearchOption.AllDirectories:
-                               throw new NotImplementedException ();
+                               return GetFiles (searchPattern);
+                       case SearchOption.AllDirectories: {
+                               ArrayList groups = new ArrayList ();
+                               int count = GetFilesSubdirs (groups, searchPattern);
+                               int current = 0;
+                               
+                               FileInfo [] all = new FileInfo [count];
+                               foreach (FileInfo [] p in groups){
+                                       p.CopyTo (all, current);
+                                       current += p.Length;
+                               }
+                               return all;
+                       }
                        default:
                                string msg = Locale.GetText ("Invalid enum value '{0}' for '{1}'.", searchOption, "SearchOption");
                                throw new ArgumentOutOfRangeException ("searchOption", msg);
@@ -233,41 +329,150 @@ namespace System.IO {
 
                // access control methods
 
-               [MonoTODO ("DirectorySecurity isn't implemented")]
+               [MonoLimitation ("DirectorySecurity isn't implemented")]
                public void Create (DirectorySecurity directorySecurity)
                {
                        if (directorySecurity != null)
-                               throw new NotImplementedException ();
+                               throw new UnauthorizedAccessException ();
                        Create ();
                }
 
-               [MonoTODO ("DirectorySecurity isn't implemented")]
-               public DirectoryInfo CreateSubdirectory (string name, DirectorySecurity directorySecurity)
+               [MonoLimitation ("DirectorySecurity isn't implemented")]
+               public DirectoryInfo CreateSubdirectory (string path, DirectorySecurity directorySecurity)
                {
                        if (directorySecurity != null)
-                               throw new NotImplementedException ();
-                       return CreateSubdirectory (name);
+                               throw new UnauthorizedAccessException ();
+                       return CreateSubdirectory (path);
                }
 
-               [MonoTODO ("DirectorySecurity isn't implemented")]
                public DirectorySecurity GetAccessControl ()
                {
-                       throw new NotImplementedException ();
+                       return Directory.GetAccessControl (FullPath);
                }
 
-               [MonoTODO ("DirectorySecurity isn't implemented")]
                public DirectorySecurity GetAccessControl (AccessControlSections includeSections)
                {
-                       throw new NotImplementedException ();
+                       return Directory.GetAccessControl (FullPath, includeSections);
                }
 
-               [MonoTODO ("DirectorySecurity isn't implemented")]
                public void SetAccessControl (DirectorySecurity directorySecurity)
                {
-                       if (directorySecurity != null)
-                               throw new ArgumentNullException ("directorySecurity");
-                       throw new NotImplementedException ();
+                       Directory.SetAccessControl (FullPath, directorySecurity);
+               }
+#endif
+
+#if NET_4_0 || MOONLIGHT || MOBILE
+
+               public IEnumerable<DirectoryInfo> EnumerateDirectories ()
+               {
+                       return EnumerateDirectories ("*", SearchOption.TopDirectoryOnly);
+               }
+
+               public IEnumerable<DirectoryInfo> EnumerateDirectories (string searchPattern)
+               {
+                       return EnumerateDirectories (searchPattern, SearchOption.TopDirectoryOnly);
+               }
+
+               public IEnumerable<DirectoryInfo> EnumerateDirectories (string searchPattern, SearchOption searchOption)
+               {
+                       if (searchPattern == null)
+                               throw new ArgumentNullException ("searchPattern");
+
+                       return CreateEnumerateDirectoriesIterator (searchPattern, searchOption);
+               }
+
+               IEnumerable<DirectoryInfo> CreateEnumerateDirectoriesIterator (string searchPattern, SearchOption searchOption)
+               {
+                       foreach (string name in Directory.EnumerateDirectories (FullPath, searchPattern, searchOption))
+                               yield return new DirectoryInfo (name);
+               }
+
+               public IEnumerable<FileInfo> EnumerateFiles ()
+               {
+                       return EnumerateFiles ("*", SearchOption.TopDirectoryOnly);
+               }
+
+               public IEnumerable<FileInfo> EnumerateFiles (string searchPattern)
+               {
+                       return EnumerateFiles (searchPattern, SearchOption.TopDirectoryOnly);
+               }
+
+               public IEnumerable<FileInfo> EnumerateFiles (string searchPattern, SearchOption searchOption)
+               {
+                       if (searchPattern == null)
+                               throw new ArgumentNullException ("searchPattern");
+
+                       return CreateEnumerateFilesIterator (searchPattern, searchOption);
+               }
+
+               IEnumerable<FileInfo> CreateEnumerateFilesIterator (string searchPattern, SearchOption searchOption)
+               {
+                       foreach (string name in Directory.EnumerateFiles (FullPath, searchPattern, searchOption))
+                               yield return new FileInfo (name);
+               }
+
+               public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos ()
+               {
+                       return EnumerateFileSystemInfos ("*", SearchOption.TopDirectoryOnly);
+               }
+
+               public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos (string searchPattern)
+               {
+                       return EnumerateFileSystemInfos (searchPattern, SearchOption.TopDirectoryOnly);
+               }
+
+               public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos (string searchPattern, SearchOption searchOption)
+               {
+                       if (searchPattern == null)
+                               throw new ArgumentNullException ("searchPattern");
+                       if (searchOption != SearchOption.TopDirectoryOnly && searchOption != SearchOption.AllDirectories)
+                               throw new ArgumentOutOfRangeException ("searchoption");
+
+                       return EnumerateFileSystemInfos (FullPath, searchPattern, searchOption);
+               }
+
+               static internal IEnumerable<FileSystemInfo> EnumerateFileSystemInfos (string full, string searchPattern, SearchOption searchOption)
+               {
+                       string path_with_pattern = Path.Combine (full, searchPattern);
+                       IntPtr handle;
+                       MonoIOError error;
+                       FileAttributes rattr;
+                       bool subdirs = searchOption == SearchOption.AllDirectories;
+
+                       Path.Validate (full);
+                       
+                       string s = MonoIO.FindFirst (full, path_with_pattern, out rattr, out error, out handle);
+                       if (s == null)
+                               yield break;
+                       if (error != 0)
+                               throw MonoIO.GetException (Path.GetDirectoryName (path_with_pattern), (MonoIOError) error);
+
+                       try {
+                               if (((rattr & FileAttributes.ReparsePoint) == 0)){
+                                       if ((rattr & FileAttributes.Directory) != 0)
+                                               yield return new DirectoryInfo (s);
+                                       else
+                                               yield return new FileInfo (s);
+                               }
+                               
+                               while ((s = MonoIO.FindNext (handle, out rattr, out error)) != null){
+                                       if ((rattr & FileAttributes.ReparsePoint) != 0)
+                                               continue;
+                                       if ((rattr & FileAttributes.Directory) != 0)
+                                               yield return new DirectoryInfo (s);
+                                       else
+                                               yield return new FileInfo (s);
+                                       
+                                       if (((rattr & FileAttributes.Directory) != 0) && subdirs)
+                                               foreach (FileSystemInfo child in EnumerateFileSystemInfos (s, searchPattern, searchOption))
+                                                       yield return child;
+                               }
+                       } finally {
+                               MonoIO.FindClose (handle);
+                       }
                }
+               
+               
 #endif
        }
 }