2010-01-20 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mcs / class / corlib / System.IO / Directory.cs
1 // 
2 // System.IO.Directory.cs 
3 //
4 // Authors:
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)
10 //
11 // Copyright (C) 2001 Moonlight Enterprises, All Rights Reserved
12 // Copyright (C) 2002 Ximian, Inc.
13 // 
14 // Created:        Monday, August 13, 2001 
15 //
16 //------------------------------------------------------------------------------
17
18 //
19 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
20 //
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:
28 // 
29 // The above copyright notice and this permission notice shall be
30 // included in all copies or substantial portions of the Software.
31 // 
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.
39 //
40
41 using System.Collections;
42 using System.Security;
43 using System.Security.Permissions;
44 using System.Text;
45 using System.Runtime.InteropServices;
46
47 #if !NET_2_1 || MONOTOUCH
48 using System.Security.AccessControl;
49 #endif
50
51 namespace System.IO
52 {
53         [ComVisible (true)]
54         public static class Directory
55         {
56
57                 public static DirectoryInfo CreateDirectory (string path)
58                 {
59                         if (path == null)
60                                 throw new ArgumentNullException ("path");
61                         
62                         if (path.Length == 0)
63                                 throw new ArgumentException ("Path is empty");
64                         
65                         if (path.IndexOfAny (Path.InvalidPathChars) != -1)
66                                 throw new ArgumentException ("Path contains invalid chars");
67
68                         if (path.Trim ().Length == 0)
69                                 throw new ArgumentException ("Only blank characters in path");
70
71                         if (File.Exists(path))
72                                 throw new IOException ("Cannot create " + path + " because a file with the same name already exists.");
73                         
74                         // LAMESPEC: with .net 1.0 version this throw NotSupportedException and msdn says so too
75                         // but v1.1 throws ArgumentException.
76                         if (path == ":")
77                                 throw new ArgumentException ("Only ':' In path");
78                         
79                         return CreateDirectoriesInternal (path);
80                 }
81
82 #if !NET_2_1 || MONOTOUCH
83                 [MonoLimitation ("DirectorySecurity not implemented")]
84                 public static DirectoryInfo CreateDirectory (string path, DirectorySecurity directorySecurity)
85                 {
86                         return(CreateDirectory (path));
87                 }
88 #endif
89
90                 static DirectoryInfo CreateDirectoriesInternal (string path)
91                 {
92 #if !NET_2_1 || MONOTOUCH
93                         if (SecurityManager.SecurityEnabled) {
94                                 new FileIOPermission (FileIOPermissionAccess.Read | FileIOPermissionAccess.Write, path).Demand ();
95                         }
96 #endif
97                         DirectoryInfo info = new DirectoryInfo (path, true);
98                         if (info.Parent != null && !info.Parent.Exists)
99                                  info.Parent.Create ();
100
101                         MonoIOError error;
102                         if (!MonoIO.CreateDirectory (path, out error)) {
103                                 // LAMESPEC: 1.1 and 1.2alpha allow CreateDirectory on a file path.
104                                 // So CreateDirectory ("/tmp/somefile") will succeed if 'somefile' is
105                                 // not a directory. However, 1.0 will throw an exception.
106                                 // We behave like 1.0 here (emulating 1.1-like behavior is just a matter
107                                 // of comparing error to ERROR_FILE_EXISTS, but it's lame to do:
108                                 //    DirectoryInfo di = Directory.CreateDirectory (something);
109                                 // and having di.Exists return false afterwards.
110                                 // I hope we don't break anyone's code, as they should be catching
111                                 // the exception anyway.
112                                 if (error != MonoIOError.ERROR_ALREADY_EXISTS &&
113                                     error != MonoIOError.ERROR_FILE_EXISTS)
114                                         throw MonoIO.GetException (path, error);
115                         }
116
117                         return info;
118                 }
119                 
120                 public static void Delete (string path)
121                 {
122                         if (path == null)
123                                 throw new ArgumentNullException ("path");
124                         
125                         if (path.Length == 0)
126                                 throw new ArgumentException ("Path is empty");
127                         
128                         if (path.IndexOfAny (Path.InvalidPathChars) != -1)
129                                 throw new ArgumentException ("Path contains invalid chars");
130
131                         if (path.Trim().Length == 0)
132                                 throw new ArgumentException ("Only blank characters in path");
133
134                         if (path == ":")
135                                 throw new NotSupportedException ("Only ':' In path");
136
137                         MonoIOError error;
138                         bool success;
139                         
140                         if (MonoIO.ExistsSymlink (path, out error)) {
141                                 /* RemoveDirectory maps to rmdir()
142                                  * which fails on symlinks (ENOTDIR)
143                                  */
144                                 success = MonoIO.DeleteFile (path, out error);
145                         } else {
146                                 success = MonoIO.RemoveDirectory (path, out error);
147                         }
148                         
149                         if (!success) {
150                                 /*
151                                  * FIXME:
152                                  * In io-layer/io.c rmdir returns error_file_not_found if directory does not exists.
153                                  * So maybe this could be handled somewhere else?
154                                  */
155                                 if (error == MonoIOError.ERROR_FILE_NOT_FOUND) {
156                                         if (File.Exists (path))
157                                                 throw new IOException ("Directory does not exist, but a file of the same name exist.");
158                                         else
159                                                 throw new DirectoryNotFoundException ("Directory does not exist.");
160                                 } else
161                                         throw MonoIO.GetException (path, error);
162                         }
163                 }
164
165                 static void RecursiveDelete (string path)
166                 {
167                         MonoIOError error;
168                         
169                         foreach (string dir in GetDirectories (path)) {
170                                 if (MonoIO.ExistsSymlink (dir, out error)) {
171                                         MonoIO.DeleteFile (dir, out error);
172                                 } else {
173                                         RecursiveDelete (dir);
174                                 }
175                         }
176
177                         foreach (string file in GetFiles (path))
178                                 File.Delete (file);
179
180                         Directory.Delete (path);
181                 }
182                 
183                 public static void Delete (string path, bool recursive)
184                 {
185                         CheckPathExceptions (path);
186                         
187                         if (recursive)
188                                 RecursiveDelete (path);
189                         else
190                                 Delete (path);
191                 }
192
193                 public static bool Exists (string path)
194                 {
195                         if (path == null)
196                                 return false;
197                                 
198                         MonoIOError error;
199                         bool exists;
200                         
201                         exists = MonoIO.ExistsDirectory (path, out error);
202                         if (error != MonoIOError.ERROR_SUCCESS &&
203                             error != MonoIOError.ERROR_PATH_NOT_FOUND &&
204                             error != MonoIOError.ERROR_INVALID_HANDLE &&
205                             error != MonoIOError.ERROR_ACCESS_DENIED) {
206
207                                 // INVALID_HANDLE might happen if the file is moved
208                                 // while testing for the existence, a kernel issue
209                                 // according to Larry Ewing.
210                                 
211                                 throw MonoIO.GetException (path, error);
212                         }
213
214                         return(exists);
215                 }
216
217                 public static DateTime GetLastAccessTime (string path)
218                 {
219                         return File.GetLastAccessTime (path);
220                 }
221
222                 public static DateTime GetLastAccessTimeUtc (string path)
223                 {
224                         return GetLastAccessTime (path).ToUniversalTime ();
225                 }
226
227                 public static DateTime GetLastWriteTime (string path)
228                 {
229                         return File.GetLastWriteTime (path);
230                 }
231                 
232                 public static DateTime GetLastWriteTimeUtc (string path)
233                 {
234                         return GetLastWriteTime (path).ToUniversalTime ();
235                 }
236
237                 public static DateTime GetCreationTime (string path)
238                 {
239                         return File.GetCreationTime (path);
240                 }
241
242                 public static DateTime GetCreationTimeUtc (string path)
243                 {
244                         return GetCreationTime (path).ToUniversalTime ();
245                 }
246
247                 public static string GetCurrentDirectory ()
248                 {
249                         MonoIOError error;
250                                 
251                         string result = MonoIO.GetCurrentDirectory (out error);
252                         if (error != MonoIOError.ERROR_SUCCESS)
253                                 throw MonoIO.GetException (error);
254 #if !NET_2_1 || MONOTOUCH
255                         if ((result != null) && (result.Length > 0) && SecurityManager.SecurityEnabled) {
256                                 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, result).Demand ();
257                         }
258 #endif
259                         return result;
260                 }
261                 
262                 public static string [] GetDirectories (string path)
263                 {
264                         return GetDirectories (path, "*");
265                 }
266                 
267                 public static string [] GetDirectories (string path, string searchPattern)
268                 {
269                         return GetFileSystemEntries (path, searchPattern, FileAttributes.Directory, FileAttributes.Directory);
270                 }
271                 
272 #if !NET_2_1 || MONOTOUCH
273                 public static string [] GetDirectories (string path, string searchPattern, SearchOption searchOption)
274                 {
275                         if (searchOption == SearchOption.TopDirectoryOnly)
276                                 return GetDirectories (path, searchPattern);
277                         ArrayList all = new ArrayList ();
278                         GetDirectoriesRecurse (path, searchPattern, all);
279                         return (string []) all.ToArray (typeof (string));
280                 }
281                 
282                 static void GetDirectoriesRecurse (string path, string searchPattern, ArrayList all)
283                 {
284                         all.AddRange (GetDirectories (path, searchPattern));
285                         foreach (string dir in GetDirectories (path))
286                                 GetDirectoriesRecurse (dir, searchPattern, all);
287                 }
288 #endif
289
290                 public static string GetDirectoryRoot (string path)
291                 {
292                         return new String(Path.DirectorySeparatorChar,1);
293                 }
294                 
295                 public static string [] GetFiles (string path)
296                 {
297                         return GetFiles (path, "*");
298                 }
299                 
300                 public static string [] GetFiles (string path, string searchPattern)
301                 {
302                         return GetFileSystemEntries (path, searchPattern, FileAttributes.Directory, 0);
303                 }
304
305 #if !NET_2_1 || MONOTOUCH
306                 public static string[] GetFiles (string path, string searchPattern, SearchOption searchOption)
307                 {
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));
313                 }
314                 
315                 static void GetFilesRecurse (string path, string searchPattern, ArrayList all)
316                 {
317                         all.AddRange (GetFiles (path, searchPattern));
318                         foreach (string dir in GetDirectories (path))
319                                 GetFilesRecurse (dir, searchPattern, all);
320                 }
321 #endif
322
323                 public static string [] GetFileSystemEntries (string path)
324                 {
325                         return GetFileSystemEntries (path, "*");
326                 }
327
328                 public static string [] GetFileSystemEntries (string path, string searchPattern)
329                 {
330                         return GetFileSystemEntries (path, searchPattern, 0, 0);
331                 }
332                 
333                 public static string[] GetLogicalDrives ()
334                 { 
335                         return Environment.GetLogicalDrives ();
336                 }
337
338                 static bool IsRootDirectory (string path)
339                 {
340                         // Unix
341                         if (Path.DirectorySeparatorChar == '/' && path == "/")
342                                 return true;
343
344                         // Windows
345                         if (Path.DirectorySeparatorChar == '\\')
346                                 if (path.Length == 3 && path.EndsWith (":\\"))
347                                         return true;
348
349                         return false;
350                 }
351
352                 public static DirectoryInfo GetParent (string path)
353                 {
354                         if (path == null)
355                                 throw new ArgumentNullException ("path");
356                         if (path.IndexOfAny (Path.InvalidPathChars) != -1)
357                                 throw new ArgumentException ("Path contains invalid characters");
358                         if (path.Length == 0)
359                                 throw new ArgumentException ("The Path do not have a valid format");
360
361                         // return null if the path is the root directory
362                         if (IsRootDirectory (path))
363                                 return null;
364
365                         string parent_name = Path.GetDirectoryName (path);
366                         if (parent_name.Length == 0)
367                                 parent_name = GetCurrentDirectory();
368
369                         return new DirectoryInfo (parent_name);
370                 }
371
372                 public static void Move (string sourceDirName, string destDirName)
373                 {
374                         if (sourceDirName == null)
375                                 throw new ArgumentNullException ("sourceDirName");
376
377                         if (destDirName == null)
378                                 throw new ArgumentNullException ("destDirName");
379
380                         if (sourceDirName.Trim ().Length == 0 || sourceDirName.IndexOfAny (Path.InvalidPathChars) != -1)
381                                 throw new ArgumentException ("Invalid source directory name: " + sourceDirName, "sourceDirName");
382
383                         if (destDirName.Trim ().Length == 0 || destDirName.IndexOfAny (Path.InvalidPathChars) != -1)
384                                 throw new ArgumentException ("Invalid target directory name: " + destDirName, "destDirName");
385
386                         if (sourceDirName == destDirName)
387                                 throw new IOException ("Source and destination path must be different.");
388
389                         if (Exists (destDirName))
390                                 throw new IOException (destDirName + " already exists.");
391
392                         if (!Exists (sourceDirName) && !File.Exists (sourceDirName))
393                                 throw new DirectoryNotFoundException (sourceDirName + " does not exist");
394
395                         MonoIOError error;
396                         if (!MonoIO.MoveFile (sourceDirName, destDirName, out error))
397                                 throw MonoIO.GetException (error);
398                 }
399
400 #if !NET_2_1 || MONOTOUCH
401                 public static void SetAccessControl (string path, DirectorySecurity directorySecurity)
402                 {
403                         throw new NotImplementedException ();
404                 }
405 #endif
406
407                 public static void SetCreationTime (string path, DateTime creationTime)
408                 {
409                         File.SetCreationTime (path, creationTime);
410                 }
411
412                 public static void SetCreationTimeUtc (string path, DateTime creationTimeUtc)
413                 {
414                         SetCreationTime (path, creationTimeUtc.ToLocalTime ());
415                 }
416
417                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
418                 public static void SetCurrentDirectory (string path)
419                 {
420                         if (path == null)
421                                 throw new ArgumentNullException ("path");
422                         if (path.Trim ().Length == 0)
423                                 throw new ArgumentException ("path string must not be an empty string or whitespace string");
424
425                         MonoIOError error;
426                                 
427                         if (!Exists (path))
428                                 throw new DirectoryNotFoundException ("Directory \"" +
429                                                                         path + "\" not found.");
430
431                         MonoIO.SetCurrentDirectory (path, out error);
432                         if (error != MonoIOError.ERROR_SUCCESS)
433                                 throw MonoIO.GetException (path, error);
434                 }
435
436                 public static void SetLastAccessTime (string path, DateTime lastAccessTime)
437                 {
438                         File.SetLastAccessTime (path, lastAccessTime);
439                 }
440
441                 public static void SetLastAccessTimeUtc (string path, DateTime lastAccessTimeUtc)
442                 {
443                         SetLastAccessTime (path, lastAccessTimeUtc.ToLocalTime ());
444                 }
445
446                 public static void SetLastWriteTime (string path, DateTime lastWriteTime)
447                 {
448                         File.SetLastWriteTime (path, lastWriteTime);
449                 }
450
451                 public static void SetLastWriteTimeUtc (string path, DateTime lastWriteTimeUtc)
452                 {
453                         SetLastWriteTime (path, lastWriteTimeUtc.ToLocalTime ());
454                 }
455
456                 // private
457                 
458                 private static void CheckPathExceptions (string path)
459                 {
460                         if (path == null)
461                                 throw new System.ArgumentNullException("path");
462                         if (path.Length == 0)
463                                 throw new System.ArgumentException("Path is Empty");
464                         if (path.Trim().Length == 0)
465                                 throw new ArgumentException ("Only blank characters in path");
466                         if (path.IndexOfAny (Path.InvalidPathChars) != -1)
467                                 throw new ArgumentException ("Path contains invalid chars");
468                 }
469
470                 // Does the common validation, searchPattern has already been checked for not-null
471                 static string ValidateDirectoryListing (string path, string searchPattern, out bool stop)
472                 {
473                         if (path == null)
474                                 throw new ArgumentNullException ("path");
475
476                         if (path.Trim ().Length == 0)
477                                 throw new ArgumentException ("The Path does not have a valid format");
478
479                         string wild = Path.Combine (path, searchPattern);
480                         string wildpath = Path.GetDirectoryName (wild);
481                         if (wildpath.IndexOfAny (Path.InvalidPathChars) != -1)
482                                 throw new ArgumentException ("Path contains invalid characters");
483
484                         if (wildpath.IndexOfAny (Path.InvalidPathChars) != -1) {
485                                 if (path.IndexOfAny (SearchPattern.InvalidChars) == -1)
486                                         throw new ArgumentException ("Path contains invalid characters", "path");
487
488                                 throw new ArgumentException ("Pattern contains invalid characters", "pattern");
489                         }
490
491                         MonoIOError error;
492                         if (!MonoIO.ExistsDirectory (wildpath, out error)) {
493                                 if (error == MonoIOError.ERROR_SUCCESS) {
494                                         MonoIOError file_error;
495                                         if (MonoIO.ExistsFile (wildpath, out file_error)) {
496                                                 stop = true;
497                                                 return wildpath;
498                                         }
499                                 }
500
501                                 if (error != MonoIOError.ERROR_PATH_NOT_FOUND)
502                                         throw MonoIO.GetException (wildpath, error);
503
504                                 if (wildpath.IndexOfAny (SearchPattern.WildcardChars) == -1)
505                                         throw new DirectoryNotFoundException ("Directory '" + wildpath + "' not found.");
506
507                                 if (path.IndexOfAny (SearchPattern.WildcardChars) == -1)
508                                         throw new ArgumentException ("Pattern is invalid", "searchPattern");
509
510                                 throw new ArgumentException ("Path is invalid", "path");
511                         }
512
513                         stop = false;
514                         return Path.Combine (wildpath, searchPattern);
515                 }
516                 
517                 private static string [] GetFileSystemEntries (string path, string searchPattern, FileAttributes mask, FileAttributes attrs)
518                 {
519                         if (searchPattern == null)
520                                 throw new ArgumentNullException ("searchPattern");
521                         if (searchPattern.Length == 0)
522                                 return new string [] {};
523                         bool stop;
524                         string path_with_pattern = ValidateDirectoryListing (path, searchPattern, out stop);
525                         if (stop)
526                                 return new string [] { path_with_pattern };
527
528                         MonoIOError error;
529                         string [] result = MonoIO.GetFileSystemEntries (path, path_with_pattern, (int) attrs, (int) mask, out error);
530                         if (error != 0)
531                                 throw MonoIO.GetException (Path.GetDirectoryName (Path.Combine (path, searchPattern)), error);
532                         
533                         return result;
534                 }
535
536 #if NET_4_0
537                 public static string[] GetFileSystemEntries (string path, string searchPattern, SearchOption searchOption)
538                 {
539                         // Take the simple way home:
540                         return new System.Collections.Generic.List<string> (EnumerateFileSystemEntries (path, searchPattern, searchOption)).ToArray ();
541                 }
542                                                        
543                 internal static System.Collections.Generic.IEnumerable<string> EnumerateKind (string path, string searchPattern, SearchOption searchOption, FileAttributes kind)
544                 {
545                         if (searchPattern == null)
546                                 throw new ArgumentNullException ("searchPattern");
547
548                         if (searchPattern.Length == 0)
549                                 yield break;
550
551                         if (searchOption != SearchOption.TopDirectoryOnly && searchOption != SearchOption.AllDirectories)
552                                 throw new ArgumentOutOfRangeException ("searchoption");
553
554                         bool stop;
555                         string path_with_pattern = ValidateDirectoryListing (path, searchPattern, out stop);
556                         if (stop){
557                                 yield return path_with_pattern;
558                                 yield break;
559                         }
560                         
561                         IntPtr handle;
562                         MonoIOError error;
563                         FileAttributes rattr;
564                         bool subdirs = searchOption == SearchOption.AllDirectories;
565                         
566                         string s = MonoIO.FindFirst (path, path_with_pattern, out rattr, out error, out handle);
567                         if (s == null)
568                                 yield break;
569                         if (error != 0)
570                                 throw MonoIO.GetException (Path.GetDirectoryName (Path.Combine (path, searchPattern)), (MonoIOError) error);
571
572                         try {
573                                 if (((rattr & FileAttributes.ReparsePoint) == 0) && ((rattr & kind) != 0))
574                                         yield return s;
575                                 
576                                 while ((s = MonoIO.FindNext (handle, out rattr, out error)) != null){
577                                         if ((rattr & FileAttributes.ReparsePoint) != 0)
578                                                 continue;
579                                         if ((rattr & kind) != 0)
580                                                 yield return s;
581                                         
582                                         if (((rattr & FileAttributes.Directory) != 0) && subdirs)
583                                                 foreach (string child in EnumerateKind (s, searchPattern, searchOption, kind))
584                                                         yield return child;
585                                 }
586                         } finally {
587                                 MonoIO.FindClose (handle);
588                         }
589                 }
590
591                 public static System.Collections.Generic.IEnumerable<string> EnumerateDirectories (string path, string searchPattern, SearchOption searchOption)
592                 {
593                         return EnumerateKind (path, searchPattern, searchOption, FileAttributes.Directory);
594                 }
595                 
596                 public static System.Collections.Generic.IEnumerable<string> EnumerateDirectories (string path, string searchPattern)
597                 {
598                         return EnumerateKind (path, searchPattern, SearchOption.TopDirectoryOnly, FileAttributes.Directory);
599                 }
600
601                 public static System.Collections.Generic.IEnumerable<string> EnumerateDirectories (string path)
602                 {
603                         return EnumerateKind (path, "*", SearchOption.TopDirectoryOnly, FileAttributes.Directory);
604                 }
605
606                 public static System.Collections.Generic.IEnumerable<string> EnumerateFiles (string path, string searchPattern, SearchOption searchOption)
607                 {
608                         return EnumerateKind (path, searchPattern, searchOption, FileAttributes.Normal);
609                 }
610
611                 public static System.Collections.Generic.IEnumerable<string> EnumerateFiles (string path, string searchPattern)
612                 {
613                         return EnumerateKind (path, searchPattern, SearchOption.TopDirectoryOnly, FileAttributes.Normal);
614                 }
615
616                 public static System.Collections.Generic.IEnumerable<string> EnumerateFiles (string path)
617                 {
618                         return EnumerateKind (path, "*", SearchOption.TopDirectoryOnly, FileAttributes.Normal);
619                 }
620
621                 public static System.Collections.Generic.IEnumerable<string> EnumerateFileSystemEntries (string path, string searchPattern, SearchOption searchOption)
622                 {
623                         return EnumerateKind (path, searchPattern, searchOption, FileAttributes.Normal | FileAttributes.Directory);
624                 }
625
626                 public static System.Collections.Generic.IEnumerable<string> EnumerateFileSystemEntries (string path, string searchPattern)
627                 {
628                         return EnumerateKind (path, searchPattern, SearchOption.TopDirectoryOnly, FileAttributes.Normal | FileAttributes.Directory);
629                 }
630
631                 public static System.Collections.Generic.IEnumerable<string> EnumerateFileSystemEntries (string path)
632                 {
633                         return EnumerateKind (path, "*", SearchOption.TopDirectoryOnly, FileAttributes.Normal | FileAttributes.Directory);
634                 }
635                 
636 #endif
637
638 #if !NET_2_1 || MONOTOUCH
639                 [MonoNotSupported ("DirectorySecurity isn't implemented")]
640                 public static DirectorySecurity GetAccessControl (string path, AccessControlSections includeSections)
641                 {
642                         throw new PlatformNotSupportedException ();
643                 }
644
645                 [MonoNotSupported ("DirectorySecurity isn't implemented")]
646                 public static DirectorySecurity GetAccessControl (string path)
647                 {
648                         throw new PlatformNotSupportedException ();
649                 }
650 #endif
651         }
652 }