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)
168 public FileStream (string path, FileMode mode,
169 FileSystemRights rights, FileShare share,
170 int bufferSize, FileOptions options)
172 throw new NotImplementedException ();
175 public FileStream (string path, FileMode mode,
176 FileSystemRights rights, FileShare share,
177 int bufferSize, FileOptions options,
178 FileSecurity fileSecurity)
180 throw new NotImplementedException ();
184 internal FileStream (string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool isAsync, bool anonymous)
185 : this (path, mode, access, share, bufferSize, anonymous, isAsync ? FileOptions.Asynchronous : FileOptions.None)
189 internal FileStream (string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool anonymous, FileOptions options)
192 throw new ArgumentNullException ("path");
195 if (path.Length == 0) {
196 throw new ArgumentException ("Path is empty");
200 // ignore the Inheritable flag
201 share &= ~FileShare.Inheritable;
206 throw new ArgumentOutOfRangeException ("bufferSize", "Positive number required.");
208 if (mode < FileMode.CreateNew || mode > FileMode.Append) {
211 throw new ArgumentException ("mode", "Enum value was out of legal range.");
214 throw new ArgumentOutOfRangeException ("mode", "Enum value was out of legal range.");
217 if (access < FileAccess.Read || access > FileAccess.ReadWrite) {
220 throw new IsolatedStorageException ("Enum value for FileAccess was out of legal range.");
223 throw new ArgumentOutOfRangeException ("access", "Enum value was out of legal range.");
227 if (share < FileShare.None || share > (FileShare.ReadWrite | FileShare.Delete)) {
229 if (share < FileShare.None || share > FileShare.ReadWrite) {
233 throw new IsolatedStorageException ("Enum value for FileShare was out of legal range.");
236 throw new ArgumentOutOfRangeException ("share", "Enum value was out of legal range.");
239 if (path.IndexOfAny (Path.InvalidPathChars) != -1) {
240 throw new ArgumentException ("Name has invalid chars");
243 if (Directory.Exists (path)) {
244 // don't leak the path information for isolated storage
245 string msg = Locale.GetText ("Access to the path '{0}' is denied.");
246 string fname = (anonymous) ? Path.GetFileName (path) : Path.GetFullPath (path);
247 throw new UnauthorizedAccessException (String.Format (msg, fname));
250 /* Append streams can't be read (see FileMode
253 if (mode==FileMode.Append &&
254 (access&FileAccess.Read)==FileAccess.Read) {
255 throw new ArgumentException("Append access can be requested only in write-only mode.");
258 if ((access & FileAccess.Write) == 0 &&
259 (mode != FileMode.Open && mode != FileMode.OpenOrCreate)) {
260 string msg = Locale.GetText ("Combining FileMode: {0} with " +
261 "FileAccess: {1} is invalid.");
262 throw new ArgumentException (string.Format (msg, access, mode));
265 string dname = Path.GetDirectoryName (path);
266 if (dname.Length > 0) {
267 string fp = Path.GetFullPath (dname);
268 if (!Directory.Exists (fp)) {
269 // don't leak the path information for isolated storage
270 string msg = Locale.GetText ("Could not find a part of the path \"{0}\".");
271 string fname = (anonymous) ? dname : Path.GetFullPath (path);
273 throw new IsolatedStorageException (String.Format (msg, fname));
275 throw new DirectoryNotFoundException (String.Format (msg, fname));
280 if (access == FileAccess.Read && mode != FileMode.Create && mode != FileMode.OpenOrCreate &&
281 mode != FileMode.CreateNew && !File.Exists (path)) {
282 // don't leak the path information for isolated storage
283 string msg = Locale.GetText ("Could not find file \"{0}\".");
284 string fname = (anonymous) ? Path.GetFileName (path) : Path.GetFullPath (path);
286 throw new IsolatedStorageException (String.Format (msg, fname));
288 throw new FileNotFoundException (String.Format (msg, fname), fname);
292 // IsolatedStorage needs to keep the Name property to the default "[Unknown]"
296 // TODO: demand permissions
300 this.handle = MonoIO.Open (path, mode, access, share, options, out error);
301 if (handle == MonoIO.InvalidHandle) {
302 // don't leak the path information for isolated storage
303 string fname = (anonymous) ? Path.GetFileName (path) : Path.GetFullPath (path);
304 throw MonoIO.GetException (fname, error);
307 this.access = access;
309 this.anonymous = anonymous;
311 /* Can we open non-files by name? */
313 if (MonoIO.GetFileType (handle, out error) == MonoFileType.Disk) {
315 this.async = (options & FileOptions.Asynchronous) != 0;
317 this.canseek = false;
322 if (access == FileAccess.Read && canseek && (bufferSize == DefaultBufferSize)) {
323 /* Avoid allocating a large buffer for small files */
325 if (bufferSize > len) {
326 bufferSize = (int)(len < 1000 ? 1000 : len);
330 InitBuffer (bufferSize, false);
332 if (mode==FileMode.Append) {
333 this.Seek (0, SeekOrigin.End);
334 this.append_startpos=this.Position;
336 this.append_startpos=0;
342 public override bool CanRead {
344 return access == FileAccess.Read ||
345 access == FileAccess.ReadWrite;
349 public override bool CanWrite {
351 return access == FileAccess.Write ||
352 access == FileAccess.ReadWrite;
356 public override bool CanSeek {
362 public virtual bool IsAsync {
374 public override long Length {
376 if (handle == MonoIO.InvalidHandle)
377 throw new ObjectDisposedException ("Stream has been closed");
380 throw new NotSupportedException ("The stream does not support seeking");
382 // Buffered data might change the length of the stream
383 FlushBufferIfDirty ();
388 length = MonoIO.GetLength (handle, out error);
389 if (error != MonoIOError.ERROR_SUCCESS) {
390 // don't leak the path information for isolated storage
391 string fname = (anonymous) ? Path.GetFileName (name) : name;
392 throw MonoIO.GetException (fname, error);
399 public override long Position {
401 if (handle == MonoIO.InvalidHandle)
402 throw new ObjectDisposedException ("Stream has been closed");
405 throw new NotSupportedException("The stream does not support seeking");
407 return(buf_start + buf_offset);
410 if (handle == MonoIO.InvalidHandle)
411 throw new ObjectDisposedException ("Stream has been closed");
413 if(CanSeek == false) {
414 throw new NotSupportedException("The stream does not support seeking");
418 throw new ArgumentOutOfRangeException("Attempt to set the position to a negative value");
421 Seek (value, SeekOrigin.Begin);
426 [Obsolete ("Use SafeFileHandle instead")]
428 public virtual IntPtr Handle {
429 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
430 [SecurityPermission (SecurityAction.InheritanceDemand, UnmanagedCode = true)]
437 public virtual SafeFileHandle SafeFileHandle {
438 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
439 [SecurityPermission (SecurityAction.InheritanceDemand, UnmanagedCode = true)]
440 get { throw new NotImplementedException (); }
446 public override int ReadByte ()
448 if (handle == MonoIO.InvalidHandle)
449 throw new ObjectDisposedException ("Stream has been closed");
452 throw new NotSupportedException ("Stream does not support reading");
455 int n = ReadData (handle, buf, 0, 1);
456 if (n == 0) return -1;
459 else if (buf_offset >= buf_length) {
466 return buf [buf_offset ++];
469 public override void WriteByte (byte value)
471 if (handle == MonoIO.InvalidHandle)
472 throw new ObjectDisposedException ("Stream has been closed");
475 throw new NotSupportedException ("Stream does not support writing");
477 if (buf_offset == buf_size)
480 if (buf_size == 0) { // No buffering
488 buf [buf_offset ++] = value;
489 if (buf_offset > buf_length)
490 buf_length = buf_offset;
495 public override int Read ([In,Out] byte[] array, int offset, int count)
497 if (handle == MonoIO.InvalidHandle)
498 throw new ObjectDisposedException ("Stream has been closed");
500 throw new ArgumentNullException ("array");
502 throw new NotSupportedException ("Stream does not support reading");
503 int len = array.Length;
505 throw new ArgumentOutOfRangeException ("offset", "< 0");
507 throw new ArgumentOutOfRangeException ("count", "< 0");
509 throw new ArgumentException ("destination offset is beyond array size");
510 // reordered to avoid possible integer overflow
511 if (offset > len - count)
512 throw new ArgumentException ("Reading would overrun buffer");
515 IAsyncResult ares = BeginRead (array, offset, count, null, null);
516 return EndRead (ares);
519 return ReadInternal (array, offset, count);
522 int ReadInternal (byte [] dest, int offset, int count)
526 int n = ReadSegment (dest, offset, count);
531 /* If there was already enough
532 * buffered, no need to read
533 * more from the file.
538 if (count > buf_size) {
539 /* Read as much as we can, up
543 n = ReadData (handle, dest,
547 /* Make the next buffer read
548 * start from the right place
553 n = ReadSegment (dest,
563 delegate int ReadDelegate (byte [] buffer, int offset, int count);
565 public override IAsyncResult BeginRead (byte [] array, int offset, int numBytes,
566 AsyncCallback userCallback, object stateObject)
568 if (handle == MonoIO.InvalidHandle)
569 throw new ObjectDisposedException ("Stream has been closed");
572 throw new NotSupportedException ("This stream does not support reading");
575 throw new ArgumentNullException ("array");
578 throw new ArgumentOutOfRangeException ("numBytes", "Must be >= 0");
581 throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
583 // reordered to avoid possible integer overflow
584 if (numBytes > array.Length - offset)
585 throw new ArgumentException ("Buffer too small. numBytes/offset wrong.");
588 return base.BeginRead (array, offset, numBytes, userCallback, stateObject);
590 ReadDelegate r = new ReadDelegate (ReadInternal);
591 return r.BeginInvoke (array, offset, numBytes, userCallback, stateObject);
594 public override int EndRead (IAsyncResult asyncResult)
596 if (asyncResult == null)
597 throw new ArgumentNullException ("asyncResult");
600 return base.EndRead (asyncResult);
602 AsyncResult ares = asyncResult as AsyncResult;
604 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
606 ReadDelegate r = ares.AsyncDelegate as ReadDelegate;
608 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
610 return r.EndInvoke (asyncResult);
613 public override void Write (byte[] array, int offset, int count)
615 if (handle == MonoIO.InvalidHandle)
616 throw new ObjectDisposedException ("Stream has been closed");
618 throw new ArgumentNullException ("array");
620 throw new ArgumentOutOfRangeException ("offset", "< 0");
622 throw new ArgumentOutOfRangeException ("count", "< 0");
623 // ordered to avoid possible integer overflow
624 if (offset > array.Length - count)
625 throw new ArgumentException ("Reading would overrun buffer");
627 throw new NotSupportedException ("Stream does not support writing");
630 IAsyncResult ares = BeginWrite (array, offset, count, null, null);
635 WriteInternal (array, offset, count);
638 void WriteInternal (byte [] src, int offset, int count)
640 if (count > buf_size) {
641 // shortcut for long writes
646 MonoIO.Write (handle, src, offset, count, out error);
647 if (error != MonoIOError.ERROR_SUCCESS) {
648 // don't leak the path information for isolated storage
649 string fname = (anonymous) ? Path.GetFileName (name) : name;
650 throw MonoIO.GetException (fname, error);
659 int n = WriteSegment (src, offset + copied, count);
672 delegate void WriteDelegate (byte [] buffer, int offset, int count);
674 public override IAsyncResult BeginWrite (byte [] array, int offset, int numBytes,
675 AsyncCallback userCallback, object stateObject)
677 if (handle == MonoIO.InvalidHandle)
678 throw new ObjectDisposedException ("Stream has been closed");
681 throw new NotSupportedException ("This stream does not support writing");
684 throw new ArgumentNullException ("array");
687 throw new ArgumentOutOfRangeException ("numBytes", "Must be >= 0");
690 throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
692 // reordered to avoid possible integer overflow
693 if (numBytes > array.Length - offset)
694 throw new ArgumentException ("array too small. numBytes/offset wrong.");
697 return base.BeginWrite (array, offset, numBytes, userCallback, stateObject);
699 FileStreamAsyncResult result = new FileStreamAsyncResult (userCallback, stateObject);
700 result.BytesRead = -1;
701 result.Count = numBytes;
702 result.OriginalCount = numBytes;
705 MemoryStream ms = new MemoryStream ();
706 FlushBufferToStream (ms);
707 ms.Write (array, offset, numBytes);
709 numBytes = (int) ms.Length;
712 WriteDelegate w = new WriteDelegate (WriteInternal);
713 return w.BeginInvoke (array, offset, numBytes, userCallback, stateObject);
716 public override void EndWrite (IAsyncResult asyncResult)
718 if (asyncResult == null)
719 throw new ArgumentNullException ("asyncResult");
722 base.EndWrite (asyncResult);
726 AsyncResult ares = asyncResult as AsyncResult;
728 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
730 WriteDelegate w = ares.AsyncDelegate as WriteDelegate;
732 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
734 w.EndInvoke (asyncResult);
738 public override long Seek (long offset, SeekOrigin origin)
742 if (handle == MonoIO.InvalidHandle)
743 throw new ObjectDisposedException ("Stream has been closed");
747 if(CanSeek == false) {
748 throw new NotSupportedException("The stream does not support seeking");
753 pos = Length + offset;
756 case SeekOrigin.Current:
757 pos = Position + offset;
760 case SeekOrigin.Begin:
765 throw new ArgumentException ("origin", "Invalid SeekOrigin");
769 /* LAMESPEC: shouldn't this be
770 * ArgumentOutOfRangeException?
772 throw new IOException("Attempted to Seek before the beginning of the stream");
775 if(pos < this.append_startpos) {
776 /* More undocumented crap */
777 throw new IOException("Can't seek back over pre-existing data in append mode");
784 buf_start = MonoIO.Seek (handle, pos,
788 if (error != MonoIOError.ERROR_SUCCESS) {
789 // don't leak the path information for isolated storage
790 string fname = (anonymous) ? Path.GetFileName (name) : name;
791 throw MonoIO.GetException (fname, error);
797 public override void SetLength (long value)
799 if (handle == MonoIO.InvalidHandle)
800 throw new ObjectDisposedException ("Stream has been closed");
803 throw new NotSupportedException("The stream does not support seeking");
805 if(CanWrite == false)
806 throw new NotSupportedException("The stream does not support writing");
809 throw new ArgumentOutOfRangeException("value is less than 0");
815 MonoIO.SetLength (handle, value, out error);
816 if (error != MonoIOError.ERROR_SUCCESS) {
817 // don't leak the path information for isolated storage
818 string fname = (anonymous) ? Path.GetFileName (name) : name;
819 throw MonoIO.GetException (fname, error);
822 if (Position > value)
826 public override void Flush ()
828 if (handle == MonoIO.InvalidHandle)
829 throw new ObjectDisposedException ("Stream has been closed");
833 // The flushing is not actually required, in
834 //the mono runtime we were mapping flush to
835 //`fsync' which is not the same.
837 //MonoIO.Flush (handle);
841 public override void Close ()
847 public virtual void Lock (long position, long length)
849 if (handle == MonoIO.InvalidHandle)
850 throw new ObjectDisposedException ("Stream has been closed");
852 throw new ArgumentOutOfRangeException ("position must not be negative");
855 throw new ArgumentOutOfRangeException ("length must not be negative");
857 if (handle == MonoIO.InvalidHandle) {
858 throw new ObjectDisposedException ("Stream has been closed");
863 MonoIO.Lock (handle, position, length, out error);
864 if (error != MonoIOError.ERROR_SUCCESS) {
865 // don't leak the path information for isolated storage
866 string fname = (anonymous) ? Path.GetFileName (name) : name;
867 throw MonoIO.GetException (fname, error);
871 public virtual void Unlock (long position, long length)
873 if (handle == MonoIO.InvalidHandle)
874 throw new ObjectDisposedException ("Stream has been closed");
876 throw new ArgumentOutOfRangeException ("position must not be negative");
879 throw new ArgumentOutOfRangeException ("length must not be negative");
884 MonoIO.Unlock (handle, position, length, out error);
885 if (error != MonoIOError.ERROR_SUCCESS) {
886 // don't leak the path information for isolated storage
887 string fname = (anonymous) ? Path.GetFileName (name) : name;
888 throw MonoIO.GetException (fname, error);
900 protected override void Dispose (bool disposing)
902 protected virtual void Dispose (bool disposing)
905 if (handle != MonoIO.InvalidHandle) {
911 MonoIO.Close (handle, out error);
912 if (error != MonoIOError.ERROR_SUCCESS) {
913 // don't leak the path information for isolated storage
914 string fname = (anonymous) ? Path.GetFileName (name) : name;
915 throw MonoIO.GetException (fname, error);
918 handle = MonoIO.InvalidHandle;
928 GC.SuppressFinalize (this);
932 public FileSecurity GetAccessControl ()
934 throw new NotImplementedException ();
937 public void SetAccessControl (FileSecurity fileSecurity)
939 throw new NotImplementedException ();
945 // ReadSegment, WriteSegment, FlushBuffer,
946 // RefillBuffer and ReadData should only be called
947 // when the Monitor lock is held, but these methods
948 // grab it again just to be safe.
950 private int ReadSegment (byte [] dest, int dest_offset, int count)
952 if (count > buf_length - buf_offset) {
953 count = buf_length - buf_offset;
957 Buffer.BlockCopy (buf, buf_offset,
966 private int WriteSegment (byte [] src, int src_offset,
969 if (count > buf_size - buf_offset) {
970 count = buf_size - buf_offset;
974 Buffer.BlockCopy (src, src_offset,
978 if (buf_offset > buf_length) {
979 buf_length = buf_offset;
988 void FlushBufferToStream (Stream st)
991 if (CanSeek == true) {
993 MonoIO.Seek (handle, buf_start,
996 if (error != MonoIOError.ERROR_SUCCESS) {
997 // don't leak the path information for isolated storage
998 string fname = (anonymous) ? Path.GetFileName (name) : name;
999 throw MonoIO.GetException (fname, error);
1002 st.Write (buf, 0, buf_length);
1005 buf_start += buf_offset;
1006 buf_offset = buf_length = 0;
1010 private void FlushBuffer ()
1015 if (CanSeek == true) {
1016 MonoIO.Seek (handle, buf_start,
1019 if (error != MonoIOError.ERROR_SUCCESS) {
1020 // don't leak the path information for isolated storage
1021 string fname = (anonymous) ? Path.GetFileName (name) : name;
1022 throw MonoIO.GetException (fname, error);
1025 MonoIO.Write (handle, buf, 0,
1026 buf_length, out error);
1028 if (error != MonoIOError.ERROR_SUCCESS) {
1029 // don't leak the path information for isolated storage
1030 string fname = (anonymous) ? Path.GetFileName (name) : name;
1031 throw MonoIO.GetException (fname, error);
1035 buf_start += buf_offset;
1036 buf_offset = buf_length = 0;
1040 private void FlushBufferIfDirty ()
1046 private void RefillBuffer ()
1050 buf_length = ReadData (handle, buf, 0,
1054 private int ReadData (IntPtr handle, byte[] buf, int offset,
1060 /* when async == true, if we get here we don't suport AIO or it's disabled
1061 * and we're using the threadpool */
1062 amount = MonoIO.Read (handle, buf, offset, count, out error);
1063 if (error == MonoIOError.ERROR_BROKEN_PIPE) {
1064 amount = 0; // might not be needed, but well...
1065 } else if (error != MonoIOError.ERROR_SUCCESS) {
1066 // don't leak the path information for isolated storage
1067 string fname = (anonymous) ? Path.GetFileName (name) : name;
1068 throw MonoIO.GetException (fname, error);
1071 /* Check for read error */
1073 throw new IOException ();
1079 private void InitBuffer (int size, bool noBuffering)
1083 // We need a buffer for the ReadByte method. This buffer won't
1084 // be used for anything else since buf_size==0.
1089 throw new ArgumentOutOfRangeException ("bufferSize", "Positive number required.");
1092 buf = new byte [size];
1097 buf_offset = buf_length = 0;
1103 internal const int DefaultBufferSize = 8192;
1105 private FileAccess access;
1108 private bool canseek;
1109 private long append_startpos;
1110 private bool anonymous;
1112 private byte [] buf; // the buffer
1113 private int buf_size; // capacity in bytes
1114 private int buf_length; // number of valid bytes in buffer
1115 private int buf_offset; // position of next byte
1116 private bool buf_dirty; // true if buffer has been written to
1117 private long buf_start; // location of buffer in file
1118 private string name = "[Unknown]"; // name of file.
1120 IntPtr handle; // handle to underlying file