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.
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
;
50 public class FileStream
: Stream
52 // construct from handle
54 #if NET_2_0_SAFEFILEHANDLE_ENABLED
55 [Obsolete ("Use FileStream(SafeFileHandle handle, FileAccess access) instead")]
57 public FileStream (IntPtr handle
, FileAccess access
)
58 : this (handle
, access
, true, DefaultBufferSize
, false) {}
60 #if NET_2_0_SAFEFILEHANDLE_ENABLED
61 [Obsolete ("Use FileStream(SafeFileHandle handle, FileAccess access) instead")]
63 public FileStream (IntPtr handle
, FileAccess access
, bool ownsHandle
)
64 : this (handle
, access
, ownsHandle
, DefaultBufferSize
, false) {}
66 #if NET_2_0_SAFEFILEHANDLE_ENABLED
67 [Obsolete ("Use FileStream(SafeFileHandle handle, FileAccess access, int bufferSize) instead")]
69 public FileStream (IntPtr handle
, FileAccess access
, bool ownsHandle
, int bufferSize
)
70 : this (handle
, access
, ownsHandle
, bufferSize
, false) {}
72 #if NET_2_0_SAFEFILEHANDLE_ENABLED
73 [Obsolete ("Use FileStream(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync) instead")]
75 public FileStream (IntPtr handle
, FileAccess access
, bool ownsHandle
, int bufferSize
, bool isAsync
)
76 : this (handle
, access
, ownsHandle
, bufferSize
, isAsync
, false) {}
78 [SecurityPermission (SecurityAction
.Demand
, UnmanagedCode
= true)]
79 internal FileStream (IntPtr handle
, FileAccess access
, bool ownsHandle
, int bufferSize
, bool isAsync
, bool noBuffering
)
81 this.handle
= MonoIO
.InvalidHandle
;
82 if (handle
== this.handle
)
83 throw new ArgumentException ("handle", Locale
.GetText ("Invalid."));
85 if (access
< FileAccess
.Read
|| access
> FileAccess
.ReadWrite
)
86 throw new ArgumentOutOfRangeException ("access");
89 MonoFileType ftype
= MonoIO
.GetFileType (handle
, out error
);
91 if (error
!= MonoIOError
.ERROR_SUCCESS
) {
92 throw MonoIO
.GetException (name
, error
);
95 if (ftype
== MonoFileType
.Unknown
) {
96 throw new IOException ("Invalid handle.");
97 } else if (ftype
== MonoFileType
.Disk
) {
100 this.canseek
= false;
103 this.handle
= handle
;
104 this.access
= access
;
105 this.owner
= ownsHandle
;
106 this.async = isAsync
;
107 this.anonymous
= false;
109 InitBuffer (bufferSize
, noBuffering
);
112 buf_start
= MonoIO
.Seek (handle
, 0, SeekOrigin
.Current
, out error
);
113 if (error
!= MonoIOError
.ERROR_SUCCESS
) {
114 throw MonoIO
.GetException (name
, error
);
118 /* Can't set append mode */
119 this.append_startpos
=0;
122 // construct from filename
124 public FileStream (string name
, FileMode mode
)
125 : this (name
, mode
, (mode
== FileMode
.Append
? FileAccess
.Write
: FileAccess
.ReadWrite
), FileShare
.Read
, DefaultBufferSize
, false, FileOptions
.None
)
129 public FileStream (string name
, FileMode mode
, FileAccess access
)
130 : this (name
, mode
, access
, access
== FileAccess
.Write
? FileShare
.None
: FileShare
.Read
, DefaultBufferSize
, false, false)
134 public FileStream (string name
, FileMode mode
, FileAccess access
, FileShare share
)
135 : this (name
, mode
, access
, share
, DefaultBufferSize
, false, FileOptions
.None
)
139 public FileStream (string name
, FileMode mode
, FileAccess access
, FileShare share
, int bufferSize
)
140 : this (name
, mode
, access
, share
, bufferSize
, false, FileOptions
.None
)
144 public FileStream (string name
, FileMode mode
, FileAccess access
, FileShare share
, int bufferSize
, bool isAsync
)
145 : this (name
, mode
, access
, share
, bufferSize
, isAsync
, FileOptions
.None
)
150 public FileStream (string name
, FileMode mode
, FileAccess access
, FileShare share
, int bufferSize
, FileOptions options
)
151 : this (name
, mode
, access
, share
, bufferSize
, false, options
)
155 public FileStream (SafeFileHandle handle
, FileAccess access
)
156 :this(handle
, access
, DefaultBufferSize
, false)
160 public FileStream (SafeFileHandle handle
, FileAccess access
,
162 :this(handle
, access
, bufferSize
, false)
166 [MonoLimitationAttribute("Need to use SafeFileHandle instead of underlying handle")]
167 public FileStream (SafeFileHandle handle
, FileAccess access
,
168 int bufferSize
, bool isAsync
)
169 :this (handle
.DangerousGetHandle (), access
, false, bufferSize
, isAsync
)
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 name
, FileMode mode
, FileAccess access
, FileShare share
, int bufferSize
, bool isAsync
, bool anonymous
)
190 : this (name
, mode
, access
, share
, bufferSize
, anonymous
, isAsync
? FileOptions
.Asynchronous
: FileOptions
.None
)
194 internal FileStream (string name
, FileMode mode
, FileAccess access
, FileShare share
, int bufferSize
, bool anonymous
, FileOptions options
)
197 throw new ArgumentNullException ("name");
200 if (name
.Length
== 0) {
201 throw new ArgumentException ("Name is empty");
205 // ignore the Inheritable flag
206 share
&= ~FileShare
.Inheritable
;
211 throw new ArgumentOutOfRangeException ("bufferSize", "Positive number required.");
213 if (mode
< FileMode
.CreateNew
|| mode
> FileMode
.Append
)
214 throw new ArgumentOutOfRangeException ("mode", "Enum value was out of legal range.");
216 if (access
< FileAccess
.Read
|| access
> FileAccess
.ReadWrite
)
217 throw new ArgumentOutOfRangeException ("access", "Enum value was out of legal range.");
220 if (share
< FileShare
.None
|| share
> FileShare
.Delete
)
222 if (share
< FileShare
.None
|| share
> FileShare
.ReadWrite
)
224 throw new ArgumentOutOfRangeException ("share", "Enum value was out of legal range.");
226 if (name
.IndexOfAny (Path
.InvalidPathChars
) != -1) {
227 throw new ArgumentException ("Name has invalid chars");
230 if (Directory
.Exists (name
)) {
231 // don't leak the path information for isolated storage
232 string msg
= Locale
.GetText ("Access to the path '{0}' is denied.");
233 string fname
= (anonymous
) ? Path
.GetFileName (name
) : Path
.GetFullPath (name
);
234 throw new UnauthorizedAccessException (String
.Format (msg
, fname
));
237 /* Append streams can't be read (see FileMode
240 if (mode
==FileMode
.Append
&&
241 (access
&FileAccess
.Read
)==FileAccess
.Read
) {
242 throw new ArgumentException("Append access can be requested only in write-only mode.");
245 if ((access
& FileAccess
.Write
) == 0 &&
246 (mode
!= FileMode
.Open
&& mode
!= FileMode
.OpenOrCreate
)) {
247 string msg
= Locale
.GetText ("Combining FileMode: {0} with " +
248 "FileAccess: {1} is invalid.");
249 throw new ArgumentException (string.Format (msg
, access
, mode
));
252 string dname
= Path
.GetDirectoryName (name
);
253 if (dname
.Length
> 0) {
254 string fp
= Path
.GetFullPath (dname
);
255 if (!Directory
.Exists (fp
)) {
256 // don't leak the path information for isolated storage
257 string msg
= Locale
.GetText ("Could not find a part of the path \"{0}\".");
258 string fname
= (anonymous
) ? dname
: Path
.GetFullPath (name
);
259 throw new DirectoryNotFoundException (String
.Format (msg
, fname
));
263 if (access
== FileAccess
.Read
&& mode
!= FileMode
.Create
&& mode
!= FileMode
.OpenOrCreate
&&
264 mode
!= FileMode
.CreateNew
&& !File
.Exists (name
)) {
265 // don't leak the path information for isolated storage
266 string msg
= Locale
.GetText ("Could not find file \"{0}\".");
267 string fname
= (anonymous
) ? Path
.GetFileName (name
) : Path
.GetFullPath (name
);
268 throw new FileNotFoundException (String
.Format (msg
, fname
), fname
);
271 // IsolatedStorage needs to keep the Name property to the default "[Unknown]"
275 // TODO: demand permissions
279 this.handle
= MonoIO
.Open (name
, mode
, access
, share
, options
, out error
);
280 if (handle
== MonoIO
.InvalidHandle
) {
281 // don't leak the path information for isolated storage
282 string fname
= (anonymous
) ? Path
.GetFileName (name
) : Path
.GetFullPath (name
);
283 throw MonoIO
.GetException (fname
, error
);
286 this.access
= access
;
288 this.anonymous
= anonymous
;
290 /* Can we open non-files by name? */
292 if (MonoIO
.GetFileType (handle
, out error
) == MonoFileType
.Disk
) {
294 this.async = (options
& FileOptions
.Asynchronous
) != 0;
296 this.canseek
= false;
301 if (access
== FileAccess
.Read
&& canseek
&& (bufferSize
== DefaultBufferSize
)) {
302 /* Avoid allocating a large buffer for small files */
304 if (bufferSize
> len
) {
305 bufferSize
= (int)(len
< 1000 ? 1000 : len
);
309 InitBuffer (bufferSize
, false);
311 if (mode
==FileMode
.Append
) {
312 this.Seek (0, SeekOrigin
.End
);
313 this.append_startpos
=this.Position
;
315 this.append_startpos
=0;
321 public override bool CanRead
{
323 return access
== FileAccess
.Read
||
324 access
== FileAccess
.ReadWrite
;
328 public override bool CanWrite
{
330 return access
== FileAccess
.Write
||
331 access
== FileAccess
.ReadWrite
;
335 public override bool CanSeek
{
341 public virtual bool IsAsync
{
353 public override long Length
{
355 if (handle
== MonoIO
.InvalidHandle
)
356 throw new ObjectDisposedException ("Stream has been closed");
359 throw new NotSupportedException ("The stream does not support seeking");
361 // Buffered data might change the length of the stream
362 FlushBufferIfDirty ();
367 length
= MonoIO
.GetLength (handle
, out error
);
368 if (error
!= MonoIOError
.ERROR_SUCCESS
) {
369 // don't leak the path information for isolated storage
370 string fname
= (anonymous
) ? Path
.GetFileName (name
) : name
;
371 throw MonoIO
.GetException (fname
, error
);
378 public override long Position
{
380 if (handle
== MonoIO
.InvalidHandle
)
381 throw new ObjectDisposedException ("Stream has been closed");
384 throw new NotSupportedException("The stream does not support seeking");
386 return(buf_start
+ buf_offset
);
389 if (handle
== MonoIO
.InvalidHandle
)
390 throw new ObjectDisposedException ("Stream has been closed");
392 if(CanSeek
== false) {
393 throw new NotSupportedException("The stream does not support seeking");
397 throw new ArgumentOutOfRangeException("Attempt to set the position to a negative value");
400 Seek (value, SeekOrigin
.Begin
);
404 #if NET_2_0_SAFEFILEHANDLE_ENABLED
405 [Obsolete ("Use SafeFileHandle instead")]
407 public virtual IntPtr Handle
{
408 [SecurityPermission (SecurityAction
.LinkDemand
, UnmanagedCode
= true)]
409 [SecurityPermission (SecurityAction
.InheritanceDemand
, UnmanagedCode
= true)]
416 public virtual SafeFileHandle SafeFileHandle
{
417 [SecurityPermission (SecurityAction
.LinkDemand
, UnmanagedCode
= true)]
418 [SecurityPermission (SecurityAction
.InheritanceDemand
, UnmanagedCode
= true)]
419 get { throw new NotImplementedException (); }
425 public override int ReadByte ()
427 if (handle
== MonoIO
.InvalidHandle
)
428 throw new ObjectDisposedException ("Stream has been closed");
431 throw new NotSupportedException ("Stream does not support reading");
434 int n
= ReadData (handle
, buf
, 0, 1);
435 if (n
== 0) return -1;
438 else if (buf_offset
>= buf_length
) {
445 return buf
[buf_offset
++];
448 public override void WriteByte (byte value)
450 if (handle
== MonoIO
.InvalidHandle
)
451 throw new ObjectDisposedException ("Stream has been closed");
454 throw new NotSupportedException ("Stream does not support writing");
456 if (buf_offset
== buf_size
)
459 if (buf_size
== 0) { // No buffering
467 buf
[buf_offset
++] = value;
468 if (buf_offset
> buf_length
)
469 buf_length
= buf_offset
;
474 public override int Read ([In
,Out
] byte[] dest
, int dest_offset
, int count
)
476 if (handle
== MonoIO
.InvalidHandle
)
477 throw new ObjectDisposedException ("Stream has been closed");
479 throw new ArgumentNullException ("destFile");
481 throw new NotSupportedException ("Stream does not support reading");
482 int len
= dest
.Length
;
484 throw new ArgumentOutOfRangeException ("dest_offset", "< 0");
486 throw new ArgumentOutOfRangeException ("count", "< 0");
487 if (dest_offset
> len
)
488 throw new ArgumentException ("destination offset is beyond array size");
489 // reordered to avoid possible integer overflow
490 if (dest_offset
> len
- count
)
491 throw new ArgumentException ("Reading would overrun buffer");
494 IAsyncResult ares
= BeginRead (dest
, dest_offset
, count
, null, null);
495 return EndRead (ares
);
498 return ReadInternal (dest
, dest_offset
, count
);
501 int ReadInternal (byte [] dest
, int dest_offset
, int count
)
505 int n
= ReadSegment (dest
, dest_offset
, count
);
510 /* If there was already enough
511 * buffered, no need to read
512 * more from the file.
517 if (count
> buf_size
) {
518 /* Read as much as we can, up
522 n
= ReadData (handle
, dest
,
526 /* Make the next buffer read
527 * start from the right place
532 n
= ReadSegment (dest
,
542 delegate int ReadDelegate (byte [] buffer
, int offset
, int count
);
544 public override IAsyncResult
BeginRead (byte [] buffer
, int offset
, int count
,
545 AsyncCallback cback
, object state
)
547 if (handle
== MonoIO
.InvalidHandle
)
548 throw new ObjectDisposedException ("Stream has been closed");
551 throw new NotSupportedException ("This stream does not support reading");
554 throw new ArgumentNullException ("buffer");
557 throw new ArgumentOutOfRangeException ("count", "Must be >= 0");
560 throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
562 // reordered to avoid possible integer overflow
563 if (count
> buffer
.Length
- offset
)
564 throw new ArgumentException ("Buffer too small. count/offset wrong.");
567 return base.BeginRead (buffer
, offset
, count
, cback
, state
);
569 ReadDelegate r
= new ReadDelegate (ReadInternal
);
570 return r
.BeginInvoke (buffer
, offset
, count
, cback
, state
);
573 public override int EndRead (IAsyncResult async_result
)
575 if (async_result
== null)
576 throw new ArgumentNullException ("async_result");
579 return base.EndRead (async_result
);
581 AsyncResult ares
= async_result
as AsyncResult
;
583 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
585 ReadDelegate r
= ares
.AsyncDelegate
as ReadDelegate
;
587 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
589 return r
.EndInvoke (async_result
);
592 public override void Write (byte[] src
, int src_offset
, int count
)
594 if (handle
== MonoIO
.InvalidHandle
)
595 throw new ObjectDisposedException ("Stream has been closed");
597 throw new ArgumentNullException ("src");
599 throw new ArgumentOutOfRangeException ("src_offset", "< 0");
601 throw new ArgumentOutOfRangeException ("count", "< 0");
602 // ordered to avoid possible integer overflow
603 if (src_offset
> src
.Length
- count
)
604 throw new ArgumentException ("Reading would overrun buffer");
606 throw new NotSupportedException ("Stream does not support writing");
609 IAsyncResult ares
= BeginWrite (src
, src_offset
, count
, null, null);
614 WriteInternal (src
, src_offset
, count
);
617 void WriteInternal (byte [] src
, int src_offset
, int count
)
619 if (count
> buf_size
) {
620 // shortcut for long writes
625 MonoIO
.Write (handle
, src
, src_offset
, count
, out error
);
626 if (error
!= MonoIOError
.ERROR_SUCCESS
) {
627 // don't leak the path information for isolated storage
628 string fname
= (anonymous
) ? Path
.GetFileName (name
) : name
;
629 throw MonoIO
.GetException (fname
, error
);
638 int n
= WriteSegment (src
, src_offset
+ copied
, count
);
651 delegate void WriteDelegate (byte [] buffer
, int offset
, int count
);
653 public override IAsyncResult
BeginWrite (byte [] buffer
, int offset
, int count
,
654 AsyncCallback cback
, object state
)
656 if (handle
== MonoIO
.InvalidHandle
)
657 throw new ObjectDisposedException ("Stream has been closed");
660 throw new NotSupportedException ("This stream does not support writing");
663 throw new ArgumentNullException ("buffer");
666 throw new ArgumentOutOfRangeException ("count", "Must be >= 0");
669 throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
671 // reordered to avoid possible integer overflow
672 if (count
> buffer
.Length
- offset
)
673 throw new ArgumentException ("Buffer too small. count/offset wrong.");
676 return base.BeginWrite (buffer
, offset
, count
, cback
, state
);
678 FileStreamAsyncResult result
= new FileStreamAsyncResult (cback
, state
);
679 result
.BytesRead
= -1;
680 result
.Count
= count
;
681 result
.OriginalCount
= count
;
684 MemoryStream ms
= new MemoryStream ();
685 FlushBufferToStream (ms
);
686 ms
.Write (buffer
, offset
, count
);
688 count
= (int) ms
.Length
;
691 WriteDelegate w
= new WriteDelegate (WriteInternal
);
692 return w
.BeginInvoke (buffer
, offset
, count
, cback
, state
);
695 public override void EndWrite (IAsyncResult async_result
)
697 if (async_result
== null)
698 throw new ArgumentNullException ("async_result");
701 base.EndWrite (async_result
);
705 AsyncResult ares
= async_result
as AsyncResult
;
707 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
709 WriteDelegate w
= ares
.AsyncDelegate
as WriteDelegate
;
711 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
713 w
.EndInvoke (async_result
);
717 public override long Seek (long offset
, SeekOrigin origin
)
721 if (handle
== MonoIO
.InvalidHandle
)
722 throw new ObjectDisposedException ("Stream has been closed");
726 if(CanSeek
== false) {
727 throw new NotSupportedException("The stream does not support seeking");
732 pos
= Length
+ offset
;
735 case SeekOrigin
.Current
:
736 pos
= Position
+ offset
;
739 case SeekOrigin
.Begin
:
744 throw new ArgumentException ("origin", "Invalid SeekOrigin");
748 /* LAMESPEC: shouldn't this be
749 * ArgumentOutOfRangeException?
751 throw new IOException("Attempted to Seek before the beginning of the stream");
754 if(pos
< this.append_startpos
) {
755 /* More undocumented crap */
756 throw new IOException("Can't seek back over pre-existing data in append mode");
763 buf_start
= MonoIO
.Seek (handle
, pos
,
767 if (error
!= MonoIOError
.ERROR_SUCCESS
) {
768 // don't leak the path information for isolated storage
769 string fname
= (anonymous
) ? Path
.GetFileName (name
) : name
;
770 throw MonoIO
.GetException (fname
, error
);
776 public override void SetLength (long length
)
778 if (handle
== MonoIO
.InvalidHandle
)
779 throw new ObjectDisposedException ("Stream has been closed");
782 throw new NotSupportedException("The stream does not support seeking");
784 if(CanWrite
== false)
785 throw new NotSupportedException("The stream does not support writing");
788 throw new ArgumentOutOfRangeException("Length is less than 0");
794 MonoIO
.SetLength (handle
, length
, out error
);
795 if (error
!= MonoIOError
.ERROR_SUCCESS
) {
796 // don't leak the path information for isolated storage
797 string fname
= (anonymous
) ? Path
.GetFileName (name
) : name
;
798 throw MonoIO
.GetException (fname
, error
);
801 if (Position
> length
)
805 public override void Flush ()
807 if (handle
== MonoIO
.InvalidHandle
)
808 throw new ObjectDisposedException ("Stream has been closed");
812 // The flushing is not actually required, in
813 //the mono runtime we were mapping flush to
814 //`fsync' which is not the same.
816 //MonoIO.Flush (handle);
819 public override void Close ()
822 GC
.SuppressFinalize (this); // remove from finalize queue
825 public virtual void Lock (long position
, long length
)
827 if (handle
== MonoIO
.InvalidHandle
)
828 throw new ObjectDisposedException ("Stream has been closed");
830 throw new ArgumentOutOfRangeException ("position must not be negative");
833 throw new ArgumentOutOfRangeException ("length must not be negative");
835 if (handle
== MonoIO
.InvalidHandle
) {
836 throw new ObjectDisposedException ("Stream has been closed");
841 MonoIO
.Lock (handle
, position
, length
, out error
);
842 if (error
!= MonoIOError
.ERROR_SUCCESS
) {
843 // don't leak the path information for isolated storage
844 string fname
= (anonymous
) ? Path
.GetFileName (name
) : name
;
845 throw MonoIO
.GetException (fname
, error
);
849 public virtual void Unlock (long position
, long length
)
851 if (handle
== MonoIO
.InvalidHandle
)
852 throw new ObjectDisposedException ("Stream has been closed");
854 throw new ArgumentOutOfRangeException ("position must not be negative");
857 throw new ArgumentOutOfRangeException ("length must not be negative");
862 MonoIO
.Unlock (handle
, position
, length
, out error
);
863 if (error
!= MonoIOError
.ERROR_SUCCESS
) {
864 // don't leak the path information for isolated storage
865 string fname
= (anonymous
) ? Path
.GetFileName (name
) : name
;
866 throw MonoIO
.GetException (fname
, error
);
878 protected override void Dispose (bool disposing
)
880 protected virtual void Dispose (bool disposing
)
883 if (handle
!= MonoIO
.InvalidHandle
) {
889 MonoIO
.Close (handle
, out error
);
890 if (error
!= MonoIOError
.ERROR_SUCCESS
) {
891 // don't leak the path information for isolated storage
892 string fname
= (anonymous
) ? Path
.GetFileName (name
) : name
;
893 throw MonoIO
.GetException (fname
, error
);
896 handle
= MonoIO
.InvalidHandle
;
908 public FileSecurity
GetAccessControl ()
910 throw new NotImplementedException ();
913 public void SetAccessControl (FileSecurity fileSecurity
)
915 throw new NotImplementedException ();
921 // ReadSegment, WriteSegment, FlushBuffer,
922 // RefillBuffer and ReadData should only be called
923 // when the Monitor lock is held, but these methods
924 // grab it again just to be safe.
926 private int ReadSegment (byte [] dest
, int dest_offset
, int count
)
928 if (count
> buf_length
- buf_offset
) {
929 count
= buf_length
- buf_offset
;
933 Buffer
.BlockCopy (buf
, buf_offset
,
942 private int WriteSegment (byte [] src
, int src_offset
,
945 if (count
> buf_size
- buf_offset
) {
946 count
= buf_size
- buf_offset
;
950 Buffer
.BlockCopy (src
, src_offset
,
954 if (buf_offset
> buf_length
) {
955 buf_length
= buf_offset
;
964 void FlushBufferToStream (Stream st
)
967 if (CanSeek
== true) {
969 MonoIO
.Seek (handle
, buf_start
,
972 if (error
!= MonoIOError
.ERROR_SUCCESS
) {
973 // don't leak the path information for isolated storage
974 string fname
= (anonymous
) ? Path
.GetFileName (name
) : name
;
975 throw MonoIO
.GetException (fname
, error
);
978 st
.Write (buf
, 0, buf_length
);
981 buf_start
+= buf_offset
;
982 buf_offset
= buf_length
= 0;
986 private void FlushBuffer ()
991 if (CanSeek
== true) {
992 MonoIO
.Seek (handle
, buf_start
,
995 if (error
!= MonoIOError
.ERROR_SUCCESS
) {
996 // don't leak the path information for isolated storage
997 string fname
= (anonymous
) ? Path
.GetFileName (name
) : name
;
998 throw MonoIO
.GetException (fname
, error
);
1001 MonoIO
.Write (handle
, buf
, 0,
1002 buf_length
, out error
);
1004 if (error
!= MonoIOError
.ERROR_SUCCESS
) {
1005 // don't leak the path information for isolated storage
1006 string fname
= (anonymous
) ? Path
.GetFileName (name
) : name
;
1007 throw MonoIO
.GetException (fname
, error
);
1011 buf_start
+= buf_offset
;
1012 buf_offset
= buf_length
= 0;
1016 private void FlushBufferIfDirty ()
1022 private void RefillBuffer ()
1026 buf_length
= ReadData (handle
, buf
, 0,
1030 private int ReadData (IntPtr handle
, byte[] buf
, int offset
,
1036 /* when async == true, if we get here we don't suport AIO or it's disabled
1037 * and we're using the threadpool */
1038 amount
= MonoIO
.Read (handle
, buf
, offset
, count
, out error
);
1039 if (error
== MonoIOError
.ERROR_BROKEN_PIPE
) {
1040 amount
= 0; // might not be needed, but well...
1041 } else if (error
!= MonoIOError
.ERROR_SUCCESS
) {
1042 // don't leak the path information for isolated storage
1043 string fname
= (anonymous
) ? Path
.GetFileName (name
) : name
;
1044 throw MonoIO
.GetException (fname
, 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;
1079 internal const int DefaultBufferSize
= 8192;
1081 private FileAccess access
;
1084 private bool canseek
;
1085 private long append_startpos
;
1086 private bool anonymous
;
1088 private byte [] buf
; // the buffer
1089 private int buf_size
; // capacity in bytes
1090 private int buf_length
; // number of valid bytes in buffer
1091 private int buf_offset
; // position of next byte
1092 private bool buf_dirty
; // true if buffer has been written to
1093 private long buf_start
; // location of buffer in file
1094 private string name
= "[Unknown]"; // name of file.
1096 IntPtr handle
; // handle to underlying file