Exemplo n.º 1
0
        public static void RemoveDirectory(string fullPath, bool recursive)
        {
            if (!recursive)
            {
                RemoveDirectoryInternal(fullPath, topLevel: true);
                return;
            }

            Interop.Kernel32.WIN32_FIND_DATA findData = default;
            // FindFirstFile($path) (used by GetFindData) fails with ACCESS_DENIED when user has no ListDirectory rights
            // but FindFirstFile($path/*") (used by RemoveDirectoryRecursive) works fine in such scenario.
            // So we ignore it here and let RemoveDirectoryRecursive throw if FindFirstFile($path/*") fails with ACCESS_DENIED.
            GetFindData(fullPath, isDirectory: true, ignoreAccessDenied: true, ref findData);
            if (IsNameSurrogateReparsePoint(ref findData))
            {
                // Don't recurse
                RemoveDirectoryInternal(fullPath, topLevel: true);
                return;
            }

            // We want extended syntax so we can delete "extended" subdirectories and files
            // (most notably ones with trailing whitespace or periods)
            fullPath = PathInternal.EnsureExtendedPrefix(fullPath);
            RemoveDirectoryRecursive(fullPath, ref findData, topLevel: true);
        }
Exemplo n.º 2
0
        private void CommonInit()
        {
            Debug.Assert(_searchCriteria != null, "searchCriteria should be initialized");

            // Execute searchCriteria against the current directory
            PathHelpers.ThrowIfEmptyOrRootedPath(_searchCriteria);
            string searchPath = Path.Combine(_searchData.FullPath, _searchCriteria);

            Interop.Kernel32.WIN32_FIND_DATA data = new Interop.Kernel32.WIN32_FIND_DATA();

            using (new DisableMediaInsertionPrompt())
            {
                // Open a Find handle
                _hnd = Interop.Kernel32.FindFirstFile(searchPath, ref data);

                if (_hnd.IsInvalid)
                {
                    int errorCode = Marshal.GetLastWin32Error();
                    if (errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND && errorCode != Interop.Errors.ERROR_NO_MORE_FILES)
                    {
                        throw 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 = _searchOption == SearchOption.TopDirectoryOnly;
                    }
                }
            }

            if (_searchOption == SearchOption.TopDirectoryOnly)
            {
                // fast path for TopDirectoryOnly. If we have a result, go ahead and set it to
                // current. If empty, dispose handle.
                if (_empty)
                {
                    _hnd.Dispose();
                }
                else
                {
                    TSource result;
                    if (IsResultIncluded(ref data, out result))
                    {
                        current = result;
                    }
                }
            }
            else
            {
                // for AllDirectories, we first recurse into dirs, so cleanup and add searchData
                // to the list
                _hnd.Dispose();
                _searchList = new List <PathPair>();
                _searchList.Add(_searchData);
            }
        }
Exemplo n.º 3
0
        internal static int FillAttributeInfo(string path, ref Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data, bool returnErrorOnNotFound)
        {
            int errorCode = Interop.Errors.ERROR_SUCCESS;

            // Neither GetFileAttributes or FindFirstFile like trailing separators
            path = path.TrimEnd(PathHelpers.DirectorySeparatorChars);

            using (new DisableMediaInsertionPrompt())
            {
                if (!Interop.Kernel32.GetFileAttributesEx(path, Interop.Kernel32.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, ref data))
                {
                    errorCode = Marshal.GetLastWin32Error();
                    if (errorCode == Interop.Errors.ERROR_ACCESS_DENIED)
                    {
                        // Files that are marked for deletion will not let you GetFileAttributes,
                        // ERROR_ACCESS_DENIED is given back without filling out the data struct.
                        // FindFirstFile, however, will. Historically we always gave back attributes
                        // for marked-for-deletion files.

                        var findData = new Interop.Kernel32.WIN32_FIND_DATA();
                        using (SafeFindHandle handle = Interop.Kernel32.FindFirstFile(path, ref findData))
                        {
                            if (handle.IsInvalid)
                            {
                                errorCode = Marshal.GetLastWin32Error();
                            }
                            else
                            {
                                errorCode = Interop.Errors.ERROR_SUCCESS;
                                data.PopulateFrom(ref findData);
                            }
                        }
                    }
                }
            }

            if (errorCode != Interop.Errors.ERROR_SUCCESS && !returnErrorOnNotFound)
            {
                switch (errorCode)
                {
                case Interop.Errors.ERROR_FILE_NOT_FOUND:
                case Interop.Errors.ERROR_PATH_NOT_FOUND:
                case Interop.Errors.ERROR_NOT_READY:     // Removable media not ready
                    // Return default value for backward compatibility
                    data.fileAttributes = -1;
                    return(Interop.Errors.ERROR_SUCCESS);
                }
            }

            return(errorCode);
        }
Exemplo n.º 4
0
 private static void GetFindData(string fullPath, bool isDirectory, ref Interop.Kernel32.WIN32_FIND_DATA findData)
 {
     using SafeFindHandle handle = Interop.Kernel32.FindFirstFile(Path.TrimEndingDirectorySeparator(fullPath), ref findData);
     if (handle.IsInvalid)
     {
         int errorCode = Marshal.GetLastWin32Error();
         // File not found doesn't make much sense coming from a directory.
         if (isDirectory && errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND)
         {
             errorCode = Interop.Errors.ERROR_PATH_NOT_FOUND;
         }
         throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
     }
 }
