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)
8 // Marek Safar (marek.safar@gmail.com)
10 // (C) 2001-2003 Ximian, Inc. http://www.ximian.com
11 // Copyright (C) 2004-2005, 2008, 2010 Novell, Inc (http://www.novell.com)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // 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.Security;
39 using System.Security.Permissions;
40 using System.Threading;
42 using Microsoft.Win32.SafeHandles;
44 using System.IO.IsolatedStorage;
46 using System.Security.AccessControl;
52 public class FileStream : Stream
54 // construct from handle
56 [Obsolete ("Use FileStream(SafeFileHandle handle, FileAccess access) instead")]
57 public FileStream (IntPtr handle, FileAccess access)
58 : this (handle, access, true, DefaultBufferSize, false) {}
60 [Obsolete ("Use FileStream(SafeFileHandle handle, FileAccess access) instead")]
61 public FileStream (IntPtr handle, FileAccess access, bool ownsHandle)
62 : this (handle, access, ownsHandle, DefaultBufferSize, false) {}
64 [Obsolete ("Use FileStream(SafeFileHandle handle, FileAccess access, int bufferSize) instead")]
65 public FileStream (IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize)
66 : this (handle, access, ownsHandle, bufferSize, false) {}
68 [Obsolete ("Use FileStream(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync) instead")]
69 public FileStream (IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize, bool isAsync)
70 : this (handle, access, ownsHandle, bufferSize, isAsync, false) {}
72 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
73 internal FileStream (IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize, bool isAsync, bool isZeroSize)
75 this.handle = MonoIO.InvalidHandle;
76 if (handle == this.handle)
77 throw new ArgumentException ("handle", Locale.GetText ("Invalid."));
79 if (access < FileAccess.Read || access > FileAccess.ReadWrite)
80 throw new ArgumentOutOfRangeException ("access");
83 MonoFileType ftype = MonoIO.GetFileType (handle, out error);
85 if (error != MonoIOError.ERROR_SUCCESS) {
86 throw MonoIO.GetException (name, error);
89 if (ftype == MonoFileType.Unknown) {
90 throw new IOException ("Invalid handle.");
91 } else if (ftype == MonoFileType.Disk) {
99 this.owner = ownsHandle;
100 this.async = isAsync;
102 // default the browser to 'all' anonymous files and let other usage (like smcs) with 'normal'
103 // (i.e. non-anonymous except for isolated storage) files and paths
104 this.anonymous = SecurityManager.SecurityEnabled;
106 this.anonymous = false;
111 InitBuffer (bufferSize);
114 buf_start = MonoIO.Seek (handle, 0, SeekOrigin.Current, out error);
115 if (error != MonoIOError.ERROR_SUCCESS) {
116 throw MonoIO.GetException (name, error);
120 /* Can't set append mode */
121 this.append_startpos=0;
124 // construct from filename
126 public FileStream (string path, FileMode mode)
127 : this (path, mode, (mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite), FileShare.Read, DefaultBufferSize, false, FileOptions.None)
131 public FileStream (string path, FileMode mode, FileAccess access)
132 : this (path, mode, access, access == FileAccess.Write ? FileShare.None : FileShare.Read, DefaultBufferSize, false, false)
136 public FileStream (string path, FileMode mode, FileAccess access, FileShare share)
137 : this (path, mode, access, share, DefaultBufferSize, false, FileOptions.None)
141 public FileStream (string path, FileMode mode, FileAccess access, FileShare share, int bufferSize)
142 : this (path, mode, access, share, bufferSize, false, FileOptions.None)
146 public FileStream (string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool useAsync)
147 : this (path, mode, access, share, bufferSize, useAsync, FileOptions.None)
152 public FileStream (string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options)
153 : this (path, mode, access, share, bufferSize, false, options)
157 public FileStream (SafeFileHandle handle, FileAccess access)
158 :this(handle, access, DefaultBufferSize, false)
162 public FileStream (SafeFileHandle handle, FileAccess access,
164 :this(handle, access, bufferSize, false)
168 [MonoLimitationAttribute("Need to use SafeFileHandle instead of underlying handle")]
169 public FileStream (SafeFileHandle handle, FileAccess access,
170 int bufferSize, bool isAsync)
171 :this (handle.DangerousGetHandle (), access, false, bufferSize, isAsync)
173 this.safeHandle = handle;
176 [MonoLimitation ("This ignores the rights parameter")]
177 public FileStream (string path, FileMode mode,
178 FileSystemRights rights, FileShare share,
179 int bufferSize, FileOptions options)
180 : this (path, mode, (mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite), share, bufferSize, false, options)
184 [MonoLimitation ("This ignores the rights and fileSecurity parameters")]
185 public FileStream (string path, FileMode mode,
186 FileSystemRights rights, FileShare share,
187 int bufferSize, FileOptions options,
188 FileSecurity fileSecurity)
189 : this (path, mode, (mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite), share, bufferSize, false, options)
194 internal FileStream (string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool isAsync, bool anonymous)
195 : this (path, mode, access, share, bufferSize, anonymous, isAsync ? FileOptions.Asynchronous : FileOptions.None)
199 internal FileStream (string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool anonymous, FileOptions options)
202 throw new ArgumentNullException ("path");
205 if (path.Length == 0) {
206 throw new ArgumentException ("Path is empty");
209 // ignore the Inheritable flag
210 share &= ~FileShare.Inheritable;
213 throw new ArgumentOutOfRangeException ("bufferSize", "Positive number required.");
215 if (mode < FileMode.CreateNew || mode > FileMode.Append) {
218 throw new ArgumentException ("mode", "Enum value was out of legal range.");
221 throw new ArgumentOutOfRangeException ("mode", "Enum value was out of legal range.");
224 if (access < FileAccess.Read || access > FileAccess.ReadWrite) {
227 throw new IsolatedStorageException ("Enum value for FileAccess was out of legal range.");
230 throw new ArgumentOutOfRangeException ("access", "Enum value was out of legal range.");
233 if (share < FileShare.None || share > (FileShare.ReadWrite | FileShare.Delete)) {
236 throw new IsolatedStorageException ("Enum value for FileShare was out of legal range.");
239 throw new ArgumentOutOfRangeException ("share", "Enum value was out of legal range.");
242 if (path.IndexOfAny (Path.InvalidPathChars) != -1) {
243 throw new ArgumentException ("Name has invalid chars");
246 if (Directory.Exists (path)) {
247 // don't leak the path information for isolated storage
248 string msg = Locale.GetText ("Access to the path '{0}' is denied.");
249 throw new UnauthorizedAccessException (String.Format (msg, GetSecureFileName (path, false)));
252 /* Append streams can't be read (see FileMode
255 if (mode==FileMode.Append &&
256 (access&FileAccess.Read)==FileAccess.Read) {
257 throw new ArgumentException("Append access can be requested only in write-only mode.");
260 if ((access & FileAccess.Write) == 0 &&
261 (mode != FileMode.Open && mode != FileMode.OpenOrCreate)) {
262 string msg = Locale.GetText ("Combining FileMode: {0} with " +
263 "FileAccess: {1} is invalid.");
264 throw new ArgumentException (string.Format (msg, access, mode));
267 SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
269 string dname = Path.GetDirectoryName (path);
270 if (dname.Length > 0) {
271 string fp = Path.GetFullPath (dname);
272 if (!Directory.Exists (fp)) {
273 // don't leak the path information for isolated storage
274 string msg = Locale.GetText ("Could not find a part of the path \"{0}\".");
275 string fname = (anonymous) ? dname : Path.GetFullPath (path);
277 // don't use GetSecureFileName for the directory name
278 throw new IsolatedStorageException (String.Format (msg, fname));
280 throw new DirectoryNotFoundException (String.Format (msg, fname));
285 if (access == FileAccess.Read && mode != FileMode.Create && mode != FileMode.OpenOrCreate &&
286 mode != FileMode.CreateNew && !File.Exists (path)) {
287 // don't leak the path information for isolated storage
288 string msg = Locale.GetText ("Could not find file \"{0}\".");
289 string fname = GetSecureFileName (path);
291 throw new IsolatedStorageException (String.Format (msg, fname));
293 throw new FileNotFoundException (String.Format (msg, fname), fname);
297 // IsolatedStorage needs to keep the Name property to the default "[Unknown]"
301 // TODO: demand permissions
305 this.handle = MonoIO.Open (path, mode, access, share, options, out error);
306 if (handle == MonoIO.InvalidHandle) {
307 // don't leak the path information for isolated storage
308 throw MonoIO.GetException (GetSecureFileName (path), error);
311 this.access = access;
313 this.anonymous = anonymous;
315 /* Can we open non-files by name? */
317 if (MonoIO.GetFileType (handle, out error) == MonoFileType.Disk) {
319 this.async = (options & FileOptions.Asynchronous) != 0;
321 this.canseek = false;
326 if (access == FileAccess.Read && canseek && (bufferSize == DefaultBufferSize)) {
327 /* Avoid allocating a large buffer for small files */
329 if (bufferSize > len) {
330 bufferSize = (int)(len < 1000 ? 1000 : len);
334 InitBuffer (bufferSize);
336 if (mode==FileMode.Append) {
337 this.Seek (0, SeekOrigin.End);
338 this.append_startpos=this.Position;
340 this.append_startpos=0;
346 public override bool CanRead {
348 return access == FileAccess.Read ||
349 access == FileAccess.ReadWrite;
353 public override bool CanWrite {
355 return access == FileAccess.Write ||
356 access == FileAccess.ReadWrite;
360 public override bool CanSeek {
366 public virtual bool IsAsync {
375 return SecurityManager.CheckElevatedPermissions () ? name : "[Unknown]";
382 public override long Length {
384 if (handle == MonoIO.InvalidHandle)
385 throw new ObjectDisposedException ("Stream has been closed");
388 throw new NotSupportedException ("The stream does not support seeking");
390 // Buffered data might change the length of the stream
391 FlushBufferIfDirty ();
396 length = MonoIO.GetLength (handle, out error);
397 if (error != MonoIOError.ERROR_SUCCESS) {
398 // don't leak the path information for isolated storage
399 throw MonoIO.GetException (GetSecureFileName (name), error);
406 public override long Position {
408 if (handle == MonoIO.InvalidHandle)
409 throw new ObjectDisposedException ("Stream has been closed");
412 throw new NotSupportedException("The stream does not support seeking");
414 return(buf_start + buf_offset);
417 if (handle == MonoIO.InvalidHandle)
418 throw new ObjectDisposedException ("Stream has been closed");
420 if(CanSeek == false) {
421 throw new NotSupportedException("The stream does not support seeking");
425 throw new ArgumentOutOfRangeException("Attempt to set the position to a negative value");
428 Seek (value, SeekOrigin.Begin);
432 [Obsolete ("Use SafeFileHandle instead")]
433 public virtual IntPtr Handle {
434 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
435 [SecurityPermission (SecurityAction.InheritanceDemand, UnmanagedCode = true)]
441 public virtual SafeFileHandle SafeFileHandle {
442 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
443 [SecurityPermission (SecurityAction.InheritanceDemand, UnmanagedCode = true)]
447 if (safeHandle != null)
450 ret = new SafeFileHandle (handle, owner);
459 public override int ReadByte ()
461 if (handle == MonoIO.InvalidHandle)
462 throw new ObjectDisposedException ("Stream has been closed");
465 throw new NotSupportedException ("Stream does not support reading");
468 int n = ReadData (handle, buf, 0, 1);
469 if (n == 0) return -1;
472 else if (buf_offset >= buf_length) {
479 return buf [buf_offset ++];
482 public override void WriteByte (byte value)
484 if (handle == MonoIO.InvalidHandle)
485 throw new ObjectDisposedException ("Stream has been closed");
488 throw new NotSupportedException ("Stream does not support writing");
490 if (buf_offset == buf_size)
493 if (buf_size == 0) { // No buffering
501 buf [buf_offset ++] = value;
502 if (buf_offset > buf_length)
503 buf_length = buf_offset;
508 public override int Read ([In,Out] byte[] array, int offset, int count)
510 if (handle == MonoIO.InvalidHandle)
511 throw new ObjectDisposedException ("Stream has been closed");
513 throw new ArgumentNullException ("array");
515 throw new NotSupportedException ("Stream does not support reading");
516 int len = array.Length;
518 throw new ArgumentOutOfRangeException ("offset", "< 0");
520 throw new ArgumentOutOfRangeException ("count", "< 0");
522 throw new ArgumentException ("destination offset is beyond array size");
523 // reordered to avoid possible integer overflow
524 if (offset > len - count)
525 throw new ArgumentException ("Reading would overrun buffer");
528 IAsyncResult ares = BeginRead (array, offset, count, null, null);
529 return EndRead (ares);
532 return ReadInternal (array, offset, count);
535 int ReadInternal (byte [] dest, int offset, int count)
539 int n = ReadSegment (dest, offset, count);
544 /* If there was already enough
545 * buffered, no need to read
546 * more from the file.
551 if (count > buf_size) {
552 /* Read as much as we can, up
556 n = ReadData (handle, dest,
560 /* Make the next buffer read
561 * start from the right place
566 n = ReadSegment (dest,
576 delegate int ReadDelegate (byte [] buffer, int offset, int count);
578 public override IAsyncResult BeginRead (byte [] array, int offset, int numBytes,
579 AsyncCallback userCallback, object stateObject)
581 if (handle == MonoIO.InvalidHandle)
582 throw new ObjectDisposedException ("Stream has been closed");
585 throw new NotSupportedException ("This stream does not support reading");
588 throw new ArgumentNullException ("array");
591 throw new ArgumentOutOfRangeException ("numBytes", "Must be >= 0");
594 throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
596 // reordered to avoid possible integer overflow
597 if (numBytes > array.Length - offset)
598 throw new ArgumentException ("Buffer too small. numBytes/offset wrong.");
601 return base.BeginRead (array, offset, numBytes, userCallback, stateObject);
603 ReadDelegate r = new ReadDelegate (ReadInternal);
604 return r.BeginInvoke (array, offset, numBytes, userCallback, stateObject);
607 public override int EndRead (IAsyncResult asyncResult)
609 if (asyncResult == null)
610 throw new ArgumentNullException ("asyncResult");
613 return base.EndRead (asyncResult);
615 AsyncResult ares = asyncResult as AsyncResult;
617 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
619 ReadDelegate r = ares.AsyncDelegate as ReadDelegate;
621 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
623 return r.EndInvoke (asyncResult);
626 public override void Write (byte[] array, int offset, int count)
628 if (handle == MonoIO.InvalidHandle)
629 throw new ObjectDisposedException ("Stream has been closed");
631 throw new ArgumentNullException ("array");
633 throw new ArgumentOutOfRangeException ("offset", "< 0");
635 throw new ArgumentOutOfRangeException ("count", "< 0");
636 // ordered to avoid possible integer overflow
637 if (offset > array.Length - count)
638 throw new ArgumentException ("Reading would overrun buffer");
640 throw new NotSupportedException ("Stream does not support writing");
643 IAsyncResult ares = BeginWrite (array, offset, count, null, null);
648 WriteInternal (array, offset, count);
651 void WriteInternal (byte [] src, int offset, int count)
653 if (count > buf_size) {
654 // shortcut for long writes
661 int n = MonoIO.Write (handle, src, offset, wcount, out error);
662 if (error != MonoIOError.ERROR_SUCCESS)
663 throw MonoIO.GetException (GetSecureFileName (name), error);
674 int n = WriteSegment (src, offset + copied, count);
687 delegate void WriteDelegate (byte [] buffer, int offset, int count);
689 public override IAsyncResult BeginWrite (byte [] array, int offset, int numBytes,
690 AsyncCallback userCallback, object stateObject)
692 if (handle == MonoIO.InvalidHandle)
693 throw new ObjectDisposedException ("Stream has been closed");
696 throw new NotSupportedException ("This stream does not support writing");
699 throw new ArgumentNullException ("array");
702 throw new ArgumentOutOfRangeException ("numBytes", "Must be >= 0");
705 throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
707 // reordered to avoid possible integer overflow
708 if (numBytes > array.Length - offset)
709 throw new ArgumentException ("array too small. numBytes/offset wrong.");
712 return base.BeginWrite (array, offset, numBytes, userCallback, stateObject);
714 FileStreamAsyncResult result = new FileStreamAsyncResult (userCallback, stateObject);
715 result.BytesRead = -1;
716 result.Count = numBytes;
717 result.OriginalCount = numBytes;
720 MemoryStream ms = new MemoryStream ();
722 ms.Write (array, offset, numBytes);
724 numBytes = (int) ms.Length;
727 WriteDelegate w = new WriteDelegate (WriteInternal);
728 return w.BeginInvoke (array, offset, numBytes, userCallback, stateObject);
731 public override void EndWrite (IAsyncResult asyncResult)
733 if (asyncResult == null)
734 throw new ArgumentNullException ("asyncResult");
737 base.EndWrite (asyncResult);
741 AsyncResult ares = asyncResult as AsyncResult;
743 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
745 WriteDelegate w = ares.AsyncDelegate as WriteDelegate;
747 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
749 w.EndInvoke (asyncResult);
753 public override long Seek (long offset, SeekOrigin origin)
757 if (handle == MonoIO.InvalidHandle)
758 throw new ObjectDisposedException ("Stream has been closed");
762 if(CanSeek == false) {
763 throw new NotSupportedException("The stream does not support seeking");
768 pos = Length + offset;
771 case SeekOrigin.Current:
772 pos = Position + offset;
775 case SeekOrigin.Begin:
780 throw new ArgumentException ("origin", "Invalid SeekOrigin");
784 /* LAMESPEC: shouldn't this be
785 * ArgumentOutOfRangeException?
787 throw new IOException("Attempted to Seek before the beginning of the stream");
790 if(pos < this.append_startpos) {
791 /* More undocumented crap */
792 throw new IOException("Can't seek back over pre-existing data in append mode");
799 buf_start = MonoIO.Seek (handle, pos,
803 if (error != MonoIOError.ERROR_SUCCESS) {
804 // don't leak the path information for isolated storage
805 throw MonoIO.GetException (GetSecureFileName (name), error);
811 public override void SetLength (long value)
813 if (handle == MonoIO.InvalidHandle)
814 throw new ObjectDisposedException ("Stream has been closed");
817 throw new NotSupportedException("The stream does not support seeking");
819 if(CanWrite == false)
820 throw new NotSupportedException("The stream does not support writing");
823 throw new ArgumentOutOfRangeException("value is less than 0");
829 MonoIO.SetLength (handle, value, out error);
830 if (error != MonoIOError.ERROR_SUCCESS) {
831 // don't leak the path information for isolated storage
832 throw MonoIO.GetException (GetSecureFileName (name), error);
835 if (Position > value)
839 public override void Flush ()
841 if (handle == MonoIO.InvalidHandle)
842 throw new ObjectDisposedException ("Stream has been closed");
848 public virtual void Flush (bool flushToDisk)
852 // This does the fsync
855 MonoIO.Flush (handle, out error);
860 public virtual void Lock (long position, long length)
862 if (handle == MonoIO.InvalidHandle)
863 throw new ObjectDisposedException ("Stream has been closed");
865 throw new ArgumentOutOfRangeException ("position must not be negative");
868 throw new ArgumentOutOfRangeException ("length must not be negative");
870 if (handle == MonoIO.InvalidHandle) {
871 throw new ObjectDisposedException ("Stream has been closed");
876 MonoIO.Lock (handle, position, length, out error);
877 if (error != MonoIOError.ERROR_SUCCESS) {
878 // don't leak the path information for isolated storage
879 throw MonoIO.GetException (GetSecureFileName (name), error);
883 public virtual void Unlock (long position, long length)
885 if (handle == MonoIO.InvalidHandle)
886 throw new ObjectDisposedException ("Stream has been closed");
888 throw new ArgumentOutOfRangeException ("position must not be negative");
891 throw new ArgumentOutOfRangeException ("length must not be negative");
896 MonoIO.Unlock (handle, position, length, out error);
897 if (error != MonoIOError.ERROR_SUCCESS) {
898 // don't leak the path information for isolated storage
899 throw MonoIO.GetException (GetSecureFileName (name), error);
910 protected override void Dispose (bool disposing)
912 Exception exc = null;
913 if (handle != MonoIO.InvalidHandle) {
916 } catch (Exception e) {
923 MonoIO.Close (handle, out error);
924 if (error != MonoIOError.ERROR_SUCCESS) {
925 // don't leak the path information for isolated storage
926 throw MonoIO.GetException (GetSecureFileName (name), error);
929 handle = MonoIO.InvalidHandle;
936 if (disposing && buf != null) {
937 if (buf.Length == DefaultBufferSize && buf_recycle == null) {
938 lock (buf_recycle_lock) {
939 if (buf_recycle == null) {
946 GC.SuppressFinalize (this);
953 public FileSecurity GetAccessControl ()
955 throw new NotImplementedException ();
958 public void SetAccessControl (FileSecurity fileSecurity)
960 throw new NotImplementedException ();
966 // ReadSegment, WriteSegment, FlushBuffer,
967 // RefillBuffer and ReadData should only be called
968 // when the Monitor lock is held, but these methods
969 // grab it again just to be safe.
971 private int ReadSegment (byte [] dest, int dest_offset, int count)
973 if (count > buf_length - buf_offset) {
974 count = buf_length - buf_offset;
978 Buffer.BlockCopy (buf, buf_offset,
987 private int WriteSegment (byte [] src, int src_offset,
990 if (count > buf_size - buf_offset) {
991 count = buf_size - buf_offset;
995 Buffer.BlockCopy (src, src_offset,
999 if (buf_offset > buf_length) {
1000 buf_length = buf_offset;
1009 void FlushBuffer (Stream st)
1014 if (CanSeek == true) {
1015 MonoIO.Seek (handle, buf_start,
1018 if (error != MonoIOError.ERROR_SUCCESS) {
1019 // don't leak the path information for isolated storage
1020 throw MonoIO.GetException (GetSecureFileName (name), error);
1024 int wcount = buf_length;
1027 int n = MonoIO.Write (handle, buf, 0, buf_length, out error);
1028 if (error != MonoIOError.ERROR_SUCCESS) {
1029 // don't leak the path information for isolated storage
1030 throw MonoIO.GetException (GetSecureFileName (name), error);
1036 st.Write (buf, 0, buf_length);
1040 buf_start += buf_offset;
1041 buf_offset = buf_length = 0;
1045 private void FlushBuffer ()
1050 private void FlushBufferIfDirty ()
1056 private void RefillBuffer ()
1060 buf_length = ReadData (handle, buf, 0,
1064 private int ReadData (IntPtr handle, byte[] buf, int offset,
1070 /* when async == true, if we get here we don't suport AIO or it's disabled
1071 * and we're using the threadpool */
1072 amount = MonoIO.Read (handle, buf, offset, count, out error);
1073 if (error == MonoIOError.ERROR_BROKEN_PIPE) {
1074 amount = 0; // might not be needed, but well...
1075 } else if (error != MonoIOError.ERROR_SUCCESS) {
1076 // don't leak the path information for isolated storage
1077 throw MonoIO.GetException (GetSecureFileName (name), error);
1080 /* Check for read error */
1082 throw new IOException ();
1088 void InitBuffer (int size)
1091 throw new ArgumentOutOfRangeException ("bufferSize", "Positive number required.");
1093 size = Math.Max (size, 8);
1096 // Instead of allocating a new default buffer use the
1097 // last one if there is any available
1099 if (size <= DefaultBufferSize && buf_recycle != null) {
1100 lock (buf_recycle_lock) {
1101 if (buf_recycle != null) {
1109 buf = new byte [size];
1111 Array.Clear (buf, 0, size);
1115 // buf_offset = buf_length = 0;
1116 // buf_dirty = false;
1119 private string GetSecureFileName (string filename)
1121 return (anonymous) ? Path.GetFileName (filename) : Path.GetFullPath (filename);
1124 private string GetSecureFileName (string filename, bool full)
1126 return (anonymous) ? Path.GetFileName (filename) :
1127 (full) ? Path.GetFullPath (filename) : filename;
1132 internal const int DefaultBufferSize = 8192;
1134 // Input buffer ready for recycling
1135 static byte[] buf_recycle;
1136 static readonly object buf_recycle_lock = new object ();
1138 private FileAccess access;
1141 private bool canseek;
1142 private long append_startpos;
1143 private bool anonymous;
1145 private byte [] buf; // the buffer
1146 private int buf_size; // capacity in bytes
1147 private int buf_length; // number of valid bytes in buffer
1148 private int buf_offset; // position of next byte
1149 private bool buf_dirty; // true if buffer has been written to
1150 private long buf_start; // location of buffer in file
1151 private string name = "[Unknown]"; // name of file.
1153 IntPtr handle; // handle to underlying file
1154 SafeFileHandle safeHandle; // set only when using one of the
1155 // constructors taking SafeFileHandle