mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-10-31 02:27:18 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			336 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			336 lines
		
	
	
		
			11 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.IO;
 | |
| using SharpCifs.Util.Sharpen;
 | |
| 
 | |
| namespace SharpCifs.Smb
 | |
| {
 | |
| 	/// <summary>This <code>OutputStream</code> can write bytes to a file on an SMB file server.
 | |
| 	/// 	</summary>
 | |
| 	/// <remarks>This <code>OutputStream</code> can write bytes to a file on an SMB file server.
 | |
| 	/// 	</remarks>
 | |
| 	public class SmbFileOutputStream : OutputStream
 | |
| 	{
 | |
| 		private SmbFile _file;
 | |
| 
 | |
| 		private bool _append;
 | |
| 
 | |
| 		private bool _useNtSmbs;
 | |
| 
 | |
| 		private int _openFlags;
 | |
| 
 | |
| 		private int _access;
 | |
| 
 | |
| 		private int _writeSize;
 | |
| 
 | |
| 		private long _fp;
 | |
| 
 | |
| 		private byte[] _tmp = new byte[1];
 | |
| 
 | |
| 		private SmbComWriteAndX _reqx;
 | |
| 
 | |
| 		private SmbComWriteAndXResponse _rspx;
 | |
| 
 | |
| 		private SmbComWrite _req;
 | |
| 
 | |
| 		private SmbComWriteResponse _rsp;
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Creates an
 | |
| 		/// <see cref="System.IO.OutputStream">System.IO.OutputStream</see>
 | |
| 		/// for writing to a file
 | |
| 		/// on an SMB server addressed by the URL 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 write to</param>
 | |
| 		/// <exception cref="SharpCifs.Smb.SmbException"></exception>
 | |
| 		/// <exception cref="System.UriFormatException"></exception>
 | |
| 		/// <exception cref="UnknownHostException"></exception>
 | |
| 		public SmbFileOutputStream(string url) : this(url, false)
 | |
| 		{
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Creates an
 | |
| 		/// <see cref="System.IO.OutputStream">System.IO.OutputStream</see>
 | |
| 		/// for writing bytes to 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 write to</param>
 | |
| 		/// <exception cref="SharpCifs.Smb.SmbException"></exception>
 | |
| 		/// <exception cref="System.UriFormatException"></exception>
 | |
| 		/// <exception cref="UnknownHostException"></exception>
 | |
| 		public SmbFileOutputStream(SmbFile file) : this(file, false)
 | |
| 		{
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Creates an
 | |
| 		/// <see cref="System.IO.OutputStream">System.IO.OutputStream</see>
 | |
| 		/// for writing bytes to a file on an
 | |
| 		/// SMB server addressed by the URL parameter. See
 | |
| 		/// <see cref="SmbFile">SmbFile</see>
 | |
| 		/// for a detailed description and examples of the smb URL syntax. If the
 | |
| 		/// second argument is <code>true</code>, then bytes will be written to the
 | |
| 		/// end of the file rather than the beginning.
 | |
| 		/// </summary>
 | |
| 		/// <param name="url">An smb URL string representing the file to write to</param>
 | |
| 		/// <param name="append">Append to the end of file</param>
 | |
| 		/// <exception cref="SharpCifs.Smb.SmbException"></exception>
 | |
| 		/// <exception cref="System.UriFormatException"></exception>
 | |
| 		/// <exception cref="UnknownHostException"></exception>
 | |
| 		public SmbFileOutputStream(string url, bool append) : this(new SmbFile(url), append
 | |
| 			)
 | |
| 		{
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Creates an
 | |
| 		/// <see cref="System.IO.OutputStream">System.IO.OutputStream</see>
 | |
| 		/// for writing bytes to a file
 | |
| 		/// on an SMB server addressed by the <code>SmbFile</code> parameter. See
 | |
| 		/// <see cref="SmbFile">SmbFile</see>
 | |
| 		/// for a detailed description and examples of
 | |
| 		/// the smb URL syntax. If the second argument is <code>true</code>, then
 | |
| 		/// bytes will be written to the end of the file rather than the beginning.
 | |
| 		/// </summary>
 | |
| 		/// <param name="file">An <code>SmbFile</code> representing the file to write to</param>
 | |
| 		/// <param name="append">Append to the end of file</param>
 | |
| 		/// <exception cref="SharpCifs.Smb.SmbException"></exception>
 | |
| 		/// <exception cref="System.UriFormatException"></exception>
 | |
| 		/// <exception cref="UnknownHostException"></exception>
 | |
| 		public SmbFileOutputStream(SmbFile file, bool append) : this(file, append, append
 | |
| 			 ? SmbFile.OCreat | SmbFile.OWronly | SmbFile.OAppend : SmbFile.OCreat | SmbFile
 | |
| 			.OWronly | SmbFile.OTrunc)
 | |
| 		{
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Creates an
 | |
| 		/// <see cref="System.IO.OutputStream">System.IO.OutputStream</see>
 | |
| 		/// for writing bytes to a file
 | |
| 		/// on an SMB server addressed by the <code>SmbFile</code> parameter. See
 | |
| 		/// <see cref="SmbFile">SmbFile</see>
 | |
| 		/// for a detailed description and examples of
 | |
| 		/// the smb URL syntax.
 | |
| 		/// <p>
 | |
| 		/// The second parameter specifies how the file should be shared. If
 | |
| 		/// <code>SmbFile.FILE_NO_SHARE</code> is specified the client will
 | |
| 		/// have exclusive access to the file. An additional open command
 | |
| 		/// from jCIFS or another application will fail with the "file is being
 | |
| 		/// accessed by another process" error. The <code>FILE_SHARE_READ</code>,
 | |
| 		/// <code>FILE_SHARE_WRITE</code>, and <code>FILE_SHARE_DELETE</code> may be
 | |
| 		/// combined with the bitwise OR '|' to specify that other peocesses may read,
 | |
| 		/// write, and/or delete the file while the jCIFS user has the file open.
 | |
| 		/// </summary>
 | |
| 		/// <param name="url">An smb URL representing the file to write to</param>
 | |
| 		/// <param name="shareAccess">File sharing flag: <code>SmbFile.FILE_NOSHARE</code> or any combination of <code>SmbFile.FILE_READ</code>, <code>SmbFile.FILE_WRITE</code>, and <code>SmbFile.FILE_DELETE</code>
 | |
| 		/// 	</param>
 | |
| 		/// <exception cref="Jcifs.Smb.SmbException"></exception>
 | |
| 		/// <exception cref="System.UriFormatException"></exception>
 | |
| 		/// <exception cref="UnknownHostException"></exception>
 | |
| 		public SmbFileOutputStream(string url, int shareAccess) : this(new SmbFile(url, string.Empty
 | |
| 			, null, shareAccess), false)
 | |
| 		{
 | |
| 		}
 | |
| 
 | |
| 		/// <exception cref="SharpCifs.Smb.SmbException"></exception>
 | |
| 		/// <exception cref="System.UriFormatException"></exception>
 | |
| 		/// <exception cref="UnknownHostException"></exception>
 | |
| 		internal SmbFileOutputStream(SmbFile file, bool append, int openFlags)
 | |
| 		{
 | |
| 			this._file = file;
 | |
| 			this._append = append;
 | |
| 			this._openFlags = openFlags;
 | |
| 			_access = ((int)(((uint)openFlags) >> 16)) & 0xFFFF;
 | |
| 			if (append)
 | |
| 			{
 | |
| 				try
 | |
| 				{
 | |
| 					_fp = file.Length();
 | |
| 				}
 | |
| 				catch (SmbAuthException sae)
 | |
| 				{
 | |
| 					throw;
 | |
| 				}
 | |
| 				catch (SmbException)
 | |
| 				{
 | |
| 					_fp = 0L;
 | |
| 				}
 | |
| 			}
 | |
| 			if (file is SmbNamedPipe && file.Unc.StartsWith("\\pipe\\"))
 | |
| 			{
 | |
| 				file.Unc = Runtime.Substring(file.Unc, 5);
 | |
| 				file.Send(new TransWaitNamedPipe("\\pipe" + file.Unc), new TransWaitNamedPipeResponse
 | |
| 					());
 | |
| 			}
 | |
| 			file.Open(openFlags, _access | SmbConstants.FileWriteData, SmbFile.AttrNormal, 
 | |
| 				0);
 | |
| 			this._openFlags &= ~(SmbFile.OCreat | SmbFile.OTrunc);
 | |
| 			_writeSize = file.Tree.Session.transport.SndBufSize - 70;
 | |
| 			_useNtSmbs = file.Tree.Session.transport.HasCapability(SmbConstants.CapNtSmbs
 | |
| 				);
 | |
| 			if (_useNtSmbs)
 | |
| 			{
 | |
| 				_reqx = new SmbComWriteAndX();
 | |
| 				_rspx = new SmbComWriteAndXResponse();
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				_req = new SmbComWrite();
 | |
| 				_rsp = new SmbComWriteResponse();
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Closes this output stream and releases any system resources associated
 | |
| 		/// with it.
 | |
| 		/// </summary>
 | |
| 		/// <remarks>
 | |
| 		/// Closes this output stream and releases any system resources associated
 | |
| 		/// with it.
 | |
| 		/// </remarks>
 | |
| 		/// <exception cref="System.IO.IOException">if a network error occurs</exception>
 | |
| 		public override void Close()
 | |
| 		{
 | |
| 			_file.Close();
 | |
| 			_tmp = null;
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>Writes the specified byte to this file output stream.</summary>
 | |
| 		/// <remarks>Writes the specified byte to this file output stream.</remarks>
 | |
| 		/// <exception cref="System.IO.IOException">if a network error occurs</exception>
 | |
| 		public override void Write(int b)
 | |
| 		{
 | |
| 			_tmp[0] = unchecked((byte)b);
 | |
| 			Write(_tmp, 0, 1);
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Writes b.length bytes from the specified byte array to this
 | |
| 		/// file output stream.
 | |
| 		/// </summary>
 | |
| 		/// <remarks>
 | |
| 		/// Writes b.length bytes from the specified byte array to this
 | |
| 		/// file output stream.
 | |
| 		/// </remarks>
 | |
| 		/// <exception cref="System.IO.IOException">if a network error occurs</exception>
 | |
| 		public override void Write(byte[] b)
 | |
| 		{
 | |
| 			Write(b, 0, b.Length);
 | |
| 		}
 | |
| 
 | |
| 		public virtual bool IsOpen()
 | |
| 		{
 | |
| 			return _file.IsOpen();
 | |
| 		}
 | |
| 
 | |
| 		/// <exception cref="System.IO.IOException"></exception>
 | |
| 		internal virtual void EnsureOpen()
 | |
| 		{
 | |
| 			// ensure file is open
 | |
| 			if (_file.IsOpen() == false)
 | |
| 			{
 | |
| 				_file.Open(_openFlags, _access | SmbConstants.FileWriteData, SmbFile.AttrNormal, 
 | |
| 					0);
 | |
| 				if (_append)
 | |
| 				{
 | |
| 					_fp = _file.Length();
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Writes len bytes from the specified byte array starting at
 | |
| 		/// offset off to this file output stream.
 | |
| 		/// </summary>
 | |
| 		/// <remarks>
 | |
| 		/// Writes len bytes from the specified byte array starting at
 | |
| 		/// offset off to this file output stream.
 | |
| 		/// </remarks>
 | |
| 		/// <param name="b">The array</param>
 | |
| 		/// <exception cref="System.IO.IOException">if a network error occurs</exception>
 | |
| 		public override void Write(byte[] b, int off, int len)
 | |
| 		{
 | |
| 			if (_file.IsOpen() == false && _file is SmbNamedPipe)
 | |
| 			{
 | |
| 				_file.Send(new TransWaitNamedPipe("\\pipe" + _file.Unc), new TransWaitNamedPipeResponse
 | |
| 					());
 | |
| 			}
 | |
| 			WriteDirect(b, off, len, 0);
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>Just bypasses TransWaitNamedPipe - used by DCERPC bind.</summary>
 | |
| 		/// <remarks>Just bypasses TransWaitNamedPipe - used by DCERPC bind.</remarks>
 | |
| 		/// <exception cref="System.IO.IOException"></exception>
 | |
| 		public virtual void WriteDirect(byte[] b, int off, int len, int flags)
 | |
| 		{
 | |
| 			if (len <= 0)
 | |
| 			{
 | |
| 				return;
 | |
| 			}
 | |
| 			if (_tmp == null)
 | |
| 			{
 | |
| 				throw new IOException("Bad file descriptor");
 | |
| 			}
 | |
| 			EnsureOpen();
 | |
| 			/*if (file.log.level >= 4)
 | |
| 			{
 | |
| 				file.log.WriteLine("write: fid=" + file.fid + ",off=" + off + ",len=" + len);
 | |
| 			}*/
 | |
| 			int w;
 | |
| 			do
 | |
| 			{
 | |
| 				w = len > _writeSize ? _writeSize : len;
 | |
| 				if (_useNtSmbs)
 | |
| 				{
 | |
| 					_reqx.SetParam(_file.Fid, _fp, len - w, b, off, w);
 | |
| 					if ((flags & 1) != 0)
 | |
| 					{
 | |
| 						_reqx.SetParam(_file.Fid, _fp, len, b, off, w);
 | |
| 						_reqx.WriteMode = 0x8;
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						_reqx.WriteMode = 0;
 | |
| 					}
 | |
| 					_file.Send(_reqx, _rspx);
 | |
| 					_fp += _rspx.Count;
 | |
| 					len -= (int)_rspx.Count;
 | |
| 					off += (int)_rspx.Count;
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					_req.SetParam(_file.Fid, _fp, len - w, b, off, w);
 | |
| 					_fp += _rsp.Count;
 | |
| 					len -= (int)_rsp.Count;
 | |
| 					off += (int)_rsp.Count;
 | |
| 					_file.Send(_req, _rsp);
 | |
| 				}
 | |
| 			}
 | |
| 			while (len > 0);
 | |
| 		}
 | |
| 	}
 | |
| }
 |