aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFileInputStream.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFileInputStream.cs')
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFileInputStream.cs339
1 files changed, 339 insertions, 0 deletions
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFileInputStream.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFileInputStream.cs
new file mode 100644
index 000000000..a9a0ea112
--- /dev/null
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFileInputStream.cs
@@ -0,0 +1,339 @@
+// This code is derived from jcifs smb client library <jcifs at samba dot org>
+// Ported by J. Arturo <webmaster at komodosoft dot net>
+//
+// 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
+{
+ /// <summary>This InputStream can read bytes from a file on an SMB file server.</summary>
+ /// <remarks>This InputStream can read bytes from a file on an SMB file server. Offsets are 64 bits.
+ /// </remarks>
+ 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;
+
+ /// <summary>
+ /// Creates an
+ /// <see cref="System.IO.InputStream">System.IO.InputStream</see>
+ /// for reading bytes from a file on
+ /// an SMB server addressed by the <code>url</code> parameter. See
+ /// <see cref="SmbFile">SmbFile</see>
+ /// for a detailed description and examples of the smb
+ /// URL syntax.
+ /// </summary>
+ /// <param name="url">An smb URL string representing the file to read from</param>
+ /// <exception cref="SharpCifs.Smb.SmbException"></exception>
+ /// <exception cref="System.UriFormatException"></exception>
+ /// <exception cref="UnknownHostException"></exception>
+ public SmbFileInputStream(string url) : this(new SmbFile(url))
+ {
+ }
+
+ /// <summary>
+ /// Creates an
+ /// <see cref="System.IO.InputStream">System.IO.InputStream</see>
+ /// for reading bytes from a file on
+ /// an SMB server represented by the
+ /// <see cref="SmbFile">SmbFile</see>
+ /// parameter. See
+ /// <see cref="SmbFile">SmbFile</see>
+ /// for a detailed description and examples of
+ /// the smb URL syntax.
+ /// </summary>
+ /// <param name="file">An <code>SmbFile</code> specifying the file to read from</param>
+ /// <exception cref="SharpCifs.Smb.SmbException"></exception>
+ /// <exception cref="System.UriFormatException"></exception>
+ /// <exception cref="UnknownHostException"></exception>
+ public SmbFileInputStream(SmbFile file) : this(file, SmbFile.ORdonly)
+ {
+ }
+
+ /// <exception cref="SharpCifs.Smb.SmbException"></exception>
+ /// <exception cref="System.UriFormatException"></exception>
+ /// <exception cref="UnknownHostException"></exception>
+ 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;
+ }
+
+ /// <summary>Closes this input stream and releases any system resources associated with the stream.
+ /// </summary>
+ /// <remarks>Closes this input stream and releases any system resources associated with the stream.
+ /// </remarks>
+ /// <exception cref="System.IO.IOException">if a network error occurs</exception>
+ public override void Close()
+ {
+ try
+ {
+ File.Close();
+ _tmp = null;
+ }
+ catch (SmbException se)
+ {
+ throw SeToIoe(se);
+ }
+ }
+
+ /// <summary>Reads a byte of data from this input stream.</summary>
+ /// <remarks>Reads a byte of data from this input stream.</remarks>
+ /// <exception cref="System.IO.IOException">if a network error occurs</exception>
+ public override int Read()
+ {
+ // need oplocks to cache otherwise use BufferedInputStream
+ if (Read(_tmp, 0, 1) == -1)
+ {
+ return -1;
+ }
+ return _tmp[0] & unchecked(0xFF);
+ }
+
+ /// <summary>Reads up to b.length bytes of data from this input stream into an array of bytes.
+ /// </summary>
+ /// <remarks>Reads up to b.length bytes of data from this input stream into an array of bytes.
+ /// </remarks>
+ /// <exception cref="System.IO.IOException">if a network error occurs</exception>
+ public override int Read(byte[] b)
+ {
+ return Read(b, 0, b.Length);
+ }
+
+ /// <summary>Reads up to len bytes of data from this input stream into an array of bytes.
+ /// </summary>
+ /// <remarks>Reads up to len bytes of data from this input stream into an array of bytes.
+ /// </remarks>
+ /// <exception cref="System.IO.IOException">if a network error occurs</exception>
+ public override int Read(byte[] b, int off, int len)
+ {
+ return ReadDirect(b, off, len);
+ }
+
+ /// <exception cref="System.IO.IOException"></exception>
+ 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);
+ }
+
+ /// <summary>This stream class is unbuffered.</summary>
+ /// <remarks>
+ /// 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.
+ /// </remarks>
+ /// <exception cref="System.IO.IOException"></exception>
+ 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);
+ }
+ }
+
+ /// <summary>Skip n bytes of data on this stream.</summary>
+ /// <remarks>
+ /// Skip n bytes of data on this stream. This operation will not result
+ /// in any IO with the server. Unlink <tt>InputStream</tt> 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).
+ /// </remarks>
+ /// <exception cref="System.IO.IOException"></exception>
+ public override long Skip(long n)
+ {
+ if (n > 0)
+ {
+ _fp += n;
+ return n;
+ }
+ return 0;
+ }
+
+
+ /// <summary>
+ /// Position in Stream
+ /// </summary>
+ /// <remarks>
+ /// Add by dobes
+ /// mod interface to WrappedSystemStream readable, for random access.
+ /// </remarks>
+ 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;
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ /// <remarks>
+ /// Add by dobes
+ /// mod interface to WrappedSystemStream readable, for random access.
+ /// </remarks>
+ internal override bool CanSeek()
+ {
+ return (File.Length() >= 0);
+ }
+
+ /// <summary>
+ /// Get file length
+ /// </summary>
+ public override long Length
+ {
+ get { return File.Length(); }
+ }
+
+ }
+}