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