2007-04-05 Dick Porter <dick@ximian.com>
[mono.git] / mcs / class / corlib / System.IO / Directory.cs
index 07fa7de0b60eae09be3de0fd363beb6d5641ff13..a802b10c8c840df7c7cc68792e43cede60e0b0aa 100644 (file)
@@ -42,6 +42,9 @@ using System.Collections;
 using System.Security;
 using System.Security.Permissions;
 using System.Text;
+#if NET_2_0
+using System.Security.AccessControl;
+#endif
 
 namespace System.IO
 {
@@ -71,6 +74,11 @@ namespace System.IO
 
                        if (path.Trim ().Length == 0)
                                throw new ArgumentException ("Only blank characters in path");
+
+#if NET_2_0
+                       if (File.Exists(path))
+                               throw new IOException ("Cannot create " + path + " because a file with the same name already exists.");
+#endif
                        
                        // LAMESPEC: with .net 1.0 version this throw NotSupportedException and msdn says so too
                        // but v1.1 throws ArgumentException.
@@ -101,7 +109,8 @@ namespace System.IO
                                // and having di.Exists return false afterwards.
                                // I hope we don't break anyone's code, as they should be catching
                                // the exception anyway.
-                               if (error != MonoIOError.ERROR_ALREADY_EXISTS)
+                               if (error != MonoIOError.ERROR_ALREADY_EXISTS &&
+                                   error != MonoIOError.ERROR_FILE_EXISTS)
                                        throw MonoIO.GetException (path, error);
                        }
 
@@ -126,15 +135,26 @@ namespace System.IO
                                throw new NotSupportedException ("Only ':' In path");
 
                        MonoIOError error;
+                       bool success;
                        
