diff options
Diffstat (limited to 'src/System.Private.CoreLib/shared/System/IO/FileStream.Win32.cs')
-rw-r--r-- | src/System.Private.CoreLib/shared/System/IO/FileStream.Win32.cs | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/src/System.Private.CoreLib/shared/System/IO/FileStream.Win32.cs b/src/System.Private.CoreLib/shared/System/IO/FileStream.Win32.cs index 4b75ad6da..edcf8e546 100644 --- a/src/System.Private.CoreLib/shared/System/IO/FileStream.Win32.cs +++ b/src/System.Private.CoreLib/shared/System/IO/FileStream.Win32.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics; using Microsoft.Win32.SafeHandles; namespace System.IO @@ -43,5 +44,62 @@ namespace System.IO Interop.Kernel32.CreateFile(_path, fAccess, share, ref secAttrs, mode, flagsAndAttributes, IntPtr.Zero)); } } + + private static bool GetDefaultIsAsync(SafeFileHandle handle) + { + return handle.IsAsync ?? !IsHandleSynchronous(handle, ignoreInvalid: true) ?? DefaultIsAsync; + } + + private static unsafe bool? IsHandleSynchronous(SafeFileHandle fileHandle, bool ignoreInvalid) + { + if (fileHandle.IsInvalid) + return null; + + uint fileMode; + + int status = Interop.NtDll.NtQueryInformationFile( + FileHandle: fileHandle, + IoStatusBlock: out Interop.NtDll.IO_STATUS_BLOCK ioStatus, + FileInformation: &fileMode, + Length: sizeof(uint), + FileInformationClass: Interop.NtDll.FileModeInformation); + + switch (status) + { + case 0: + // We we're successful + break; + case Interop.NtDll.STATUS_INVALID_HANDLE: + if (!ignoreInvalid) + { + throw Win32Marshal.GetExceptionForWin32Error(Interop.Errors.ERROR_INVALID_HANDLE); + } + else + { + return null; + } + default: + // Something else is preventing access + Debug.Fail("Unable to get the file mode information, status was" + status.ToString()); + return null; + } + + // If either of these two flags are set, the file handle is synchronous (not overlapped) + return (fileMode & (Interop.NtDll.FILE_SYNCHRONOUS_IO_ALERT | Interop.NtDll.FILE_SYNCHRONOUS_IO_NONALERT)) > 0; + } + + private static void VerifyHandleIsSync(SafeFileHandle handle, int fileType, FileAccess access) + { + // As we can accurately check the handle type when we have access to NtQueryInformationFile we don't need to skip for + // any particular file handle type. + + // If the handle was passed in without an explicit async setting, we already looked it up in GetDefaultIsAsync + if (!handle.IsAsync.HasValue) + return; + + // If we can't check the handle, just assume it is ok. + if (!(IsHandleSynchronous(handle, ignoreInvalid: false) ?? true)) + throw new ArgumentException(SR.Arg_HandleNotSync, nameof(handle)); + } } } |