mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-11-03 19:17:24 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			340 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			340 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
// 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;
 | 
						||
					}
 | 
						||
                    //<2F><><EFBFBD><EFBFBD><EFBFBD>œǂݍ<C782><DD8D><EFBFBD><EFBFBD>ł<EFBFBD><C582><EFBFBD><EFBFBD>炵<EFBFBD><E782B5><EFBFBD>B
 | 
						||
					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(); }
 | 
						||
	    }
 | 
						||
        
 | 
						||
	}
 | 
						||
}
 |