FileStream.Win32.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Diagnostics;
  5. using Microsoft.Win32.SafeHandles;
  6. namespace System.IO
  7. {
  8. public partial class FileStream : Stream
  9. {
  10. private SafeFileHandle OpenHandle(FileMode mode, FileShare share, FileOptions options)
  11. {
  12. return CreateFileOpenHandle(mode, share, options);
  13. }
  14. private unsafe SafeFileHandle CreateFileOpenHandle(FileMode mode, FileShare share, FileOptions options)
  15. {
  16. Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share);
  17. int fAccess =
  18. ((_access & FileAccess.Read) == FileAccess.Read ? GENERIC_READ : 0) |
  19. ((_access & FileAccess.Write) == FileAccess.Write ? GENERIC_WRITE : 0);
  20. // Our Inheritable bit was stolen from Windows, but should be set in
  21. // the security attributes class. Don't leave this bit set.
  22. share &= ~FileShare.Inheritable;
  23. // Must use a valid Win32 constant here...
  24. if (mode == FileMode.Append)
  25. mode = FileMode.OpenOrCreate;
  26. int flagsAndAttributes = (int)options;
  27. // For mitigating local elevation of privilege attack through named pipes
  28. // make sure we always call CreateFile with SECURITY_ANONYMOUS so that the
  29. // named pipe server can't impersonate a high privileged client security context
  30. // (note that this is the effective default on CreateFile2)
  31. flagsAndAttributes |= (Interop.Kernel32.SecurityOptions.SECURITY_SQOS_PRESENT | Interop.Kernel32.SecurityOptions.SECURITY_ANONYMOUS);
  32. using (DisableMediaInsertionPrompt.Create())
  33. {
  34. return ValidateFileHandle(
  35. Interop.Kernel32.CreateFile(_path, fAccess, share, ref secAttrs, mode, flagsAndAttributes, IntPtr.Zero));
  36. }
  37. }
  38. private static bool GetDefaultIsAsync(SafeFileHandle handle)
  39. {
  40. return handle.IsAsync ?? !IsHandleSynchronous(handle, ignoreInvalid: true) ?? DefaultIsAsync;
  41. }
  42. private static unsafe bool? IsHandleSynchronous(SafeFileHandle fileHandle, bool ignoreInvalid)
  43. {
  44. if (fileHandle.IsInvalid)
  45. return null;
  46. uint fileMode;
  47. int status = Interop.NtDll.NtQueryInformationFile(
  48. FileHandle: fileHandle,
  49. IoStatusBlock: out Interop.NtDll.IO_STATUS_BLOCK ioStatus,
  50. FileInformation: &fileMode,
  51. Length: sizeof(uint),
  52. FileInformationClass: Interop.NtDll.FileModeInformation);
  53. switch (status)
  54. {
  55. case 0:
  56. // We we're successful
  57. break;
  58. case Interop.NtDll.STATUS_INVALID_HANDLE:
  59. if (!ignoreInvalid)
  60. {
  61. throw Win32Marshal.GetExceptionForWin32Error(Interop.Errors.ERROR_INVALID_HANDLE);
  62. }
  63. else
  64. {
  65. return null;
  66. }
  67. default:
  68. // Something else is preventing access
  69. Debug.Fail("Unable to get the file mode information, status was" + status.ToString());
  70. return null;
  71. }
  72. // If either of these two flags are set, the file handle is synchronous (not overlapped)
  73. return (fileMode & (Interop.NtDll.FILE_SYNCHRONOUS_IO_ALERT | Interop.NtDll.FILE_SYNCHRONOUS_IO_NONALERT)) > 0;
  74. }
  75. private static void VerifyHandleIsSync(SafeFileHandle handle, int fileType, FileAccess access)
  76. {
  77. // As we can accurately check the handle type when we have access to NtQueryInformationFile we don't need to skip for
  78. // any particular file handle type.
  79. // If the handle was passed in without an explicit async setting, we already looked it up in GetDefaultIsAsync
  80. if (!handle.IsAsync.HasValue)
  81. return;
  82. // If we can't check the handle, just assume it is ok.
  83. if (!(IsHandleSynchronous(handle, ignoreInvalid: false) ?? true))
  84. throw new ArgumentException(SR.Arg_HandleNotSync, nameof(handle));
  85. }
  86. }
  87. }