Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / mscorlib / system / io / filestream.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 /*============================================================
7 **
8 ** Class:  FileStream
9 ** 
10 ** <OWNER>[....]</OWNER>
11 **
12 **
13 ** Purpose: Exposes a Stream around a file, with full 
14 ** synchronous and asychronous support, and buffering.
15 **
16 **
17 ===========================================================*/
18 using System;
19 using Microsoft.Win32;
20 using Microsoft.Win32.SafeHandles;
21 using System.Security;
22 #if FEATURE_MACL
23 using System.Security.AccessControl;
24 #endif
25 using System.Security.Permissions;
26 using System.Threading;
27 #if FEATURE_ASYNC_IO
28 using System.Threading.Tasks;
29 #endif
30 using System.Runtime.InteropServices;
31 #if FEATURE_REMOTING
32 using System.Runtime.Remoting.Messaging;
33 #endif
34 using System.Runtime.CompilerServices;
35 using System.Globalization;
36 using System.Runtime.Versioning;
37 using System.Diagnostics.Contracts;
38 using System.Diagnostics.Tracing;
39
40 /*
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.
48  *
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.
53  *
54  * Class Invariants:
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
57  * should be true:
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.
65  *
66  */
67
68 namespace System.IO {
69
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
75
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
79     {
80         // README:
81         // If you modify the order of these fields, make sure to update 
82         // the native VM definition of this class as well!!! 
83 #if FEATURE_ASYNC_IO
84         // User code callback
85         private AsyncCallback _userCallback;
86 #endif
87         private Object _userStateObject;
88         private ManualResetEvent _waitHandle;
89         [System.Security.SecurityCritical]
90         private SafeFileHandle _handle;      // For cancellation support.
91 #if !FEATURE_PAL
92         [SecurityCritical]
93         private NativeOverlapped* _overlapped;
94         internal NativeOverlapped* OverLapped { [SecurityCritical]get { return _overlapped; } }
95         internal bool IsAsync { [SecuritySafeCritical]get { return _overlapped != null; } }
96 #endif
97
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; } }
101
102         private int _errorCode;
103         internal int ErrorCode { get { return _errorCode; } }
104
105         private int _numBufferedBytes;
106         internal int NumBufferedBytes { get { return _numBufferedBytes; } }
107
108         internal int NumBytesRead { get { return _numBytes + _numBufferedBytes; } }
109
110         private bool _isWrite;     // Whether this is a read or a write
111         internal bool IsWrite { get { return _isWrite; } }
112
113         private bool _isComplete;  // Value for IsCompleted property        
114         private bool _completedSynchronously;  // Which thread called callback
115
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. 
119
120         // Overlapped class will take care of the async IO operations in progress 
121         // when an appdomain unload occurs.
122
123 #if FEATURE_ASYNC_IO
124         [System.Security.SecurityCritical] // auto-generated
125         private unsafe static IOCompletionCallback s_IOCallback;
126
127         [SecuritySafeCritical]
128         internal FileStreamAsyncResult(
129             int numBufferedBytes,
130             byte[] bytes,
131             SafeFileHandle handle,
132             AsyncCallback userCallback,
133             Object userStateObject,
134             bool isWrite)
135         {
136             _userCallback = userCallback;
137             _userStateObject = userStateObject;
138             _isWrite = isWrite;
139             _numBufferedBytes = numBufferedBytes;
140             _handle = handle;
141
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;
146
147             // Create a managed overlapped class
148             // We will set the file offsets later
149             Overlapped overlapped = new Overlapped(0, 0, IntPtr.Zero, this);
150
151             // Pack the Overlapped class, and store it in the async result
152             if (userCallback != null)
153             {
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);
157             }
158             else
159             {
160                 _overlapped = overlapped.UnsafePack(null, bytes);
161             }
162
163             Contract.Assert(_overlapped != null, "Did Overlapped.Pack or Overlapped.UnsafePack just return a null?");
164         }
165
166         internal static FileStreamAsyncResult CreateBufferedReadResult(int numBufferedBytes, AsyncCallback userCallback, Object userStateObject, bool isWrite)
167         {
168             FileStreamAsyncResult asyncResult = new FileStreamAsyncResult(numBufferedBytes, userCallback, userStateObject, isWrite);
169             asyncResult.CallUserCallback();
170             return asyncResult;
171         }
172
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)
176         {
177             _userCallback = userCallback;
178             _userStateObject = userStateObject;
179             _isWrite = isWrite;
180             _numBufferedBytes = numBufferedBytes;
181         }
182 #endif // FEATURE_ASYNC_IO
183
184         public Object AsyncState
185         {
186             get { return _userStateObject; }
187         }
188
189         public bool IsCompleted
190         {
191             get { return _isComplete; }
192         }
193
194         public WaitHandle AsyncWaitHandle
195         {
196 #if !FEATURE_PAL
197             [System.Security.SecuritySafeCritical]  // auto-generated
198             [ResourceExposure(ResourceScope.None)]
199             [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
200             get {
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);
212                     }
213
214                     // make sure only one thread sets _waitHandle
215                     if (Interlocked.CompareExchange<ManualResetEvent>(ref _waitHandle, mre, null) == null) {
216                         if (_isComplete)
217                             _waitHandle.Set();
218                     }
219                     else {
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.
226                         mre.Close();
227                     }
228                 }
229                 return _waitHandle;
230             }
231 #else
232             get { return null; }
233 #endif //!FEATURE_PAL
234         }
235
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
243         {
244             get { return _completedSynchronously; }
245         }
246
247 #if FEATURE_ASYNC_IO
248         private void CallUserCallbackWorker()
249         {
250             _isComplete = true;
251
252             // ensure _isComplete is set before reading _waitHandle
253             Thread.MemoryBarrier();
254             if (_waitHandle != null)
255                 _waitHandle.Set();
256
257             _userCallback(this);
258         }
259
260         internal void CallUserCallback()
261         {
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.
265             
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);
272             }
273             else {
274                 _isComplete = true;
275
276                 // ensure _isComplete is set before reading _waitHandle
277                 Thread.MemoryBarrier();
278                 if (_waitHandle != null)
279                     _waitHandle.Set();
280             }
281         }
282
283         [SecurityCritical]
284         internal void ReleaseNativeResource()
285         {
286             // Free memory & GC handles.
287             if (this._overlapped != null)
288                 Overlapped.Free(_overlapped);
289         }
290
291         internal void Wait()
292         {
293             if (_waitHandle != null)
294             {
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.
299                 try
300                 {
301                     _waitHandle.WaitOne();
302                     Contract.Assert(_isComplete == true, "FileStreamAsyncResult::Wait - AsyncFSCallback  didn't set _isComplete to true!");
303                 }
304                 finally
305                 {
306                     _waitHandle.Close();
307                 }
308             }
309         }
310         
311         // When doing IO asynchronously (ie, _isAsync==true), this callback is 
312         // called by a free thread in the threadpool when the IO operation 
313         // completes.  
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)
318         {
319             BCLDebug.Log(String.Format("AsyncFSCallback called.  errorCode: " + errorCode + "  numBytes: " + numBytes));
320
321             // Unpack overlapped
322             Overlapped overlapped = Overlapped.Unpack(pOverlapped);
323             // Free the overlapped struct in EndRead/EndWrite.
324
325             // Extract async result from overlapped 
326             FileStreamAsyncResult asyncResult =
327                 (FileStreamAsyncResult)overlapped.AsyncResult;
328             asyncResult._numBytes = (int)numBytes;
329
330             if (FrameworkEventSource.IsInitialized && FrameworkEventSource.Log.IsEnabled(EventLevel.Informational, FrameworkEventSource.Keywords.ThreadTransfer))
331                 FrameworkEventSource.Log.ThreadTransferReceive((long)(asyncResult.OverLapped), 2, string.Empty);
332
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)
338                 errorCode = 0;
339
340             asyncResult._errorCode = (int)errorCode;
341
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;
349
350             // ensure _isComplete is set before reading _waitHandle
351             Thread.MemoryBarrier();
352
353             // The OS does not signal this event.  We must do it ourselves.
354             ManualResetEvent wh = asyncResult._waitHandle;
355             if (wh != null)
356             {
357                 Contract.Assert(!wh.SafeWaitHandle.IsClosed, "ManualResetEvent already closed!");
358                 bool r = wh.Set();
359                 Contract.Assert(r, "ManualResetEvent::Set failed!");
360                 if (!r) __Error.WinIOError();
361             }
362
363             AsyncCallback userCallback = asyncResult._userCallback;
364             if (userCallback != null)
365                 userCallback(asyncResult);
366         }
367
368         [SecuritySafeCritical]
369         [HostProtection(ExternalThreading = true)]
370         internal void Cancel()
371         {
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");
374
375             if (IsCompleted)
376                 return;
377
378             if (_handle.IsInvalid)
379                 return;
380
381             bool r = Win32Native.CancelIoEx(_handle, _overlapped);
382             if (!r)
383             {
384                 int errorCode = Marshal.GetLastWin32Error();
385
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);
390             }
391         }
392 #endif //FEATURE_ASYNC_IO
393     }
394
395     [ComVisible(true)]
396     public class FileStream : Stream
397     {
398         internal const int DefaultBufferSize = 4096;
399
400
401 #if FEATURE_LEGACYNETCF
402         // Mango didn't do support Async IO.
403         private static readonly bool _canUseAsync = !CompatibilitySwitches.IsAppEarlierThanWindowsPhone8;
404 #else
405         private const bool _canUseAsync = true;
406 #endif //FEATURE_ASYNC_IO
407
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.
424 #if FEATURE_ASYNC_IO
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;        
429 #endif
430
431         //This exists only to support IsolatedStorageFileStream.
432         //Any changes to FileStream must include the corresponding changes in IsolatedStorage.
433         internal FileStream() { 
434         }
435 #if FEATURE_CORECLR
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"),
450                         caller,
451                         callee));
452                 }
453             }
454 #endif // FEATURE_LEGACYNETCF
455         }
456     
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"),
471                         caller,
472                         callee));
473                 }
474             }
475 #endif // FEATURE_LEGACYNETCF
476         }
477
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"),
492                         caller,
493                         callee));
494                 }
495             }
496 #endif // FEATURE_LEGACYNETCF
497         }
498
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)
504         {
505         }
506
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) {
513         }
514     
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) {
520         }
521
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) {
527         }
528
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)
534         {
535         }
536 #endif // FEATURE_CORECLR
537
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)
543         {
544         }
545
546         #if FEATURE_CORECLR
547         [System.Security.SecurityCritical] // auto-generated
548         #else
549         [System.Security.SecuritySafeCritical]
550         #endif
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)
555         {
556         }
557
558 #if FEATURE_MACL
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)
565         {
566             Object pinningHandle;
567             Win32Native.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share, fileSecurity, out pinningHandle);
568             try {
569                 Init(path, mode, (FileAccess)0, (int)rights, true, share, bufferSize, options, secAttrs, Path.GetFileName(path), false, false, false);
570             }
571             finally {
572                 if (pinningHandle != null) {
573                     GCHandle pinHandle = (GCHandle) pinningHandle;
574                     pinHandle.Free();
575                 }
576             }
577         }
578
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)
583         {
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);
586         }
587 #endif
588
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)
593         {
594             Win32Native.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share);
595             Init(path, mode, access, 0, false, share, bufferSize, options, secAttrs, msgPath, bFromProxy, false, false);
596         }
597
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)
602         {
603             Win32Native.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share);
604             Init(path, mode, access, 0, false, share, bufferSize, options, secAttrs, msgPath, bFromProxy, useLongPath, false);
605         }
606
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)
611         {
612             Win32Native.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share);
613             Init(path, mode, access, 0, false, share, bufferSize, options, secAttrs, msgPath, bFromProxy, useLongPath, checkHost);
614         }
615
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)
621         {
622             if (path == null)
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();
627
628 #if FEATURE_MACL
629             FileSystemRights fileSystemRights = (FileSystemRights)rights;
630 #endif  
631             // msgPath must be safe to hand back to untrusted code.
632
633             _fileName = msgPath;  // To handle odd cases of finalizing partially constructed objects.
634             _exposedHandle = false;
635
636 #if FEATURE_PAL
637             Contract.Assert(!useRights, "Specifying FileSystemRights is not supported on this platform!");
638 #endif  
639           
640             // don't include inheritable in our bounds check for share
641             FileShare tempshare = share & ~FileShare.Inheritable;
642             String badArg = null;
643
644             if (mode < FileMode.CreateNew || mode > FileMode.Append)
645                 badArg = "mode";
646             else if (!useRights && (access < FileAccess.Read || access > FileAccess.ReadWrite))
647                 badArg = "access";
648 #if FEATURE_MACL
649             else if (useRights && (fileSystemRights < FileSystemRights.ReadData || fileSystemRights > FileSystemRights.FullControl))
650                 badArg = "rights";
651 #endif            
652             else if (tempshare < FileShare.None || tempshare > (FileShare.ReadWrite | FileShare.Delete))
653                 badArg = "share";
654             
655             if (badArg != null)
656                 throw new ArgumentOutOfRangeException(badArg, Environment.GetResourceString("ArgumentOutOfRange_Enum"));
657             
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"));
661
662             if (bufferSize <= 0)
663                 throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
664
665             // Write access validation
666 #if FEATURE_MACL
667             if ((!useRights && (access & FileAccess.Write) == 0) 
668                 || (useRights && (fileSystemRights & FileSystemRights.Write) == 0))
669 #else
670             if (!useRights && (access & FileAccess.Write) == 0)
671 #endif //FEATURE_MACL
672             {
673                 if (mode==FileMode.Truncate || mode==FileMode.CreateNew || mode==FileMode.Create || mode==FileMode.Append) {
674                     // No write access
675                     if (!useRights)
676                         throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFileMode&AccessCombo", mode, access));
677 #if FEATURE_MACL
678                     else
679                         throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFileMode&RightsCombo", mode, fileSystemRights));
680 #endif //FEATURE_MACL
681                 }
682             }
683
684 #if 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) {
689                     useRights = false;
690                     access = FileAccess.Write;
691                 }
692                 else {
693                     throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFileModeTruncate&RightsCombo", mode, fileSystemRights));
694                 }
695             }
696 #endif
697
698             int fAccess;
699             if (!useRights) {
700                 fAccess = access == FileAccess.Read? GENERIC_READ:
701                 access == FileAccess.Write? GENERIC_WRITE:
702                 GENERIC_READ | GENERIC_WRITE;
703             }
704             else {
705                 fAccess = rights;
706             }
707             
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);
713
714             _fileName = filePath;
715
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"));
719
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.
728
729             Path.CheckInvalidPathChars(filePath, true);
730
731             if (filePath.IndexOf( ':', 2 ) != -1)
732                 throw new NotSupportedException( Environment.GetResourceString( "Argument_PathFormatNotSupported" ) );
733
734             bool read = false;
735
736 #if FEATURE_MACL
737             if ((!useRights && (access & FileAccess.Read) != 0) || (useRights && (fileSystemRights & FileSystemRights.ReadAndExecute) != 0))
738 #else
739             if (!useRights && (access & FileAccess.Read) != 0)
740 #endif //FEATURE_MACL
741             {
742                 if (mode == FileMode.Append)
743                     throw new ArgumentException(Environment.GetResourceString("Argument_InvalidAppendMode"));
744                 else
745                     read = true;
746             }
747
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
752             {
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;
757
758                 if (read)
759                 {
760                     Contract.Assert(mode != FileMode.Append);
761                     secAccess = secAccess | FileIOPermissionAccess.Read;
762                 }
763
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
766                 // in those cases.
767
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.
771
772 #if FEATURE_MACL
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)
781                    )
782 #else
783                 if (!useRights && (access & FileAccess.Write) != 0) 
784 #endif //FEATURE_MACL
785                 {
786                     if (mode==FileMode.Append)
787                         secAccess = secAccess | FileIOPermissionAccess.Append;
788                     else
789                         secAccess = secAccess | FileIOPermissionAccess.Write;
790                 }
791
792 #if FEATURE_MACL
793                 bool specifiedAcl;
794                 unsafe {
795                     specifiedAcl = secAttrs != null && secAttrs.pSecurityDescriptor != null;
796                 }
797                 
798                 AccessControlActions control = specifiedAcl ? AccessControlActions.Change : AccessControlActions.None;
799                 new FileIOPermission(secAccess, control, new String[] { filePath }, false, false).Demand();
800 #else
801 #if FEATURE_CORECLR
802                 if (checkHost) {
803                     FileSecurityState state = new FileSecurityState(FileSecurityState.ToFileSecurityState(secAccess), path, filePath);
804                     state.EnsureState();
805                 }
806 #else
807                 new FileIOPermission(secAccess, new String[] { filePath }, false, false).Demand();
808 #endif // FEATURE_CORECLR
809 #endif
810             }
811
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;
815
816             bool seekToEnd = (mode==FileMode.Append);
817             // Must use a valid Win32 constant here...
818             if (mode == FileMode.Append)
819                 mode = FileMode.OpenOrCreate;
820
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)
825                 _isAsync = true;
826             else
827                 options &= ~FileOptions.Asynchronous;
828
829             int flagsAndAttributes = (int) options;
830             
831 #if !FEATURE_PAL
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);
836 #endif
837             // Don't pop up a dialog for reading from an emtpy floppy drive
838             int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
839             try {
840                 String tempPath = filePath;
841                 if (useLongPath)
842                     tempPath = Path.AddLongPathPrefix(tempPath);
843                 _handle = Win32Native.SafeCreateFile(tempPath, fAccess, share, secAttrs, mode, flagsAndAttributes, IntPtr.Zero);
844                 
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.
850                     
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;
857     
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;
865     
866                     if (!bFromProxy)
867                     {
868                         try {
869 #if !FEATURE_CORECLR
870                             new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { _fileName }, false, false ).Demand();
871 #endif
872                             canGiveFullPath = true;
873                         }
874                         catch(SecurityException) {}
875                     }
876     
877                     if (canGiveFullPath)
878                         __Error.WinIOError(errorCode, _fileName);
879                     else
880                         __Error.WinIOError(errorCode, msgPath);
881                 }
882             }
883             finally {
884                 Win32Native.SetErrorMode(oldMode);
885             }
886                 
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) {
893                 _handle.Close();
894                 throw new NotSupportedException(Environment.GetResourceString("NotSupported_FileStreamOnNonFiles"));
895             }
896
897 #if FEATURE_ASYNC_IO
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.)
906             if (_isAsync) {
907                 bool b = false;
908                 // BindHandle requires UnmanagedCode permission
909                 new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
910                 try {
911                     b = ThreadPool.BindHandle(_handle);
912                 }
913                 finally {
914                     CodeAccessPermission.RevertAssert();
915                     if (!b) {
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?");
918                         _handle.Close();
919                     }
920                 }
921                 if (!b) 
922                     throw new IOException(Environment.GetResourceString("IO.IO_BindHandleFailed"));
923             }
924 #endif // FEATURE_ASYNC_IO
925             if (!useRights) {
926                 _canRead = (access & FileAccess.Read) != 0;
927                 _canWrite = (access & FileAccess.Write) != 0;
928             }
929 #if FEATURE_MACL
930             else {
931                 _canRead = (fileSystemRights & FileSystemRights.ReadData) != 0;
932                 _canWrite = ((fileSystemRights & FileSystemRights.WriteData) != 0) 
933                             || ((fileSystemRights & FileSystemRights.AppendData) != 0);
934             }
935 #endif //FEATURE_MACL
936
937             _canSeek = true;
938             _isPipe = false;
939             _pos = 0;
940             _bufferSize = bufferSize;
941             _readPos = 0;
942             _readLen = 0;
943             _writePos = 0;
944
945             // For Append mode...
946             if (seekToEnd) {
947                 _appendStart = SeekCore(0, SeekOrigin.End);
948             }
949             else {
950                 _appendStart = -1;
951             }
952         }
953
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) {
959         }
960
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) {
966         }
967
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) {
973         }
974
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) {
985         }
986
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) {
992         }
993
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) {
999         }
1000
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();
1012
1013             _handle = handle;
1014             _exposedHandle = true;
1015
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"));
1021
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;
1029             _readPos = 0;
1030             _readLen = 0;
1031             _writePos = 0;
1032             _fileName = null;
1033             _isPipe = handleType == Win32Native.FILE_TYPE_PIPE;
1034
1035 #if !FEATURE_PAL
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
1045             if (_isAsync) {
1046                 bool b = false;
1047                 try {
1048                     b = ThreadPool.BindHandle(_handle);
1049                 }
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"));
1054                 }
1055                 if (!b) {
1056                     throw new IOException(Environment.GetResourceString("IO.IO_BindHandleFailed"));
1057                 }
1058             }
1059             else {
1060 #endif // FEATURE_CORECLR
1061                 if (handleType != Win32Native.FILE_TYPE_PIPE)
1062                     VerifyHandleIsSync();
1063 #if !FEATURE_CORECLR
1064             }
1065 #endif // FEATURE_CORECLR
1066 #else
1067                 if (handleType != Win32Native.FILE_TYPE_PIPE)
1068                     VerifyHandleIsSync();
1069 #endif //!FEATURE_PAL
1070             if (_canSeek)
1071                 SeekCore(0, SeekOrigin.Current);
1072             else
1073                 _pos = 0;
1074         }
1075
1076         [System.Security.SecuritySafeCritical]  // auto-generated
1077         private static Win32Native.SECURITY_ATTRIBUTES GetSecAttrs(FileShare share)
1078         {
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);
1083
1084                 secAttrs.bInheritHandle = 1;
1085             }
1086             return secAttrs;
1087         }
1088
1089 #if FEATURE_MACL
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)
1094         {
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);
1100
1101                 if ((share & FileShare.Inheritable) != 0) {
1102                     secAttrs.bInheritHandle = 1;
1103                 }
1104
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;
1111                 }
1112             }
1113             return secAttrs;
1114         }
1115 #endif
1116
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()
1121         {
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).
1126
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];
1132             int hr = 0;
1133             int r = 0;
1134             
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.
1139             if (CanRead) {
1140                 r = ReadFileNative(_handle, bytes, 0, 0, null, out hr);
1141             }
1142             else if (CanWrite) {
1143                 r = WriteFileNative(_handle, bytes, 0, 0, null, out hr);
1144             }
1145
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>");
1150         }
1151
1152
1153         public override bool CanRead {
1154             [Pure]
1155             get { return _canRead; }
1156         }
1157
1158         public override bool CanWrite {
1159             [Pure]
1160             get { return _canWrite; }
1161         }
1162
1163         public override bool CanSeek {
1164             [Pure]
1165             get { return _canSeek; }
1166         }
1167
1168         public virtual bool IsAsync {
1169             get { return _isAsync; }
1170         }
1171
1172         public override long Length {
1173             [System.Security.SecuritySafeCritical]  // auto-generated
1174             get {
1175                 if (_handle.IsClosed) __Error.FileNotOpen();
1176                 if (!CanSeek) __Error.SeekNotSupported();
1177                 int hi = 0, lo = 0;
1178
1179                 lo = Win32Native.GetFileSize(_handle, out hi);
1180
1181                 if (lo==-1) {  // Check for either an error or a 4GB - 1 byte file.
1182                     int hr = Marshal.GetLastWin32Error();
1183                     if (hr != 0)
1184                         __Error.WinIOError(hr, String.Empty);
1185                 }
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;
1192                 return len;
1193             }
1194         }
1195
1196         public String Name {
1197                 [System.Security.SecuritySafeCritical]
1198             get {
1199                 if (_fileName == null)
1200                     return Environment.GetResourceString("IO_UnknownFileName");
1201 #if FEATURE_CORECLR
1202                 FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, _fileName);
1203                 sourceState.EnsureState();
1204 #else
1205                 new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { _fileName }, false, false).Demand();
1206 #endif
1207                 return _fileName;
1208             }
1209         }
1210
1211         internal String NameInternal {
1212             get {
1213                 if (_fileName == null)
1214                     return "<UnknownFileName>";
1215                 return _fileName;
1216             }
1217         }
1218
1219         public override long Position {
1220             [System.Security.SecuritySafeCritical]  // auto-generated
1221             get {
1222                 if (_handle.IsClosed) __Error.FileNotOpen();
1223                 if (!CanSeek) __Error.SeekNotSupported();
1224
1225                 Contract.Assert((_readPos == 0 && _readLen == 0 && _writePos >= 0) || (_writePos == 0 && _readPos <= _readLen), "We're either reading or writing, but not both.");
1226
1227                 // Verify that internal position is in [....] with the handle
1228                 if (_exposedHandle)
1229                     VerifyOSHandlePosition();
1230
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  
1233                 // buffered data
1234                 return _pos + (_readPos - _readLen + _writePos);
1235             }
1236             set {
1237                 if (value < 0) throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
1238                 Contract.EndContractBlock();
1239                 if (_writePos > 0) FlushWrite(false);
1240                 _readPos = 0;
1241                 _readLen = 0;
1242                 Seek(value, SeekOrigin.Begin);
1243             }
1244         }
1245
1246 #if FEATURE_MACL
1247         [System.Security.SecuritySafeCritical]  // auto-generated
1248         [ResourceExposure(ResourceScope.Machine)]
1249         [ResourceConsumption(ResourceScope.Machine)]
1250         public FileSecurity GetAccessControl()
1251         {
1252             if (_handle.IsClosed) __Error.FileNotOpen();
1253             return new FileSecurity(_handle, _fileName, AccessControlSections.Access | AccessControlSections.Owner | AccessControlSections.Group);
1254         }
1255
1256         [System.Security.SecuritySafeCritical]  // auto-generated
1257         public void SetAccessControl(FileSecurity fileSecurity)
1258         {
1259             if (fileSecurity == null)
1260                 throw new ArgumentNullException("fileSecurity");
1261             Contract.EndContractBlock();
1262
1263             if (_handle.IsClosed) __Error.FileNotOpen();
1264
1265             fileSecurity.Persist(_handle, _fileName);
1266         }
1267 #endif
1268
1269         [System.Security.SecuritySafeCritical]  // auto-generated
1270         protected override void Dispose(bool disposing)
1271         {
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 
1277             // finalized.
1278             try {
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);
1287                     }
1288                 }
1289             }
1290             finally {
1291                 if (_handle != null && !_handle.IsClosed)
1292                     _handle.Dispose();
1293                 
1294                 _canRead = false;
1295                 _canWrite = false;
1296                 _canSeek = false;
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).
1300                 //_buffer = null;
1301                 base.Dispose(disposing);
1302             }
1303         }
1304
1305         [System.Security.SecuritySafeCritical]  // auto-generated
1306         ~FileStream()
1307         {
1308             if (_handle != null) {
1309                 BCLDebug.Correctness(_handle.IsClosed, "You didn't close a FileStream & it got finalized.  Name: \""+_fileName+"\"");
1310                 Dispose(false);
1311             }
1312         }
1313
1314         public override void Flush()
1315         {
1316             Flush(false);
1317         }
1318
1319         [System.Security.SecuritySafeCritical]
1320         public virtual void Flush(Boolean flushToDisk)
1321         {
1322             // This code is duplicated in Dispose
1323             if (_handle.IsClosed) __Error.FileNotOpen();
1324
1325             FlushInternalBuffer();
1326
1327             if (flushToDisk && CanWrite)
1328             {
1329                 FlushOSBuffer();
1330             }
1331         }
1332
1333         private void FlushInternalBuffer()
1334         {
1335             if (_writePos > 0)
1336             {
1337                 FlushWrite(false);
1338             }
1339             else if (_readPos < _readLen && CanSeek)
1340             {
1341                 FlushRead();
1342             }
1343         }
1344
1345         [System.Security.SecuritySafeCritical]
1346         private void FlushOSBuffer()
1347         {
1348             if (!Win32Native.FlushFileBuffers(_handle))
1349             {
1350                 __Error.WinIOError();
1351             }
1352         }
1353
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);
1363             }
1364             _readPos = 0;
1365             _readLen = 0;
1366         }
1367
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!");
1373
1374 #if FEATURE_ASYNC_IO
1375             if (_isAsync) {
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);
1392             }
1393             else
1394 #endif // FEATURE_ASYNC_IO
1395                 WriteCore(_buffer, 0, _writePos);
1396
1397             _writePos = 0;
1398         }
1399
1400
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)]
1406 #endif
1407             [ResourceExposure(ResourceScope.Machine)]
1408             [ResourceConsumption(ResourceScope.Machine)]
1409             get { 
1410                 Flush();
1411                 // Explicitly dump any buffered data, since the user could move our
1412                 // position or write to the file.
1413                 _readPos = 0;
1414                 _readLen = 0;
1415                 _writePos = 0;
1416                 _exposedHandle = true;
1417
1418                 return _handle.DangerousGetHandle();
1419             }
1420         }
1421
1422         public virtual SafeFileHandle SafeFileHandle {
1423             [System.Security.SecurityCritical]  // auto-generated_required
1424 #if !FEATURE_CORECLR
1425             [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
1426 #endif
1427             get { 
1428                 Flush();
1429                 // Explicitly dump any buffered data, since the user could move our
1430                 // position or write to the file.
1431                 _readPos = 0;
1432                 _readLen = 0;
1433                 _writePos = 0;
1434                 _exposedHandle = true;
1435
1436                 return _handle;
1437             }
1438         }
1439
1440         [System.Security.SecuritySafeCritical]  // auto-generated
1441         public override void SetLength(long value)
1442         {
1443             if (value < 0)
1444                 throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
1445             Contract.EndContractBlock();
1446
1447             if (_handle.IsClosed) __Error.FileNotOpen();
1448             if (!CanSeek) __Error.SeekNotSupported();
1449             if (!CanWrite) __Error.WriteNotSupported();
1450
1451             // Handle buffering updates.
1452             if (_writePos > 0) {
1453                 FlushWrite(false);
1454             }
1455             else if (_readPos < _readLen) {
1456                 FlushRead();
1457             }
1458             _readPos = 0;
1459             _readLen = 0;
1460
1461             if (_appendStart != -1 && value < _appendStart)
1462                 throw new IOException(Environment.GetResourceString("IO.IO_SetLengthAppendTruncate"));
1463             SetLengthCore(value);
1464         }
1465
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
1468         // FlushWrite.
1469         [System.Security.SecuritySafeCritical]  // auto-generated
1470         private void SetLengthCore(long value)
1471         {
1472             Contract.Assert(value >= 0, "value >= 0");
1473             long origPos = _pos;
1474
1475             if (_exposedHandle)
1476                 VerifyOSHandlePosition();
1477             if (_pos != value)
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);
1484             }
1485             // Return file pointer to where it was before setting length
1486             if (origPos != value) {
1487                 if (origPos < value)
1488                     SeekCore(origPos, SeekOrigin.Begin);
1489                 else
1490                     SeekCore(0, SeekOrigin.End);
1491             }
1492         }
1493
1494         [System.Security.SecuritySafeCritical]  // auto-generated
1495         public override int Read([In, Out] byte[] array, int offset, int count) {
1496             if (array==null)
1497                 throw new ArgumentNullException("array", Environment.GetResourceString("ArgumentNull_Buffer"));
1498             if (offset < 0)
1499                 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
1500             if (count < 0)
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();
1505             
1506             if (_handle.IsClosed) __Error.FileNotOpen();
1507             
1508             Contract.Assert((_readPos==0 && _readLen==0 && _writePos >= 0) || (_writePos==0 && _readPos <= _readLen), "We're either reading or writing, but not both.");
1509
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.
1514             if (n == 0) {
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.
1520                     _readPos = 0;
1521                     _readLen = 0;
1522                     return n;
1523                 }
1524                 if (_buffer == null) _buffer = new byte[_bufferSize];
1525                 n = ReadCore(_buffer, 0, _bufferSize);
1526                 if (n == 0) return 0;
1527                 isBlocked = n < _bufferSize;
1528                 _readPos = 0;
1529                 _readLen = n;
1530             }
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);
1534             _readPos += n;
1535
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.         -- 
1544
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.
1547             if (!_isPipe) {
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);
1555                     n += moreBytesRead;
1556                     // We've just made our buffer inconsistent with our position 
1557                     // pointer.  We must throw away the read buffer.
1558                     _readPos = 0;
1559                     _readLen = 0;
1560                 }
1561             }
1562
1563             return n;
1564         }
1565
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");
1570
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
1576             if (_isAsync) {
1577                 IAsyncResult result = BeginReadCore(buffer, offset, count, null, null, 0);
1578                 return EndRead(result);
1579             }
1580 #endif //FEATURE_ASYNC_IO
1581
1582             // Make sure we are reading from the right spot
1583             if (_exposedHandle)
1584                 VerifyOSHandlePosition();
1585
1586             int hr = 0;
1587             int r = ReadFileNative(_handle, buffer, offset, count, null, out hr);
1588             if (r == -1) {
1589                 // For pipes, ERROR_BROKEN_PIPE is the normal end of the pipe.
1590                 if (hr == ERROR_BROKEN_PIPE) {
1591                     r = 0;
1592                 }
1593                 else {
1594                     if (hr == ERROR_INVALID_PARAMETER)
1595                         throw new ArgumentException(Environment.GetResourceString("Arg_HandleNotSync"));
1596                     
1597                     __Error.WinIOError(hr, String.Empty);
1598                 }
1599             }
1600             Contract.Assert(r >= 0, "FileStream's ReadCore is likely broken.");
1601             _pos += r;
1602
1603             return r;
1604         }
1605
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();
1613
1614             Contract.Assert((_readPos==0 && _readLen==0 && _writePos >= 0) || (_writePos==0 && _readPos <= _readLen), "We're either reading or writing, but not both.");
1615
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) {
1622                 FlushWrite(false);
1623             }
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);
1629             }
1630
1631             // Verify that internal position is in [....] with the handle
1632             if (_exposedHandle)
1633                 VerifyOSHandlePosition();
1634
1635             long oldPos = _pos + (_readPos - _readLen);
1636             long pos = SeekCore(offset, origin);
1637
1638             // Prevent users from overwriting data in a file that was opened in
1639             // append mode.
1640             if (_appendStart != -1 && pos < _appendStart) {
1641                 SeekCore(oldPos, SeekOrigin.Begin);
1642                 throw new IOException(Environment.GetResourceString("IO.IO_SeekAppendOverwrite"));
1643             }
1644
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.
1649             if (_readLen > 0) {
1650                 // We can optimize the following condition:
1651                 // oldPos - _readPos <= pos < oldPos + _readLen - _readPos
1652                 if (oldPos == pos) {
1653                     if (_readPos > 0) {
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;
1657                         _readPos = 0;
1658                     }
1659                     // If we still have buffered data, we must update the stream's 
1660                     // position so our Position property is correct.
1661                     if (_readLen > 0)
1662                         SeekCore(_readLen, SeekOrigin.Current);
1663                 }
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);
1669                     _readPos = 0;
1670                     if (_readLen > 0)
1671                         SeekCore(_readLen, SeekOrigin.Current);
1672                 }
1673                 else {
1674                     // Lose the read buffer.
1675                     _readPos = 0;
1676                     _readLen = 0;
1677                 }
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.");
1680             }
1681             return pos;
1682         }
1683
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");
1691             int hr = 0;
1692             long ret = 0;
1693             
1694             ret = Win32Native.SetFilePointer(_handle, offset, origin, out hr);
1695             if (ret == -1) {
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.
1699                 // 
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 
1703                 // scenarios.
1704                 // 
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 
1709                 // operations.
1710                 //
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)
1715                     _handle.Dispose();
1716                 __Error.WinIOError(hr, String.Empty);
1717             }
1718             
1719             _pos = ret;
1720             return ret;
1721         }
1722
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()
1727         {
1728             if (!CanSeek)
1729                 return;
1730
1731             // SeekCore will override the current _pos, so save it now
1732             long oldPos = _pos;
1733             long curPos = SeekCore(0, SeekOrigin.Current);
1734             
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 
1738                 _readPos = 0;  
1739                 _readLen = 0;
1740                 if(_writePos > 0) {
1741                     // Discard the buffer and let the user know!
1742                     _writePos = 0;
1743                     throw new IOException(Environment.GetResourceString("IO.IO_FileStreamHandlePosition"));
1744                 }
1745             }
1746         }
1747
1748         [System.Security.SecuritySafeCritical]  // auto-generated
1749         public override void Write(byte[] array, int offset, int count) {
1750             if (array==null)
1751                 throw new ArgumentNullException("array", Environment.GetResourceString("ArgumentNull_Buffer"));
1752             if (offset < 0)
1753                 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
1754             if (count < 0)
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();
1759
1760             if (_handle.IsClosed) __Error.FileNotOpen();
1761
1762             if (_writePos == 0)
1763             {
1764                 // Ensure we can write to the stream, and ready buffer for writing.
1765                 if (!CanWrite) __Error.WriteNotSupported();
1766                 if (_readPos < _readLen) FlushRead();
1767                 _readPos = 0;
1768                 _readLen = 0;
1769             }
1770
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 
1778             // size repeatedly)
1779             if (_writePos > 0) {
1780                 int numBytes = _bufferSize - _writePos;   // space left in buffer
1781                 if (numBytes > 0) {
1782                     if (numBytes > count)
1783                         numBytes = count;
1784                     Buffer.InternalBlockCopy(array, offset, _buffer, _writePos, numBytes);
1785                     _writePos += numBytes;
1786                     if (count==numBytes) return;
1787                     offset += numBytes;
1788                     count -= numBytes;
1789                 }
1790                 // Reset our buffer.  We essentially want to call FlushWrite
1791                 // without calling Flush on the underlying Stream.
1792 #if FEATURE_ASYNC_IO
1793
1794                 if (_isAsync) {
1795                     IAsyncResult result = BeginWriteCore(_buffer, 0, _writePos, null, null);
1796                     EndWrite(result);
1797                 }
1798                 else
1799                 {
1800                     WriteCore(_buffer, 0, _writePos);
1801                 }
1802 #else
1803                 WriteCore(_buffer, 0, _writePos);
1804 #endif // FEATURE_ASYNC_IO
1805                 _writePos = 0;
1806             }
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);
1811                 return;
1812             }
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);
1818             _writePos = count;
1819             return;
1820         }
1821
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");
1826
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
1832             if (_isAsync) {
1833                 IAsyncResult result = BeginWriteCore(buffer, offset, count, null, null);
1834                 EndWrite(result);
1835                 return;
1836             }
1837 #endif //FEATURE_ASYNC_IO
1838
1839             // Make sure we are writing to the position that we think we are
1840             if (_exposedHandle)
1841                 VerifyOSHandlePosition();
1842             
1843             int hr = 0;
1844             int r = WriteFileNative(_handle, buffer, offset, count, null, out hr);
1845             if (r == -1) {
1846                 // For pipes, ERROR_NO_DATA is not an error, but the pipe is closing.
1847                 if (hr == ERROR_NO_DATA) {
1848                     r = 0;
1849                 }
1850                 else {
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 
1854                     // asynchronously.
1855                     if (hr == ERROR_INVALID_PARAMETER)
1856                         throw new IOException(Environment.GetResourceString("IO.IO_FileTooLongOrHandleNotSync"));
1857                     __Error.WinIOError(hr, String.Empty);
1858                 }
1859             }
1860             Contract.Assert(r >= 0, "FileStream's WriteCore is likely broken.");
1861             _pos += r;
1862             return;
1863         }
1864
1865
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)
1869         {
1870             if (array==null)
1871                 throw new ArgumentNullException("array");
1872             if (offset < 0)
1873                 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
1874             if (numBytes < 0)
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();
1879
1880             if (_handle.IsClosed) __Error.FileNotOpen();
1881
1882 #if FEATURE_ASYNC_IO
1883             if (!_isAsync)
1884                 return base.BeginRead(array, offset, numBytes, userCallback, stateObject);
1885             else
1886                 return BeginReadAsync(array, offset, numBytes, userCallback, stateObject);
1887 #else
1888             return base.BeginRead(array, offset, numBytes, userCallback, stateObject);
1889 #endif // FEATURE_ASYNC_IO
1890         }
1891
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)
1896         {
1897             Contract.Assert(_isAsync);
1898
1899             if (!CanRead) __Error.ReadNotSupported();
1900
1901             Contract.Assert((_readPos == 0 && _readLen == 0 && _writePos >= 0) || (_writePos == 0 && _readPos <= _readLen), "We're either reading or writing, but not both.");
1902
1903             if (_isPipe)
1904             {
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)
1919                 {
1920                     int n = _readLen - _readPos;
1921                     if (n > numBytes) n = numBytes;
1922                     Buffer.InternalBlockCopy(_buffer, _readPos, array, offset, n);
1923                     _readPos += n;
1924
1925                     // Return a synchronous FileStreamAsyncResult
1926                     return FileStreamAsyncResult.CreateBufferedReadResult(n, userCallback, stateObject, false);
1927                 }
1928                 else
1929                 {
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);
1932                 }
1933             }
1934
1935             Contract.Assert(!_isPipe, "Should not be a pipe.");
1936
1937             // Handle buffering.
1938             if (_writePos > 0) FlushWrite(false);
1939             if (_readPos == _readLen)
1940             {
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...       -- 
1951
1952                 if (numBytes < _bufferSize)
1953                 {
1954                     if (_buffer == null) _buffer = new byte[_bufferSize];
1955                     IAsyncResult bufferRead = BeginReadCore(_buffer, 0, _bufferSize, null, null, 0);
1956                     _readLen = EndRead(bufferRead);
1957                     int n = _readLen;
1958                     if (n > numBytes) n = numBytes;
1959                     Buffer.InternalBlockCopy(_buffer, 0, array, offset, n);
1960                     _readPos = n;
1961
1962                     // Return a synchronous FileStreamAsyncResult
1963                     return FileStreamAsyncResult.CreateBufferedReadResult(n, userCallback, stateObject, false);
1964                 }
1965                 else
1966                 {
1967                     // Here we're making our position pointer inconsistent
1968                     // with our read buffer.  Throw away the read buffer's contents.
1969                     _readPos = 0;
1970                     _readLen = 0;
1971                     return BeginReadCore(array, offset, numBytes, userCallback, stateObject, 0);
1972                 }
1973             }
1974             else
1975             {
1976                 int n = _readLen - _readPos;
1977                 if (n > numBytes) n = numBytes;
1978                 Buffer.InternalBlockCopy(_buffer, _readPos, array, offset, n);
1979                 _readPos += n;
1980
1981                 if (n >= numBytes)
1982                 {
1983                     // Return a synchronous FileStreamAsyncResult
1984                     return FileStreamAsyncResult.CreateBufferedReadResult(n, userCallback, stateObject, false);
1985                 }
1986                 else
1987                 {
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.
1993                     _readPos = 0;
1994                     _readLen = 0;
1995                     return BeginReadCore(array, offset + n, numBytes - n, userCallback, stateObject, n);
1996                 }
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.
2000             }
2001         }
2002 #endif // FEATURE_ASYNC_IO
2003
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)
2009         {
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");
2017
2018             // Create and store async stream class library specific data in the async result
2019
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;
2026
2027             // Calculate position in the file we should be at after the read is done
2028             if (CanSeek) {
2029                 long len = Length;
2030                 
2031                 // Make sure we are reading from the position that we think we are
2032                 if (_exposedHandle)
2033                     VerifyOSHandlePosition();
2034                 
2035                 if (_pos + numBytes > len) {
2036                     if (_pos <= len)
2037                         numBytes = (int) (len - _pos);
2038                     else
2039                         numBytes = 0;
2040                 }
2041
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);
2046
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.
2050
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);
2057             }
2058
2059             if (FrameworkEventSource.IsInitialized && FrameworkEventSource.Log.IsEnabled(EventLevel.Informational, FrameworkEventSource.Keywords.ThreadTransfer))
2060                 FrameworkEventSource.Log.ThreadTransferSend((long)(asyncResult.OverLapped), 2, string.Empty, false);
2061
2062             // queue an async ReadFile operation and pass in a packed overlapped
2063             int hr = 0;
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
2067             // the following:
2068             // On error, r==-1.
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) {
2076                 
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.
2081
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.
2087                 }
2088                 else if (hr != ERROR_IO_PENDING) {
2089                     if (!_handle.IsClosed && CanSeek)  // Update Position - It could be anywhere.
2090                         SeekCore(0, SeekOrigin.Current);
2091
2092                     if (hr == ERROR_HANDLE_EOF)
2093                         __Error.EndOfFile();
2094                     else
2095                         __Error.WinIOError(hr, String.Empty);
2096                 }
2097             }
2098             else {
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
2105                 // results.  
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");
2107             }
2108
2109             return asyncResult;
2110         }
2111 #endif //FEATURE_ASYNC_IO
2112
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)
2115         {
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();
2123
2124 #if FEATURE_ASYNC_IO
2125             if (!_isAsync)
2126                 return base.EndRead(asyncResult);
2127
2128             FileStreamAsyncResult afsar = asyncResult as FileStreamAsyncResult;
2129             if (afsar==null || afsar.IsWrite)
2130                 __Error.WrongAsyncResult();
2131
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();
2137
2138             // Obtain the WaitHandle, but don't use public property in case we
2139             // delay initialize the manual reset event in the future.
2140             afsar.Wait();
2141
2142             // Free memory & GC handles.
2143             afsar.ReleaseNativeResource();
2144
2145             // Now check for any error during the read.
2146             if (afsar.ErrorCode != 0)
2147                 __Error.WinIOError(afsar.ErrorCode, String.Empty);
2148
2149             return afsar.NumBytesRead;
2150 #else
2151             return base.EndRead(asyncResult);
2152 #endif // FEATURE_ASYNC_IO
2153         }
2154
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);
2167                 _readPos = 0;
2168             }
2169             if (_readPos == _readLen)
2170                 return -1;
2171
2172             int result = _buffer[_readPos];
2173             _readPos++;
2174             return result;
2175         }
2176
2177
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)
2181         {
2182             if (array==null)
2183                 throw new ArgumentNullException("array");
2184             if (offset < 0)
2185                 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
2186             if (numBytes < 0)
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();
2191
2192             if (_handle.IsClosed) __Error.FileNotOpen();
2193
2194 #if FEATURE_ASYNC_IO
2195             if (!_isAsync)
2196                 return base.BeginWrite(array, offset, numBytes, userCallback, stateObject);
2197             else
2198                 return BeginWriteAsync(array, offset, numBytes, userCallback, stateObject);
2199 #else
2200             return base.BeginWrite(array, offset, numBytes, userCallback, stateObject);
2201 #endif // FEATURE_ASYNC_IO
2202         }
2203
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)
2208         {
2209             Contract.Assert(_isAsync);
2210
2211             if (!CanWrite) __Error.WriteNotSupported();
2212
2213             Contract.Assert((_readPos == 0 && _readLen == 0 && _writePos >= 0) || (_writePos == 0 && _readPos <= _readLen), "We're either reading or writing, but not both.");
2214
2215             if (_isPipe)
2216             {
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
2229                 // pipes.   
2230                 Contract.Assert(_readPos == 0 && _readLen == 0, "FileStream must not have buffered data here!  Pipes should be unidirectional.");
2231
2232                 if (_writePos > 0)
2233                     FlushWrite(false);
2234
2235                 return BeginWriteCore(array, offset, numBytes, userCallback, stateObject);
2236             }
2237
2238             // Handle buffering.
2239             if (_writePos == 0)
2240             {
2241                 if (_readPos < _readLen) FlushRead();
2242                 _readPos = 0;
2243                 _readLen = 0;
2244             }
2245
2246             int n = _bufferSize - _writePos;
2247             if (numBytes <= n)
2248             {
2249                 if (_writePos == 0) _buffer = new byte[_bufferSize];
2250                 Buffer.InternalBlockCopy(array, offset, _buffer, _writePos, numBytes);
2251                 _writePos += numBytes;
2252
2253                 // Return a synchronous FileStreamAsyncResult
2254                 return FileStreamAsyncResult.CreateBufferedReadResult(numBytes, userCallback, stateObject, true);
2255             }
2256
2257             if (_writePos > 0)
2258                 FlushWrite(false);
2259
2260             return BeginWriteCore(array, offset, numBytes, userCallback, stateObject);
2261         }
2262 #endif // FEATURE_ASYNC_IO
2263
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) 
2269         {
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");
2277
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;
2281
2282             if (CanSeek) {
2283                 // Make sure we set the length of the file appropriately.
2284                 long len = Length;
2285                 //Console.WriteLine("BeginWrite - Calculating end pos.  pos: "+pos+"  len: "+len+"  numBytes: "+numBytes);
2286                 
2287                 // Make sure we are writing to the position that we think we are
2288                 if (_exposedHandle)
2289                     VerifyOSHandlePosition();
2290                 
2291                 if (_pos + numBytes > len) {
2292                     //Console.WriteLine("BeginWrite - Setting length to: "+(pos + numBytes));
2293                     SetLengthCore(_pos + numBytes);
2294                 }
2295
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);
2300                 
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.
2304
2305                 // 
2306
2307
2308
2309
2310
2311
2312                 
2313                 SeekCore(numBytes, SeekOrigin.Current);
2314             }
2315
2316             //Console.WriteLine("BeginWrite finishing.  pos: "+pos+"  numBytes: "+numBytes+"  _pos: "+_pos+"  Position: "+Position);
2317
2318             if (FrameworkEventSource.IsInitialized && FrameworkEventSource.Log.IsEnabled(EventLevel.Informational, FrameworkEventSource.Keywords.ThreadTransfer))
2319                 FrameworkEventSource.Log.ThreadTransferSend((long)(asyncResult.OverLapped), 2, string.Empty, false);
2320
2321             int hr = 0;
2322             // queue an async WriteFile operation and pass in a packed overlapped
2323             int r = WriteFileNative(_handle, bytes, offset, numBytes, intOverlapped, out hr);
2324
2325             // WriteFile, the OS version, will return 0 on failure.  But
2326             // my WriteFileNative wrapper returns -1.  My wrapper will return
2327             // the following:
2328             // On error, r==-1.
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);
2337                 
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.
2344                 }
2345                 else if (hr != ERROR_IO_PENDING) {
2346                     if (!_handle.IsClosed && CanSeek)  // Update Position - It could be anywhere.
2347                         SeekCore(0, SeekOrigin.Current);
2348
2349                     if (hr == ERROR_HANDLE_EOF)
2350                         __Error.EndOfFile();
2351                     else
2352                         __Error.WinIOError(hr, String.Empty);
2353                 }
2354             }
2355             else {
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
2362                 // results.  
2363                 //Console.WriteLine("WriteFile returned: "+r+" (0x"+Int32.Format(r, "x")+")  The IO completed synchronously, but the user callback was called on another thread.");
2364             }
2365             
2366             return asyncResult;
2367         }
2368 #endif //FEATURE_ASYNC_IO
2369
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)
2372         {
2373             if (asyncResult==null)
2374                 throw new ArgumentNullException("asyncResult");
2375             Contract.EndContractBlock();
2376
2377 #if FEATURE_ASYNC_IO
2378             if (!_isAsync) {
2379                 base.EndWrite(asyncResult);
2380                 return;
2381             }
2382
2383             FileStreamAsyncResult afsar = asyncResult as FileStreamAsyncResult;
2384             if (afsar==null || !afsar.IsWrite)
2385                 __Error.WrongAsyncResult();
2386
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();
2392
2393             // Obtain the WaitHandle, but don't use public property in case we
2394             // delay initialize the manual reset event in the future.
2395             afsar.Wait();
2396
2397             // Free memory & GC handles.
2398             afsar.ReleaseNativeResource();
2399
2400             // Now check for any error during the write.
2401             if (afsar.ErrorCode != 0)
2402                 __Error.WinIOError(afsar.ErrorCode, String.Empty);
2403
2404             // Number of bytes written is afsar._numBytes + afsar._numBufferedBytes.
2405             return;
2406 #else
2407             base.EndWrite(asyncResult);
2408 #endif // FEATURE_ASYNC_IO
2409         }
2410
2411         [System.Security.SecuritySafeCritical]  // auto-generated
2412         public override void WriteByte(byte value)
2413         {
2414             if (_handle.IsClosed) __Error.FileNotOpen();
2415             if (_writePos==0) {
2416                 if (!CanWrite) __Error.WriteNotSupported();
2417                 if (_readPos < _readLen) FlushRead();
2418                 _readPos = 0;
2419                 _readLen = 0;
2420                 Contract.Assert(_bufferSize > 0, "_bufferSize > 0");
2421                 if (_buffer==null) _buffer = new byte[_bufferSize];
2422             }
2423             if (_writePos == _bufferSize)
2424                 FlushWrite(false);
2425
2426             _buffer[_writePos] = value;
2427             _writePos++;
2428         }
2429
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();
2436
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));
2441             
2442             if (!Win32Native.LockFile(_handle, positionLow, positionHigh, lengthLow, lengthHigh))
2443                 __Error.WinIOError();
2444         }
2445
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();
2452
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));
2457
2458             if (!Win32Native.UnlockFile(_handle, positionLow, positionHigh, lengthLow, lengthHigh))
2459                 __Error.WinIOError();
2460         }
2461
2462         // Windows API definitions, from winbase.h and others
2463         
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;
2469     
2470         private const int FILE_BEGIN = 0;
2471         private const int FILE_CURRENT = 1;
2472         private const int FILE_END = 2;
2473
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;
2480
2481
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)
2485         {
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();
2495
2496             Contract.Assert((_isAsync && overlapped != null) || (!_isAsync && overlapped == null), "Async IO parameter ----up in call to ReadFileNative.");
2497
2498             // You can't use the fixed statement on an array of length 0.
2499             if (bytes.Length==0) {
2500                 hr = 0;
2501                 return 0;
2502             }
2503
2504             int r = 0;
2505             int numBytesRead = 0;
2506
2507             fixed(byte* p = bytes) {
2508                 if (_isAsync)
2509                     r = Win32Native.ReadFile(handle, p + offset, count, IntPtr.Zero, overlapped);
2510                 else
2511                     r = Win32Native.ReadFile(handle, p + offset, count, out numBytesRead, IntPtr.Zero);
2512             }
2513
2514             if (r==0) {
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.
2525                     return -1;
2526                 }
2527
2528                 // See code:#errorInvalidHandle in "private long SeekCore(long offset, SeekOrigin origin)".
2529                 if (hr == Win32Native.ERROR_INVALID_HANDLE)
2530                     _handle.Dispose();
2531
2532                 return -1;
2533             }
2534             else
2535                 hr = 0;
2536             return numBytesRead;
2537         }
2538
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();
2552
2553             Contract.Assert((_isAsync && overlapped != null) || (!_isAsync && overlapped == null), "Async IO parameter ----up in call to WriteFileNative.");
2554
2555             // You can't use the fixed statement on an array of length 0.
2556             if (bytes.Length==0) {
2557                 hr = 0;
2558                 return 0;
2559             }
2560
2561             int numBytesWritten = 0;
2562             int r = 0;
2563             
2564             fixed(byte* p = bytes) {
2565                 if (_isAsync)
2566                     r = Win32Native.WriteFile(handle, p + offset, count, IntPtr.Zero, overlapped);
2567                 else
2568                     r = Win32Native.WriteFile(handle, p + offset, count, out numBytesWritten, IntPtr.Zero);
2569             }
2570
2571             if (r==0) {
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.  
2577
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.
2582                     return -1;
2583                 }
2584                 
2585                 // See code:#errorInvalidHandle in "private long SeekCore(long offset, SeekOrigin origin)".
2586                 if (hr == Win32Native.ERROR_INVALID_HANDLE)
2587                     _handle.Dispose();
2588
2589                 return -1;
2590             }
2591             else
2592                 hr = 0;
2593             return numBytesWritten;          
2594         }
2595
2596
2597 #if FEATURE_ASYNC_IO
2598         [HostProtection(ExternalThreading = true)]
2599         [ComVisible(false)]
2600         [SecuritySafeCritical]
2601         public override Task<int> ReadAsync(Byte[] buffer, int offset, int count, CancellationToken cancellationToken)
2602         {
2603             if (buffer == null)
2604                 throw new ArgumentNullException("buffer");
2605             if (offset < 0)
2606                 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
2607             if (count < 0)
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();
2612
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);
2619
2620             if (cancellationToken.IsCancellationRequested)
2621                 return Task.FromCancellation<int>(cancellationToken);
2622
2623             if (_handle.IsClosed)
2624                 __Error.FileNotOpen();
2625
2626             // If async IO is not supported on this platform or 
2627             // if this FileStream was not opened with FileOptions.Asynchronous.
2628             if (!_isAsync)
2629                 return base.ReadAsync(buffer, offset, count, cancellationToken);
2630
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);
2635
2636             if (readTask._asyncResult.IsAsync && cancellationToken.CanBeCanceled)
2637             {
2638                 var cancelReadHandler = s_cancelReadHandler;
2639                 if (cancelReadHandler == null) s_cancelReadHandler = cancelReadHandler = CancelTask<int>; // benign initialization ----
2640                 readTask._registration = cancellationToken.Register(cancelReadHandler,  readTask);
2641
2642                 // In case the task is completed right before we register the cancellation callback.
2643                 if (readTask._asyncResult.IsCompleted)
2644                     readTask._registration.Dispose();
2645             }
2646
2647             return readTask;
2648         }
2649
2650         [HostProtection(ExternalThreading = true)]
2651         [ComVisible(false)]
2652         [SecuritySafeCritical]
2653         public override Task WriteAsync(Byte[] buffer, int offset, int count, CancellationToken cancellationToken)
2654         {
2655             if (buffer == null)
2656                 throw new ArgumentNullException("buffer");
2657             if (offset < 0)
2658                 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
2659             if (count < 0)
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();
2664
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);
2671
2672             if (cancellationToken.IsCancellationRequested)
2673                 return Task.FromCancellation(cancellationToken);
2674
2675             if (_handle.IsClosed)
2676                 __Error.FileNotOpen();
2677
2678             // If async IO is not supported on this platform or 
2679             // if this FileStream was not opened with FileOptions.Asynchronous.
2680             if (!_isAsync)
2681                 return base.WriteAsync(buffer, offset, count, cancellationToken);
2682
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);
2687
2688             if (writeTask._asyncResult.IsAsync && cancellationToken.CanBeCanceled)
2689             {
2690                 var cancelWriteHandler = s_cancelWriteHandler;
2691                 if (cancelWriteHandler == null) s_cancelWriteHandler = cancelWriteHandler = CancelTask<VoidTaskResult>; // benign initialization ----
2692                 writeTask._registration = cancellationToken.Register(cancelWriteHandler, writeTask);
2693
2694                 // In case the task is completed right before we register the cancellation callback.
2695                 if (writeTask._asyncResult.IsCompleted)
2696                     writeTask._registration.Dispose();
2697             }
2698
2699             return writeTask;
2700         }
2701
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>
2705         {
2706             internal CancellationToken _cancellationToken;
2707             internal CancellationTokenRegistration _registration;
2708             internal FileStreamAsyncResult _asyncResult; // initialized after Begin call completes
2709
2710             internal FileStreamReadWriteTask(CancellationToken cancellationToken) : base()
2711             {
2712                 _cancellationToken = cancellationToken;
2713             }
2714         }
2715
2716         // Cancellation callback for both ReadAsync and WriteAsync.
2717         [SecuritySafeCritical]
2718         private static void CancelTask<T>(object state)
2719         {
2720             var task = state as FileStreamReadWriteTask<T>;
2721             Contract.Assert(task != null);
2722             FileStreamAsyncResult asyncResult = task._asyncResult;
2723
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);
2734
2735             try
2736             {
2737                 // Cancel the overlapped read and set the task to cancelled state.
2738                 if (!asyncResult.IsCompleted)
2739                     asyncResult.Cancel();
2740             }
2741             catch (Exception ex)
2742             {
2743                 task.TrySetException(ex);
2744             }
2745         }
2746
2747         // Completion callback for ReadAsync
2748         [SecuritySafeCritical]
2749         private static void EndReadTask(IAsyncResult iar)
2750         {
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?");
2754
2755             var readTask = asyncResult.AsyncState as FileStreamReadWriteTask<int>;
2756             Contract.Assert(readTask != null);
2757
2758             try
2759             {
2760                 if (asyncResult.IsAsync)
2761                 {
2762                     asyncResult.ReleaseNativeResource();
2763
2764                     // release the resource held by CancellationTokenRegistration
2765                     readTask._registration.Dispose();
2766                 }
2767
2768                 if (asyncResult.ErrorCode == Win32Native.ERROR_OPERATION_ABORTED)
2769                 {
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);
2773                 }
2774                 else
2775                     readTask.TrySetResult(asyncResult.NumBytesRead);
2776             }
2777             catch (Exception ex)
2778             {
2779                 readTask.TrySetException(ex);
2780             }
2781         }
2782
2783         // Completion callback for WriteAsync
2784         [SecuritySafeCritical]
2785         private static void EndWriteTask(IAsyncResult iar)
2786         {   
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?");
2790
2791             var writeTask = iar.AsyncState as FileStreamReadWriteTask<VoidTaskResult>;
2792             Contract.Assert(writeTask != null);
2793
2794             try
2795             {
2796                 if (asyncResult.IsAsync)
2797                 {
2798                     asyncResult.ReleaseNativeResource();
2799
2800                     // release the resource held by CancellationTokenRegistration
2801                     writeTask._registration.Dispose();
2802                 }
2803
2804                 if (asyncResult.ErrorCode == Win32Native.ERROR_OPERATION_ABORTED)
2805                 {
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);
2809                 }
2810                 else
2811                     writeTask.TrySetResult(default(VoidTaskResult));
2812             }
2813             catch (Exception ex)
2814             {
2815                 writeTask.TrySetException(ex);
2816             }
2817         }
2818
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)]
2824         [ComVisible(false)]
2825         [System.Security.SecuritySafeCritical]
2826         public override Task FlushAsync(CancellationToken cancellationToken)
2827         {
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);
2834
2835             if (cancellationToken.IsCancellationRequested)
2836                 return Task.FromCancellation(cancellationToken);
2837
2838             if (_handle.IsClosed)
2839                 __Error.FileNotOpen();
2840
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.
2848             try
2849             {
2850                 FlushInternalBuffer();
2851             }
2852             catch (Exception e)
2853             {
2854                 return Task.FromException(e);
2855             }
2856
2857             if (CanWrite)
2858                 return Task.Factory.StartNew(
2859                     state => ((FileStream)state).FlushOSBuffer(),
2860                     this,
2861                     cancellationToken,
2862                     TaskCreationOptions.DenyChildAttach,
2863                     TaskScheduler.Default);
2864             else
2865                 return Task.CompletedTask;
2866         }
2867 #endif //FEATURE_ASYNC_IO
2868
2869     }
2870 }