2007-04-05 Dick Porter <dick@ximian.com>
[mono.git] / mcs / class / corlib / System.IO / Directory.cs
index d212b28dd0e94762576075b9f714cdfb6bb3f6b8..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);
@@ -250,10 +302,20 @@ namespace System.IO
                }
 
 #if NET_2_0
-               [MonoTODO]
                public static string[] GetFiles (string path, string searchPattern, SearchOption searchOption)
                {
-                       throw new NotImplementedException ();
+                       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
 
@@ -298,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)
@@ -437,12 +503,27 @@ namespace System.IO
                                throw new ArgumentException ("Path is invalid", "path");
                        }
 
-                       string [] result = MonoIO.GetFileSystemEntries (wildpath, pattern, (int) attrs, (int) mask, out 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;
                }
+
+#if NET_2_0
+               [MonoNotSupported ("DirectorySecurity isn't implemented")]
+               public static DirectorySecurity GetAccessControl (string path, AccessControlSections includeSections)
+               {
+                       throw new PlatformNotSupportedException ();
+               }
+
+               [MonoNotSupported ("DirectorySecurity isn't implemented")]
+               public static DirectorySecurity GetAccessControl (string path)
+               {
+                       throw new PlatformNotSupportedException ();
+               }
+#endif
        }
 }