[System.Security.SecurityCritical] // auto-generated private void AddSearchableDirsToStack(Directory.SearchData localSearchData) { Contract.Requires(localSearchData != null); String searchPath = Path.Combine(localSearchData.fullPath, "*"); SafeFindHandle hnd = null; Interop.WIN32_FIND_DATA data = new Interop.WIN32_FIND_DATA(); try { // Get all files and dirs hnd = Interop.mincore.FindFirstFile(searchPath, ref data); if (hnd.IsInvalid) { int errorCode = Marshal.GetLastWin32Error(); // This could happen if the dir doesn't contain any files. // Continue with the recursive search though, eventually // searchStack will become empty if (errorCode == Interop.ERROR_FILE_NOT_FOUND || errorCode == Interop.ERROR_NO_MORE_FILES || errorCode == Interop.ERROR_PATH_NOT_FOUND) { return; } HandleError(errorCode, localSearchData.fullPath); } // Add subdirs to searchStack. Exempt ReparsePoints as appropriate int incr = 0; do { if (Win32FileSystemEnumerableHelpers.IsDir(data)) { Contract.Assert(data.cFileName.Length != 0 && !Path.IsPathRooted(data.cFileName), "Expected file system enumeration to not have empty file/directory name and not have rooted name"); String tempFullPath = Path.Combine(localSearchData.fullPath, data.cFileName); String tempUserPath = Path.Combine(localSearchData.userPath, data.cFileName); SearchOption option = localSearchData.searchOption; // Setup search data for the sub directory and push it into the stack Directory.SearchData searchDataSubDir = new Directory.SearchData(tempFullPath, tempUserPath, option); _searchStack.Insert(incr++, searchDataSubDir); } } while (Interop.mincore.FindNextFile(hnd, ref data)); // We don't care about errors here } finally { if (hnd != null) { hnd.Dispose(); } } }
internal SearchResult(String fullPath, String userPath, Interop.WIN32_FIND_DATA findData) { Contract.Requires(fullPath != null); Contract.Requires(userPath != null); this._fullPath = fullPath; this._userPath = userPath; this._findData = findData; }
private void CommonInit() { Contract.Assert(_searchCriteria != null && _searchData != null, "searchCriteria and searchData should be initialized"); // Execute searchCriteria against the current directory PathHelpers.ThrowIfEmptyOrRootedPath(_searchCriteria); String searchPath = Path.Combine(_searchData.fullPath, _searchCriteria); Interop.WIN32_FIND_DATA data = new Interop.WIN32_FIND_DATA(); // Open a Find handle _hnd = Interop.mincore.FindFirstFile(searchPath, ref data); if (_hnd.IsInvalid) { int errorCode = Marshal.GetLastWin32Error(); if (errorCode != Interop.ERROR_FILE_NOT_FOUND && errorCode != Interop.ERROR_NO_MORE_FILES) { HandleError(errorCode, _searchData.fullPath); } else { // flag this as empty only if we're searching just top directory // Used in fast path for top directory only _empty = _searchData.searchOption == SearchOption.TopDirectoryOnly; } } // fast path for TopDirectoryOnly. If we have a result, go ahead and set it to // current. If empty, dispose handle. if (_searchData.searchOption == SearchOption.TopDirectoryOnly) { if (_empty) { _hnd.Dispose(); } else { SearchResult searchResult = CreateSearchResult(_searchData, data); if (_resultHandler.IsResultIncluded(searchResult)) { current = _resultHandler.CreateObject(searchResult); } } } // for AllDirectories, we first recurse into dirs, so cleanup and add searchData // to the stack else { _hnd.Dispose(); _searchStack.Add(_searchData); } }
public Win32FileSystemObject(string fullPath, Interop.WIN32_FIND_DATA findData, bool asDirectory) { _fullPath = fullPath; // Copy the information to data _data.fileAttributes = (int)findData.dwFileAttributes; _data.ftCreationTimeLow = findData.ftCreationTime.dwLowDateTime; _data.ftCreationTimeHigh = findData.ftCreationTime.dwHighDateTime; _data.ftLastAccessTimeLow = findData.ftLastAccessTime.dwLowDateTime; _data.ftLastAccessTimeHigh = findData.ftLastAccessTime.dwHighDateTime; _data.ftLastWriteTimeLow = findData.ftLastWriteTime.dwLowDateTime; _data.ftLastWriteTimeHigh = findData.ftLastWriteTime.dwHighDateTime; _data.fileSizeHigh = findData.nFileSizeHigh; _data.fileSizeLow = findData.nFileSizeLow; _dataInitialised = 0; }
private bool ShouldUseWinRT(string fullPath, bool isCreate) { bool useWinRt = false; do { Interop.WIN32_FIND_DATA findData = new Interop.WIN32_FIND_DATA(); using (SafeFindHandle handle = Interop.mincore.FindFirstFile(fullPath, ref findData)) { int error = Marshal.GetLastWin32Error(); if (handle.IsInvalid) { if (error == Interop.ERROR_ACCESS_DENIED) { // The path was not accessible with Win32, so try WinRT useWinRt = true; break; } else if (error != Interop.ERROR_PATH_NOT_FOUND && error != Interop.ERROR_FILE_NOT_FOUND) { // We hit some error other than ACCESS_DENIED or NOT_FOUND, // Default to Win32 to provide most accurate error behavior break; } } else { // Use WinRT for placeholder files useWinRt = IsPlaceholderFile(findData); break; } } // error was ERROR_PATH_NOT_FOUND or ERROR_FILE_NOT_FOUND // if we are creating a file/directory we cannot assume that Win32 will have access to // the parent directory, so we walk up the path. fullPath = PathHelpers.GetDirectoryNameInternal(fullPath); // only walk up the path if we are creating a file/directory and not at the root } while (isCreate && !String.IsNullOrEmpty(fullPath)); return(useWinRt); }
internal static SafeFindHandle FindFirstFile(String fileName, ref Interop.WIN32_FIND_DATA data) { // use FindExInfoBasic since we don't care about short name and it has better perf return(FindFirstFileEx(fileName, FINDEX_INFO_LEVELS.FindExInfoBasic, ref data, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, 0)); }
private static bool IsPlaceholderFile(Interop.WIN32_FIND_DATA findData) { return((findData.dwFileAttributes & Interop.FILE_ATTRIBUTE_DIRECTORY) == 0 && (findData.dwFileAttributes & Interop.FILE_ATTRIBUTE_REPARSE_POINT) != 0 && (findData.dwReserved0 == Interop.IO_REPARSE_TAG_FILE_PLACEHOLDER)); }
[System.Security.SecurityCritical] // auto-generated internal static bool IsFile(Interop.WIN32_FIND_DATA data) { return(0 == (data.dwFileAttributes & Interop.FILE_ATTRIBUTE_DIRECTORY)); }
[System.Security.SecurityCritical] // auto-generated internal static bool IsDir(Interop.WIN32_FIND_DATA data) { // Don't add "." nor ".." return((0 != (data.dwFileAttributes & Interop.FILE_ATTRIBUTE_DIRECTORY)) && !data.cFileName.Equals(".") && !data.cFileName.Equals("..")); }
[System.Security.SecurityCritical] // auto-generated internal static int FillAttributeInfo(String path, ref Interop.WIN32_FILE_ATTRIBUTE_DATA data, bool tryagain, bool returnErrorOnNotFound) { int errorCode = 0; if (tryagain) // someone has a handle to the file open, or other error { Interop.WIN32_FIND_DATA findData; findData = new Interop.WIN32_FIND_DATA(); // Remove trialing slash since this can cause grief to FindFirstFile. You will get an invalid argument error String tempPath = path.TrimEnd(PathHelpers.DirectorySeparatorChars); // For floppy drives, normally the OS will pop up a dialog saying // there is no disk in drive A:, please insert one. We don't want that. // SetErrorMode will let us disable this, but we should set the error // mode back, since this may have wide-ranging effects. uint oldMode = Interop.mincore.SetErrorMode(Interop.SEM_FAILCRITICALERRORS); try { bool error = false; SafeFindHandle handle = Interop.mincore.FindFirstFile(tempPath, ref findData); try { if (handle.IsInvalid) { error = true; errorCode = Marshal.GetLastWin32Error(); if (errorCode == Interop.ERROR_FILE_NOT_FOUND || errorCode == Interop.ERROR_PATH_NOT_FOUND || errorCode == Interop.ERROR_NOT_READY) // floppy device not ready { if (!returnErrorOnNotFound) { // Return default value for backward compatibility errorCode = 0; data.fileAttributes = -1; } } return errorCode; } } finally { // Close the Win32 handle try { handle.Dispose(); } catch { // if we're already returning an error, don't throw another one. if (!error) { throw Win32Marshal.GetExceptionForLastWin32Error(); } } } } finally { Interop.mincore.SetErrorMode(oldMode); } // Copy the information to data data.PopulateFrom(findData); } else { // For floppy drives, normally the OS will pop up a dialog saying // there is no disk in drive A:, please insert one. We don't want that. // SetErrorMode will let us disable this, but we should set the error // mode back, since this may have wide-ranging effects. bool success = false; uint oldMode = Interop.mincore.SetErrorMode(Interop.SEM_FAILCRITICALERRORS); try { success = Interop.mincore.GetFileAttributesEx(path, Interop.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, ref data); } finally { Interop.mincore.SetErrorMode(oldMode); } if (!success) { errorCode = Marshal.GetLastWin32Error(); if (errorCode != Interop.ERROR_FILE_NOT_FOUND && errorCode != Interop.ERROR_PATH_NOT_FOUND && errorCode != Interop.ERROR_NOT_READY) // floppy device not ready { // In case someone latched onto the file. Take the perf hit only for failure return FillAttributeInfo(path, ref data, true, returnErrorOnNotFound); } else { if (!returnErrorOnNotFound) { // Return default value for backward compbatibility errorCode = 0; data.fileAttributes = -1; } } } } return errorCode; }
private SearchResult CreateSearchResult(Directory.SearchData localSearchData, Interop.WIN32_FIND_DATA findData) { string findData_fileName = findData.cFileName; Contract.Requires(findData_fileName.Length != 0 && !Path.IsPathRooted(findData_fileName), "Expected file system enumeration to not have empty file/directory name and not have rooted name"); String userPathFinal = Path.Combine(localSearchData.userPath, findData_fileName); String fullPathFinal = Path.Combine(localSearchData.fullPath, findData_fileName); return(new SearchResult(fullPathFinal, userPathFinal, findData)); }
public override bool MoveNext() { Interop.WIN32_FIND_DATA data = new Interop.WIN32_FIND_DATA(); switch (state) { case STATE_INIT: { if (_empty) { state = STATE_FINISH; goto case STATE_FINISH; } if (_searchData.searchOption == SearchOption.TopDirectoryOnly) { state = STATE_FIND_NEXT_FILE; if (current != null) { return(true); } else { goto case STATE_FIND_NEXT_FILE; } } else { state = STATE_SEARCH_NEXT_DIR; goto case STATE_SEARCH_NEXT_DIR; } } case STATE_SEARCH_NEXT_DIR: { Contract.Assert(_searchData.searchOption != SearchOption.TopDirectoryOnly, "should not reach this code path if searchOption == TopDirectoryOnly"); // Traverse directory structure. We need to get '*' while (_searchStack.Count > 0) { _searchData = _searchStack[0]; Contract.Assert((_searchData.fullPath != null), "fullpath can't be null!"); _searchStack.RemoveAt(0); // Traverse the subdirs AddSearchableDirsToStack(_searchData); // Execute searchCriteria against the current directory String searchPath = Path.Combine(_searchData.fullPath, _searchCriteria); // Open a Find handle _hnd = Interop.mincore.FindFirstFile(searchPath, ref data); if (_hnd.IsInvalid) { int errorCode = Marshal.GetLastWin32Error(); if (errorCode == Interop.ERROR_FILE_NOT_FOUND || errorCode == Interop.ERROR_NO_MORE_FILES || errorCode == Interop.ERROR_PATH_NOT_FOUND) { continue; } _hnd.Dispose(); HandleError(errorCode, _searchData.fullPath); } state = STATE_FIND_NEXT_FILE; SearchResult searchResult = CreateSearchResult(_searchData, data); if (_resultHandler.IsResultIncluded(searchResult)) { current = _resultHandler.CreateObject(searchResult); return(true); } else { goto case STATE_FIND_NEXT_FILE; } } state = STATE_FINISH; goto case STATE_FINISH; } case STATE_FIND_NEXT_FILE: { if (_searchData != null && _hnd != null) { // Keep asking for more matching files/dirs, add it to the list while (Interop.mincore.FindNextFile(_hnd, ref data)) { SearchResult searchResult = CreateSearchResult(_searchData, data); if (_resultHandler.IsResultIncluded(searchResult)) { current = _resultHandler.CreateObject(searchResult); return(true); } } // Make sure we quit with a sensible error. int errorCode = Marshal.GetLastWin32Error(); if (_hnd != null) { _hnd.Dispose(); } // ERROR_FILE_NOT_FOUND is valid here because if the top level // dir doen't contain any subdirs and matching files then // we will get here with this errorcode from the searchStack walk if ((errorCode != 0) && (errorCode != Interop.ERROR_NO_MORE_FILES) && (errorCode != Interop.ERROR_FILE_NOT_FOUND)) { HandleError(errorCode, _searchData.fullPath); } } if (_searchData.searchOption == SearchOption.TopDirectoryOnly) { state = STATE_FINISH; goto case STATE_FINISH; } else { state = STATE_SEARCH_NEXT_DIR; goto case STATE_SEARCH_NEXT_DIR; } } case STATE_FINISH: { Dispose(); break; } } return(false); }
private bool ShouldUseWinRT(string fullPath, bool isCreate) { // The purpose of this method is to determine if we can access a path // via Win32 or if we need to fallback to WinRT. // We prefer Win32 since it is faster, WinRT's APIs eventually just // call into Win32 after all, but it doesn't provide access to, // brokered paths (like Pictures or Documents) nor does it handle // placeholder files. So we'd like to fall back to WinRT whenever // we can't access a path, or if it known to be a placeholder file. bool useWinRt = false; do { // first use GetFileAttributesEx as it is faster than FindFirstFile and requires minimum permissions Interop.WIN32_FILE_ATTRIBUTE_DATA data = new Interop.WIN32_FILE_ATTRIBUTE_DATA(); if (Interop.mincore.GetFileAttributesEx(fullPath, Interop.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, ref data)) { // got the attributes if ((data.fileAttributes & Interop.FILE_ATTRIBUTE_DIRECTORY) != 0 || (data.fileAttributes & Interop.FILE_ATTRIBUTE_REPARSE_POINT) == 0) { // we have a directory or a file that is not a reparse point // useWinRt = false; break; } else { // we need to get the find data to determine if it is a placeholder file Interop.WIN32_FIND_DATA findData = new Interop.WIN32_FIND_DATA(); using (SafeFindHandle handle = Interop.mincore.FindFirstFile(fullPath, ref findData)) { if (!handle.IsInvalid) { // got the find data, use WinRT for placeholder files Debug.Assert((findData.dwFileAttributes & Interop.FILE_ATTRIBUTE_DIRECTORY) == 0); Debug.Assert((findData.dwFileAttributes & Interop.FILE_ATTRIBUTE_REPARSE_POINT) != 0); useWinRt = findData.dwReserved0 == Interop.IO_REPARSE_TAG_FILE_PLACEHOLDER; break; } } } } int error = Marshal.GetLastWin32Error(); Debug.Assert(error != Interop.ERROR_SUCCESS); if (error == Interop.ERROR_ACCESS_DENIED) { // The path was not accessible with Win32, so try WinRT useWinRt = true; break; } else if (error != Interop.ERROR_PATH_NOT_FOUND && error != Interop.ERROR_FILE_NOT_FOUND) { // We hit some error other than ACCESS_DENIED or NOT_FOUND, // Default to Win32 to provide most accurate error behavior break; } // error was ERROR_PATH_NOT_FOUND or ERROR_FILE_NOT_FOUND // if we are creating a file/directory we cannot assume that Win32 will have access to // the parent directory, so we walk up the path. fullPath = PathHelpers.GetDirectoryNameInternal(fullPath); // only walk up the path if we are creating a file/directory and not at the root } while (isCreate && !String.IsNullOrEmpty(fullPath)); return(useWinRt); }
[System.Security.SecurityCritical] // auto-generated private static void RemoveDirectoryHelper(String fullPath, bool recursive, bool throwOnTopLevelDirectoryNotFound) { bool r; int errorCode; Exception ex = null; // Do not recursively delete through reparse points. Perhaps in a // future version we will add a new flag to control this behavior, // but for now we're much safer if we err on the conservative side. // This applies to symbolic links and mount points. // Note the logic to check whether fullPath is a reparse point is // in Delete(String, String, bool), and will set "recursive" to false. // Note that Win32's DeleteFile and RemoveDirectory will just delete // the reparse point itself. if (recursive) { Interop.WIN32_FIND_DATA data = new Interop.WIN32_FIND_DATA(); // Open a Find handle using (SafeFindHandle hnd = Interop.mincore.FindFirstFile(fullPath + PathHelpers.DirectorySeparatorCharAsString + "*", ref data)) { if (hnd.IsInvalid) throw Win32Marshal.GetExceptionForLastWin32Error(fullPath); do { bool isDir = (0 != (data.dwFileAttributes & Interop.FILE_ATTRIBUTE_DIRECTORY)); if (isDir) { // Skip ".", "..". if (data.cFileName.Equals(".") || data.cFileName.Equals("..")) continue; // Recurse for all directories, unless they are // reparse points. Do not follow mount points nor // symbolic links, but do delete the reparse point // itself. bool shouldRecurse = (0 == (data.dwFileAttributes & (int)FileAttributes.ReparsePoint)); if (shouldRecurse) { String newFullPath = Path.Combine(fullPath, data.cFileName); try { RemoveDirectoryHelper(newFullPath, recursive, false); } catch (Exception e) { if (ex == null) ex = e; } } else { // Check to see if this is a mount point, and // unmount it. if (data.dwReserved0 == Interop.IO_REPARSE_TAG_MOUNT_POINT) { // Use full path plus a trailing '\' String mountPoint = Path.Combine(fullPath, data.cFileName + PathHelpers.DirectorySeparatorCharAsString); r = Interop.mincore.DeleteVolumeMountPoint(mountPoint); if (!r) { errorCode = Marshal.GetLastWin32Error(); if (errorCode != Interop.ERROR_PATH_NOT_FOUND) { try { throw Win32Marshal.GetExceptionForWin32Error(errorCode, data.cFileName); } catch (Exception e) { if (ex == null) ex = e; } } } } // RemoveDirectory on a symbolic link will // remove the link itself. String reparsePoint = Path.Combine(fullPath, data.cFileName); r = Interop.mincore.RemoveDirectory(reparsePoint); if (!r) { errorCode = Marshal.GetLastWin32Error(); if (errorCode != Interop.ERROR_PATH_NOT_FOUND) { try { throw Win32Marshal.GetExceptionForWin32Error(errorCode, data.cFileName); } catch (Exception e) { if (ex == null) ex = e; } } } } } else { String fileName = Path.Combine(fullPath, data.cFileName); r = Interop.mincore.DeleteFile(fileName); if (!r) { errorCode = Marshal.GetLastWin32Error(); if (errorCode != Interop.ERROR_FILE_NOT_FOUND) { try { throw Win32Marshal.GetExceptionForWin32Error(errorCode, data.cFileName); } catch (Exception e) { if (ex == null) ex = e; } } } } } while (Interop.mincore.FindNextFile(hnd, ref data)); // Make sure we quit with a sensible error. errorCode = Marshal.GetLastWin32Error(); } if (ex != null) throw ex; if (errorCode != 0 && errorCode != Interop.ERROR_NO_MORE_FILES) throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath); } r = Interop.mincore.RemoveDirectory(fullPath); if (!r) { errorCode = Marshal.GetLastWin32Error(); if (errorCode == Interop.ERROR_FILE_NOT_FOUND) // A dubious error code. errorCode = Interop.ERROR_PATH_NOT_FOUND; // 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. if (errorCode == Interop.ERROR_ACCESS_DENIED) throw new IOException(SR.Format(SR.UnauthorizedAccess_IODenied_Path, fullPath)); // don't throw the DirectoryNotFoundException since this is a subdir and // there could be a race condition between two Directory.Delete callers if (errorCode == Interop.ERROR_PATH_NOT_FOUND && !throwOnTopLevelDirectoryNotFound) return; throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath); } }
[System.Security.SecurityCritical] // auto-generated internal static int FillAttributeInfo(String path, ref Interop.WIN32_FILE_ATTRIBUTE_DATA data, bool tryagain, bool returnErrorOnNotFound) { int errorCode = 0; if (tryagain) // someone has a handle to the file open, or other error { Interop.WIN32_FIND_DATA findData; findData = new Interop.WIN32_FIND_DATA(); // Remove trialing slash since this can cause grief to FindFirstFile. You will get an invalid argument error String tempPath = path.TrimEnd(PathHelpers.DirectorySeparatorChars); // For floppy drives, normally the OS will pop up a dialog saying // there is no disk in drive A:, please insert one. We don't want that. // SetErrorMode will let us disable this, but we should set the error // mode back, since this may have wide-ranging effects. uint oldMode = Interop.mincore.SetErrorMode(Interop.SEM_FAILCRITICALERRORS); try { bool error = false; SafeFindHandle handle = Interop.mincore.FindFirstFile(tempPath, ref findData); try { if (handle.IsInvalid) { error = true; errorCode = Marshal.GetLastWin32Error(); if (errorCode == Interop.ERROR_FILE_NOT_FOUND || errorCode == Interop.ERROR_PATH_NOT_FOUND || errorCode == Interop.ERROR_NOT_READY) // floppy device not ready { if (!returnErrorOnNotFound) { // Return default value for backward compatibility errorCode = 0; data.fileAttributes = -1; } } return(errorCode); } } finally { // Close the Win32 handle try { handle.Dispose(); } catch { // if we're already returning an error, don't throw another one. if (!error) { throw Win32Marshal.GetExceptionForLastWin32Error(); } } } } finally { Interop.mincore.SetErrorMode(oldMode); } // Copy the information to data data.PopulateFrom(findData); } else { // For floppy drives, normally the OS will pop up a dialog saying // there is no disk in drive A:, please insert one. We don't want that. // SetErrorMode will let us disable this, but we should set the error // mode back, since this may have wide-ranging effects. bool success = false; uint oldMode = Interop.mincore.SetErrorMode(Interop.SEM_FAILCRITICALERRORS); try { success = Interop.mincore.GetFileAttributesEx(path, Interop.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, ref data); } finally { Interop.mincore.SetErrorMode(oldMode); } if (!success) { errorCode = Marshal.GetLastWin32Error(); if (errorCode != Interop.ERROR_FILE_NOT_FOUND && errorCode != Interop.ERROR_PATH_NOT_FOUND && errorCode != Interop.ERROR_NOT_READY) // floppy device not ready { // In case someone latched onto the file. Take the perf hit only for failure return(FillAttributeInfo(path, ref data, true, returnErrorOnNotFound)); } else { if (!returnErrorOnNotFound) { // Return default value for backward compatibility errorCode = 0; data.fileAttributes = -1; } } } } return(errorCode); }
[System.Security.SecurityCritical] // auto-generated private static void RemoveDirectoryHelper(String fullPath, bool recursive, bool throwOnTopLevelDirectoryNotFound) { bool r; int errorCode; Exception ex = null; // Do not recursively delete through reparse points. Perhaps in a // future version we will add a new flag to control this behavior, // but for now we're much safer if we err on the conservative side. // This applies to symbolic links and mount points. // Note the logic to check whether fullPath is a reparse point is // in Delete(String, String, bool), and will set "recursive" to false. // Note that Win32's DeleteFile and RemoveDirectory will just delete // the reparse point itself. if (recursive) { Interop.WIN32_FIND_DATA data = new Interop.WIN32_FIND_DATA(); // Open a Find handle using (SafeFindHandle hnd = Interop.mincore.FindFirstFile(fullPath + PathHelpers.DirectorySeparatorCharAsString + "*", ref data)) { if (hnd.IsInvalid) { throw Win32Marshal.GetExceptionForLastWin32Error(fullPath); } do { bool isDir = (0 != (data.dwFileAttributes & Interop.FILE_ATTRIBUTE_DIRECTORY)); if (isDir) { // Skip ".", "..". if (data.cFileName.Equals(".") || data.cFileName.Equals("..")) { continue; } // Recurse for all directories, unless they are // reparse points. Do not follow mount points nor // symbolic links, but do delete the reparse point // itself. bool shouldRecurse = (0 == (data.dwFileAttributes & (int)FileAttributes.ReparsePoint)); if (shouldRecurse) { String newFullPath = Path.Combine(fullPath, data.cFileName); try { RemoveDirectoryHelper(newFullPath, recursive, false); } catch (Exception e) { if (ex == null) { ex = e; } } } else { // Check to see if this is a mount point, and // unmount it. if (data.dwReserved0 == Interop.IO_REPARSE_TAG_MOUNT_POINT) { // Use full path plus a trailing '\' String mountPoint = Path.Combine(fullPath, data.cFileName + PathHelpers.DirectorySeparatorCharAsString); r = Interop.mincore.DeleteVolumeMountPoint(mountPoint); if (!r) { errorCode = Marshal.GetLastWin32Error(); if (errorCode != Interop.ERROR_PATH_NOT_FOUND) { try { throw Win32Marshal.GetExceptionForWin32Error(errorCode, data.cFileName); } catch (Exception e) { if (ex == null) { ex = e; } } } } } // RemoveDirectory on a symbolic link will // remove the link itself. String reparsePoint = Path.Combine(fullPath, data.cFileName); r = Interop.mincore.RemoveDirectory(reparsePoint); if (!r) { errorCode = Marshal.GetLastWin32Error(); if (errorCode != Interop.ERROR_PATH_NOT_FOUND) { try { throw Win32Marshal.GetExceptionForWin32Error(errorCode, data.cFileName); } catch (Exception e) { if (ex == null) { ex = e; } } } } } } else { String fileName = Path.Combine(fullPath, data.cFileName); r = Interop.mincore.DeleteFile(fileName); if (!r) { errorCode = Marshal.GetLastWin32Error(); if (errorCode != Interop.ERROR_FILE_NOT_FOUND) { try { throw Win32Marshal.GetExceptionForWin32Error(errorCode, data.cFileName); } catch (Exception e) { if (ex == null) { ex = e; } } } } } } while (Interop.mincore.FindNextFile(hnd, ref data)); // Make sure we quit with a sensible error. errorCode = Marshal.GetLastWin32Error(); } if (ex != null) { throw ex; } if (errorCode != 0 && errorCode != Interop.ERROR_NO_MORE_FILES) { throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath); } } r = Interop.mincore.RemoveDirectory(fullPath); if (!r) { errorCode = Marshal.GetLastWin32Error(); if (errorCode == Interop.ERROR_FILE_NOT_FOUND) // A dubious error code. { errorCode = Interop.ERROR_PATH_NOT_FOUND; } // 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. if (errorCode == Interop.ERROR_ACCESS_DENIED) { throw new IOException(SR.Format(SR.UnauthorizedAccess_IODenied_Path, fullPath)); } // don't throw the DirectoryNotFoundException since this is a subdir and // there could be a race condition between two Directory.Delete callers if (errorCode == Interop.ERROR_PATH_NOT_FOUND && !throwOnTopLevelDirectoryNotFound) { return; } throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath); } }
private bool ShouldUseWinRT(string fullPath, bool isCreate) { bool useWinRt = false; do { Interop.WIN32_FIND_DATA findData = new Interop.WIN32_FIND_DATA(); using (SafeFindHandle handle = Interop.mincore.FindFirstFile(fullPath, ref findData)) { int error = Marshal.GetLastWin32Error(); if (handle.IsInvalid) { if (error == Interop.ERROR_ACCESS_DENIED) { // The path was not accessible with Win32, so try WinRT useWinRt = true; break; } else if (error != Interop.ERROR_PATH_NOT_FOUND && error != Interop.ERROR_FILE_NOT_FOUND) { // We hit some error other than ACCESS_DENIED or NOT_FOUND, // Default to Win32 to provide most accurate error behavior break; } } else { // Use WinRT for placeholder files useWinRt = IsPlaceholderFile(findData); break; } } // error was ERROR_PATH_NOT_FOUND or ERROR_FILE_NOT_FOUND // if we are creating a file/directory we cannot assume that Win32 will have access to // the parent directory, so we walk up the path. fullPath = PathHelpers.GetDirectoryNameInternal(fullPath); // only walk up the path if we are creating a file/directory and not at the root } while (isCreate && !String.IsNullOrEmpty(fullPath)); return useWinRt; }