2008-01-15 Stephane Delcroix <sdelcroix@novell.com>
[mono.git] / mcs / class / corlib / System.IO / Directory.cs
index f56f1597111cbad90ee7efcebec8978724c40f11..dfc6049f1bc8f2bfcfce0e246f80464f95a30630 100644 (file)
@@ -42,9 +42,16 @@ using System.Collections;
 using System.Security;
 using System.Security.Permissions;
 using System.Text;
+#if NET_2_0
+using System.Security.AccessControl;
+using System.Runtime.InteropServices;
+#endif
 
 namespace System.IO
 {
+#if NET_2_0
+       [ComVisible (true)]
+#endif
        public
 #if NET_2_0
        static
@@ -71,6 +78,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.
@@ -80,6 +92,14 @@ namespace System.IO
                        return CreateDirectoriesInternal (path);
                }
 
+#if NET_2_0
+               [MonoTODO ("DirectorySecurity not implemented")]
+               public static DirectoryInfo CreateDirectory (string path, DirectorySecurity directorySecurity)
+               {
+                       return(CreateDirectory (path));
+               }
+#endif
+
                static DirectoryInfo CreateDirectoriesInternal (string path)
                {
                        if (SecurityManager.SecurityEnabled) {
@@ -101,7 +121,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 +147,25 @@ 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 +173,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 +211,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);
                        }
 
@@ -184,12 +229,12 @@ namespace System.IO
                {
                        return File.GetLastAccessTime (path);
                }
-               
+
                public static DateTime GetLastAccessTimeUtc (string path)
                {
                        return GetLastAccessTime (path).ToUniversalTime ();
                }
-                     
+
                public static DateTime GetLastWriteTime (string path)
                {
                        return File.GetLastWriteTime (path);
@@ -234,6 +279,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 +312,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, "*");
@@ -267,15 +348,15 @@ namespace System.IO
                static bool IsRootDirectory (string path)
                {
                        // Unix
-                      if (Path.DirectorySeparatorChar == '/' && path == "/")
-                              return true;
+                       if (Path.DirectorySeparatorChar == '/' && path == "/")
+                               return true;
 
-                      // Windows
-                      if (Path.DirectorySeparatorChar == '\\')
-                              if (path.Length == 3 && path.EndsWith (":\\"))
-                                      return true;
+                       // Windows
+                       if (Path.DirectorySeparatorChar == '\\')
+                               if (path.Length == 3 && path.EndsWith (":\\"))
+                                       return true;
 
-                      return false;
+                       return false;
                }
 
                public static DirectoryInfo GetParent (string path)
@@ -290,38 +371,49 @@ 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)
+               public static void Move (string sourceDirName, string destDirName)
                {
-                       if (src == null)
-                               throw new ArgumentNullException ("src");
+                       if (sourceDirName == null)
+                               throw new ArgumentNullException ("sourceDirName");
 
-                       if (dest == null)
-                               throw new ArgumentNullException ("dest");
+                       if (destDirName == null)
+                               throw new ArgumentNullException ("destDirName");
 
-                       if (src.Trim () == "" || src.IndexOfAny (Path.InvalidPathChars) != -1)
-                               throw new ArgumentException ("Invalid source directory name: " + src, "src");
+                       if (sourceDirName.Trim () == "" || sourceDirName.IndexOfAny (Path.InvalidPathChars) != -1)
+                               throw new ArgumentException ("Invalid source directory name: " + sourceDirName, "sourceDirName");
 
-                       if (dest.Trim () == "" || dest.IndexOfAny (Path.InvalidPathChars) != -1)
-                               throw new ArgumentException ("Invalid target directory name: " + dest, "dest");
+                       if (destDirName.Trim () == "" || destDirName.IndexOfAny (Path.InvalidPathChars) != -1)
+                               throw new ArgumentException ("Invalid target directory name: " + destDirName, "destDirName");
 
-                       if (src == dest)
-                               throw new IOException ("Source directory cannot be same as a target directory.");
+                       if (sourceDirName == destDirName)
+                               throw new IOException ("Source and destination path must be different.");
 
-                       if (Exists (dest))
-                               throw new IOException (dest + " already exists.");
+                       if (Exists (destDirName))
+                               throw new IOException (destDirName + " already exists.");
 
-                       if (!Exists (src))
-                               throw new DirectoryNotFoundException (src + " does not exist");
+                       if (!Exists (sourceDirName) && !File.Exists (sourceDirName))
+                               throw new DirectoryNotFoundException (sourceDirName + " does not exist");
 
                        MonoIOError error;
-                       if (!MonoIO.MoveFile (src, dest, out error))
+                       if (!MonoIO.MoveFile (sourceDirName, destDirName, out error))
                                throw MonoIO.GetException (error);
                }
 
+#if NET_2_0
+               public static void SetAccessControl (string path, DirectorySecurity directorySecurity)
+               {
+                       throw new NotImplementedException ();
+               }
+#endif
+
                public static void SetCreationTime (string path, DateTime creation_time)
                {
                        File.SetCreationTime (path, creation_time);
@@ -387,9 +479,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,32 +521,26 @@ namespace System.IO
                                throw new ArgumentException ("Path is invalid", "path");
                        }
 
-                       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);
                        
-                       ArrayList entries = new ArrayList ();
-
-                       do {
-                               if ((stat.Attributes & mask) == attrs)
-                                       entries.Add (Path.Combine (wildpath, stat.Name));
-                       } while (MonoIO.FindNextFile (find, out stat, out error));
+                       return result;
+               }
 
-                       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
        }
 }