3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 /*============================================================
10 ** <OWNER>[....]</OWNER>
13 ** Purpose: Exposes a Stream around a file, with full
14 ** synchronous and asychronous support, and buffering.
17 ===========================================================*/
19 using Microsoft.Win32;
20 using Microsoft.Win32.SafeHandles;
21 using System.Security;
23 using System.Security.AccessControl;
25 using System.Security.Permissions;
26 using System.Threading;
28 using System.Threading.Tasks;
30 using System.Runtime.InteropServices;
32 using System.Runtime.Remoting.Messaging;
34 using System.Runtime.CompilerServices;
35 using System.Globalization;
36 using System.Runtime.Versioning;
37 using System.Diagnostics.Contracts;
38 using System.Diagnostics.Tracing;
41 * FileStream supports different modes of accessing the disk - async mode
42 * and [....] mode. They are two completely different codepaths in the
43 * [....] & async methods (ie, Read/Write vs. BeginRead/BeginWrite). File
44 * handles in NT can be opened in only [....] or overlapped (async) mode,
45 * and we have to deal with this pain. Stream has implementations of
46 * the [....] methods in terms of the async ones, so we'll
47 * call through to our base class to get those methods when necessary.
49 * Also buffering is added into FileStream as well. Folded in the
50 * code from BufferedStream, so all the comments about it being mostly
51 * aggressive (and the possible perf improvement) apply to FileStream as
52 * well. Also added some buffering to the async code paths.
55 * The class has one buffer, shared for reading & writing. It can only be
56 * used for one or the other at any point in time - not both. The following
58 * 0 <= _readPos <= _readLen < _bufferSize
59 * 0 <= _writePos < _bufferSize
60 * _readPos == _readLen && _readPos > 0 implies the read buffer is valid,
61 * but we're at the end of the buffer.
62 * _readPos == _readLen == 0 means the read buffer contains garbage.
63 * Either _writePos can be greater than 0, or _readLen & _readPos can be
64 * greater than zero, but neither can be greater than zero at the same time.
70 // This is an internal object implementing IAsyncResult with fields
71 // for all of the relevant data necessary to complete the IO operation.
72 // This is used by AsyncFSCallback and all of the async methods.
73 // We should probably make this a nested type of FileStream. But
74 // I don't know how to define a nested class in mscorlib.h
76 // Ideally we shoult make this type windows only (!FEATURE_PAL). But to make that happen
77 // we need to do a lot of untangling in the VM code.
78 unsafe internal sealed class FileStreamAsyncResult : IAsyncResult
81 // If you modify the order of these fields, make sure to update
82 // the native VM definition of this class as well!!!
85 private AsyncCallback _userCallback;
87 private Object _userStateObject;
88 private ManualResetEvent _waitHandle;
89 [System.Security.SecurityCritical]
90 private SafeFileHandle _handle; // For cancellation support.
93 private NativeOverlapped* _overlapped;
94 internal NativeOverlapped* OverLapped { [SecurityCritical]get { return _overlapped; } }
95 internal bool IsAsync { [SecuritySafeCritical]get { return _overlapped != null; } }
98 internal int _EndXxxCalled; // Whether we've called EndXxx already.
99 private int _numBytes; // number of bytes read OR written
100 internal int NumBytes { get { return _numBytes; } }
102 private int _errorCode;
103 internal int ErrorCode { get { return _errorCode; } }
105 private int _numBufferedBytes;
106 internal int NumBufferedBytes { get { return _numBufferedBytes; } }
108 internal int NumBytesRead { get { return _numBytes + _numBufferedBytes; } }
110 private bool _isWrite; // Whether this is a read or a write
111 internal bool IsWrite { get { return _isWrite; } }
113 private bool _isComplete; // Value for IsCompleted property
114 private bool _completedSynchronously; // Which thread called callback
116 // The NativeOverlapped struct keeps a GCHandle to this IAsyncResult object.
117 // So if the user doesn't call EndRead/EndWrite, a finalizer won't help because
118 // it'll never get called.
120 // Overlapped class will take care of the async IO operations in progress
121 // when an appdomain unload occurs.
124 [System.Security.SecurityCritical] // auto-generated
125 private unsafe static IOCompletionCallback s_IOCallback;
127 [SecuritySafeCritical]
128 internal FileStreamAsyncResult(
129 int numBufferedBytes,
131 SafeFileHandle handle,
132 AsyncCallback userCallback,
133 Object userStateObject,
136 _userCallback = userCallback;
137 _userStateObject = userStateObject;
139 _numBufferedBytes = numBufferedBytes;
142 // For Synchronous IO, I could go with either a callback and using
143 // the managed Monitor class, or I could create a handle and wait on it.
144 ManualResetEvent waitHandle = new ManualResetEvent(false);
145 _waitHandle = waitHandle;
147 // Create a managed overlapped class
148 // We will set the file offsets later
149 Overlapped overlapped = new Overlapped(0, 0, IntPtr.Zero, this);
151 // Pack the Overlapped class, and store it in the async result
152 if (userCallback != null)
154 var ioCallback = s_IOCallback; // cached static delegate; delay initialized due to it being SecurityCritical
155 if (ioCallback == null) s_IOCallback = ioCallback = new IOCompletionCallback(AsyncFSCallback);
156 _overlapped = overlapped.Pack(ioCallback, bytes);
160 _overlapped = overlapped.UnsafePack(null, bytes);
163 Contract.Assert(_overlapped != null, "Did Overlapped.Pack or Overlapped.UnsafePack just return a null?");
166 internal static FileStreamAsyncResult CreateBufferedReadResult(int numBufferedBytes, AsyncCallback userCallback, Object userStateObject, bool isWrite)
168 FileStreamAsyncResult asyncResult = new FileStreamAsyncResult(numBufferedBytes, userCallback, userStateObject, isWrite);
169 asyncResult.CallUserCallback();
173 // This creates a synchronous Async Result. We should consider making this a separate class and maybe merge it with
174 // System.IO.Stream.SynchronousAsyncResult
175 private FileStreamAsyncResult(int numBufferedBytes, AsyncCallback userCallback, Object userStateObject, bool isWrite)
177 _userCallback = userCallback;
178 _userStateObject = userStateObject;
180 _numBufferedBytes = numBufferedBytes;
182 #endif // FEATURE_ASYNC_IO
184 public Object AsyncState
186 get { return _userStateObject; }
189 public bool IsCompleted
191 get { return _isComplete; }
194 public WaitHandle AsyncWaitHandle
197 [System.Security.SecuritySafeCritical] // auto-generated
198 [ResourceExposure(ResourceScope.None)]
199 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
201 // Consider uncommenting this someday soon - the EventHandle
202 // in the Overlapped struct is really useless half of the
203 // time today since the OS doesn't signal it. If users call
204 // EndXxx after the OS call happened to complete, there's no
205 // reason to create a synchronization primitive here. Fixing
206 // this will save us some perf, assuming we can correctly
207 // initialize the ManualResetEvent.
208 if (_waitHandle == null) {
209 ManualResetEvent mre = new ManualResetEvent(false);
210 if (_overlapped != null && _overlapped->EventHandle != IntPtr.Zero) {
211 mre.SafeWaitHandle = new SafeWaitHandle(_overlapped->EventHandle, true);
214 // make sure only one thread sets _waitHandle
215 if (Interlocked.CompareExchange<ManualResetEvent>(ref _waitHandle, mre, null) == null) {
220 // There's a slight but acceptable ---- if we weren't
221 // the thread that set _waitHandle and this code path
222 // returns before the code in the if statement
223 // executes (on the other thread). However, the
224 // caller is waiting for the wait handle to be set,
225 // which will still happen.
233 #endif //!FEATURE_PAL
236 // Returns true iff the user callback was called by the thread that
237 // called BeginRead or BeginWrite. If we use an async delegate or
238 // threadpool thread internally, this will be false. This is used
239 // by code to determine whether a successive call to BeginRead needs
240 // to be done on their main thread or in their callback to avoid a
241 // stack overflow on many reads or writes.
242 public bool CompletedSynchronously
244 get { return _completedSynchronously; }
248 private void CallUserCallbackWorker()
252 // ensure _isComplete is set before reading _waitHandle
253 Thread.MemoryBarrier();
254 if (_waitHandle != null)
260 internal void CallUserCallback()
262 // Convenience method for me, since I have to do this in a number
263 // of places in the buffering code for fake IAsyncResults.
264 // AsyncFSCallback intentionally does not use this method.
266 if (_userCallback != null) {
267 // Call user's callback on a threadpool thread.
268 // Set completedSynchronously to false, since it's on another
269 // thread, not the main thread.
270 _completedSynchronously = false;
271 ThreadPool.QueueUserWorkItem(state => ((FileStreamAsyncResult)state).CallUserCallbackWorker(), this);
276 // ensure _isComplete is set before reading _waitHandle
277 Thread.MemoryBarrier();
278 if (_waitHandle != null)
284 internal void ReleaseNativeResource()
286 // Free memory & GC handles.
287 if (this._overlapped != null)
288 Overlapped.Free(_overlapped);
293 if (_waitHandle != null)
295 // We must block to ensure that AsyncFSCallback has completed,
296 // and we should close the WaitHandle in here. AsyncFSCallback
297 // and the hand-ported imitation version in COMThreadPool.cpp
298 // are the only places that set this event.
301 _waitHandle.WaitOne();
302 Contract.Assert(_isComplete == true, "FileStreamAsyncResult::Wait - AsyncFSCallback didn't set _isComplete to true!");
311 // When doing IO asynchronously (ie, _isAsync==true), this callback is
312 // called by a free thread in the threadpool when the IO operation
314 [System.Security.SecurityCritical] // auto-generated
315 [ResourceExposure(ResourceScope.None)]
316 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
317 unsafe private static void AsyncFSCallback(uint errorCode, uint numBytes, NativeOverlapped* pOverlapped)
319 BCLDebug.Log(String.Format("AsyncFSCallback called. errorCode: " + errorCode + " numBytes: " + numBytes));
322 Overlapped overlapped = Overlapped.Unpack(pOverlapped);
323 // Free the overlapped struct in EndRead/EndWrite.
325 // Extract async result from overlapped
326 FileStreamAsyncResult asyncResult =
327 (FileStreamAsyncResult)overlapped.AsyncResult;
328 asyncResult._numBytes = (int)numBytes;
330 if (FrameworkEventSource.IsInitialized && FrameworkEventSource.Log.IsEnabled(EventLevel.Informational, FrameworkEventSource.Keywords.ThreadTransfer))
331 FrameworkEventSource.Log.ThreadTransferReceive((long)(asyncResult.OverLapped), 2, string.Empty);
333 // Handle reading from & writing to closed pipes. While I'm not sure
334 // this is entirely necessary anymore, maybe it's possible for
335 // an async read on a pipe to be issued and then the pipe is closed,
336 // returning this error. This may very well be necessary.
337 if (errorCode == FileStream.ERROR_BROKEN_PIPE || errorCode == FileStream.ERROR_NO_DATA)
340 asyncResult._errorCode = (int)errorCode;
342 // Call the user-provided callback. It can and often should
343 // call EndRead or EndWrite. There's no reason to use an async
344 // delegate here - we're already on a threadpool thread.
345 // IAsyncResult's completedSynchronously property must return
346 // false here, saying the user callback was called on another thread.
347 asyncResult._completedSynchronously = false;
348 asyncResult._isComplete = true;
350 // ensure _isComplete is set before reading _waitHandle
351 Thread.MemoryBarrier();
353 // The OS does not signal this event. We must do it ourselves.
354 ManualResetEvent wh = asyncResult._waitHandle;
357 Contract.Assert(!wh.SafeWaitHandle.IsClosed, "ManualResetEvent already closed!");
359 Contract.Assert(r, "ManualResetEvent::Set failed!");
360 if (!r) __Error.WinIOError();
363 AsyncCallback userCallback = asyncResult._userCallback;
364 if (userCallback != null)
365 userCallback(asyncResult);
368 [SecuritySafeCritical]
369 [HostProtection(ExternalThreading = true)]
370 internal void Cancel()
372 Contract.Assert(_handle != null, "_handle should not be null.");
373 Contract.Assert(_overlapped != null, "Cancel should only be called on true asynchronous FileStreamAsyncResult, i.e. _overlapped is not null");
378 if (_handle.IsInvalid)
381 bool r = Win32Native.CancelIoEx(_handle, _overlapped);
384 int errorCode = Marshal.GetLastWin32Error();
386 // ERROR_NOT_FOUND is returned if CancelIoEx cannot find the request to cancel.
387 // This probably means that the IO operation has completed.
388 if (errorCode != Win32Native.ERROR_NOT_FOUND)
389 __Error.WinIOError(errorCode, String.Empty);
392 #endif //FEATURE_ASYNC_IO
396 public class FileStream : Stream
398 internal const int DefaultBufferSize = 4096;
401 #if FEATURE_LEGACYNETCF
402 // Mango didn't do support Async IO.
403 private static readonly bool _canUseAsync = !CompatibilitySwitches.IsAppEarlierThanWindowsPhone8;
405 private const bool _canUseAsync = true;
406 #endif //FEATURE_ASYNC_IO
408 private byte[] _buffer; // Shared read/write buffer. Alloc on first use.
409 private String _fileName; // Fully qualified file name.
410 private bool _isAsync; // Whether we opened the handle for overlapped IO
411 private bool _canRead;
412 private bool _canWrite;
413 private bool _canSeek;
414 private bool _exposedHandle; // Could other code be using this handle?
415 private bool _isPipe; // Whether to disable async buffering code.
416 private int _readPos; // Read pointer within shared buffer.
417 private int _readLen; // Number of bytes read in buffer from file.
418 private int _writePos; // Write pointer within shared buffer.
419 private int _bufferSize; // Length of internal buffer, if it's allocated.
420 [System.Security.SecurityCritical] // auto-generated
421 private SafeFileHandle _handle;
422 private long _pos; // Cache current location in the file.
423 private long _appendStart;// When appending, prevent overwriting file.
425 private static AsyncCallback s_endReadTask;
426 private static AsyncCallback s_endWriteTask;
427 private static Action<object> s_cancelReadHandler;
428 private static Action<object> s_cancelWriteHandler;
431 //This exists only to support IsolatedStorageFileStream.
432 //Any changes to FileStream must include the corresponding changes in IsolatedStorage.
433 internal FileStream() {
436 [System.Security.SecuritySafeCritical]
437 [ResourceExposure(ResourceScope.Machine)]
438 [ResourceConsumption(ResourceScope.Machine)]
439 public FileStream(String path, FileMode mode)
440 : this(path, mode, (mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite), FileShare.Read, DefaultBufferSize, FileOptions.None, Path.GetFileName(path), false, false, true) {
441 #if FEATURE_LEGACYNETCF
442 if(CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
443 System.Reflection.Assembly callingAssembly = System.Reflection.Assembly.GetCallingAssembly();
444 if(callingAssembly != null && !callingAssembly.IsProfileAssembly) {
445 string caller = new System.Diagnostics.StackFrame(1).GetMethod().FullName;
446 string callee = System.Reflection.MethodBase.GetCurrentMethod().FullName;
447 throw new MethodAccessException(String.Format(
448 CultureInfo.CurrentCulture,
449 Environment.GetResourceString("Arg_MethodAccessException_WithCaller"),
454 #endif // FEATURE_LEGACYNETCF
457 [System.Security.SecuritySafeCritical]
458 [ResourceExposure(ResourceScope.Machine)]
459 [ResourceConsumption(ResourceScope.Machine)]
460 public FileStream(String path, FileMode mode, FileAccess access)
461 : this(path, mode, access, FileShare.Read, DefaultBufferSize, FileOptions.None, Path.GetFileName(path), false, false, true) {
462 #if FEATURE_LEGACYNETCF
463 if(CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
464 System.Reflection.Assembly callingAssembly = System.Reflection.Assembly.GetCallingAssembly();
465 if(callingAssembly != null && !callingAssembly.IsProfileAssembly) {
466 string caller = new System.Diagnostics.StackFrame(1).GetMethod().FullName;
467 string callee = System.Reflection.MethodBase.GetCurrentMethod().FullName;
468 throw new MethodAccessException(String.Format(
469 CultureInfo.CurrentCulture,
470 Environment.GetResourceString("Arg_MethodAccessException_WithCaller"),
475 #endif // FEATURE_LEGACYNETCF
478 [System.Security.SecuritySafeCritical]
479 [ResourceExposure(ResourceScope.Machine)]
480 [ResourceConsumption(ResourceScope.Machine)]
481 public FileStream(String path, FileMode mode, FileAccess access, FileShare share)
482 : this(path, mode, access, share, DefaultBufferSize, FileOptions.None, Path.GetFileName(path), false, false, true) {
483 #if FEATURE_LEGACYNETCF
484 if(CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
485 System.Reflection.Assembly callingAssembly = System.Reflection.Assembly.GetCallingAssembly();
486 if(callingAssembly != null && !callingAssembly.IsProfileAssembly) {
487 string caller = new System.Diagnostics.StackFrame(1).GetMethod().FullName;
488 string callee = System.Reflection.MethodBase.GetCurrentMethod().FullName;
489 throw new MethodAccessException(String.Format(
490 CultureInfo.CurrentCulture,
491 Environment.GetResourceString("Arg_MethodAccessException_WithCaller"),
496 #endif // FEATURE_LEGACYNETCF
499 [System.Security.SecuritySafeCritical]
500 [ResourceExposure(ResourceScope.Machine)]
501 [ResourceConsumption(ResourceScope.Machine)]
502 public FileStream(String path, FileMode mode, FileAccess access, FileShare share, int bufferSize)
503 : this(path, mode, access, share, bufferSize, FileOptions.None, Path.GetFileName(path), false, false, true)
507 #else // FEATURE_CORECLR
508 [System.Security.SecuritySafeCritical] // auto-generated
509 [ResourceExposure(ResourceScope.Machine)]
510 [ResourceConsumption(ResourceScope.Machine)]
511 public FileStream(String path, FileMode mode)
512 : this(path, mode, (mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite), FileShare.Read, DefaultBufferSize, FileOptions.None, Path.GetFileName(path), false) {
515 [System.Security.SecuritySafeCritical] // auto-generated
516 [ResourceExposure(ResourceScope.Machine)]
517 [ResourceConsumption(ResourceScope.Machine)]
518 public FileStream(String path, FileMode mode, FileAccess access)
519 : this(path, mode, access, FileShare.Read, DefaultBufferSize, FileOptions.None, Path.GetFileName(path), false) {
522 [System.Security.SecuritySafeCritical] // auto-generated
523 [ResourceExposure(ResourceScope.Machine)]
524 [ResourceConsumption(ResourceScope.Machine)]
525 public FileStream(String path, FileMode mode, FileAccess access, FileShare share)
526 : this(path, mode, access, share, DefaultBufferSize, FileOptions.None, Path.GetFileName(path), false) {
529 [System.Security.SecuritySafeCritical] // auto-generated
530 [ResourceExposure(ResourceScope.Machine)]
531 [ResourceConsumption(ResourceScope.Machine)]
532 public FileStream(String path, FileMode mode, FileAccess access, FileShare share, int bufferSize)
533 : this(path, mode, access, share, bufferSize, FileOptions.None, Path.GetFileName(path), false)
536 #endif // FEATURE_CORECLR
538 [System.Security.SecuritySafeCritical] // auto-generated
539 [ResourceExposure(ResourceScope.Machine)]
540 [ResourceConsumption(ResourceScope.Machine)]
541 public FileStream(String path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options)
542 : this(path, mode, access, share, bufferSize, options, Path.GetFileName(path), false)
547 [System.Security.SecurityCritical] // auto-generated
549 [System.Security.SecuritySafeCritical]
551 [ResourceExposure(ResourceScope.Machine)]
552 [ResourceConsumption(ResourceScope.Machine)]
553 public FileStream(String path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool useAsync)
554 : this(path, mode, access, share, bufferSize, (useAsync ? FileOptions.Asynchronous : FileOptions.None), Path.GetFileName(path), false)
559 // This constructor is done differently to avoid loading a few more
560 // classes, and more importantly, to build correctly on Rotor.
561 [System.Security.SecuritySafeCritical] // auto-generated
562 [ResourceExposure(ResourceScope.Machine)]
563 [ResourceConsumption(ResourceScope.Machine)]
564 public FileStream(String path, FileMode mode, FileSystemRights rights, FileShare share, int bufferSize, FileOptions options, FileSecurity fileSecurity)
566 Object pinningHandle;
567 Win32Native.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share, fileSecurity, out pinningHandle);
569 Init(path, mode, (FileAccess)0, (int)rights, true, share, bufferSize, options, secAttrs, Path.GetFileName(path), false, false, false);
572 if (pinningHandle != null) {
573 GCHandle pinHandle = (GCHandle) pinningHandle;
579 [System.Security.SecuritySafeCritical] // auto-generated
580 [ResourceExposure(ResourceScope.Machine)]
581 [ResourceConsumption(ResourceScope.Machine)]
582 public FileStream(String path, FileMode mode, FileSystemRights rights, FileShare share, int bufferSize, FileOptions options)
584 Win32Native.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share);
585 Init(path, mode, (FileAccess)0, (int)rights, true, share, bufferSize, options, secAttrs, Path.GetFileName(path), false, false, false);
589 [System.Security.SecurityCritical] // auto-generated
590 [ResourceExposure(ResourceScope.Machine)]
591 [ResourceConsumption(ResourceScope.Machine)]
592 internal FileStream(String path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, String msgPath, bool bFromProxy)
594 Win32Native.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share);
595 Init(path, mode, access, 0, false, share, bufferSize, options, secAttrs, msgPath, bFromProxy, false, false);
598 [System.Security.SecurityCritical]
599 [ResourceExposure(ResourceScope.Machine)]
600 [ResourceConsumption(ResourceScope.Machine)]
601 internal FileStream(String path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, String msgPath, bool bFromProxy, bool useLongPath)
603 Win32Native.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share);
604 Init(path, mode, access, 0, false, share, bufferSize, options, secAttrs, msgPath, bFromProxy, useLongPath, false);
607 [System.Security.SecurityCritical]
608 [ResourceExposure(ResourceScope.Machine)]
609 [ResourceConsumption(ResourceScope.Machine)]
610 internal FileStream(String path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, String msgPath, bool bFromProxy, bool useLongPath, bool checkHost)
612 Win32Native.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share);
613 Init(path, mode, access, 0, false, share, bufferSize, options, secAttrs, msgPath, bFromProxy, useLongPath, checkHost);
616 // AccessControl namespace is not defined in Rotor
617 [System.Security.SecuritySafeCritical]
618 [ResourceExposure(ResourceScope.Machine)]
619 [ResourceConsumption(ResourceScope.Machine)]
620 private void Init(String path, FileMode mode, FileAccess access, int rights, bool useRights, FileShare share, int bufferSize, FileOptions options, Win32Native.SECURITY_ATTRIBUTES secAttrs, String msgPath, bool bFromProxy, bool useLongPath, bool checkHost)
623 throw new ArgumentNullException("path", Environment.GetResourceString("ArgumentNull_Path"));
624 if (path.Length == 0)
625 throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"));
626 Contract.EndContractBlock();
629 FileSystemRights fileSystemRights = (FileSystemRights)rights;
631 // msgPath must be safe to hand back to untrusted code.
633 _fileName = msgPath; // To handle odd cases of finalizing partially constructed objects.
634 _exposedHandle = false;
637 Contract.Assert(!useRights, "Specifying FileSystemRights is not supported on this platform!");
640 // don't include inheritable in our bounds check for share
641 FileShare tempshare = share & ~FileShare.Inheritable;
642 String badArg = null;
644 if (mode < FileMode.CreateNew || mode > FileMode.Append)
646 else if (!useRights && (access < FileAccess.Read || access > FileAccess.ReadWrite))
649 else if (useRights && (fileSystemRights < FileSystemRights.ReadData || fileSystemRights > FileSystemRights.FullControl))
652 else if (tempshare < FileShare.None || tempshare > (FileShare.ReadWrite | FileShare.Delete))
656 throw new ArgumentOutOfRangeException(badArg, Environment.GetResourceString("ArgumentOutOfRange_Enum"));
658 // NOTE: any change to FileOptions enum needs to be matched here in the error validation
659 if (options != FileOptions.None && (options & ~(FileOptions.WriteThrough | FileOptions.Asynchronous | FileOptions.RandomAccess | FileOptions.DeleteOnClose | FileOptions.SequentialScan | FileOptions.Encrypted | (FileOptions)0x20000000 /* NoBuffering */)) != 0)
660 throw new ArgumentOutOfRangeException("options", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
663 throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
665 // Write access validation
667 if ((!useRights && (access & FileAccess.Write) == 0)
668 || (useRights && (fileSystemRights & FileSystemRights.Write) == 0))
670 if (!useRights && (access & FileAccess.Write) == 0)
671 #endif //FEATURE_MACL
673 if (mode==FileMode.Truncate || mode==FileMode.CreateNew || mode==FileMode.Create || mode==FileMode.Append) {
676 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFileMode&AccessCombo", mode, access));
679 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFileMode&RightsCombo", mode, fileSystemRights));
680 #endif //FEATURE_MACL
685 // FileMode.Truncate only works with GENERIC_WRITE (FileAccess.Write), source:MSDN
686 // For backcomp use FileAccess.Write when FileSystemRights.Write is specified
687 if (useRights && (mode == FileMode.Truncate)) {
688 if (fileSystemRights == FileSystemRights.Write) {
690 access = FileAccess.Write;
693 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFileModeTruncate&RightsCombo", mode, fileSystemRights));
700 fAccess = access == FileAccess.Read? GENERIC_READ:
701 access == FileAccess.Write? GENERIC_WRITE:
702 GENERIC_READ | GENERIC_WRITE;
708 // Get absolute path - Security needs this to prevent something
709 // like trying to create a file in c:\tmp with the name
710 // "..\WinNT\System32\ntoskrnl.exe". Store it for user convenience.
711 int maxPath = useLongPath ? Path.MaxLongPath : Path.MaxPath;
712 String filePath = Path.NormalizePath(path, true, maxPath);
714 _fileName = filePath;
716 // Prevent access to your disk drives as raw block devices.
717 if (filePath.StartsWith("\\\\.\\", StringComparison.Ordinal))
718 throw new ArgumentException(Environment.GetResourceString("Arg_DevicesNotSupported"));
720 // In 4.0, we always construct a FileIOPermission object below.
721 // If filePath contained a ':', we would throw a NotSupportedException in
722 // System.Security.Util.StringExpressionSet.CanonicalizePath.
723 // If filePath contained other illegal characters, we would throw an ArgumentException in
724 // FileIOPermission.CheckIllegalCharacters.
725 // In 4.5 we on longer construct the FileIOPermission object in full trust.
726 // To preserve the 4.0 behavior we do an explicit check for ':' here and also call Path.CheckInvalidPathChars.
727 // Note that we need to call CheckInvalidPathChars before checking for ':' because that is what FileIOPermission does.
729 Path.CheckInvalidPathChars(filePath, true);
731 if (filePath.IndexOf( ':', 2 ) != -1)
732 throw new NotSupportedException( Environment.GetResourceString( "Argument_PathFormatNotSupported" ) );
737 if ((!useRights && (access & FileAccess.Read) != 0) || (useRights && (fileSystemRights & FileSystemRights.ReadAndExecute) != 0))
739 if (!useRights && (access & FileAccess.Read) != 0)
740 #endif //FEATURE_MACL
742 if (mode == FileMode.Append)
743 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidAppendMode"));
748 // All demands in full trust domains are no-ops, so skip
749 #if FEATURE_CAS_POLICY
750 if (!CodeAccessSecurityEngine.QuickCheckForAllDemands())
751 #endif // FEATURE_CAS_POLICY
753 // Build up security permissions required, as well as validate we
754 // have a sensible set of parameters. IE, creating a brand new file
755 // for reading doesn't make much sense.
756 FileIOPermissionAccess secAccess = FileIOPermissionAccess.NoAccess;
760 Contract.Assert(mode != FileMode.Append);
761 secAccess = secAccess | FileIOPermissionAccess.Read;
764 // I can't think of any combos of FileMode we should disallow if we
765 // don't have read access. Writing would pretty much always be valid
768 // For any FileSystemRights other than ReadAndExecute, demand Write permission
769 // This is probably bit overkill for TakeOwnership etc but we don't have any
770 // matching FileIOPermissionAccess to demand. It is better that we ask for Write permission.
773 // FileMode.OpenOrCreate & FileSystemRights.Synchronize can create 0-byte file; demand write
774 if ((!useRights && (access & FileAccess.Write) != 0)
775 || (useRights && (fileSystemRights & (FileSystemRights.Write | FileSystemRights.Delete
776 | FileSystemRights.DeleteSubdirectoriesAndFiles
777 | FileSystemRights.ChangePermissions
778 | FileSystemRights.TakeOwnership)) != 0)
779 || (useRights && ((fileSystemRights & FileSystemRights.Synchronize) != 0)
780 && mode==FileMode.OpenOrCreate)
783 if (!useRights && (access & FileAccess.Write) != 0)
784 #endif //FEATURE_MACL
786 if (mode==FileMode.Append)
787 secAccess = secAccess | FileIOPermissionAccess.Append;
789 secAccess = secAccess | FileIOPermissionAccess.Write;
795 specifiedAcl = secAttrs != null && secAttrs.pSecurityDescriptor != null;
798 AccessControlActions control = specifiedAcl ? AccessControlActions.Change : AccessControlActions.None;
799 new FileIOPermission(secAccess, control, new String[] { filePath }, false, false).Demand();
803 FileSecurityState state = new FileSecurityState(FileSecurityState.ToFileSecurityState(secAccess), path, filePath);
807 new FileIOPermission(secAccess, new String[] { filePath }, false, false).Demand();
808 #endif // FEATURE_CORECLR
812 // Our Inheritable bit was stolen from Windows, but should be set in
813 // the security attributes class. Don't leave this bit set.
814 share &= ~FileShare.Inheritable;
816 bool seekToEnd = (mode==FileMode.Append);
817 // Must use a valid Win32 constant here...
818 if (mode == FileMode.Append)
819 mode = FileMode.OpenOrCreate;
821 // WRT async IO, do the right thing for whatever platform we're on.
822 // This way, someone can easily write code that opens a file
823 // asynchronously no matter what their platform is.
824 if (_canUseAsync && (options & FileOptions.Asynchronous) != 0)
827 options &= ~FileOptions.Asynchronous;
829 int flagsAndAttributes = (int) options;
832 // For mitigating local elevation of privilege attack through named pipes
833 // make sure we always call CreateFile with SECURITY_ANONYMOUS so that the
834 // named pipe server can't impersonate a high privileged client security context
835 flagsAndAttributes|= (Win32Native.SECURITY_SQOS_PRESENT | Win32Native.SECURITY_ANONYMOUS);
837 // Don't pop up a dialog for reading from an emtpy floppy drive
838 int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
840 String tempPath = filePath;
842 tempPath = Path.AddLongPathPrefix(tempPath);
843 _handle = Win32Native.SafeCreateFile(tempPath, fAccess, share, secAttrs, mode, flagsAndAttributes, IntPtr.Zero);
845 if (_handle.IsInvalid) {
846 // Return a meaningful exception, using the RELATIVE path to
847 // the file to avoid returning extra information to the caller
848 // unless they have path discovery permission, in which case
849 // the full path is fine & useful.
851 // NT5 oddity - when trying to open "C:\" as a FileStream,
852 // we usually get ERROR_PATH_NOT_FOUND from the OS. We should
853 // probably be consistent w/ every other directory.
854 int errorCode = Marshal.GetLastWin32Error();
855 if (errorCode==__Error.ERROR_PATH_NOT_FOUND && filePath.Equals(Directory.InternalGetDirectoryRoot(filePath)))
856 errorCode = __Error.ERROR_ACCESS_DENIED;
858 // We need to give an exception, and preferably it would include
859 // the fully qualified path name. Do security check here. If
860 // we fail, give back the msgPath, which should not reveal much.
861 // While this logic is largely duplicated in
862 // __Error.WinIOError, we need this for
863 // IsolatedStorageFileStream.
864 bool canGiveFullPath = false;
870 new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { _fileName }, false, false ).Demand();
872 canGiveFullPath = true;
874 catch(SecurityException) {}
878 __Error.WinIOError(errorCode, _fileName);
880 __Error.WinIOError(errorCode, msgPath);
884 Win32Native.SetErrorMode(oldMode);
887 // Disallow access to all non-file devices from the FileStream
888 // constructors that take a String. Everyone else can call
889 // CreateFile themselves then use the constructor that takes an
890 // IntPtr. Disallows "con:", "com1:", "lpt1:", etc.
891 int fileType = Win32Native.GetFileType(_handle);
892 if (fileType != Win32Native.FILE_TYPE_DISK) {
894 throw new NotSupportedException(Environment.GetResourceString("NotSupported_FileStreamOnNonFiles"));
898 // This is necessary for async IO using IO Completion ports via our
899 // managed Threadpool API's. This (theoretically) calls the OS's
900 // BindIoCompletionCallback method, and passes in a stub for the
901 // LPOVERLAPPED_COMPLETION_ROUTINE. This stub looks at the Overlapped
902 // struct for this request and gets a delegate to a managed callback
903 // from there, which it then calls on a threadpool thread. (We allocate
904 // our native OVERLAPPED structs 2 pointers too large and store EE state
905 // & GC handles there, one to an IAsyncResult, the other to a delegate.)
908 // BindHandle requires UnmanagedCode permission
909 new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
911 b = ThreadPool.BindHandle(_handle);
914 CodeAccessPermission.RevertAssert();
916 // We should close the handle so that the handle is not open until SafeFileHandle GC
917 Contract.Assert(!_exposedHandle, "Are we closing handle that we exposed/not own, how?");
922 throw new IOException(Environment.GetResourceString("IO.IO_BindHandleFailed"));
924 #endif // FEATURE_ASYNC_IO
926 _canRead = (access & FileAccess.Read) != 0;
927 _canWrite = (access & FileAccess.Write) != 0;
931 _canRead = (fileSystemRights & FileSystemRights.ReadData) != 0;
932 _canWrite = ((fileSystemRights & FileSystemRights.WriteData) != 0)
933 || ((fileSystemRights & FileSystemRights.AppendData) != 0);
935 #endif //FEATURE_MACL
940 _bufferSize = bufferSize;
945 // For Append mode...
947 _appendStart = SeekCore(0, SeekOrigin.End);
954 [Obsolete("This constructor has been deprecated. Please use new FileStream(SafeFileHandle handle, FileAccess access) instead. http://go.microsoft.com/fwlink/?linkid=14202")]
955 [ResourceExposure(ResourceScope.Machine)]
956 [ResourceConsumption(ResourceScope.Machine)]
957 public FileStream(IntPtr handle, FileAccess access)
958 : this(handle, access, true, DefaultBufferSize, false) {
961 [Obsolete("This constructor has been deprecated. Please use new FileStream(SafeFileHandle handle, FileAccess access) instead, and optionally make a new SafeFileHandle with ownsHandle=false if needed. http://go.microsoft.com/fwlink/?linkid=14202")]
962 [ResourceExposure(ResourceScope.Machine)]
963 [ResourceConsumption(ResourceScope.Machine)]
964 public FileStream(IntPtr handle, FileAccess access, bool ownsHandle)
965 : this(handle, access, ownsHandle, DefaultBufferSize, false) {
968 [Obsolete("This constructor has been deprecated. Please use new FileStream(SafeFileHandle handle, FileAccess access, int bufferSize) instead, and optionally make a new SafeFileHandle with ownsHandle=false if needed. http://go.microsoft.com/fwlink/?linkid=14202")]
969 [ResourceExposure(ResourceScope.Machine)]
970 [ResourceConsumption(ResourceScope.Machine)]
971 public FileStream(IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize)
972 : this(handle, access, ownsHandle, bufferSize, false) {
975 // We explicitly do a Demand, not a LinkDemand here.
976 [System.Security.SecuritySafeCritical] // auto-generated
977 [Obsolete("This constructor has been deprecated. Please use new FileStream(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync) instead, and optionally make a new SafeFileHandle with ownsHandle=false if needed. http://go.microsoft.com/fwlink/?linkid=14202")]
978 #pragma warning disable 618
979 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
980 #pragma warning restore 618
981 [ResourceExposure(ResourceScope.Machine)]
982 [ResourceConsumption(ResourceScope.Machine)]
983 public FileStream(IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize, bool isAsync)
984 : this(new SafeFileHandle(handle, ownsHandle), access, bufferSize, isAsync) {
987 [System.Security.SecuritySafeCritical] // auto-generated
988 [ResourceExposure(ResourceScope.Machine)]
989 [ResourceConsumption(ResourceScope.Machine)]
990 public FileStream(SafeFileHandle handle, FileAccess access)
991 : this(handle, access, DefaultBufferSize, false) {
994 [System.Security.SecuritySafeCritical] // auto-generated
995 [ResourceExposure(ResourceScope.Machine)]
996 [ResourceConsumption(ResourceScope.Machine)]
997 public FileStream(SafeFileHandle handle, FileAccess access, int bufferSize)
998 : this(handle, access, bufferSize, false) {
1001 [System.Security.SecuritySafeCritical] // auto-generated
1002 [ResourceExposure(ResourceScope.Machine)]
1003 [ResourceConsumption(ResourceScope.Machine)]
1004 #pragma warning disable 618
1005 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
1006 #pragma warning restore 618
1007 public FileStream(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync) {
1008 // To ensure we don't leak a handle, put it in a SafeFileHandle first
1009 if (handle.IsInvalid)
1010 throw new ArgumentException(Environment.GetResourceString("Arg_InvalidHandle"), "handle");
1011 Contract.EndContractBlock();
1014 _exposedHandle = true;
1016 // Now validate arguments.
1017 if (access < FileAccess.Read || access > FileAccess.ReadWrite)
1018 throw new ArgumentOutOfRangeException("access", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
1019 if (bufferSize <= 0)
1020 throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
1022 int handleType = Win32Native.GetFileType(_handle);
1023 Contract.Assert(handleType == Win32Native.FILE_TYPE_DISK || handleType == Win32Native.FILE_TYPE_PIPE || handleType == Win32Native.FILE_TYPE_CHAR, "FileStream was passed an unknown file type!");
1024 _isAsync = isAsync && _canUseAsync;
1025 _canRead = 0 != (access & FileAccess.Read);
1026 _canWrite = 0 != (access & FileAccess.Write);
1027 _canSeek = handleType == Win32Native.FILE_TYPE_DISK;
1028 _bufferSize = bufferSize;
1033 _isPipe = handleType == Win32Native.FILE_TYPE_PIPE;
1036 // This is necessary for async IO using IO Completion ports via our
1037 // managed Threadpool API's. This calls the OS's
1038 // BindIoCompletionCallback method, and passes in a stub for the
1039 // LPOVERLAPPED_COMPLETION_ROUTINE. This stub looks at the Overlapped
1040 // struct for this request and gets a delegate to a managed callback
1041 // from there, which it then calls on a threadpool thread. (We allocate
1042 // our native OVERLAPPED structs 2 pointers too large and store EE
1043 // state & a handle to a delegate there.)
1044 #if !FEATURE_CORECLR
1048 b = ThreadPool.BindHandle(_handle);
1050 catch (ApplicationException) {
1051 // If you passed in a synchronous handle and told us to use
1052 // it asynchronously, throw here.
1053 throw new ArgumentException(Environment.GetResourceString("Arg_HandleNotAsync"));
1056 throw new IOException(Environment.GetResourceString("IO.IO_BindHandleFailed"));
1060 #endif // FEATURE_CORECLR
1061 if (handleType != Win32Native.FILE_TYPE_PIPE)
1062 VerifyHandleIsSync();
1063 #if !FEATURE_CORECLR
1065 #endif // FEATURE_CORECLR
1067 if (handleType != Win32Native.FILE_TYPE_PIPE)
1068 VerifyHandleIsSync();
1069 #endif //!FEATURE_PAL
1071 SeekCore(0, SeekOrigin.Current);
1076 [System.Security.SecuritySafeCritical] // auto-generated
1077 private static Win32Native.SECURITY_ATTRIBUTES GetSecAttrs(FileShare share)
1079 Win32Native.SECURITY_ATTRIBUTES secAttrs = null;
1080 if ((share & FileShare.Inheritable) != 0) {
1081 secAttrs = new Win32Native.SECURITY_ATTRIBUTES();
1082 secAttrs.nLength = (int)Marshal.SizeOf(secAttrs);
1084 secAttrs.bInheritHandle = 1;
1090 // If pinningHandle is not null, caller must free it AFTER the call to
1091 // CreateFile has returned.
1092 [System.Security.SecuritySafeCritical] // auto-generated
1093 private unsafe static Win32Native.SECURITY_ATTRIBUTES GetSecAttrs(FileShare share, FileSecurity fileSecurity, out Object pinningHandle)
1095 pinningHandle = null;
1096 Win32Native.SECURITY_ATTRIBUTES secAttrs = null;
1097 if ((share & FileShare.Inheritable) != 0 || fileSecurity != null) {
1098 secAttrs = new Win32Native.SECURITY_ATTRIBUTES();
1099 secAttrs.nLength = (int)Marshal.SizeOf(secAttrs);
1101 if ((share & FileShare.Inheritable) != 0) {
1102 secAttrs.bInheritHandle = 1;
1105 // For ACL's, get the security descriptor from the FileSecurity.
1106 if (fileSecurity != null) {
1107 byte[] sd = fileSecurity.GetSecurityDescriptorBinaryForm();
1108 pinningHandle = GCHandle.Alloc(sd, GCHandleType.Pinned);
1109 fixed(byte* pSecDescriptor = sd)
1110 secAttrs.pSecurityDescriptor = pSecDescriptor;
1117 // Verifies that this handle supports synchronous IO operations (unless you
1118 // didn't open it for either reading or writing).
1119 [System.Security.SecuritySafeCritical] // auto-generated
1120 private unsafe void VerifyHandleIsSync()
1122 // Do NOT use this method on pipes. Reading or writing to a pipe may
1123 // cause an app to block incorrectly, introducing a deadlock (depending
1124 // on whether a write will wake up an already-blocked thread or this
1125 // FileStream's thread).
1127 // Do NOT change this to use a byte[] of length 0, or test test won't
1128 // work. Our ReadFile & WriteFile methods are special cased to return
1129 // for arrays of length 0, since we'd get an IndexOutOfRangeException
1130 // while using C#'s fixed syntax.
1131 byte[] bytes = new byte[1];
1135 // If the handle is a pipe, ReadFile will block until there
1136 // has been a write on the other end. We'll just have to deal with it,
1137 // For the read end of a pipe, you can mess up and
1138 // accidentally read synchronously from an async pipe.
1140 r = ReadFileNative(_handle, bytes, 0, 0, null, out hr);
1142 else if (CanWrite) {
1143 r = WriteFileNative(_handle, bytes, 0, 0, null, out hr);
1146 if (hr==ERROR_INVALID_PARAMETER)
1147 throw new ArgumentException(Environment.GetResourceString("Arg_HandleNotSync"));
1148 if (hr == Win32Native.ERROR_INVALID_HANDLE)
1149 __Error.WinIOError(hr, "<OS handle>");
1153 public override bool CanRead {
1155 get { return _canRead; }
1158 public override bool CanWrite {
1160 get { return _canWrite; }
1163 public override bool CanSeek {
1165 get { return _canSeek; }
1168 public virtual bool IsAsync {
1169 get { return _isAsync; }
1172 public override long Length {
1173 [System.Security.SecuritySafeCritical] // auto-generated
1175 if (_handle.IsClosed) __Error.FileNotOpen();
1176 if (!CanSeek) __Error.SeekNotSupported();
1179 lo = Win32Native.GetFileSize(_handle, out hi);
1181 if (lo==-1) { // Check for either an error or a 4GB - 1 byte file.
1182 int hr = Marshal.GetLastWin32Error();
1184 __Error.WinIOError(hr, String.Empty);
1186 long len = (((long)hi) << 32) | ((uint) lo);
1187 // If we're writing near the end of the file, we must include our
1188 // internal buffer in our Length calculation. Don't flush because
1189 // we use the length of the file in our async write method.
1190 if (_writePos > 0 && _pos + _writePos > len)
1191 len = _writePos + _pos;
1196 public String Name {
1197 [System.Security.SecuritySafeCritical]
1199 if (_fileName == null)
1200 return Environment.GetResourceString("IO_UnknownFileName");
1202 FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, _fileName);
1203 sourceState.EnsureState();
1205 new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { _fileName }, false, false).Demand();
1211 internal String NameInternal {
1213 if (_fileName == null)
1214 return "<UnknownFileName>";
1219 public override long Position {
1220 [System.Security.SecuritySafeCritical] // auto-generated
1222 if (_handle.IsClosed) __Error.FileNotOpen();
1223 if (!CanSeek) __Error.SeekNotSupported();
1225 Contract.Assert((_readPos == 0 && _readLen == 0 && _writePos >= 0) || (_writePos == 0 && _readPos <= _readLen), "We're either reading or writing, but not both.");
1227 // Verify that internal position is in [....] with the handle
1229 VerifyOSHandlePosition();
1231 // Compensate for buffer that we read from the handle (_readLen) Vs what the user
1232 // read so far from the internel buffer (_readPos). Of course add any unwrittern
1234 return _pos + (_readPos - _readLen + _writePos);
1237 if (value < 0) throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
1238 Contract.EndContractBlock();
1239 if (_writePos > 0) FlushWrite(false);
1242 Seek(value, SeekOrigin.Begin);
1247 [System.Security.SecuritySafeCritical] // auto-generated
1248 [ResourceExposure(ResourceScope.Machine)]
1249 [ResourceConsumption(ResourceScope.Machine)]
1250 public FileSecurity GetAccessControl()
1252 if (_handle.IsClosed) __Error.FileNotOpen();
1253 return new FileSecurity(_handle, _fileName, AccessControlSections.Access | AccessControlSections.Owner | AccessControlSections.Group);
1256 [System.Security.SecuritySafeCritical] // auto-generated
1257 public void SetAccessControl(FileSecurity fileSecurity)
1259 if (fileSecurity == null)
1260 throw new ArgumentNullException("fileSecurity");
1261 Contract.EndContractBlock();
1263 if (_handle.IsClosed) __Error.FileNotOpen();
1265 fileSecurity.Persist(_handle, _fileName);
1269 [System.Security.SecuritySafeCritical] // auto-generated
1270 protected override void Dispose(bool disposing)
1272 // Nothing will be done differently based on whether we are
1273 // disposing vs. finalizing. This is taking advantage of the
1274 // weak ordering between normal finalizable objects & critical
1275 // finalizable objects, which I included in the SafeHandle
1276 // design for FileStream, which would often "just work" when
1279 if (_handle != null && !_handle.IsClosed) {
1280 // Flush data to disk iff we were writing. After
1281 // thinking about this, we also don't need to flush
1282 // our read position, regardless of whether the handle
1283 // was exposed to the user. They probably would NOT
1284 // want us to do this.
1285 if (_writePos > 0) {
1286 FlushWrite(!disposing);
1291 if (_handle != null && !_handle.IsClosed)
1297 // Don't set the buffer to null, to avoid a NullReferenceException
1298 // when users have a race condition in their code (ie, they call
1299 // Close when calling another method on Stream like Read).
1301 base.Dispose(disposing);
1305 [System.Security.SecuritySafeCritical] // auto-generated
1308 if (_handle != null) {
1309 BCLDebug.Correctness(_handle.IsClosed, "You didn't close a FileStream & it got finalized. Name: \""+_fileName+"\"");
1314 public override void Flush()
1319 [System.Security.SecuritySafeCritical]
1320 public virtual void Flush(Boolean flushToDisk)
1322 // This code is duplicated in Dispose
1323 if (_handle.IsClosed) __Error.FileNotOpen();
1325 FlushInternalBuffer();
1327 if (flushToDisk && CanWrite)
1333 private void FlushInternalBuffer()
1339 else if (_readPos < _readLen && CanSeek)
1345 [System.Security.SecuritySafeCritical]
1346 private void FlushOSBuffer()
1348 if (!Win32Native.FlushFileBuffers(_handle))
1350 __Error.WinIOError();
1354 // Reading is done by blocks from the file, but someone could read
1355 // 1 byte from the buffer then write. At that point, the OS's file
1356 // pointer is out of [....] with the stream's position. All write
1357 // functions should call this function to preserve the position in the file.
1358 private void FlushRead() {
1359 Contract.Assert(_writePos == 0, "FileStream: Write buffer must be empty in FlushRead!");
1360 if (_readPos - _readLen != 0) {
1361 Contract.Assert(CanSeek, "FileStream will lose buffered read data now.");
1362 SeekCore(_readPos - _readLen, SeekOrigin.Current);
1368 // Writes are buffered. Anytime the buffer fills up
1369 // (_writePos + delta > _bufferSize) or the buffer switches to reading
1370 // and there is left over data (_writePos > 0), this function must be called.
1371 private void FlushWrite(bool calledFromFinalizer) {
1372 Contract.Assert(_readPos == 0 && _readLen == 0, "FileStream: Read buffer must be empty in FlushWrite!");
1374 #if FEATURE_ASYNC_IO
1376 IAsyncResult asyncResult = BeginWriteCore(_buffer, 0, _writePos, null, null);
1377 // With our Whidbey async IO & overlapped support for AD unloads,
1378 // we don't strictly need to block here to release resources
1379 // since that support takes care of the pinning & freeing the
1380 // overlapped struct. We need to do this when called from
1381 // Close so that the handle is closed when Close returns, but
1382 // we do't need to call EndWrite from the finalizer.
1383 // Additionally, if we do call EndWrite, we block forever
1384 // because AD unloads prevent us from running the managed
1385 // callback from the IO completion port. Blocking here when
1386 // called from the finalizer during AD unload is clearly wrong,
1387 // but we can't use any sort of test for whether the AD is
1388 // unloading because if we weren't unloading, an AD unload
1389 // could happen on a separate thread before we call EndWrite.
1390 if (!calledFromFinalizer)
1391 EndWrite(asyncResult);
1394 #endif // FEATURE_ASYNC_IO
1395 WriteCore(_buffer, 0, _writePos);
1401 [Obsolete("This property has been deprecated. Please use FileStream's SafeFileHandle property instead. http://go.microsoft.com/fwlink/?linkid=14202")]
1402 public virtual IntPtr Handle {
1403 [System.Security.SecurityCritical] // auto-generated_required
1404 #if !FEATURE_CORECLR
1405 [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
1407 [ResourceExposure(ResourceScope.Machine)]
1408 [ResourceConsumption(ResourceScope.Machine)]
1411 // Explicitly dump any buffered data, since the user could move our
1412 // position or write to the file.
1416 _exposedHandle = true;
1418 return _handle.DangerousGetHandle();
1422 public virtual SafeFileHandle SafeFileHandle {
1423 [System.Security.SecurityCritical] // auto-generated_required
1424 #if !FEATURE_CORECLR
1425 [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
1429 // Explicitly dump any buffered data, since the user could move our
1430 // position or write to the file.
1434 _exposedHandle = true;
1440 [System.Security.SecuritySafeCritical] // auto-generated
1441 public override void SetLength(long value)
1444 throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
1445 Contract.EndContractBlock();
1447 if (_handle.IsClosed) __Error.FileNotOpen();
1448 if (!CanSeek) __Error.SeekNotSupported();
1449 if (!CanWrite) __Error.WriteNotSupported();
1451 // Handle buffering updates.
1452 if (_writePos > 0) {
1455 else if (_readPos < _readLen) {
1461 if (_appendStart != -1 && value < _appendStart)
1462 throw new IOException(Environment.GetResourceString("IO.IO_SetLengthAppendTruncate"));
1463 SetLengthCore(value);
1466 // We absolutely need this method broken out so that BeginWriteCore can call
1467 // a method without having to go through buffering code that might call
1469 [System.Security.SecuritySafeCritical] // auto-generated
1470 private void SetLengthCore(long value)
1472 Contract.Assert(value >= 0, "value >= 0");
1473 long origPos = _pos;
1476 VerifyOSHandlePosition();
1478 SeekCore(value, SeekOrigin.Begin);
1479 if (!Win32Native.SetEndOfFile(_handle)) {
1480 int hr = Marshal.GetLastWin32Error();
1481 if (hr==__Error.ERROR_INVALID_PARAMETER)
1482 throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_FileLengthTooBig"));
1483 __Error.WinIOError(hr, String.Empty);
1485 // Return file pointer to where it was before setting length
1486 if (origPos != value) {
1487 if (origPos < value)
1488 SeekCore(origPos, SeekOrigin.Begin);
1490 SeekCore(0, SeekOrigin.End);
1494 [System.Security.SecuritySafeCritical] // auto-generated
1495 public override int Read([In, Out] byte[] array, int offset, int count) {
1497 throw new ArgumentNullException("array", Environment.GetResourceString("ArgumentNull_Buffer"));
1499 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
1501 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
1502 if (array.Length - offset < count)
1503 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
1504 Contract.EndContractBlock();
1506 if (_handle.IsClosed) __Error.FileNotOpen();
1508 Contract.Assert((_readPos==0 && _readLen==0 && _writePos >= 0) || (_writePos==0 && _readPos <= _readLen), "We're either reading or writing, but not both.");
1510 bool isBlocked = false;
1511 int n = _readLen - _readPos;
1512 // if the read buffer is empty, read into either user's array or our
1513 // buffer, depending on number of bytes user asked for and buffer size.
1515 if (!CanRead) __Error.ReadNotSupported();
1516 if (_writePos > 0) FlushWrite(false);
1517 if (!CanSeek || (count >= _bufferSize)) {
1518 n = ReadCore(array, offset, count);
1519 // Throw away read buffer.
1524 if (_buffer == null) _buffer = new byte[_bufferSize];
1525 n = ReadCore(_buffer, 0, _bufferSize);
1526 if (n == 0) return 0;
1527 isBlocked = n < _bufferSize;
1531 // Now copy min of count or numBytesAvailable (ie, near EOF) to array.
1532 if (n > count) n = count;
1533 Buffer.InternalBlockCopy(_buffer, _readPos, array, offset, n);
1536 // We may have read less than the number of bytes the user asked
1537 // for, but that is part of the Stream contract. Reading again for
1538 // more data may cause us to block if we're using a device with
1539 // no clear end of file, such as a serial port or pipe. If we
1540 // blocked here & this code was used with redirected pipes for a
1541 // process's standard output, this can lead to deadlocks involving
1542 // two processes. But leave this here for files to avoid what would
1543 // probably be a breaking change. --
1545 // If we are reading from a device with no clear EOF like a
1546 // serial port or a pipe, this will cause us to block incorrectly.
1548 // If we hit the end of the buffer and didn't have enough bytes, we must
1549 // read some more from the underlying stream. However, if we got
1550 // fewer bytes from the underlying stream than we asked for (ie, we're
1551 // probably blocked), don't ask for more bytes.
1552 if (n < count && !isBlocked) {
1553 Contract.Assert(_readPos == _readLen, "Read buffer should be empty!");
1554 int moreBytesRead = ReadCore(array, offset + n, count - n);
1556 // We've just made our buffer inconsistent with our position
1557 // pointer. We must throw away the read buffer.
1566 [System.Security.SecuritySafeCritical] // auto-generated
1567 private unsafe int ReadCore(byte[] buffer, int offset, int count) {
1568 Contract.Assert(!_handle.IsClosed, "!_handle.IsClosed");
1569 Contract.Assert(CanRead, "CanRead");
1571 Contract.Assert(buffer != null, "buffer != null");
1572 Contract.Assert(_writePos == 0, "_writePos == 0");
1573 Contract.Assert(offset >= 0, "offset is negative");
1574 Contract.Assert(count >= 0, "count is negative");
1575 #if FEATURE_ASYNC_IO
1577 IAsyncResult result = BeginReadCore(buffer, offset, count, null, null, 0);
1578 return EndRead(result);
1580 #endif //FEATURE_ASYNC_IO
1582 // Make sure we are reading from the right spot
1584 VerifyOSHandlePosition();
1587 int r = ReadFileNative(_handle, buffer, offset, count, null, out hr);
1589 // For pipes, ERROR_BROKEN_PIPE is the normal end of the pipe.
1590 if (hr == ERROR_BROKEN_PIPE) {
1594 if (hr == ERROR_INVALID_PARAMETER)
1595 throw new ArgumentException(Environment.GetResourceString("Arg_HandleNotSync"));
1597 __Error.WinIOError(hr, String.Empty);
1600 Contract.Assert(r >= 0, "FileStream's ReadCore is likely broken.");
1606 [System.Security.SecuritySafeCritical] // auto-generated
1607 public override long Seek(long offset, SeekOrigin origin) {
1608 if (origin<SeekOrigin.Begin || origin>SeekOrigin.End)
1609 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidSeekOrigin"));
1610 Contract.EndContractBlock();
1611 if (_handle.IsClosed) __Error.FileNotOpen();
1612 if (!CanSeek) __Error.SeekNotSupported();
1614 Contract.Assert((_readPos==0 && _readLen==0 && _writePos >= 0) || (_writePos==0 && _readPos <= _readLen), "We're either reading or writing, but not both.");
1616 // If we've got bytes in our buffer to write, write them out.
1617 // If we've read in and consumed some bytes, we'll have to adjust
1618 // our seek positions ONLY IF we're seeking relative to the current
1619 // position in the stream. This simulates doing a seek to the new
1620 // position, then a read for the number of bytes we have in our buffer.
1621 if (_writePos > 0) {
1624 else if (origin == SeekOrigin.Current) {
1625 // Don't call FlushRead here, which would have caused an infinite
1626 // loop. Simply adjust the seek origin. This isn't necessary
1627 // if we're seeking relative to the beginning or end of the stream.
1628 offset -= (_readLen - _readPos);
1631 // Verify that internal position is in [....] with the handle
1633 VerifyOSHandlePosition();
1635 long oldPos = _pos + (_readPos - _readLen);
1636 long pos = SeekCore(offset, origin);
1638 // Prevent users from overwriting data in a file that was opened in
1640 if (_appendStart != -1 && pos < _appendStart) {
1641 SeekCore(oldPos, SeekOrigin.Begin);
1642 throw new IOException(Environment.GetResourceString("IO.IO_SeekAppendOverwrite"));
1645 // We now must update the read buffer. We can in some cases simply
1646 // update _readPos within the buffer, copy around the buffer so our
1647 // Position property is still correct, and avoid having to do more
1648 // reads from the disk. Otherwise, discard the buffer's contents.
1650 // We can optimize the following condition:
1651 // oldPos - _readPos <= pos < oldPos + _readLen - _readPos
1652 if (oldPos == pos) {
1654 //Console.WriteLine("Seek: seeked for 0, adjusting buffer back by: "+_readPos+" _readLen: "+_readLen);
1655 Buffer.InternalBlockCopy(_buffer, _readPos, _buffer, 0, _readLen - _readPos);
1656 _readLen -= _readPos;
1659 // If we still have buffered data, we must update the stream's
1660 // position so our Position property is correct.
1662 SeekCore(_readLen, SeekOrigin.Current);
1664 else if (oldPos - _readPos < pos && pos < oldPos + _readLen - _readPos) {
1665 int diff = (int)(pos - oldPos);
1666 //Console.WriteLine("Seek: diff was "+diff+", readpos was "+_readPos+" adjusting buffer - shrinking by "+ (_readPos + diff));
1667 Buffer.InternalBlockCopy(_buffer, _readPos+diff, _buffer, 0, _readLen - (_readPos + diff));
1668 _readLen -= (_readPos + diff);
1671 SeekCore(_readLen, SeekOrigin.Current);
1674 // Lose the read buffer.
1678 Contract.Assert(_readLen >= 0 && _readPos <= _readLen, "_readLen should be nonnegative, and _readPos should be less than or equal _readLen");
1679 Contract.Assert(pos == Position, "Seek optimization: pos != Position! Buffer math was mangled.");
1684 // This doesn't do argument checking. Necessary for SetLength, which must
1685 // set the file pointer beyond the end of the file. This will update the
1686 // internal position
1687 [System.Security.SecuritySafeCritical] // auto-generated
1688 private long SeekCore(long offset, SeekOrigin origin) {
1689 Contract.Assert(!_handle.IsClosed && CanSeek, "!_handle.IsClosed && CanSeek");
1690 Contract.Assert(origin>=SeekOrigin.Begin && origin<=SeekOrigin.End, "origin>=SeekOrigin.Begin && origin<=SeekOrigin.End");
1694 ret = Win32Native.SetFilePointer(_handle, offset, origin, out hr);
1696 // #errorInvalidHandle
1697 // If ERROR_INVALID_HANDLE is returned, it doesn't suffice to set
1698 // the handle as invalid; the handle must also be closed.
1700 // Marking the handle as invalid but not closing the handle
1701 // resulted in exceptions during finalization and locked column
1702 // values (due to invalid but unclosed handle) in SQL FileStream
1705 // A more mainstream scenario involves accessing a file on a
1706 // network share. ERROR_INVALID_HANDLE may occur because the network
1707 // connection was dropped and the server closed the handle. However,
1708 // the client side handle is still open and even valid for certain
1711 // Note that Dispose doesn't throw so we don't need to special case.
1712 // SetHandleAsInvalid only sets _closed field to true (without
1713 // actually closing handle) so we don't need to call that as well.
1714 if (hr == Win32Native.ERROR_INVALID_HANDLE)
1716 __Error.WinIOError(hr, String.Empty);
1723 // Checks the position of the OS's handle equals what we expect it to.
1724 // This will fail if someone else moved the FileStream's handle or if
1725 // we've hit a bug in FileStream's position updating code.
1726 private void VerifyOSHandlePosition()
1731 // SeekCore will override the current _pos, so save it now
1733 long curPos = SeekCore(0, SeekOrigin.Current);
1735 if (curPos != oldPos) {
1736 // For reads, this is non-fatal but we still could have returned corrupted
1737 // data in some cases. So discard the internal buffer. Potential MDA
1741 // Discard the buffer and let the user know!
1743 throw new IOException(Environment.GetResourceString("IO.IO_FileStreamHandlePosition"));
1748 [System.Security.SecuritySafeCritical] // auto-generated
1749 public override void Write(byte[] array, int offset, int count) {
1751 throw new ArgumentNullException("array", Environment.GetResourceString("ArgumentNull_Buffer"));
1753 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
1755 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
1756 if (array.Length - offset < count)
1757 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
1758 Contract.EndContractBlock();
1760 if (_handle.IsClosed) __Error.FileNotOpen();
1764 // Ensure we can write to the stream, and ready buffer for writing.
1765 if (!CanWrite) __Error.WriteNotSupported();
1766 if (_readPos < _readLen) FlushRead();
1771 // If our buffer has data in it, copy data from the user's array into
1772 // the buffer, and if we can fit it all there, return. Otherwise, write
1773 // the buffer to disk and copy any remaining data into our buffer.
1774 // The assumption here is memcpy is cheaper than disk (or net) IO.
1775 // (10 milliseconds to disk vs. ~20-30 microseconds for a 4K memcpy)
1776 // So the extra copying will reduce the total number of writes, in
1777 // non-pathological cases (ie, write 1 byte, then write for the buffer
1779 if (_writePos > 0) {
1780 int numBytes = _bufferSize - _writePos; // space left in buffer
1782 if (numBytes > count)
1784 Buffer.InternalBlockCopy(array, offset, _buffer, _writePos, numBytes);
1785 _writePos += numBytes;
1786 if (count==numBytes) return;
1790 // Reset our buffer. We essentially want to call FlushWrite
1791 // without calling Flush on the underlying Stream.
1792 #if FEATURE_ASYNC_IO
1795 IAsyncResult result = BeginWriteCore(_buffer, 0, _writePos, null, null);
1800 WriteCore(_buffer, 0, _writePos);
1803 WriteCore(_buffer, 0, _writePos);
1804 #endif // FEATURE_ASYNC_IO
1807 // If the buffer would slow writes down, avoid buffer completely.
1808 if (count >= _bufferSize) {
1809 Contract.Assert(_writePos == 0, "FileStream cannot have buffered data to write here! Your stream will be corrupted.");
1810 WriteCore(array, offset, count);
1813 else if (count == 0)
1814 return; // Don't allocate a buffer then call memcpy for 0 bytes.
1815 if (_buffer==null) _buffer = new byte[_bufferSize];
1816 // Copy remaining bytes into buffer, to write at a later date.
1817 Buffer.InternalBlockCopy(array, offset, _buffer, _writePos, count);
1822 [System.Security.SecuritySafeCritical] // auto-generated
1823 private unsafe void WriteCore(byte[] buffer, int offset, int count) {
1824 Contract.Assert(!_handle.IsClosed, "!_handle.IsClosed");
1825 Contract.Assert(CanWrite, "CanWrite");
1827 Contract.Assert(buffer != null, "buffer != null");
1828 Contract.Assert(_readPos == _readLen, "_readPos == _readLen");
1829 Contract.Assert(offset >= 0, "offset is negative");
1830 Contract.Assert(count >= 0, "count is negative");
1831 #if FEATURE_ASYNC_IO
1833 IAsyncResult result = BeginWriteCore(buffer, offset, count, null, null);
1837 #endif //FEATURE_ASYNC_IO
1839 // Make sure we are writing to the position that we think we are
1841 VerifyOSHandlePosition();
1844 int r = WriteFileNative(_handle, buffer, offset, count, null, out hr);
1846 // For pipes, ERROR_NO_DATA is not an error, but the pipe is closing.
1847 if (hr == ERROR_NO_DATA) {
1851 // ERROR_INVALID_PARAMETER may be returned for writes
1852 // where the position is too large (ie, writing at Int64.MaxValue
1853 // on Win9x) OR for synchronous writes to a handle opened
1855 if (hr == ERROR_INVALID_PARAMETER)
1856 throw new IOException(Environment.GetResourceString("IO.IO_FileTooLongOrHandleNotSync"));
1857 __Error.WinIOError(hr, String.Empty);
1860 Contract.Assert(r >= 0, "FileStream's WriteCore is likely broken.");
1866 [System.Security.SecuritySafeCritical] // auto-generated
1867 [HostProtection(ExternalThreading = true)]
1868 public override IAsyncResult BeginRead(byte[] array, int offset, int numBytes, AsyncCallback userCallback, Object stateObject)
1871 throw new ArgumentNullException("array");
1873 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
1875 throw new ArgumentOutOfRangeException("numBytes", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
1876 if (array.Length - offset < numBytes)
1877 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
1878 Contract.EndContractBlock();
1880 if (_handle.IsClosed) __Error.FileNotOpen();
1882 #if FEATURE_ASYNC_IO
1884 return base.BeginRead(array, offset, numBytes, userCallback, stateObject);
1886 return BeginReadAsync(array, offset, numBytes, userCallback, stateObject);
1888 return base.BeginRead(array, offset, numBytes, userCallback, stateObject);
1889 #endif // FEATURE_ASYNC_IO
1892 #if FEATURE_ASYNC_IO
1893 [System.Security.SecuritySafeCritical] // auto-generated
1894 [HostProtection(ExternalThreading = true)]
1895 private FileStreamAsyncResult BeginReadAsync(byte[] array, int offset, int numBytes, AsyncCallback userCallback, Object stateObject)
1897 Contract.Assert(_isAsync);
1899 if (!CanRead) __Error.ReadNotSupported();
1901 Contract.Assert((_readPos == 0 && _readLen == 0 && _writePos >= 0) || (_writePos == 0 && _readPos <= _readLen), "We're either reading or writing, but not both.");
1905 // Pipes are ----ed up, at least when you have 2 different pipes
1906 // that you want to use simultaneously. When redirecting stdout
1907 // & stderr with the Process class, it's easy to deadlock your
1908 // parent & child processes when doing writes 4K at a time. The
1909 // OS appears to use a 4K buffer internally. If you write to a
1910 // pipe that is full, you will block until someone read from
1911 // that pipe. If you try reading from an empty pipe and
1912 // FileStream's BeginRead blocks waiting for data to fill it's
1913 // internal buffer, you will be blocked. In a case where a child
1914 // process writes to stdout & stderr while a parent process tries
1915 // reading from both, you can easily get into a deadlock here.
1916 // To avoid this deadlock, don't buffer when doing async IO on
1917 // pipes. But don't completely ignore buffered data either.
1918 if (_readPos < _readLen)
1920 int n = _readLen - _readPos;
1921 if (n > numBytes) n = numBytes;
1922 Buffer.InternalBlockCopy(_buffer, _readPos, array, offset, n);
1925 // Return a synchronous FileStreamAsyncResult
1926 return FileStreamAsyncResult.CreateBufferedReadResult(n, userCallback, stateObject, false);
1930 Contract.Assert(_writePos == 0, "FileStream must not have buffered write data here! Pipes should be unidirectional.");
1931 return BeginReadCore(array, offset, numBytes, userCallback, stateObject, 0);
1935 Contract.Assert(!_isPipe, "Should not be a pipe.");
1937 // Handle buffering.
1938 if (_writePos > 0) FlushWrite(false);
1939 if (_readPos == _readLen)
1941 // I can't see how to handle buffering of async requests when
1942 // filling the buffer asynchronously, without a lot of complexity.
1943 // The problems I see are issuing an async read, we do an async
1944 // read to fill the buffer, then someone issues another read
1945 // (either synchronously or asynchronously) before the first one
1946 // returns. This would involve some sort of complex buffer locking
1947 // that we probably don't want to get into, at least not in V1.
1948 // If we did a [....] read to fill the buffer, we could avoid the
1949 // problem, and any async read less than 64K gets turned into a
1950 // synchronous read by NT anyways... --
1952 if (numBytes < _bufferSize)
1954 if (_buffer == null) _buffer = new byte[_bufferSize];
1955 IAsyncResult bufferRead = BeginReadCore(_buffer, 0, _bufferSize, null, null, 0);
1956 _readLen = EndRead(bufferRead);
1958 if (n > numBytes) n = numBytes;
1959 Buffer.InternalBlockCopy(_buffer, 0, array, offset, n);
1962 // Return a synchronous FileStreamAsyncResult
1963 return FileStreamAsyncResult.CreateBufferedReadResult(n, userCallback, stateObject, false);
1967 // Here we're making our position pointer inconsistent
1968 // with our read buffer. Throw away the read buffer's contents.
1971 return BeginReadCore(array, offset, numBytes, userCallback, stateObject, 0);
1976 int n = _readLen - _readPos;
1977 if (n > numBytes) n = numBytes;
1978 Buffer.InternalBlockCopy(_buffer, _readPos, array, offset, n);
1983 // Return a synchronous FileStreamAsyncResult
1984 return FileStreamAsyncResult.CreateBufferedReadResult(n, userCallback, stateObject, false);
1988 // For streams with no clear EOF like serial ports or pipes
1989 // we cannot read more data without causing an app to block
1990 // incorrectly. Pipes don't go down this path
1991 // though. This code needs to be fixed.
1992 // Throw away read buffer.
1995 return BeginReadCore(array, offset + n, numBytes - n, userCallback, stateObject, n);
1997 // WARNING: all state on asyncResult objects must be set before
1998 // we call ReadFile in BeginReadCore, since the OS can run our
1999 // callback & the user's callback before ReadFile returns.
2002 #endif // FEATURE_ASYNC_IO
2004 #if FEATURE_ASYNC_IO
2005 [System.Security.SecuritySafeCritical] // auto-generated
2006 [ResourceExposure(ResourceScope.None)]
2007 [ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain)]
2008 unsafe private FileStreamAsyncResult BeginReadCore(byte[] bytes, int offset, int numBytes, AsyncCallback userCallback, Object stateObject, int numBufferedBytesRead)
2010 Contract.Assert(!_handle.IsClosed, "!_handle.IsClosed");
2011 Contract.Assert(CanRead, "CanRead");
2012 Contract.Assert(bytes != null, "bytes != null");
2013 Contract.Assert(_writePos == 0, "_writePos == 0");
2014 Contract.Assert(_isAsync, "BeginReadCore doesn't work on synchronous file streams!");
2015 Contract.Assert(offset >= 0, "offset is negative");
2016 Contract.Assert(numBytes >= 0, "numBytes is negative");
2018 // Create and store async stream class library specific data in the async result
2020 // Must pass in _numBufferedBytes here to ensure all the state on the IAsyncResult
2021 // object is set before we call ReadFile, which gives the OS an
2022 // opportunity to run our callback (including the user callback &
2023 // the call to EndRead) before ReadFile has returned.
2024 FileStreamAsyncResult asyncResult = new FileStreamAsyncResult(numBufferedBytesRead, bytes, _handle, userCallback, stateObject, false);
2025 NativeOverlapped* intOverlapped = asyncResult.OverLapped;
2027 // Calculate position in the file we should be at after the read is done
2031 // Make sure we are reading from the position that we think we are
2033 VerifyOSHandlePosition();
2035 if (_pos + numBytes > len) {
2037 numBytes = (int) (len - _pos);
2042 // Now set the position to read from in the NativeOverlapped struct
2043 // For pipes, we should leave the offset fields set to 0.
2044 intOverlapped->OffsetLow = unchecked((int)_pos);
2045 intOverlapped->OffsetHigh = (int)(_pos>>32);
2047 // When using overlapped IO, the OS is not supposed to
2048 // touch the file pointer location at all. We will adjust it
2049 // ourselves. This isn't threadsafe.
2051 // WriteFile should not update the file pointer when writing
2052 // in overlapped mode, according to MSDN. But it does update
2053 // the file pointer when writing to a UNC path!
2054 // So changed the code below to seek to an absolute
2055 // location, not a relative one. ReadFile seems consistent though.
2056 SeekCore(numBytes, SeekOrigin.Current);
2059 if (FrameworkEventSource.IsInitialized && FrameworkEventSource.Log.IsEnabled(EventLevel.Informational, FrameworkEventSource.Keywords.ThreadTransfer))
2060 FrameworkEventSource.Log.ThreadTransferSend((long)(asyncResult.OverLapped), 2, string.Empty, false);
2062 // queue an async ReadFile operation and pass in a packed overlapped
2064 int r = ReadFileNative(_handle, bytes, offset, numBytes, intOverlapped, out hr);
2065 // ReadFile, the OS version, will return 0 on failure. But
2066 // my ReadFileNative wrapper returns -1. My wrapper will return
2069 // On async requests that are still pending, r==-1 w/ hr==ERROR_IO_PENDING
2070 // on async requests that completed sequentially, r==0
2071 // You will NEVER RELIABLY be able to get the number of bytes
2072 // read back from this call when using overlapped structures! You must
2073 // not pass in a non-null lpNumBytesRead to ReadFile when using
2074 // overlapped structures! This is by design NT behavior.
2075 if (r==-1 && numBytes!=-1) {
2077 // For pipes, when they hit EOF, they will come here.
2078 if (hr == ERROR_BROKEN_PIPE) {
2079 // Not an error, but EOF. AsyncFSCallback will NOT be
2080 // called. Call the user callback here.
2082 // We clear the overlapped status bit for this special case.
2083 // Failure to do so looks like we are freeing a pending overlapped later.
2084 intOverlapped->InternalLow = IntPtr.Zero;
2085 asyncResult.CallUserCallback();
2086 // EndRead will free the Overlapped struct correctly.
2088 else if (hr != ERROR_IO_PENDING) {
2089 if (!_handle.IsClosed && CanSeek) // Update Position - It could be anywhere.
2090 SeekCore(0, SeekOrigin.Current);
2092 if (hr == ERROR_HANDLE_EOF)
2093 __Error.EndOfFile();
2095 __Error.WinIOError(hr, String.Empty);
2099 // Due to a workaround for a race condition in NT's ReadFile &
2100 // WriteFile routines, we will always be returning 0 from ReadFileNative
2101 // when we do async IO instead of the number of bytes read,
2102 // irregardless of whether the operation completed
2103 // synchronously or asynchronously. We absolutely must not
2104 // set asyncResult._numBytes here, since will never have correct
2106 //Console.WriteLine("ReadFile returned: "+r+" (0x"+Int32.Format(r, "x")+") The IO completed synchronously, but the user callback was called on a separate thread");
2111 #endif //FEATURE_ASYNC_IO
2113 [System.Security.SecuritySafeCritical] // Although the unsafe code is only required in PAL, the block is wide scoped. Leave it here for desktop to ensure it's reviewed.
2114 public unsafe override int EndRead(IAsyncResult asyncResult)
2116 // There are 3 significantly different IAsyncResults we'll accept
2117 // here. One is from Stream::BeginRead. The other two are variations
2118 // on our FileStreamAsyncResult. One is from BeginReadCore,
2119 // while the other is from the BeginRead buffering wrapper.
2120 if (asyncResult==null)
2121 throw new ArgumentNullException("asyncResult");
2122 Contract.EndContractBlock();
2124 #if FEATURE_ASYNC_IO
2126 return base.EndRead(asyncResult);
2128 FileStreamAsyncResult afsar = asyncResult as FileStreamAsyncResult;
2129 if (afsar==null || afsar.IsWrite)
2130 __Error.WrongAsyncResult();
2132 // Ensure we can't get into any ----s by doing an interlocked
2133 // CompareExchange here. Avoids corrupting memory via freeing the
2134 // NativeOverlapped class or GCHandle twice. --
2135 if (1 == Interlocked.CompareExchange(ref afsar._EndXxxCalled, 1, 0))
2136 __Error.EndReadCalledTwice();
2138 // Obtain the WaitHandle, but don't use public property in case we
2139 // delay initialize the manual reset event in the future.
2142 // Free memory & GC handles.
2143 afsar.ReleaseNativeResource();
2145 // Now check for any error during the read.
2146 if (afsar.ErrorCode != 0)
2147 __Error.WinIOError(afsar.ErrorCode, String.Empty);
2149 return afsar.NumBytesRead;
2151 return base.EndRead(asyncResult);
2152 #endif // FEATURE_ASYNC_IO
2155 // Reads a byte from the file stream. Returns the byte cast to an int
2156 // or -1 if reading from the end of the stream.
2157 [System.Security.SecuritySafeCritical] // auto-generated
2158 public override int ReadByte() {
2159 if (_handle.IsClosed) __Error.FileNotOpen();
2160 if (_readLen==0 && !CanRead) __Error.ReadNotSupported();
2161 Contract.Assert((_readPos==0 && _readLen==0 && _writePos >= 0) || (_writePos==0 && _readPos <= _readLen), "We're either reading or writing, but not both.");
2162 if (_readPos == _readLen) {
2163 if (_writePos > 0) FlushWrite(false);
2164 Contract.Assert(_bufferSize > 0, "_bufferSize > 0");
2165 if (_buffer == null) _buffer = new byte[_bufferSize];
2166 _readLen = ReadCore(_buffer, 0, _bufferSize);
2169 if (_readPos == _readLen)
2172 int result = _buffer[_readPos];
2178 [System.Security.SecuritySafeCritical] // auto-generated
2179 [HostProtection(ExternalThreading=true)]
2180 public override IAsyncResult BeginWrite(byte[] array, int offset, int numBytes, AsyncCallback userCallback, Object stateObject)
2183 throw new ArgumentNullException("array");
2185 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
2187 throw new ArgumentOutOfRangeException("numBytes", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
2188 if (array.Length - offset < numBytes)
2189 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
2190 Contract.EndContractBlock();
2192 if (_handle.IsClosed) __Error.FileNotOpen();
2194 #if FEATURE_ASYNC_IO
2196 return base.BeginWrite(array, offset, numBytes, userCallback, stateObject);
2198 return BeginWriteAsync(array, offset, numBytes, userCallback, stateObject);
2200 return base.BeginWrite(array, offset, numBytes, userCallback, stateObject);
2201 #endif // FEATURE_ASYNC_IO
2204 #if FEATURE_ASYNC_IO
2205 [System.Security.SecuritySafeCritical] // auto-generated
2206 [HostProtection(ExternalThreading = true)]
2207 private FileStreamAsyncResult BeginWriteAsync(byte[] array, int offset, int numBytes, AsyncCallback userCallback, Object stateObject)
2209 Contract.Assert(_isAsync);
2211 if (!CanWrite) __Error.WriteNotSupported();
2213 Contract.Assert((_readPos == 0 && _readLen == 0 && _writePos >= 0) || (_writePos == 0 && _readPos <= _readLen), "We're either reading or writing, but not both.");
2217 // Pipes are ----ed up, at least when you have 2 different pipes
2218 // that you want to use simultaneously. When redirecting stdout
2219 // & stderr with the Process class, it's easy to deadlock your
2220 // parent & child processes when doing writes 4K at a time. The
2221 // OS appears to use a 4K buffer internally. If you write to a
2222 // pipe that is full, you will block until someone read from
2223 // that pipe. If you try reading from an empty pipe and
2224 // FileStream's BeginRead blocks waiting for data to fill it's
2225 // internal buffer, you will be blocked. In a case where a child
2226 // process writes to stdout & stderr while a parent process tries
2227 // reading from both, you can easily get into a deadlock here.
2228 // To avoid this deadlock, don't buffer when doing async IO on
2230 Contract.Assert(_readPos == 0 && _readLen == 0, "FileStream must not have buffered data here! Pipes should be unidirectional.");
2235 return BeginWriteCore(array, offset, numBytes, userCallback, stateObject);
2238 // Handle buffering.
2241 if (_readPos < _readLen) FlushRead();
2246 int n = _bufferSize - _writePos;
2249 if (_writePos == 0) _buffer = new byte[_bufferSize];
2250 Buffer.InternalBlockCopy(array, offset, _buffer, _writePos, numBytes);
2251 _writePos += numBytes;
2253 // Return a synchronous FileStreamAsyncResult
2254 return FileStreamAsyncResult.CreateBufferedReadResult(numBytes, userCallback, stateObject, true);
2260 return BeginWriteCore(array, offset, numBytes, userCallback, stateObject);
2262 #endif // FEATURE_ASYNC_IO
2264 #if FEATURE_ASYNC_IO
2265 [System.Security.SecuritySafeCritical] // auto-generated
2266 [ResourceExposure(ResourceScope.None)]
2267 [ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain)]
2268 unsafe private FileStreamAsyncResult BeginWriteCore(byte[] bytes, int offset, int numBytes, AsyncCallback userCallback, Object stateObject)
2270 Contract.Assert(!_handle.IsClosed, "!_handle.IsClosed");
2271 Contract.Assert(CanWrite, "CanWrite");
2272 Contract.Assert(bytes != null, "bytes != null");
2273 Contract.Assert(_readPos == _readLen, "_readPos == _readLen");
2274 Contract.Assert(_isAsync, "BeginWriteCore doesn't work on synchronous file streams!");
2275 Contract.Assert(offset >= 0, "offset is negative");
2276 Contract.Assert(numBytes >= 0, "numBytes is negative");
2278 // Create and store async stream class library specific data in the async result
2279 FileStreamAsyncResult asyncResult = new FileStreamAsyncResult(0, bytes, _handle, userCallback, stateObject, true);
2280 NativeOverlapped* intOverlapped = asyncResult.OverLapped;
2283 // Make sure we set the length of the file appropriately.
2285 //Console.WriteLine("BeginWrite - Calculating end pos. pos: "+pos+" len: "+len+" numBytes: "+numBytes);
2287 // Make sure we are writing to the position that we think we are
2289 VerifyOSHandlePosition();
2291 if (_pos + numBytes > len) {
2292 //Console.WriteLine("BeginWrite - Setting length to: "+(pos + numBytes));
2293 SetLengthCore(_pos + numBytes);
2296 // Now set the position to read from in the NativeOverlapped struct
2297 // For pipes, we should leave the offset fields set to 0.
2298 intOverlapped->OffsetLow = (int)_pos;
2299 intOverlapped->OffsetHigh = (int)(_pos>>32);
2301 // When using overlapped IO, the OS is not supposed to
2302 // touch the file pointer location at all. We will adjust it
2303 // ourselves. This isn't threadsafe.
2313 SeekCore(numBytes, SeekOrigin.Current);
2316 //Console.WriteLine("BeginWrite finishing. pos: "+pos+" numBytes: "+numBytes+" _pos: "+_pos+" Position: "+Position);
2318 if (FrameworkEventSource.IsInitialized && FrameworkEventSource.Log.IsEnabled(EventLevel.Informational, FrameworkEventSource.Keywords.ThreadTransfer))
2319 FrameworkEventSource.Log.ThreadTransferSend((long)(asyncResult.OverLapped), 2, string.Empty, false);
2322 // queue an async WriteFile operation and pass in a packed overlapped
2323 int r = WriteFileNative(_handle, bytes, offset, numBytes, intOverlapped, out hr);
2325 // WriteFile, the OS version, will return 0 on failure. But
2326 // my WriteFileNative wrapper returns -1. My wrapper will return
2329 // On async requests that are still pending, r==-1 w/ hr==ERROR_IO_PENDING
2330 // On async requests that completed sequentially, r==0
2331 // You will NEVER RELIABLY be able to get the number of bytes
2332 // written back from this call when using overlapped IO! You must
2333 // not pass in a non-null lpNumBytesWritten to WriteFile when using
2334 // overlapped structures! This is ByDesign NT behavior.
2335 if (r==-1 && numBytes!=-1) {
2336 //Console.WriteLine("WriteFile returned 0; Write will complete asynchronously (if hr==3e5) hr: 0x{0:x}", hr);
2338 // For pipes, when they are closed on the other side, they will come here.
2339 if (hr == ERROR_NO_DATA) {
2340 // Not an error, but EOF. AsyncFSCallback will NOT be
2341 // called. Call the user callback here.
2342 asyncResult.CallUserCallback();
2343 // EndWrite will free the Overlapped struct correctly.
2345 else if (hr != ERROR_IO_PENDING) {
2346 if (!_handle.IsClosed && CanSeek) // Update Position - It could be anywhere.
2347 SeekCore(0, SeekOrigin.Current);
2349 if (hr == ERROR_HANDLE_EOF)
2350 __Error.EndOfFile();
2352 __Error.WinIOError(hr, String.Empty);
2356 // Due to a workaround for a race condition in NT's ReadFile &
2357 // WriteFile routines, we will always be returning 0 from WriteFileNative
2358 // when we do async IO instead of the number of bytes written,
2359 // irregardless of whether the operation completed
2360 // synchronously or asynchronously. We absolutely must not
2361 // set asyncResult._numBytes here, since will never have correct
2363 //Console.WriteLine("WriteFile returned: "+r+" (0x"+Int32.Format(r, "x")+") The IO completed synchronously, but the user callback was called on another thread.");
2368 #endif //FEATURE_ASYNC_IO
2370 [System.Security.SecuritySafeCritical] // Although the unsafe code is only required in PAL, the block is wide scoped. Leave it here for desktop to ensure it's reviewed.
2371 public unsafe override void EndWrite(IAsyncResult asyncResult)
2373 if (asyncResult==null)
2374 throw new ArgumentNullException("asyncResult");
2375 Contract.EndContractBlock();
2377 #if FEATURE_ASYNC_IO
2379 base.EndWrite(asyncResult);
2383 FileStreamAsyncResult afsar = asyncResult as FileStreamAsyncResult;
2384 if (afsar==null || !afsar.IsWrite)
2385 __Error.WrongAsyncResult();
2387 // Ensure we can't get into any ----s by doing an interlocked
2388 // CompareExchange here. Avoids corrupting memory via freeing the
2389 // NativeOverlapped class or GCHandle twice. --
2390 if (1 == Interlocked.CompareExchange(ref afsar._EndXxxCalled, 1, 0))
2391 __Error.EndWriteCalledTwice();
2393 // Obtain the WaitHandle, but don't use public property in case we
2394 // delay initialize the manual reset event in the future.
2397 // Free memory & GC handles.
2398 afsar.ReleaseNativeResource();
2400 // Now check for any error during the write.
2401 if (afsar.ErrorCode != 0)
2402 __Error.WinIOError(afsar.ErrorCode, String.Empty);
2404 // Number of bytes written is afsar._numBytes + afsar._numBufferedBytes.
2407 base.EndWrite(asyncResult);
2408 #endif // FEATURE_ASYNC_IO
2411 [System.Security.SecuritySafeCritical] // auto-generated
2412 public override void WriteByte(byte value)
2414 if (_handle.IsClosed) __Error.FileNotOpen();
2416 if (!CanWrite) __Error.WriteNotSupported();
2417 if (_readPos < _readLen) FlushRead();
2420 Contract.Assert(_bufferSize > 0, "_bufferSize > 0");
2421 if (_buffer==null) _buffer = new byte[_bufferSize];
2423 if (_writePos == _bufferSize)
2426 _buffer[_writePos] = value;
2430 [System.Security.SecuritySafeCritical] // auto-generated
2431 public virtual void Lock(long position, long length) {
2432 if (position < 0 || length < 0)
2433 throw new ArgumentOutOfRangeException((position < 0 ? "position" : "length"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
2434 Contract.EndContractBlock();
2435 if (_handle.IsClosed) __Error.FileNotOpen();
2437 int positionLow = unchecked((int)(position ));
2438 int positionHigh = unchecked((int)(position >> 32));
2439 int lengthLow = unchecked((int)(length ));
2440 int lengthHigh = unchecked((int)(length >> 32));
2442 if (!Win32Native.LockFile(_handle, positionLow, positionHigh, lengthLow, lengthHigh))
2443 __Error.WinIOError();
2446 [System.Security.SecuritySafeCritical] // auto-generated
2447 public virtual void Unlock(long position, long length) {
2448 if (position < 0 || length < 0)
2449 throw new ArgumentOutOfRangeException((position < 0 ? "position" : "length"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
2450 Contract.EndContractBlock();
2451 if (_handle.IsClosed) __Error.FileNotOpen();
2453 int positionLow = unchecked((int)(position ));
2454 int positionHigh = unchecked((int)(position >> 32));
2455 int lengthLow = unchecked((int)(length ));
2456 int lengthHigh = unchecked((int)(length >> 32));
2458 if (!Win32Native.UnlockFile(_handle, positionLow, positionHigh, lengthLow, lengthHigh))
2459 __Error.WinIOError();
2462 // Windows API definitions, from winbase.h and others
2464 private const int FILE_ATTRIBUTE_NORMAL = 0x00000080;
2465 private const int FILE_ATTRIBUTE_ENCRYPTED = 0x00004000;
2466 private const int FILE_FLAG_OVERLAPPED = 0x40000000;
2467 internal const int GENERIC_READ = unchecked((int)0x80000000);
2468 private const int GENERIC_WRITE = 0x40000000;
2470 private const int FILE_BEGIN = 0;
2471 private const int FILE_CURRENT = 1;
2472 private const int FILE_END = 2;
2474 // Error codes (not HRESULTS), from winerror.h
2475 internal const int ERROR_BROKEN_PIPE = 109;
2476 internal const int ERROR_NO_DATA = 232;
2477 private const int ERROR_HANDLE_EOF = 38;
2478 private const int ERROR_INVALID_PARAMETER = 87;
2479 private const int ERROR_IO_PENDING = 997;
2482 // __ConsoleStream also uses this code.
2483 [System.Security.SecurityCritical] // auto-generated
2484 private unsafe int ReadFileNative(SafeFileHandle handle, byte[] bytes, int offset, int count, NativeOverlapped* overlapped, out int hr)
2486 Contract.Requires(handle != null, "handle != null");
2487 Contract.Requires(offset >= 0, "offset >= 0");
2488 Contract.Requires(count >= 0, "count >= 0");
2489 Contract.Requires(bytes != null, "bytes != null");
2490 // Don't corrupt memory when multiple threads are erroneously writing
2491 // to this stream simultaneously.
2492 if (bytes.Length - offset < count)
2493 throw new IndexOutOfRangeException(Environment.GetResourceString("IndexOutOfRange_IORaceCondition"));
2494 Contract.EndContractBlock();
2496 Contract.Assert((_isAsync && overlapped != null) || (!_isAsync && overlapped == null), "Async IO parameter ----up in call to ReadFileNative.");
2498 // You can't use the fixed statement on an array of length 0.
2499 if (bytes.Length==0) {
2505 int numBytesRead = 0;
2507 fixed(byte* p = bytes) {
2509 r = Win32Native.ReadFile(handle, p + offset, count, IntPtr.Zero, overlapped);
2511 r = Win32Native.ReadFile(handle, p + offset, count, out numBytesRead, IntPtr.Zero);
2515 hr = Marshal.GetLastWin32Error();
2516 // We should never silently ---- an error here without some
2517 // extra work. We must make sure that BeginReadCore won't return an
2518 // IAsyncResult that will cause EndRead to block, since the OS won't
2519 // call AsyncFSCallback for us.
2520 if (hr == ERROR_BROKEN_PIPE || hr == Win32Native.ERROR_PIPE_NOT_CONNECTED) {
2521 // This handle was a pipe, and it's done. Not an error, but EOF.
2522 // However, the OS will not call AsyncFSCallback!
2523 // Let the caller handle this, since BeginReadCore & ReadCore
2524 // need to do different things.
2528 // See code:#errorInvalidHandle in "private long SeekCore(long offset, SeekOrigin origin)".
2529 if (hr == Win32Native.ERROR_INVALID_HANDLE)
2536 return numBytesRead;
2539 [System.Security.SecurityCritical] // auto-generated
2540 private unsafe int WriteFileNative(SafeFileHandle handle, byte[] bytes, int offset, int count, NativeOverlapped* overlapped, out int hr) {
2541 Contract.Requires(handle != null, "handle != null");
2542 Contract.Requires(offset >= 0, "offset >= 0");
2543 Contract.Requires(count >= 0, "count >= 0");
2544 Contract.Requires(bytes != null, "bytes != null");
2545 // Don't corrupt memory when multiple threads are erroneously writing
2546 // to this stream simultaneously. (the OS is reading from
2547 // the array we pass to WriteFile, but if we read beyond the end and
2548 // that memory isn't allocated, we could get an AV.)
2549 if (bytes.Length - offset < count)
2550 throw new IndexOutOfRangeException(Environment.GetResourceString("IndexOutOfRange_IORaceCondition"));
2551 Contract.EndContractBlock();
2553 Contract.Assert((_isAsync && overlapped != null) || (!_isAsync && overlapped == null), "Async IO parameter ----up in call to WriteFileNative.");
2555 // You can't use the fixed statement on an array of length 0.
2556 if (bytes.Length==0) {
2561 int numBytesWritten = 0;
2564 fixed(byte* p = bytes) {
2566 r = Win32Native.WriteFile(handle, p + offset, count, IntPtr.Zero, overlapped);
2568 r = Win32Native.WriteFile(handle, p + offset, count, out numBytesWritten, IntPtr.Zero);
2572 hr = Marshal.GetLastWin32Error();
2573 // We should never silently ---- an error here without some
2574 // extra work. We must make sure that BeginWriteCore won't return an
2575 // IAsyncResult that will cause EndWrite to block, since the OS won't
2576 // call AsyncFSCallback for us.
2578 if (hr==ERROR_NO_DATA) {
2579 // This handle was a pipe, and the pipe is being closed on the
2580 // other side. Let the caller handle this, since BeginWriteCore
2581 // & WriteCore need to do different things.
2585 // See code:#errorInvalidHandle in "private long SeekCore(long offset, SeekOrigin origin)".
2586 if (hr == Win32Native.ERROR_INVALID_HANDLE)
2593 return numBytesWritten;
2597 #if FEATURE_ASYNC_IO
2598 [HostProtection(ExternalThreading = true)]
2600 [SecuritySafeCritical]
2601 public override Task<int> ReadAsync(Byte[] buffer, int offset, int count, CancellationToken cancellationToken)
2604 throw new ArgumentNullException("buffer");
2606 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
2608 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
2609 if (buffer.Length - offset < count)
2610 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
2611 Contract.EndContractBlock();
2613 // If we have been inherited into a subclass, the following implementation could be incorrect
2614 // since it does not call through to Read() or BeginRead() which a subclass might have overriden.
2615 // To be safe we will only use this implementation in cases where we know it is safe to do so,
2616 // and delegate to our base class (which will call into Read/BeginRead) when we are not sure.
2617 if (this.GetType() != typeof(FileStream))
2618 return base.ReadAsync(buffer, offset, count, cancellationToken);
2620 if (cancellationToken.IsCancellationRequested)
2621 return Task.FromCancellation<int>(cancellationToken);
2623 if (_handle.IsClosed)
2624 __Error.FileNotOpen();
2626 // If async IO is not supported on this platform or
2627 // if this FileStream was not opened with FileOptions.Asynchronous.
2629 return base.ReadAsync(buffer, offset, count, cancellationToken);
2631 var readTask = new FileStreamReadWriteTask<int>(cancellationToken);
2632 var endReadTask = s_endReadTask;
2633 if (endReadTask == null) s_endReadTask = endReadTask = EndReadTask; // benign initialization ----
2634 readTask._asyncResult = BeginReadAsync(buffer, offset, count, endReadTask, readTask);
2636 if (readTask._asyncResult.IsAsync && cancellationToken.CanBeCanceled)
2638 var cancelReadHandler = s_cancelReadHandler;
2639 if (cancelReadHandler == null) s_cancelReadHandler = cancelReadHandler = CancelTask<int>; // benign initialization ----
2640 readTask._registration = cancellationToken.Register(cancelReadHandler, readTask);
2642 // In case the task is completed right before we register the cancellation callback.
2643 if (readTask._asyncResult.IsCompleted)
2644 readTask._registration.Dispose();
2650 [HostProtection(ExternalThreading = true)]
2652 [SecuritySafeCritical]
2653 public override Task WriteAsync(Byte[] buffer, int offset, int count, CancellationToken cancellationToken)
2656 throw new ArgumentNullException("buffer");
2658 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
2660 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
2661 if (buffer.Length - offset < count)
2662 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
2663 Contract.EndContractBlock();
2665 // If we have been inherited into a subclass, the following implementation could be incorrect
2666 // since it does not call through to Write() or BeginWrite() which a subclass might have overriden.
2667 // To be safe we will only use this implementation in cases where we know it is safe to do so,
2668 // and delegate to our base class (which will call into Write/BeginWrite) when we are not sure.
2669 if (this.GetType() != typeof(FileStream))
2670 return base.WriteAsync(buffer, offset, count, cancellationToken);
2672 if (cancellationToken.IsCancellationRequested)
2673 return Task.FromCancellation(cancellationToken);
2675 if (_handle.IsClosed)
2676 __Error.FileNotOpen();
2678 // If async IO is not supported on this platform or
2679 // if this FileStream was not opened with FileOptions.Asynchronous.
2681 return base.WriteAsync(buffer, offset, count, cancellationToken);
2683 var writeTask = new FileStreamReadWriteTask<VoidTaskResult>(cancellationToken);
2684 var endWriteTask = s_endWriteTask;
2685 if (endWriteTask == null) s_endWriteTask = endWriteTask = EndWriteTask; // benign initialization ----
2686 writeTask._asyncResult = BeginWriteAsync(buffer, offset, count, endWriteTask, writeTask);
2688 if (writeTask._asyncResult.IsAsync && cancellationToken.CanBeCanceled)
2690 var cancelWriteHandler = s_cancelWriteHandler;
2691 if (cancelWriteHandler == null) s_cancelWriteHandler = cancelWriteHandler = CancelTask<VoidTaskResult>; // benign initialization ----
2692 writeTask._registration = cancellationToken.Register(cancelWriteHandler, writeTask);
2694 // In case the task is completed right before we register the cancellation callback.
2695 if (writeTask._asyncResult.IsCompleted)
2696 writeTask._registration.Dispose();
2702 // The task instance returned from ReadAsync and WriteAsync.
2703 // Also stores all of the state necessary for those calls to avoid closures and extraneous delegate allocations.
2704 private sealed class FileStreamReadWriteTask<T> : Task<T>
2706 internal CancellationToken _cancellationToken;
2707 internal CancellationTokenRegistration _registration;
2708 internal FileStreamAsyncResult _asyncResult; // initialized after Begin call completes
2710 internal FileStreamReadWriteTask(CancellationToken cancellationToken) : base()
2712 _cancellationToken = cancellationToken;
2716 // Cancellation callback for both ReadAsync and WriteAsync.
2717 [SecuritySafeCritical]
2718 private static void CancelTask<T>(object state)
2720 var task = state as FileStreamReadWriteTask<T>;
2721 Contract.Assert(task != null);
2722 FileStreamAsyncResult asyncResult = task._asyncResult;
2724 // This method is used as both the completion callback and the cancellation callback.
2725 // We should try to cancel the operation if this is running as the completion callback
2726 // or if cancellation is not applicable:
2727 // 1. asyncResult is not a FileStreamAsyncResult
2728 // 2. asyncResult.IsAsync is false: asyncResult is a "synchronous" FileStreamAsyncResult.
2729 // 3. The asyncResult is completed: this should never happen.
2730 Contract.Assert((!asyncResult.IsWrite && typeof(T) == typeof(int)) ||
2731 (asyncResult.IsWrite && typeof(T) == typeof(VoidTaskResult)));
2732 Contract.Assert(asyncResult != null);
2733 Contract.Assert(asyncResult.IsAsync);
2737 // Cancel the overlapped read and set the task to cancelled state.
2738 if (!asyncResult.IsCompleted)
2739 asyncResult.Cancel();
2741 catch (Exception ex)
2743 task.TrySetException(ex);
2747 // Completion callback for ReadAsync
2748 [SecuritySafeCritical]
2749 private static void EndReadTask(IAsyncResult iar)
2751 FileStreamAsyncResult asyncResult = iar as FileStreamAsyncResult;
2752 Contract.Assert(asyncResult != null);
2753 Contract.Assert(asyncResult.IsCompleted, "How can we end up in the completion callback if the IAsyncResult is not completed?");
2755 var readTask = asyncResult.AsyncState as FileStreamReadWriteTask<int>;
2756 Contract.Assert(readTask != null);
2760 if (asyncResult.IsAsync)
2762 asyncResult.ReleaseNativeResource();
2764 // release the resource held by CancellationTokenRegistration
2765 readTask._registration.Dispose();
2768 if (asyncResult.ErrorCode == Win32Native.ERROR_OPERATION_ABORTED)
2770 var cancellationToken = readTask._cancellationToken;
2771 Contract.Assert(cancellationToken.IsCancellationRequested, "How can the IO operation be aborted if cancellation was not requested?");
2772 readTask.TrySetCanceled(cancellationToken);
2775 readTask.TrySetResult(asyncResult.NumBytesRead);
2777 catch (Exception ex)
2779 readTask.TrySetException(ex);
2783 // Completion callback for WriteAsync
2784 [SecuritySafeCritical]
2785 private static void EndWriteTask(IAsyncResult iar)
2787 var asyncResult = iar as FileStreamAsyncResult;
2788 Contract.Assert(asyncResult != null);
2789 Contract.Assert(asyncResult.IsCompleted, "How can we end up in the completion callback if the IAsyncResult is not completed?");
2791 var writeTask = iar.AsyncState as FileStreamReadWriteTask<VoidTaskResult>;
2792 Contract.Assert(writeTask != null);
2796 if (asyncResult.IsAsync)
2798 asyncResult.ReleaseNativeResource();
2800 // release the resource held by CancellationTokenRegistration
2801 writeTask._registration.Dispose();
2804 if (asyncResult.ErrorCode == Win32Native.ERROR_OPERATION_ABORTED)
2806 var cancellationToken = writeTask._cancellationToken;
2807 Contract.Assert(cancellationToken.IsCancellationRequested, "How can the IO operation be aborted if cancellation was not requested?");
2808 writeTask.TrySetCanceled(cancellationToken);
2811 writeTask.TrySetResult(default(VoidTaskResult));
2813 catch (Exception ex)
2815 writeTask.TrySetException(ex);
2819 // Unlike Flush(), FlushAsync() always flushes to disk. This is intentional.
2820 // Legend is that we chose not to flush the OS file buffers in Flush() in fear of
2821 // perf problems with frequent, long running FlushFileBuffers() calls. But we don't
2822 // have that problem with FlushAsync() because we will call FlushFileBuffers() in the background.
2823 [HostProtection(ExternalThreading = true)]
2825 [System.Security.SecuritySafeCritical]
2826 public override Task FlushAsync(CancellationToken cancellationToken)
2828 // If we have been inherited into a subclass, the following implementation could be incorrect
2829 // since it does not call through to Flush() which a subclass might have overriden. To be safe
2830 // we will only use this implementation in cases where we know it is safe to do so,
2831 // and delegate to our base class (which will call into Flush) when we are not sure.
2832 if (this.GetType() != typeof(FileStream))
2833 return base.FlushAsync(cancellationToken);
2835 if (cancellationToken.IsCancellationRequested)
2836 return Task.FromCancellation(cancellationToken);
2838 if (_handle.IsClosed)
2839 __Error.FileNotOpen();
2841 // The always synchronous data transfer between the OS and the internal buffer is intentional
2842 // because this is needed to allow concurrent async IO requests. Concurrent data transfer
2843 // between the OS and the internal buffer will result in race conditions. Since FlushWrite and
2844 // FlushRead modify internal state of the stream and transfer data between the OS and the
2845 // internal buffer, they cannot be truly async. We will, however, flush the OS file buffers
2846 // asynchronously because it doesn't modify any internal state of the stream and is potentially
2847 // a long running process.
2850 FlushInternalBuffer();
2854 return Task.FromException(e);
2858 return Task.Factory.StartNew(
2859 state => ((FileStream)state).FlushOSBuffer(),
2862 TaskCreationOptions.DenyChildAttach,
2863 TaskScheduler.Default);
2865 return Task.CompletedTask;
2867 #endif //FEATURE_ASYNC_IO