2 // System.IO.FileStream.cs
5 // Dietmar Maurer (dietmar@ximian.com)
6 // Dan Lewis (dihlewis@yahoo.co.uk)
7 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 // (C) 2001-2003 Ximian, Inc. http://www.ximian.com
10 // Copyright (C) 2004-2005, 2008 Novell, Inc (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Collections;
33 using System.Globalization;
34 using System.Runtime.CompilerServices;
35 using System.Runtime.InteropServices;
36 using System.Runtime.Remoting.Messaging;
37 using System.Security.Permissions;
38 using System.Threading;
41 using Microsoft.Win32.SafeHandles;
42 using System.Security.AccessControl;
45 using System.IO.IsolatedStorage;
53 public class FileStream : Stream
55 // construct from handle
57 [Obsolete ("Use FileStream(SafeFileHandle handle, FileAccess access) instead")]
58 public FileStream (IntPtr handle, FileAccess access)
59 : this (handle, access, true, DefaultBufferSize, false) {}
61 [Obsolete ("Use FileStream(SafeFileHandle handle, FileAccess access) instead")]
62 public FileStream (IntPtr handle, FileAccess access, bool ownsHandle)
63 : this (handle, access, ownsHandle, DefaultBufferSize, false) {}
65 [Obsolete ("Use FileStream(SafeFileHandle handle, FileAccess access, int bufferSize) instead")]
66 public FileStream (IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize)
67 : this (handle, access, ownsHandle, bufferSize, false) {}
69 [Obsolete ("Use FileStream(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync) instead")]
70 public FileStream (IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize, bool isAsync)
71 : this (handle, access, ownsHandle, bufferSize, isAsync, false) {}
73 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
74 internal FileStream (IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize, bool isAsync, bool noBuffering)
76 this.handle = MonoIO.InvalidHandle;
77 if (handle == this.handle)
78 throw new ArgumentException ("handle", Locale.GetText ("Invalid."));
80 if (access < FileAccess.Read || access > FileAccess.ReadWrite)
81 throw new ArgumentOutOfRangeException ("access");
84 MonoFileType ftype = MonoIO.GetFileType (handle, out error);
86 if (error != MonoIOError.ERROR_SUCCESS) {
87 throw MonoIO.GetException (name, error);
90 if (ftype == MonoFileType.Unknown) {
91 throw new IOException ("Invalid handle.");
92 } else if (ftype == MonoFileType.Disk) {
100 this.owner = ownsHandle;
101 this.async = isAsync;
102 this.anonymous = false;
104 InitBuffer (bufferSize, noBuffering);
107 buf_start = MonoIO.Seek (handle, 0, SeekOrigin.Current, out error);
108 if (error != MonoIOError.ERROR_SUCCESS) {
109 throw MonoIO.GetException (name, error);
113 /* Can't set append mode */
114 this.append_startpos=0;
117 // construct from filename
119 public FileStream (string path, FileMode mode)
120 : this (path, mode, (mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite), FileShare.Read, DefaultBufferSize, false, FileOptions.None)
124 public FileStream (string path, FileMode mode, FileAccess access)
125 : this (path, mode, access, access == FileAccess.Write ? FileShare.None : FileShare.Read, DefaultBufferSize, false, false)
129 public FileStream (string path, FileMode mode, FileAccess access, FileShare share)
130 : this (path, mode, access, share, DefaultBufferSize, false, FileOptions.None)
134 public FileStream (string path, FileMode mode, FileAccess access, FileShare share, int bufferSize)
135 : this (path, mode, access, share, bufferSize, false, FileOptions.None)
139 public FileStream (string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool useAsync)
140 : this (path, mode, access, share, bufferSize, useAsync, FileOptions.None)
145 public FileStream (string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options)
146 : this (path, mode, access, share, bufferSize, false, options)
150 public FileStream (SafeFileHandle handle, FileAccess access)
151 :this(handle, access, DefaultBufferSize, false)
155 public FileStream (SafeFileHandle handle, FileAccess access,
157 :this(handle, access, bufferSize, false)
161 [MonoLimitationAttribute("Need to use SafeFileHandle instead of underlying handle")]
162 public FileStream (SafeFileHandle handle, FileAccess access,
163 int bufferSize, bool isAsync)
164 :this (handle.DangerousGetHandle (), access, false, bufferSize, isAsync)
166 this.safeHandle = handle;
169 public FileStream (string path, FileMode mode,
170 FileSystemRights rights, FileShare share,
171 int bufferSize, FileOptions options)
173 throw new NotImplementedException ();
176 public FileStream (string path, FileMode mode,
177 FileSystemRights rights, FileShare share,
178 int bufferSize, FileOptions options,
179 FileSecurity fileSecurity)
181 throw new NotImplementedException ();
185 internal FileStream (string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool isAsync, bool anonymous)
186 : this (path, mode, access, share, bufferSize, anonymous, isAsync ? FileOptions.Asynchronous : FileOptions.None)
190 internal FileStream (string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool anonymous, FileOptions options)
193 throw new ArgumentNullException ("path");
196 if (path.Length == 0) {
197 throw new ArgumentException ("Path is empty");
201 // ignore the Inheritable flag
202 share &= ~FileShare.Inheritable;
207 throw new ArgumentOutOfRangeException ("bufferSize", "Positive number required.");
209 if (mode < FileMode.CreateNew || mode > FileMode.Append) {
212 throw new ArgumentException ("mode", "Enum value was out of legal range.");
215 throw new ArgumentOutOfRangeException ("mode", "Enum value was out of legal range.");
218 if (access < FileAccess.Read || access > FileAccess.ReadWrite) {
221 throw new IsolatedStorageException ("Enum value for FileAccess was out of legal range.");
224 throw new ArgumentOutOfRangeException ("access", "Enum value was out of legal range.");
228 if (share < FileShare.None || share > (FileShare.ReadWrite | FileShare.Delete)) {
230 if (share < FileShare.None || share > FileShare.ReadWrite) {
234 throw new IsolatedStorageException ("Enum value for FileShare was out of legal range.");
237 throw new ArgumentOutOfRangeException ("share", "Enum value was out of legal range.");
240 if (path.IndexOfAny (Path.InvalidPathChars) != -1) {
241 throw new ArgumentException ("Name has invalid chars");
244 if (Directory.Exists (path)) {
245 // don't leak the path information for isolated storage
246 string msg = Locale.GetText ("Access to the path '{0}' is denied.");
247 string fname = (anonymous) ? Path.GetFileName (path) : Path.GetFullPath (path);
248 throw new UnauthorizedAccessException (String.Format (msg, fname));
251 /* Append streams can't be read (see FileMode
254 if (mode==FileMode.Append &&
255 (access&FileAccess.Read)==FileAccess.Read) {
256 throw new ArgumentException("Append access can be requested only in write-only mode.");
259 if ((access & FileAccess.Write) == 0 &&
260 (mode != FileMode.Open && mode != FileMode.OpenOrCreate)) {
261 string msg = Locale.GetText ("Combining FileMode: {0} with " +
262 "FileAccess: {1} is invalid.");
263 throw new ArgumentException (string.Format (msg, access, mode));
266 string dname = Path.GetDirectoryName (path);
267 if (dname.Length > 0) {
268 string fp = Path.GetFullPath (dname);
269 if (!Directory.Exists (fp)) {
270 // don't leak the path information for isolated storage
271 string msg = Locale.GetText ("Could not find a part of the path \"{0}\".");
272 string fname = (anonymous) ? dname : Path.GetFullPath (path);
274 throw new IsolatedStorageException (String.Format (msg, fname));
276 throw new DirectoryNotFoundException (String.Format (msg, fname));
281 if (access == FileAccess.Read && mode != FileMode.Create && mode != FileMode.OpenOrCreate &&
282 mode != FileMode.CreateNew && !File.Exists (path)) {
283 // don't leak the path information for isolated storage
284 string msg = Locale.GetText ("Could not find file \"{0}\".");
285 string fname = (anonymous) ? Path.GetFileName (path) : Path.GetFullPath (path);
287 throw new IsolatedStorageException (String.Format (msg, fname));
289 throw new FileNotFoundException (String.Format (msg, fname), fname);
293 // IsolatedStorage needs to keep the Name property to the default "[Unknown]"
297 // TODO: demand permissions
301 this.handle = MonoIO.Open (path, mode, access, share, options, out error);
302 if (handle == MonoIO.InvalidHandle) {
303 // don't leak the path information for isolated storage
304 string fname = (anonymous) ? Path.GetFileName (path) : Path.GetFullPath (path);
305 throw MonoIO.GetException (fname, error);
308 this.access = access;
310 this.anonymous = anonymous;
312 /* Can we open non-files by name? */
314 if (MonoIO.GetFileType (handle, out error) == MonoFileType.Disk) {
316 this.async = (options & FileOptions.Asynchronous) != 0;
318 this.canseek = false;
323 if (access == FileAccess.Read && canseek && (bufferSize == DefaultBufferSize)) {
324 /* Avoid allocating a large buffer for small files */
326 if (bufferSize > len) {
327 bufferSize = (int)(len < 1000 ? 1000 : len);
331 InitBuffer (bufferSize, false);
333 if (mode==FileMode.Append) {
334 this.Seek (0, SeekOrigin.End);
335 this.append_startpos=this.Position;
337 this.append_startpos=0;
343 public override bool CanRead {
345 return access == FileAccess.Read ||
346 access == FileAccess.ReadWrite;
350 public override bool CanWrite {
352 return access == FileAccess.Write ||
353 access == FileAccess.ReadWrite;
357 public override bool CanSeek {
363 public virtual bool IsAsync {
375 public override long Length {
377 if (handle == MonoIO.InvalidHandle)
378 throw new ObjectDisposedException ("Stream has been closed");
381 throw new NotSupportedException ("The stream does not support seeking");
383 // Buffered data might change the length of the stream
384 FlushBufferIfDirty ();
389 length = MonoIO.GetLength (handle, out error);
390 if (error != MonoIOError.ERROR_SUCCESS) {
391 // don't leak the path information for isolated storage
392 string fname = (anonymous) ? Path.GetFileName (name) : name;
393 throw MonoIO.GetException (fname, error);
400 public override long Position {
402 if (handle == MonoIO.InvalidHandle)
403 throw new ObjectDisposedException ("Stream has been closed");
406 throw new NotSupportedException("The stream does not support seeking");
408 return(buf_start + buf_offset);
411 if (handle == MonoIO.InvalidHandle)
412 throw new ObjectDisposedException ("Stream has been closed");
414 if(CanSeek == false) {
415 throw new NotSupportedException("The stream does not support seeking");
419 throw new ArgumentOutOfRangeException("Attempt to set the position to a negative value");
422 Seek (value, SeekOrigin.Begin);
427 [Obsolete ("Use SafeFileHandle instead")]
429 public virtual IntPtr Handle {
430 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
431 [SecurityPermission (SecurityAction.InheritanceDemand, UnmanagedCode = true)]
438 public virtual SafeFileHandle SafeFileHandle {
439 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
440 [SecurityPermission (SecurityAction.InheritanceDemand, UnmanagedCode = true)]
444 if (safeHandle != null)
447 ret = new SafeFileHandle (handle, owner);
457 public override int ReadByte ()
459 if (handle == MonoIO.InvalidHandle)
460 throw new ObjectDisposedException ("Stream has been closed");
463 throw new NotSupportedException ("Stream does not support reading");
466 int n = ReadData (handle, buf, 0, 1);
467 if (n == 0) return -1;
470 else if (buf_offset >= buf_length) {
477 return buf [buf_offset ++];
480 public override void WriteByte (byte value)
482 if (handle == MonoIO.InvalidHandle)
483 throw new ObjectDisposedException ("Stream has been closed");
486 throw new NotSupportedException ("Stream does not support writing");
488 if (buf_offset == buf_size)
491 if (buf_size == 0) { // No buffering
499 buf [buf_offset ++] = value;
500 if (buf_offset > buf_length)
501 buf_length = buf_offset;
506 public override int Read ([In,Out] byte[] array, int offset, int count)
508 if (handle == MonoIO.InvalidHandle)
509 throw new ObjectDisposedException ("Stream has been closed");
511 throw new ArgumentNullException ("array");
513 throw new NotSupportedException ("Stream does not support reading");
514 int len = array.Length;
516 throw new ArgumentOutOfRangeException ("offset", "< 0");
518 throw new ArgumentOutOfRangeException ("count", "< 0");
520 throw new ArgumentException ("destination offset is beyond array size");
521 // reordered to avoid possible integer overflow
522 if (offset > len - count)
523 throw new ArgumentException ("Reading would overrun buffer");
526 IAsyncResult ares = BeginRead (array, offset, count, null, null);
527 return EndRead (ares);
530 return ReadInternal (array, offset, count);
533 int ReadInternal (byte [] dest, int offset, int count)
537 int n = ReadSegment (dest, offset, count);
542 /* If there was already enough
543 * buffered, no need to read
544 * more from the file.
549 if (count > buf_size) {
550 /* Read as much as we can, up
554 n = ReadData (handle, dest,
558 /* Make the next buffer read
559 * start from the right place
564 n = ReadSegment (dest,
574 delegate int ReadDelegate (byte [] buffer, int offset, int count);
576 public override IAsyncResult BeginRead (byte [] array, int offset, int numBytes,
577 AsyncCallback userCallback, object stateObject)
579 if (handle == MonoIO.InvalidHandle)
580 throw new ObjectDisposedException ("Stream has been closed");
583 throw new NotSupportedException ("This stream does not support reading");
586 throw new ArgumentNullException ("array");
589 throw new ArgumentOutOfRangeException ("numBytes", "Must be >= 0");
592 throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
594 // reordered to avoid possible integer overflow
595 if (numBytes > array.Length - offset)
596 throw new ArgumentException ("Buffer too small. numBytes/offset wrong.");
599 return base.BeginRead (array, offset, numBytes, userCallback, stateObject);
601 ReadDelegate r = new ReadDelegate (ReadInternal);
602 return r.BeginInvoke (array, offset, numBytes, userCallback, stateObject);
605 public override int EndRead (IAsyncResult asyncResult)
607 if (asyncResult == null)
608 throw new ArgumentNullException ("asyncResult");
611 return base.EndRead (asyncResult);
613 AsyncResult ares = asyncResult as AsyncResult;
615 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
617 ReadDelegate r = ares.AsyncDelegate as ReadDelegate;
619 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
621 return r.EndInvoke (asyncResult);
624 public override void Write (byte[] array, int offset, int count)
626 if (handle == MonoIO.InvalidHandle)
627 throw new ObjectDisposedException ("Stream has been closed");
629 throw new ArgumentNullException ("array");
631 throw new ArgumentOutOfRangeException ("offset", "< 0");
633 throw new ArgumentOutOfRangeException ("count", "< 0");
634 // ordered to avoid possible integer overflow
635 if (offset > array.Length - count)
636 throw new ArgumentException ("Reading would overrun buffer");
638 throw new NotSupportedException ("Stream does not support writing");
641 IAsyncResult ares = BeginWrite (array, offset, count, null, null);
646 WriteInternal (array, offset, count);
649 void WriteInternal (byte [] src, int offset, int count)
651 if (count > buf_size) {
652 // shortcut for long writes
657 MonoIO.Write (handle, src, offset, count, out error);
658 if (error != MonoIOError.ERROR_SUCCESS) {
659 // don't leak the path information for isolated storage
660 string fname = (anonymous) ? Path.GetFileName (name) : name;
661 throw MonoIO.GetException (fname, error);
670 int n = WriteSegment (src, offset + copied, count);
683 delegate void WriteDelegate (byte [] buffer, int offset, int count);
685 public override IAsyncResult BeginWrite (byte [] array, int offset, int numBytes,
686 AsyncCallback userCallback, object stateObject)
688 if (handle == MonoIO.InvalidHandle)
689 throw new ObjectDisposedException ("Stream has been closed");
692 throw new NotSupportedException ("This stream does not support writing");
695 throw new ArgumentNullException ("array");
698 throw new ArgumentOutOfRangeException ("numBytes", "Must be >= 0");
701 throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
703 // reordered to avoid possible integer overflow
704 if (numBytes > array.Length - offset)
705 throw new ArgumentException ("array too small. numBytes/offset wrong.");
708 return base.BeginWrite (array, offset, numBytes, userCallback, stateObject);
710 FileStreamAsyncResult result = new FileStreamAsyncResult (userCallback, stateObject);
711 result.BytesRead = -1;
712 result.Count = numBytes;
713 result.OriginalCount = numBytes;
716 MemoryStream ms = new MemoryStream ();
717 FlushBufferToStream (ms);
718 ms.Write (array, offset, numBytes);
720 numBytes = (int) ms.Length;
723 WriteDelegate w = new WriteDelegate (WriteInternal);
724 return w.BeginInvoke (array, offset, numBytes, userCallback, stateObject);
727 public override void EndWrite (IAsyncResult asyncResult)
729 if (asyncResult == null)
730 throw new ArgumentNullException ("asyncResult");
733 base.EndWrite (asyncResult);
737 AsyncResult ares = asyncResult as AsyncResult;
739 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
741 WriteDelegate w = ares.AsyncDelegate as WriteDelegate;
743 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
745 w.EndInvoke (asyncResult);
749 public override long Seek (long offset, SeekOrigin origin)
753 if (handle == MonoIO.InvalidHandle)
754 throw new ObjectDisposedException ("Stream has been closed");
758 if(CanSeek == false) {
759 throw new NotSupportedException("The stream does not support seeking");
764 pos = Length + offset;
767 case SeekOrigin.Current:
768 pos = Position + offset;
771 case SeekOrigin.Begin:
776 throw new ArgumentException ("origin", "Invalid SeekOrigin");
780 /* LAMESPEC: shouldn't this be
781 * ArgumentOutOfRangeException?
783 throw new IOException("Attempted to Seek before the beginning of the stream");
786 if(pos < this.append_startpos) {
787 /* More undocumented crap */
788 throw new IOException("Can't seek back over pre-existing data in append mode");
795 buf_start = MonoIO.Seek (handle, pos,
799 if (error != MonoIOError.ERROR_SUCCESS) {
800 // don't leak the path information for isolated storage
801 string fname = (anonymous) ? Path.GetFileName (name) : name;
802 throw MonoIO.GetException (fname, error);
808 public override void SetLength (long value)
810 if (handle == MonoIO.InvalidHandle)
811 throw new ObjectDisposedException ("Stream has been closed");
814 throw new NotSupportedException("The stream does not support seeking");
816 if(CanWrite == false)
817 throw new NotSupportedException("The stream does not support writing");
820 throw new ArgumentOutOfRangeException("value is less than 0");
826 MonoIO.SetLength (handle, value, out error);
827 if (error != MonoIOError.ERROR_SUCCESS) {
828 // don't leak the path information for isolated storage
829 string fname = (anonymous) ? Path.GetFileName (name) : name;
830 throw MonoIO.GetException (fname, error);
833 if (Position > value)
837 public override void Flush ()
839 if (handle == MonoIO.InvalidHandle)
840 throw new ObjectDisposedException ("Stream has been closed");
844 // The flushing is not actually required, in
845 //the mono runtime we were mapping flush to
846 //`fsync' which is not the same.
848 //MonoIO.Flush (handle);
852 public override void Close ()
858 public virtual void Lock (long position, long length)
860 if (handle == MonoIO.InvalidHandle)
861 throw new ObjectDisposedException ("Stream has been closed");
863 throw new ArgumentOutOfRangeException ("position must not be negative");
866 throw new ArgumentOutOfRangeException ("length must not be negative");
868 if (handle == MonoIO.InvalidHandle) {
869 throw new ObjectDisposedException ("Stream has been closed");
874 MonoIO.Lock (handle, position, length, out error);
875 if (error != MonoIOError.ERROR_SUCCESS) {
876 // don't leak the path information for isolated storage
877 string fname = (anonymous) ? Path.GetFileName (name) : name;
878 throw MonoIO.GetException (fname, error);
882 public virtual void Unlock (long position, long length)
884 if (handle == MonoIO.InvalidHandle)
885 throw new ObjectDisposedException ("Stream has been closed");
887 throw new ArgumentOutOfRangeException ("position must not be negative");
890 throw new ArgumentOutOfRangeException ("length must not be negative");
895 MonoIO.Unlock (handle, position, length, out error);
896 if (error != MonoIOError.ERROR_SUCCESS) {
897 // don't leak the path information for isolated storage
898 string fname = (anonymous) ? Path.GetFileName (name) : name;
899 throw MonoIO.GetException (fname, error);
911 protected override void Dispose (bool disposing)
913 protected virtual void Dispose (bool disposing)
916 if (handle != MonoIO.InvalidHandle) {
922 MonoIO.Close (handle, out error);
923 if (error != MonoIOError.ERROR_SUCCESS) {
924 // don't leak the path information for isolated storage
925 string fname = (anonymous) ? Path.GetFileName (name) : name;
926 throw MonoIO.GetException (fname, error);
929 handle = MonoIO.InvalidHandle;
939 GC.SuppressFinalize (this);
943 public FileSecurity GetAccessControl ()
945 throw new NotImplementedException ();
948 public void SetAccessControl (FileSecurity fileSecurity)
950 throw new NotImplementedException ();
956 // ReadSegment, WriteSegment, FlushBuffer,
957 // RefillBuffer and ReadData should only be called
958 // when the Monitor lock is held, but these methods
959 // grab it again just to be safe.
961 private int ReadSegment (byte [] dest, int dest_offset, int count)
963 if (count > buf_length - buf_offset) {
964 count = buf_length - buf_offset;
968 Buffer.BlockCopy (buf, buf_offset,
977 private int WriteSegment (byte [] src, int src_offset,
980 if (count > buf_size - buf_offset) {
981 count = buf_size - buf_offset;
985 Buffer.BlockCopy (src, src_offset,
989 if (buf_offset > buf_length) {
990 buf_length = buf_offset;
999 void FlushBufferToStream (Stream st)
1002 if (CanSeek == true) {
1004 MonoIO.Seek (handle, buf_start,
1007 if (error != MonoIOError.ERROR_SUCCESS) {
1008 // don't leak the path information for isolated storage
1009 string fname = (anonymous) ? Path.GetFileName (name) : name;
1010 throw MonoIO.GetException (fname, error);
1013 st.Write (buf, 0, buf_length);
1016 buf_start += buf_offset;
1017 buf_offset = buf_length = 0;
1021 private void FlushBuffer ()
1026 if (CanSeek == true) {
1027 MonoIO.Seek (handle, buf_start,
1030 if (error != MonoIOError.ERROR_SUCCESS) {
1031 // don't leak the path information for isolated storage
1032 string fname = (anonymous) ? Path.GetFileName (name) : name;
1033 throw MonoIO.GetException (fname, error);
1036 MonoIO.Write (handle, buf, 0,
1037 buf_length, out error);
1039 if (error != MonoIOError.ERROR_SUCCESS) {
1040 // don't leak the path information for isolated storage
1041 string fname = (anonymous) ? Path.GetFileName (name) : name;
1042 throw MonoIO.GetException (fname, error);
1046 buf_start += buf_offset;
1047 buf_offset = buf_length = 0;
1051 private void FlushBufferIfDirty ()
1057 private void RefillBuffer ()
1061 buf_length = ReadData (handle, buf, 0,
1065 private int ReadData (IntPtr handle, byte[] buf, int offset,
1071 /* when async == true, if we get here we don't suport AIO or it's disabled
1072 * and we're using the threadpool */
1073 amount = MonoIO.Read (handle, buf, offset, count, out error);
1074 if (error == MonoIOError.ERROR_BROKEN_PIPE) {
1075 amount = 0; // might not be needed, but well...
1076 } else if (error != MonoIOError.ERROR_SUCCESS) {
1077 // don't leak the path information for isolated storage
1078 string fname = (anonymous) ? Path.GetFileName (name) : name;
1079 throw MonoIO.GetException (fname, error);
1082 /* Check for read error */
1084 throw new IOException ();
1090 private void InitBuffer (int size, bool noBuffering)
1094 // We need a buffer for the ReadByte method. This buffer won't
1095 // be used for anything else since buf_size==0.
1100 throw new ArgumentOutOfRangeException ("bufferSize", "Positive number required.");
1103 buf = new byte [size];
1108 buf_offset = buf_length = 0;
1114 internal const int DefaultBufferSize = 8192;
1116 private FileAccess access;
1119 private bool canseek;
1120 private long append_startpos;
1121 private bool anonymous;
1123 private byte [] buf; // the buffer
1124 private int buf_size; // capacity in bytes
1125 private int buf_length; // number of valid bytes in buffer
1126 private int buf_offset; // position of next byte
1127 private bool buf_dirty; // true if buffer has been written to
1128 private long buf_start; // location of buffer in file
1129 private string name = "[Unknown]"; // name of file.
1131 IntPtr handle; // handle to underlying file
1133 SafeFileHandle safeHandle; // set only when using one of the
1134 // constructors taking SafeFileHandle