The Labs \ Source Viewer \ SSCLI \ System.IO \ Directory

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** Class:  Directory
  18. **
  19. **
  20. ** Purpose: Exposes routines for enumerating through a
  21. ** directory.
  22. **
  23. **          April 11,2000
  24. **
  25. ===========================================================*/
  26. using System;
  27. using System.Collections;
  28. using System.Collections.Generic;
  29. using System.Security;
  30. using System.Security.Permissions;
  31. using Microsoft.Win32;
  32. using Microsoft.Win32.SafeHandles;
  33. using System.Text;
  34. using System.Runtime.InteropServices;
  35. using System.Globalization;
  36. using System.Runtime.Versioning;
  37. namespace System.IO
  38. {
  39.     [ComVisible(true)]
  40.     public static class Directory
  41.     {
  42.         [ResourceExposure(ResourceScope.Machine)]
  43.         [ResourceConsumption(ResourceScope.Machine)]
  44.         public static DirectoryInfo GetParent(string path)
  45.         {
  46.             if (path == null)
  47.                 throw new ArgumentNullException("path");
  48.            
  49.             if (path.Length == 0)
  50.                 throw new ArgumentException(Environment.GetResourceString("Argument_PathEmpty"), "path");
  51.            
  52.             string fullPath = Path.GetFullPathInternal(path);
  53.            
  54.             string s = Path.GetDirectoryName(fullPath);
  55.             if (s == null)
  56.                 return null;
  57.             return new DirectoryInfo(s);
  58.         }
  59.        
  60.         [ResourceExposure(ResourceScope.Machine)]
  61.         [ResourceConsumption(ResourceScope.Machine)]
  62.         public static DirectoryInfo CreateDirectory(string path)
  63.         {
  64.             if (path == null)
  65.                 throw new ArgumentNullException("path");
  66.             if (path.Length == 0)
  67.                 throw new ArgumentException(Environment.GetResourceString("Argument_PathEmpty"));
  68.            
  69.             string fullPath = Path.GetFullPathInternal(path);
  70.            
  71.             // You need read access to the directory to be returned back and write access to all the directories
  72.             // that you need to create. If we fail any security checks we will not create any directories at all.
  73.             // We attempt to create directories only after all the security checks have passed. This is avoid doing
  74.             // a demand at every level.
  75.             string demandDir = GetDemandDir(fullPath, true);
  76.             new FileIOPermission(FileIOPermissionAccess.Read, new string[] {demandDir}, false, false).Demand();
  77.             InternalCreateDirectory(fullPath, path);
  78.            
  79.             return new DirectoryInfo(fullPath, false);
  80.         }
  81.        
  82.         // Input to this method should already be fullpath. This method will ensure that we append
  83.         // the trailing slash only when appropriate and when thisDirOnly is specified append a "."
  84.         // at the end of the path to indicate that the demand is only for the fullpath and not
  85.         // everything underneath it.
  86.         [ResourceExposure(ResourceScope.None)]
  87.         [ResourceConsumption(ResourceScope.None, ResourceScope.None)]
  88.         static internal string GetDemandDir(string fullPath, bool thisDirOnly)
  89.         {
  90.             string demandPath;
  91.            
  92.             if (thisDirOnly) {
  93.                 if (fullPath.EndsWith(Path.DirectorySeparatorChar) || fullPath.EndsWith(Path.AltDirectorySeparatorChar))
  94.                     demandPath = fullPath + '.';
  95.                 else
  96.                     demandPath = fullPath + Path.DirectorySeparatorChar + '.';
  97.             }
  98.             else {
  99.                 if (!(fullPath.EndsWith(Path.DirectorySeparatorChar) || fullPath.EndsWith(Path.AltDirectorySeparatorChar)))
  100.                     demandPath = fullPath + Path.DirectorySeparatorChar;
  101.                 else
  102.                     demandPath = fullPath;
  103.             }
  104.             return demandPath;
  105.         }
  106.        
  107.         [ResourceExposure(ResourceScope.Machine)]
  108.         [ResourceConsumption(ResourceScope.Machine)]
  109.         unsafe static internal void InternalCreateDirectory(string fullPath, string path)
  110.         {
  111.             int length = fullPath.Length;
  112.            
  113.             // We need to trim the trailing slash or the code will try to create 2 directories of the same name.
  114.             if (length >= 2 && Path.IsDirectorySeparator(fullPath[length - 1]))
  115.                 length--;
  116.            
  117.             int lengthRoot = Path.GetRootLength(fullPath);
  118.            
  119.             #if !PLATFORM_UNIX
  120.             // For UNC paths that are only // or ///
  121.             if (length == 2 && Path.IsDirectorySeparator(fullPath[1]))
  122.                 throw new IOException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("IO.IO_CannotCreateDirectory"), path));
  123.             #endif // !PLATFORM_UNIX
  124.            
  125.             List<string> stackDir = new List<string>();
  126.            
  127.             // Attempt to figure out which directories don't exist, and only
  128.             // create the ones we need. Note that InternalExists may fail due
  129.             // to Win32 ACL's preventing us from seeing a directory, and this
  130.             // isn't threadsafe.
  131.            
  132.             bool somepathexists = false;
  133.            
  134.             if (length > lengthRoot) {
  135.                 // Special case root (fullpath = X:\\)
  136.                 int i = length - 1;
  137.                 while (i >= lengthRoot) {
  138.                     string dir = fullPath.Substring(0, i + 1);
  139.                    
  140.                     if (!InternalExists(dir))
  141.                         stackDir.Add(dir);
  142.                     else
  143.                         // Create only the ones missing
  144.                         somepathexists = true;
  145.                    
  146.                     while (i > lengthRoot && fullPath[i] != Path.DirectorySeparatorChar && fullPath[i] != Path.AltDirectorySeparatorChar)
  147.                         i--;
  148.                     i--;
  149.                 }
  150.             }
  151.            
  152.             int count = stackDir.Count;
  153.            
  154.             if (stackDir.Count != 0) {
  155.                 string[] securityList = new string[stackDir.Count];
  156.                 stackDir.CopyTo(securityList, 0);
  157.                 for (int j = 0; j < securityList.Length; j++)
  158.                     securityList[j] += "\\.";
  159.                 // leaf will never have a slash at the end
  160.                 // Security check for all directories not present only.
  161.                 new FileIOPermission(FileIOPermissionAccess.Write, securityList, false, false).Demand();
  162.             }
  163.            
  164.             // If we were passed a DirectorySecurity, convert it to a security
  165.             // descriptor and set it in he call to CreateDirectory.
  166.             Win32Native.SECURITY_ATTRIBUTES secAttrs = null;
  167.            
  168.             bool r = true;
  169.             int firstError = 0;
  170.             string errorString = path;
  171.             // If all the security checks succeeded create all the directories
  172.             while (stackDir.Count > 0) {
  173.                 string name = stackDir[stackDir.Count - 1];
  174.                 stackDir.RemoveAt(stackDir.Count - 1);
  175.                 if (name.Length > Path.MAX_DIRECTORY_PATH)
  176.                     throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
  177.                 r = Win32Native.CreateDirectory(name, secAttrs);
  178.                 if (!r && (firstError == 0)) {
  179.                     int currentError = Marshal.GetLastWin32Error();
  180.                     // While we tried to avoid creating directories that don't
  181.                     // exist above, there are at least two cases that will
  182.                     // cause us to see ERROR_ALREADY_EXISTS here. InternalExists
  183.                     // can fail because we didn't have permission to the
  184.                     // directory. Secondly, another thread or process could
  185.                     // create the directory between the time we check and the
  186.                     // time we try using the directory. Thirdly, it could
  187.                     // fail because the target does exist, but is a file.
  188.                     if (currentError != Win32Native.ERROR_ALREADY_EXISTS)
  189.                         firstError = currentError;
  190.                     else {
  191.                         // If there's a file in this directory's place, throw.
  192.                         if (File.InternalExists(name)) {
  193.                             firstError = currentError;
  194.                             // Give the user a nice error message, but don't leak path information.
  195.                             try {
  196.                                 new FileIOPermission(FileIOPermissionAccess.PathDiscovery, GetDemandDir(name, true)).Demand();
  197.                                 errorString = name;
  198.                             }
  199.                             catch (SecurityException) {
  200.                             }
  201.                         }
  202.                     }
  203.                 }
  204.             }
  205.            
  206.             // We need this check to mask OS differences
  207.             // Handle CreateDirectory("X:\\foo") when X: doesn't exist. Similarly for n/w paths.
  208.             if ((count == 0) && !somepathexists) {
  209.                 string root = InternalGetDirectoryRoot(fullPath);
  210.                 if (!InternalExists(root)) {
  211.                     // Extract the root from the passed in path again for security.
  212.                     __Error.WinIOError(Win32Native.ERROR_PATH_NOT_FOUND, InternalGetDirectoryRoot(path));
  213.                 }
  214.                 return;
  215.             }
  216.            
  217.             // Only throw an exception if creating the exact directory we
  218.             // wanted failed to work correctly.
  219.             if (!r && (firstError != 0)) {
  220.                 __Error.WinIOError(firstError, errorString);
  221.             }
  222.         }
  223.        
  224.        
  225.         // Tests if the given path refers to an existing DirectoryInfo on disk.
  226.         //
  227.         // Your application must have Read permission to the directory's
  228.         // contents.
  229.         //
  230.         [ResourceExposure(ResourceScope.Machine)]
  231.         [ResourceConsumption(ResourceScope.Machine)]
  232.         public static bool Exists(string path)
  233.         {
  234.             try {
  235.                 if (path == null)
  236.                     return false;
  237.                 if (path.Length == 0)
  238.                     return false;
  239.                
  240.                 // Get fully qualified file name ending in \* for security check
  241.                
  242.                 string fullPath = Path.GetFullPathInternal(path);
  243.                 string demandPath = GetDemandDir(fullPath, true);
  244.                
  245.                 new FileIOPermission(FileIOPermissionAccess.Read, new string[] {demandPath}, false, false).Demand();
  246.                
  247.                
  248.                 return InternalExists(fullPath);
  249.             }
  250.             catch (ArgumentException) {
  251.             }
  252.             catch (NotSupportedException) {
  253.             }
  254.             // Security can throw this on ":"
  255.             catch (SecurityException) {
  256.             }
  257.             catch (IOException) {
  258.             }
  259.             catch (UnauthorizedAccessException) {
  260.             }
  261.             return false;
  262.         }
  263.        
  264.         // Determine whether path describes an existing directory
  265.         // on disk, avoiding security checks.
  266.         [ResourceExposure(ResourceScope.Machine)]
  267.         [ResourceConsumption(ResourceScope.Machine)]
  268.         static internal bool InternalExists(string path)
  269.         {
  270.             Win32Native.WIN32_FILE_ATTRIBUTE_DATA data = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
  271.             int dataInitialised = File.FillAttributeInfo(path, ref data, false, true);
  272.            
  273.             return (dataInitialised == 0) && (data.fileAttributes != -1) && ((data.fileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY) != 0);
  274.         }
  275.        
  276.         [ResourceExposure(ResourceScope.Machine)]
  277.         [ResourceConsumption(ResourceScope.Machine)]
  278.         public static void SetCreationTime(string path, DateTime creationTime)
  279.         {
  280.             SetCreationTimeUtc(path, creationTime.ToUniversalTime());
  281.         }
  282.        
  283.         [ResourceExposure(ResourceScope.Machine)]
  284.         [ResourceConsumption(ResourceScope.Machine)]
  285.         unsafe public static void SetCreationTimeUtc(string path, DateTime creationTimeUtc)
  286.         {
  287.             {
  288.                 using (SafeFileHandle handle = Directory.OpenHandle(path)) {
  289.                     Win32Native.FILE_TIME fileTime = new Win32Native.FILE_TIME(creationTimeUtc.ToFileTimeUtc());
  290.                     bool r = Win32Native.SetFileTime(handle, &fileTime, null, null);
  291.                     if (!r) {
  292.                         int errorCode = Marshal.GetLastWin32Error();
  293.                         __Error.WinIOError(errorCode, path);
  294.                     }
  295.                 }
  296.             }
  297.         }
  298.        
  299.         [ResourceExposure(ResourceScope.Machine)]
  300.         [ResourceConsumption(ResourceScope.Machine)]
  301.         public static DateTime GetCreationTime(string path)
  302.         {
  303.             return File.GetCreationTime(path);
  304.         }
  305.        
  306.         [ResourceExposure(ResourceScope.Machine)]
  307.         [ResourceConsumption(ResourceScope.Machine)]
  308.         public static DateTime GetCreationTimeUtc(string path)
  309.         {
  310.             return File.GetCreationTimeUtc(path);
  311.         }
  312.        
  313.         [ResourceExposure(ResourceScope.Machine)]
  314.         [ResourceConsumption(ResourceScope.Machine)]
  315.         public static void SetLastWriteTime(string path, DateTime lastWriteTime)
  316.         {
  317.             SetLastWriteTimeUtc(path, lastWriteTime.ToUniversalTime());
  318.         }
  319.        
  320.         [ResourceExposure(ResourceScope.Machine)]
  321.         [ResourceConsumption(ResourceScope.Machine)]
  322.         unsafe public static void SetLastWriteTimeUtc(string path, DateTime lastWriteTimeUtc)
  323.         {
  324.             {
  325.                 using (SafeFileHandle handle = Directory.OpenHandle(path)) {
  326.                     Win32Native.FILE_TIME fileTime = new Win32Native.FILE_TIME(lastWriteTimeUtc.ToFileTimeUtc());
  327.                     bool r = Win32Native.SetFileTime(handle, null, null, &fileTime);
  328.                     if (!r) {
  329.                         int errorCode = Marshal.GetLastWin32Error();
  330.                         __Error.WinIOError(errorCode, path);
  331.                     }
  332.                 }
  333.             }
  334.         }
  335.        
  336.         [ResourceExposure(ResourceScope.Machine)]
  337.         [ResourceConsumption(ResourceScope.Machine)]
  338.         public static DateTime GetLastWriteTime(string path)
  339.         {
  340.             return File.GetLastWriteTime(path);
  341.         }
  342.        
  343.         [ResourceExposure(ResourceScope.Machine)]
  344.         [ResourceConsumption(ResourceScope.Machine)]
  345.         public static DateTime GetLastWriteTimeUtc(string path)
  346.         {
  347.             return File.GetLastWriteTimeUtc(path);
  348.         }
  349.        
  350.         [ResourceExposure(ResourceScope.Machine)]
  351.         [ResourceConsumption(ResourceScope.Machine)]
  352.         public static void SetLastAccessTime(string path, DateTime lastAccessTime)
  353.         {
  354.             SetLastAccessTimeUtc(path, lastAccessTime.ToUniversalTime());
  355.         }
  356.        
  357.         [ResourceExposure(ResourceScope.Machine)]
  358.         [ResourceConsumption(ResourceScope.Machine)]
  359.         unsafe public static void SetLastAccessTimeUtc(string path, DateTime lastAccessTimeUtc)
  360.         {
  361.             {
  362.                 using (SafeFileHandle handle = Directory.OpenHandle(path)) {
  363.                     Win32Native.FILE_TIME fileTime = new Win32Native.FILE_TIME(lastAccessTimeUtc.ToFileTimeUtc());
  364.                     bool r = Win32Native.SetFileTime(handle, null, &fileTime, null);
  365.                     if (!r) {
  366.                         int errorCode = Marshal.GetLastWin32Error();
  367.                         __Error.WinIOError(errorCode, path);
  368.                     }
  369.                 }
  370.             }
  371.         }
  372.        
  373.         [ResourceExposure(ResourceScope.Machine)]
  374.         [ResourceConsumption(ResourceScope.Machine)]
  375.         public static DateTime GetLastAccessTime(string path)
  376.         {
  377.             return File.GetLastAccessTime(path);
  378.         }
  379.        
  380.         [ResourceExposure(ResourceScope.Machine)]
  381.         [ResourceConsumption(ResourceScope.Machine)]
  382.         public static DateTime GetLastAccessTimeUtc(string path)
  383.         {
  384.             return File.GetLastAccessTimeUtc(path);
  385.         }
  386.        
  387.        
  388.         // Returns an array of filenames in the DirectoryInfo specified by path
  389.         [ResourceExposure(ResourceScope.Machine)]
  390.         [ResourceConsumption(ResourceScope.Machine)]
  391.         public static string[] GetFiles(string path)
  392.         {
  393.             return GetFiles(path, "*");
  394.         }
  395.        
  396.         // Returns an array of Files in the current DirectoryInfo matching the
  397.         // given search pattern (ie, "*.txt").
  398.         [ResourceExposure(ResourceScope.Machine)]
  399.         [ResourceConsumption(ResourceScope.Machine)]
  400.         public static string[] GetFiles(string path, string searchPattern)
  401.         {
  402.             return GetFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
  403.         }
  404.        
  405.         // Returns an array of Files in the current DirectoryInfo matching the
  406.         // given search pattern (ie, "*.txt") and search option
  407.         [ResourceExposure(ResourceScope.Machine)]
  408.         [ResourceConsumption(ResourceScope.Machine)]
  409.         public static string[] GetFiles(string path, string searchPattern, SearchOption searchOption)
  410.         {
  411.             if (path == null)
  412.                 throw new ArgumentNullException("path");
  413.            
  414.             if (searchPattern == null)
  415.                 throw new ArgumentNullException("searchPattern");
  416.            
  417.             return InternalGetFileDirectoryNames(path, path, searchPattern, true, false, searchOption);
  418.         }
  419.        
  420.         // Returns an array of Directories in the current directory.
  421.         [ResourceExposure(ResourceScope.Machine)]
  422.         [ResourceConsumption(ResourceScope.Machine)]
  423.         public static string[] GetDirectories(string path)
  424.         {
  425.             return GetDirectories(path, "*");
  426.         }
  427.        
  428.         // Returns an array of Directories in the current DirectoryInfo matching the
  429.         // given search criteria (ie, "*.txt").
  430.         [ResourceExposure(ResourceScope.Machine)]
  431.         [ResourceConsumption(ResourceScope.Machine)]
  432.         public static string[] GetDirectories(string path, string searchPattern)
  433.         {
  434.             return GetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly);
  435.         }
  436.        
  437.         // Returns an array of Directories in the current DirectoryInfo matching the
  438.         // given search criteria (ie, "*.txt").
  439.         [ResourceExposure(ResourceScope.Machine)]
  440.         [ResourceConsumption(ResourceScope.Machine)]
  441.         public static string[] GetDirectories(string path, string searchPattern, SearchOption searchOption)
  442.         {
  443.             if (path == null)
  444.                 throw new ArgumentNullException("path");
  445.            
  446.             if (searchPattern == null)
  447.                 throw new ArgumentNullException("searchPattern");
  448.            
  449.             return InternalGetFileDirectoryNames(path, path, searchPattern, false, true, searchOption);
  450.         }
  451.        
  452.         // Returns an array of strongly typed FileSystemInfo entries in the path
  453.         [ResourceExposure(ResourceScope.Machine)]
  454.         [ResourceConsumption(ResourceScope.Machine)]
  455.         public static string[] GetFileSystemEntries(string path)
  456.         {
  457.             return GetFileSystemEntries(path, "*");
  458.         }
  459.        
  460.         // Returns an array of strongly typed FileSystemInfo entries in the path with the
  461.         // given search criteria (ie, "*.txt"). We disallow .. as a part of the search criteria
  462.         [ResourceExposure(ResourceScope.Machine)]
  463.         [ResourceConsumption(ResourceScope.Machine)]
  464.         public static string[] GetFileSystemEntries(string path, string searchPattern)
  465.         {
  466.             return GetFileSystemEntries(path, searchPattern, SearchOption.TopDirectoryOnly);
  467.         }
  468.        
  469.         // Returns an array of strongly typed FileSystemInfo entries in the path with the
  470.         // given search criteria (ie, "*.txt"). We disallow .. as a part of the search criteria
  471.         [ResourceExposure(ResourceScope.Machine)]
  472.         [ResourceConsumption(ResourceScope.Machine)]
  473.         private static string[] GetFileSystemEntries(string path, string searchPattern, SearchOption searchOption)
  474.         {
  475.             if (path == null)
  476.                 throw new ArgumentNullException("path");
  477.            
  478.             if (searchPattern == null)
  479.                 throw new ArgumentNullException("searchPattern");
  480.            
  481.             return InternalGetFileDirectoryNames(path, path, searchPattern, true, true, searchOption);
  482.         }
  483.        
  484.         // Private class that holds search data that is passed around
  485.         // in the heap based stack recursion
  486.         private sealed class SearchData
  487.         {
  488.             public SearchData()
  489.             {
  490.             }
  491.            
  492.             public SearchData(string fullPath, string userPath, SearchOption searchOption)
  493.             {
  494.                 this.fullPath = fullPath;
  495.                 this.userPath = userPath;
  496.                 this.searchOption = searchOption;
  497.             }
  498.             public string fullPath;
  499.             // Fully qualified search path excluding the search criteria in the end (ex, c:\temp\bar\foo)
  500.             public string userPath;
  501.             // User specified path (ex, bar\foo)
  502.             public SearchOption searchOption;
  503.         }
  504.        
  505.         // Returns fully qualified user path of dirs/files that matches the search parameters.
  506.         // For recursive search this method will search through all the sub dirs and execute
  507.         // the given search criteria against every dir.
  508.         // For all the dirs/files returned, it will then demand path discovery permission for
  509.         // their parent folders (it will avoid duplicate permission checks)
  510.         [ResourceExposure(ResourceScope.Machine)]
  511.         [ResourceConsumption(ResourceScope.Machine)]
  512.         static internal string[] InternalGetFileDirectoryNames(string path, string userPathOriginal, string searchPattern, bool includeFiles, bool includeDirs, SearchOption searchOption)
  513.         {
  514.             int hr = 0;
  515.            
  516.             if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
  517.                 throw new ArgumentOutOfRangeException("searchOption", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
  518.            
  519.             searchPattern = searchPattern.TrimEnd();
  520.             if (searchPattern.Length == 0)
  521.                 return new string[0];
  522.            
  523.             Path.CheckSearchPattern(searchPattern);
  524.            
  525.             // Build various paths and query strings
  526.            
  527.             // Must fully qualify the path for the security check
  528.             string fullPath = Path.GetFullPathInternal(path);
  529.            
  530.             // Any illegal chars such as *, ? will be caught by FileIOPermission.HasIllegalCharacters
  531.             string[] demandPaths = new string[] {GetDemandDir(fullPath, true)};
  532.             new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandPaths, false, false).Demand();
  533.            
  534.             string userPath = userPathOriginal;
  535.             string tempPath = Path.GetDirectoryName(searchPattern);
  536.            
  537.             if (tempPath != null && tempPath.Length != 0) {
  538.                 // For filters like foo\*.cs we need to verify if the directory foo is not denied access.
  539.                 // Do a demand on the combined path so that we can fail early in case of deny
  540.                 demandPaths = new string[] {GetDemandDir(Path.InternalCombine(fullPath, tempPath), true)};
  541.                 new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandPaths, false, false).Demand();
  542.                
  543.                 userPath = Path.Combine(userPath, tempPath);
  544.                 // Need to add the searchPath to return correct path and for right security checks
  545.             }
  546.            
  547.             string tempStr = Path.InternalCombine(fullPath, searchPattern);
  548.            
  549.             // If path ends in a trailing slash (\), append a * or we'll
  550.             // get a "Cannot find the file specified" exception
  551.             char lastChar = tempStr[tempStr.Length - 1];
  552.             if (lastChar == Path.DirectorySeparatorChar || lastChar == Path.AltDirectorySeparatorChar || lastChar == Path.VolumeSeparatorChar)
  553.                 tempStr = tempStr + '*';
  554.            
  555.             fullPath = Path.GetDirectoryName(tempStr);
  556.             BCLDebug.Assert((fullPath != null), "fullpath can't be null!");
  557.            
  558.             string searchCriteria;
  559.             bool trailingSlash = false;
  560.             bool trailingSlashUserPath = false;
  561.            
  562.             lastChar = fullPath[fullPath.Length - 1];
  563.             trailingSlash = (lastChar == Path.DirectorySeparatorChar) || (lastChar == Path.AltDirectorySeparatorChar);
  564.            
  565.             if (trailingSlash) {
  566.                 // Can happen if the path is C:\temp, in which case GetDirectoryName would return C:\
  567.                 searchCriteria = tempStr.Substring(fullPath.Length);
  568.             }
  569.             else
  570.                 searchCriteria = tempStr.Substring(fullPath.Length + 1);
  571.            
  572.             Win32Native.WIN32_FIND_DATA data = new Win32Native.WIN32_FIND_DATA();
  573.             SafeFindHandle hnd = null;
  574.            
  575.             // Heap based search stack
  576.             SearchData searchData = new SearchData(fullPath, userPath, searchOption);
  577.             List<SearchData> searchStack = new List<SearchData>();
  578.             searchStack.Add(searchData);
  579.            
  580.             List<string> demandPathList = new List<string>();
  581.            
  582.             int numEntries = 0;
  583.             // Number of directory entities we see.
  584.             int listSize = 0;
  585.             string[] list = new string[10];
  586.             string searchPath;
  587.            
  588.             int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
  589.             try {
  590.                 // Traverse directory structure. We need to get '*'
  591.                 while (searchStack.Count > 0) {
  592.                     searchData = searchStack[searchStack.Count - 1];
  593.                     searchStack.RemoveAt(searchStack.Count - 1);
  594.                     BCLDebug.Assert((searchData.fullPath != null), "fullpath can't be null!");
  595.                    
  596.                     lastChar = searchData.fullPath[searchData.fullPath.Length - 1];
  597.                     trailingSlash = (lastChar == Path.DirectorySeparatorChar) || (lastChar == Path.AltDirectorySeparatorChar);
  598.                    
  599.                     if (searchData.userPath.Length > 0) {
  600.                         lastChar = searchData.userPath[searchData.userPath.Length - 1];
  601.                         trailingSlashUserPath = (lastChar == Path.DirectorySeparatorChar) || (lastChar == Path.AltDirectorySeparatorChar);
  602.                     }
  603.                    
  604.                     // Traverse the subdirs if specified
  605.                     if (searchData.searchOption != SearchOption.TopDirectoryOnly) {
  606.                         try {
  607.                             if (trailingSlash)
  608.                                 searchPath = searchData.fullPath + "*";
  609.                             else
  610.                                 searchPath = searchData.fullPath + Path.DirectorySeparatorChar + "*";
  611.                            
  612.                             // Get all files and dirs
  613.                             hnd = Win32Native.FindFirstFile(searchPath, data);
  614.                            
  615.                             if (hnd.IsInvalid) {
  616.                                 hr = Marshal.GetLastWin32Error();
  617.                                
  618.                                 // This could happen if the dir doesn't contain any files.
  619.                                 // Continue with the recursive search though, eventually
  620.                                 // searchStack will become empty
  621.                                 if (hr == Win32Native.ERROR_FILE_NOT_FOUND)
  622.                                     continue;
  623.                                 __Error.WinIOError(hr, searchData.fullPath);
  624.                             }
  625.                            
  626.                             // Add subdirs to searchStack. Exempt ReparsePoints as appropriate
  627.                             do {
  628.                                 if ((0 != (data.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY)) && !data.cFileName.Equals(".") && !data.cFileName.Equals("..")) {
  629.                                    
  630.                                     // Setup search data for the sub directory and push it into the stack
  631.                                     SearchData searchDataSubDir = new SearchData();
  632.                                    
  633.                                     // FullPath
  634.                                     StringBuilder strBldr = new StringBuilder(searchData.fullPath);
  635.                                     if (!trailingSlash)
  636.                                         strBldr.Append(Path.DirectorySeparatorChar);
  637.                                     strBldr.Append(data.cFileName);
  638.                                     searchDataSubDir.fullPath = strBldr.ToString();
  639.                                    
  640.                                     // UserPath
  641.                                     strBldr.Length = 0;
  642.                                     strBldr.Append(searchData.userPath);
  643.                                     if (!trailingSlashUserPath)
  644.                                         strBldr.Append(Path.DirectorySeparatorChar);
  645.                                     strBldr.Append(data.cFileName);
  646.                                     searchDataSubDir.userPath = strBldr.ToString();
  647.                                    
  648.                                     // SearchOption
  649.                                     searchDataSubDir.searchOption = searchData.searchOption;
  650.                                    
  651.                                     searchStack.Add(searchDataSubDir);
  652.                                 }
  653.                             }
  654.                             while (Win32Native.FindNextFile(hnd, data));
  655.                             // We don't care about any error here
  656.                         }
  657.                         finally {
  658.                             if (hnd != null)
  659.                                 hnd.Dispose();
  660.                         }
  661.                     }
  662.                    
  663.                     // Execute searchCriteria against the current directory
  664.                     try {
  665.                         if (trailingSlash)
  666.                             searchPath = searchData.fullPath + searchCriteria;
  667.                         else
  668.                             searchPath = searchData.fullPath + Path.DirectorySeparatorChar + searchCriteria;
  669.                        
  670.                         // Open a Find handle
  671.                         hnd = Win32Native.FindFirstFile(searchPath, data);
  672.                         if (hnd.IsInvalid) {
  673.                             hr = Marshal.GetLastWin32Error();
  674.                             if (hr == Win32Native.ERROR_FILE_NOT_FOUND)
  675.                                 continue;
  676.                             __Error.WinIOError(hr, searchData.fullPath);
  677.                         }
  678.                        
  679.                         numEntries = 0;
  680.                        
  681.                         // Keep asking for more matching files/dirs, add it to the list
  682.                         do {
  683.                             bool includeThis = false;
  684.                             // Should this file/directory be included in the output?
  685.                             if (includeFiles)
  686.                                 includeThis = (0 == (data.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY));
  687.                            
  688.                             if (includeDirs) {
  689.                                 // Don't add "." nor ".."
  690.                                 if ((0 != (data.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY)) && !data.cFileName.Equals(".") && !data.cFileName.Equals("..")) {
  691.                                    
  692.                                     BCLDebug.Assert(!includeThis, data.cFileName + ": current item can't be both file and dir!");
  693.                                     includeThis = true;
  694.                                 }
  695.                             }
  696.                            
  697.                             if (includeThis) {
  698.                                 numEntries++;
  699.                                 if (listSize == list.Length) {
  700.                                     string[] newList = new string[list.Length * 2];
  701.                                     Array.Copy(list, 0, newList, 0, listSize);
  702.                                     list = newList;
  703.                                 }
  704.                                 list[listSize++] = Path.InternalCombine(searchData.userPath, data.cFileName);
  705.                             }
  706.                         }
  707.                         while (Win32Native.FindNextFile(hnd, data));
  708.                        
  709.                         // Make sure we quit with a sensible error.
  710.                         hr = Marshal.GetLastWin32Error();
  711.                        
  712.                         // Demand pathdiscovery for all the parent dirs that are returned
  713.                         // I.e, if C:\temp\foo\bar is returned, demand C:\temp\foo
  714.                         if (numEntries > 0) {
  715.                             demandPathList.Add(GetDemandDir(searchData.fullPath, true));
  716.                         }
  717.                     }
  718.                     finally {
  719.                         if (hnd != null)
  720.                             hnd.Dispose();
  721.                     }
  722.                 }
  723.                 // End while
  724.             }
  725.             finally {
  726.                 Win32Native.SetErrorMode(oldMode);
  727.             }
  728.            
  729.             // ERROR_FILE_NOT_FOUND is valid here because if the top level
  730.             // dir doen't contain any subdirs and matching files then
  731.             // we will get here with this errorcode from the searchStack walk
  732.             if ((hr != 0) && (hr != Win32Native.ERROR_NO_MORE_FILES) && (hr != Win32Native.ERROR_FILE_NOT_FOUND)) {
  733.                 __Error.WinIOError(hr, searchData.fullPath);
  734.             }
  735.            
  736.             // Demand pathdiscovery for all the parent dirs that are returned
  737.             // I.e, if C:\temp\foo\bar is returned, demand C:\temp\foo
  738.             if (demandPathList.Count > 0) {
  739.                 demandPaths = new string[demandPathList.Count];
  740.                 demandPathList.CopyTo(demandPaths, 0);
  741.                
  742.                 // No need to check for dupls as the demandPathList entries should be unique
  743.                 new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandPaths, false, false).Demand();
  744.             }
  745.            
  746.             // Check for a string such as "C:\tmp", in which case we return
  747.             // just the DirectoryInfo name. FindNextFile fails first time, and
  748.             // data still contains a directory.
  749.             /*
  750.             if (includeDirs && numEntries==1 && (0!=(data.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY))) {
  751.                 String[] sa = new String[1];
  752.                 sa[0] = Path.InternalCombine(searchData.userPath, data.cFileName);
  753.                 return sa;
  754.             }
  755. */           
  756.             // Return list of files/directories as an array of strings
  757. if (listSize == list.Length)
  758.                 return list;
  759.             string[] items = new string[listSize];
  760.             Array.Copy(list, 0, items, 0, listSize);
  761.             return items;
  762.         }
  763.        
  764.         // Retrieves the names of the logical drives on this machine in the
  765.         // form "C:\".
  766.         //
  767.         // Your application must have System Info permission.
  768.         //
  769.         #if !PLATFORM_UNIX
  770.         public static string[] GetLogicalDrives()
  771.         {
  772.             new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
  773.            
  774.             int drives = Win32Native.GetLogicalDrives();
  775.             if (drives == 0)
  776.                 __Error.WinIOError();
  777.             uint d = (uint)drives;
  778.             int count = 0;
  779.             while (d != 0) {
  780.                 if (((int)d & 1) != 0)
  781.                     count++;
  782.                 d >>= 1;
  783.             }
  784.             string[] result = new string[count];
  785.             char[] root = new char[] {'A', ':', '\\'};
  786.             d = (uint)drives;
  787.             count = 0;
  788.             while (d != 0) {
  789.                 if (((int)d & 1) != 0) {
  790.                     result[count++] = new string(root);
  791.                 }
  792.                 d >>= 1;
  793.                 root[0]++;
  794.             }
  795.             return result;
  796.         }
  797.         #else
  798.         public static string[] GetLogicalDrives()
  799.         {
  800.             // On Unix systems, GetLogicalDrives
  801.             // should return an empty string array
  802.             return new string[0];
  803.         }
  804.         #endif // !PLATFORM_UNIX
  805.        
  806.         [ResourceExposure(ResourceScope.Machine)]
  807.         [ResourceConsumption(ResourceScope.Machine)]
  808.         public static string GetDirectoryRoot(string path)
  809.         {
  810.             if (path == null)
  811.                 throw new ArgumentNullException("path");
  812.            
  813.             string fullPath = Path.GetFullPathInternal(path);
  814.             string root = fullPath.Substring(0, Path.GetRootLength(fullPath));
  815.             string demandPath = GetDemandDir(root, true);
  816.            
  817.             new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new string[] {demandPath}, false, false).Demand();
  818.            
  819.             return root;
  820.         }
  821.        
  822.         static internal string InternalGetDirectoryRoot(string path)
  823.         {
  824.             if (path == null)
  825.                 return null;
  826.             return path.Substring(0, Path.GetRootLength(path));
  827.         }
  828.        
  829. /*===============================CurrentDirectory===============================
  830.         **Action:  Provides a getter and setter for the current directory.  The original
  831.         **        current DirectoryInfo is the one from which the process was started. 
  832.         **Returns: The current DirectoryInfo (from the getter).  Void from the setter.
  833.         **Arguments: The current DirectoryInfo to which to switch to the setter.
  834.         **Exceptions:
  835.         ==============================================================================*/       
  836.         [ResourceExposure(ResourceScope.Machine)]
  837.         [ResourceConsumption(ResourceScope.Machine)]
  838.         public static string GetCurrentDirectory()
  839.         {
  840.             StringBuilder sb = new StringBuilder(Path.MAX_PATH + 1);
  841.             if (Win32Native.GetCurrentDirectory(sb.Capacity, sb) == 0)
  842.                 __Error.WinIOError();
  843.             string currentDirectory = sb.ToString();
  844.             // Note that if we have somehow put our command prompt into short
  845.             // file name mode (ie, by running edlin or a DOS grep, etc), then
  846.             // this will return a short file name.
  847.             if (currentDirectory.IndexOf('~') >= 0) {
  848.                 int r = Win32Native.GetLongPathName(currentDirectory, sb, sb.Capacity);
  849.                 if (r == 0 || r >= Path.MAX_PATH) {
  850.                     int errorCode = Marshal.GetLastWin32Error();
  851.                     if (r >= Path.MAX_PATH)
  852.                         errorCode = Win32Native.ERROR_FILENAME_EXCED_RANGE;
  853.                     if (errorCode != Win32Native.ERROR_FILE_NOT_FOUND && errorCode != Win32Native.ERROR_PATH_NOT_FOUND && errorCode != Win32Native.ERROR_INVALID_FUNCTION && errorCode != Win32Native.ERROR_ACCESS_DENIED)
  854.                         // by design - enough said.
  855.                         __Error.WinIOError(errorCode, String.Empty);
  856.                 }
  857.                 currentDirectory = sb.ToString();
  858.             }
  859.            
  860.             string demandPath = GetDemandDir(currentDirectory, true);
  861.             new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new string[] {demandPath}, false, false).Demand();
  862.             return currentDirectory;
  863.         }
  864.        
  865.         [ResourceExposure(ResourceScope.Machine)]
  866.         [ResourceConsumption(ResourceScope.Machine)]
  867.         public static void SetCurrentDirectory(string path)
  868.         {
  869.             if (path == null)
  870.                 throw new ArgumentNullException("value");
  871.             if (path.Length == 0)
  872.                 throw new ArgumentException(Environment.GetResourceString("Argument_PathEmpty"));
  873.             if (path.Length >= Path.MAX_PATH)
  874.                 throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
  875.            
  876.             // This will have some large effects on the rest of the runtime
  877.             // and other appdomains in this process. Demand unmanaged code.
  878.             new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
  879.            
  880.             string fulldestDirName = Path.GetFullPathInternal(path);
  881.             if (Environment.IsWin9X() && !InternalExists(Path.GetPathRoot(fulldestDirName)))
  882.                 // For Win9x
  883.                 throw new DirectoryNotFoundException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("IO.PathNotFound_Path"), path));
  884.            
  885.             if (!Win32Native.SetCurrentDirectory(fulldestDirName)) {
  886.                 // If path doesn't exist, this sets last error to 2 (File
  887.                 // not Found). This may potentially have worked correctly
  888.                 // on Win9x, maybe.
  889.                 int errorCode = Marshal.GetLastWin32Error();
  890.                 if (errorCode == Win32Native.ERROR_FILE_NOT_FOUND)
  891.                     errorCode = Win32Native.ERROR_PATH_NOT_FOUND;
  892.                 __Error.WinIOError(errorCode, fulldestDirName);
  893.             }
  894.         }
  895.        
  896.         [ResourceExposure(ResourceScope.Machine)]
  897.         [ResourceConsumption(ResourceScope.Machine)]
  898.         public static void Move(string sourceDirName, string destDirName)
  899.         {
  900.             if (sourceDirName == null)
  901.                 throw new ArgumentNullException("sourceDirName");
  902.             if (sourceDirName.Length == 0)
  903.                 throw new ArgumentException(Environment.GetResourceString("Argument_EmptyFileName"), "sourceDirName");
  904.            
  905.             if (destDirName == null)
  906.                 throw new ArgumentNullException("destDirName");
  907.             if (destDirName.Length == 0)
  908.                 throw new ArgumentException(Environment.GetResourceString("Argument_EmptyFileName"), "destDirName");
  909.            
  910.             string fullsourceDirName = Path.GetFullPathInternal(sourceDirName);
  911.             string sourcePath = GetDemandDir(fullsourceDirName, false);
  912.            
  913.             if (sourcePath.Length >= Path.MAX_DIRECTORY_PATH + 1)
  914.                 throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
  915.            
  916.             string fulldestDirName = Path.GetFullPathInternal(destDirName);
  917.             string destPath = GetDemandDir(fulldestDirName, false);
  918.            
  919.             if (destPath.Length >= Path.MAX_DIRECTORY_PATH + 1)
  920.                 throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
  921.            
  922.             new FileIOPermission(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, new string[] {sourcePath}, false, false).Demand();
  923.             new FileIOPermission(FileIOPermissionAccess.Write, new string[] {destPath}, false, false).Demand();
  924.            
  925.             if (CultureInfo.InvariantCulture.CompareInfo.Compare(sourcePath, destPath, CompareOptions.IgnoreCase) == 0)
  926.                 throw new IOException(Environment.GetResourceString("IO.IO_SourceDestMustBeDifferent"));
  927.            
  928.             string sourceRoot = Path.GetPathRoot(sourcePath);
  929.             string destinationRoot = Path.GetPathRoot(destPath);
  930.             if (CultureInfo.InvariantCulture.CompareInfo.Compare(sourceRoot, destinationRoot, CompareOptions.IgnoreCase) != 0)
  931.                 throw new IOException(Environment.GetResourceString("IO.IO_SourceDestMustHaveSameRoot"));
  932.            
  933.             if (Environment.IsWin9X() && !Directory.InternalExists(Path.GetPathRoot(fulldestDirName)))
  934.                 // For Win9x
  935.                 throw new DirectoryNotFoundException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("IO.PathNotFound_Path"), destDirName));
  936.            
  937.             if (!Win32Native.MoveFile(sourceDirName, destDirName)) {
  938.                 int hr = Marshal.GetLastWin32Error();
  939.                 // Source dir not found
  940.                 if (hr == Win32Native.ERROR_FILE_NOT_FOUND) {
  941.                     hr = Win32Native.ERROR_PATH_NOT_FOUND;
  942.                     __Error.WinIOError(hr, fullsourceDirName);
  943.                 }
  944.                 if (hr == Win32Native.ERROR_ACCESS_DENIED)
  945.                     // WinNT throws IOException. This check is for Win9x. We can't change it for backcomp.
  946.                     throw new IOException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("UnauthorizedAccess_IODenied_Path"), sourceDirName), Win32Native.MakeHRFromErrorCode(hr));
  947.                 __Error.WinIOError(hr, String.Empty);
  948.             }
  949.         }
  950.        
  951.         [ResourceExposure(ResourceScope.Machine)]
  952.         [ResourceConsumption(ResourceScope.Machine)]
  953.         public static void Delete(string path)
  954.         {
  955.             string fullPath = Path.GetFullPathInternal(path);
  956.             Delete(fullPath, path, false);
  957.         }
  958.        
  959.         [ResourceExposure(ResourceScope.Machine)]
  960.         [ResourceConsumption(ResourceScope.Machine)]
  961.         public static void Delete(string path, bool recursive)
  962.         {
  963.             string fullPath = Path.GetFullPathInternal(path);
  964.             Delete(fullPath, path, recursive);
  965.         }
  966.        
  967.         // Called from DirectoryInfo as well. FullPath is fully qualified,
  968.         // while the user path is used for feedback in exceptions.
  969.         [ResourceExposure(ResourceScope.Machine)]
  970.         [ResourceConsumption(ResourceScope.Machine)]
  971.         static internal void Delete(string fullPath, string userPath, bool recursive)
  972.         {
  973.             string demandPath;
  974.            
  975.             // If not recursive, do permission check only on this directory
  976.             // else check for the whole directory structure rooted below
  977.             demandPath = GetDemandDir(fullPath, !recursive);
  978.            
  979.             // Make sure we have write permission to this directory
  980.             new FileIOPermission(FileIOPermissionAccess.Write, new string[] {demandPath}, false, false).Demand();
  981.            
  982.             // Do not recursively delete through reparse points. Perhaps in a
  983.             // future version we will add a new flag to control this behavior,
  984.             // but for now we're much safer if we err on the conservative side.
  985.             // This applies to symbolic links and mount points.
  986.             Win32Native.WIN32_FILE_ATTRIBUTE_DATA data = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
  987.             int dataInitialised = File.FillAttributeInfo(fullPath, ref data, false, true);
  988.             if (dataInitialised != 0) {
  989.                 // Ensure we throw a DirectoryNotFoundException.
  990.                 if (dataInitialised == Win32Native.ERROR_FILE_NOT_FOUND)
  991.                     dataInitialised = Win32Native.ERROR_PATH_NOT_FOUND;
  992.                 __Error.WinIOError(dataInitialised, fullPath);
  993.             }
  994.            
  995.             if (((FileAttributes)data.fileAttributes & FileAttributes.ReparsePoint) != 0)
  996.                 recursive = false;
  997.            
  998.             DeleteHelper(fullPath, userPath, recursive);
  999.         }
  1000.        
  1001.         // Note that fullPath is fully qualified, while userPath may be
  1002.         // relative. Use userPath for all exception messages to avoid leaking
  1003.         // fully qualified path information.
  1004.         [ResourceExposure(ResourceScope.Machine)]
  1005.         [ResourceConsumption(ResourceScope.Machine)]
  1006.         private static void DeleteHelper(string fullPath, string userPath, bool recursive)
  1007.         {
  1008.             bool r;
  1009.             int hr;
  1010.             Exception ex = null;
  1011.            
  1012.             // Do not recursively delete through reparse points. Perhaps in a
  1013.             // future version we will add a new flag to control this behavior,
  1014.             // but for now we're much safer if we err on the conservative side.
  1015.             // This applies to symbolic links and mount points.
  1016.             // Note the logic to check whether fullPath is a reparse point is
  1017.             // in Delete(String, String, bool), and will set "recursive" to false.
  1018.             // Note that Win32's DeleteFile and RemoveDirectory will just delete
  1019.             // the reparse point itself.
  1020.            
  1021.             if (recursive) {
  1022.                 Win32Native.WIN32_FIND_DATA data = new Win32Native.WIN32_FIND_DATA();
  1023.                
  1024.                 // Open a Find handle
  1025.                 using (SafeFindHandle hnd = Win32Native.FindFirstFile(fullPath + Path.DirectorySeparatorChar + "*", data)) {
  1026.                     if (hnd.IsInvalid) {
  1027.                         hr = Marshal.GetLastWin32Error();
  1028.                         __Error.WinIOError(hr, fullPath);
  1029.                     }
  1030.                    
  1031.                     do {
  1032.                         bool isDir = (0 != (data.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY));
  1033.                         if (isDir) {
  1034.                             // Skip ".", "..".
  1035.                             if (data.cFileName.Equals(".") || data.cFileName.Equals(".."))
  1036.                                 continue;
  1037.                            
  1038.                             // Recurse for all directories, unless they are
  1039.                             // reparse points. Do not follow mount points nor
  1040.                             // symbolic links, but do delete the reparse point
  1041.                             // itself.
  1042.                             bool shouldRecurse = (0 == (data.dwFileAttributes & (int)FileAttributes.ReparsePoint));
  1043.                             if (shouldRecurse) {
  1044.                                 string newFullPath = Path.InternalCombine(fullPath, data.cFileName);
  1045.                                 string newUserPath = Path.InternalCombine(userPath, data.cFileName);
  1046.                                 try {
  1047.                                     DeleteHelper(newFullPath, newUserPath, recursive);
  1048.                                 }
  1049.                                 catch (Exception e) {
  1050.                                     if (ex == null) {
  1051.                                         ex = e;
  1052.                                     }
  1053.                                 }
  1054.                             }
  1055.                             else {
  1056.                                 // Check to see if this is a mount point, and
  1057.                                 // unmount it.
  1058.                                 if (data.dwReserved0 == Win32Native.IO_REPARSE_TAG_MOUNT_POINT) {
  1059.                                     // Use full path plus a trailing '\'
  1060.                                     string mountPoint = Path.InternalCombine(fullPath, data.cFileName + Path.DirectorySeparatorChar);
  1061.                                     r = Win32Native.DeleteVolumeMountPoint(mountPoint);
  1062.                                     if (!r) {
  1063.                                         hr = Marshal.GetLastWin32Error();
  1064.                                         try {
  1065.                                             __Error.WinIOError(hr, data.cFileName);
  1066.                                         }
  1067.                                         catch (Exception e) {
  1068.                                             if (ex == null) {
  1069.                                                 ex = e;
  1070.                                             }
  1071.                                         }
  1072.                                     }
  1073.                                 }
  1074.                                
  1075.                                 // RemoveDirectory on a symbolic link will
  1076.                                 // remove the link itself.
  1077.                                 string reparsePoint = Path.InternalCombine(fullPath, data.cFileName);
  1078.                                 r = Win32Native.RemoveDirectory(reparsePoint);
  1079.                                 if (!r) {
  1080.                                     hr = Marshal.GetLastWin32Error();
  1081.                                     try {
  1082.                                         __Error.WinIOError(hr, data.cFileName);
  1083.                                     }
  1084.                                     catch (Exception e) {
  1085.                                         if (ex == null) {
  1086.                                             ex = e;
  1087.                                         }
  1088.                                     }
  1089.                                 }
  1090.                             }
  1091.                         }
  1092.                         else {
  1093.                             string fileName = Path.InternalCombine(fullPath, data.cFileName);
  1094.                             r = Win32Native.DeleteFile(fileName);
  1095.                             if (!r) {
  1096.                                 hr = Marshal.GetLastWin32Error();
  1097.                                 try {
  1098.                                     __Error.WinIOError(hr, data.cFileName);
  1099.                                 }
  1100.                                 catch (Exception e) {
  1101.                                     if (ex == null) {
  1102.                                         ex = e;
  1103.                                     }
  1104.                                 }
  1105.                             }
  1106.                         }
  1107.                     }
  1108.                     while (Win32Native.FindNextFile(hnd, data));
  1109.                     // Make sure we quit with a sensible error.
  1110.                     hr = Marshal.GetLastWin32Error();
  1111.                 }
  1112.                
  1113.                 if (ex != null)
  1114.                     throw ex;
  1115.                 if (hr != 0 && hr != Win32Native.ERROR_NO_MORE_FILES)
  1116.                     __Error.WinIOError(hr, userPath);
  1117.             }
  1118.            
  1119.             r = Win32Native.RemoveDirectory(fullPath);
  1120.            
  1121.             if (!r) {
  1122.                 hr = Marshal.GetLastWin32Error();
  1123.                 if (hr == Win32Native.ERROR_FILE_NOT_FOUND)
  1124.                     // A dubious error code.
  1125.                     hr = Win32Native.ERROR_PATH_NOT_FOUND;
  1126.                 if (hr == Win32Native.ERROR_ACCESS_DENIED)
  1127.                     throw new IOException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("UnauthorizedAccess_IODenied_Path"), userPath));
  1128.                 __Error.WinIOError(hr, fullPath);
  1129.             }
  1130.         }
  1131.        
  1132.        
  1133.         [ResourceExposure(ResourceScope.Machine)]
  1134.         [ResourceConsumption(ResourceScope.Machine)]
  1135.         private static SafeFileHandle OpenHandle(string path)
  1136.         {
  1137.             string fullPath = Path.GetFullPathInternal(path);
  1138.             string root = Path.GetPathRoot(fullPath);
  1139.             if (root == fullPath && root[1] == Path.VolumeSeparatorChar)
  1140.                 throw new ArgumentException(Environment.GetResourceString("Arg_PathIsVolume"));
  1141.            
  1142.             new FileIOPermission(FileIOPermissionAccess.Write, new string[] {GetDemandDir(fullPath, true)}, false, false).Demand();
  1143.            
  1144.             SafeFileHandle handle = Win32Native.SafeCreateFile(fullPath, GENERIC_WRITE, (FileShare)(FILE_SHARE_WRITE | FILE_SHARE_DELETE), null, FileMode.Open, FILE_FLAG_BACKUP_SEMANTICS, Win32Native.NULL);
  1145.            
  1146.             if (handle.IsInvalid) {
  1147.                 int hr = Marshal.GetLastWin32Error();
  1148.                 __Error.WinIOError(hr, fullPath);
  1149.             }
  1150.             return handle;
  1151.         }
  1152.        
  1153.         private const int FILE_ATTRIBUTE_DIRECTORY = 16;
  1154.         private const int GENERIC_WRITE = unchecked((int)1073741824);
  1155.         private const int FILE_SHARE_WRITE = 2;
  1156.         private const int FILE_SHARE_DELETE = 4;
  1157.         private const int OPEN_EXISTING = 3;
  1158.         private const int FILE_FLAG_BACKUP_SEMANTICS = 33554432;
  1159.     }
  1160. }

Developer Fusion