3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 /*============================================================
10 ** <OWNER>[....]</OWNER>
13 ** Purpose: Exposes routines for enumerating through a
18 ===========================================================*/
21 using System.Collections;
22 using System.Collections.Generic;
23 using System.Security;
24 using System.Security.Permissions;
25 using Microsoft.Win32;
26 using Microsoft.Win32.SafeHandles;
28 using System.Runtime.InteropServices;
29 using System.Globalization;
30 using System.Runtime.Versioning;
31 using System.Diagnostics.Contracts;
32 using System.Threading;
35 using System.Security.AccessControl;
40 public static class Directory {
41 [ResourceExposure(ResourceScope.Machine)]
42 [ResourceConsumption(ResourceScope.Machine)]
43 public static DirectoryInfo GetParent(String path)
46 throw new ArgumentNullException("path");
49 throw new ArgumentException(Environment.GetResourceString("Argument_PathEmpty"), "path");
50 Contract.EndContractBlock();
52 String fullPath = Path.GetFullPathInternal(path);
54 String s = Path.GetDirectoryName(fullPath);
57 return new DirectoryInfo(s);
60 [System.Security.SecuritySafeCritical]
61 [ResourceExposure(ResourceScope.Machine)]
62 [ResourceConsumption(ResourceScope.Machine)]
63 public static DirectoryInfo CreateDirectory(String path) {
65 throw new ArgumentNullException("path");
67 throw new ArgumentException(Environment.GetResourceString("Argument_PathEmpty"));
68 Contract.EndContractBlock();
70 #if FEATURE_LEGACYNETCF
71 if(CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
72 System.Reflection.Assembly callingAssembly = System.Reflection.Assembly.GetCallingAssembly();
73 if(callingAssembly != null && !callingAssembly.IsProfileAssembly) {
74 string caller = new System.Diagnostics.StackFrame(1).GetMethod().FullName;
75 string callee = System.Reflection.MethodBase.GetCurrentMethod().FullName;
76 throw new MethodAccessException(String.Format(
77 CultureInfo.CurrentCulture,
78 Environment.GetResourceString("Arg_MethodAccessException_WithCaller"),
83 #endif // FEATURE_LEGACYNETCF
85 return InternalCreateDirectoryHelper(path, true);
88 [System.Security.SecurityCritical]
89 [ResourceExposure(ResourceScope.Machine)]
90 [ResourceConsumption(ResourceScope.Machine)]
91 internal static DirectoryInfo UnsafeCreateDirectory(String path)
94 throw new ArgumentNullException("path");
96 throw new ArgumentException(Environment.GetResourceString("Argument_PathEmpty"));
97 Contract.EndContractBlock();
99 return InternalCreateDirectoryHelper(path, false);
102 [System.Security.SecurityCritical]
103 [ResourceExposure(ResourceScope.Machine)]
104 [ResourceConsumption(ResourceScope.Machine)]
105 internal static DirectoryInfo InternalCreateDirectoryHelper(String path, bool checkHost)
107 Contract.Requires(path != null);
108 Contract.Requires(path.Length != 0);
110 String fullPath = Path.GetFullPathInternal(path);
112 // You need read access to the directory to be returned back and write access to all the directories
113 // that you need to create. If we fail any security checks we will not create any directories at all.
114 // We attempt to create directories only after all the security checks have passed. This is avoid doing
115 // a demand at every level.
116 String demandDir = GetDemandDir(fullPath, true);
121 FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Read, path, demandDir);
122 state.EnsureState(); // do the check on the AppDomainManager to make sure this is allowed
125 FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, demandDir, false, false);
128 InternalCreateDirectory(fullPath, path, null, checkHost);
130 return new DirectoryInfo(fullPath, false);
134 [System.Security.SecuritySafeCritical] // auto-generated
135 [ResourceExposure(ResourceScope.Machine)]
136 [ResourceConsumption(ResourceScope.Machine)]
137 public static DirectoryInfo CreateDirectory(String path, DirectorySecurity directorySecurity) {
139 throw new ArgumentNullException("path");
140 if (path.Length == 0)
141 throw new ArgumentException(Environment.GetResourceString("Argument_PathEmpty"));
142 Contract.EndContractBlock();
144 String fullPath = Path.GetFullPathInternal(path);
146 // You need read access to the directory to be returned back and write access to all the directories
147 // that you need to create. If we fail any security checks we will not create any directories at all.
148 // We attempt to create directories only after all the security checks have passed. This is avoid doing
149 // a demand at every level.
150 String demandDir = GetDemandDir(fullPath, true);
151 FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, demandDir, false, false );
153 InternalCreateDirectory(fullPath, path, directorySecurity);
155 return new DirectoryInfo(fullPath, false);
157 #endif // FEATURE_MACL
159 // Input to this method should already be fullpath. This method will ensure that we append
160 // the trailing slash only when appropriate and when thisDirOnly is specified append a "."
161 // at the end of the path to indicate that the demand is only for the fullpath and not
162 // everything underneath it.
163 [ResourceExposure(ResourceScope.None)]
164 [ResourceConsumption(ResourceScope.None, ResourceScope.None)]
165 internal static String GetDemandDir(string fullPath, bool thisDirOnly)
170 if (fullPath.EndsWith( Path.DirectorySeparatorChar )
171 || fullPath.EndsWith( Path.AltDirectorySeparatorChar ) )
172 demandPath = fullPath + ".";
174 demandPath = fullPath + Path.DirectorySeparatorCharAsString + ".";
177 if (!(fullPath.EndsWith( Path.DirectorySeparatorChar )
178 || fullPath.EndsWith( Path.AltDirectorySeparatorChar )) )
179 demandPath = fullPath + Path.DirectorySeparatorCharAsString;
181 demandPath = fullPath;
186 [ResourceExposure(ResourceScope.Machine)]
187 [ResourceConsumption(ResourceScope.Machine)]
188 internal static void InternalCreateDirectory(String fullPath, String path, Object dirSecurityObj)
190 InternalCreateDirectory(fullPath, path, dirSecurityObj, false);
194 [System.Security.SecuritySafeCritical]
195 [ResourceExposure(ResourceScope.Machine)]
196 [ResourceConsumption(ResourceScope.Machine)]
197 internal unsafe static void InternalCreateDirectory(String fullPath, String path, Object dirSecurityObj, bool checkHost)
200 DirectorySecurity dirSecurity = (DirectorySecurity)dirSecurityObj;
201 #endif // FEATURE_MACL
203 int length = fullPath.Length;
205 // We need to trim the trailing slash or the code will try to create 2 directories of the same name.
206 if (length >= 2 && Path.IsDirectorySeparator(fullPath[length - 1]))
209 int lengthRoot = Path.GetRootLength(fullPath);
211 // For UNC paths that are only // or ///
212 if (length == 2 && Path.IsDirectorySeparator(fullPath[1]))
213 throw new IOException(Environment.GetResourceString("IO.IO_CannotCreateDirectory", path));
215 // We can save a bunch of work if the directory we want to create already exists. This also
216 // saves us in the case where sub paths are inaccessible (due to ERROR_ACCESS_DENIED) but the
217 // final path is accessable and the directory already exists. For example, consider trying
218 // to create c:\Foo\Bar\Baz, where everything already exists but ACLS prevent access to c:\Foo
219 // and c:\Foo\Bar. In that case, this code will think it needs to create c:\Foo, and c:\Foo\Bar
220 // and fail to due so, causing an exception to be thrown. This is not what we want.
221 if (InternalExists(fullPath)) {
225 List<string> stackDir = new List<string>();
227 // Attempt to figure out which directories don't exist, and only
228 // create the ones we need. Note that InternalExists may fail due
229 // to Win32 ACL's preventing us from seeing a directory, and this
232 bool somepathexists = false;
234 if (length > lengthRoot) { // Special case root (fullpath = X:\\)
236 while (i >= lengthRoot && !somepathexists) {
237 String dir = fullPath.Substring(0, i+1);
239 if (!InternalExists(dir)) // Create only the ones missing
242 somepathexists = true;
244 while (i > lengthRoot && fullPath[i] != Path.DirectorySeparatorChar && fullPath[i] != Path.AltDirectorySeparatorChar) i--;
249 int count = stackDir.Count;
251 if (stackDir.Count != 0)
253 String [] securityList = new String[stackDir.Count];
254 stackDir.CopyTo(securityList, 0);
255 for (int j = 0 ; j < securityList.Length; j++)
256 securityList[j] += "\\."; // leaf will never have a slash at the end
258 // Security check for all directories not present only.
259 #if !FEATURE_PAL && FEATURE_MACL
260 AccessControlActions control = (dirSecurity == null) ? AccessControlActions.None : AccessControlActions.Change;
261 new FileIOPermission(FileIOPermissionAccess.Write, control, securityList, false, false ).Demand();
266 foreach (String demandPath in securityList)
268 FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Write, String.Empty, demandPath);
273 new FileIOPermission(FileIOPermissionAccess.Write, securityList, false, false ).Demand();
275 #endif //!FEATURE_PAL && FEATURE_MACL
278 // If we were passed a DirectorySecurity, convert it to a security
279 // descriptor and set it in he call to CreateDirectory.
280 Win32Native.SECURITY_ATTRIBUTES secAttrs = null;
282 if (dirSecurity != null) {
283 secAttrs = new Win32Native.SECURITY_ATTRIBUTES();
284 secAttrs.nLength = (int)Marshal.SizeOf(secAttrs);
286 // For ACL's, get the security descriptor from the FileSecurity.
287 byte[] sd = dirSecurity.GetSecurityDescriptorBinaryForm();
288 byte * bytesOnStack = stackalloc byte[sd.Length];
289 Buffer.Memcpy(bytesOnStack, 0, sd, 0, sd.Length);
290 secAttrs.pSecurityDescriptor = bytesOnStack;
296 String errorString = path;
297 // If all the security checks succeeded create all the directories
298 while (stackDir.Count > 0) {
299 String name = stackDir[stackDir.Count - 1];
300 stackDir.RemoveAt(stackDir.Count - 1);
301 if (name.Length >= Path.MAX_DIRECTORY_PATH)
302 throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
303 r = Win32Native.CreateDirectory(name, secAttrs);
304 if (!r && (firstError == 0)) {
305 int currentError = Marshal.GetLastWin32Error();
306 // While we tried to avoid creating directories that don't
307 // exist above, there are at least two cases that will
308 // cause us to see ERROR_ALREADY_EXISTS here. InternalExists
309 // can fail because we didn't have permission to the
310 // directory. Secondly, another thread or process could
311 // create the directory between the time we check and the
312 // time we try using the directory. Thirdly, it could
313 // fail because the target does exist, but is a file.
314 if (currentError != Win32Native.ERROR_ALREADY_EXISTS)
315 firstError = currentError;
317 // If there's a file in this directory's place, or if we have ERROR_ACCESS_DENIED when checking if the directory already exists throw.
318 if (File.InternalExists(name) || (!InternalExists(name, out currentError) && currentError == Win32Native.ERROR_ACCESS_DENIED)) {
319 firstError = currentError;
320 // Give the user a nice error message, but don't leak path information.
325 FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, GetDemandDir(name, true));
329 new FileIOPermission(FileIOPermissionAccess.PathDiscovery, GetDemandDir(name, true)).Demand();
330 #endif // FEATURE_CORECLR
333 catch(SecurityException) {}
339 // We need this check to mask OS differences
340 // Handle CreateDirectory("X:\\foo") when X: doesn't exist. Similarly for n/w paths.
341 if ((count == 0) && !somepathexists) {
342 String root = InternalGetDirectoryRoot(fullPath);
343 if (!InternalExists(root)) {
344 // Extract the root from the passed in path again for security.
345 __Error.WinIOError(Win32Native.ERROR_PATH_NOT_FOUND, InternalGetDirectoryRoot(path));
350 // Only throw an exception if creating the exact directory we
351 // wanted failed to work correctly.
352 if (!r && (firstError != 0)) {
353 __Error.WinIOError(firstError, errorString);
358 // Tests if the given path refers to an existing DirectoryInfo on disk.
360 // Your application must have Read permission to the directory's
363 [System.Security.SecuritySafeCritical] // auto-generated
364 [ResourceExposure(ResourceScope.Machine)]
365 [ResourceConsumption(ResourceScope.Machine)]
366 public static bool Exists(String path)
368 return InternalExistsHelper(path, true);
371 [System.Security.SecurityCritical]
372 [ResourceExposure(ResourceScope.Machine)]
373 [ResourceConsumption(ResourceScope.Machine)]
374 internal static bool UnsafeExists(String path)
376 return InternalExistsHelper(path, false);
379 [System.Security.SecurityCritical]
380 [ResourceExposure(ResourceScope.Machine)]
381 [ResourceConsumption(ResourceScope.Machine)]
382 internal static bool InternalExistsHelper(String path, bool checkHost) {
387 if (path.Length == 0)
390 // Get fully qualified file name ending in \* for security check
392 String fullPath = Path.GetFullPathInternal(path);
393 String demandPath = GetDemandDir(fullPath, true);
398 FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Read, path, demandPath);
402 FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, demandPath, false, false);
406 return InternalExists(fullPath);
408 catch (ArgumentException) { }
409 catch (NotSupportedException) { } // Security can throw this on ":"
410 catch (SecurityException) { }
411 catch (IOException) { }
412 catch (UnauthorizedAccessException)
415 Contract.Assert(false, "Ignore this assert and send a repro to [....]. This assert was tracking purposes only.");
416 #endif //!FEATURE_PAL
421 // Determine whether path describes an existing directory
422 // on disk, avoiding security checks.
423 [System.Security.SecurityCritical] // auto-generated
424 [ResourceExposure(ResourceScope.Machine)]
425 [ResourceConsumption(ResourceScope.Machine)]
426 internal static bool InternalExists(String path) {
427 int lastError = Win32Native.ERROR_SUCCESS;
428 return InternalExists(path, out lastError);
431 // Determine whether path describes an existing directory
432 // on disk, avoiding security checks.
433 [System.Security.SecurityCritical] // auto-generated
434 [ResourceExposure(ResourceScope.Machine)]
435 [ResourceConsumption(ResourceScope.Machine)]
436 internal static bool InternalExists(String path, out int lastError) {
437 Win32Native.WIN32_FILE_ATTRIBUTE_DATA data = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
438 lastError = File.FillAttributeInfo(path, ref data, false, true);
440 return (lastError == 0) && (data.fileAttributes != -1)
441 && ((data.fileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY) != 0);
444 [ResourceExposure(ResourceScope.Machine)]
445 [ResourceConsumption(ResourceScope.Machine)]
446 public static void SetCreationTime(String path,DateTime creationTime)
448 SetCreationTimeUtc(path, creationTime.ToUniversalTime());
451 [System.Security.SecuritySafeCritical] // auto-generated
452 [ResourceExposure(ResourceScope.Machine)]
453 [ResourceConsumption(ResourceScope.Machine)]
454 public unsafe static void SetCreationTimeUtc(String path,DateTime creationTimeUtc)
456 using (SafeFileHandle handle = Directory.OpenHandle(path)) {
457 Win32Native.FILE_TIME fileTime = new Win32Native.FILE_TIME(creationTimeUtc.ToFileTimeUtc());
458 bool r = Win32Native.SetFileTime(handle, &fileTime, null, null);
461 int errorCode = Marshal.GetLastWin32Error();
462 __Error.WinIOError(errorCode, path);
467 [ResourceExposure(ResourceScope.Machine)]
468 [ResourceConsumption(ResourceScope.Machine)]
469 public static DateTime GetCreationTime(String path)
471 return File.GetCreationTime(path);
474 [ResourceExposure(ResourceScope.Machine)]
475 [ResourceConsumption(ResourceScope.Machine)]
476 public static DateTime GetCreationTimeUtc(String path)
478 return File.GetCreationTimeUtc(path);
481 [ResourceExposure(ResourceScope.Machine)]
482 [ResourceConsumption(ResourceScope.Machine)]
483 public static void SetLastWriteTime(String path,DateTime lastWriteTime)
485 SetLastWriteTimeUtc(path, lastWriteTime.ToUniversalTime());
488 [System.Security.SecuritySafeCritical] // auto-generated
489 [ResourceExposure(ResourceScope.Machine)]
490 [ResourceConsumption(ResourceScope.Machine)]
491 public unsafe static void SetLastWriteTimeUtc(String path,DateTime lastWriteTimeUtc)
493 using (SafeFileHandle handle = Directory.OpenHandle(path)) {
494 Win32Native.FILE_TIME fileTime = new Win32Native.FILE_TIME(lastWriteTimeUtc.ToFileTimeUtc());
495 bool r = Win32Native.SetFileTime(handle, null, null, &fileTime);
498 int errorCode = Marshal.GetLastWin32Error();
499 __Error.WinIOError(errorCode, path);
504 [ResourceExposure(ResourceScope.Machine)]
505 [ResourceConsumption(ResourceScope.Machine)]
506 public static DateTime GetLastWriteTime(String path)
508 return File.GetLastWriteTime(path);
511 [ResourceExposure(ResourceScope.Machine)]
512 [ResourceConsumption(ResourceScope.Machine)]
513 public static DateTime GetLastWriteTimeUtc(String path)
515 return File.GetLastWriteTimeUtc(path);
518 [ResourceExposure(ResourceScope.Machine)]
519 [ResourceConsumption(ResourceScope.Machine)]
520 public static void SetLastAccessTime(String path,DateTime lastAccessTime)
522 SetLastAccessTimeUtc(path, lastAccessTime.ToUniversalTime());
525 [System.Security.SecuritySafeCritical] // auto-generated
526 [ResourceExposure(ResourceScope.Machine)]
527 [ResourceConsumption(ResourceScope.Machine)]
528 public unsafe static void SetLastAccessTimeUtc(String path,DateTime lastAccessTimeUtc)
530 using (SafeFileHandle handle = Directory.OpenHandle(path)) {
531 Win32Native.FILE_TIME fileTime = new Win32Native.FILE_TIME(lastAccessTimeUtc.ToFileTimeUtc());
532 bool r = Win32Native.SetFileTime(handle, null, &fileTime, null);
535 int errorCode = Marshal.GetLastWin32Error();
536 __Error.WinIOError(errorCode, path);
541 [ResourceExposure(ResourceScope.Machine)]
542 [ResourceConsumption(ResourceScope.Machine)]
543 public static DateTime GetLastAccessTime(String path)
545 return File.GetLastAccessTime(path);
548 [ResourceExposure(ResourceScope.Machine)]
549 [ResourceConsumption(ResourceScope.Machine)]
550 public static DateTime GetLastAccessTimeUtc(String path)
552 return File.GetLastAccessTimeUtc(path);
556 [ResourceExposure(ResourceScope.Machine)]
557 [ResourceConsumption(ResourceScope.Machine)]
558 public static DirectorySecurity GetAccessControl(String path)
560 return new DirectorySecurity(path, AccessControlSections.Access | AccessControlSections.Owner | AccessControlSections.Group);
563 [ResourceExposure(ResourceScope.Machine)]
564 [ResourceConsumption(ResourceScope.Machine)]
565 public static DirectorySecurity GetAccessControl(String path, AccessControlSections includeSections)
567 return new DirectorySecurity(path, includeSections);
570 [System.Security.SecuritySafeCritical] // auto-generated
571 [ResourceExposure(ResourceScope.Machine)]
572 [ResourceConsumption(ResourceScope.Machine)]
573 public static void SetAccessControl(String path, DirectorySecurity directorySecurity)
575 if (directorySecurity == null)
576 throw new ArgumentNullException("directorySecurity");
577 Contract.EndContractBlock();
579 String fullPath = Path.GetFullPathInternal(path);
580 directorySecurity.Persist(fullPath);
584 // Returns an array of filenames in the DirectoryInfo specified by path
585 [ResourceExposure(ResourceScope.Machine)]
586 [ResourceConsumption(ResourceScope.Machine)]
587 public static String[] GetFiles(String path)
590 throw new ArgumentNullException("path");
591 Contract.Ensures(Contract.Result<String[]>() != null);
592 Contract.EndContractBlock();
594 return InternalGetFiles(path, "*", SearchOption.TopDirectoryOnly);
597 // Returns an array of Files in the current DirectoryInfo matching the
598 // given search pattern (ie, "*.txt").
599 [ResourceExposure(ResourceScope.Machine)]
600 [ResourceConsumption(ResourceScope.Machine)]
601 public static String[] GetFiles(String path, String searchPattern)
604 throw new ArgumentNullException("path");
605 if (searchPattern == null)
606 throw new ArgumentNullException("searchPattern");
607 Contract.Ensures(Contract.Result<String[]>() != null);
608 Contract.EndContractBlock();
610 return InternalGetFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
613 // Returns an array of Files in the current DirectoryInfo matching the
614 // given search pattern (ie, "*.txt") and search option
615 [ResourceExposure(ResourceScope.Machine)]
616 [ResourceConsumption(ResourceScope.Machine)]
617 public static String[] GetFiles(String path, String searchPattern, SearchOption searchOption)
620 throw new ArgumentNullException("path");
621 if (searchPattern == null)
622 throw new ArgumentNullException("searchPattern");
623 if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
624 throw new ArgumentOutOfRangeException("searchOption", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
625 Contract.Ensures(Contract.Result<String[]>() != null);
626 Contract.EndContractBlock();
628 return InternalGetFiles(path, searchPattern, searchOption);
631 // Returns an array of Files in the current DirectoryInfo matching the
632 // given search pattern (ie, "*.txt") and search option
633 [ResourceExposure(ResourceScope.Machine)]
634 [ResourceConsumption(ResourceScope.Machine)]
635 private static String[] InternalGetFiles(String path, String searchPattern, SearchOption searchOption)
637 Contract.Requires(path != null);
638 Contract.Requires(searchPattern != null);
639 Contract.Requires(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
641 return InternalGetFileDirectoryNames(path, path, searchPattern, true, false, searchOption, true);
644 [System.Security.SecurityCritical]
645 [ResourceExposure(ResourceScope.Machine)]
646 [ResourceConsumption(ResourceScope.Machine)]
647 internal static String[] UnsafeGetFiles(String path, String searchPattern, SearchOption searchOption)
649 Contract.Requires(path != null);
650 Contract.Requires(searchPattern != null);
651 Contract.Requires(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
653 return InternalGetFileDirectoryNames(path, path, searchPattern, true, false, searchOption, false);
656 // Returns an array of Directories in the current directory.
657 [ResourceExposure(ResourceScope.Machine)]
658 [ResourceConsumption(ResourceScope.Machine)]
659 public static String[] GetDirectories(String path)
662 throw new ArgumentNullException("path");
663 Contract.Ensures(Contract.Result<String[]>() != null);
664 Contract.EndContractBlock();
666 return InternalGetDirectories(path, "*", SearchOption.TopDirectoryOnly);
669 // Returns an array of Directories in the current DirectoryInfo matching the
670 // given search criteria (ie, "*.txt").
671 [ResourceExposure(ResourceScope.Machine)]
672 [ResourceConsumption(ResourceScope.Machine)]
673 public static String[] GetDirectories(String path, String searchPattern)
676 throw new ArgumentNullException("path");
677 if (searchPattern == null)
678 throw new ArgumentNullException("searchPattern");
679 Contract.Ensures(Contract.Result<String[]>() != null);
680 Contract.EndContractBlock();
682 return InternalGetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly);
685 // Returns an array of Directories in the current DirectoryInfo matching the
686 // given search criteria (ie, "*.txt").
687 [ResourceExposure(ResourceScope.Machine)]
688 [ResourceConsumption(ResourceScope.Machine)]
689 public static String[] GetDirectories(String path, String searchPattern, SearchOption searchOption)
692 throw new ArgumentNullException("path");
693 if (searchPattern == null)
694 throw new ArgumentNullException("searchPattern");
695 if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
696 throw new ArgumentOutOfRangeException("searchOption", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
697 Contract.Ensures(Contract.Result<String[]>() != null);
698 Contract.EndContractBlock();
700 return InternalGetDirectories(path, searchPattern, searchOption);
703 // Returns an array of Directories in the current DirectoryInfo matching the
704 // given search criteria (ie, "*.txt").
705 [ResourceExposure(ResourceScope.Machine)]
706 [ResourceConsumption(ResourceScope.Machine)]
707 private static String[] InternalGetDirectories(String path, String searchPattern, SearchOption searchOption)
709 Contract.Requires(path != null);
710 Contract.Requires(searchPattern != null);
711 Contract.Requires(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
712 Contract.Ensures(Contract.Result<String[]>() != null);
714 return InternalGetFileDirectoryNames(path, path, searchPattern, false, true, searchOption, true);
717 [System.Security.SecurityCritical]
718 [ResourceExposure(ResourceScope.Machine)]
719 [ResourceConsumption(ResourceScope.Machine)]
720 internal static String[] UnsafeGetDirectories(String path, String searchPattern, SearchOption searchOption)
722 Contract.Requires(path != null);
723 Contract.Requires(searchPattern != null);
724 Contract.Requires(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
725 Contract.Ensures(Contract.Result<String[]>() != null);
727 return InternalGetFileDirectoryNames(path, path, searchPattern, false, true, searchOption, false);
730 // Returns an array of strongly typed FileSystemInfo entries in the path
731 [ResourceExposure(ResourceScope.Machine)]
732 [ResourceConsumption(ResourceScope.Machine)]
733 public static String[] GetFileSystemEntries(String path)
736 throw new ArgumentNullException("path");
737 Contract.Ensures(Contract.Result<String[]>() != null);
738 Contract.EndContractBlock();
740 return InternalGetFileSystemEntries(path, "*", SearchOption.TopDirectoryOnly);
743 // Returns an array of strongly typed FileSystemInfo entries in the path with the
744 // given search criteria (ie, "*.txt"). We disallow .. as a part of the search criteria
745 [ResourceExposure(ResourceScope.Machine)]
746 [ResourceConsumption(ResourceScope.Machine)]
747 public static String[] GetFileSystemEntries(String path, String searchPattern)
750 throw new ArgumentNullException("path");
751 if (searchPattern == null)
752 throw new ArgumentNullException("searchPattern");
753 Contract.Ensures(Contract.Result<String[]>() != null);
754 Contract.EndContractBlock();
756 return InternalGetFileSystemEntries(path, searchPattern, SearchOption.TopDirectoryOnly);
759 // Returns an array of strongly typed FileSystemInfo entries in the path with the
760 // given search criteria (ie, "*.txt"). We disallow .. as a part of the search criteria
761 [ResourceExposure(ResourceScope.Machine)]
762 [ResourceConsumption(ResourceScope.Machine)]
763 public static String[] GetFileSystemEntries(String path, String searchPattern, SearchOption searchOption)
766 throw new ArgumentNullException("path");
767 if (searchPattern == null)
768 throw new ArgumentNullException("searchPattern");
769 if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
770 throw new ArgumentOutOfRangeException("searchOption", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
771 Contract.Ensures(Contract.Result<String[]>() != null);
772 Contract.EndContractBlock();
774 return InternalGetFileSystemEntries(path, searchPattern, searchOption);
777 [ResourceExposure(ResourceScope.Machine)]
778 [ResourceConsumption(ResourceScope.Machine)]
779 private static String[] InternalGetFileSystemEntries(String path, String searchPattern, SearchOption searchOption)
781 Contract.Requires(path != null);
782 Contract.Requires(searchPattern != null);
783 Contract.Requires(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
785 return InternalGetFileDirectoryNames(path, path, searchPattern, true, true, searchOption, true);
789 // Private class that holds search data that is passed around
790 // in the heap based stack recursion
791 internal sealed class SearchData
793 public SearchData(String fullPath, String userPath, SearchOption searchOption)
795 Contract.Requires(fullPath != null && fullPath.Length > 0);
796 Contract.Requires(userPath != null && userPath.Length > 0);
797 Contract.Requires(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
799 this.fullPath = fullPath;
800 this.userPath = userPath;
801 this.searchOption = searchOption;
804 public readonly string fullPath; // Fully qualified search path excluding the search criteria in the end (ex, c:\temp\bar\foo)
805 public readonly string userPath; // User specified path (ex, bar\foo)
806 public readonly SearchOption searchOption;
810 // Returns fully qualified user path of dirs/files that matches the search parameters.
811 // For recursive search this method will search through all the sub dirs and execute
812 // the given search criteria against every dir.
813 // For all the dirs/files returned, it will then demand path discovery permission for
814 // their parent folders (it will avoid duplicate permission checks)
815 [ResourceExposure(ResourceScope.Machine)]
816 [ResourceConsumption(ResourceScope.Machine)]
817 internal static String[] InternalGetFileDirectoryNames(String path, String userPathOriginal, String searchPattern, bool includeFiles, bool includeDirs, SearchOption searchOption, bool checkHost)
819 Contract.Requires(path != null);
820 Contract.Requires(userPathOriginal != null);
821 Contract.Requires(searchPattern != null);
822 Contract.Requires(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
824 IEnumerable<String> enble = FileSystemEnumerableFactory.CreateFileNameIterator(
825 path, userPathOriginal, searchPattern,
826 includeFiles, includeDirs, searchOption, checkHost);
827 List<String> fileList = new List<String>(enble);
828 return fileList.ToArray();
831 [ResourceExposure(ResourceScope.Machine)]
832 [ResourceConsumption(ResourceScope.Machine)]
833 public static IEnumerable<String> EnumerateDirectories(String path)
836 throw new ArgumentNullException("path");
837 Contract.EndContractBlock();
839 return InternalEnumerateDirectories(path, "*", SearchOption.TopDirectoryOnly);
842 [ResourceExposure(ResourceScope.Machine)]
843 [ResourceConsumption(ResourceScope.Machine)]
844 public static IEnumerable<String> EnumerateDirectories(String path, String searchPattern)
847 throw new ArgumentNullException("path");
848 if (searchPattern == null)
849 throw new ArgumentNullException("searchPattern");
850 Contract.EndContractBlock();
852 return InternalEnumerateDirectories(path, searchPattern, SearchOption.TopDirectoryOnly);
855 [ResourceExposure(ResourceScope.Machine)]
856 [ResourceConsumption(ResourceScope.Machine)]
857 public static IEnumerable<String> EnumerateDirectories(String path, String searchPattern, SearchOption searchOption)
860 throw new ArgumentNullException("path");
861 if (searchPattern == null)
862 throw new ArgumentNullException("searchPattern");
863 if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
864 throw new ArgumentOutOfRangeException("searchOption", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
865 Contract.EndContractBlock();
867 return InternalEnumerateDirectories(path, searchPattern, searchOption);
870 [ResourceExposure(ResourceScope.Machine)]
871 [ResourceConsumption(ResourceScope.Machine)]
872 private static IEnumerable<String> InternalEnumerateDirectories(String path, String searchPattern, SearchOption searchOption)
874 Contract.Requires(path != null);
875 Contract.Requires(searchPattern != null);
876 Contract.Requires(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
878 return EnumerateFileSystemNames(path, searchPattern, searchOption, false, true);
881 [ResourceExposure(ResourceScope.Machine)]
882 [ResourceConsumption(ResourceScope.Machine)]
883 public static IEnumerable<String> EnumerateFiles(String path)
886 throw new ArgumentNullException("path");
887 Contract.Ensures(Contract.Result<IEnumerable<String>>() != null);
888 Contract.EndContractBlock();
890 return InternalEnumerateFiles(path, "*", SearchOption.TopDirectoryOnly);
893 [ResourceExposure(ResourceScope.Machine)]
894 [ResourceConsumption(ResourceScope.Machine)]
895 public static IEnumerable<String> EnumerateFiles(String path, String searchPattern)
898 throw new ArgumentNullException("path");
899 if (searchPattern == null)
900 throw new ArgumentNullException("searchPattern");
901 Contract.Ensures(Contract.Result<IEnumerable<String>>() != null);
902 Contract.EndContractBlock();
904 return InternalEnumerateFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
907 [ResourceExposure(ResourceScope.Machine)]
908 [ResourceConsumption(ResourceScope.Machine)]
909 public static IEnumerable<String> EnumerateFiles(String path, String searchPattern, SearchOption searchOption)
912 throw new ArgumentNullException("path");
913 if (searchPattern == null)
914 throw new ArgumentNullException("searchPattern");
915 if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
916 throw new ArgumentOutOfRangeException("searchOption", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
917 Contract.Ensures(Contract.Result<IEnumerable<String>>() != null);
918 Contract.EndContractBlock();
920 return InternalEnumerateFiles(path, searchPattern, searchOption);
923 [ResourceExposure(ResourceScope.Machine)]
924 [ResourceConsumption(ResourceScope.Machine)]
925 private static IEnumerable<String> InternalEnumerateFiles(String path, String searchPattern, SearchOption searchOption)
927 Contract.Requires(path != null);
928 Contract.Requires(searchPattern != null);
929 Contract.Requires(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
930 Contract.Ensures(Contract.Result<IEnumerable<String>>() != null);
932 return EnumerateFileSystemNames(path, searchPattern, searchOption, true, false);
935 [ResourceExposure(ResourceScope.Machine)]
936 [ResourceConsumption(ResourceScope.Machine)]
937 public static IEnumerable<String> EnumerateFileSystemEntries(String path)
940 throw new ArgumentNullException("path");
941 Contract.Ensures(Contract.Result<IEnumerable<String>>() != null);
942 Contract.EndContractBlock();
944 return InternalEnumerateFileSystemEntries(path, "*", SearchOption.TopDirectoryOnly);
947 [ResourceExposure(ResourceScope.Machine)]
948 [ResourceConsumption(ResourceScope.Machine)]
949 public static IEnumerable<String> EnumerateFileSystemEntries(String path, String searchPattern)
952 throw new ArgumentNullException("path");
953 if (searchPattern == null)
954 throw new ArgumentNullException("searchPattern");
955 Contract.Ensures(Contract.Result<IEnumerable<String>>() != null);
956 Contract.EndContractBlock();
958 return InternalEnumerateFileSystemEntries(path, searchPattern, SearchOption.TopDirectoryOnly);
961 [ResourceExposure(ResourceScope.Machine)]
962 [ResourceConsumption(ResourceScope.Machine)]
963 public static IEnumerable<String> EnumerateFileSystemEntries(String path, String searchPattern, SearchOption searchOption)
966 throw new ArgumentNullException("path");
967 if (searchPattern == null)
968 throw new ArgumentNullException("searchPattern");
969 if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
970 throw new ArgumentOutOfRangeException("searchOption", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
971 Contract.Ensures(Contract.Result<IEnumerable<String>>() != null);
972 Contract.EndContractBlock();
974 return InternalEnumerateFileSystemEntries(path, searchPattern, searchOption);
977 [ResourceExposure(ResourceScope.Machine)]
978 [ResourceConsumption(ResourceScope.Machine)]
979 private static IEnumerable<String> InternalEnumerateFileSystemEntries(String path, String searchPattern, SearchOption searchOption)
981 Contract.Requires(path != null);
982 Contract.Requires(searchPattern != null);
983 Contract.Requires(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
984 Contract.Ensures(Contract.Result<IEnumerable<String>>() != null);
986 return EnumerateFileSystemNames(path, searchPattern, searchOption, true, true);
989 private static IEnumerable<String> EnumerateFileSystemNames(String path, String searchPattern, SearchOption searchOption,
990 bool includeFiles, bool includeDirs)
992 Contract.Requires(path != null);
993 Contract.Requires(searchPattern != null);
994 Contract.Requires(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
995 Contract.Ensures(Contract.Result<IEnumerable<String>>() != null);
997 return FileSystemEnumerableFactory.CreateFileNameIterator(path, path, searchPattern,
998 includeFiles, includeDirs, searchOption, true);
1001 // Retrieves the names of the logical drives on this machine in the
1004 // Your application must have System Info permission.
1006 [System.Security.SecuritySafeCritical] // auto-generated
1007 public static String[] GetLogicalDrives()
1009 Contract.Ensures(Contract.Result<String[]>() != null);
1011 #pragma warning disable 618
1012 new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
1013 #pragma warning restore 618
1015 int drives = Win32Native.GetLogicalDrives();
1017 __Error.WinIOError();
1018 uint d = (uint)drives;
1021 if (((int)d & 1) != 0) count++;
1024 String[] result = new String[count];
1025 char[] root = new char[] {'A', ':', '\\'};
1029 if (((int)d & 1) != 0) {
1030 result[count++] = new String(root);
1038 [System.Security.SecuritySafeCritical]
1039 [ResourceExposure(ResourceScope.Machine)]
1040 [ResourceConsumption(ResourceScope.Machine)]
1041 public static String GetDirectoryRoot(String path) {
1043 throw new ArgumentNullException("path");
1044 Contract.EndContractBlock();
1046 String fullPath = Path.GetFullPathInternal(path);
1047 String root = fullPath.Substring(0, Path.GetRootLength(fullPath));
1048 String demandPath = GetDemandDir(root, true);
1051 FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, path, demandPath);
1052 state.EnsureState();
1054 FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, demandPath, false, false);
1060 internal static String InternalGetDirectoryRoot(String path) {
1061 if (path == null) return null;
1062 return path.Substring(0, Path.GetRootLength(path));
1065 /*===============================CurrentDirectory===============================
1066 **Action: Provides a getter and setter for the current directory. The original
1067 ** current DirectoryInfo is the one from which the process was started.
1068 **Returns: The current DirectoryInfo (from the getter). Void from the setter.
1069 **Arguments: The current DirectoryInfo to which to switch to the setter.
1071 ==============================================================================*/
1072 [System.Security.SecuritySafeCritical]
1073 [ResourceExposure(ResourceScope.Machine)]
1074 [ResourceConsumption(ResourceScope.Machine)]
1075 public static String GetCurrentDirectory()
1077 return InternalGetCurrentDirectory(true);
1080 [System.Security.SecurityCritical]
1081 [ResourceExposure(ResourceScope.Machine)]
1082 [ResourceConsumption(ResourceScope.Machine)]
1083 internal static String UnsafeGetCurrentDirectory()
1085 return InternalGetCurrentDirectory(false);
1088 [System.Security.SecurityCritical]
1089 [ResourceExposure(ResourceScope.Machine)]
1090 [ResourceConsumption(ResourceScope.Machine)]
1091 private static String InternalGetCurrentDirectory(bool checkHost)
1093 StringBuilder sb = StringBuilderCache.Acquire(Path.MAX_PATH + 1);
1094 if (Win32Native.GetCurrentDirectory(sb.Capacity, sb) == 0)
1095 __Error.WinIOError();
1096 String currentDirectory = sb.ToString();
1097 // Note that if we have somehow put our command prompt into short
1098 // file name mode (ie, by running edlin or a DOS grep, etc), then
1099 // this will return a short file name.
1100 if (currentDirectory.IndexOf('~') >= 0) {
1101 int r = Win32Native.GetLongPathName(currentDirectory, sb, sb.Capacity);
1102 if (r == 0 || r >= Path.MAX_PATH) {
1103 int errorCode = Marshal.GetLastWin32Error();
1104 if (r >= Path.MAX_PATH)
1105 errorCode = Win32Native.ERROR_FILENAME_EXCED_RANGE;
1106 if (errorCode != Win32Native.ERROR_FILE_NOT_FOUND &&
1107 errorCode != Win32Native.ERROR_PATH_NOT_FOUND &&
1108 errorCode != Win32Native.ERROR_INVALID_FUNCTION && // by design - enough said.
1109 errorCode != Win32Native.ERROR_ACCESS_DENIED)
1110 __Error.WinIOError(errorCode, String.Empty);
1112 currentDirectory = sb.ToString();
1114 StringBuilderCache.Release(sb);
1115 String demandPath = GetDemandDir(currentDirectory, true);
1121 FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, demandPath);
1122 state.EnsureState();
1125 new FileIOPermission( FileIOPermissionAccess.PathDiscovery, new String[] { demandPath }, false, false ).Demand();
1127 return currentDirectory;
1132 [System.Security.SecurityCritical] // auto-generated
1134 [System.Security.SecuritySafeCritical]
1136 [ResourceExposure(ResourceScope.Machine)]
1137 [ResourceConsumption(ResourceScope.Machine)]
1138 public static void SetCurrentDirectory(String path)
1141 throw new ArgumentNullException("value");
1143 throw new ArgumentException(Environment.GetResourceString("Argument_PathEmpty"));
1144 Contract.EndContractBlock();
1145 if (path.Length >= Path.MAX_PATH)
1146 throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
1148 // This will have some large effects on the rest of the runtime
1149 // and other appdomains in this process. Demand unmanaged code.
1150 #pragma warning disable 618
1151 new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
1152 #pragma warning restore 618
1154 String fulldestDirName = Path.GetFullPathInternal(path);
1156 if (!Win32Native.SetCurrentDirectory(fulldestDirName)) {
1157 // If path doesn't exist, this sets last error to 2 (File
1158 // not Found). LEGACY: This may potentially have worked correctly
1160 int errorCode = Marshal.GetLastWin32Error();
1161 if (errorCode == Win32Native.ERROR_FILE_NOT_FOUND)
1162 errorCode = Win32Native.ERROR_PATH_NOT_FOUND;
1163 __Error.WinIOError(errorCode, fulldestDirName);
1167 [System.Security.SecuritySafeCritical]
1168 [ResourceExposure(ResourceScope.Machine)]
1169 [ResourceConsumption(ResourceScope.Machine)]
1170 public static void Move(String sourceDirName,String destDirName) {
1171 InternalMove(sourceDirName, destDirName, true);
1174 [System.Security.SecurityCritical]
1175 [ResourceExposure(ResourceScope.Machine)]
1176 [ResourceConsumption(ResourceScope.Machine)]
1177 internal static void UnsafeMove(String sourceDirName,String destDirName) {
1178 InternalMove(sourceDirName, destDirName, false);
1181 [System.Security.SecurityCritical]
1182 [ResourceExposure(ResourceScope.Machine)]
1183 [ResourceConsumption(ResourceScope.Machine)]
1184 private static void InternalMove(String sourceDirName,String destDirName,bool checkHost) {
1185 if (sourceDirName==null)
1186 throw new ArgumentNullException("sourceDirName");
1187 if (sourceDirName.Length==0)
1188 throw new ArgumentException(Environment.GetResourceString("Argument_EmptyFileName"), "sourceDirName");
1190 if (destDirName==null)
1191 throw new ArgumentNullException("destDirName");
1192 if (destDirName.Length==0)
1193 throw new ArgumentException(Environment.GetResourceString("Argument_EmptyFileName"), "destDirName");
1194 Contract.EndContractBlock();
1196 String fullsourceDirName = Path.GetFullPathInternal(sourceDirName);
1197 String sourcePath = GetDemandDir(fullsourceDirName, false);
1199 if (sourcePath.Length >= Path.MAX_DIRECTORY_PATH)
1200 throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
1202 String fulldestDirName = Path.GetFullPathInternal(destDirName);
1203 String destPath = GetDemandDir(fulldestDirName, false);
1205 if (destPath.Length >= Path.MAX_DIRECTORY_PATH)
1206 throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
1210 FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.Write | FileSecurityStateAccess.Read, sourceDirName, sourcePath);
1211 FileSecurityState destState = new FileSecurityState(FileSecurityStateAccess.Write, destDirName, destPath);
1212 sourceState.EnsureState();
1213 destState.EnsureState();
1216 FileIOPermission.QuickDemand(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, sourcePath, false, false);
1217 FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, destPath, false, false);
1220 if (String.Compare(sourcePath, destPath, StringComparison.OrdinalIgnoreCase) == 0)
1221 throw new IOException(Environment.GetResourceString("IO.IO_SourceDestMustBeDifferent"));
1223 String sourceRoot = Path.GetPathRoot(sourcePath);
1224 String destinationRoot = Path.GetPathRoot(destPath);
1225 if (String.Compare(sourceRoot, destinationRoot, StringComparison.OrdinalIgnoreCase) != 0)
1226 throw new IOException(Environment.GetResourceString("IO.IO_SourceDestMustHaveSameRoot"));
1228 if (!Win32Native.MoveFile(sourceDirName, destDirName))
1230 int hr = Marshal.GetLastWin32Error();
1231 if (hr == Win32Native.ERROR_FILE_NOT_FOUND) // Source dir not found
1233 hr = Win32Native.ERROR_PATH_NOT_FOUND;
1234 __Error.WinIOError(hr, fullsourceDirName);
1236 // This check was originally put in for Win9x (unfortunately without special casing it to be for Win9x only). We can't change the NT codepath now for backcomp reasons.
1237 if (hr == Win32Native.ERROR_ACCESS_DENIED) // WinNT throws IOException. This check is for Win9x. We can't change it for backcomp.
1238 throw new IOException(Environment.GetResourceString("UnauthorizedAccess_IODenied_Path", sourceDirName), Win32Native.MakeHRFromErrorCode(hr));
1239 __Error.WinIOError(hr, String.Empty);
1243 [System.Security.SecuritySafeCritical]
1244 [ResourceExposure(ResourceScope.Machine)]
1245 [ResourceConsumption(ResourceScope.Machine)]
1246 public static void Delete(String path)
1248 String fullPath = Path.GetFullPathInternal(path);
1249 Delete(fullPath, path, false, true);
1252 [System.Security.SecuritySafeCritical]
1253 [ResourceExposure(ResourceScope.Machine)]
1254 [ResourceConsumption(ResourceScope.Machine)]
1255 public static void Delete(String path, bool recursive)
1257 String fullPath = Path.GetFullPathInternal(path);
1258 Delete(fullPath, path, recursive, true);
1261 [System.Security.SecurityCritical]
1262 [ResourceExposure(ResourceScope.Machine)]
1263 [ResourceConsumption(ResourceScope.Machine)]
1264 internal static void UnsafeDelete(String path, bool recursive)
1266 String fullPath = Path.GetFullPathInternal(path);
1267 Delete(fullPath, path, recursive, false);
1270 // Called from DirectoryInfo as well. FullPath is fully qualified,
1271 // while the user path is used for feedback in exceptions.
1272 [System.Security.SecurityCritical] // auto-generated
1273 [ResourceExposure(ResourceScope.Machine)]
1274 [ResourceConsumption(ResourceScope.Machine)]
1275 internal static void Delete(String fullPath, String userPath, bool recursive, bool checkHost)
1279 // If not recursive, do permission check only on this directory
1280 // else check for the whole directory structure rooted below
1281 demandPath = GetDemandDir(fullPath, !recursive);
1286 FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Write, userPath, demandPath);
1287 state.EnsureState();
1290 // Make sure we have write permission to this directory
1291 new FileIOPermission(FileIOPermissionAccess.Write, new String[] { demandPath }, false, false ).Demand();
1294 // Do not recursively delete through reparse points. Perhaps in a
1295 // future version we will add a new flag to control this behavior,
1296 // but for now we're much safer if we err on the conservative side.
1297 // This applies to symbolic links and mount points.
1298 Win32Native.WIN32_FILE_ATTRIBUTE_DATA data = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
1299 int dataInitialised = File.FillAttributeInfo(fullPath, ref data, false, true);
1300 if (dataInitialised != 0) {
1301 // Ensure we throw a DirectoryNotFoundException.
1302 if (dataInitialised == Win32Native.ERROR_FILE_NOT_FOUND)
1303 dataInitialised = Win32Native.ERROR_PATH_NOT_FOUND;
1304 __Error.WinIOError(dataInitialised, fullPath);
1307 if (((FileAttributes)data.fileAttributes & FileAttributes.ReparsePoint) != 0)
1310 DeleteHelper(fullPath, userPath, recursive, true);
1313 // Note that fullPath is fully qualified, while userPath may be
1314 // relative. Use userPath for all exception messages to avoid leaking
1315 // fully qualified path information.
1316 [System.Security.SecurityCritical] // auto-generated
1317 [ResourceExposure(ResourceScope.Machine)]
1318 [ResourceConsumption(ResourceScope.Machine)]
1319 private static void DeleteHelper(String fullPath, String userPath, bool recursive, bool throwOnTopLevelDirectoryNotFound)
1323 Exception ex = null;
1325 // Do not recursively delete through reparse points. Perhaps in a
1326 // future version we will add a new flag to control this behavior,
1327 // but for now we're much safer if we err on the conservative side.
1328 // This applies to symbolic links and mount points.
1329 // Note the logic to check whether fullPath is a reparse point is
1330 // in Delete(String, String, bool), and will set "recursive" to false.
1331 // Note that Win32's DeleteFile and RemoveDirectory will just delete
1332 // the reparse point itself.
1335 Win32Native.WIN32_FIND_DATA data = new Win32Native.WIN32_FIND_DATA();
1337 // Open a Find handle
1338 using (SafeFindHandle hnd = Win32Native.FindFirstFile(fullPath+Path.DirectorySeparatorCharAsString+"*", data)) {
1339 if (hnd.IsInvalid) {
1340 hr = Marshal.GetLastWin32Error();
1341 __Error.WinIOError(hr, fullPath);
1345 bool isDir = (0!=(data.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY));
1348 if (data.cFileName.Equals(".") || data.cFileName.Equals(".."))
1351 // Recurse for all directories, unless they are
1352 // reparse points. Do not follow mount points nor
1353 // symbolic links, but do delete the reparse point
1355 bool shouldRecurse = (0 == (data.dwFileAttributes & (int) FileAttributes.ReparsePoint));
1356 if (shouldRecurse) {
1357 String newFullPath = Path.InternalCombine(fullPath, data.cFileName);
1358 String newUserPath = Path.InternalCombine(userPath, data.cFileName);
1360 DeleteHelper(newFullPath, newUserPath, recursive, false);
1362 catch(Exception e) {
1369 // Check to see if this is a mount point, and
1371 if (data.dwReserved0 == Win32Native.IO_REPARSE_TAG_MOUNT_POINT) {
1372 // Use full path plus a trailing '\'
1373 String mountPoint = Path.InternalCombine(fullPath, data.cFileName + Path.DirectorySeparatorChar);
1374 r = Win32Native.DeleteVolumeMountPoint(mountPoint);
1376 hr = Marshal.GetLastWin32Error();
1377 if (hr != Win32Native.ERROR_PATH_NOT_FOUND) {
1379 __Error.WinIOError(hr, data.cFileName);
1381 catch(Exception e) {
1390 // RemoveDirectory on a symbolic link will
1391 // remove the link itself.
1392 String reparsePoint = Path.InternalCombine(fullPath, data.cFileName);
1393 r = Win32Native.RemoveDirectory(reparsePoint);
1395 hr = Marshal.GetLastWin32Error();
1396 if (hr != Win32Native.ERROR_PATH_NOT_FOUND) {
1398 __Error.WinIOError(hr, data.cFileName);
1400 catch(Exception e) {
1410 String fileName = Path.InternalCombine(fullPath, data.cFileName);
1411 r = Win32Native.DeleteFile(fileName);
1413 hr = Marshal.GetLastWin32Error();
1414 if (hr != Win32Native.ERROR_FILE_NOT_FOUND) {
1416 __Error.WinIOError(hr, data.cFileName);
1418 catch (Exception e) {
1426 } while (Win32Native.FindNextFile(hnd, data));
1427 // Make sure we quit with a sensible error.
1428 hr = Marshal.GetLastWin32Error();
1433 if (hr!=0 && hr!=Win32Native.ERROR_NO_MORE_FILES)
1434 __Error.WinIOError(hr, userPath);
1437 r = Win32Native.RemoveDirectory(fullPath);
1440 hr = Marshal.GetLastWin32Error();
1441 if (hr == Win32Native.ERROR_FILE_NOT_FOUND) // A dubious error code.
1442 hr = Win32Native.ERROR_PATH_NOT_FOUND;
1443 // This check was originally put in for Win9x (unfortunately without special casing it to be for Win9x only). We can't change the NT codepath now for backcomp reasons.
1444 if (hr == Win32Native.ERROR_ACCESS_DENIED)
1445 throw new IOException(Environment.GetResourceString("UnauthorizedAccess_IODenied_Path", userPath));
1447 // don't throw the DirectoryNotFoundException since this is a subdir and there could be a ----
1448 // between two Directory.Delete callers
1449 if (hr == Win32Native.ERROR_PATH_NOT_FOUND && !throwOnTopLevelDirectoryNotFound)
1452 __Error.WinIOError(hr, fullPath);
1456 // WinNT only. Win9x this code will not work.
1457 [System.Security.SecurityCritical] // auto-generated
1458 [ResourceExposure(ResourceScope.Machine)]
1459 [ResourceConsumption(ResourceScope.Machine)]
1460 private static SafeFileHandle OpenHandle(String path)
1462 String fullPath = Path.GetFullPathInternal(path);
1463 String root = Path.GetPathRoot(fullPath);
1464 if (root == fullPath && root[1] == Path.VolumeSeparatorChar)
1465 throw new ArgumentException(Environment.GetResourceString("Arg_PathIsVolume"));
1467 #if !FEATURE_CORECLR
1468 FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, GetDemandDir(fullPath, true), false, false);
1471 SafeFileHandle handle = Win32Native.SafeCreateFile (
1474 (FileShare) (FILE_SHARE_WRITE|FILE_SHARE_DELETE),
1477 FILE_FLAG_BACKUP_SEMANTICS,
1481 if (handle.IsInvalid) {
1482 int hr = Marshal.GetLastWin32Error();
1483 __Error.WinIOError(hr, fullPath);
1488 private const int FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
1489 private const int GENERIC_WRITE = unchecked((int)0x40000000);
1490 private const int FILE_SHARE_WRITE = 0x00000002;
1491 private const int FILE_SHARE_DELETE = 0x00000004;
1492 private const int OPEN_EXISTING = 0x00000003;
1493 private const int FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;