2017-04-02 00:36:06 +00:00
// 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
{
2017-06-21 06:46:57 +00:00
/// <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 ;
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
private bool _append ;
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
private bool _useNtSmbs ;
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
private int _openFlags ;
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
private int _access ;
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
private int _writeSize ;
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
private long _fp ;
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
private byte [ ] _tmp = new byte [ 1 ] ;
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
private SmbComWriteAndX _reqx ;
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
private SmbComWriteAndXResponse _rspx ;
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
private SmbComWrite _req ;
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
private SmbComWriteResponse _rsp ;
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
/// <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 )
{
}
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
/// <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 )
{
}
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
/// <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 )
{
}
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
/// <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 )
{
}
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
/// <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 )
{
}
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
/// <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 ( ) ;
}
}
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
/// <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 ;
}
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
/// <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 ) ;
}
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
/// <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 ) ;
}
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
public virtual bool IsOpen ( )
{
return _file . IsOpen ( ) ;
}
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
/// <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 ( ) ;
}
}
}
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
/// <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 ) ;
}
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
/// <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 )
2017-04-02 00:36:06 +00:00
{
file . log . WriteLine ( "write: fid=" + file . fid + ",off=" + off + ",len=" + len ) ;
}
2017-06-21 06:46:57 +00:00
* /
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 ) ;
}
}
2017-04-02 00:36:06 +00:00
}