[coop] Temporarily restore MonoThreadInfo when TLS destructor runs. Fixes #43099
[mono.git] / mcs / class / referencesource / mscorlib / system / io / directoryinfo.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 /*============================================================
7 **
8 ** Class:  DirectoryInfo
9 ** 
10 ** <OWNER>[....]</OWNER>
11 **
12 **
13 ** Purpose: Exposes routines for enumerating through a 
14 ** directory.
15 **
16 **          April 11,2000
17 **
18 ===========================================================*/
19
20 using System;
21 using System.Collections;
22 using System.Collections.Generic;
23 using System.Security;
24 #if FEATURE_MACL
25 using System.Security.AccessControl;
26 #endif
27 using System.Security.Permissions;
28 using Microsoft.Win32;
29 using System.Text;
30 using System.Runtime.InteropServices;
31 using System.Globalization;
32 using System.Runtime.Serialization;
33 using System.Runtime.Versioning;
34 using System.Diagnostics.Contracts;
35
36 namespace System.IO {
37     [Serializable]
38     [ComVisible(true)]
39     public sealed class DirectoryInfo : FileSystemInfo {
40         private String[] demandDir;
41
42 #if FEATURE_CORECLR
43          // Migrating InheritanceDemands requires this default ctor, so we can annotate it.
44 #if FEATURE_CORESYSTEM
45         [System.Security.SecurityCritical]
46 #else
47         [System.Security.SecuritySafeCritical]
48 #endif //FEATURE_CORESYSTEM
49         private DirectoryInfo(){}
50
51
52         [System.Security.SecurityCritical]
53         [ResourceExposure(ResourceScope.Machine)]
54         [ResourceConsumption(ResourceScope.Machine)]
55         public static DirectoryInfo UnsafeCreateDirectoryInfo(String path)
56         {
57             if (path == null)
58                 throw new ArgumentNullException("path");
59             Contract.EndContractBlock();
60
61             DirectoryInfo di = new DirectoryInfo();
62             di.Init(path, false);
63             return di;
64         }
65 #endif
66
67         [System.Security.SecuritySafeCritical]
68         [ResourceExposure(ResourceScope.Machine)]
69         [ResourceConsumption(ResourceScope.Machine)]
70         public DirectoryInfo(String path)
71         {
72             if (path==null)
73                 throw new ArgumentNullException("path");
74             Contract.EndContractBlock();
75
76             Init(path, true);
77         }
78
79         [System.Security.SecurityCritical]
80         [ResourceExposure(ResourceScope.Machine)]
81         [ResourceConsumption(ResourceScope.Machine)]
82         private void Init(String path, bool checkHost)
83         {
84             // Special case "<DriveLetter>:" to point to "<CurrentDirectory>" instead
85             if ((path.Length == 2) && (path[1] == ':'))
86             {
87                 OriginalPath = ".";
88             }
89             else
90             {
91                 OriginalPath = path;
92             }
93
94             // Must fully qualify the path for the security check
95             String fullPath = Path.GetFullPathInternal(path);
96
97             demandDir = new String[] {Directory.GetDemandDir(fullPath, true)};
98 #if FEATURE_CORECLR
99             if (checkHost)
100             {
101                 FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Read, OriginalPath, fullPath);
102                 state.EnsureState();
103             }
104 #else
105             new FileIOPermission(FileIOPermissionAccess.Read, demandDir, false, false ).Demand();
106 #endif
107
108             FullPath = fullPath;
109             DisplayPath = GetDisplayName(OriginalPath, FullPath);
110         }
111
112         [ResourceExposure(ResourceScope.Machine)]
113         [ResourceConsumption(ResourceScope.Machine)]
114 #if FEATURE_CORESYSTEM
115         [System.Security.SecuritySafeCritical]
116 #endif //FEATURE_CORESYSTEM
117         internal DirectoryInfo(String fullPath, bool junk)
118         {
119             Contract.Assert(Path.GetRootLength(fullPath) > 0, "fullPath must be fully qualified!");
120             // Fast path when we know a DirectoryInfo exists.
121             OriginalPath = Path.GetFileName(fullPath);
122
123             FullPath = fullPath;
124             DisplayPath = GetDisplayName(OriginalPath, FullPath);
125             demandDir = new String[] {Directory.GetDemandDir(fullPath, true)};
126         }
127
128         [System.Security.SecurityCritical]  // auto-generated
129         private DirectoryInfo(SerializationInfo info, StreamingContext context) : base(info, context)
130         {
131 #if !FEATURE_CORECLR
132             demandDir = new String[] {Directory.GetDemandDir(FullPath, true)};
133             new FileIOPermission(FileIOPermissionAccess.Read, demandDir, false, false ).Demand();
134 #endif
135             DisplayPath = GetDisplayName(OriginalPath, FullPath);
136         }
137
138         public override String Name {
139             [ResourceExposure(ResourceScope.Machine)]
140             [ResourceConsumption(ResourceScope.Machine)]
141             get 
142             {
143 #if FEATURE_CORECLR
144                 // DisplayPath is dir name for coreclr
145                 return DisplayPath;
146 #else
147                 // Return just dir name
148                 return GetDirName(FullPath);
149 #endif
150             }
151         }
152
153         public DirectoryInfo Parent {
154             [System.Security.SecuritySafeCritical]
155             [ResourceExposure(ResourceScope.Machine)]
156             [ResourceConsumption(ResourceScope.Machine)]
157             get {
158                 String parentName;
159                 // FullPath might be either "c:\bar" or "c:\bar\".  Handle 
160                 // those cases, as well as avoiding mangling "c:\".
161                 String s = FullPath;
162                 if (s.Length > 3 && s.EndsWith(Path.DirectorySeparatorChar))
163                     s = FullPath.Substring(0, FullPath.Length - 1);                
164                 parentName = Path.GetDirectoryName(s);
165                 if (parentName==null)
166                     return null;
167                 DirectoryInfo dir = new DirectoryInfo(parentName,false);
168 #if FEATURE_CORECLR
169                 FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.PathDiscovery | FileSecurityStateAccess.Read, String.Empty, dir.demandDir[0]);
170                 state.EnsureState();
171 #else
172                 new FileIOPermission(FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read, dir.demandDir, false, false).Demand();
173 #endif
174                 return dir;
175             }
176         }
177
178       
179         [ResourceExposure(ResourceScope.Machine)]
180         [ResourceConsumption(ResourceScope.Machine)]
181 #if FEATURE_CORECLR
182         [System.Security.SecuritySafeCritical]
183 #endif
184         public DirectoryInfo CreateSubdirectory(String path) {
185             if (path == null)
186                 throw new ArgumentNullException("path");
187             Contract.EndContractBlock();
188
189             return CreateSubdirectory(path, null);
190         }
191
192 #if FEATURE_MACL
193         [System.Security.SecuritySafeCritical]  // auto-generated
194         [ResourceExposure(ResourceScope.Machine)]
195         [ResourceConsumption(ResourceScope.Machine)]
196         public DirectoryInfo CreateSubdirectory(String path, DirectorySecurity directorySecurity)
197         {
198             return CreateSubdirectoryHelper(path, directorySecurity);
199         }
200 #else  // FEATURE_MACL
201         #if FEATURE_CORECLR
202         [System.Security.SecurityCritical] // auto-generated
203         #endif
204         [ResourceExposure(ResourceScope.Machine)]
205         [ResourceConsumption(ResourceScope.Machine)]
206         public DirectoryInfo CreateSubdirectory(String path, Object directorySecurity)
207         {
208             if (path == null)
209                 throw new ArgumentNullException("path");
210             Contract.EndContractBlock();
211
212             return CreateSubdirectoryHelper(path, directorySecurity);
213         }
214 #endif // FEATURE_MACL
215
216         [System.Security.SecurityCritical]  // auto-generated
217         [ResourceExposure(ResourceScope.Machine)]
218         [ResourceConsumption(ResourceScope.Machine)]
219         private DirectoryInfo CreateSubdirectoryHelper(String path, Object directorySecurity)
220         {
221             Contract.Requires(path != null);
222
223             String newDirs = Path.InternalCombine(FullPath, path);
224             String fullPath = Path.GetFullPathInternal(newDirs);
225
226             if (0!=String.Compare(FullPath,0,fullPath,0, FullPath.Length,StringComparison.OrdinalIgnoreCase)) {
227                 String displayPath = __Error.GetDisplayablePath(DisplayPath, false);
228                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidSubPath", path, displayPath));
229             }
230
231             // Ensure we have permission to create this subdirectory.
232             String demandDirForCreation = Directory.GetDemandDir(fullPath, true);
233 #if FEATURE_CORECLR
234             FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Write, OriginalPath, demandDirForCreation);
235             state.EnsureState();
236 #else
237             new FileIOPermission(FileIOPermissionAccess.Write, new String[] { demandDirForCreation }, false, false).Demand();
238 #endif
239
240             Directory.InternalCreateDirectory(fullPath, path, directorySecurity);
241
242             // Check for read permission to directory we hand back by calling this constructor.
243             return new DirectoryInfo(fullPath);
244         }
245
246         [ResourceExposure(ResourceScope.None)]
247         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
248         public void Create()
249         {
250             Directory.InternalCreateDirectory(FullPath, OriginalPath, null, true);
251         }
252
253 #if FEATURE_MACL
254         [ResourceExposure(ResourceScope.None)]
255         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
256         public void Create(DirectorySecurity directorySecurity)
257         {
258             Directory.InternalCreateDirectory(FullPath, OriginalPath, directorySecurity, true);
259         }
260 #endif
261
262         // Tests if the given path refers to an existing DirectoryInfo on disk.
263         // 
264         // Your application must have Read permission to the directory's
265         // contents.
266         //
267         public override bool Exists {
268             [System.Security.SecuritySafeCritical]  // auto-generated
269             get
270             {
271                 try
272                 {
273                     if (_dataInitialised == -1)
274                         Refresh();
275                     if (_dataInitialised != 0) // Refresh was unable to initialise the data
276                         return false;
277                    
278                     return _data.fileAttributes != -1 && (_data.fileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY) != 0;
279                 }
280                 catch
281                 {
282                     return false;
283                 }
284             }
285         }
286       
287 #if FEATURE_MACL
288         [ResourceExposure(ResourceScope.None)]
289         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
290         public DirectorySecurity GetAccessControl()
291         {
292             return Directory.GetAccessControl(FullPath, AccessControlSections.Access | AccessControlSections.Owner | AccessControlSections.Group);
293         }
294
295         [ResourceExposure(ResourceScope.None)]
296         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
297         public DirectorySecurity GetAccessControl(AccessControlSections includeSections)
298         {
299             return Directory.GetAccessControl(FullPath, includeSections);
300         }
301
302         [ResourceExposure(ResourceScope.None)]
303         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
304         public void SetAccessControl(DirectorySecurity directorySecurity)
305         {
306             Directory.SetAccessControl(FullPath, directorySecurity);
307         }
308 #endif
309
310         // Returns an array of Files in the current DirectoryInfo matching the 
311         // given search criteria (ie, "*.txt").
312         [ResourceExposure(ResourceScope.Machine)]
313         [ResourceConsumption(ResourceScope.Machine)]
314         public FileInfo[] GetFiles(String searchPattern)
315         {
316             if (searchPattern == null)
317                 throw new ArgumentNullException("searchPattern");
318             Contract.EndContractBlock();
319
320             return InternalGetFiles(searchPattern, SearchOption.TopDirectoryOnly);
321         }
322
323         // Returns an array of Files in the current DirectoryInfo matching the 
324         // given search criteria (ie, "*.txt").
325         [ResourceExposure(ResourceScope.Machine)]
326         [ResourceConsumption(ResourceScope.Machine)]
327         public FileInfo[] GetFiles(String searchPattern, SearchOption searchOption)
328         {
329             if (searchPattern == null)
330                 throw new ArgumentNullException("searchPattern");
331             if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
332                 throw new ArgumentOutOfRangeException("searchOption", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
333             Contract.EndContractBlock();
334
335             return InternalGetFiles(searchPattern, searchOption);
336         }
337
338         // Returns an array of Files in the current DirectoryInfo matching the 
339         // given search criteria (ie, "*.txt").
340         [ResourceExposure(ResourceScope.Machine)]
341         [ResourceConsumption(ResourceScope.Machine)]
342         private FileInfo[] InternalGetFiles(String searchPattern, SearchOption searchOption)
343         {
344             Contract.Requires(searchPattern != null);
345             Contract.Requires(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
346
347             IEnumerable<FileInfo> enble = FileSystemEnumerableFactory.CreateFileInfoIterator(FullPath, OriginalPath, searchPattern, searchOption);
348             List<FileInfo> fileList = new List<FileInfo>(enble);
349             return fileList.ToArray();
350         }
351
352         // Returns an array of Files in the DirectoryInfo specified by path
353         [ResourceExposure(ResourceScope.Machine)]
354         [ResourceConsumption(ResourceScope.Machine)]
355         public FileInfo[] GetFiles()
356         {
357             return InternalGetFiles("*", SearchOption.TopDirectoryOnly);
358         }
359
360         // Returns an array of Directories in the current directory.
361         [ResourceExposure(ResourceScope.Machine)]
362         [ResourceConsumption(ResourceScope.Machine)]
363         public DirectoryInfo[] GetDirectories()
364         {
365             return InternalGetDirectories("*", SearchOption.TopDirectoryOnly);
366         }
367
368         // Returns an array of strongly typed FileSystemInfo entries in the path with the
369         // given search criteria (ie, "*.txt").
370         [ResourceExposure(ResourceScope.Machine)]
371         [ResourceConsumption(ResourceScope.Machine)]
372         public FileSystemInfo[] GetFileSystemInfos(String searchPattern)
373         {
374             if (searchPattern == null)
375                 throw new ArgumentNullException("searchPattern");
376             Contract.EndContractBlock();
377
378             return InternalGetFileSystemInfos(searchPattern, SearchOption.TopDirectoryOnly);
379         }
380
381         // Returns an array of strongly typed FileSystemInfo entries in the path with the
382         // given search criteria (ie, "*.txt").
383         [ResourceExposure(ResourceScope.Machine)]
384         [ResourceConsumption(ResourceScope.Machine)]
385         public FileSystemInfo[] GetFileSystemInfos(String searchPattern, SearchOption searchOption)
386         {
387             if (searchPattern == null)
388                 throw new ArgumentNullException("searchPattern");
389             if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
390                 throw new ArgumentOutOfRangeException("searchOption", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
391             Contract.EndContractBlock();
392
393             return InternalGetFileSystemInfos(searchPattern, searchOption);
394         }
395
396         // Returns an array of strongly typed FileSystemInfo entries in the path with the
397         // given search criteria (ie, "*.txt").
398         [ResourceExposure(ResourceScope.Machine)]
399         [ResourceConsumption(ResourceScope.Machine)]
400         private FileSystemInfo[] InternalGetFileSystemInfos(String searchPattern, SearchOption searchOption)
401         {
402             Contract.Requires(searchPattern != null);
403             Contract.Requires(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
404
405             IEnumerable<FileSystemInfo> enble = FileSystemEnumerableFactory.CreateFileSystemInfoIterator(FullPath, OriginalPath, searchPattern, searchOption);
406             List<FileSystemInfo> fileList = new List<FileSystemInfo>(enble);
407             return fileList.ToArray();
408         }
409
410         // Returns an array of strongly typed FileSystemInfo entries which will contain a listing
411         // of all the files and directories.
412         [ResourceExposure(ResourceScope.Machine)]
413         [ResourceConsumption(ResourceScope.Machine)]
414         public FileSystemInfo[] GetFileSystemInfos()
415         {
416             return InternalGetFileSystemInfos("*", SearchOption.TopDirectoryOnly);
417         }
418
419         // Returns an array of Directories in the current DirectoryInfo matching the 
420         // given search criteria (ie, "System*" could match the System & System32
421         // directories).
422         [ResourceExposure(ResourceScope.Machine)]
423         [ResourceConsumption(ResourceScope.Machine)]
424         public DirectoryInfo[] GetDirectories(String searchPattern)
425         {
426             if (searchPattern == null)
427                 throw new ArgumentNullException("searchPattern");
428             Contract.EndContractBlock();
429
430             return InternalGetDirectories(searchPattern, SearchOption.TopDirectoryOnly);
431         }
432
433         // Returns an array of Directories in the current DirectoryInfo matching the 
434         // given search criteria (ie, "System*" could match the System & System32
435         // directories).
436         [ResourceExposure(ResourceScope.Machine)]
437         [ResourceConsumption(ResourceScope.Machine)]
438         public DirectoryInfo[] GetDirectories(String searchPattern, SearchOption searchOption)
439         {
440             if (searchPattern == null)
441                 throw new ArgumentNullException("searchPattern");
442             if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
443                 throw new ArgumentOutOfRangeException("searchOption", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
444             Contract.EndContractBlock();
445
446             return InternalGetDirectories(searchPattern, searchOption);
447         }
448
449         // Returns an array of Directories in the current DirectoryInfo matching the 
450         // given search criteria (ie, "System*" could match the System & System32
451         // directories).
452         [ResourceExposure(ResourceScope.Machine)]
453         [ResourceConsumption(ResourceScope.Machine)]
454         private DirectoryInfo[] InternalGetDirectories(String searchPattern, SearchOption searchOption)
455         {
456             Contract.Requires(searchPattern != null);
457             Contract.Requires(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
458
459             IEnumerable<DirectoryInfo> enble = FileSystemEnumerableFactory.CreateDirectoryInfoIterator(FullPath, OriginalPath, searchPattern, searchOption);
460             List<DirectoryInfo> fileList = new List<DirectoryInfo>(enble);
461             return fileList.ToArray();
462         }
463
464         [ResourceExposure(ResourceScope.Machine)]
465         [ResourceConsumption(ResourceScope.Machine)]
466         public IEnumerable<DirectoryInfo> EnumerateDirectories()
467         {
468             return InternalEnumerateDirectories("*", SearchOption.TopDirectoryOnly);
469         }
470
471         [ResourceExposure(ResourceScope.Machine)]
472         [ResourceConsumption(ResourceScope.Machine)]
473         public IEnumerable<DirectoryInfo> EnumerateDirectories(String searchPattern)
474         {
475             if (searchPattern == null)
476                 throw new ArgumentNullException("searchPattern");
477             Contract.EndContractBlock();
478
479             return InternalEnumerateDirectories(searchPattern, SearchOption.TopDirectoryOnly);
480         }
481
482         [ResourceExposure(ResourceScope.Machine)]
483         [ResourceConsumption(ResourceScope.Machine)]
484         public IEnumerable<DirectoryInfo> EnumerateDirectories(String searchPattern, SearchOption searchOption)
485         {
486             if (searchPattern == null)
487                 throw new ArgumentNullException("searchPattern");
488             if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
489                 throw new ArgumentOutOfRangeException("searchOption", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
490             Contract.EndContractBlock();
491
492             return InternalEnumerateDirectories(searchPattern, searchOption);
493         }
494
495         [ResourceExposure(ResourceScope.Machine)]
496         [ResourceConsumption(ResourceScope.Machine)]
497         private IEnumerable<DirectoryInfo> InternalEnumerateDirectories(String searchPattern, SearchOption searchOption)
498         {
499             Contract.Requires(searchPattern != null);
500             Contract.Requires(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
501
502             return FileSystemEnumerableFactory.CreateDirectoryInfoIterator(FullPath, OriginalPath, searchPattern, searchOption);
503         }
504
505         [ResourceExposure(ResourceScope.Machine)]
506         [ResourceConsumption(ResourceScope.Machine)]
507         public IEnumerable<FileInfo> EnumerateFiles()
508         {
509             return InternalEnumerateFiles("*", SearchOption.TopDirectoryOnly);
510         }
511
512         [ResourceExposure(ResourceScope.Machine)]
513         [ResourceConsumption(ResourceScope.Machine)]
514         public IEnumerable<FileInfo> EnumerateFiles(String searchPattern)
515         {
516             if (searchPattern == null)
517                 throw new ArgumentNullException("searchPattern");
518             Contract.EndContractBlock();
519
520             return InternalEnumerateFiles(searchPattern, SearchOption.TopDirectoryOnly);
521         }
522
523         [ResourceExposure(ResourceScope.Machine)]
524         [ResourceConsumption(ResourceScope.Machine)]
525         public IEnumerable<FileInfo> EnumerateFiles(String searchPattern, SearchOption searchOption)
526         {
527             if (searchPattern == null)
528                 throw new ArgumentNullException("searchPattern");
529             if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
530                 throw new ArgumentOutOfRangeException("searchOption", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
531             Contract.EndContractBlock();
532
533             return InternalEnumerateFiles(searchPattern, searchOption);
534         }
535
536         [ResourceExposure(ResourceScope.Machine)]
537         [ResourceConsumption(ResourceScope.Machine)]
538         private IEnumerable<FileInfo> InternalEnumerateFiles(String searchPattern, SearchOption searchOption)
539         {
540             Contract.Requires(searchPattern != null);
541             Contract.Requires(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
542
543             return FileSystemEnumerableFactory.CreateFileInfoIterator(FullPath, OriginalPath, searchPattern, searchOption);
544         }
545
546         [ResourceExposure(ResourceScope.Machine)]
547         [ResourceConsumption(ResourceScope.Machine)]
548         public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos()
549         {
550             return InternalEnumerateFileSystemInfos("*", SearchOption.TopDirectoryOnly);
551         }
552
553         [ResourceExposure(ResourceScope.Machine)]
554         [ResourceConsumption(ResourceScope.Machine)]
555         public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos(String searchPattern)
556         {
557             if (searchPattern == null)
558                 throw new ArgumentNullException("searchPattern");
559             Contract.EndContractBlock();
560
561             return InternalEnumerateFileSystemInfos(searchPattern, SearchOption.TopDirectoryOnly);
562         }
563
564         [ResourceExposure(ResourceScope.Machine)]
565         [ResourceConsumption(ResourceScope.Machine)]
566         public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos(String searchPattern, SearchOption searchOption)
567         {
568             if (searchPattern == null)
569                 throw new ArgumentNullException("searchPattern");
570             if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
571                 throw new ArgumentOutOfRangeException("searchOption", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
572             Contract.EndContractBlock();
573
574             return InternalEnumerateFileSystemInfos(searchPattern, searchOption);
575         }
576
577         [ResourceExposure(ResourceScope.Machine)]
578         [ResourceConsumption(ResourceScope.Machine)]
579         private IEnumerable<FileSystemInfo> InternalEnumerateFileSystemInfos(String searchPattern, SearchOption searchOption)
580         {
581             Contract.Requires(searchPattern != null);
582             Contract.Requires(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
583
584             return FileSystemEnumerableFactory.CreateFileSystemInfoIterator(FullPath, OriginalPath, searchPattern, searchOption);
585         }
586         
587         // Returns the root portion of the given path. The resulting string
588         // consists of those rightmost characters of the path that constitute the
589         // root of the path. Possible patterns for the resulting string are: An
590         // empty string (a relative path on the current drive), "\" (an absolute
591         // path on the current drive), "X:" (a relative path on a given drive,
592         // where X is the drive letter), "X:\" (an absolute path on a given drive),
593         // and "\\server\share" (a UNC path for a given server and share name).
594         // The resulting string is null if path is null.
595         //
596
597         public DirectoryInfo Root {
598             [System.Security.SecuritySafeCritical]
599             [ResourceExposure(ResourceScope.None)]
600             [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
601             get
602             {
603                 String demandPath;
604                 int rootLength = Path.GetRootLength(FullPath);
605                 String rootPath = FullPath.Substring(0, rootLength);
606                 demandPath = Directory.GetDemandDir(rootPath, true);
607
608 #if FEATURE_CORECLR
609                 FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, demandPath);
610                 sourceState.EnsureState();
611 #else
612                 new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { demandPath }, false, false).Demand();
613 #endif
614                 return new DirectoryInfo(rootPath);
615             }
616         }
617
618         [System.Security.SecuritySafeCritical]
619         [ResourceExposure(ResourceScope.Machine)]
620         [ResourceConsumption(ResourceScope.Machine)]
621         public void MoveTo(String destDirName) {
622             if (destDirName==null)
623                 throw new ArgumentNullException("destDirName");
624             if (destDirName.Length==0)
625                 throw new ArgumentException(Environment.GetResourceString("Argument_EmptyFileName"), "destDirName");
626             Contract.EndContractBlock();
627             
628 #if FEATURE_CORECLR
629             FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.Write | FileSecurityStateAccess.Read, DisplayPath, Directory.GetDemandDir(FullPath, true));
630             sourceState.EnsureState();
631 #else
632             new FileIOPermission(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, demandDir, false, false).Demand();
633 #endif
634             String fullDestDirName = Path.GetFullPathInternal(destDirName);
635             String demandPath;
636             if (!fullDestDirName.EndsWith(Path.DirectorySeparatorChar))
637                 fullDestDirName = fullDestDirName + Path.DirectorySeparatorChar;
638
639             demandPath = fullDestDirName + '.';
640
641             // Demand read & write permission to destination.  The reason is
642             // we hand back a DirectoryInfo to the destination that would allow
643             // you to read a directory listing from that directory.  Sure, you 
644             // had the ability to read the file contents in the old location,
645             // but you technically also need read permissions to the new 
646             // location as well, and write is not a true superset of read.
647 #if FEATURE_CORECLR
648             FileSecurityState destState = new FileSecurityState(FileSecurityStateAccess.Write, destDirName, demandPath);
649             destState.EnsureState();
650 #else
651             new FileIOPermission(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, demandPath).Demand();
652 #endif
653             
654             String fullSourcePath;
655             if (FullPath.EndsWith(Path.DirectorySeparatorChar))
656                 fullSourcePath = FullPath;
657             else
658                 fullSourcePath = FullPath + Path.DirectorySeparatorChar;
659
660             if (String.Compare(fullSourcePath, fullDestDirName, StringComparison.OrdinalIgnoreCase) == 0)
661                 throw new IOException(Environment.GetResourceString("IO.IO_SourceDestMustBeDifferent"));
662
663             String sourceRoot = Path.GetPathRoot(fullSourcePath);
664             String destinationRoot = Path.GetPathRoot(fullDestDirName);
665
666             if (String.Compare(sourceRoot, destinationRoot, StringComparison.OrdinalIgnoreCase) != 0)
667                 throw new IOException(Environment.GetResourceString("IO.IO_SourceDestMustHaveSameRoot"));
668                        
669             if (!Win32Native.MoveFile(FullPath, destDirName))
670             {
671                 int hr = Marshal.GetLastWin32Error();
672                 if (hr == Win32Native.ERROR_FILE_NOT_FOUND) // A dubious error code
673                 {
674                     hr = Win32Native.ERROR_PATH_NOT_FOUND;
675                     __Error.WinIOError(hr, DisplayPath);
676                 }
677                 
678                 if (hr == Win32Native.ERROR_ACCESS_DENIED) // We did this for Win9x. We can't change it for backcomp. 
679                     throw new IOException(Environment.GetResourceString("UnauthorizedAccess_IODenied_Path", DisplayPath));
680             
681                 __Error.WinIOError(hr,String.Empty);
682             }
683             FullPath = fullDestDirName;
684             OriginalPath = destDirName;
685             DisplayPath = GetDisplayName(OriginalPath, FullPath);
686             demandDir = new String[] { Directory.GetDemandDir(FullPath, true) };
687
688             // Flush any cached information about the directory.
689             _dataInitialised = -1;
690         }
691
692         [System.Security.SecuritySafeCritical]
693         [ResourceExposure(ResourceScope.None)]
694         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
695         public override void Delete()
696         {
697             Directory.Delete(FullPath, OriginalPath, false, true);
698         }
699
700         [System.Security.SecuritySafeCritical]
701         [ResourceExposure(ResourceScope.None)]
702         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
703         public void Delete(bool recursive)
704         {
705             Directory.Delete(FullPath, OriginalPath, recursive, true);
706         }
707
708         // Returns the fully qualified path
709         public override String ToString()
710         {
711             return DisplayPath;
712         }
713
714         private static String GetDisplayName(String originalPath, String fullPath)
715         {
716             Contract.Assert(originalPath != null);
717             Contract.Assert(fullPath != null);
718
719             String displayName = "";
720
721             // Special case "<DriveLetter>:" to point to "<CurrentDirectory>" instead
722             if ((originalPath.Length == 2) && (originalPath[1] == ':'))
723             {
724                 displayName = ".";
725             }
726             else 
727             {
728 #if FEATURE_CORECLR
729                 displayName = GetDirName(fullPath);
730 #else
731                 displayName = originalPath;
732 #endif
733             }
734             return displayName;
735         }
736
737         private static String GetDirName(String fullPath)
738         {
739             Contract.Assert(fullPath != null);
740
741             String dirName = null;
742             if (fullPath.Length > 3)
743             {
744                 String s = fullPath;
745                 if (fullPath.EndsWith(Path.DirectorySeparatorChar))
746                 {
747                     s = fullPath.Substring(0, fullPath.Length - 1);
748                 }
749                 dirName = Path.GetFileName(s);
750             }
751             else
752             {
753                 dirName = fullPath;  // For rooted paths, like "c:\"
754             }
755             return dirName;
756         }
757
758     }       
759 }
760