SmbFileOutputStream.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. // This code is derived from jcifs smb client library <jcifs at samba dot org>
  2. // Ported by J. Arturo <webmaster at komodosoft dot net>
  3. //
  4. // This library is free software; you can redistribute it and/or
  5. // modify it under the terms of the GNU Lesser General Public
  6. // License as published by the Free Software Foundation; either
  7. // version 2.1 of the License, or (at your option) any later version.
  8. //
  9. // This library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. // Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public
  15. // License along with this library; if not, write to the Free Software
  16. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. using System.IO;
  18. using SharpCifs.Util.Sharpen;
  19. namespace SharpCifs.Smb
  20. {
  21. /// <summary>This <code>OutputStream</code> can write bytes to a file on an SMB file server.
  22. /// </summary>
  23. /// <remarks>This <code>OutputStream</code> can write bytes to a file on an SMB file server.
  24. /// </remarks>
  25. public class SmbFileOutputStream : OutputStream
  26. {
  27. private SmbFile _file;
  28. private bool _append;
  29. private bool _useNtSmbs;
  30. private int _openFlags;
  31. private int _access;
  32. private int _writeSize;
  33. private long _fp;
  34. private byte[] _tmp = new byte[1];
  35. private SmbComWriteAndX _reqx;
  36. private SmbComWriteAndXResponse _rspx;
  37. private SmbComWrite _req;
  38. private SmbComWriteResponse _rsp;
  39. /// <summary>
  40. /// Creates an
  41. /// <see cref="System.IO.OutputStream">System.IO.OutputStream</see>
  42. /// for writing to a file
  43. /// on an SMB server addressed by the URL parameter. See
  44. /// <see cref="SmbFile">SmbFile</see>
  45. /// for a detailed description and examples of
  46. /// the smb URL syntax.
  47. /// </summary>
  48. /// <param name="url">An smb URL string representing the file to write to</param>
  49. /// <exception cref="SharpCifs.Smb.SmbException"></exception>
  50. /// <exception cref="System.UriFormatException"></exception>
  51. /// <exception cref="UnknownHostException"></exception>
  52. public SmbFileOutputStream(string url) : this(url, false)
  53. {
  54. }
  55. /// <summary>
  56. /// Creates an
  57. /// <see cref="System.IO.OutputStream">System.IO.OutputStream</see>
  58. /// for writing bytes to a file on
  59. /// an SMB server represented by the
  60. /// <see cref="SmbFile">SmbFile</see>
  61. /// parameter. See
  62. /// <see cref="SmbFile">SmbFile</see>
  63. /// for a detailed description and examples of
  64. /// the smb URL syntax.
  65. /// </summary>
  66. /// <param name="file">An <code>SmbFile</code> specifying the file to write to</param>
  67. /// <exception cref="SharpCifs.Smb.SmbException"></exception>
  68. /// <exception cref="System.UriFormatException"></exception>
  69. /// <exception cref="UnknownHostException"></exception>
  70. public SmbFileOutputStream(SmbFile file) : this(file, false)
  71. {
  72. }
  73. /// <summary>
  74. /// Creates an
  75. /// <see cref="System.IO.OutputStream">System.IO.OutputStream</see>
  76. /// for writing bytes to a file on an
  77. /// SMB server addressed by the URL parameter. See
  78. /// <see cref="SmbFile">SmbFile</see>
  79. /// for a detailed description and examples of the smb URL syntax. If the
  80. /// second argument is <code>true</code>, then bytes will be written to the
  81. /// end of the file rather than the beginning.
  82. /// </summary>
  83. /// <param name="url">An smb URL string representing the file to write to</param>
  84. /// <param name="append">Append to the end of file</param>
  85. /// <exception cref="SharpCifs.Smb.SmbException"></exception>
  86. /// <exception cref="System.UriFormatException"></exception>
  87. /// <exception cref="UnknownHostException"></exception>
  88. public SmbFileOutputStream(string url, bool append) : this(new SmbFile(url), append)
  89. {
  90. }
  91. /// <summary>
  92. /// Creates an
  93. /// <see cref="System.IO.OutputStream">System.IO.OutputStream</see>
  94. /// for writing bytes to a file
  95. /// on an SMB server addressed by the <code>SmbFile</code> parameter. See
  96. /// <see cref="SmbFile">SmbFile</see>
  97. /// for a detailed description and examples of
  98. /// the smb URL syntax. If the second argument is <code>true</code>, then
  99. /// bytes will be written to the end of the file rather than the beginning.
  100. /// </summary>
  101. /// <param name="file">An <code>SmbFile</code> representing the file to write to</param>
  102. /// <param name="append">Append to the end of file</param>
  103. /// <exception cref="SharpCifs.Smb.SmbException"></exception>
  104. /// <exception cref="System.UriFormatException"></exception>
  105. /// <exception cref="UnknownHostException"></exception>
  106. public SmbFileOutputStream(SmbFile file, bool append)
  107. : this(file,
  108. append,
  109. append
  110. ? SmbFile.OCreat | SmbFile.OWronly | SmbFile.OAppend
  111. : SmbFile.OCreat | SmbFile.OWronly | SmbFile.OTrunc)
  112. {
  113. }
  114. /// <summary>
  115. /// Creates an
  116. /// <see cref="System.IO.OutputStream">System.IO.OutputStream</see>
  117. /// for writing bytes to a file
  118. /// on an SMB server addressed by the <code>SmbFile</code> parameter. See
  119. /// <see cref="SmbFile">SmbFile</see>
  120. /// for a detailed description and examples of
  121. /// the smb URL syntax.
  122. /// <p>
  123. /// The second parameter specifies how the file should be shared. If
  124. /// <code>SmbFile.FILE_NO_SHARE</code> is specified the client will
  125. /// have exclusive access to the file. An additional open command
  126. /// from jCIFS or another application will fail with the "file is being
  127. /// accessed by another process" error. The <code>FILE_SHARE_READ</code>,
  128. /// <code>FILE_SHARE_WRITE</code>, and <code>FILE_SHARE_DELETE</code> may be
  129. /// combined with the bitwise OR '|' to specify that other peocesses may read,
  130. /// write, and/or delete the file while the jCIFS user has the file open.
  131. /// </summary>
  132. /// <param name="url">An smb URL representing the file to write to</param>
  133. /// <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>
  134. /// </param>
  135. /// <exception cref="Jcifs.Smb.SmbException"></exception>
  136. /// <exception cref="System.UriFormatException"></exception>
  137. /// <exception cref="UnknownHostException"></exception>
  138. public SmbFileOutputStream(string url, int shareAccess)
  139. : this(new SmbFile(url, string.Empty, null, shareAccess), false)
  140. {
  141. }
  142. /// <exception cref="SharpCifs.Smb.SmbException"></exception>
  143. /// <exception cref="System.UriFormatException"></exception>
  144. /// <exception cref="UnknownHostException"></exception>
  145. internal SmbFileOutputStream(SmbFile file, bool append, int openFlags)
  146. {
  147. this._file = file;
  148. this._append = append;
  149. this._openFlags = openFlags;
  150. _access = ((int)(((uint)openFlags) >> 16)) & 0xFFFF;
  151. if (append)
  152. {
  153. try
  154. {
  155. _fp = file.Length();
  156. }
  157. catch (SmbAuthException sae)
  158. {
  159. throw;
  160. }
  161. catch (SmbException)
  162. {
  163. _fp = 0L;
  164. }
  165. }
  166. if (file is SmbNamedPipe && file.Unc.StartsWith("\\pipe\\"))
  167. {
  168. file.Unc = Runtime.Substring(file.Unc, 5);
  169. file.Send(new TransWaitNamedPipe("\\pipe" + file.Unc),
  170. new TransWaitNamedPipeResponse());
  171. }
  172. file.Open(openFlags,
  173. _access | SmbConstants.FileWriteData,
  174. SmbFile.AttrNormal,
  175. 0);
  176. this._openFlags &= ~(SmbFile.OCreat | SmbFile.OTrunc);
  177. _writeSize = file.Tree.Session.transport.SndBufSize - 70;
  178. _useNtSmbs = file.Tree.Session.transport.HasCapability(SmbConstants.CapNtSmbs);
  179. if (_useNtSmbs)
  180. {
  181. _reqx = new SmbComWriteAndX();
  182. _rspx = new SmbComWriteAndXResponse();
  183. }
  184. else
  185. {
  186. _req = new SmbComWrite();
  187. _rsp = new SmbComWriteResponse();
  188. }
  189. }
  190. /// <summary>
  191. /// Closes this output stream and releases any system resources associated
  192. /// with it.
  193. /// </summary>
  194. /// <remarks>
  195. /// Closes this output stream and releases any system resources associated
  196. /// with it.
  197. /// </remarks>
  198. /// <exception cref="System.IO.IOException">if a network error occurs</exception>
  199. public override void Close()
  200. {
  201. _file.Close();
  202. _tmp = null;
  203. }
  204. /// <summary>Writes the specified byte to this file output stream.</summary>
  205. /// <remarks>Writes the specified byte to this file output stream.</remarks>
  206. /// <exception cref="System.IO.IOException">if a network error occurs</exception>
  207. public override void Write(int b)
  208. {
  209. _tmp[0] = unchecked((byte)b);
  210. Write(_tmp, 0, 1);
  211. }
  212. /// <summary>
  213. /// Writes b.length bytes from the specified byte array to this
  214. /// file output stream.
  215. /// </summary>
  216. /// <remarks>
  217. /// Writes b.length bytes from the specified byte array to this
  218. /// file output stream.
  219. /// </remarks>
  220. /// <exception cref="System.IO.IOException">if a network error occurs</exception>
  221. public override void Write(byte[] b)
  222. {
  223. Write(b, 0, b.Length);
  224. }
  225. public virtual bool IsOpen()
  226. {
  227. return _file.IsOpen();
  228. }
  229. /// <exception cref="System.IO.IOException"></exception>
  230. internal virtual void EnsureOpen()
  231. {
  232. // ensure file is open
  233. if (_file.IsOpen() == false)
  234. {
  235. _file.Open(_openFlags,
  236. _access | SmbConstants.FileWriteData,
  237. SmbFile.AttrNormal,
  238. 0);
  239. if (_append)
  240. {
  241. _fp = _file.Length();
  242. }
  243. }
  244. }
  245. /// <summary>
  246. /// Writes len bytes from the specified byte array starting at
  247. /// offset off to this file output stream.
  248. /// </summary>
  249. /// <remarks>
  250. /// Writes len bytes from the specified byte array starting at
  251. /// offset off to this file output stream.
  252. /// </remarks>
  253. /// <param name="b">The array</param>
  254. /// <exception cref="System.IO.IOException">if a network error occurs</exception>
  255. public override void Write(byte[] b, int off, int len)
  256. {
  257. if (_file.IsOpen() == false && _file is SmbNamedPipe)
  258. {
  259. _file.Send(new TransWaitNamedPipe("\\pipe" + _file.Unc),
  260. new TransWaitNamedPipeResponse());
  261. }
  262. WriteDirect(b, off, len, 0);
  263. }
  264. /// <summary>Just bypasses TransWaitNamedPipe - used by DCERPC bind.</summary>
  265. /// <remarks>Just bypasses TransWaitNamedPipe - used by DCERPC bind.</remarks>
  266. /// <exception cref="System.IO.IOException"></exception>
  267. public virtual void WriteDirect(byte[] b, int off, int len, int flags)
  268. {
  269. if (len <= 0)
  270. {
  271. return;
  272. }
  273. if (_tmp == null)
  274. {
  275. throw new IOException("Bad file descriptor");
  276. }
  277. EnsureOpen();
  278. /*
  279. if (file.log.level >= 4)
  280. {
  281. file.log.WriteLine("write: fid=" + file.fid + ",off=" + off + ",len=" + len);
  282. }
  283. */
  284. int w;
  285. do
  286. {
  287. w = len > _writeSize ? _writeSize : len;
  288. if (_useNtSmbs)
  289. {
  290. _reqx.SetParam(_file.Fid, _fp, len - w, b, off, w);
  291. if ((flags & 1) != 0)
  292. {
  293. _reqx.SetParam(_file.Fid, _fp, len, b, off, w);
  294. _reqx.WriteMode = 0x8;
  295. }
  296. else
  297. {
  298. _reqx.WriteMode = 0;
  299. }
  300. _file.Send(_reqx, _rspx);
  301. _fp += _rspx.Count;
  302. len -= (int)_rspx.Count;
  303. off += (int)_rspx.Count;
  304. }
  305. else
  306. {
  307. _req.SetParam(_file.Fid, _fp, len - w, b, off, w);
  308. _fp += _rsp.Count;
  309. len -= (int)_rsp.Count;
  310. off += (int)_rsp.Count;
  311. _file.Send(_req, _rsp);
  312. }
  313. }
  314. while (len > 0);
  315. }
  316. }
  317. }