Beispiel #1
0
        private static unsafe void ThrowExceptionEncryptDecryptFail(string fullPath)
        {
            int errorCode = Marshal.GetLastWin32Error();

            if (errorCode == Interop.Errors.ERROR_ACCESS_DENIED)
            {
                // Check to see if the file system support the Encrypted File System (EFS)
                string name = DriveInfoInternal.NormalizeDriveName(Path.GetPathRoot(fullPath) !);

                using (DisableMediaInsertionPrompt.Create())
                {
                    if (!Interop.Kernel32.GetVolumeInformation(name, null, 0, null, null, out int fileSystemFlags, null, 0))
                    {
                        errorCode = Marshal.GetLastWin32Error();
                        throw Win32Marshal.GetExceptionForWin32Error(errorCode, name);
                    }

                    if ((fileSystemFlags & Interop.Kernel32.FILE_SUPPORTS_ENCRYPTION) == 0)
                    {
                        throw new NotSupportedException(SR.PlatformNotSupported_FileEncryption);
                    }
                }
            }
            throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
        }
Beispiel #2
0
        private static unsafe SafeFileHandle CreateFileHandle(string fullPath, FileMode mode, FileSystemRights rights, FileShare share, FileOptions options, FileSecurity security)
        {
            Debug.Assert(fullPath != null);

            // Must use a valid Win32 constant
            if (mode == FileMode.Append)
            {
                mode = FileMode.OpenOrCreate;
            }

            // For mitigating local elevation of privilege attack through named pipes make sure we always call CreateFile with SECURITY_ANONYMOUS so that the
            // named pipe server can't impersonate a high privileged client security context (note that this is the effective default on CreateFile2)
            // SECURITY_SQOS_PRESENT flags that a SECURITY_ flag is present.
            int flagsAndAttributes = (int)options | Interop.Kernel32.SecurityOptions.SECURITY_SQOS_PRESENT | Interop.Kernel32.SecurityOptions.SECURITY_ANONYMOUS;

            SafeFileHandle handle;

            fixed(byte *pSecurityDescriptor = security.GetSecurityDescriptorBinaryForm())
            {
                var secAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES
                {
                    nLength              = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES),
                    bInheritHandle       = ((share & FileShare.Inheritable) != 0) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE,
                    lpSecurityDescriptor = (IntPtr)pSecurityDescriptor
                };

                using (DisableMediaInsertionPrompt.Create())
                {
                    handle = Interop.Kernel32.CreateFile(fullPath, (int)rights, share, ref secAttrs, mode, flagsAndAttributes, IntPtr.Zero);
                    ValidateFileHandle(handle, fullPath);
                }
            }

            return(handle);
        }
Beispiel #3
0
        private unsafe SafeFileHandle CreateFileOpenHandle(FileMode mode, FileShare share, FileOptions options)
        {
            Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share);

            int fAccess =
                ((_access & FileAccess.Read) == FileAccess.Read ? GENERIC_READ : 0) |
                ((_access & FileAccess.Write) == FileAccess.Write ? GENERIC_WRITE : 0);

            // Our Inheritable bit was stolen from Windows, but should be set in
            // the security attributes class.  Don't leave this bit set.
            share &= ~FileShare.Inheritable;

            // Must use a valid Win32 constant here...
            if (mode == FileMode.Append)
            {
                mode = FileMode.OpenOrCreate;
            }

            int flagsAndAttributes = (int)options;

            // For mitigating local elevation of privilege attack through named pipes
            // make sure we always call CreateFile with SECURITY_ANONYMOUS so that the
            // named pipe server can't impersonate a high privileged client security context
            // (note that this is the effective default on CreateFile2)
            flagsAndAttributes |= (Interop.Kernel32.SecurityOptions.SECURITY_SQOS_PRESENT | Interop.Kernel32.SecurityOptions.SECURITY_ANONYMOUS);

            using (DisableMediaInsertionPrompt.Create())
            {
                Debug.Assert(_path != null);
                return(ValidateFileHandle(
                           Interop.Kernel32.CreateFile(_path, fAccess, share, ref secAttrs, mode, flagsAndAttributes, IntPtr.Zero)));
            }
        }
Beispiel #4
0
        private unsafe SafeFileHandle CreateFile2OpenHandle(FileMode mode, FileShare share, FileOptions options)
        {
            Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share);

            int access =
                ((_access & FileAccess.Read) == FileAccess.Read ? GENERIC_READ : 0) |
                ((_access & FileAccess.Write) == FileAccess.Write ? GENERIC_WRITE : 0);

            // Our Inheritable bit was stolen from Windows, but should be set in
            // the security attributes class.  Don't leave this bit set.
            share &= ~FileShare.Inheritable;

            // Must use a valid Win32 constant here...
            if (mode == FileMode.Append)
            {
                mode = FileMode.OpenOrCreate;
            }

            Interop.Kernel32.CREATEFILE2_EXTENDED_PARAMETERS parameters = new Interop.Kernel32.CREATEFILE2_EXTENDED_PARAMETERS();
            parameters.dwSize               = (uint)sizeof(Interop.Kernel32.CREATEFILE2_EXTENDED_PARAMETERS);
            parameters.dwFileFlags          = (uint)options;
            parameters.lpSecurityAttributes = &secAttrs;

            using (DisableMediaInsertionPrompt.Create())
            {
                return(ValidateFileHandle(Interop.FileApiInterop.CreateFile2FromApp(
                                              lpFileName: _path,
                                              dwDesiredAccess: access,
                                              dwShareMode: share,
                                              dwCreationDisposition: mode,
                                              pCreateExParams: ref parameters)));
            }
        }
        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 (DisableMediaInsertionPrompt.Create())
            {
                // 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);
            }
        }
            static unsafe SafeFileHandle CreateFileHandleInternal(string fullPath, FileMode mode, FileSystemRights rights, FileShare share, int flagsAndAttributes, Interop.Kernel32.SECURITY_ATTRIBUTES *secAttrs)
            {
                SafeFileHandle handle;

                using (DisableMediaInsertionPrompt.Create())
                {
                    // The Inheritable bit is only set in the SECURITY_ATTRIBUTES struct,
                    // and should not be passed to the CreateFile P/Invoke.
                    handle = Interop.Kernel32.CreateFile(fullPath, (int)rights, (share & ~FileShare.Inheritable), secAttrs, mode, flagsAndAttributes, IntPtr.Zero);
                    ValidateFileHandle(handle, fullPath);
                }
                return(handle);
            }
Beispiel #7
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 = path.TrimEnd(PathHelpers.DirectorySeparatorChars);

            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_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.dwFileAttributes = -1;
                    return(Interop.Errors.ERROR_SUCCESS);
                }
            }

            return(errorCode);
        }
Beispiel #8
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);
        }
        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 (DisableMediaInsertionPrompt.Create())
                {
                    // 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();
            }
        }
        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 (DisableMediaInsertionPrompt.Create())
                    {
                        // 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 (DisableMediaInsertionPrompt.Create())
                    {
                        // 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);
        }