// This code is derived from jcifs smb client library // Ported by J. Arturo // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA using System; using System.IO; using SharpCifs.Util.Sharpen; using SharpCifs.Util.Transport; namespace SharpCifs.Smb { /// This InputStream can read bytes from a file on an SMB file server. /// This InputStream can read bytes from a file on an SMB file server. Offsets are 64 bits. /// public class SmbFileInputStream : InputStream { private long _fp; private int _readSize; private int _openFlags; private int _access; private byte[] _tmp = new byte[1]; internal SmbFile File; /// /// Creates an /// System.IO.InputStream /// for reading bytes from a file on /// an SMB server addressed by the url parameter. See /// SmbFile /// for a detailed description and examples of the smb /// URL syntax. /// /// An smb URL string representing the file to read from /// /// /// public SmbFileInputStream(string url) : this(new SmbFile(url)) { } /// /// Creates an /// System.IO.InputStream /// for reading bytes from a file on /// an SMB server represented by the /// SmbFile /// parameter. See /// SmbFile /// for a detailed description and examples of /// the smb URL syntax. /// /// An SmbFile specifying the file to read from /// /// /// public SmbFileInputStream(SmbFile file) : this(file, SmbFile.ORdonly) { } /// /// /// internal SmbFileInputStream(SmbFile file, int openFlags) { this.File = file; this._openFlags = openFlags & 0xFFFF; _access = ((int)(((uint)openFlags) >> 16)) & 0xFFFF; if (file.Type != SmbFile.TypeNamedPipe) { file.Open(openFlags, _access, SmbFile.AttrNormal, 0); this._openFlags &= ~(SmbFile.OCreat | SmbFile.OTrunc); } else { file.Connect0(); } _readSize = Math.Min(file.Tree.Session.transport.RcvBufSize - 70, file.Tree.Session .transport.Server.MaxBufferSize - 70); } protected internal virtual IOException SeToIoe(SmbException se) { IOException ioe = se; Exception root = se.GetRootCause(); if (root is TransportException) { ioe = (TransportException)root; root = ((TransportException)ioe).GetRootCause(); } if (root is Exception) { ioe = new IOException(root.Message); ioe.InitCause(root); } return ioe; } /// Closes this input stream and releases any system resources associated with the stream. /// /// Closes this input stream and releases any system resources associated with the stream. /// /// if a network error occurs public override void Close() { try { File.Close(); _tmp = null; } catch (SmbException se) { throw SeToIoe(se); } } /// Reads a byte of data from this input stream. /// Reads a byte of data from this input stream. /// if a network error occurs public override int Read() { // need oplocks to cache otherwise use BufferedInputStream if (Read(_tmp, 0, 1) == -1) { return -1; } return _tmp[0] & unchecked(0xFF); } /// Reads up to b.length bytes of data from this input stream into an array of bytes. /// /// Reads up to b.length bytes of data from this input stream into an array of bytes. /// /// if a network error occurs public override int Read(byte[] b) { return Read(b, 0, b.Length); } /// Reads up to len bytes of data from this input stream into an array of bytes. /// /// Reads up to len bytes of data from this input stream into an array of bytes. /// /// if a network error occurs public override int Read(byte[] b, int off, int len) { return ReadDirect(b, off, len); } /// public virtual int ReadDirect(byte[] b, int off, int len) { if (len <= 0) { return 0; } long start = _fp; if (_tmp == null) { throw new IOException("Bad file descriptor"); } // ensure file is open File.Open(_openFlags, _access, SmbFile.AttrNormal, 0); if (File.Log.Level >= 4) { File.Log.WriteLine("read: fid=" + File.Fid + ",off=" + off + ",len=" + len); } SmbComReadAndXResponse response = new SmbComReadAndXResponse(b, off); if (File.Type == SmbFile.TypeNamedPipe) { response.ResponseTimeout = 0; } int r; int n; do { r = len > _readSize ? _readSize : len; if (File.Log.Level >= 4) { File.Log.WriteLine("read: len=" + len + ",r=" + r + ",fp=" + _fp); } try { SmbComReadAndX request = new SmbComReadAndX(File.Fid, _fp, r, null); if (File.Type == SmbFile.TypeNamedPipe) { request.MinCount = request.MaxCount = request.Remaining = 1024; } //ここで読み込んでいるらしい。 File.Send(request, response); } catch (SmbException se) { if (File.Type == SmbFile.TypeNamedPipe && se.GetNtStatus() == NtStatus.NtStatusPipeBroken) { return -1; } throw SeToIoe(se); } if ((n = response.DataLength) <= 0) { return (int)((_fp - start) > 0L ? _fp - start : -1); } _fp += n; len -= n; response.Off += n; } while (len > 0 && n == r); return (int)(_fp - start); } /// This stream class is unbuffered. /// /// This stream class is unbuffered. Therefore this method will always /// return 0 for streams connected to regular files. However, a /// stream created from a Named Pipe this method will query the server using a /// "peek named pipe" operation and return the number of available bytes /// on the server. /// /// public override int Available() { SmbNamedPipe pipe; TransPeekNamedPipe req; TransPeekNamedPipeResponse resp; if (File.Type != SmbFile.TypeNamedPipe) { return 0; } try { pipe = (SmbNamedPipe)File; File.Open(SmbFile.OExcl, pipe.PipeType & 0xFF0000, SmbFile.AttrNormal , 0); req = new TransPeekNamedPipe(File.Unc, File.Fid); resp = new TransPeekNamedPipeResponse(pipe); pipe.Send(req, resp); if (resp.status == TransPeekNamedPipeResponse.StatusDisconnected || resp.status == TransPeekNamedPipeResponse.StatusServerEndClosed) { File.Opened = false; return 0; } return resp.Available; } catch (SmbException se) { throw SeToIoe(se); } } /// Skip n bytes of data on this stream. /// /// Skip n bytes of data on this stream. This operation will not result /// in any IO with the server. Unlink InputStream value less than /// the one provided will not be returned if it exceeds the end of the file /// (if this is a problem let us know). /// /// public override long Skip(long n) { if (n > 0) { _fp += n; return n; } return 0; } /// /// Position in Stream /// /// /// Add by dobes /// mod interface to WrappedSystemStream readable, for random access. /// internal override long Position { get { return this._fp; } set { var tmpPos = value; var length = File.Length(); if (tmpPos < 0) tmpPos = 0; else if (length < tmpPos) tmpPos = length; this._fp = tmpPos; } } /// /// /// /// /// /// Add by dobes /// mod interface to WrappedSystemStream readable, for random access. /// internal override bool CanSeek() { return (File.Length() >= 0); } /// /// Get file length /// public override long Length { get { return File.Length(); } } } }