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;
40 using Microsoft.Win32.SafeHandles;
42 using System.IO.IsolatedStorage;
43 using System.Security;
45 using System.Security.AccessControl;
51 public class FileStream : Stream
53 // construct from handle
55 [Obsolete ("Use FileStream(SafeFileHandle handle, FileAccess access) instead")]
56 public FileStream (IntPtr handle, FileAccess access)
57 : this (handle, access, true, DefaultBufferSize, false) {}
59 [Obsolete ("Use FileStream(SafeFileHandle handle, FileAccess access) instead")]
60 public FileStream (IntPtr handle, FileAccess access, bool ownsHandle)
61 : this (handle, access, ownsHandle, DefaultBufferSize, false) {}
63 [Obsolete ("Use FileStream(SafeFileHandle handle, FileAccess access, int bufferSize) instead")]
64 public FileStream (IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize)
65 : this (handle, access, ownsHandle, bufferSize, false) {}
67 [Obsolete ("Use FileStream(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync) instead")]
68 public FileStream (IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize, bool isAsync)
69 : this (handle, access, ownsHandle, bufferSize, isAsync, false) {}
71 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
72 internal FileStream (IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize, bool isAsync, bool noBuffering)
74 this.handle = MonoIO.InvalidHandle;
75 if (handle == this.handle)
76 throw new ArgumentException ("handle", Locale.GetText ("Invalid."));
78 if (access < FileAccess.Read || access > FileAccess.ReadWrite)
79 throw new ArgumentOutOfRangeException ("access");
82 MonoFileType ftype = MonoIO.GetFileType (handle, out error);
84 if (error != MonoIOError.ERROR_SUCCESS) {
85 throw MonoIO.GetException (name, error);
88 if (ftype == MonoFileType.Unknown) {
89 throw new IOException ("Invalid handle.");
90 } else if (ftype == MonoFileType.Disk) {
98 this.owner = ownsHandle;
100 #if NET_2_1 && !MONOTOUCH
101 // default the browser to 'all' anonymous files and let other usage (like smcs) with 'normal'
102 // (i.e. non-anonymous except for isolated storage) files and paths
103 this.anonymous = SecurityManager.SecurityEnabled;
105 this.anonymous = false;
108 InitBuffer (bufferSize, noBuffering);
111 buf_start = MonoIO.Seek (handle, 0, SeekOrigin.Current, out error);
112 if (error != MonoIOError.ERROR_SUCCESS) {
113 throw MonoIO.GetException (name, error);
117 /* Can't set append mode */
118 this.append_startpos=0;
121 // construct from filename
123 public FileStream (string path, FileMode mode)
124 : this (path, mode, (mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite), FileShare.Read, DefaultBufferSize, false, FileOptions.None)
128 public FileStream (string path, FileMode mode, FileAccess access)
129 : this (path, mode, access, access == FileAccess.Write ? FileShare.None : FileShare.Read, DefaultBufferSize, false, false)
133 public FileStream (string path, FileMode mode, FileAccess access, FileShare share)
134 : this (path, mode, access, share, DefaultBufferSize, false, FileOptions.None)
138 public FileStream (string path, FileMode mode, FileAccess access, FileShare share, int bufferSize)
139 : this (path, mode, access, share, bufferSize, false, FileOptions.None)
143 public FileStream (string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool useAsync)
144 : this (path, mode, access, share, bufferSize, useAsync, FileOptions.None)
149 public FileStream (string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options)
150 : this (path, mode, access, share, bufferSize, false, options)
154 public FileStream (SafeFileHandle handle, FileAccess access)
155 :this(handle, access, DefaultBufferSize, false)
159 public FileStream (SafeFileHandle handle, FileAccess access,
161 :this(handle, access, bufferSize, false)
165 [MonoLimitationAttribute("Need to use SafeFileHandle instead of underlying handle")]
166 public FileStream (SafeFileHandle handle, FileAccess access,
167 int bufferSize, bool isAsync)
168 :this (handle.DangerousGetHandle (), access, false, bufferSize, isAsync)
170 this.safeHandle = handle;
173 public FileStream (string path, FileMode mode,
174 FileSystemRights rights, FileShare share,
175 int bufferSize, FileOptions options)
177 throw new NotImplementedException ();
180 public FileStream (string path, FileMode mode,
181 FileSystemRights rights, FileShare share,
182 int bufferSize, FileOptions options,
183 FileSecurity fileSecurity)
185 throw new NotImplementedException ();
189 internal FileStream (string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool isAsync, bool anonymous)
190 : this (path, mode, access, share, bufferSize, anonymous, isAsync ? FileOptions.Asynchronous : FileOptions.None)
194 internal FileStream (string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool anonymous, FileOptions options)
197 throw new ArgumentNullException ("path");
200 if (path.Length == 0) {
201 throw new ArgumentException ("Path is empty");
204 // ignore the Inheritable flag
205 share &= ~FileShare.Inheritable;
208 throw new ArgumentOutOfRangeException ("bufferSize", "Positive number required.");
210 if (mode < FileMode.CreateNew || mode > FileMode.Append) {
213 throw new ArgumentException ("mode", "Enum value was out of legal range.");
216 throw new ArgumentOutOfRangeException ("mode", "Enum value was out of legal range.");
219 if (access < FileAccess.Read || access > FileAccess.ReadWrite) {
222 throw new IsolatedStorageException ("Enum value for FileAccess was out of legal range.");
225 throw new ArgumentOutOfRangeException ("access", "Enum value was out of legal range.");
228 if (share < FileShare.None || share > (FileShare.ReadWrite | FileShare.Delete)) {
231 throw new IsolatedStorageException ("Enum value for FileShare was out of legal range.");
234 throw new ArgumentOutOfRangeException ("share", "Enum value was out of legal range.");
237 if (path.IndexOfAny (Path.InvalidPathChars) != -1) {
238 throw new ArgumentException ("Name has invalid chars");
241 if (Directory.Exists (path)) {
242 // don't leak the path information for isolated storage
243 string msg = Locale.GetText ("Access to the path '{0}' is denied.");
244 throw new UnauthorizedAccessException (String.Format (msg, GetSecureFileName (path, false)));
247 /* Append streams can't be read (see FileMode
250 if (mode==FileMode.Append &&
251 (access&FileAccess.Read)==FileAccess.Read) {
252 throw new ArgumentException("Append access can be requested only in write-only mode.");
255 if ((access & FileAccess.Write) == 0 &&
256 (mode != FileMode.Open && mode != FileMode.OpenOrCreate)) {
257 string msg = Locale.GetText ("Combining FileMode: {0} with " +
258 "FileAccess: {1} is invalid.");
259 throw new ArgumentException (string.Format (msg, access, mode));
262 string dname = Path.GetDirectoryName (path);
263 if (dname.Length > 0) {
264 string fp = Path.GetFullPath (dname);
265 if (!Directory.Exists (fp)) {
266 // don't leak the path information for isolated storage
267 string msg = Locale.GetText ("Could not find a part of the path \"{0}\".");
268 string fname = (anonymous) ? dname : Path.GetFullPath (path);
270 // don't use GetSecureFileName for the directory name
271 throw new IsolatedStorageException (String.Format (msg, fname));
273 throw new DirectoryNotFoundException (String.Format (msg, fname));
278 if (access == FileAccess.Read && mode != FileMode.Create && mode != FileMode.OpenOrCreate &&
279 mode != FileMode.CreateNew && !File.Exists (path)) {
280 // don't leak the path information for isolated storage
281 string msg = Locale.GetText ("Could not find file \"{0}\".");
282 string fname = GetSecureFileName (path);
284 throw new IsolatedStorageException (String.Format (msg, fname));
286 throw new FileNotFoundException (String.Format (msg, fname), fname);
290 // IsolatedStorage needs to keep the Name property to the default "[Unknown]"
294 // TODO: demand permissions
298 this.handle = MonoIO.Open (path, mode, access, share, options, out error);
299 if (handle == MonoIO.InvalidHandle) {
300 // don't leak the path information for isolated storage
301 throw MonoIO.GetException (GetSecureFileName (path), error);
304 this.access = access;
306 this.anonymous = anonymous;
308 /* Can we open non-files by name? */
310 if (MonoIO.GetFileType (handle, out error) == MonoFileType.Disk) {
312 this.async = (options & FileOptions.Asynchronous) != 0;
314 this.canseek = false;
319 if (access == FileAccess.Read && canseek && (bufferSize == DefaultBufferSize)) {
320 /* Avoid allocating a large buffer for small files */
322 if (bufferSize > len) {
323 bufferSize = (int)(len < 1000 ? 1000 : len);
327 InitBuffer (bufferSize, false);
329 if (mode==FileMode.Append) {
330 this.Seek (0, SeekOrigin.End);
331 this.append_startpos=this.Position;
333 this.append_startpos=0;
339 public override bool CanRead {
341 return access == FileAccess.Read ||
342 access == FileAccess.ReadWrite;
346 public override bool CanWrite {
348 return access == FileAccess.Write ||
349 access == FileAccess.ReadWrite;
353 public override bool CanSeek {
359 public virtual bool IsAsync {
371 public override long Length {
373 if (handle == MonoIO.InvalidHandle)
374 throw new ObjectDisposedException ("Stream has been closed");
377 throw new NotSupportedException ("The stream does not support seeking");
379 // Buffered data might change the length of the stream
380 FlushBufferIfDirty ();
385 length = MonoIO.GetLength (handle, out error);
386 if (error != MonoIOError.ERROR_SUCCESS) {
387 // don't leak the path information for isolated storage
388 throw MonoIO.GetException (GetSecureFileName (name), error);
395 public override long Position {
397 if (handle == MonoIO.InvalidHandle)
398 throw new ObjectDisposedException ("Stream has been closed");
401 throw new NotSupportedException("The stream does not support seeking");
403 return(buf_start + buf_offset);
406 if (handle == MonoIO.InvalidHandle)
407 throw new ObjectDisposedException ("Stream has been closed");
409 if(CanSeek == false) {
410 throw new NotSupportedException("The stream does not support seeking");
414 throw new ArgumentOutOfRangeException("Attempt to set the position to a negative value");
417 Seek (value, SeekOrigin.Begin);
421 [Obsolete ("Use SafeFileHandle instead")]
422 public virtual IntPtr Handle {
423 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
424 [SecurityPermission (SecurityAction.InheritanceDemand, UnmanagedCode = true)]
430 public virtual SafeFileHandle SafeFileHandle {
431 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
432 [SecurityPermission (SecurityAction.InheritanceDemand, UnmanagedCode = true)]
436 if (safeHandle != null)
439 ret = new SafeFileHandle (handle, owner);
448 public override int ReadByte ()
450 if (handle == MonoIO.InvalidHandle)
451 throw new ObjectDisposedException ("Stream has been closed");
454 throw new NotSupportedException ("Stream does not support reading");
457 int n = ReadData (handle, buf, 0, 1);
458 if (n == 0) return -1;
461 else if (buf_offset >= buf_length) {
468 return buf [buf_offset ++];
471 public override void WriteByte (byte value)
473 if (handle == MonoIO.InvalidHandle)
474 throw new ObjectDisposedException ("Stream has been closed");
477 throw new NotSupportedException ("Stream does not support writing");
479 if (buf_offset == buf_size)
482 if (buf_size == 0) { // No buffering
490 buf [buf_offset ++] = value;
491 if (buf_offset > buf_length)
492 buf_length = buf_offset;
497 public override int Read ([In,Out] byte[] array, int offset, int count)
499 if (handle == MonoIO.InvalidHandle)
500 throw new ObjectDisposedException ("Stream has been closed");
502 throw new ArgumentNullException ("array");
504 throw new NotSupportedException ("Stream does not support reading");
505 int len = array.Length;
507 throw new ArgumentOutOfRangeException ("offset", "< 0");
509 throw new ArgumentOutOfRangeException ("count", "< 0");
511 throw new ArgumentException ("destination offset is beyond array size");
512 // reordered to avoid possible integer overflow
513 if (offset > len - count)
514 throw new ArgumentException ("Reading would overrun buffer");
517 IAsyncResult ares = BeginRead (array, offset, count, null, null);
518 return EndRead (ares);
521 return ReadInternal (array, offset, count);
524 int ReadInternal (byte [] dest, int offset, int count)
528 int n = ReadSegment (dest, offset, count);
533 /* If there was already enough
534 * buffered, no need to read
535 * more from the file.
540 if (count > buf_size) {
541 /* Read as much as we can, up
545 n = ReadData (handle, dest,
549 /* Make the next buffer read
550 * start from the right place
555 n = ReadSegment (dest,
565 delegate int ReadDelegate (byte [] buffer, int offset, int count);
567 public override IAsyncResult BeginRead (byte [] array, int offset, int numBytes,
568 AsyncCallback userCallback, object stateObject)
570 if (handle == MonoIO.InvalidHandle)
571 throw new ObjectDisposedException ("Stream has been closed");
574 throw new NotSupportedException ("This stream does not support reading");
577 throw new ArgumentNullException ("array");
580 throw new ArgumentOutOfRangeException ("numBytes", "Must be >= 0");
583 throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
585 // reordered to avoid possible integer overflow
586 if (numBytes > array.Length - offset)
587 throw new ArgumentException ("Buffer too small. numBytes/offset wrong.");
590 return base.BeginRead (array, offset, numBytes, userCallback, stateObject);
592 ReadDelegate r = new ReadDelegate (ReadInternal);
593 return r.BeginInvoke (array, offset, numBytes, userCallback, stateObject);
596 public override int EndRead (IAsyncResult asyncResult)
598 if (asyncResult == null)
599 throw new ArgumentNullException ("asyncResult");
602 return base.EndRead (asyncResult);
604 AsyncResult ares = asyncResult as AsyncResult;
606 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
608 ReadDelegate r = ares.AsyncDelegate as ReadDelegate;
610 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
612 return r.EndInvoke (asyncResult);
615 public override void Write (byte[] array, int offset, int count)
617 if (handle == MonoIO.InvalidHandle)
618 throw new ObjectDisposedException ("Stream has been closed");
620 throw new ArgumentNullException ("array");
622 throw new ArgumentOutOfRangeException ("offset", "< 0");
624 throw new ArgumentOutOfRangeException ("count", "< 0");
625 // ordered to avoid possible integer overflow
626 if (offset > array.Length - count)
627 throw new ArgumentException ("Reading would overrun buffer");
629 throw new NotSupportedException ("Stream does not support writing");
632 IAsyncResult ares = BeginWrite (array, offset, count, null, null);
637 WriteInternal (array, offset, count);
640 void WriteInternal (byte [] src, int offset, int count)
642 if (count > buf_size) {
643 // shortcut for long writes
650 int n = MonoIO.Write (handle, src, offset, wcount, out error);
651 if (error != MonoIOError.ERROR_SUCCESS)
652 throw MonoIO.GetException (GetSecureFileName (name), error);
663 int n = WriteSegment (src, offset + copied, count);
676 delegate void WriteDelegate (byte [] buffer, int offset, int count);
678 public override IAsyncResult BeginWrite (byte [] array, int offset, int numBytes,
679 AsyncCallback userCallback, object stateObject)
681 if (handle == MonoIO.InvalidHandle)
682 throw new ObjectDisposedException ("Stream has been closed");
685 throw new NotSupportedException ("This stream does not support writing");
688 throw new ArgumentNullException ("array");
691 throw new ArgumentOutOfRangeException ("numBytes", "Must be >= 0");
694 throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
696 // reordered to avoid possible integer overflow
697 if (numBytes > array.Length - offset)
698 throw new ArgumentException ("array too small. numBytes/offset wrong.");
701 return base.BeginWrite (array, offset, numBytes, userCallback, stateObject);
703 FileStreamAsyncResult result = new FileStreamAsyncResult (userCallback, stateObject);
704 result.BytesRead = -1;
705 result.Count = numBytes;
706 result.OriginalCount = numBytes;
709 MemoryStream ms = new MemoryStream ();
711 ms.Write (array, offset, numBytes);
713 numBytes = (int) ms.Length;
716 WriteDelegate w = new WriteDelegate (WriteInternal);
717 return w.BeginInvoke (array, offset, numBytes, userCallback, stateObject);
720 public override void EndWrite (IAsyncResult asyncResult)
722 if (asyncResult == null)
723 throw new ArgumentNullException ("asyncResult");
726 base.EndWrite (asyncResult);
730 AsyncResult ares = asyncResult as AsyncResult;
732 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
734 WriteDelegate w = ares.AsyncDelegate as WriteDelegate;
736 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
738 w.EndInvoke (asyncResult);
742 public override long Seek (long offset, SeekOrigin origin)
746 if (handle == MonoIO.InvalidHandle)
747 throw new ObjectDisposedException ("Stream has been closed");
751 if(CanSeek == false) {
752 throw new NotSupportedException("The stream does not support seeking");
757 pos = Length + offset;
760 case SeekOrigin.Current:
761 pos = Position + offset;
764 case SeekOrigin.Begin:
769 throw new ArgumentException ("origin", "Invalid SeekOrigin");
773 /* LAMESPEC: shouldn't this be
774 * ArgumentOutOfRangeException?
776 throw new IOException("Attempted to Seek before the beginning of the stream");
779 if(pos < this.append_startpos) {
780 /* More undocumented crap */
781 throw new IOException("Can't seek back over pre-existing data in append mode");
788 buf_start = MonoIO.Seek (handle, pos,
792 if (error != MonoIOError.ERROR_SUCCESS) {
793 // don't leak the path information for isolated storage
794 throw MonoIO.GetException (GetSecureFileName (name), error);
800 public override void SetLength (long value)
802 if (handle == MonoIO.InvalidHandle)
803 throw new ObjectDisposedException ("Stream has been closed");
806 throw new NotSupportedException("The stream does not support seeking");
808 if(CanWrite == false)
809 throw new NotSupportedException("The stream does not support writing");
812 throw new ArgumentOutOfRangeException("value is less than 0");
818 MonoIO.SetLength (handle, value, out error);
819 if (error != MonoIOError.ERROR_SUCCESS) {
820 // don't leak the path information for isolated storage
821 throw MonoIO.GetException (GetSecureFileName (name), error);
824 if (Position > value)
828 public override void Flush ()
830 if (handle == MonoIO.InvalidHandle)
831 throw new ObjectDisposedException ("Stream has been closed");
835 // The flushing is not actually required, in
836 //the mono runtime we were mapping flush to
837 //`fsync' which is not the same.
839 //MonoIO.Flush (handle);
842 public virtual void Lock (long position, long length)
844 if (handle == MonoIO.InvalidHandle)
845 throw new ObjectDisposedException ("Stream has been closed");
847 throw new ArgumentOutOfRangeException ("position must not be negative");
850 throw new ArgumentOutOfRangeException ("length must not be negative");
852 if (handle == MonoIO.InvalidHandle) {
853 throw new ObjectDisposedException ("Stream has been closed");
858 MonoIO.Lock (handle, position, length, out error);
859 if (error != MonoIOError.ERROR_SUCCESS) {
860 // don't leak the path information for isolated storage
861 throw MonoIO.GetException (GetSecureFileName (name), error);
865 public virtual void Unlock (long position, long length)
867 if (handle == MonoIO.InvalidHandle)
868 throw new ObjectDisposedException ("Stream has been closed");
870 throw new ArgumentOutOfRangeException ("position must not be negative");
873 throw new ArgumentOutOfRangeException ("length must not be negative");
878 MonoIO.Unlock (handle, position, length, out error);
879 if (error != MonoIOError.ERROR_SUCCESS) {
880 // don't leak the path information for isolated storage
881 throw MonoIO.GetException (GetSecureFileName (name), error);
892 protected override void Dispose (bool disposing)
894 if (handle != MonoIO.InvalidHandle) {
900 MonoIO.Close (handle, out error);
901 if (error != MonoIOError.ERROR_SUCCESS) {
902 // don't leak the path information for isolated storage
903 throw MonoIO.GetException (GetSecureFileName (name), error);
906 handle = MonoIO.InvalidHandle;
916 GC.SuppressFinalize (this);
920 public FileSecurity GetAccessControl ()
922 throw new NotImplementedException ();
925 public void SetAccessControl (FileSecurity fileSecurity)
927 throw new NotImplementedException ();
933 // ReadSegment, WriteSegment, FlushBuffer,
934 // RefillBuffer and ReadData should only be called
935 // when the Monitor lock is held, but these methods
936 // grab it again just to be safe.
938 private int ReadSegment (byte [] dest, int dest_offset, int count)
940 if (count > buf_length - buf_offset) {
941 count = buf_length - buf_offset;
945 Buffer.BlockCopy (buf, buf_offset,
954 private int WriteSegment (byte [] src, int src_offset,
957 if (count > buf_size - buf_offset) {
958 count = buf_size - buf_offset;
962 Buffer.BlockCopy (src, src_offset,
966 if (buf_offset > buf_length) {
967 buf_length = buf_offset;
976 void FlushBuffer (Stream st)
981 if (CanSeek == true) {
982 MonoIO.Seek (handle, buf_start,
985 if (error != MonoIOError.ERROR_SUCCESS) {
986 // don't leak the path information for isolated storage
987 throw MonoIO.GetException (GetSecureFileName (name), error);
991 int wcount = buf_length;
994 int n = MonoIO.Write (handle, buf, 0, buf_length, out error);
995 if (error != MonoIOError.ERROR_SUCCESS) {
996 // don't leak the path information for isolated storage
997 throw MonoIO.GetException (GetSecureFileName (name), error);
1003 st.Write (buf, 0, buf_length);
1007 buf_start += buf_offset;
1008 buf_offset = buf_length = 0;
1012 private void FlushBuffer ()
1017 private void FlushBufferIfDirty ()
1023 private void RefillBuffer ()
1027 buf_length = ReadData (handle, buf, 0,
1031 private int ReadData (IntPtr handle, byte[] buf, int offset,
1037 /* when async == true, if we get here we don't suport AIO or it's disabled
1038 * and we're using the threadpool */
1039 amount = MonoIO.Read (handle, buf, offset, count, out error);
1040 if (error == MonoIOError.ERROR_BROKEN_PIPE) {
1041 amount = 0; // might not be needed, but well...
1042 } else if (error != MonoIOError.ERROR_SUCCESS) {
1043 // don't leak the path information for isolated storage
1044 throw MonoIO.GetException (GetSecureFileName (name), error);
1047 /* Check for read error */
1049 throw new IOException ();
1055 private void InitBuffer (int size, bool noBuffering)
1059 // We need a buffer for the ReadByte method. This buffer won't
1060 // be used for anything else since buf_size==0.
1065 throw new ArgumentOutOfRangeException ("bufferSize", "Positive number required.");
1068 buf = new byte [size];
1073 buf_offset = buf_length = 0;
1077 private string GetSecureFileName (string filename)
1079 return (anonymous) ? Path.GetFileName (filename) : Path.GetFullPath (filename);
1082 private string GetSecureFileName (string filename, bool full)
1084 return (anonymous) ? Path.GetFileName (filename) :
1085 (full) ? Path.GetFullPath (filename) : filename;
1090 internal const int DefaultBufferSize = 8192;
1092 private FileAccess access;
1095 private bool canseek;
1096 private long append_startpos;
1097 private bool anonymous;
1099 private byte [] buf; // the buffer
1100 private int buf_size; // capacity in bytes
1101 private int buf_length; // number of valid bytes in buffer
1102 private int buf_offset; // position of next byte
1103 private bool buf_dirty; // true if buffer has been written to
1104 private long buf_start; // location of buffer in file
1105 private string name = "[Unknown]"; // name of file.
1107 IntPtr handle; // handle to underlying file
1108 SafeFileHandle safeHandle; // set only when using one of the
1109 // constructors taking SafeFileHandle