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;
47 using System.Runtime.InteropServices;
65 private Directory () {}
68 public static DirectoryInfo CreateDirectory (string path)
71 throw new ArgumentNullException ("path");
74 throw new ArgumentException ("Path is empty");
76 if (path.IndexOfAny (Path.InvalidPathChars) != -1)
77 throw new ArgumentException ("Path contains invalid chars");
79 if (path.Trim ().Length == 0)
80 throw new ArgumentException ("Only blank characters in path");
83 if (File.Exists(path))
84 throw new IOException ("Cannot create " + path + " because a file with the same name already exists.");
87 // LAMESPEC: with .net 1.0 version this throw NotSupportedException and msdn says so too
88 // but v1.1 throws ArgumentException.
90 throw new ArgumentException ("Only ':' In path");
92 return CreateDirectoriesInternal (path);
96 [MonoTODO ("DirectorySecurity not implemented")]
97 public static DirectoryInfo CreateDirectory (string path, DirectorySecurity directorySecurity)
99 return(CreateDirectory (path));
103 static DirectoryInfo CreateDirectoriesInternal (string path)
105 if (SecurityManager.SecurityEnabled) {
106 new FileIOPermission (FileIOPermissionAccess.Read | FileIOPermissionAccess.Write, path).Demand ();
109 DirectoryInfo info = new DirectoryInfo (path);
110 if (info.Parent != null && !info.Parent.Exists)
111 info.Parent.Create ();
114 if (!MonoIO.CreateDirectory (path, out error)) {
115 // LAMESPEC: 1.1 and 1.2alpha allow CreateDirectory on a file path.
116 // So CreateDirectory ("/tmp/somefile") will succeed if 'somefile' is
117 // not a directory. However, 1.0 will throw an exception.
118 // We behave like 1.0 here (emulating 1.1-like behavior is just a matter
119 // of comparing error to ERROR_FILE_EXISTS, but it's lame to do:
120 // DirectoryInfo di = Directory.CreateDirectory (something);
121 // and having di.Exists return false afterwards.
122 // I hope we don't break anyone's code, as they should be catching
123 // the exception anyway.
124 if (error != MonoIOError.ERROR_ALREADY_EXISTS &&
125 error != MonoIOError.ERROR_FILE_EXISTS)
126 throw MonoIO.GetException (path, error);
132 public static void Delete (string path)
135 throw new ArgumentNullException ("path");
138 throw new ArgumentException ("Path is empty");
140 if (path.IndexOfAny (Path.InvalidPathChars) != -1)
141 throw new ArgumentException ("Path contains invalid chars");
143 if (path.Trim().Length == 0)
144 throw new ArgumentException ("Only blank characters in path");
147 throw new NotSupportedException ("Only ':' In path");
152 if (MonoIO.ExistsSymlink (path, out error)) {
153 /* RemoveDirectory maps to rmdir()
154 * which fails on symlinks (ENOTDIR)
156 success = MonoIO.DeleteFile (path, out error);
158 success = MonoIO.RemoveDirectory (path, out error);
164 * In io-layer/io.c rmdir returns error_file_not_found if directory does not exists.
165 * So maybe this could be handled somewhere else?
167 if (error == MonoIOError.ERROR_FILE_NOT_FOUND)
168 throw new DirectoryNotFoundException ("Directory '" + path + "' does not exist");
170 throw MonoIO.GetException (path, error);
174 static void RecursiveDelete (string path)
178 foreach (string dir in GetDirectories (path)) {
179 if (MonoIO.ExistsSymlink (dir, out error)) {
180 MonoIO.DeleteFile (dir, out error);
182 RecursiveDelete (dir);
186 foreach (string file in GetFiles (path))
189 Directory.Delete (path);
192 public static void Delete (string path, bool recurse)
194 CheckPathExceptions (path);
196 if (recurse == false){
201 RecursiveDelete (path);
204 public static bool Exists (string path)
212 exists = MonoIO.ExistsDirectory (path, out error);
213 if (error != MonoIOError.ERROR_SUCCESS &&
214 error != MonoIOError.ERROR_PATH_NOT_FOUND &&
215 error != MonoIOError.ERROR_INVALID_HANDLE &&
216 error != MonoIOError.ERROR_ACCESS_DENIED) {
218 // INVALID_HANDLE might happen if the file is moved
219 // while testing for the existence, a kernel issue
220 // according to Larry Ewing.
222 throw MonoIO.GetException (path, error);
228 public static DateTime GetLastAccessTime (string path)
230 return File.GetLastAccessTime (path);
233 public static DateTime GetLastAccessTimeUtc (string path)
235 return GetLastAccessTime (path).ToUniversalTime ();
238 public static DateTime GetLastWriteTime (string path)
240 return File.GetLastWriteTime (path);
243 public static DateTime GetLastWriteTimeUtc (string path)
245 return GetLastWriteTime (path).ToUniversalTime ();
248 public static DateTime GetCreationTime (string path)
250 return File.GetCreationTime (path);
253 public static DateTime GetCreationTimeUtc (string path)
255 return GetCreationTime (path).ToUniversalTime ();
258 public static string GetCurrentDirectory ()
262 string result = MonoIO.GetCurrentDirectory (out error);
263 if (error != MonoIOError.ERROR_SUCCESS)
264 throw MonoIO.GetException (error);
266 if ((result != null) && (result.Length > 0) && SecurityManager.SecurityEnabled) {
267 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, result).Demand ();
272 public static string [] GetDirectories (string path)
274 return GetDirectories (path, "*");
277 public static string [] GetDirectories (string path, string pattern)
279 return GetFileSystemEntries (path, pattern, FileAttributes.Directory, FileAttributes.Directory);
283 public static string [] GetDirectories (string path, string pattern, SearchOption option)
285 if (option == SearchOption.TopDirectoryOnly)
286 return GetDirectories (path, pattern);
287 ArrayList all = new ArrayList ();
288 GetDirectoriesRecurse (path, pattern, all);
289 return (string []) all.ToArray (typeof (string));
292 static void GetDirectoriesRecurse (string path, string pattern, ArrayList all)
294 all.AddRange (GetDirectories (path, pattern));
295 foreach (string dir in GetDirectories (path))
296 GetDirectoriesRecurse (dir, pattern, all);
300 public static string GetDirectoryRoot (string path)
302 return new String(Path.DirectorySeparatorChar,1);
305 public static string [] GetFiles (string path)
307 return GetFiles (path, "*");
310 public static string [] GetFiles (string path, string pattern)
312 return GetFileSystemEntries (path, pattern, FileAttributes.Directory, 0);
316 public static string[] GetFiles (string path, string searchPattern, SearchOption searchOption)
318 if (searchOption == SearchOption.TopDirectoryOnly)
319 return GetFiles (path, searchPattern);
320 ArrayList all = new ArrayList ();
321 GetFilesRecurse (path, searchPattern, all);
322 return (string []) all.ToArray (typeof (string));
325 static void GetFilesRecurse (string path, string pattern, ArrayList all)
327 all.AddRange (GetFiles (path, pattern));
328 foreach (string dir in GetDirectories (path))
329 GetFilesRecurse (dir, pattern, all);
333 public static string [] GetFileSystemEntries (string path)
335 return GetFileSystemEntries (path, "*");
338 public static string [] GetFileSystemEntries (string path, string pattern)
340 return GetFileSystemEntries (path, pattern, 0, 0);
343 public static string[] GetLogicalDrives ()
345 return Environment.GetLogicalDrives ();
348 static bool IsRootDirectory (string path)
351 if (Path.DirectorySeparatorChar == '/' && path == "/")
355 if (Path.DirectorySeparatorChar == '\\')
356 if (path.Length == 3 && path.EndsWith (":\\"))
362 public static DirectoryInfo GetParent (string path)
365 throw new ArgumentNullException ();
366 if (path.IndexOfAny (Path.InvalidPathChars) != -1)
367 throw new ArgumentException ("Path contains invalid characters");
369 throw new ArgumentException ("The Path do not have a valid format");
371 // return null if the path is the root directory
372 if (IsRootDirectory (path))
375 string parent_name = Path.GetDirectoryName (path);
376 if (parent_name == "")
377 parent_name = GetCurrentDirectory();
379 return new DirectoryInfo (parent_name);
382 public static void Move (string sourceDirName, string destDirName)
384 if (sourceDirName == null)
385 throw new ArgumentNullException ("sourceDirName");
387 if (destDirName == null)
388 throw new ArgumentNullException ("destDirName");
390 if (sourceDirName.Trim () == "" || sourceDirName.IndexOfAny (Path.InvalidPathChars) != -1)
391 throw new ArgumentException ("Invalid source directory name: " + sourceDirName, "sourceDirName");
393 if (destDirName.Trim () == "" || destDirName.IndexOfAny (Path.InvalidPathChars) != -1)
394 throw new ArgumentException ("Invalid target directory name: " + destDirName, "destDirName");
396 if (sourceDirName == destDirName)
397 throw new IOException ("Source and destination path must be different.");
399 if (Exists (destDirName))
400 throw new IOException (destDirName + " already exists.");
402 if (!Exists (sourceDirName) && !File.Exists (sourceDirName))
403 throw new DirectoryNotFoundException (sourceDirName + " does not exist");
406 if (!MonoIO.MoveFile (sourceDirName, destDirName, out error))
407 throw MonoIO.GetException (error);
411 public static void SetAccessControl (string path, DirectorySecurity directorySecurity)
413 throw new NotImplementedException ();
417 public static void SetCreationTime (string path, DateTime creation_time)
419 File.SetCreationTime (path, creation_time);
422 public static void SetCreationTimeUtc (string path, DateTime creation_time)
424 SetCreationTime (path, creation_time.ToLocalTime ());
427 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
428 public static void SetCurrentDirectory (string path)
431 throw new ArgumentNullException ("path");
432 if (path.Trim () == String.Empty)
433 throw new ArgumentException ("path string must not be an empty string or whitespace string");
438 throw new DirectoryNotFoundException ("Directory \"" +
439 path + "\" not found.");
441 MonoIO.SetCurrentDirectory (path, out error);
442 if (error != MonoIOError.ERROR_SUCCESS)
443 throw MonoIO.GetException (path, error);
446 public static void SetLastAccessTime (string path, DateTime last_access_time)
448 File.SetLastAccessTime (path, last_access_time);
451 public static void SetLastAccessTimeUtc (string path, DateTime last_access_time)
453 SetLastAccessTime (path, last_access_time.ToLocalTime ());
456 public static void SetLastWriteTime (string path, DateTime last_write_time)
458 File.SetLastWriteTime (path, last_write_time);
461 public static void SetLastWriteTimeUtc (string path, DateTime last_write_time)
463 SetLastWriteTime (path, last_write_time.ToLocalTime ());
468 private static void CheckPathExceptions (string path)
471 throw new System.ArgumentNullException("Path is Null");
473 throw new System.ArgumentException("Path is Empty");
474 if (path.Trim().Length == 0)
475 throw new ArgumentException ("Only blank characters in path");
476 if (path.IndexOfAny (Path.InvalidPathChars) != -1)
477 throw new ArgumentException ("Path contains invalid chars");
480 private static string [] GetFileSystemEntries (string path, string pattern, FileAttributes mask, FileAttributes attrs)
482 if (path == null || pattern == null)
483 throw new ArgumentNullException ();
485 if (pattern == String.Empty)
486 return new string [] {};
488 if (path.Trim () == "")
489 throw new ArgumentException ("The Path does not have a valid format");
491 string wild = Path.Combine (path, pattern);
492 string wildpath = Path.GetDirectoryName (wild);
493 if (wildpath.IndexOfAny (Path.InvalidPathChars) != -1)
494 throw new ArgumentException ("Path contains invalid characters");
496 if (wildpath.IndexOfAny (Path.InvalidPathChars) != -1) {
497 if (path.IndexOfAny (SearchPattern.InvalidChars) == -1)
498 throw new ArgumentException ("Path contains invalid characters", "path");
500 throw new ArgumentException ("Pattern contains invalid characters", "pattern");
504 if (!MonoIO.ExistsDirectory (wildpath, out error)) {
505 if (error == MonoIOError.ERROR_SUCCESS) {
506 MonoIOError file_error;
507 if (MonoIO.ExistsFile (wildpath, out file_error)) {
508 return new string [] { wildpath };
512 if (error != MonoIOError.ERROR_PATH_NOT_FOUND)
513 throw MonoIO.GetException (wildpath, error);
515 if (wildpath.IndexOfAny (SearchPattern.WildcardChars) == -1)
516 throw new DirectoryNotFoundException ("Directory '" + wildpath + "' not found.");
518 if (path.IndexOfAny (SearchPattern.WildcardChars) == -1)
519 throw new ArgumentException ("Pattern is invalid", "pattern");
521 throw new ArgumentException ("Path is invalid", "path");
524 string path_with_pattern = Path.Combine (wildpath, pattern);
525 string [] result = MonoIO.GetFileSystemEntries (path, path_with_pattern, (int) attrs, (int) mask, out error);
527 throw MonoIO.GetException (wildpath, error);
533 [MonoNotSupported ("DirectorySecurity isn't implemented")]
534 public static DirectorySecurity GetAccessControl (string path, AccessControlSections includeSections)
536 throw new PlatformNotSupportedException ();
539 [MonoNotSupported ("DirectorySecurity isn't implemented")]
540 public static DirectorySecurity GetAccessControl (string path)
542 throw new PlatformNotSupportedException ();