2 // System.IO.Directory.cs
5 // Jim Richardson (develop@wtfo-guru.com)
6 // Miguel de Icaza (miguel@ximian.com)
7 // Dan Lewis (dihlewis@yahoo.co.uk)
8 // Eduardo Garcia (kiwnix@yahoo.es)
9 // Ville Palo (vi64pa@kolumbus.fi)
11 // Copyright (C) 2001 Moonlight Enterprises, All Rights Reserved
12 // Copyright (C) 2002 Ximian, Inc.
14 // Created: Monday, August 13, 2001
16 //------------------------------------------------------------------------------
19 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
21 // Permission is hereby granted, free of charge, to any person obtaining
22 // a copy of this software and associated documentation files (the
23 // "Software"), to deal in the Software without restriction, including
24 // without limitation the rights to use, copy, modify, merge, publish,
25 // distribute, sublicense, and/or sell copies of the Software, and to
26 // permit persons to whom the Software is furnished to do so, subject to
27 // the following conditions:
29 // The above copyright notice and this permission notice shall be
30 // included in all copies or substantial portions of the Software.
32 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
33 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
34 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
35 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
36 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
37 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
38 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41 using System.Collections;
42 using System.Security;
43 using System.Security.Permissions;
46 using System.Security.AccessControl;
61 private Directory () {}
64 public static DirectoryInfo CreateDirectory (string path)
67 throw new ArgumentNullException ("path");
69 path = path.TrimEnd ();
72 throw new ArgumentException ("Path is empty");
74 if (path.IndexOfAny (Path.InvalidPathChars) != -1)
75 throw new ArgumentException ("Path contains invalid chars");
78 if (File.Exists(path))
79 throw new IOException ("Cannot create " + path + " because a file with the same name already exists.");
82 // LAMESPEC: with .net 1.0 version this throw NotSupportedException and msdn says so too
83 // but v1.1 throws ArgumentException.
85 throw new ArgumentException ("Only ':' In path");
87 return CreateDirectoriesInternal (path);
90 static DirectoryInfo CreateDirectoriesInternal (string path)
92 if (SecurityManager.SecurityEnabled) {
93 new FileIOPermission (FileIOPermissionAccess.Read | FileIOPermissionAccess.Write, path).Demand ();
96 DirectoryInfo info = new DirectoryInfo (path);
97 if (info.Parent != null && !info.Parent.Exists)
98 info.Parent.Create ();
100 path = Path.GetFullPath (path);
103 if (!MonoIO.CreateDirectory (path, out error)) {
104 // LAMESPEC: 1.1 and 1.2alpha allow CreateDirectory on a file path.
105 // So CreateDirectory ("/tmp/somefile") will succeed if 'somefile' is
106 // not a directory. However, 1.0 will throw an exception.
107 // We behave like 1.0 here (emulating 1.1-like behavior is just a matter
108 // of comparing error to ERROR_FILE_EXISTS, but it's lame to do:
109 // DirectoryInfo di = Directory.CreateDirectory (something);
110 // and having di.Exists return false afterwards.
111 // I hope we don't break anyone's code, as they should be catching
112 // the exception anyway.
113 if (error != MonoIOError.ERROR_ALREADY_EXISTS &&
114 error != MonoIOError.ERROR_FILE_EXISTS)
115 throw MonoIO.GetException (path, error);
121 public static void Delete (string path)
124 throw new ArgumentNullException ("path");
127 throw new ArgumentException ("Path is empty");
129 if (path.IndexOfAny (Path.InvalidPathChars) != -1)
130 throw new ArgumentException ("Path contains invalid chars");
132 if (path.Trim().Length == 0)
133 throw new ArgumentException ("Only blank characters in path");
136 throw new NotSupportedException ("Only ':' In path");
141 if (MonoIO.ExistsSymlink (path, out error)) {
142 /* RemoveDirectory maps to rmdir()
143 * which fails on symlinks (ENOTDIR)
145 success = MonoIO.DeleteFile (path, out error);
147 success = MonoIO.RemoveDirectory (path,
154 * In io-layer/io.c rmdir returns error_file_not_found if directory does not exists.
155 * So maybe this could be handled somewhere else?
157 if (error == MonoIOError.ERROR_FILE_NOT_FOUND)
158 throw new DirectoryNotFoundException ("Directory '" + path + "' doesnt exists.");
160 throw MonoIO.GetException (path, error);
164 static void RecursiveDelete (string path)
168 foreach (string dir in GetDirectories (path)) {
169 if (MonoIO.ExistsSymlink (dir, out error)) {
170 MonoIO.DeleteFile (dir, out error);
172 RecursiveDelete (dir);
176 foreach (string file in GetFiles (path))
179 Directory.Delete (path);
182 public static void Delete (string path, bool recurse)
184 CheckPathExceptions (path);
186 if (recurse == false){
191 RecursiveDelete (path);
194 public static bool Exists (string path)
196 if (path == null || path.Trim ().Length == 0)
202 exists = MonoIO.ExistsDirectory (path, out error);
203 if (error != MonoIOError.ERROR_SUCCESS &&
204 error != MonoIOError.ERROR_PATH_NOT_FOUND &&
205 error != MonoIOError.ERROR_INVALID_HANDLE &&
206 error != MonoIOError.ERROR_ACCESS_DENIED) {
208 // INVALID_HANDLE might happen if the file is moved
209 // while testing for the existence, a kernel issue
210 // according to Larry Ewing.
212 throw MonoIO.GetException (path, error);
218 public static DateTime GetLastAccessTime (string path)
220 return File.GetLastAccessTime (path);
223 public static DateTime GetLastAccessTimeUtc (string path)
225 return GetLastAccessTime (path).ToUniversalTime ();
228 public static DateTime GetLastWriteTime (string path)
230 return File.GetLastWriteTime (path);
233 public static DateTime GetLastWriteTimeUtc (string path)
235 return GetLastWriteTime (path).ToUniversalTime ();
238 public static DateTime GetCreationTime (string path)
240 return File.GetCreationTime (path);
243 public static DateTime GetCreationTimeUtc (string path)
245 return GetCreationTime (path).ToUniversalTime ();
248 public static string GetCurrentDirectory ()
252 string result = MonoIO.GetCurrentDirectory (out error);
253 if (error != MonoIOError.ERROR_SUCCESS)
254 throw MonoIO.GetException (error);
256 if ((result != null) && (result.Length > 0) && SecurityManager.SecurityEnabled) {
257 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, result).Demand ();
262 public static string [] GetDirectories (string path)
264 return GetDirectories (path, "*");
267 public static string [] GetDirectories (string path, string pattern)
269 return GetFileSystemEntries (path, pattern, FileAttributes.Directory, FileAttributes.Directory);
273 public static string [] GetDirectories (string path, string pattern, SearchOption option)
275 if (option == SearchOption.TopDirectoryOnly)
276 return GetDirectories (path, pattern);
277 ArrayList all = new ArrayList ();
278 GetDirectoriesRecurse (path, pattern, all);
279 return (string []) all.ToArray (typeof (string));
282 static void GetDirectoriesRecurse (string path, string pattern, ArrayList all)
284 all.AddRange (GetDirectories (path, pattern));
285 foreach (string dir in GetDirectories (path))
286 GetDirectoriesRecurse (dir, pattern, all);
290 public static string GetDirectoryRoot (string path)
292 return new String(Path.DirectorySeparatorChar,1);
295 public static string [] GetFiles (string path)
297 return GetFiles (path, "*");
300 public static string [] GetFiles (string path, string pattern)
302 return GetFileSystemEntries (path, pattern, FileAttributes.Directory, 0);
306 public static string[] GetFiles (string path, string searchPattern, SearchOption searchOption)
308 if (searchOption == SearchOption.TopDirectoryOnly)
309 return GetFiles (path, searchPattern);
310 ArrayList all = new ArrayList ();
311 GetFilesRecurse (path, searchPattern, all);
312 return (string []) all.ToArray (typeof (string));
315 static void GetFilesRecurse (string path, string pattern, ArrayList all)
317 all.AddRange (GetFiles (path, pattern));
318 foreach (string dir in GetDirectories (path))
319 GetFilesRecurse (dir, pattern, all);
323 public static string [] GetFileSystemEntries (string path)
325 return GetFileSystemEntries (path, "*");
328 public static string [] GetFileSystemEntries (string path, string pattern)
330 return GetFileSystemEntries (path, pattern, 0, 0);
333 public static string[] GetLogicalDrives ()
335 return Environment.GetLogicalDrives ();
338 static bool IsRootDirectory (string path)
341 if (Path.DirectorySeparatorChar == '/' && path == "/")
345 if (Path.DirectorySeparatorChar == '\\')
346 if (path.Length == 3 && path.EndsWith (":\\"))
352 public static DirectoryInfo GetParent (string path)
355 throw new ArgumentNullException ();
356 if (path.IndexOfAny (Path.InvalidPathChars) != -1)
357 throw new ArgumentException ("Path contains invalid characters");
359 throw new ArgumentException ("The Path do not have a valid format");
361 // return null if the path is the root directory
362 if (IsRootDirectory (path))
365 string parent_name = Path.GetDirectoryName (path);
366 if (parent_name == "")
367 parent_name = GetCurrentDirectory();
369 return new DirectoryInfo (parent_name);
372 public static void Move (string src, string dest)
375 throw new ArgumentNullException ("src");
378 throw new ArgumentNullException ("dest");
380 if (src.Trim () == "" || src.IndexOfAny (Path.InvalidPathChars) != -1)
381 throw new ArgumentException ("Invalid source directory name: " + src, "src");
383 if (dest.Trim () == "" || dest.IndexOfAny (Path.InvalidPathChars) != -1)
384 throw new ArgumentException ("Invalid target directory name: " + dest, "dest");
387 throw new IOException ("Source directory cannot be same as a target directory.");
390 throw new IOException (dest + " already exists.");
393 throw new DirectoryNotFoundException (src + " does not exist");
396 if (!MonoIO.MoveFile (src, dest, out error))
397 throw MonoIO.GetException (error);
400 public static void SetCreationTime (string path, DateTime creation_time)
402 File.SetCreationTime (path, creation_time);
405 public static void SetCreationTimeUtc (string path, DateTime creation_time)
407 SetCreationTime (path, creation_time.ToLocalTime ());
410 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
411 public static void SetCurrentDirectory (string path)
414 throw new ArgumentNullException ("path");
415 if (path.Trim () == String.Empty)
416 throw new ArgumentException ("path string must not be an empty string or whitespace string");
421 throw new DirectoryNotFoundException ("Directory \"" +
422 path + "\" not found.");
424 MonoIO.SetCurrentDirectory (path, out error);
425 if (error != MonoIOError.ERROR_SUCCESS)
426 throw MonoIO.GetException (path, error);
429 public static void SetLastAccessTime (string path, DateTime last_access_time)
431 File.SetLastAccessTime (path, last_access_time);
434 public static void SetLastAccessTimeUtc (string path, DateTime last_access_time)
436 SetLastAccessTime (path, last_access_time.ToLocalTime ());
439 public static void SetLastWriteTime (string path, DateTime last_write_time)
441 File.SetLastWriteTime (path, last_write_time);
444 public static void SetLastWriteTimeUtc (string path, DateTime last_write_time)
446 SetLastWriteTime (path, last_write_time.ToLocalTime ());
451 private static void CheckPathExceptions (string path)
454 throw new System.ArgumentNullException("Path is Null");
456 throw new System.ArgumentException("Path is Empty");
457 if (path.Trim().Length == 0)
458 throw new ArgumentException ("Only blank characters in path");
459 if (path.IndexOfAny (Path.InvalidPathChars) != -1)
460 throw new ArgumentException ("Path contains invalid chars");
463 private static string [] GetFileSystemEntries (string path, string pattern, FileAttributes mask, FileAttributes attrs)
465 if (path == null || pattern == null)
466 throw new ArgumentNullException ();
468 if (pattern == String.Empty)
469 return new string [] {};
471 if (path.Trim () == "")
472 throw new ArgumentException ("The Path does not have a valid format");
474 string wild = Path.Combine (path, pattern);
475 string wildpath = Path.GetDirectoryName (wild);
476 if (wildpath.IndexOfAny (Path.InvalidPathChars) != -1)
477 throw new ArgumentException ("Path contains invalid characters");
479 if (wildpath.IndexOfAny (Path.InvalidPathChars) != -1) {
480 if (path.IndexOfAny (SearchPattern.InvalidChars) == -1)
481 throw new ArgumentException ("Path contains invalid characters", "path");
483 throw new ArgumentException ("Pattern contains invalid characters", "pattern");
487 if (!MonoIO.ExistsDirectory (wildpath, out error)) {
488 if (error == MonoIOError.ERROR_SUCCESS) {
489 MonoIOError file_error;
490 if (MonoIO.ExistsFile (wildpath, out file_error)) {
491 return new string [] { wildpath };
495 if (error != MonoIOError.ERROR_PATH_NOT_FOUND)
496 throw MonoIO.GetException (wildpath, error);
498 if (wildpath.IndexOfAny (SearchPattern.WildcardChars) == -1)
499 throw new DirectoryNotFoundException ("Directory '" + wildpath + "' not found.");
501 if (path.IndexOfAny (SearchPattern.WildcardChars) == -1)
502 throw new ArgumentException ("Pattern is invalid", "pattern");
504 throw new ArgumentException ("Path is invalid", "path");
507 string [] result = MonoIO.GetFileSystemEntries (wildpath, pattern, (int) attrs, (int) mask, out error);
509 throw MonoIO.GetException (wildpath, error);
515 [MonoLimitation ("Mono always throws PlatformNotSupported regardless of the platform")]
516 public static DirectorySecurity GetAccessControl (string path, AccessControlSections includeSections)
518 throw new PlatformNotSupportedException ();
521 [MonoLimitation ("Mono always throws PlatformNotSupported regardless of the platform")]
522 public static DirectorySecurity GetAccessControl (string path)
524 throw new PlatformNotSupportedException ();