2 // System.IO.DirectoryInfo.cs
5 // Miguel de Icaza, miguel@ximian.com
6 // Jim Richardson, develop@wtfo-guru.com
7 // Dan Lewis, dihlewis@yahoo.co.uk
8 // Sebastien Pouliot <sebastien@ximian.com>
10 // Copyright (C) 2002 Ximian, Inc.
11 // Copyright (C) 2001 Moonlight Enterprises, All Rights Reserved
12 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Collections;
35 using System.Collections.Generic;
36 using System.Runtime.InteropServices;
37 using System.Runtime.Serialization;
38 using System.Security;
41 using System.Security.AccessControl;
48 public sealed class DirectoryInfo : FileSystemInfo {
50 private string current;
51 private string parent;
54 internal DirectoryInfo ()
58 public DirectoryInfo (string path) : this (path, false)
62 internal DirectoryInfo (string path, bool simpleOriginalPath)
66 SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
68 FullPath = Path.GetFullPath (path);
69 if (simpleOriginalPath)
70 OriginalPath = Path.GetFileName (path);
77 private DirectoryInfo (SerializationInfo info, StreamingContext context)
78 : base (info, context)
85 int len = FullPath.Length - 1;
86 if ((len > 1) && (FullPath [len] == Path.DirectorySeparatorChar))
88 int last = FullPath.LastIndexOf (Path.DirectorySeparatorChar, len);
89 if ((last == -1) || ((last == 0) && (len == 0))) {
93 current = FullPath.Substring (last + 1, len - last);
94 if (last == 0 && !Environment.IsRunningOnWindows)
95 parent = Path.DirectorySeparatorStr;
97 parent = FullPath.Substring (0, last);
98 // adjust for drives, i.e. a special case for windows
99 if (Environment.IsRunningOnWindows) {
100 if ((parent.Length == 2) && (parent [1] == ':') && Char.IsLetter (parent [0]))
101 parent += Path.DirectorySeparatorChar;
108 public override bool Exists {
112 if (stat.Attributes == MonoIO.InvalidFileAttributes)
115 if ((stat.Attributes & FileAttributes.Directory) == 0)
122 public override string Name {
123 get { return current; }
126 public DirectoryInfo Parent {
128 if ((parent == null) || (parent.Length == 0))
130 return new DirectoryInfo (parent);
134 public DirectoryInfo Root {
136 string root = Path.GetPathRoot (FullPath);
140 return new DirectoryInfo (root);
144 // creational methods
146 public void Create ()
148 Directory.CreateDirectory (FullPath);
151 public DirectoryInfo CreateSubdirectory (string path)
155 path = Path.Combine (FullPath, path);
156 Directory.CreateDirectory (path);
157 return new DirectoryInfo (path);
160 // directory listing methods
162 public FileInfo [] GetFiles ()
164 return GetFiles ("*");
167 public FileInfo [] GetFiles (string searchPattern)
169 if (searchPattern == null)
170 throw new ArgumentNullException ("searchPattern");
172 string [] names = Directory.GetFiles (FullPath, searchPattern);
174 FileInfo[] infos = new FileInfo [names.Length];
176 foreach (string name in names)
177 infos [i++] = new FileInfo (name);
182 public DirectoryInfo [] GetDirectories ()
184 return GetDirectories ("*");
187 public DirectoryInfo [] GetDirectories (string searchPattern)
189 if (searchPattern == null)
190 throw new ArgumentNullException ("searchPattern");
192 string [] names = Directory.GetDirectories (FullPath, searchPattern);
194 DirectoryInfo[] infos = new DirectoryInfo [names.Length];
196 foreach (string name in names)
197 infos [i++] = new DirectoryInfo (name);
202 public FileSystemInfo [] GetFileSystemInfos ()
204 return GetFileSystemInfos ("*");
207 public FileSystemInfo [] GetFileSystemInfos (string searchPattern)
209 return GetFileSystemInfos (searchPattern, SearchOption.TopDirectoryOnly);
215 FileSystemInfo [] GetFileSystemInfos (string searchPattern, SearchOption searchOption)
217 if (searchPattern == null)
218 throw new ArgumentNullException ("searchPattern");
219 if (searchOption != SearchOption.TopDirectoryOnly && searchOption != SearchOption.AllDirectories)
220 throw new ArgumentOutOfRangeException ("searchOption", "Must be TopDirectoryOnly or AllDirectories");
221 if (!Directory.Exists (FullPath))
222 throw new IOException ("Invalid directory");
224 List<FileSystemInfo> infos = new List<FileSystemInfo> ();
225 InternalGetFileSystemInfos (searchPattern, searchOption, infos);
226 return infos.ToArray ();
229 void InternalGetFileSystemInfos (string searchPattern, SearchOption searchOption, List<FileSystemInfo> infos)
231 // UnauthorizedAccessExceptions might happen here and break everything for SearchOption.AllDirectories
232 string [] dirs = Directory.GetDirectories (FullPath, searchPattern);
233 string [] files = Directory.GetFiles (FullPath, searchPattern);
235 Array.ForEach<string> (dirs, (dir) => { infos.Add (new DirectoryInfo (dir)); });
236 Array.ForEach<string> (files, (file) => { infos.Add (new FileInfo (file)); });
237 if (dirs.Length == 0 || searchOption == SearchOption.TopDirectoryOnly)
240 foreach (string dir in dirs) {
241 DirectoryInfo dinfo = new DirectoryInfo (dir);
242 dinfo.InternalGetFileSystemInfos (searchPattern, searchOption, infos);
246 // directory management methods
248 public override void Delete ()
253 public void Delete (bool recursive)
255 Directory.Delete (FullPath, recursive);
258 public void MoveTo (string destDirName)
260 if (destDirName == null)
261 throw new ArgumentNullException ("destDirName");
262 if (destDirName.Length == 0)
263 throw new ArgumentException ("An empty file name is not valid.", "destDirName");
265 Directory.Move (FullPath, Path.GetFullPath (destDirName));
268 public override string ToString ()
274 public DirectoryInfo[] GetDirectories (string searchPattern, SearchOption searchOption)
276 switch (searchOption) {
277 case SearchOption.TopDirectoryOnly:
278 return GetDirectories (searchPattern);
279 case SearchOption.AllDirectories:
280 Queue workq = new Queue(GetDirectories(searchPattern));
281 Queue doneq = new Queue();
282 while (workq.Count > 0)
284 DirectoryInfo cinfo = (DirectoryInfo) workq.Dequeue();
285 DirectoryInfo[] cinfoDirs = cinfo.GetDirectories(searchPattern);
286 foreach (DirectoryInfo i in cinfoDirs) workq.Enqueue(i);
287 doneq.Enqueue(cinfo);
290 DirectoryInfo[] infos = new DirectoryInfo[doneq.Count];
291 doneq.CopyTo(infos, 0);
294 string msg = Locale.GetText ("Invalid enum value '{0}' for '{1}'.", searchOption, "SearchOption");
295 throw new ArgumentOutOfRangeException ("searchOption", msg);
299 internal int GetFilesSubdirs (ArrayList l, string pattern)
302 FileInfo [] thisdir = null;
305 thisdir = GetFiles (pattern);
306 } catch (System.UnauthorizedAccessException){
310 count = thisdir.Length;
313 foreach (DirectoryInfo subdir in GetDirectories ()){
314 count += subdir.GetFilesSubdirs (l, pattern);
319 public FileInfo[] GetFiles (string searchPattern, SearchOption searchOption)
321 switch (searchOption) {
322 case SearchOption.TopDirectoryOnly:
323 return GetFiles (searchPattern);
324 case SearchOption.AllDirectories: {
325 ArrayList groups = new ArrayList ();
326 int count = GetFilesSubdirs (groups, searchPattern);
329 FileInfo [] all = new FileInfo [count];
330 foreach (FileInfo [] p in groups){
331 p.CopyTo (all, current);
337 string msg = Locale.GetText ("Invalid enum value '{0}' for '{1}'.", searchOption, "SearchOption");
338 throw new ArgumentOutOfRangeException ("searchOption", msg);
342 // access control methods
344 [MonoLimitation ("DirectorySecurity isn't implemented")]
345 public void Create (DirectorySecurity directorySecurity)
347 if (directorySecurity != null)
348 throw new UnauthorizedAccessException ();
352 [MonoLimitation ("DirectorySecurity isn't implemented")]
353 public DirectoryInfo CreateSubdirectory (string path, DirectorySecurity directorySecurity)
355 if (directorySecurity != null)
356 throw new UnauthorizedAccessException ();
357 return CreateSubdirectory (path);
360 [MonoNotSupported ("DirectorySecurity isn't implemented")]
361 public DirectorySecurity GetAccessControl ()
363 throw new UnauthorizedAccessException ();
366 [MonoNotSupported ("DirectorySecurity isn't implemented")]
367 public DirectorySecurity GetAccessControl (AccessControlSections includeSections)
369 throw new UnauthorizedAccessException ();
372 [MonoLimitation ("DirectorySecurity isn't implemented")]
373 public void SetAccessControl (DirectorySecurity directorySecurity)
375 if (directorySecurity != null)
376 throw new ArgumentNullException ("directorySecurity");
377 throw new UnauthorizedAccessException ();
381 #if NET_4_0 || MOONLIGHT || MOBILE
383 public IEnumerable<DirectoryInfo> EnumerateDirectories ()
385 return EnumerateDirectories ("*", SearchOption.TopDirectoryOnly);
388 public IEnumerable<DirectoryInfo> EnumerateDirectories (string searchPattern)
390 return EnumerateDirectories (searchPattern, SearchOption.TopDirectoryOnly);
393 public IEnumerable<DirectoryInfo> EnumerateDirectories (string searchPattern, SearchOption searchOption)
395 if (searchPattern == null)
396 throw new ArgumentNullException ("searchPattern");
398 return CreateEnumerateDirectoriesIterator (searchPattern, searchOption);
401 IEnumerable<DirectoryInfo> CreateEnumerateDirectoriesIterator (string searchPattern, SearchOption searchOption)
403 foreach (string name in Directory.EnumerateDirectories (FullPath, searchPattern, searchOption))
404 yield return new DirectoryInfo (name);
407 public IEnumerable<FileInfo> EnumerateFiles ()
409 return EnumerateFiles ("*", SearchOption.TopDirectoryOnly);
412 public IEnumerable<FileInfo> EnumerateFiles (string searchPattern)
414 return EnumerateFiles (searchPattern, SearchOption.TopDirectoryOnly);
417 public IEnumerable<FileInfo> EnumerateFiles (string searchPattern, SearchOption searchOption)
419 if (searchPattern == null)
420 throw new ArgumentNullException ("searchPattern");
422 return CreateEnumerateFilesIterator (searchPattern, searchOption);
425 IEnumerable<FileInfo> CreateEnumerateFilesIterator (string searchPattern, SearchOption searchOption)
427 foreach (string name in Directory.EnumerateFiles (FullPath, searchPattern, searchOption))
428 yield return new FileInfo (name);
431 public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos ()
433 return EnumerateFileSystemInfos ("*", SearchOption.TopDirectoryOnly);
436 public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos (string searchPattern)
438 return EnumerateFileSystemInfos (searchPattern, SearchOption.TopDirectoryOnly);
441 public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos (string searchPattern, SearchOption searchOption)
443 if (searchPattern == null)
444 throw new ArgumentNullException ("searchPattern");
445 if (searchOption != SearchOption.TopDirectoryOnly && searchOption != SearchOption.AllDirectories)
446 throw new ArgumentOutOfRangeException ("searchoption");
448 return EnumerateFileSystemInfos (FullPath, searchPattern, searchOption);
451 static internal IEnumerable<FileSystemInfo> EnumerateFileSystemInfos (string full, string searchPattern, SearchOption searchOption)
453 string path_with_pattern = Path.Combine (full, searchPattern);
456 FileAttributes rattr;
457 bool subdirs = searchOption == SearchOption.AllDirectories;
459 Path.Validate (full);
461 string s = MonoIO.FindFirst (full, path_with_pattern, out rattr, out error, out handle);
465 throw MonoIO.GetException (Path.GetDirectoryName (path_with_pattern), (MonoIOError) error);
468 if (((rattr & FileAttributes.ReparsePoint) == 0)){
469 if ((rattr & FileAttributes.Directory) != 0)
470 yield return new DirectoryInfo (s);
472 yield return new FileInfo (s);
475 while ((s = MonoIO.FindNext (handle, out rattr, out error)) != null){
476 if ((rattr & FileAttributes.ReparsePoint) != 0)
478 if ((rattr & FileAttributes.Directory) != 0)
479 yield return new DirectoryInfo (s);
481 yield return new FileInfo (s);
483 if (((rattr & FileAttributes.Directory) != 0) && subdirs)
484 foreach (FileSystemInfo child in EnumerateFileSystemInfos (s, searchPattern, searchOption))
488 MonoIO.FindClose (handle);