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, true);
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 if (File.Exists (path))
169 throw new IOException ("Directory does not exist, but a file of the same name exist.");
171 throw new DirectoryNotFoundException ("Directory does not exist.");
173 throw MonoIO.GetException (path, error);
177 static void RecursiveDelete (string path)
181 foreach (string dir in GetDirectories (path)) {
182 if (MonoIO.ExistsSymlink (dir, out error)) {
183 MonoIO.DeleteFile (dir, out error);
185 RecursiveDelete (dir);
189 foreach (string file in GetFiles (path))
192 Directory.Delete (path);
195 public static void Delete (string path, bool recurse)
197 CheckPathExceptions (path);
199 if (recurse == false){
204 RecursiveDelete (path);
207 public static bool Exists (string path)
215 exists = MonoIO.ExistsDirectory (path, out error);
216 if (error != MonoIOError.ERROR_SUCCESS &&
217 error != MonoIOError.ERROR_PATH_NOT_FOUND &&
218 error != MonoIOError.ERROR_INVALID_HANDLE &&
219 error != MonoIOError.ERROR_ACCESS_DENIED) {
221 // INVALID_HANDLE might happen if the file is moved
222 // while testing for the existence, a kernel issue
223 // according to Larry Ewing.
225 throw MonoIO.GetException (path, error);
231 public static DateTime GetLastAccessTime (string path)
233 return File.GetLastAccessTime (path);
236 public static DateTime GetLastAccessTimeUtc (string path)
238 return GetLastAccessTime (path).ToUniversalTime ();
241 public static DateTime GetLastWriteTime (string path)
243 return File.GetLastWriteTime (path);
246 public static DateTime GetLastWriteTimeUtc (string path)
248 return GetLastWriteTime (path).ToUniversalTime ();
251 public static DateTime GetCreationTime (string path)
253 return File.GetCreationTime (path);
256 public static DateTime GetCreationTimeUtc (string path)
258 return GetCreationTime (path).ToUniversalTime ();
261 public static string GetCurrentDirectory ()
265 string result = MonoIO.GetCurrentDirectory (out error);
266 if (error != MonoIOError.ERROR_SUCCESS)
267 throw MonoIO.GetException (error);
269 if ((result != null) && (result.Length > 0) && SecurityManager.SecurityEnabled) {
270 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, result).Demand ();
275 public static string [] GetDirectories (string path)
277 return GetDirectories (path, "*");
280 public static string [] GetDirectories (string path, string pattern)
282 return GetFileSystemEntries (path, pattern, FileAttributes.Directory, FileAttributes.Directory);
286 public static string [] GetDirectories (string path, string pattern, SearchOption option)
288 if (option == SearchOption.TopDirectoryOnly)
289 return GetDirectories (path, pattern);
290 ArrayList all = new ArrayList ();
291 GetDirectoriesRecurse (path, pattern, all);
292 return (string []) all.ToArray (typeof (string));
295 static void GetDirectoriesRecurse (string path, string pattern, ArrayList all)
297 all.AddRange (GetDirectories (path, pattern));
298 foreach (string dir in GetDirectories (path))
299 GetDirectoriesRecurse (dir, pattern, all);
303 public static string GetDirectoryRoot (string path)
305 return new String(Path.DirectorySeparatorChar,1);
308 public static string [] GetFiles (string path)
310 return GetFiles (path, "*");
313 public static string [] GetFiles (string path, string pattern)
315 return GetFileSystemEntries (path, pattern, FileAttributes.Directory, 0);
319 public static string[] GetFiles (string path, string searchPattern, SearchOption searchOption)
321 if (searchOption == SearchOption.TopDirectoryOnly)
322 return GetFiles (path, searchPattern);
323 ArrayList all = new ArrayList ();
324 GetFilesRecurse (path, searchPattern, all);
325 return (string []) all.ToArray (typeof (string));
328 static void GetFilesRecurse (string path, string pattern, ArrayList all)
330 all.AddRange (GetFiles (path, pattern));
331 foreach (string dir in GetDirectories (path))
332 GetFilesRecurse (dir, pattern, all);
336 public static string [] GetFileSystemEntries (string path)
338 return GetFileSystemEntries (path, "*");
341 public static string [] GetFileSystemEntries (string path, string pattern)
343 return GetFileSystemEntries (path, pattern, 0, 0);
346 public static string[] GetLogicalDrives ()
348 return Environment.GetLogicalDrives ();
351 static bool IsRootDirectory (string path)
354 if (Path.DirectorySeparatorChar == '/' && path == "/")
358 if (Path.DirectorySeparatorChar == '\\')
359 if (path.Length == 3 && path.EndsWith (":\\"))
365 public static DirectoryInfo GetParent (string path)
368 throw new ArgumentNullException ();
369 if (path.IndexOfAny (Path.InvalidPathChars) != -1)
370 throw new ArgumentException ("Path contains invalid characters");
372 throw new ArgumentException ("The Path do not have a valid format");
374 // return null if the path is the root directory
375 if (IsRootDirectory (path))
378 string parent_name = Path.GetDirectoryName (path);
379 if (parent_name == "")
380 parent_name = GetCurrentDirectory();
382 return new DirectoryInfo (parent_name);
385 public static void Move (string sourceDirName, string destDirName)
387 if (sourceDirName == null)
388 throw new ArgumentNullException ("sourceDirName");
390 if (destDirName == null)
391 throw new ArgumentNullException ("destDirName");
393 if (sourceDirName.Trim () == "" || sourceDirName.IndexOfAny (Path.InvalidPathChars) != -1)
394 throw new ArgumentException ("Invalid source directory name: " + sourceDirName, "sourceDirName");
396 if (destDirName.Trim () == "" || destDirName.IndexOfAny (Path.InvalidPathChars) != -1)
397 throw new ArgumentException ("Invalid target directory name: " + destDirName, "destDirName");
399 if (sourceDirName == destDirName)
400 throw new IOException ("Source and destination path must be different.");
402 if (Exists (destDirName))
403 throw new IOException (destDirName + " already exists.");
405 if (!Exists (sourceDirName) && !File.Exists (sourceDirName))
406 throw new DirectoryNotFoundException (sourceDirName + " does not exist");
409 if (!MonoIO.MoveFile (sourceDirName, destDirName, out error))
410 throw MonoIO.GetException (error);
414 public static void SetAccessControl (string path, DirectorySecurity directorySecurity)
416 throw new NotImplementedException ();
420 public static void SetCreationTime (string path, DateTime creation_time)
422 File.SetCreationTime (path, creation_time);
425 public static void SetCreationTimeUtc (string path, DateTime creation_time)
427 SetCreationTime (path, creation_time.ToLocalTime ());
430 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
431 public static void SetCurrentDirectory (string path)
434 throw new ArgumentNullException ("path");
435 if (path.Trim () == String.Empty)
436 throw new ArgumentException ("path string must not be an empty string or whitespace string");
441 throw new DirectoryNotFoundException ("Directory \"" +
442 path + "\" not found.");
444 MonoIO.SetCurrentDirectory (path, out error);
445 if (error != MonoIOError.ERROR_SUCCESS)
446 throw MonoIO.GetException (path, error);
449 public static void SetLastAccessTime (string path, DateTime last_access_time)
451 File.SetLastAccessTime (path, last_access_time);
454 public static void SetLastAccessTimeUtc (string path, DateTime last_access_time)
456 SetLastAccessTime (path, last_access_time.ToLocalTime ());
459 public static void SetLastWriteTime (string path, DateTime last_write_time)
461 File.SetLastWriteTime (path, last_write_time);
464 public static void SetLastWriteTimeUtc (string path, DateTime last_write_time)
466 SetLastWriteTime (path, last_write_time.ToLocalTime ());
471 private static void CheckPathExceptions (string path)
474 throw new System.ArgumentNullException("Path is Null");
476 throw new System.ArgumentException("Path is Empty");
477 if (path.Trim().Length == 0)
478 throw new ArgumentException ("Only blank characters in path");
479 if (path.IndexOfAny (Path.InvalidPathChars) != -1)
480 throw new ArgumentException ("Path contains invalid chars");
483 private static string [] GetFileSystemEntries (string path, string pattern, FileAttributes mask, FileAttributes attrs)
485 if (path == null || pattern == null)
486 throw new ArgumentNullException ();
488 if (pattern == String.Empty)
489 return new string [] {};
491 if (path.Trim () == "")
492 throw new ArgumentException ("The Path does not have a valid format");
494 string wild = Path.Combine (path, pattern);
495 string wildpath = Path.GetDirectoryName (wild);
496 if (wildpath.IndexOfAny (Path.InvalidPathChars) != -1)
497 throw new ArgumentException ("Path contains invalid characters");
499 if (wildpath.IndexOfAny (Path.InvalidPathChars) != -1) {
500 if (path.IndexOfAny (SearchPattern.InvalidChars) == -1)
501 throw new ArgumentException ("Path contains invalid characters", "path");
503 throw new ArgumentException ("Pattern contains invalid characters", "pattern");
507 if (!MonoIO.ExistsDirectory (wildpath, out error)) {
508 if (error == MonoIOError.ERROR_SUCCESS) {
509 MonoIOError file_error;
510 if (MonoIO.ExistsFile (wildpath, out file_error)) {
511 return new string [] { wildpath };
515 if (error != MonoIOError.ERROR_PATH_NOT_FOUND)
516 throw MonoIO.GetException (wildpath, error);
518 if (wildpath.IndexOfAny (SearchPattern.WildcardChars) == -1)
519 throw new DirectoryNotFoundException ("Directory '" + wildpath + "' not found.");
521 if (path.IndexOfAny (SearchPattern.WildcardChars) == -1)
522 throw new ArgumentException ("Pattern is invalid", "pattern");
524 throw new ArgumentException ("Path is invalid", "path");
527 string path_with_pattern = Path.Combine (wildpath, pattern);
528 string [] result = MonoIO.GetFileSystemEntries (path, path_with_pattern, (int) attrs, (int) mask, out error);
530 throw MonoIO.GetException (wildpath, error);
536 [MonoNotSupported ("DirectorySecurity isn't implemented")]
537 public static DirectorySecurity GetAccessControl (string path, AccessControlSections includeSections)
539 throw new PlatformNotSupportedException ();
542 [MonoNotSupported ("DirectorySecurity isn't implemented")]
543 public static DirectorySecurity GetAccessControl (string path)
545 throw new PlatformNotSupportedException ();