// This code is derived from jcifs smb client library // Ported by J. Arturo // // 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 { /// This OutputStream can write bytes to a file on an SMB file server. /// /// This OutputStream can write bytes to a file on an SMB file server. /// 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; /// /// Creates an /// System.IO.OutputStream /// for writing to a file /// on an SMB server addressed by the URL parameter. See /// SmbFile /// for a detailed description and examples of /// the smb URL syntax. /// /// An smb URL string representing the file to write to /// /// /// public SmbFileOutputStream(string url) : this(url, false) { } /// /// Creates an /// System.IO.OutputStream /// for writing bytes to a file on /// an SMB server represented by the /// SmbFile /// parameter. See /// SmbFile /// for a detailed description and examples of /// the smb URL syntax. /// /// An SmbFile specifying the file to write to /// /// /// public SmbFileOutputStream(SmbFile file) : this(file, false) { } /// /// Creates an /// System.IO.OutputStream /// for writing bytes to a file on an /// SMB server addressed by the URL parameter. See /// SmbFile /// for a detailed description and examples of the smb URL syntax. If the /// second argument is true, then bytes will be written to the /// end of the file rather than the beginning. /// /// An smb URL string representing the file to write to /// Append to the end of file /// /// /// public SmbFileOutputStream(string url, bool append) : this(new SmbFile(url), append) { } /// /// Creates an /// System.IO.OutputStream /// for writing bytes to a file /// on an SMB server addressed by the SmbFile parameter. See /// SmbFile /// for a detailed description and examples of /// the smb URL syntax. If the second argument is true, then /// bytes will be written to the end of the file rather than the beginning. /// /// An SmbFile representing the file to write to /// Append to the end of file /// /// /// public SmbFileOutputStream(SmbFile file, bool append) : this(file, append, append ? SmbFile.OCreat | SmbFile.OWronly | SmbFile.OAppend : SmbFile.OCreat | SmbFile.OWronly | SmbFile.OTrunc) { } /// /// Creates an /// System.IO.OutputStream /// for writing bytes to a file /// on an SMB server addressed by the SmbFile parameter. See /// SmbFile /// for a detailed description and examples of /// the smb URL syntax. ///

/// The second parameter specifies how the file should be shared. If /// SmbFile.FILE_NO_SHARE 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 FILE_SHARE_READ, /// FILE_SHARE_WRITE, and FILE_SHARE_DELETE 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. ///

/// An smb URL representing the file to write to /// File sharing flag: SmbFile.FILE_NOSHARE or any combination of SmbFile.FILE_READ, SmbFile.FILE_WRITE, and SmbFile.FILE_DELETE /// /// /// /// public SmbFileOutputStream(string url, int shareAccess) : this(new SmbFile(url, string.Empty, null, shareAccess), false) { } /// /// /// 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(); } } /// /// Closes this output stream and releases any system resources associated /// with it. /// /// /// Closes this output stream and releases any system resources associated /// with it. /// /// if a network error occurs public override void Close() { _file.Close(); _tmp = null; } /// Writes the specified byte to this file output stream. /// Writes the specified byte to this file output stream. /// if a network error occurs public override void Write(int b) { _tmp[0] = unchecked((byte)b); Write(_tmp, 0, 1); } /// /// Writes b.length bytes from the specified byte array to this /// file output stream. /// /// /// Writes b.length bytes from the specified byte array to this /// file output stream. /// /// if a network error occurs public override void Write(byte[] b) { Write(b, 0, b.Length); } public virtual bool IsOpen() { return _file.IsOpen(); } /// 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(); } } } /// /// Writes len bytes from the specified byte array starting at /// offset off to this file output stream. /// /// /// Writes len bytes from the specified byte array starting at /// offset off to this file output stream. /// /// The array /// if a network error occurs 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); } /// Just bypasses TransWaitNamedPipe - used by DCERPC bind. /// Just bypasses TransWaitNamedPipe - used by DCERPC bind. /// 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); } } }