-                       if (!MonoIO.RemoveDirectory (path, out error)) {
+                       if (MonoIO.ExistsSymlink (path, out error)) {
+                               /* RemoveDirectory maps to rmdir()
+                                * which fails on symlinks (ENOTDIR)
+                                */
+                               success = MonoIO.DeleteFile (path, out error);
+                       } else {
+                               success = MonoIO.RemoveDirectory (path,
+                                                                 out error);
+                       }
+                       
+                       if (!success) {
                                /*
                                 * FIXME:
                                 * In io-layer/io.c rmdir returns error_file_not_found if directory does not exists.
                                 * So maybe this could be handled somewhere else?
                                 */
                                if (error == MonoIOError.ERROR_FILE_NOT_FOUND) 
-                                       throw new DirectoryNotFoundException ("Directory '" + path + "' doesnt exists.");
+                                       throw new DirectoryNotFoundException ("Directory '" + path + "' does not exist");
                                else
                                        throw MonoIO.GetException (path, error);
                        }
@@ -142,8 +162,15 @@ namespace System.IO
 
                static void RecursiveDelete (string path)
                {
-                       foreach (string dir in GetDirectories (path))
-                               RecursiveDelete (dir);
+                       MonoIOError error;
+                       
+                       foreach (string dir in GetDirectories (path)) {
+                               if (MonoIO.ExistsSymlink (dir, out error)) {
+                                       MonoIO.DeleteFile (dir, out error);
+                               } else {
+                                       RecursiveDelete (dir);
+                               }
+                       }
 
                        foreach (string file in GetFiles (path))
                                File.Delete (file);
@@ -173,7 +200,14 @@ namespace System.IO
                        
                        exists = MonoIO.ExistsDirectory (path, out error);
                        if (error != MonoIOError.ERROR_SUCCESS &&
-                           error != MonoIOError.ERROR_PATH_NOT_FOUND) {
+                           error != MonoIOError.ERROR_PATH_NOT_FOUND &&
+                           error != MonoIOError.ERROR_INVALID_HANDLE &&
+                           error != MonoIOError.ERROR_ACCESS_DENIED) {
+
+                               // INVALID_HANDLE might happen if the file is moved
+                               // while testing for the existence, a kernel issue
+                               // according to Larry Ewing.
+                               
                                throw MonoIO.GetException (path, error);
                        }
 
@@ -234,6 +268,24 @@ namespace System.IO
                        return GetFileSystemEntries (path, pattern, FileAttributes.Directory, FileAttributes.Directory);
                }
                
+#if NET_2_0
+               public static string [] GetDirectories (string path, string pattern, SearchOption option)
+               {
+                       if (option == SearchOption.TopDirectoryOnly)
+                               return GetDirectories (path, pattern);
+                       ArrayList all = new ArrayList ();
+                       GetDirectoriesRecurse (path, pattern, all);
+                       return (string []) all.ToArray (typeof (string));
+               }
+               
+               static void GetDirectoriesRecurse (string path, string pattern, ArrayList all)
+               {
+                       all.AddRange (GetDirectories (path, pattern));
+                       foreach (string dir in GetDirectories (path))
+                               GetDirectoriesRecurse (dir, pattern, all);
+               }
+#endif
+
                public static string GetDirectoryRoot (string path)
                {
                        return new String(Path.DirectorySeparatorChar,1);
@@ -249,6 +301,24 @@ namespace System.IO
                        return GetFileSystemEntries (path, pattern, FileAttributes.Directory, 0);
                }
 
+#if NET_2_0
+               public static string[] GetFiles (string path, string searchPattern, SearchOption searchOption)
+               {
+                       if (searchOption == SearchOption.TopDirectoryOnly)
+                               return GetFiles (path, searchPattern);
+                       ArrayList all = new ArrayList ();
+                       GetFilesRecurse (path, searchPattern, all);
+                       return (string []) all.ToArray (typeof (string));
+               }
+               
+               static void GetFilesRecurse (string path, string pattern, ArrayList all)
+               {
+                       all.AddRange (GetFiles (path, pattern));
+                       foreach (string dir in GetDirectories (path))
+                               GetFilesRecurse (dir, pattern, all);
+               }
+#endif
+
                public static string [] GetFileSystemEntries (string path)
                {
                        return GetFileSystemEntries (path, "*");
@@ -290,8 +360,12 @@ namespace System.IO
                        // return null if the path is the root directory
                        if (IsRootDirectory (path))
                                return null;
-                       
-                       return new DirectoryInfo (Path.GetDirectoryName (path));
+
+                       string parent_name = Path.GetDirectoryName (path);
+                       if (parent_name == "")
+                               parent_name = GetCurrentDirectory();
+
+                       return new DirectoryInfo (parent_name);
                }
 
                public static void Move (string src, string dest)
@@ -387,9 +461,6 @@ namespace System.IO
 
                private static string [] GetFileSystemEntries (string path, string pattern, FileAttributes mask, FileAttributes attrs)
                {
-                       MonoIOStat stat;
-                       IntPtr find;
-
                        if (path == null || pattern == null)
                                throw new ArgumentNullException ();
 
@@ -432,36 +503,27 @@ namespace System.IO
                                throw new ArgumentException ("Path is invalid", "path");
                        }
 
-                       ArrayList entries = null;
-                       find = MonoIO.InvalidHandle;
-                       try {
-                               find = MonoIO.FindFirstFile (wild, out stat, out error);
-                               if (find == MonoIO.InvalidHandle) {
-                                       switch (error) {
-                                       case MonoIOError.ERROR_PATH_NOT_FOUND:
-                                               string message = String.Format ("Could not find a part of the path \"{0}\"",
-                                                                               wildpath);
-                                               throw new DirectoryNotFoundException (message);
-                                       case MonoIOError.ERROR_FILE_NOT_FOUND:
-                                       case MonoIOError.ERROR_NO_MORE_FILES:
-                                               return new string [0];
-
-                                       default:
-                                               throw MonoIO.GetException (wildpath, error);
-                                       }
-                               }
+                       string path_with_pattern = Path.Combine (wildpath, pattern);
+                       string [] result = MonoIO.GetFileSystemEntries (path, path_with_pattern, (int) attrs, (int) mask, out error);
+                       if (error != 0)
+                               throw MonoIO.GetException (wildpath, error);
+                       
+                       return result;
+               }
 
-                               entries = new ArrayList ();
-                               do {
-                                       if ((stat.Attributes & mask) == attrs)
-                                               entries.Add (Path.Combine (wildpath, stat.Name));
-                               } while (MonoIO.FindNextFile (find, out stat, out error));
-                       } finally {
-                               if (find != MonoIO.InvalidHandle)
-                                       MonoIO.FindClose (find, out error);
-                       }
+#if NET_2_0
+               [MonoNotSupported ("DirectorySecurity isn't implemented")]
+               public static DirectorySecurity GetAccessControl (string path, AccessControlSections includeSections)
+               {
+                       throw new PlatformNotSupportedException ();
+               }
 
-                       return (string []) entries.ToArray (typeof (string));
+               [MonoNotSupported ("DirectorySecurity isn't implemented")]
+               public static DirectorySecurity GetAccessControl (string path)
+               {
+                       throw new PlatformNotSupportedException ();
                }
+#endif
        }
 }
+