Path handling fixes in File, Directory and Path including windows-specific negative...
[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.Runtime.InteropServices;
36 using System.Text;
37 #if NET_2_0
38 using System.Security.AccessControl;
39 #endif
40
41 namespace System.IO {
42         
43         [Serializable]
44 #if NET_2_0
45         [ComVisible (true)]
46 #endif
47         public sealed class DirectoryInfo : FileSystemInfo {
48
49                 private string current;
50                 private string parent;
51         
52                 public DirectoryInfo (string path)
53                 {
54                         CheckPath (path);
55
56                         FullPath = Path.GetFullPath (path);
57                         OriginalPath = path;
58
59                         int len = FullPath.Length - 1;
60                         if ((len > 1) && (FullPath [len] == Path.DirectorySeparatorChar))
61                                 len--;
62                         int last = FullPath.LastIndexOf (Path.DirectorySeparatorChar, len);
63                         if ((last == -1) || ((last == 0) && (len == 0))) {
64                                 current = FullPath;
65                                 parent = null;
66                         } else {
67                                 current = FullPath.Substring (last + 1, len - last);
68                                 if (last == 0 && !Environment.IsRunningOnWindows)
69                                         parent = Path.DirectorySeparatorStr;
70                                 else
71                                         parent = FullPath.Substring (0, last);
72                                 // adjust for drives, i.e. a special case for windows
73                                 if (Environment.IsRunningOnWindows) {
74                                         if ((parent.Length == 2) && (parent [1] == ':') && Char.IsLetter (parent [0]))
75                                                 parent += Path.DirectorySeparatorChar;
76                                 }
77                         }
78                 }
79
80                 // properties
81
82                 public override bool Exists {
83                         get {
84                                 Refresh (false);
85
86                                 if (stat.Attributes == MonoIO.InvalidFileAttributes)
87                                         return false;
88
89                                 if ((stat.Attributes & FileAttributes.Directory) == 0)
90                                         return false;
91
92                                 return true;
93                         }
94                 }
95
96                 public override string Name {
97                         get { return current; }
98                 }
99
100                 public DirectoryInfo Parent {
101                         get {
102                                 if ((parent == null) || (parent.Length == 0))
103                                         return null;
104                                 return new DirectoryInfo (parent);
105                         }
106                 }
107
108                 public DirectoryInfo Root {
109                         get {
110                                 string root = Path.GetPathRoot (FullPath);
111                                 if (root == null)
112                                         return null;
113
114                                 return new DirectoryInfo (root);
115                         }
116                 }
117
118                 // creational methods
119
120                 public void Create () {
121                         Directory.CreateDirectory (FullPath);
122                 }
123
124                 public DirectoryInfo CreateSubdirectory (string name) {
125                         CheckPath (name);
126                         
127                         if (Path.IsPathRooted (name))
128                                 throw new ArgumentException ();
129
130                         if (Environment.IsRunningOnWindows)
131                                 if (name.IndexOf (':') != -1)
132                                         throw new NotSupportedException ("The given path's format is not supported.");
133                         
134                         string path = Path.Combine (FullPath, name);
135
136                         string subdirectoryPath = Path.GetFullPath (path);
137
138                         if (!subdirectoryPath.StartsWith (FullPath))
139                                 throw new ArgumentException (String.Format ("The directory specified, '{0}', is not a subdirectory of '{1}'.", name, FullPath));
140
141                         Directory.CreateDirectory (path);
142
143                         return new DirectoryInfo (path);
144                 }
145
146                 // directory listing methods
147
148                 public FileInfo [] GetFiles () {
149                         return GetFiles ("*");
150                 }
151
152                 public FileInfo [] GetFiles (string pattern)
153                 {
154                         string [] names = Directory.GetFiles (FullPath, pattern);
155
156                         FileInfo[] infos = new FileInfo [names.Length];
157                         int i = 0;
158                         foreach (string name in names)
159                                 infos [i++] = new FileInfo (name);
160
161                         return infos;
162                 }
163
164                 public DirectoryInfo [] GetDirectories () {
165                         return GetDirectories ("*");
166                 }
167
168                 public DirectoryInfo [] GetDirectories (string pattern)
169                 {
170                         string [] names = Directory.GetDirectories (FullPath, pattern);
171
172                         DirectoryInfo[] infos = new DirectoryInfo [names.Length];
173                         int i = 0;
174                         foreach (string name in names)
175                                 infos [i++] = new DirectoryInfo (name);
176
177                         return infos;
178                 }
179
180                 public FileSystemInfo [] GetFileSystemInfos () {
181                         return GetFileSystemInfos ("*");
182                 }
183
184                 public FileSystemInfo [] GetFileSystemInfos (string pattern)
185                 {
186                         string[] dirs = Directory.GetDirectories (FullPath, pattern);
187                         string[] files = Directory.GetFiles (FullPath, pattern);
188
189                         FileSystemInfo[] infos = new FileSystemInfo [dirs.Length + files.Length];
190                         int i = 0;
191                         foreach (string dir in dirs)
192                                 infos [i++] = new DirectoryInfo (dir);
193                         foreach (string file in files)
194                                 infos [i++] = new FileInfo (file);
195
196                         return infos;
197                 }
198
199                 // directory management methods
200
201                 public override void Delete () {
202                         Delete (false);
203                 }
204
205                 public void Delete (bool recurse) {
206                         Directory.Delete (FullPath, recurse);
207                 }
208
209                 public void MoveTo (string dest) {
210                         Directory.Move (FullPath, Path.GetFullPath (dest));
211                         this.FullPath = Path.GetFullPath (dest);
212                 }
213
214                 public override string ToString () {
215                         return OriginalPath;
216                 }
217 #if NET_2_0
218                 // additional search methods
219
220                 public DirectoryInfo[] GetDirectories (string pattern, SearchOption searchOption)
221                 {
222                         switch (searchOption) {
223                         case SearchOption.TopDirectoryOnly:
224                                 return GetDirectories (pattern);
225                         case SearchOption.AllDirectories:
226                                 Queue workq = new Queue(GetDirectories(pattern));
227                                 Queue doneq = new Queue();
228                                 while (workq.Count > 0)
229                                         {
230                                                 DirectoryInfo cinfo = (DirectoryInfo) workq.Dequeue();
231                                                 DirectoryInfo[] cinfoDirs = cinfo.GetDirectories(pattern);
232                                                 foreach (DirectoryInfo i in cinfoDirs) workq.Enqueue(i);
233                                                 doneq.Enqueue(cinfo);
234                                         }
235
236                                 DirectoryInfo[] infos = new DirectoryInfo[doneq.Count];
237                                 doneq.CopyTo(infos, 0);
238                                 return infos;
239                         default:
240                                 string msg = Locale.GetText ("Invalid enum value '{0}' for '{1}'.", searchOption, "SearchOption");
241                                 throw new ArgumentOutOfRangeException ("searchOption", msg);
242                         }
243                 }       
244
245                 internal int GetFilesSubdirs (ArrayList l, string pattern)
246                 {
247                         int count;
248                         FileInfo [] thisdir = null;
249
250                         try {
251                                 thisdir = GetFiles (pattern);
252                         } catch (System.UnauthorizedAccessException){
253                                 return 0;
254                         }
255                         
256                         count = thisdir.Length;
257                         l.Add (thisdir);
258
259                         foreach (DirectoryInfo subdir in GetDirectories ()){
260                                 count += subdir.GetFilesSubdirs (l, pattern);
261                         }
262                         return count;
263                 }
264                 
265                 public FileInfo[] GetFiles (string pattern, SearchOption searchOption)
266                 {
267                         switch (searchOption) {
268                         case SearchOption.TopDirectoryOnly:
269                                 return GetFiles (pattern);
270                         case SearchOption.AllDirectories: {
271                                 ArrayList groups = new ArrayList ();
272                                 int count = GetFilesSubdirs (groups, pattern);
273                                 int current = 0;
274                                 
275                                 FileInfo [] all = new FileInfo [count];
276                                 foreach (FileInfo [] p in groups){
277                                         p.CopyTo (all, current);
278                                         current += p.Length;
279                                 }
280                                 return all;
281                         }
282                         default:
283                                 string msg = Locale.GetText ("Invalid enum value '{0}' for '{1}'.", searchOption, "SearchOption");
284                                 throw new ArgumentOutOfRangeException ("searchOption", msg);
285                         }
286                 }
287
288                 // access control methods
289
290                 [MonoTODO ("DirectorySecurity isn't implemented")]
291                 public void Create (DirectorySecurity directorySecurity)
292                 {
293                         if (directorySecurity != null)
294                                 throw new UnauthorizedAccessException ();
295                         Create ();
296                 }
297
298                 [MonoTODO ("Mono provides no support for DirectorySecurity")]
299                 public DirectoryInfo CreateSubdirectory (string name, DirectorySecurity directorySecurity)
300                 {
301                         if (directorySecurity != null)
302                                 throw new UnauthorizedAccessException ();
303                         return CreateSubdirectory (name);
304                 }
305
306                 [MonoTODO ("Mono provides no support for this")]
307                 public DirectorySecurity GetAccessControl ()
308                 {
309                         throw new UnauthorizedAccessException ();
310                 }
311
312                 [MonoTODO ("Mono provides no support for this")]
313                 public DirectorySecurity GetAccessControl (AccessControlSections includeSections)
314                 {
315                         throw new UnauthorizedAccessException ();
316                 }
317
318                 [MonoTODO ("Mono provides no support for this")]
319                 public void SetAccessControl (DirectorySecurity directorySecurity)
320                 {
321                         if (directorySecurity != null)
322                                 throw new ArgumentNullException ("directorySecurity");
323                         throw new UnauthorizedAccessException ();
324                 }
325 #endif
326         }
327 }