Exemplo n.º 5
0
        private static bool IsNameSurrogateReparsePoint(ref Interop.Kernel32.WIN32_FIND_DATA data)
        {
            // Name surrogates are reparse points that point to other named entities local to the file system.
            // Reparse points can be used for other types of files, notably OneDrive placeholder files. We
            // should treat reparse points that are not name surrogates as any other directory, e.g. recurse
            // into them. Surrogates should just be detached.
            //
            // See
            // https://github.com/dotnet/corefx/issues/24250
            // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365511.aspx
            // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365197.aspx

            return(((FileAttributes)data.dwFileAttributes & FileAttributes.ReparsePoint) != 0 &&
                   (data.dwReserved0 & 0x20000000) != 0); // IsReparseTagNameSurrogate
        }
Exemplo n.º 6
0
        public static void RemoveDirectory(string fullPath, bool recursive)
        {
            // Do not recursively delete through reparse points.
            if (!recursive || IsReparsePoint(fullPath))
            {
                RemoveDirectoryInternal(fullPath, topLevel: true);
                return;
            }

            // We want extended syntax so we can delete "extended" subdirectories and files
            // (most notably ones with trailing whitespace or periods)
            fullPath = PathInternal.EnsureExtendedPrefix(fullPath);

            Interop.Kernel32.WIN32_FIND_DATA findData = new Interop.Kernel32.WIN32_FIND_DATA();
            RemoveDirectoryRecursive(fullPath, ref findData, topLevel: true);
        }
Exemplo n.º 7
0
        public static void RemoveDirectory(string fullPath, bool recursive)
        {
            if (!recursive)
            {
                RemoveDirectoryInternal(fullPath, topLevel: true);
                return;
            }

            Interop.Kernel32.WIN32_FIND_DATA findData = default;
            GetFindData(fullPath, ref findData);
            if (IsNameSurrogateReparsePoint(ref findData))
            {
                // Don't recurse
                RemoveDirectoryInternal(fullPath, topLevel: true);
                return;
            }

            // We want extended syntax so we can delete "extended" subdirectories and files
            // (most notably ones with trailing whitespace or periods)
            fullPath = PathInternal.EnsureExtendedPrefix(fullPath);
            RemoveDirectoryRecursive(fullPath, ref findData, topLevel: true);
        }
Exemplo n.º 8
0
 [SecurityCritical]  // auto-generated
 internal static bool IsFile(ref Interop.Kernel32.WIN32_FIND_DATA data)
 {
     return(0 == (data.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY));
 }
Exemplo n.º 9
0
            internal override bool IsResultIncluded(string fullPath, string userPath, ref Interop.Kernel32.WIN32_FIND_DATA findData, out FileSystemInfo result)
            {
                if (Win32FileSystemEnumerableHelpers.IsFile(ref findData))
                {
                    string fullPathFinal = Path.Combine(fullPath, findData.cFileName.GetStringFromFixedBuffer());
                    result = new FileInfo(fullPathFinal, ref findData);
                    return(true);
                }
                else if (Win32FileSystemEnumerableHelpers.IsDir(ref findData))
                {
                    string fullPathFinal = Path.Combine(fullPath, findData.cFileName.GetStringFromFixedBuffer());
                    result = new DirectoryInfo(fullPathFinal, ref findData);
                    return(true);
                }

                result = null;
                return(false);
            }
Exemplo n.º 10
0
 [SecurityCritical]  // auto-generated
 internal static bool IsDir(ref Interop.Kernel32.WIN32_FIND_DATA data)
 {
     // Don't add "." nor ".."
     return((0 != (data.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY)) &&
            !data.cFileName.FixedBufferEqualsString(".") && !data.cFileName.FixedBufferEqualsString(".."));
 }
Exemplo n.º 11
0
 internal abstract bool IsResultIncluded(string fullPath, string userPath, ref Interop.Kernel32.WIN32_FIND_DATA findData, out TSource result);
Exemplo n.º 12
0
            internal override bool IsResultIncluded(string fullPath, string userPath, ref Interop.Kernel32.WIN32_FIND_DATA findData, out string result)
            {
                if ((_includeFiles && Win32FileSystemEnumerableHelpers.IsFile(ref findData)) ||
                    (_includeDirs && Win32FileSystemEnumerableHelpers.IsDir(ref findData)))
                {
                    result = Path.Combine(userPath, findData.cFileName.GetStringFromFixedBuffer());
                    return(true);
                }

                result = null;
                return(false);
            }
