FileStream.WinRT.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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 Microsoft.Win32.SafeHandles;
  5. using System.Diagnostics;
  6. using System.Runtime.InteropServices;
  7. namespace System.IO
  8. {
  9. public partial class FileStream : Stream
  10. {
  11. private unsafe SafeFileHandle OpenHandle(FileMode mode, FileShare share, FileOptions options)
  12. {
  13. Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share);
  14. int access =
  15. ((_access & FileAccess.Read) == FileAccess.Read ? GENERIC_READ : 0) |
  16. ((_access & FileAccess.Write) == FileAccess.Write ? GENERIC_WRITE : 0);
  17. // Our Inheritable bit was stolen from Windows, but should be set in
  18. // the security attributes class. Don't leave this bit set.
  19. share &= ~FileShare.Inheritable;
  20. // Must use a valid Win32 constant here...
  21. if (mode == FileMode.Append)
  22. mode = FileMode.OpenOrCreate;
  23. Interop.Kernel32.CREATEFILE2_EXTENDED_PARAMETERS parameters = new Interop.Kernel32.CREATEFILE2_EXTENDED_PARAMETERS();
  24. parameters.dwSize = (uint)sizeof(Interop.Kernel32.CREATEFILE2_EXTENDED_PARAMETERS);
  25. parameters.dwFileFlags = (uint)options;
  26. parameters.lpSecurityAttributes = &secAttrs;
  27. using (DisableMediaInsertionPrompt.Create())
  28. {
  29. Debug.Assert(_path != null);
  30. return ValidateFileHandle(Interop.Kernel32.CreateFile2(
  31. lpFileName: _path,
  32. dwDesiredAccess: access,
  33. dwShareMode: share,
  34. dwCreationDisposition: mode,
  35. pCreateExParams: ref parameters));
  36. }
  37. }
  38. private static bool GetDefaultIsAsync(SafeFileHandle handle) => handle.IsAsync ?? DefaultIsAsync;
  39. private static unsafe bool? IsHandleSynchronous(SafeFileHandle handle, FileAccess access)
  40. {
  41. // Do NOT use this method on any type other than DISK. Reading or writing to a pipe may
  42. // cause an app to block incorrectly, introducing a deadlock (depending on whether a write
  43. // will wake up an already-blocked thread or this Win32FileStream's thread).
  44. byte* bytes = stackalloc byte[1];
  45. int numBytesReadWritten;
  46. int r = -1;
  47. // If the handle is a pipe, ReadFile will block until there
  48. // has been a write on the other end. We'll just have to deal with it,
  49. // For the read end of a pipe, you can mess up and
  50. // accidentally read synchronously from an async pipe.
  51. if ((access & FileAccess.Read) != 0)
  52. {
  53. r = Interop.Kernel32.ReadFile(handle, bytes, 0, out numBytesReadWritten, IntPtr.Zero);
  54. }
  55. else if ((access & FileAccess.Write) != 0)
  56. {
  57. r = Interop.Kernel32.WriteFile(handle, bytes, 0, out numBytesReadWritten, IntPtr.Zero);
  58. }
  59. if (r == 0)
  60. {
  61. int errorCode = Marshal.GetLastWin32Error();
  62. switch (errorCode)
  63. {
  64. case Interop.Errors.ERROR_INVALID_PARAMETER:
  65. return false;
  66. case Interop.Errors.ERROR_INVALID_HANDLE:
  67. throw Win32Marshal.GetExceptionForWin32Error(errorCode);
  68. }
  69. }
  70. return true;
  71. }
  72. private static void VerifyHandleIsSync(SafeFileHandle handle, int fileType, FileAccess access)
  73. {
  74. // The technique here only really works for FILE_TYPE_DISK. FileMode is the right thing to check, but it currently
  75. // isn't available in WinRT.
  76. if (fileType == Interop.Kernel32.FileTypes.FILE_TYPE_DISK)
  77. {
  78. // If we can't check the handle, just assume it is ok.
  79. if (!(IsHandleSynchronous(handle, access) ?? true))
  80. throw new ArgumentException(SR.Arg_HandleNotSync, nameof(handle));
  81. }
  82. }
  83. }
  84. }