FileStream.WinRT.cs 4.1 KB

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