Merge pull request #556 from jack-pappas/ipproto-patch
[mono.git] / mcs / class / corlib / System.IO / DirectoryInfo.cs
1 // 
2 // System.IO.DirectoryInfo.cs 
3 //
4 // Authors:
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>
9 //
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)
13 //
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:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
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.
32 //
33
34 using System.Collections;
35 using System.Collections.Generic;
36 using System.Runtime.InteropServices;
37 using System.Runtime.Serialization;
38 using System.Security;
39 using System.Text;
40 using System.Security.AccessControl;
41
42 namespace System.IO {
43         
44         [Serializable]
45         [ComVisible (true)]
46         public sealed class DirectoryInfo : FileSystemInfo {
47
48                 private string current;
49                 private string parent;
50         
51                 public DirectoryInfo (string path) : this (path, false)
52                 {
53                 }
54
55                 internal DirectoryInfo (string path, bool simpleOriginalPath)
56                 {
57                         CheckPath (path);
58
59                         SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
60
61                         FullPath = Path.GetFullPath (path);
62                         if (simpleOriginalPath)
63                                 OriginalPath = Path.GetFileName (path);
64                         else
65                                 OriginalPath = path;
66
67                         Initialize ();
68                 }
69
70                 private DirectoryInfo (SerializationInfo info, StreamingContext context)
71                         : base (info, context)
72                 {
73                         Initialize ();
74                 }
75
76                 void Initialize ()
77                 {
78                         int len = FullPath.Length - 1;
79                         if ((len > 1) && (FullPath [len] == Path.DirectorySeparatorChar))
80                                 len--;
81                         int last = FullPath.LastIndexOf (Path.DirectorySeparatorChar, len);
82                         if ((last == -1) || ((last == 0) && (len == 0))) {
83                                 current = FullPath;
84                                 parent = null;
85                         } else {
86                                 current = FullPath.Substring (last + 1, len - last);
87                                 if (last == 0 && !Environment.IsRunningOnWindows)
88                                         parent = Path.DirectorySeparatorStr;
89                                 else
90                                         parent = FullPath.Substring (0, last);
91                                 // adjust for drives, i.e. a special case for windows
92                                 if (Environment.IsRunningOnWindows) {
93                                         if ((parent.Length == 2) && (parent [1] == ':') && Char.IsLetter (parent [0]))
94                                                 parent += Path.DirectorySeparatorChar;
95                                 }
96                         }
97                 }
98
99                 // properties
100
101                 public override bool Exists {
102                         get {
103                                 Refresh (false);
104
105                                 if (stat.Attributes == MonoIO.InvalidFileAttributes)
106                                         return false;
107
108                                 if ((stat.Attributes & FileAttributes.Directory) == 0)
109                                         return false;
110
111                                 return true;
112                         }
113                 }
114
115                 public override string Name {
116                         get { return current; }
117                 }
118
119                 public DirectoryInfo Parent {
120                         get {
121                                 if ((parent == null) || (parent.Length == 0))
122                                         return null;
123                                 return new DirectoryInfo (parent);
124                         }
125                 }
126
127                 public DirectoryInfo Root {
128                         get {
129                                 string root = Path.GetPathRoot (FullPath);
130                                 if (root == null)
131                                         return null;
132
133                                 return new DirectoryInfo (root);
134                         }
135                 }
136
137                 // creational methods
138
139                 public void Create ()
140                 {
141                         Directory.CreateDirectory (FullPath);
142                 }
143
144                 public DirectoryInfo CreateSubdirectory (string path)
145                 {
146                         CheckPath (path);
147
148                         path = Path.Combine (FullPath, path);
149                         Directory.CreateDirectory (path);
150                         return new DirectoryInfo (path);
151                 }
152
153                 // directory listing methods
154
155                 public FileInfo [] GetFiles ()
156                 {
157                         return GetFiles ("*");
158                 }
159
160                 public FileInfo [] GetFiles (string searchPattern)
161                 {
162                         if (searchPattern == null)
163                                 throw new ArgumentNullException ("searchPattern");
164
165                         string [] names = Directory.GetFiles (FullPath, searchPattern);
166
167                         FileInfo[] infos = new FileInfo [names.Length];
168                         int i = 0;
169                         foreach (string name in names)
170                                 infos [i++] = new FileInfo (name);
171
172                         return infos;
173                 }
174
175                 public DirectoryInfo [] GetDirectories ()
176                 {
177                         return GetDirectories ("*");
178                 }
179
180                 public DirectoryInfo [] GetDirectories (string searchPattern)
181                 {
182                         if (searchPattern == null)
183                                 throw new ArgumentNullException ("searchPattern");
184
185                         string [] names = Directory.GetDirectories (FullPath, searchPattern);
186
187                         DirectoryInfo[] infos = new DirectoryInfo [names.Length];
188                         int i = 0;
189                         foreach (string name in names)
190                                 infos [i++] = new DirectoryInfo (name);
191
192                         return infos;
193                 }
194
195                 public FileSystemInfo [] GetFileSystemInfos ()
196                 {
197                         return GetFileSystemInfos ("*");
198                 }
199
200                 public FileSystemInfo [] GetFileSystemInfos (string searchPattern)
201                 {
202                         return GetFileSystemInfos (searchPattern, SearchOption.TopDirectoryOnly);
203                 }
204
205 #if NET_4_0
206                 public
207 #endif
208                 FileSystemInfo [] GetFileSystemInfos (string searchPattern, SearchOption searchOption)
209                 {
210                         if (searchPattern == null)
211                                 throw new ArgumentNullException ("searchPattern");
212                         if (searchOption != SearchOption.TopDirectoryOnly && searchOption != SearchOption.AllDirectories)
213                                 throw new ArgumentOutOfRangeException ("searchOption", "Must be TopDirectoryOnly or AllDirectories");
214                         if (!Directory.Exists (FullPath))
215                                 throw new IOException ("Invalid directory");
216
217                         List<FileSystemInfo> infos = new List<FileSystemInfo> ();
218                         InternalGetFileSystemInfos (searchPattern, searchOption, infos);
219                         return infos.ToArray ();
220                 }
221
222                 void InternalGetFileSystemInfos (string searchPattern, SearchOption searchOption, List<FileSystemInfo> infos)
223                 {
224                         // UnauthorizedAccessExceptions might happen here and break everything for SearchOption.AllDirectories
225                         string [] dirs = Directory.GetDirectories (FullPath, searchPattern);
226                         string [] files = Directory.GetFiles (FullPath, searchPattern);
227
228                         Array.ForEach<string> (dirs, (dir) => { infos.Add (new DirectoryInfo (dir)); });
229                         Array.ForEach<string> (files, (file) => { infos.Add (new FileInfo (file)); });
230                         if (dirs.Length == 0 || searchOption == SearchOption.TopDirectoryOnly)
231                                 return;
232
233                         foreach (string dir in dirs) {
234                                 DirectoryInfo dinfo = new DirectoryInfo (dir);
235                                 dinfo.InternalGetFileSystemInfos (searchPattern, searchOption, infos);
236                         }
237                 }
238
239                 // directory management methods
240
241                 public override void Delete ()
242                 {
243                         Delete (false);
244                 }
245
246                 public void Delete (bool recursive)
247                 {
248                         Directory.Delete (FullPath, recursive);
249                 }
250
251                 public void MoveTo (string destDirName)
252                 {
253                         if (destDirName == null)
254                                 throw new ArgumentNullException ("destDirName");
255                         if (destDirName.Length == 0)
256                                 throw new ArgumentException ("An empty file name is not valid.", "destDirName");
257
258                         Directory.Move (FullPath, Path.GetFullPath (destDirName));
259                         FullPath = OriginalPath = destDirName;
260                         Initialize ();
261                 }
262
263                 public override string ToString ()
264                 {
265                         return OriginalPath;
266                 }
267
268                 public DirectoryInfo[] GetDirectories (string searchPattern, SearchOption searchOption)
269                 {
270                     //NULL-check of searchPattern is done in Directory.GetDirectories
271                         string [] names = Directory.GetDirectories (FullPath, searchPattern, searchOption);
272                         //Convert the names to DirectoryInfo instances
273                         DirectoryInfo[] infos = new DirectoryInfo [names.Length];
274                         for (int i = 0; i<names.Length; ++i){
275                                 string name = names[i];
276                                 infos [i] = new DirectoryInfo (name);
277                         }
278                         return infos;
279                 }       
280
281                 internal int GetFilesSubdirs (ArrayList l, string pattern)
282                 {
283                         int count;
284                         FileInfo [] thisdir = null;
285
286                         try {
287                                 thisdir = GetFiles (pattern);
288                         } catch (System.UnauthorizedAccessException){
289                                 return 0;
290                         }
291                         
292                         count = thisdir.Length;
293                         l.Add (thisdir);
294
295                         foreach (DirectoryInfo subdir in GetDirectories ()){
296                                 count += subdir.GetFilesSubdirs (l, pattern);
297                         }
298                         return count;
299                 }
300                 
301                 public FileInfo[] GetFiles (string searchPattern, SearchOption searchOption)
302                 {
303                         switch (searchOption) {
304                         case SearchOption.TopDirectoryOnly:
305                                 return GetFiles (searchPattern);
306                         case SearchOption.AllDirectories: {
307                                 ArrayList groups = new ArrayList ();
308                                 int count = GetFilesSubdirs (groups, searchPattern);
309                                 int current = 0;
310                                 
311                                 FileInfo [] all = new FileInfo [count];
312                                 foreach (FileInfo [] p in groups){
313                                         p.CopyTo (all, current);
314                                         current += p.Length;
315                                 }
316                                 return all;
317                         }
318                         default:
319                                 string msg = Locale.GetText ("Invalid enum value '{0}' for '{1}'.", searchOption, "SearchOption");
320                                 throw new ArgumentOutOfRangeException ("searchOption", msg);
321                         }
322                 }
323
324                 // access control methods
325
326                 [MonoLimitation ("DirectorySecurity isn't implemented")]
327                 public void Create (DirectorySecurity directorySecurity)
328                 {
329                         if (directorySecurity != null)
330                                 throw new UnauthorizedAccessException ();
331                         Create ();
332                 }
333
334                 [MonoLimitation ("DirectorySecurity isn't implemented")]
335                 public DirectoryInfo CreateSubdirectory (string path, DirectorySecurity directorySecurity)
336                 {
337                         if (directorySecurity != null)
338                                 throw new UnauthorizedAccessException ();
339                         return CreateSubdirectory (path);
340                 }
341
342                 public DirectorySecurity GetAccessControl ()
343                 {
344                         return Directory.GetAccessControl (FullPath);
345                 }
346
347                 public DirectorySecurity GetAccessControl (AccessControlSections includeSections)
348                 {
349                         return Directory.GetAccessControl (FullPath, includeSections);
350                 }
351
352                 public void SetAccessControl (DirectorySecurity directorySecurity)
353                 {
354                         Directory.SetAccessControl (FullPath, directorySecurity);
355                 }
356
357 #if NET_4_0
358
359                 public IEnumerable<DirectoryInfo> EnumerateDirectories ()
360                 {
361                         return EnumerateDirectories ("*", SearchOption.TopDirectoryOnly);
362                 }
363
364                 public IEnumerable<DirectoryInfo> EnumerateDirectories (string searchPattern)
365                 {
366                         return EnumerateDirectories (searchPattern, SearchOption.TopDirectoryOnly);
367                 }
368
369                 public IEnumerable<DirectoryInfo> EnumerateDirectories (string searchPattern, SearchOption searchOption)
370                 {
371                         if (searchPattern == null)
372                                 throw new ArgumentNullException ("searchPattern");
373
374                         return CreateEnumerateDirectoriesIterator (searchPattern, searchOption);
375                 }
376
377                 IEnumerable<DirectoryInfo> CreateEnumerateDirectoriesIterator (string searchPattern, SearchOption searchOption)
378                 {
379                         foreach (string name in Directory.EnumerateDirectories (FullPath, searchPattern, searchOption))
380                                 yield return new DirectoryInfo (name);
381                 }
382
383                 public IEnumerable<FileInfo> EnumerateFiles ()
384                 {
385                         return EnumerateFiles ("*", SearchOption.TopDirectoryOnly);
386                 }
387
388                 public IEnumerable<FileInfo> EnumerateFiles (string searchPattern)
389                 {
390                         return EnumerateFiles (searchPattern, SearchOption.TopDirectoryOnly);
391                 }
392
393                 public IEnumerable<FileInfo> EnumerateFiles (string searchPattern, SearchOption searchOption)
394                 {
395                         if (searchPattern == null)
396                                 throw new ArgumentNullException ("searchPattern");
397
398                         return CreateEnumerateFilesIterator (searchPattern, searchOption);
399                 }
400
401                 IEnumerable<FileInfo> CreateEnumerateFilesIterator (string searchPattern, SearchOption searchOption)
402                 {
403                         foreach (string name in Directory.EnumerateFiles (FullPath, searchPattern, searchOption))
404                                 yield return new FileInfo (name);
405                 }
406
407                 public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos ()
408                 {
409                         return EnumerateFileSystemInfos ("*", SearchOption.TopDirectoryOnly);
410                 }
411
412                 public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos (string searchPattern)
413                 {
414                         return EnumerateFileSystemInfos (searchPattern, SearchOption.TopDirectoryOnly);
415                 }
416
417                 public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos (string searchPattern, SearchOption searchOption)
418                 {
419                         if (searchPattern == null)
420                                 throw new ArgumentNullException ("searchPattern");
421                         if (searchOption != SearchOption.TopDirectoryOnly && searchOption != SearchOption.AllDirectories)
422                                 throw new ArgumentOutOfRangeException ("searchoption");
423
424                         return EnumerateFileSystemInfos (FullPath, searchPattern, searchOption);
425                 }
426
427                 static internal IEnumerable<FileSystemInfo> EnumerateFileSystemInfos (string full, string searchPattern, SearchOption searchOption)
428                 {
429                         string path_with_pattern = Path.Combine (full, searchPattern);
430                         IntPtr handle;
431                         MonoIOError error;
432                         FileAttributes rattr;
433                         bool subdirs = searchOption == SearchOption.AllDirectories;
434
435                         Path.Validate (full);
436                         
437                         string s = MonoIO.FindFirst (full, path_with_pattern, out rattr, out error, out handle);
438                         if (s == null)
439                                 yield break;
440                         if (error != 0)
441                                 throw MonoIO.GetException (Path.GetDirectoryName (path_with_pattern), (MonoIOError) error);
442
443                         try {
444                                 if (((rattr & FileAttributes.ReparsePoint) == 0)){
445                                         if ((rattr & FileAttributes.Directory) != 0)
446                                                 yield return new DirectoryInfo (s);
447                                         else
448                                                 yield return new FileInfo (s);
449                                 }
450                                 
451                                 while ((s = MonoIO.FindNext (handle, out rattr, out error)) != null){
452                                         if ((rattr & FileAttributes.ReparsePoint) != 0)
453                                                 continue;
454                                         if ((rattr & FileAttributes.Directory) != 0)
455                                                 yield return new DirectoryInfo (s);
456                                         else
457                                                 yield return new FileInfo (s);
458                                         
459                                         if (((rattr & FileAttributes.Directory) != 0) && subdirs)
460                                                 foreach (FileSystemInfo child in EnumerateFileSystemInfos (s, searchPattern, searchOption))
461                                                         yield return child;
462                                 }
463                         } finally {
464                                 MonoIO.FindClose (handle);
465                         }
466                 }
467                 
468                 
469 #endif
470         }
471 }