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);
|
||
|
}
|
||
|
}
|
||
|
}
|