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 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.
33 using System.Collections;
34 using System.Globalization;
35 using System.Runtime.CompilerServices;
36 using System.Runtime.InteropServices;
37 using System.Runtime.Remoting.Messaging;
38 using System.Threading;
41 using Microsoft.Win32.SafeHandles;
46 public class FileStream : Stream
48 // construct from handle
50 public FileStream (IntPtr handle, FileAccess access)
51 : this (handle, access, true, DefaultBufferSize, false) {}
53 public FileStream (IntPtr handle, FileAccess access, bool ownsHandle)
54 : this (handle, access, ownsHandle, DefaultBufferSize, false) {}
56 public FileStream (IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize)
57 : this (handle, access, ownsHandle, bufferSize, false) {}
59 public FileStream (IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize, bool isAsync)
60 : this (handle, access, ownsHandle, bufferSize, isAsync, false) {}
62 internal FileStream (IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize, bool isAsync, bool noBuffering)
64 this.handle = MonoIO.InvalidHandle;
65 if (handle == this.handle)
66 throw new ArgumentException ("handle", Locale.GetText ("Invalid."));
68 if (access < FileAccess.Read || access > FileAccess.ReadWrite)
69 throw new ArgumentOutOfRangeException ("access");
72 MonoFileType ftype = MonoIO.GetFileType (handle, out error);
74 if (error != MonoIOError.ERROR_SUCCESS) {
75 throw MonoIO.GetException (name, error);
78 if (ftype == MonoFileType.Unknown) {
79 throw new IOException ("Invalid handle.");
80 } else if (ftype == MonoFileType.Disk) {
88 this.owner = ownsHandle;
90 this.anonymous = false;
92 if (isAsync && MonoIO.SupportsAsync)
93 ThreadPool.BindHandle (handle);
95 InitBuffer (bufferSize, noBuffering);
97 /* Can't set append mode */
98 this.append_startpos=0;
101 // construct from filename
103 public FileStream (string name, FileMode mode)
104 : this (name, mode, (mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite), FileShare.Read, DefaultBufferSize, false, false)
108 public FileStream (string name, FileMode mode, FileAccess access)
109 : this (name, mode, access, access == FileAccess.Write ? FileShare.None : FileShare.Read, DefaultBufferSize, false, false)
113 public FileStream (string name, FileMode mode, FileAccess access, FileShare share)
114 : this (name, mode, access, share, DefaultBufferSize, false, false)
118 public FileStream (string name, FileMode mode, FileAccess access, FileShare share, int bufferSize)
119 : this (name, mode, access, share, bufferSize, false, false)
123 public FileStream (string name, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool isAsync)
124 : this (name, mode, access, share, bufferSize, isAsync, false)
128 internal FileStream (string name, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool isAsync, bool anonymous)
131 throw new ArgumentNullException ("name");
134 if (name.Length == 0) {
135 throw new ArgumentException ("Name is empty");
139 throw new ArgumentOutOfRangeException ("Positive number required.");
141 if (mode < FileMode.CreateNew || mode > FileMode.Append)
142 throw new ArgumentOutOfRangeException ("mode");
144 if (access < FileAccess.Read || access > FileAccess.ReadWrite)
145 throw new ArgumentOutOfRangeException ("access");
147 if (share < FileShare.None || share > FileShare.ReadWrite)
148 throw new ArgumentOutOfRangeException ("share");
150 if (name.IndexOfAny (Path.InvalidPathChars) != -1) {
151 throw new ArgumentException ("Name has invalid chars");
154 if (Directory.Exists (name)) {
155 // don't leak the path information for isolated storage
156 string msg = Locale.GetText ("Access to the path '{0}' is denied.");
157 string fname = (anonymous) ? Path.GetFileName (name) : Path.GetFullPath (name);
158 throw new UnauthorizedAccessException (String.Format (msg, fname));
161 /* Append streams can't be read (see FileMode
164 if (mode==FileMode.Append &&
165 (access&FileAccess.Read)==FileAccess.Read) {
166 throw new ArgumentException("Append streams can not be read");
169 if ((access & FileAccess.Write) == 0 &&
170 (mode != FileMode.Open && mode != FileMode.OpenOrCreate))
171 throw new ArgumentException ("access and mode not compatible");
173 string dname = Path.GetDirectoryName (name);
174 if (dname.Length > 0) {
175 string fp = Path.GetFullPath (dname);
176 if (!Directory.Exists (fp)) {
177 // don't leak the path information for isolated storage
178 string msg = Locale.GetText ("Could not find a part of the path \"{0}\".");
179 string fname = (anonymous) ? dname : fp;
180 throw new DirectoryNotFoundException (String.Format (msg, fname));
184 if (access == FileAccess.Read && mode != FileMode.Create && mode != FileMode.OpenOrCreate &&
185 mode != FileMode.CreateNew && !File.Exists (name)) {
186 // don't leak the path information for isolated storage
187 string msg = Locale.GetText ("Could not find file \"{0}\".");
188 string fname = (anonymous) ? Path.GetFileName (name) : name;
189 throw new FileNotFoundException (String.Format (msg, fname), fname);
192 // IsolatedStorage needs to keep the Name property to the default "[Unknown]"
196 // TODO: demand permissions
200 bool openAsync = (isAsync && MonoIO.SupportsAsync);
201 this.handle = MonoIO.Open (name, mode, access, share, openAsync, out error);
202 if (handle == MonoIO.InvalidHandle) {
203 // don't leak the path information for isolated storage
204 string fname = (anonymous) ? Path.GetFileName (name) : name;
205 throw MonoIO.GetException (fname, error);
208 this.access = access;
210 this.anonymous = anonymous;
212 /* Can we open non-files by name? */
214 if (MonoIO.GetFileType (handle, out error) == MonoFileType.Disk) {
216 this.async = isAsync;
218 ThreadPool.BindHandle (handle);
220 this.canseek = false;
225 if (access == FileAccess.Read && canseek && (bufferSize == DefaultBufferSize)) {
226 /* Avoid allocating a large buffer for small files */
228 if (bufferSize > len) {
229 bufferSize = (int)(len < 1000 ? 1000 : len);
233 InitBuffer (bufferSize, false);
235 if (mode==FileMode.Append) {
236 this.Seek (0, SeekOrigin.End);
237 this.append_startpos=this.Position;
239 this.append_startpos=0;
245 public override bool CanRead {
247 return access == FileAccess.Read ||
248 access == FileAccess.ReadWrite;
252 public override bool CanWrite {
254 return access == FileAccess.Write ||
255 access == FileAccess.ReadWrite;
259 public override bool CanSeek {
265 public virtual bool IsAsync {
277 public override long Length {
279 if (handle == MonoIO.InvalidHandle)
280 throw new ObjectDisposedException ("Stream has been closed");
283 throw new NotSupportedException ("The stream does not support seeking");
285 // Buffered data might change the length of the stream
286 FlushBufferIfDirty ();
291 length = MonoIO.GetLength (handle, out error);
292 if (error != MonoIOError.ERROR_SUCCESS) {
293 // don't leak the path information for isolated storage
294 string fname = (anonymous) ? Path.GetFileName (name) : name;
295 throw MonoIO.GetException (fname, error);
302 public override long Position {
304 if (handle == MonoIO.InvalidHandle)
305 throw new ObjectDisposedException ("Stream has been closed");
308 throw new NotSupportedException("The stream does not support seeking");
310 return(buf_start + buf_offset);
313 if (handle == MonoIO.InvalidHandle)
314 throw new ObjectDisposedException ("Stream has been closed");
316 if(CanSeek == false) {
317 throw new NotSupportedException("The stream does not support seeking");
321 throw new ArgumentOutOfRangeException("Attempt to set the position to a negative value");
324 Seek (value, SeekOrigin.Begin);
328 public virtual IntPtr Handle {
335 public virtual SafeFileHandle SafeFileHandle {
336 get { throw new NotImplementedException (); }
342 public override int ReadByte ()
344 if (handle == MonoIO.InvalidHandle)
345 throw new ObjectDisposedException ("Stream has been closed");
348 throw new NotSupportedException ("Stream does not support reading");
351 int n = ReadData (handle, buf, 0, 1);
352 if (n == 0) return -1;
355 else if (buf_offset >= buf_length) {
362 return buf [buf_offset ++];
365 public override void WriteByte (byte value)
367 if (handle == MonoIO.InvalidHandle)
368 throw new ObjectDisposedException ("Stream has been closed");
371 throw new NotSupportedException ("Stream does not support writing");
373 if (buf_offset == buf_size)
376 buf [buf_offset ++] = value;
377 if (buf_offset > buf_length)
378 buf_length = buf_offset;
383 public override int Read ([In,Out] byte[] dest, int dest_offset, int count)
385 if (handle == MonoIO.InvalidHandle)
386 throw new ObjectDisposedException ("Stream has been closed");
388 throw new ArgumentNullException ("destFile");
390 throw new NotSupportedException ("Stream does not support reading");
391 int len = dest.Length;
393 throw new ArgumentOutOfRangeException ("dest_offset", "< 0");
395 throw new ArgumentOutOfRangeException ("count", "< 0");
396 if (dest_offset > len)
397 throw new ArgumentException ("destination offset is beyond array size");
398 // reordered to avoid possible integer overflow
399 if (dest_offset > len - count)
400 throw new ArgumentException ("Reading would overrun buffer");
403 IAsyncResult ares = BeginRead (dest, dest_offset, count, null, null);
404 return EndRead (ares);
407 return ReadInternal (dest, dest_offset, count);
410 int ReadInternal (byte [] dest, int dest_offset, int count)
414 int n = ReadSegment (dest, dest_offset, count);
419 /* If there was already enough
420 * buffered, no need to read
421 * more from the file.
426 if (count > buf_size) {
427 /* Read as much as we can, up
431 n = ReadData (handle, dest,
435 /* Make the next buffer read
436 * start from the right place
441 n = ReadSegment (dest,
451 delegate int ReadDelegate (byte [] buffer, int offset, int count);
453 public override IAsyncResult BeginRead (byte [] buffer, int offset, int count,
454 AsyncCallback cback, object state)
456 if (handle == MonoIO.InvalidHandle)
457 throw new ObjectDisposedException ("Stream has been closed");
460 throw new NotSupportedException ("This stream does not support reading");
463 throw new ArgumentNullException ("buffer");
466 throw new ArgumentOutOfRangeException ("count", "Must be >= 0");
469 throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
471 // reordered to avoid possible integer overflow
472 if (count > buffer.Length - offset)
473 throw new ArgumentException ("Buffer too small. count/offset wrong.");
476 return base.BeginRead (buffer, offset, count, cback, state);
478 if (!MonoIO.SupportsAsync) {
479 ReadDelegate r = new ReadDelegate (ReadInternal);
480 return r.BeginInvoke (buffer, offset, count, cback, state);
483 FileStreamAsyncResult result = new FileStreamAsyncResult (cback, state);
484 result.Count = count;
485 result.OriginalCount = count;
486 int buffered = ReadSegment (buffer, offset, count);
487 if (buffered >= count) {
488 result.SetComplete (null, buffered, true);
492 result.Buffer = buffer;
493 result.Offset = offset + buffered;
494 result.Count -= buffered;
496 KeepReference (result);
497 MonoIO.BeginRead (handle, result);
502 public override int EndRead (IAsyncResult async_result)
504 if (async_result == null)
505 throw new ArgumentNullException ("async_result");
508 return base.EndRead (async_result);
510 if (!MonoIO.SupportsAsync) {
511 AsyncResult ares = async_result as AsyncResult;
513 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
515 ReadDelegate r = ares.AsyncDelegate as ReadDelegate;
517 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
519 return r.EndInvoke (async_result);
522 FileStreamAsyncResult result = async_result as FileStreamAsyncResult;
523 if (result == null || result.BytesRead == -1)
524 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
526 RemoveReference (result);
528 throw new InvalidOperationException ("EndRead already called.");
531 if (!result.IsCompleted)
532 result.AsyncWaitHandle.WaitOne ();
534 if (result.Exception != null)
535 throw result.Exception;
537 buf_start += result.BytesRead;
538 return result.OriginalCount - result.Count + result.BytesRead;
541 public override void Write (byte[] src, int src_offset, int count)
543 if (handle == MonoIO.InvalidHandle)
544 throw new ObjectDisposedException ("Stream has been closed");
546 throw new ArgumentNullException ("src");
548 throw new ArgumentOutOfRangeException ("src_offset", "< 0");
550 throw new ArgumentOutOfRangeException ("count", "< 0");
551 // ordered to avoid possible integer overflow
552 if (src_offset > src.Length - count)
553 throw new ArgumentException ("Reading would overrun buffer");
555 throw new NotSupportedException ("Stream does not support writing");
558 IAsyncResult ares = BeginWrite (src, src_offset, count, null, null);
563 WriteInternal (src, src_offset, count);
566 void WriteInternal (byte [] src, int src_offset, int count)
568 if (count > buf_size) {
569 // shortcut for long writes
574 MonoIO.Write (handle, src, src_offset, count, out error);
575 if (error != MonoIOError.ERROR_SUCCESS) {
576 // don't leak the path information for isolated storage
577 string fname = (anonymous) ? Path.GetFileName (name) : name;
578 throw MonoIO.GetException (fname, error);
587 int n = WriteSegment (src, src_offset + copied, count);
600 delegate void WriteDelegate (byte [] buffer, int offset, int count);
602 public override IAsyncResult BeginWrite (byte [] buffer, int offset, int count,
603 AsyncCallback cback, object state)
605 if (handle == MonoIO.InvalidHandle)
606 throw new ObjectDisposedException ("Stream has been closed");
609 throw new NotSupportedException ("This stream does not support writing");
612 throw new ArgumentNullException ("buffer");
615 throw new ArgumentOutOfRangeException ("count", "Must be >= 0");
618 throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
620 // reordered to avoid possible integer overflow
621 if (count > buffer.Length - offset)
622 throw new ArgumentException ("Buffer too small. count/offset wrong.");
625 return base.BeginWrite (buffer, offset, count, cback, state);
629 FileStreamAsyncResult result = new FileStreamAsyncResult (cback, state);
630 result.BytesRead = -1;
631 result.Count = count;
632 result.OriginalCount = count;
635 MemoryStream ms = new MemoryStream ();
636 FlushBufferToStream (ms);
637 buffered = (int) ms.Length;
638 ms.Write (buffer, offset, count);
639 bytes = ms.GetBuffer ();
641 count = (int) ms.Length;
646 if (!MonoIO.SupportsAsync) {
647 WriteDelegate w = new WriteDelegate (WriteInternal);
648 return w.BeginInvoke (buffer, offset, count, cback, state);
651 if (buffered >= count) {
652 result.SetComplete (null, buffered, true);
656 result.Buffer = buffer;
657 result.Offset = offset;
658 result.Count = count;
660 KeepReference (result);
661 MonoIO.BeginWrite (handle, result);
666 public override void EndWrite (IAsyncResult async_result)
668 if (async_result == null)
669 throw new ArgumentNullException ("async_result");
672 base.EndWrite (async_result);
676 if (!MonoIO.SupportsAsync) {
677 AsyncResult ares = async_result as AsyncResult;
679 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
681 WriteDelegate w = ares.AsyncDelegate as WriteDelegate;
683 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
685 w.EndInvoke (async_result);
689 FileStreamAsyncResult result = async_result as FileStreamAsyncResult;
690 if (result == null || result.BytesRead != -1)
691 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
693 RemoveReference (result);
695 throw new InvalidOperationException ("EndWrite already called.");
698 if (!result.IsCompleted)
699 result.AsyncWaitHandle.WaitOne ();
701 if (result.Exception != null)
702 throw result.Exception;
704 buf_start += result.Count;
705 buf_offset = buf_length = 0;
708 public override long Seek (long offset, SeekOrigin origin)
712 if (handle == MonoIO.InvalidHandle)
713 throw new ObjectDisposedException ("Stream has been closed");
717 if(CanSeek == false) {
718 throw new NotSupportedException("The stream does not support seeking");
723 pos = Length + offset;
726 case SeekOrigin.Current:
727 pos = Position + offset;
730 case SeekOrigin.Begin:
735 throw new ArgumentException ("origin", "Invalid SeekOrigin");
739 /* LAMESPEC: shouldn't this be
740 * ArgumentOutOfRangeException?
742 throw new IOException("Attempted to Seek before the beginning of the stream");
745 if(pos < this.append_startpos) {
746 /* More undocumented crap */
747 throw new IOException("Can't seek back over pre-existing data in append mode");
750 if (buf_length > 0) {
751 if (pos >= buf_start &&
752 pos <= buf_start + buf_length) {
753 buf_offset = (int) (pos - buf_start);
762 buf_start = MonoIO.Seek (handle, pos,
766 if (error != MonoIOError.ERROR_SUCCESS) {
767 // don't leak the path information for isolated storage
768 string fname = (anonymous) ? Path.GetFileName (name) : name;
769 throw MonoIO.GetException (fname, error);
775 public override void SetLength (long length)
777 if (handle == MonoIO.InvalidHandle)
778 throw new ObjectDisposedException ("Stream has been closed");
781 throw new NotSupportedException("The stream does not support seeking");
783 if(CanWrite == false)
784 throw new NotSupportedException("The stream does not support writing");
787 throw new ArgumentOutOfRangeException("Length is less than 0");
793 MonoIO.SetLength (handle, length, out error);
794 if (error != MonoIOError.ERROR_SUCCESS) {
795 // don't leak the path information for isolated storage
796 string fname = (anonymous) ? Path.GetFileName (name) : name;
797 throw MonoIO.GetException (fname, error);
800 if (Position > length)
804 public override void Flush ()
806 if (handle == MonoIO.InvalidHandle)
807 throw new ObjectDisposedException ("Stream has been closed");
811 // The flushing is not actually required, in
812 //the mono runtime we were mapping flush to
813 //`fsync' which is not the same.
815 //MonoIO.Flush (handle);
818 public override void Close ()
821 GC.SuppressFinalize (this); // remove from finalize queue
824 public virtual void Lock (long position, long length)
826 if (handle == MonoIO.InvalidHandle)
827 throw new ObjectDisposedException ("Stream has been closed");
829 throw new ArgumentOutOfRangeException ("position must not be negative");
832 throw new ArgumentOutOfRangeException ("length must not be negative");
834 if (handle == MonoIO.InvalidHandle) {
835 throw new ObjectDisposedException ("Stream has been closed");
840 MonoIO.Lock (handle, position, length, out error);
841 if (error != MonoIOError.ERROR_SUCCESS) {
842 // don't leak the path information for isolated storage
843 string fname = (anonymous) ? Path.GetFileName (name) : name;
844 throw MonoIO.GetException (fname, error);
848 public virtual void Unlock (long position, long length)
850 if (handle == MonoIO.InvalidHandle)
851 throw new ObjectDisposedException ("Stream has been closed");
853 throw new ArgumentOutOfRangeException ("position must not be negative");
856 throw new ArgumentOutOfRangeException ("length must not be negative");
861 MonoIO.Unlock (handle, position, length, out error);
862 if (error != MonoIOError.ERROR_SUCCESS) {
863 // don't leak the path information for isolated storage
864 string fname = (anonymous) ? Path.GetFileName (name) : name;
865 throw MonoIO.GetException (fname, error);
876 protected virtual void Dispose (bool disposing) {
877 if (handle != MonoIO.InvalidHandle) {
883 MonoIO.Close (handle, out error);
884 if (error != MonoIOError.ERROR_SUCCESS) {
885 // don't leak the path information for isolated storage
886 string fname = (anonymous) ? Path.GetFileName (name) : name;
887 throw MonoIO.GetException (fname, error);
890 handle = MonoIO.InvalidHandle;
903 // ReadSegment, WriteSegment, FlushBuffer,
904 // RefillBuffer and ReadData should only be called
905 // when the Monitor lock is held, but these methods
906 // grab it again just to be safe.
908 private int ReadSegment (byte [] dest, int dest_offset, int count)
910 if (count > buf_length - buf_offset) {
911 count = buf_length - buf_offset;
915 Buffer.BlockCopy (buf, buf_offset,
924 private int WriteSegment (byte [] src, int src_offset,
927 if (count > buf_size - buf_offset) {
928 count = buf_size - buf_offset;
932 Buffer.BlockCopy (src, src_offset,
936 if (buf_offset > buf_length) {
937 buf_length = buf_offset;
946 void FlushBufferToStream (Stream st)
949 if (CanSeek == true) {
951 MonoIO.Seek (handle, buf_start,
954 if (error != MonoIOError.ERROR_SUCCESS) {
955 // don't leak the path information for isolated storage
956 string fname = (anonymous) ? Path.GetFileName (name) : name;
957 throw MonoIO.GetException (fname, error);
960 st.Write (buf, 0, buf_length);
963 buf_start += buf_offset;
964 buf_offset = buf_length = 0;
968 private void FlushBuffer ()
973 if (CanSeek == true) {
974 MonoIO.Seek (handle, buf_start,
977 if (error != MonoIOError.ERROR_SUCCESS) {
978 // don't leak the path information for isolated storage
979 string fname = (anonymous) ? Path.GetFileName (name) : name;
980 throw MonoIO.GetException (fname, error);
983 MonoIO.Write (handle, buf, 0,
984 buf_length, out error);
986 if (error != MonoIOError.ERROR_SUCCESS) {
987 // don't leak the path information for isolated storage
988 string fname = (anonymous) ? Path.GetFileName (name) : name;
989 throw MonoIO.GetException (fname, error);
993 buf_start += buf_offset;
994 buf_offset = buf_length = 0;
998 private void FlushBufferIfDirty ()
1004 private void RefillBuffer ()
1008 buf_length = ReadData (handle, buf, 0,
1012 private int ReadData (IntPtr handle, byte[] buf, int offset,
1018 /* when async == true, if we get here we don't suport AIO or it's disabled
1019 * and we're using the threadpool */
1020 amount = MonoIO.Read (handle, buf, offset, count, out error);
1021 if (error == MonoIOError.ERROR_BROKEN_PIPE) {
1022 amount = 0; // might not be needed, but well...
1023 } else if (error != MonoIOError.ERROR_SUCCESS) {
1024 // don't leak the path information for isolated storage
1025 string fname = (anonymous) ? Path.GetFileName (name) : name;
1026 throw MonoIO.GetException (fname, error);
1029 /* Check for read error */
1031 throw new IOException ();
1037 private void InitBuffer (int size, bool noBuffering)
1041 // We need a buffer for the ReadByte method. This buffer won't
1042 // be used for anything else since buf_size==0.
1047 throw new ArgumentOutOfRangeException ("bufferSize", "Positive number required.");
1050 buf = new byte [size];
1055 buf_offset = buf_length = 0;
1059 static void KeepReference (object o)
1061 lock (typeof (FileStream)) {
1062 if (asyncObjects == null)
1063 asyncObjects = new Hashtable ();
1065 asyncObjects [o] = o;
1069 static void RemoveReference (object o)
1071 lock (typeof (FileStream)) {
1072 if (asyncObjects == null)
1075 asyncObjects.Remove (o);
1081 internal const int DefaultBufferSize = 8192;
1082 private static Hashtable asyncObjects;
1084 private FileAccess access;
1087 private bool canseek;
1088 private long append_startpos;
1089 private bool anonymous;
1091 private byte [] buf; // the buffer
1092 private int buf_size; // capacity in bytes
1093 private int buf_length; // number of valid bytes in buffer
1094 private int buf_offset; // position of next byte
1095 private bool buf_dirty; // true if buffer has been written to
1096 private long buf_start; // location of buffer in file
1097 private string name = "[Unknown]"; // name of file.
1099 IntPtr handle; // handle to underlying file