/src/System.IO.FileSystem/src/System/IO/WinRTFileStream.cs

https://gitlab.com/0072016/0072016-corefx- · C# · 234 lines · 178 code · 39 blank · 17 comment · 24 complexity · d3d627f98a3e965554a1bfaa8115901d MD5 · raw file

  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.Threading;
  7. using System.Threading.Tasks;
  8. using Windows.Storage;
  9. namespace System.IO
  10. {
  11. internal sealed class WinRTFileStream : FileStreamBase
  12. {
  13. private readonly FileAccess _access;
  14. private bool _disposed;
  15. private StorageFile _file;
  16. private readonly Stream _innerStream;
  17. private readonly FileOptions _options;
  18. private static readonly SafeFileHandle s_invalidHandle = new SafeFileHandle(IntPtr.Zero, false);
  19. internal WinRTFileStream(Stream innerStream, StorageFile file, FileAccess access, FileOptions options, FileStream parent)
  20. : base(parent)
  21. {
  22. Debug.Assert(innerStream != null);
  23. Debug.Assert(file != null);
  24. this._access = access;
  25. this._disposed = false;
  26. this._file = file;
  27. this._innerStream = innerStream;
  28. this._options = options;
  29. }
  30. ~WinRTFileStream()
  31. {
  32. Dispose(false);
  33. }
  34. #region FileStream members
  35. public override bool IsAsync { get { return true; } }
  36. public override string Name { get { return _file.Name; } }
  37. public override Microsoft.Win32.SafeHandles.SafeFileHandle SafeFileHandle { get { return s_invalidHandle; } }
  38. public override void Flush(bool flushToDisk)
  39. {
  40. // WinRT streams are not buffered, however the WinRT stream will be wrapped in a BufferedStream
  41. // Flush & FlushAsync will flush the internal managed buffer of the BufferedStream wrapper
  42. // The WinRT stream only exposes FlushAsync which flushes to disk.
  43. // The managed Stream adapter does nothing for Flush() and forwards to WinRT for FlushAsync (flushing to disk).
  44. if (flushToDisk)
  45. {
  46. // FlushAsync() will do the write to disk when it hits the WinRT->NetFx adapter
  47. Task flushTask = _innerStream.FlushAsync();
  48. flushTask.Wait();
  49. }
  50. else
  51. {
  52. // Flush doesn't write to disk
  53. _innerStream.Flush();
  54. }
  55. }
  56. #endregion
  57. #region Stream members
  58. #region Properties
  59. public override bool CanRead
  60. {
  61. // WinRT doesn't support write-only streams, override what the stream tells us
  62. // with what was passed in when creating it.
  63. get { return _innerStream.CanRead && (_access & FileAccess.Read) != 0; }
  64. }
  65. public override bool CanSeek
  66. {
  67. get { return _innerStream.CanSeek; }
  68. }
  69. public override bool CanWrite
  70. {
  71. get { return _innerStream.CanWrite; }
  72. }
  73. public override long Length
  74. {
  75. get { return _innerStream.Length; }
  76. }
  77. public override long Position
  78. {
  79. get { return _innerStream.Position; }
  80. set { _innerStream.Position = value; }
  81. }
  82. public override int ReadTimeout
  83. {
  84. get { return _innerStream.ReadTimeout; }
  85. set { _innerStream.ReadTimeout = value; }
  86. }
  87. public override bool CanTimeout
  88. {
  89. get { return _innerStream.CanTimeout; }
  90. }
  91. public override int WriteTimeout
  92. {
  93. get { return _innerStream.WriteTimeout; }
  94. set { _innerStream.WriteTimeout = value; }
  95. }
  96. #endregion Properties
  97. #region Methods
  98. public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
  99. {
  100. return _innerStream.CopyToAsync(destination, bufferSize, cancellationToken);
  101. }
  102. protected override void Dispose(bool disposing)
  103. {
  104. try
  105. {
  106. if (disposing)
  107. _innerStream.Dispose();
  108. if ((_options & FileOptions.DeleteOnClose) != 0 && _file != null)
  109. {
  110. // WinRT doesn't directly support DeleteOnClose but we can mimic it
  111. // There are a few reasons that this will fail
  112. // 1) the file may not allow delete permissions for the current user
  113. // 2) the storage file RCW may have already been disconnected
  114. try
  115. {
  116. _file.DeleteAsync().AsTask().Wait();
  117. }
  118. catch { }
  119. }
  120. _disposed = true;
  121. _file = null;
  122. }
  123. finally
  124. {
  125. base.Dispose(disposing);
  126. }
  127. }
  128. public override void Flush()
  129. {
  130. _parent.Flush(false);
  131. }
  132. public override Task FlushAsync(CancellationToken cancellationToken)
  133. {
  134. return _innerStream.FlushAsync(cancellationToken);
  135. }
  136. public override int Read(byte[] buffer, int offset, int count)
  137. {
  138. if (!_disposed && !CanRead)
  139. throw Error.GetReadNotSupported();
  140. return _innerStream.Read(buffer, offset, count);
  141. }
  142. public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
  143. {
  144. if (!_disposed && !CanRead)
  145. throw Error.GetReadNotSupported();
  146. return _innerStream.ReadAsync(buffer, offset, count, cancellationToken);
  147. }
  148. public override int ReadByte()
  149. {
  150. if (!_disposed && !CanRead)
  151. throw Error.GetReadNotSupported();
  152. return _innerStream.ReadByte();
  153. }
  154. public override long Seek(long offset, SeekOrigin origin)
  155. {
  156. if (origin == SeekOrigin.Begin && offset < 0)
  157. throw Win32Marshal.GetExceptionForWin32Error(Interop.mincore.Errors.ERROR_NEGATIVE_SEEK);
  158. return _innerStream.Seek(offset, origin);
  159. }
  160. public override void SetLength(long value)
  161. {
  162. _innerStream.SetLength(value);
  163. // WinRT ignores all errors when setting length, check after setting
  164. if (_innerStream.Length < value)
  165. {
  166. throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_FileLengthTooBig);
  167. }
  168. else if (_innerStream.Length != value)
  169. {
  170. throw new ArgumentException(SR.Argument_FileNotResized, nameof(value));
  171. }
  172. // WinRT doesn't update the position when truncating a file
  173. if (value < _innerStream.Position)
  174. _innerStream.Position = value;
  175. }
  176. public override string ToString()
  177. {
  178. return _innerStream.ToString();
  179. }
  180. public override void Write(byte[] buffer, int offset, int count)
  181. {
  182. _innerStream.Write(buffer, offset, count);
  183. }
  184. public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
  185. {
  186. return _innerStream.WriteAsync(buffer, offset, count, cancellationToken);
  187. }
  188. public override void WriteByte(byte value)
  189. {
  190. _innerStream.WriteByte(value);
  191. }
  192. #endregion Methods
  193. #endregion Stream members
  194. }
  195. }