Exemplo n.º 13
0
        public override bool MoveNext()
        {
            Interop.Kernel32.WIN32_FIND_DATA data = new Interop.Kernel32.WIN32_FIND_DATA();
            switch (state)
            {
            case STATE_INIT:
            {
                if (_empty)
                {
                    state = STATE_FINISH;
                    goto case STATE_FINISH;
                }
                if (_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:
            {
                Debug.Assert(_searchOption != SearchOption.TopDirectoryOnly, "should not reach this code path if searchOption == TopDirectoryOnly");
                Debug.Assert(_searchList != null, "_searchList should not be null");

                // Traverse directory structure. We need to get '*'
                while (_searchList.Count > 0)
                {
                    int index = _searchList.Count - 1;
                    _searchData = _searchList[index];
                    Debug.Assert((_searchData.FullPath != null), "fullpath can't be null!");
                    _searchList.RemoveAt(index);

                    // Traverse the subdirs
                    AddSearchableDirsToList(_searchData);

                    // Execute searchCriteria against the current directory
                    string searchPath = Path.Combine(_searchData.FullPath, _searchCriteria);

                    using (new DisableMediaInsertionPrompt())
                    {
                        // Open a Find handle
                        _hnd = Interop.Kernel32.FindFirstFile(searchPath, ref data);

                        if (_hnd.IsInvalid)
                        {
                            int errorCode = Marshal.GetLastWin32Error();
                            switch (errorCode)
                            {
                            case Interop.Errors.ERROR_FILE_NOT_FOUND:
                            case Interop.Errors.ERROR_NO_MORE_FILES:
                            case Interop.Errors.ERROR_PATH_NOT_FOUND:
                                continue;
                            }

                            _hnd.Dispose();
                            throw HandleError(errorCode, _searchData.FullPath);
                        }
                    }

                    state = STATE_FIND_NEXT_FILE;

                    TSource result;
                    if (IsResultIncluded(ref data, out result))
                    {
                        current = result;
                        return(true);
                    }
                    else
                    {
                        goto case STATE_FIND_NEXT_FILE;
                    }
                }
                state = STATE_FINISH;
                goto case STATE_FINISH;
            }

            case STATE_FIND_NEXT_FILE:
            {
                if (_hnd != null)
                {
                    using (new DisableMediaInsertionPrompt())
                    {
                        // Keep asking for more matching files/dirs, add it to the list
                        while (Interop.Kernel32.FindNextFile(_hnd, ref data))
                        {
                            TSource result;
                            if (IsResultIncluded(ref data, out result))
                            {
                                current = result;
                                return(true);
                            }
                        }
                    }

                    // Make sure we quit with a sensible error.
                    int errorCode = Marshal.GetLastWin32Error();
                    _hnd?.Dispose();

                    switch (errorCode)
                    {
                    case Interop.Errors.ERROR_SUCCESS:
                    case Interop.Errors.ERROR_NO_MORE_FILES:

                    // ERROR_FILE_NOT_FOUND is valid here because if the top level
                    // dir doesn't contain any subdirs and matching files then
                    // we will get here with this errorcode from the _searchList walk
                    case Interop.Errors.ERROR_FILE_NOT_FOUND:
                        break;

                    default:
                        throw HandleError(errorCode, _searchData.FullPath);
                    }
                }

                if (_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);
        }
Exemplo n.º 14
0
        [SecurityCritical]  // auto-generated
        private void AddSearchableDirsToList(PathPair localSearchData)
        {
            string         searchPath = Path.Combine(localSearchData.FullPath, "*");
            SafeFindHandle hnd        = null;

            Interop.Kernel32.WIN32_FIND_DATA data = new Interop.Kernel32.WIN32_FIND_DATA();
            try
            {
                using (new DisableMediaInsertionPrompt())
                {
                    // Get all files and dirs
                    hnd = Interop.Kernel32.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
                        // _searchList will become empty
                        switch (errorCode)
                        {
                        case Interop.Errors.ERROR_FILE_NOT_FOUND:
                        case Interop.Errors.ERROR_NO_MORE_FILES:
                        case Interop.Errors.ERROR_PATH_NOT_FOUND:
                            return;

                        default:
                            throw HandleError(errorCode, localSearchData.FullPath);
                        }
                    }
                }

                // Add subdirs to _searchList. Exempt ReparsePoints as appropriate
                Debug.Assert(_searchList != null, "_searchList should not be null");
                int initialCount = _searchList.Count;
                do
                {
                    if (Win32FileSystemEnumerableHelpers.IsDir(ref data))
                    {
                        string fileName = data.cFileName.GetStringFromFixedBuffer();

                        Debug.Assert(fileName.Length != 0 && !Path.IsPathRooted(fileName),
                                     "Expected file system enumeration to not have empty file/directory name and not have rooted name");

                        string tempFullPath = Path.Combine(localSearchData.FullPath, fileName);
                        string tempUserPath = Path.Combine(localSearchData.UserPath, fileName);

                        // Setup search data for the sub directory and push it into the list
                        PathPair searchDataSubDir = new PathPair(tempUserPath, tempFullPath);

                        _searchList.Add(searchDataSubDir);
                    }
                } while (Interop.Kernel32.FindNextFile(hnd, ref data));

                // Reverse the items just added to maintain FIFO order
                if (_searchList.Count > initialCount)
                {
                    _searchList.Reverse(initialCount, _searchList.Count - initialCount);
                }

                // We don't care about errors here
            }
            finally
            {
                hnd?.Dispose();
            }
        }
Exemplo n.º 15
0
 internal FileInfo(string fullPath, ref Interop.Kernel32.WIN32_FIND_DATA findData)
     : this(fullPath, findData.cFileName.GetStringFromFixedBuffer())
 {
     Debug.Assert(findData.cFileName.FixedBufferEqualsString(Path.GetFileName(fullPath)));
     Init(ref findData);
 }
        private static 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.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data = new Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA();
                if (Interop.Kernel32.GetFileAttributesEx(fullPath, Interop.Kernel32.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, ref data))
                {
                    // got the attributes
                    if ((data.fileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) != 0 ||
                        (data.fileAttributes & Interop.Kernel32.FileAttributes.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.Kernel32.WIN32_FIND_DATA findData = new Interop.Kernel32.WIN32_FIND_DATA();
                        using (SafeFindHandle handle = Interop.Kernel32.FindFirstFile(fullPath, ref findData))
                        {
                            if (!handle.IsInvalid)
                            {
                                // got the find data, use WinRT for placeholder files

                                Debug.Assert((findData.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) == 0);
                                Debug.Assert((findData.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_REPARSE_POINT) != 0);

                                useWinRt = findData.dwReserved0 == Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_FILE_PLACEHOLDER;
                                break;
                            }
                        }
                    }
                }

                int error = Marshal.GetLastWin32Error();
                Debug.Assert(error != Interop.Errors.ERROR_SUCCESS);

                if (error == Interop.Errors.ERROR_ACCESS_DENIED)
                {
                    // The path was not accessible with Win32, so try WinRT
                    useWinRt = true;
                    break;
                }
                else if (error != Interop.Errors.ERROR_PATH_NOT_FOUND && error != Interop.Errors.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;
        }
Exemplo n.º 17
0
 internal void Init(ref Interop.Kernel32.WIN32_FIND_DATA findData)
 {
     // Copy the information to data
     _data.PopulateFrom(ref findData);
     _dataInitialized = 0;
 }
Exemplo n.º 18
0
        private static unsafe string?GetFinalLinkTarget(string linkPath, bool isDirectory)
        {
            Interop.Kernel32.WIN32_FIND_DATA data = default;
            GetFindData(linkPath, isDirectory, ignoreAccessDenied: false, ref data);

            // The file or directory is not a reparse point.
            if ((data.dwFileAttributes & (uint)FileAttributes.ReparsePoint) == 0 ||
                // Only symbolic links are supported at the moment.
                (data.dwReserved0 & Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_SYMLINK) == 0)
            {
                return(null);
            }

            // We try to open the final file since they asked for the final target.
            using SafeFileHandle handle = OpenSafeFileHandle(linkPath,
                                                             Interop.Kernel32.FileOperations.OPEN_EXISTING |
                                                             Interop.Kernel32.FileOperations.FILE_FLAG_BACKUP_SEMANTICS);

            if (handle.IsInvalid)
            {
                // If the handle fails because it is unreachable, is because the link was broken.
                // We need to fallback to manually traverse the links and return the target of the last resolved link.
                int error = Marshal.GetLastWin32Error();
                if (IsPathUnreachableError(error))
                {
                    return(GetFinalLinkTargetSlow(linkPath));
                }

                throw Win32Marshal.GetExceptionForWin32Error(error, linkPath);
            }

            const int InitialBufferSize = 4096;

            char[] buffer = ArrayPool <char> .Shared.Rent(InitialBufferSize);

            try
            {
                uint result = GetFinalPathNameByHandle(handle, buffer);

                // If the function fails because lpszFilePath is too small to hold the string plus the terminating null character,
                // the return value is the required buffer size, in TCHARs. This value includes the size of the terminating null character.
                if (result > buffer.Length)
                {
                    char[] toReturn = buffer;
                    buffer = ArrayPool <char> .Shared.Rent((int)result);

                    ArrayPool <char> .Shared.Return(toReturn);

                    result = GetFinalPathNameByHandle(handle, buffer);
                }

                // If the function fails for any other reason, the return value is zero.
                if (result == 0)
                {
                    throw Win32Marshal.GetExceptionForLastWin32Error(linkPath);
                }

                Debug.Assert(PathInternal.IsExtended(new string(buffer, 0, (int)result).AsSpan()));
                // GetFinalPathNameByHandle always returns with extended DOS prefix even if the link target was created without one.
                // While this does not interfere with correct behavior, it might be unexpected.
                // Hence we trim it if the passed-in path to the link wasn't extended.
                int start = PathInternal.IsExtended(linkPath.AsSpan()) ? 0 : 4;
                return(new string(buffer, start, (int)result - start));
            }
            finally
            {
                ArrayPool <char> .Shared.Return(buffer);
            }

            uint GetFinalPathNameByHandle(SafeFileHandle handle, char[] buffer)
            {
                fixed(char *bufPtr = buffer)
                {
                    return(Interop.Kernel32.GetFinalPathNameByHandle(handle, bufPtr, (uint)buffer.Length, Interop.Kernel32.FILE_NAME_NORMALIZED));
                }
            }

            string?GetFinalLinkTargetSlow(string linkPath)
            {
                // Since all these paths will be passed to CreateFile, which takes a string anyway, it is pointless to use span.
                // I am not sure if it's possible to change CreateFile's param to ROS<char> and avoid all these allocations.

                // We don't throw on error since we already did all the proper validations before.
                string?current = GetImmediateLinkTarget(linkPath, isDirectory, throwOnError: false, returnFullPath: true);
                string?prev    = null;

                while (current != null)
                {
                    prev    = current;
                    current = GetImmediateLinkTarget(current, isDirectory, throwOnError: false, returnFullPath: true);
                }

                return(prev);
            }
        }
Exemplo n.º 19
0
        // Returns 0 on success, otherwise a Win32 error code.  Note that
        // classes should use -1 as the uninitialized state for dataInitialized.
        internal static int FillAttributeInfo(String path, ref Interop.Kernel32.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.Kernel32.WIN32_FIND_DATA findData;
                findData = new Interop.Kernel32.WIN32_FIND_DATA();

                // Remove trailing slash since this can cause grief to FindFirstFile. You will get an invalid argument error
                String tempPath = path.TrimEnd(new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar });

                // 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.
                // SetThreadErrorMode will let us disable this, but we should set the error
                // mode back, since this may have wide-ranging effects.
                uint oldMode;
                bool setThreadErrorModeSuccess = Interop.Kernel32.SetThreadErrorMode(Interop.Kernel32.SEM_FAILCRITICALERRORS, out oldMode);
                try
                {
                    bool           error  = false;
                    SafeFindHandle handle = Interop.Kernel32.FindFirstFile(tempPath, ref findData);
                    try
                    {
                        if (handle.IsInvalid)
                        {
                            error     = true;
                            errorCode = Marshal.GetLastWin32Error();

                            if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND ||
                                errorCode == Interop.Errors.ERROR_PATH_NOT_FOUND ||
                                errorCode == Interop.Errors.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
                {
                    if (setThreadErrorModeSuccess)
                    {
                        Interop.Kernel32.SetThreadErrorMode(oldMode, out oldMode);
                    }
                }

                // Copy the information to data
                data.PopulateFrom(ref 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.
                // SetThreadErrorMode 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;
                bool setThreadErrorModeSuccess = Interop.Kernel32.SetThreadErrorMode(Interop.Kernel32.SEM_FAILCRITICALERRORS, out oldMode);
                try
                {
                    success = Interop.Kernel32.GetFileAttributesEx(path, Interop.Kernel32.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, ref data);
                }
                finally
                {
                    if (setThreadErrorModeSuccess)
                    {
                        Interop.Kernel32.SetThreadErrorMode(oldMode, out oldMode);
                    }
                }

                if (!success)
                {
                    errorCode = Marshal.GetLastWin32Error();
                    if (errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND &&
                        errorCode != Interop.Errors.ERROR_PATH_NOT_FOUND &&
                        errorCode != Interop.Errors.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);
        }
Exemplo n.º 20
0
        private static 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.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data = new Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA();
                if (Interop.Kernel32.GetFileAttributesEx(fullPath, Interop.Kernel32.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, ref data))
                {
                    // got the attributes
                    if ((data.fileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) != 0 ||
                        (data.fileAttributes & Interop.Kernel32.FileAttributes.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.Kernel32.WIN32_FIND_DATA findData = new Interop.Kernel32.WIN32_FIND_DATA();
                        using (SafeFindHandle handle = Interop.Kernel32.FindFirstFile(fullPath, ref findData))
                        {
                            if (!handle.IsInvalid)
                            {
                                // got the find data, use WinRT for placeholder files

                                Debug.Assert((findData.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) == 0);
                                Debug.Assert((findData.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_REPARSE_POINT) != 0);

                                useWinRt = findData.dwReserved0 == Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_FILE_PLACEHOLDER;
                                break;
                            }
                        }
                    }
                }

                int error = Marshal.GetLastWin32Error();
                Debug.Assert(error != Interop.Errors.ERROR_SUCCESS);

                if (error == Interop.Errors.ERROR_ACCESS_DENIED)
                {
                    // The path was not accessible with Win32, so try WinRT
                    useWinRt = true;
                    break;
                }
                else if (error != Interop.Errors.ERROR_PATH_NOT_FOUND && error != Interop.Errors.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);
        }
Exemplo n.º 21
0
        private static void RemoveDirectoryRecursive(string fullPath, ref Interop.Kernel32.WIN32_FIND_DATA findData, bool topLevel)
        {
            int       errorCode;
            Exception exception = null;

            using (SafeFindHandle handle = Interop.Kernel32.FindFirstFile(Directory.EnsureTrailingDirectorySeparator(fullPath) + "*", ref findData))
            {
                if (handle.IsInvalid)
                {
                    throw Win32Marshal.GetExceptionForLastWin32Error(fullPath);
                }

                do
                {
                    if ((findData.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) == 0)
                    {
                        // File
                        string fileName = findData.cFileName.GetStringFromFixedBuffer();
                        if (!Interop.Kernel32.DeleteFile(Path.Combine(fullPath, fileName)) && exception == null)
                        {
                            errorCode = Marshal.GetLastWin32Error();

                            // We don't care if something else deleted the file first
                            if (errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND)
                            {
                                exception = Win32Marshal.GetExceptionForWin32Error(errorCode, fileName);
                            }
                        }
                    }
                    else
                    {
                        // Directory, skip ".", "..".
                        if (findData.cFileName.FixedBufferEqualsString(".") || findData.cFileName.FixedBufferEqualsString(".."))
                        {
                            continue;
                        }

                        string fileName = findData.cFileName.GetStringFromFixedBuffer();
                        if ((findData.dwFileAttributes & (int)FileAttributes.ReparsePoint) == 0)
                        {
                            // Not a reparse point, recurse.
                            try
                            {
                                RemoveDirectoryRecursive(
                                    Path.Combine(fullPath, fileName),
                                    findData: ref findData,
                                    topLevel: false);
                            }
                            catch (Exception e)
                            {
                                if (exception == null)
                                {
                                    exception = e;
                                }
                            }
                        }
                        else
                        {
                            // Reparse point, don't recurse, just remove. (dwReserved0 is documented for this flag)
                            if (findData.dwReserved0 == Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_MOUNT_POINT)
                            {
                                // Mount point. Unmount using full path plus a trailing '\'.
                                // (Note: This doesn't remove the underlying directory)
                                string mountPoint = Path.Combine(fullPath, fileName + PathHelpers.DirectorySeparatorCharAsString);
                                if (!Interop.Kernel32.DeleteVolumeMountPoint(mountPoint) && exception == null)
                                {
                                    errorCode = Marshal.GetLastWin32Error();
                                    if (errorCode != Interop.Errors.ERROR_SUCCESS &&
                                        errorCode != Interop.Errors.ERROR_PATH_NOT_FOUND)
                                    {
                                        exception = Win32Marshal.GetExceptionForWin32Error(errorCode, fileName);
                                    }
                                }
                            }

                            // Note that RemoveDirectory on a symbolic link will remove the link itself.
                            if (!Interop.Kernel32.RemoveDirectory(Path.Combine(fullPath, fileName)) && exception == null)
                            {
                                errorCode = Marshal.GetLastWin32Error();
                                if (errorCode != Interop.Errors.ERROR_PATH_NOT_FOUND)
                                {
                                    exception = Win32Marshal.GetExceptionForWin32Error(errorCode, fileName);
                                }
                            }
                        }
                    }
                } while (Interop.Kernel32.FindNextFile(handle, ref findData));

                if (exception != null)
                {
                    throw exception;
                }

                errorCode = Marshal.GetLastWin32Error();
                if (errorCode != Interop.Errors.ERROR_SUCCESS && errorCode != Interop.Errors.ERROR_NO_MORE_FILES)
                {
                    throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
                }
            }

            RemoveDirectoryInternal(fullPath, topLevel: topLevel);
        }
Exemplo n.º 22
0
        [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.Kernel32.WIN32_FIND_DATA data = new Interop.Kernel32.WIN32_FIND_DATA();

                // Open a Find handle
                using (SafeFindHandle hnd = Interop.Kernel32.FindFirstFile(Directory.EnsureTrailingDirectorySeparator(fullPath) + "*", ref data))
                {
                    if (hnd.IsInvalid)
                        throw Win32Marshal.GetExceptionForLastWin32Error(fullPath);

                    do
                    {
                        bool isDir = (0 != (data.dwFileAttributes & Interop.Kernel32.FileAttributes.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.Kernel32.IOReparseOptions.IO_REPARSE_TAG_MOUNT_POINT)
                                {
                                    // Use full path plus a trailing '\'
                                    String mountPoint = Path.Combine(fullPath, data.cFileName + PathHelpers.DirectorySeparatorCharAsString);
                                    if (!Interop.Kernel32.DeleteVolumeMountPoint(mountPoint))
                                    {
                                         errorCode = Marshal.GetLastWin32Error();
                                    
                                        if (errorCode != Interop.Errors.ERROR_SUCCESS && 
                                            errorCode != Interop.Errors.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.Kernel32.RemoveDirectory(reparsePoint);
                                if (!r)
                                {
                                    errorCode = Marshal.GetLastWin32Error();
                                    if (errorCode != Interop.Errors.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.Kernel32.DeleteFile(fileName);
                            if (!r)
                            {
                                errorCode = Marshal.GetLastWin32Error();
                                if (errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND)
                                {
                                    try
                                    {
                                        throw Win32Marshal.GetExceptionForWin32Error(errorCode, data.cFileName);
                                    }
                                    catch (Exception e)
                                    {
                                        if (ex == null)
                                            ex = e;
                                    }
                                }
                            }
                        }
                    } while (Interop.Kernel32.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.Errors.ERROR_NO_MORE_FILES)
                    throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
            }

            r = Interop.Kernel32.RemoveDirectory(fullPath);

            if (!r)
            {
                errorCode = Marshal.GetLastWin32Error();
                if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND) // A dubious error code.
                    errorCode = Interop.Errors.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.Errors.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.Errors.ERROR_PATH_NOT_FOUND && !throwOnTopLevelDirectoryNotFound)
                    return;

                throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
            }
        }
Exemplo n.º 23
0
 internal FileInfo(string fullPath, ref Interop.Kernel32.WIN32_FIND_DATA findData)
     : this(fullPath, findData.cFileName)
 {
     Debug.Assert(string.Equals(findData.cFileName, Path.GetFileName(fullPath), StringComparison.Ordinal));
     Init(ref findData);
 }
Exemplo n.º 24
0
        /// <summary>
        /// Returns 0 on success, otherwise a Win32 error code.  Note that
        /// classes should use -1 as the uninitialized state for dataInitialized.
        /// </summary>
        /// <param name="returnErrorOnNotFound">Return the error code for not found errors?</param>
        internal static int FillAttributeInfo(string path, ref Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data, bool returnErrorOnNotFound)
        {
            int errorCode = Interop.Errors.ERROR_SUCCESS;

            // Neither GetFileAttributes or FindFirstFile like trailing separators
            path = PathInternal.TrimEndingDirectorySeparator(path);

            using (DisableMediaInsertionPrompt.Create())
            {
                if (!Interop.Kernel32.GetFileAttributesEx(path, Interop.Kernel32.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, ref data))
                {
                    errorCode = Marshal.GetLastWin32Error();
                    if (errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND &&
                        errorCode != Interop.Errors.ERROR_PATH_NOT_FOUND &&
                        errorCode != Interop.Errors.ERROR_NOT_READY &&
                        errorCode != Interop.Errors.ERROR_INVALID_NAME &&
                        errorCode != Interop.Errors.ERROR_BAD_PATHNAME &&
                        errorCode != Interop.Errors.ERROR_BAD_NETPATH &&
                        errorCode != Interop.Errors.ERROR_BAD_NET_NAME &&
                        errorCode != Interop.Errors.ERROR_INVALID_PARAMETER &&
                        errorCode != Interop.Errors.ERROR_NETWORK_UNREACHABLE)
                    {
                        // Assert so we can track down other cases (if any) to add to our test suite
                        Debug.Assert(errorCode == Interop.Errors.ERROR_ACCESS_DENIED || errorCode == Interop.Errors.ERROR_SHARING_VIOLATION,
                                     $"Unexpected error code getting attributes {errorCode}");

                        // Files that are marked for deletion will not let you GetFileAttributes,
                        // ERROR_ACCESS_DENIED is given back without filling out the data struct.
                        // FindFirstFile, however, will. Historically we always gave back attributes
                        // for marked-for-deletion files.
                        //
                        // Another case where enumeration works is with special system files such as
                        // pagefile.sys that give back ERROR_SHARING_VIOLATION on GetAttributes.
                        //
                        // Ideally we'd only try again for known cases due to the potential performance
                        // hit. The last attempt to do so baked for nearly a year before we found the
                        // pagefile.sys case. As such we're probably stuck filtering out specific
                        // cases that we know we don't want to retry on.

                        var findData = new Interop.Kernel32.WIN32_FIND_DATA();
                        using (SafeFindHandle handle = Interop.Kernel32.FindFirstFile(path, ref findData))
                        {
                            if (handle.IsInvalid)
                            {
                                errorCode = Marshal.GetLastWin32Error();
                            }
                            else
                            {
                                errorCode = Interop.Errors.ERROR_SUCCESS;
                                data.PopulateFrom(ref findData);
                            }
                        }
                    }
                }
            }

            if (errorCode != Interop.Errors.ERROR_SUCCESS && !returnErrorOnNotFound)
            {
                switch (errorCode)
                {
                case Interop.Errors.ERROR_FILE_NOT_FOUND:
                case Interop.Errors.ERROR_PATH_NOT_FOUND:
                case Interop.Errors.ERROR_NOT_READY:     // Removable media not ready
                    // Return default value for backward compatibility
                    data.dwFileAttributes = -1;
                    return(Interop.Errors.ERROR_SUCCESS);
                }
            }

            return(errorCode);
        }
Exemplo n.º 25
0
        [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.Kernel32.WIN32_FIND_DATA data = new Interop.Kernel32.WIN32_FIND_DATA();

                // Open a Find handle
                using (SafeFindHandle hnd = Interop.Kernel32.FindFirstFile(Directory.EnsureTrailingDirectorySeparator(fullPath) + "*", ref data))
                {
                    if (hnd.IsInvalid)
                    {
                        throw Win32Marshal.GetExceptionForLastWin32Error(fullPath);
                    }

                    do
                    {
                        bool isDir = (0 != (data.dwFileAttributes & Interop.Kernel32.FileAttributes.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.Kernel32.IOReparseOptions.IO_REPARSE_TAG_MOUNT_POINT)
                                {
                                    // Use full path plus a trailing '\'
                                    string mountPoint = Path.Combine(fullPath, data.cFileName + PathHelpers.DirectorySeparatorCharAsString);
                                    if (!Interop.Kernel32.DeleteVolumeMountPoint(mountPoint))
                                    {
                                        errorCode = Marshal.GetLastWin32Error();

                                        if (errorCode != Interop.Errors.ERROR_SUCCESS &&
                                            errorCode != Interop.Errors.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.Kernel32.RemoveDirectory(reparsePoint);
                                if (!r)
                                {
                                    errorCode = Marshal.GetLastWin32Error();
                                    if (errorCode != Interop.Errors.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.Kernel32.DeleteFile(fileName);
                            if (!r)
                            {
                                errorCode = Marshal.GetLastWin32Error();
                                if (errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND)
                                {
                                    try
                                    {
                                        throw Win32Marshal.GetExceptionForWin32Error(errorCode, data.cFileName);
                                    }
                                    catch (Exception e)
                                    {
                                        if (ex == null)
                                        {
                                            ex = e;
                                        }
                                    }
                                }
                            }
                        }
                    } while (Interop.Kernel32.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.Errors.ERROR_NO_MORE_FILES)
                {
                    throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
                }
            }

            r = Interop.Kernel32.RemoveDirectory(fullPath);

            if (!r)
            {
                errorCode = Marshal.GetLastWin32Error();
                if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND) // A dubious error code.
                {
                    errorCode = Interop.Errors.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.Errors.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.Errors.ERROR_PATH_NOT_FOUND && !throwOnTopLevelDirectoryNotFound)
                {
                    return;
                }

                throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
            }
        }
Exemplo n.º 26
0
        private static void RemoveDirectoryRecursive(string fullPath, ref Interop.Kernel32.WIN32_FIND_DATA findData, bool topLevel)
        {
            int       errorCode;
            Exception exception = null;

            using (SafeFindHandle handle = Interop.Kernel32.FindFirstFile(Path.Join(fullPath, "*"), ref findData))
            {
                if (handle.IsInvalid)
                {
                    throw Win32Marshal.GetExceptionForLastWin32Error(fullPath);
                }

                do
                {
                    if ((findData.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) == 0)
                    {
                        // File
                        string fileName = findData.cFileName.GetStringFromFixedBuffer();
                        if (!Interop.Kernel32.DeleteFile(Path.Combine(fullPath, fileName)) && exception == null)
                        {
                            errorCode = Marshal.GetLastWin32Error();

                            // We don't care if something else deleted the file first
                            if (errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND)
                            {
                                exception = Win32Marshal.GetExceptionForWin32Error(errorCode, fileName);
                            }
                        }
                    }
                    else
                    {
                        // Directory, skip ".", "..".
                        if (findData.cFileName.FixedBufferEqualsString(".") || findData.cFileName.FixedBufferEqualsString(".."))
                        {
                            continue;
                        }

                        string fileName = findData.cFileName.GetStringFromFixedBuffer();

                        if (!IsNameSurrogateReparsePoint(ref findData))
                        {
                            // Not a reparse point, or the reparse point isn't a name surrogate, recurse.
                            try
                            {
                                RemoveDirectoryRecursive(
                                    Path.Combine(fullPath, fileName),
                                    findData: ref findData,
                                    topLevel: false);
                            }
                            catch (Exception e)
                            {
                                if (exception == null)
                                {
                                    exception = e;
                                }
                            }
                        }
                        else
                        {
                            // Name surrogate reparse point, don't recurse, simply remove the directory.
                            // If a mount point, we have to delete the mount point first.
                            if (findData.dwReserved0 == Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_MOUNT_POINT)
                            {
                                // Mount point. Unmount using full path plus a trailing '\'.
                                // (Note: This doesn't remove the underlying directory)
                                string mountPoint = Path.Join(fullPath, fileName, PathInternal.DirectorySeparatorCharAsString);
                                if (!Interop.Kernel32.DeleteVolumeMountPoint(mountPoint) && exception == null)
                                {
                                    errorCode = Marshal.GetLastWin32Error();
                                    if (errorCode != Interop.Errors.ERROR_SUCCESS &&
                                        errorCode != Interop.Errors.ERROR_PATH_NOT_FOUND)
                                    {
                                        exception = Win32Marshal.GetExceptionForWin32Error(errorCode, fileName);
                                    }
                                }
                            }

                            // Note that RemoveDirectory on a symbolic link will remove the link itself.
                            if (!Interop.Kernel32.RemoveDirectory(Path.Combine(fullPath, fileName)) && exception == null)
                            {
                                errorCode = Marshal.GetLastWin32Error();
                                if (errorCode != Interop.Errors.ERROR_PATH_NOT_FOUND)
                                {
                                    exception = Win32Marshal.GetExceptionForWin32Error(errorCode, fileName);
                                }
                            }
                        }
                    }
                } while (Interop.Kernel32.FindNextFile(handle, ref findData));

                if (exception != null)
                {
                    throw exception;
                }

                errorCode = Marshal.GetLastWin32Error();
                if (errorCode != Interop.Errors.ERROR_SUCCESS && errorCode != Interop.Errors.ERROR_NO_MORE_FILES)
                {
                    throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
                }
            }

            // As we successfully removed all of the files we shouldn't care about the directory itself
            // not being empty. As file deletion is just a marker to remove the file when all handles
            // are closed we could still have contents hanging around.
            RemoveDirectoryInternal(fullPath, topLevel: topLevel, allowDirectoryNotEmpty: true);
        }
Exemplo n.º 27
0
        [System.Security.SecurityCritical]  // auto-generated
        internal static int FillAttributeInfo(String path, ref Interop.Kernel32.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.Kernel32.WIN32_FIND_DATA findData;
                findData = new Interop.Kernel32.WIN32_FIND_DATA();

                // Remove trailing 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.Kernel32.SetErrorMode(Interop.Kernel32.SEM_FAILCRITICALERRORS);
                try
                {
                    bool error = false;
                    SafeFindHandle handle = Interop.Kernel32.FindFirstFile(tempPath, ref findData);
                    try
                    {
                        if (handle.IsInvalid)
                        {
                            error = true;
                            errorCode = Marshal.GetLastWin32Error();

                            if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND ||
                                errorCode == Interop.Errors.ERROR_PATH_NOT_FOUND ||
                                errorCode == Interop.Errors.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.Kernel32.SetErrorMode(oldMode);
                }

                // Copy the information to data
                data.PopulateFrom(ref 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.Kernel32.SetErrorMode(Interop.Kernel32.SEM_FAILCRITICALERRORS);
                try
                {
                    success = Interop.Kernel32.GetFileAttributesEx(path, Interop.Kernel32.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, ref data);
                }
                finally
                {
                    Interop.Kernel32.SetErrorMode(oldMode);
                }

                if (!success)
                {
                    errorCode = Marshal.GetLastWin32Error();
                    if (errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND &&
                        errorCode != Interop.Errors.ERROR_PATH_NOT_FOUND &&
                        errorCode != Interop.Errors.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;
        }