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;
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 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
63 internal FileStream (IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize, bool isAsync, bool noBuffering)
65 this.handle = MonoIO.InvalidHandle;
66 if (handle == this.handle)
67 throw new ArgumentException ("handle", Locale.GetText ("Invalid."));
69 if (access < FileAccess.Read || access > FileAccess.ReadWrite)
70 throw new ArgumentOutOfRangeException ("access");
73 MonoFileType ftype = MonoIO.GetFileType (handle, out error);
75 if (error != MonoIOError.ERROR_SUCCESS) {
76 throw MonoIO.GetException (name, error);
79 if (ftype == MonoFileType.Unknown) {
80 throw new IOException ("Invalid handle.");
81 } else if (ftype == MonoFileType.Disk) {
91 this.owner = ownsHandle;
93 this.anonymous = false;
95 InitBuffer (bufferSize, noBuffering);
98 buf_start = MonoIO.Seek (handle, 0, SeekOrigin.Current, out error);
99 if (error != MonoIOError.ERROR_SUCCESS) {
100 throw MonoIO.GetException (name, error);
104 /* Can't set append mode */
105 this.append_startpos=0;
108 // construct from filename
110 public FileStream (string name, FileMode mode)
111 : this (name, mode, (mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite), FileShare.Read, DefaultBufferSize, false, FileOptions.None)
115 public FileStream (string name, FileMode mode, FileAccess access)
116 : this (name, mode, access, access == FileAccess.Write ? FileShare.None : FileShare.Read, DefaultBufferSize, false, false)
120 public FileStream (string name, FileMode mode, FileAccess access, FileShare share)
121 : this (name, mode, access, share, DefaultBufferSize, false, FileOptions.None)
125 public FileStream (string name, FileMode mode, FileAccess access, FileShare share, int bufferSize)
126 : this (name, mode, access, share, bufferSize, false, FileOptions.None)
130 public FileStream (string name, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool isAsync)
131 : this (name, mode, access, share, bufferSize, isAsync, FileOptions.None)
136 public FileStream (string name, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options)
137 : this (name, mode, access, share, bufferSize, false, options)
142 internal FileStream (string name, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool isAsync, bool anonymous)
143 : this (name, mode, access, share, bufferSize, anonymous, isAsync ? FileOptions.Asynchronous : FileOptions.None)
147 internal FileStream (string name, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool anonymous, FileOptions options)
150 throw new ArgumentNullException ("name");
153 if (name.Length == 0) {
154 throw new ArgumentException ("Name is empty");
158 // ignore the Inheritable flag
159 share &= ~FileShare.Inheritable;
164 throw new ArgumentOutOfRangeException ("Positive number required.");
166 if (mode < FileMode.CreateNew || mode > FileMode.Append)
167 throw new ArgumentOutOfRangeException ("mode", "Enum value was out of legal range.");
169 if (access < FileAccess.Read || access > FileAccess.ReadWrite)
170 throw new ArgumentOutOfRangeException ("access", "Enum value was out of legal range.");
173 if (share < FileShare.None || share > FileShare.Delete)
175 if (share < FileShare.None || share > FileShare.ReadWrite)
177 throw new ArgumentOutOfRangeException ("share", "Enum value was out of legal range.");
179 if (name.IndexOfAny (Path.InvalidPathChars) != -1) {
180 throw new ArgumentException ("Name has invalid chars");
183 if (Directory.Exists (name)) {
184 // don't leak the path information for isolated storage
185 string msg = Locale.GetText ("Access to the path '{0}' is denied.");
186 string fname = (anonymous) ? Path.GetFileName (name) : Path.GetFullPath (name);
187 throw new UnauthorizedAccessException (String.Format (msg, fname));
190 /* Append streams can't be read (see FileMode
193 if (mode==FileMode.Append &&
194 (access&FileAccess.Read)==FileAccess.Read) {
195 throw new ArgumentException("Append access can be requested only in write-only mode.");
198 if ((access & FileAccess.Write) == 0 &&
199 (mode != FileMode.Open && mode != FileMode.OpenOrCreate)) {
200 string msg = Locale.GetText ("Combining FileMode: {0} with " +
201 "FileAccess: {1} is invalid.");
202 throw new ArgumentException (string.Format (msg, access, mode));
205 string dname = Path.GetDirectoryName (name);
206 if (dname.Length > 0) {
207 string fp = Path.GetFullPath (dname);
208 if (!Directory.Exists (fp)) {
209 // don't leak the path information for isolated storage
210 string msg = Locale.GetText ("Could not find a part of the path \"{0}\".");
211 string fname = (anonymous) ? dname : fp;
212 throw new DirectoryNotFoundException (String.Format (msg, fname));
216 if (access == FileAccess.Read && mode != FileMode.Create && mode != FileMode.OpenOrCreate &&
217 mode != FileMode.CreateNew && !File.Exists (name)) {
218 // don't leak the path information for isolated storage
219 string msg = Locale.GetText ("Could not find file \"{0}\".");
220 string fname = (anonymous) ? Path.GetFileName (name) : name;
221 throw new FileNotFoundException (String.Format (msg, fname), fname);
224 // IsolatedStorage needs to keep the Name property to the default "[Unknown]"
228 // TODO: demand permissions
232 this.handle = MonoIO.Open (name, mode, access, share, options, out error);
233 if (handle == MonoIO.InvalidHandle) {
234 // don't leak the path information for isolated storage
235 string fname = (anonymous) ? Path.GetFileName (name) : name;
236 throw MonoIO.GetException (fname, error);
239 this.access = access;
241 this.anonymous = anonymous;
243 /* Can we open non-files by name? */
245 if (MonoIO.GetFileType (handle, out error) == MonoFileType.Disk) {
247 this.async = (options & FileOptions.Asynchronous) != 0;
249 this.canseek = false;
254 if (access == FileAccess.Read && canseek && (bufferSize == DefaultBufferSize)) {
255 /* Avoid allocating a large buffer for small files */
257 if (bufferSize > len) {
258 bufferSize = (int)(len < 1000 ? 1000 : len);
262 InitBuffer (bufferSize, false);
264 if (mode==FileMode.Append) {
265 this.Seek (0, SeekOrigin.End);
266 this.append_startpos=this.Position;
268 this.append_startpos=0;
274 public override bool CanRead {
276 return access == FileAccess.Read ||
277 access == FileAccess.ReadWrite;
281 public override bool CanWrite {
283 return access == FileAccess.Write ||
284 access == FileAccess.ReadWrite;
288 public override bool CanSeek {
294 public virtual bool IsAsync {
306 public override long Length {
308 if (handle == MonoIO.InvalidHandle)
309 throw new ObjectDisposedException ("Stream has been closed");
312 throw new NotSupportedException ("The stream does not support seeking");
314 // Buffered data might change the length of the stream
315 FlushBufferIfDirty ();
320 length = MonoIO.GetLength (handle, out error);
321 if (error != MonoIOError.ERROR_SUCCESS) {
322 // don't leak the path information for isolated storage
323 string fname = (anonymous) ? Path.GetFileName (name) : name;
324 throw MonoIO.GetException (fname, error);
331 public override long Position {
333 if (handle == MonoIO.InvalidHandle)
334 throw new ObjectDisposedException ("Stream has been closed");
337 throw new NotSupportedException("The stream does not support seeking");
339 return(buf_start + buf_offset);
342 if (handle == MonoIO.InvalidHandle)
343 throw new ObjectDisposedException ("Stream has been closed");
345 if(CanSeek == false) {
346 throw new NotSupportedException("The stream does not support seeking");
350 throw new ArgumentOutOfRangeException("Attempt to set the position to a negative value");
353 Seek (value, SeekOrigin.Begin);
357 public virtual IntPtr Handle {
358 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
359 [SecurityPermission (SecurityAction.InheritanceDemand, UnmanagedCode = true)]
366 public virtual SafeFileHandle SafeFileHandle {
367 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
368 [SecurityPermission (SecurityAction.InheritanceDemand, UnmanagedCode = true)]
369 get { throw new NotImplementedException (); }
375 public override int ReadByte ()
377 if (handle == MonoIO.InvalidHandle)
378 throw new ObjectDisposedException ("Stream has been closed");
381 throw new NotSupportedException ("Stream does not support reading");
384 int n = ReadData (handle, buf, 0, 1);
385 if (n == 0) return -1;
388 else if (buf_offset >= buf_length) {
395 return buf [buf_offset ++];
398 public override void WriteByte (byte value)
400 if (handle == MonoIO.InvalidHandle)
401 throw new ObjectDisposedException ("Stream has been closed");
404 throw new NotSupportedException ("Stream does not support writing");
406 if (buf_offset == buf_size)
409 if (buf_size == 0) { // No buffering
417 buf [buf_offset ++] = value;
418 if (buf_offset > buf_length)
419 buf_length = buf_offset;
424 public override int Read ([In,Out] byte[] dest, int dest_offset, int count)
426 if (handle == MonoIO.InvalidHandle)
427 throw new ObjectDisposedException ("Stream has been closed");
429 throw new ArgumentNullException ("destFile");
431 throw new NotSupportedException ("Stream does not support reading");
432 int len = dest.Length;
434 throw new ArgumentOutOfRangeException ("dest_offset", "< 0");
436 throw new ArgumentOutOfRangeException ("count", "< 0");
437 if (dest_offset > len)
438 throw new ArgumentException ("destination offset is beyond array size");
439 // reordered to avoid possible integer overflow
440 if (dest_offset > len - count)
441 throw new ArgumentException ("Reading would overrun buffer");
444 IAsyncResult ares = BeginRead (dest, dest_offset, count, null, null);
445 return EndRead (ares);
448 return ReadInternal (dest, dest_offset, count);
451 int ReadInternal (byte [] dest, int dest_offset, int count)
455 int n = ReadSegment (dest, dest_offset, count);
460 /* If there was already enough
461 * buffered, no need to read
462 * more from the file.
467 if (count > buf_size) {
468 /* Read as much as we can, up
472 n = ReadData (handle, dest,
476 /* Make the next buffer read
477 * start from the right place
482 n = ReadSegment (dest,
492 delegate int ReadDelegate (byte [] buffer, int offset, int count);
494 public override IAsyncResult BeginRead (byte [] buffer, int offset, int count,
495 AsyncCallback cback, object state)
497 if (handle == MonoIO.InvalidHandle)
498 throw new ObjectDisposedException ("Stream has been closed");
501 throw new NotSupportedException ("This stream does not support reading");
504 throw new ArgumentNullException ("buffer");
507 throw new ArgumentOutOfRangeException ("count", "Must be >= 0");
510 throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
512 // reordered to avoid possible integer overflow
513 if (count > buffer.Length - offset)
514 throw new ArgumentException ("Buffer too small. count/offset wrong.");
517 return base.BeginRead (buffer, offset, count, cback, state);
519 ReadDelegate r = new ReadDelegate (ReadInternal);
520 return r.BeginInvoke (buffer, offset, count, cback, state);
523 public override int EndRead (IAsyncResult async_result)
525 if (async_result == null)
526 throw new ArgumentNullException ("async_result");
529 return base.EndRead (async_result);
531 AsyncResult ares = async_result as AsyncResult;
533 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
535 ReadDelegate r = ares.AsyncDelegate as ReadDelegate;
537 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
539 return r.EndInvoke (async_result);
542 public override void Write (byte[] src, int src_offset, int count)
544 if (handle == MonoIO.InvalidHandle)
545 throw new ObjectDisposedException ("Stream has been closed");
547 throw new ArgumentNullException ("src");
549 throw new ArgumentOutOfRangeException ("src_offset", "< 0");
551 throw new ArgumentOutOfRangeException ("count", "< 0");
552 // ordered to avoid possible integer overflow
553 if (src_offset > src.Length - count)
554 throw new ArgumentException ("Reading would overrun buffer");
556 throw new NotSupportedException ("Stream does not support writing");
559 IAsyncResult ares = BeginWrite (src, src_offset, count, null, null);
564 WriteInternal (src, src_offset, count);
567 void WriteInternal (byte [] src, int src_offset, int count)
569 if (count > buf_size) {
570 // shortcut for long writes
575 MonoIO.Write (handle, src, src_offset, count, out error);
576 if (error != MonoIOError.ERROR_SUCCESS) {
577 // don't leak the path information for isolated storage
578 string fname = (anonymous) ? Path.GetFileName (name) : name;
579 throw MonoIO.GetException (fname, error);
588 int n = WriteSegment (src, src_offset + copied, count);
601 delegate void WriteDelegate (byte [] buffer, int offset, int count);
603 public override IAsyncResult BeginWrite (byte [] buffer, int offset, int count,
604 AsyncCallback cback, object state)
606 if (handle == MonoIO.InvalidHandle)
607 throw new ObjectDisposedException ("Stream has been closed");
610 throw new NotSupportedException ("This stream does not support writing");
613 throw new ArgumentNullException ("buffer");
616 throw new ArgumentOutOfRangeException ("count", "Must be >= 0");
619 throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
621 // reordered to avoid possible integer overflow
622 if (count > buffer.Length - offset)
623 throw new ArgumentException ("Buffer too small. count/offset wrong.");
626 return base.BeginWrite (buffer, offset, count, cback, state);
628 FileStreamAsyncResult result = new FileStreamAsyncResult (cback, state);
629 result.BytesRead = -1;
630 result.Count = count;
631 result.OriginalCount = count;
634 MemoryStream ms = new MemoryStream ();
635 FlushBufferToStream (ms);
636 ms.Write (buffer, offset, count);
638 count = (int) ms.Length;
641 WriteDelegate w = new WriteDelegate (WriteInternal);
642 return w.BeginInvoke (buffer, offset, count, cback, state);
645 public override void EndWrite (IAsyncResult async_result)
647 if (async_result == null)
648 throw new ArgumentNullException ("async_result");
651 base.EndWrite (async_result);
655 AsyncResult ares = async_result as AsyncResult;
657 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
659 WriteDelegate w = ares.AsyncDelegate as WriteDelegate;
661 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
663 w.EndInvoke (async_result);
667 public override long Seek (long offset, SeekOrigin origin)
671 if (handle == MonoIO.InvalidHandle)
672 throw new ObjectDisposedException ("Stream has been closed");
676 if(CanSeek == false) {
677 throw new NotSupportedException("The stream does not support seeking");
682 pos = Length + offset;
685 case SeekOrigin.Current:
686 pos = Position + offset;
689 case SeekOrigin.Begin:
694 throw new ArgumentException ("origin", "Invalid SeekOrigin");
698 /* LAMESPEC: shouldn't this be
699 * ArgumentOutOfRangeException?
701 throw new IOException("Attempted to Seek before the beginning of the stream");
704 if(pos < this.append_startpos) {
705 /* More undocumented crap */
706 throw new IOException("Can't seek back over pre-existing data in append mode");
713 buf_start = MonoIO.Seek (handle, pos,
717 if (error != MonoIOError.ERROR_SUCCESS) {
718 // don't leak the path information for isolated storage
719 string fname = (anonymous) ? Path.GetFileName (name) : name;
720 throw MonoIO.GetException (fname, error);
726 public override void SetLength (long length)
728 if (handle == MonoIO.InvalidHandle)
729 throw new ObjectDisposedException ("Stream has been closed");
732 throw new NotSupportedException("The stream does not support seeking");
734 if(CanWrite == false)
735 throw new NotSupportedException("The stream does not support writing");
738 throw new ArgumentOutOfRangeException("Length is less than 0");
744 MonoIO.SetLength (handle, length, out error);
745 if (error != MonoIOError.ERROR_SUCCESS) {
746 // don't leak the path information for isolated storage
747 string fname = (anonymous) ? Path.GetFileName (name) : name;
748 throw MonoIO.GetException (fname, error);
751 if (Position > length)
755 public override void Flush ()
757 if (handle == MonoIO.InvalidHandle)
758 throw new ObjectDisposedException ("Stream has been closed");
762 // The flushing is not actually required, in
763 //the mono runtime we were mapping flush to
764 //`fsync' which is not the same.
766 //MonoIO.Flush (handle);
769 public override void Close ()
772 GC.SuppressFinalize (this); // remove from finalize queue
775 public virtual void Lock (long position, long length)
777 if (handle == MonoIO.InvalidHandle)
778 throw new ObjectDisposedException ("Stream has been closed");
780 throw new ArgumentOutOfRangeException ("position must not be negative");
783 throw new ArgumentOutOfRangeException ("length must not be negative");
785 if (handle == MonoIO.InvalidHandle) {
786 throw new ObjectDisposedException ("Stream has been closed");
791 MonoIO.Lock (handle, position, length, out error);
792 if (error != MonoIOError.ERROR_SUCCESS) {
793 // don't leak the path information for isolated storage
794 string fname = (anonymous) ? Path.GetFileName (name) : name;
795 throw MonoIO.GetException (fname, error);
799 public virtual void Unlock (long position, long length)
801 if (handle == MonoIO.InvalidHandle)
802 throw new ObjectDisposedException ("Stream has been closed");
804 throw new ArgumentOutOfRangeException ("position must not be negative");
807 throw new ArgumentOutOfRangeException ("length must not be negative");
812 MonoIO.Unlock (handle, position, length, out error);
813 if (error != MonoIOError.ERROR_SUCCESS) {
814 // don't leak the path information for isolated storage
815 string fname = (anonymous) ? Path.GetFileName (name) : name;
816 throw MonoIO.GetException (fname, error);
828 protected override void Dispose (bool disposing)
830 protected virtual void Dispose (bool disposing)
833 if (handle != MonoIO.InvalidHandle) {
839 MonoIO.Close (handle, out error);
840 if (error != MonoIOError.ERROR_SUCCESS) {
841 // don't leak the path information for isolated storage
842 string fname = (anonymous) ? Path.GetFileName (name) : name;
843 throw MonoIO.GetException (fname, error);
846 handle = MonoIO.InvalidHandle;
859 // ReadSegment, WriteSegment, FlushBuffer,
860 // RefillBuffer and ReadData should only be called
861 // when the Monitor lock is held, but these methods
862 // grab it again just to be safe.
864 private int ReadSegment (byte [] dest, int dest_offset, int count)
866 if (count > buf_length - buf_offset) {
867 count = buf_length - buf_offset;
871 Buffer.BlockCopy (buf, buf_offset,
880 private int WriteSegment (byte [] src, int src_offset,
883 if (count > buf_size - buf_offset) {
884 count = buf_size - buf_offset;
888 Buffer.BlockCopy (src, src_offset,
892 if (buf_offset > buf_length) {
893 buf_length = buf_offset;
902 void FlushBufferToStream (Stream st)
905 if (CanSeek == true) {
907 MonoIO.Seek (handle, buf_start,
910 if (error != MonoIOError.ERROR_SUCCESS) {
911 // don't leak the path information for isolated storage
912 string fname = (anonymous) ? Path.GetFileName (name) : name;
913 throw MonoIO.GetException (fname, error);
916 st.Write (buf, 0, buf_length);
919 buf_start += buf_offset;
920 buf_offset = buf_length = 0;
924 private void FlushBuffer ()
929 if (CanSeek == true) {
930 MonoIO.Seek (handle, buf_start,
933 if (error != MonoIOError.ERROR_SUCCESS) {
934 // don't leak the path information for isolated storage
935 string fname = (anonymous) ? Path.GetFileName (name) : name;
936 throw MonoIO.GetException (fname, error);
939 MonoIO.Write (handle, buf, 0,
940 buf_length, out error);
942 if (error != MonoIOError.ERROR_SUCCESS) {
943 // don't leak the path information for isolated storage
944 string fname = (anonymous) ? Path.GetFileName (name) : name;
945 throw MonoIO.GetException (fname, error);
949 buf_start += buf_offset;
950 buf_offset = buf_length = 0;
954 private void FlushBufferIfDirty ()
960 private void RefillBuffer ()
964 buf_length = ReadData (handle, buf, 0,
968 private int ReadData (IntPtr handle, byte[] buf, int offset,
974 /* when async == true, if we get here we don't suport AIO or it's disabled
975 * and we're using the threadpool */
976 amount = MonoIO.Read (handle, buf, offset, count, out error);
977 if (error == MonoIOError.ERROR_BROKEN_PIPE) {
978 amount = 0; // might not be needed, but well...
979 } else if (error != MonoIOError.ERROR_SUCCESS) {
980 // don't leak the path information for isolated storage
981 string fname = (anonymous) ? Path.GetFileName (name) : name;
982 throw MonoIO.GetException (fname, error);
985 /* Check for read error */
987 throw new IOException ();
993 private void InitBuffer (int size, bool noBuffering)
997 // We need a buffer for the ReadByte method. This buffer won't
998 // be used for anything else since buf_size==0.
1003 throw new ArgumentOutOfRangeException ("bufferSize", "Positive number required.");
1006 buf = new byte [size];
1011 buf_offset = buf_length = 0;
1017 internal const int DefaultBufferSize = 8192;
1019 private FileAccess access;
1022 private bool canseek;
1023 private long append_startpos;
1024 private bool anonymous;
1026 private byte [] buf; // the buffer
1027 private int buf_size; // capacity in bytes
1028 private int buf_length; // number of valid bytes in buffer
1029 private int buf_offset; // position of next byte
1030 private bool buf_dirty; // true if buffer has been written to
1031 private long buf_start; // location of buffer in file
1032 private string name = "[Unknown]"; // name of file.
1034 IntPtr handle; // handle to underlying file