SmbFileInputStream.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  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;
  18. using System.IO;
  19. using SharpCifs.Util.Sharpen;
  20. using SharpCifs.Util.Transport;
  21. namespace SharpCifs.Smb
  22. {
  23. /// <summary>This InputStream can read bytes from a file on an SMB file server.</summary>
  24. /// <remarks>This InputStream can read bytes from a file on an SMB file server. Offsets are 64 bits.
  25. /// </remarks>
  26. public class SmbFileInputStream : InputStream
  27. {
  28. private long _fp;
  29. private int _readSize;
  30. private int _openFlags;
  31. private int _access;
  32. private byte[] _tmp = new byte[1];
  33. internal SmbFile File;
  34. /// <summary>
  35. /// Creates an
  36. /// <see cref="System.IO.InputStream">System.IO.InputStream</see>
  37. /// for reading bytes from a file on
  38. /// an SMB server addressed by the <code>url</code> parameter. See
  39. /// <see cref="SmbFile">SmbFile</see>
  40. /// for a detailed description and examples of the smb
  41. /// URL syntax.
  42. /// </summary>
  43. /// <param name="url">An smb URL string representing the file to read from</param>
  44. /// <exception cref="SharpCifs.Smb.SmbException"></exception>
  45. /// <exception cref="System.UriFormatException"></exception>
  46. /// <exception cref="UnknownHostException"></exception>
  47. public SmbFileInputStream(string url) : this(new SmbFile(url))
  48. {
  49. }
  50. /// <summary>
  51. /// Creates an
  52. /// <see cref="System.IO.InputStream">System.IO.InputStream</see>
  53. /// for reading bytes from a file on
  54. /// an SMB server represented by the
  55. /// <see cref="SmbFile">SmbFile</see>
  56. /// parameter. See
  57. /// <see cref="SmbFile">SmbFile</see>
  58. /// for a detailed description and examples of
  59. /// the smb URL syntax.
  60. /// </summary>
  61. /// <param name="file">An <code>SmbFile</code> specifying the file to read from</param>
  62. /// <exception cref="SharpCifs.Smb.SmbException"></exception>
  63. /// <exception cref="System.UriFormatException"></exception>
  64. /// <exception cref="UnknownHostException"></exception>
  65. public SmbFileInputStream(SmbFile file) : this(file, SmbFile.ORdonly)
  66. {
  67. }
  68. /// <exception cref="SharpCifs.Smb.SmbException"></exception>
  69. /// <exception cref="System.UriFormatException"></exception>
  70. /// <exception cref="UnknownHostException"></exception>
  71. internal SmbFileInputStream(SmbFile file, int openFlags)
  72. {
  73. this.File = file;
  74. this._openFlags = openFlags & 0xFFFF;
  75. _access = ((int)(((uint)openFlags) >> 16)) & 0xFFFF;
  76. if (file.Type != SmbFile.TypeNamedPipe)
  77. {
  78. file.Open(openFlags, _access, SmbFile.AttrNormal, 0);
  79. this._openFlags &= ~(SmbFile.OCreat | SmbFile.OTrunc);
  80. }
  81. else
  82. {
  83. file.Connect0();
  84. }
  85. _readSize = Math.Min(file.Tree.Session.transport.RcvBufSize - 70,
  86. file.Tree.Session.transport.Server.MaxBufferSize - 70);
  87. }
  88. protected internal virtual IOException SeToIoe(SmbException se)
  89. {
  90. IOException ioe = se;
  91. Exception root = se.GetRootCause();
  92. if (root is TransportException)
  93. {
  94. ioe = (TransportException)root;
  95. root = ((TransportException)ioe).GetRootCause();
  96. }
  97. if (root is Exception)
  98. {
  99. ioe = new IOException(root.Message);
  100. ioe.InitCause(root);
  101. }
  102. return ioe;
  103. }
  104. /// <summary>Closes this input stream and releases any system resources associated with the stream.
  105. /// </summary>
  106. /// <remarks>Closes this input stream and releases any system resources associated with the stream.
  107. /// </remarks>
  108. /// <exception cref="System.IO.IOException">if a network error occurs</exception>
  109. public override void Close()
  110. {
  111. try
  112. {
  113. File.Close();
  114. _tmp = null;
  115. }
  116. catch (SmbException se)
  117. {
  118. throw SeToIoe(se);
  119. }
  120. }
  121. /// <summary>Reads a byte of data from this input stream.</summary>
  122. /// <remarks>Reads a byte of data from this input stream.</remarks>
  123. /// <exception cref="System.IO.IOException">if a network error occurs</exception>
  124. public override int Read()
  125. {
  126. // need oplocks to cache otherwise use BufferedInputStream
  127. if (Read(_tmp, 0, 1) == -1)
  128. {
  129. return -1;
  130. }
  131. return _tmp[0] & unchecked(0xFF);
  132. }
  133. /// <summary>Reads up to b.length bytes of data from this input stream into an array of bytes.
  134. /// </summary>
  135. /// <remarks>Reads up to b.length bytes of data from this input stream into an array of bytes.
  136. /// </remarks>
  137. /// <exception cref="System.IO.IOException">if a network error occurs</exception>
  138. public override int Read(byte[] b)
  139. {
  140. return Read(b, 0, b.Length);
  141. }
  142. /// <summary>Reads up to len bytes of data from this input stream into an array of bytes.
  143. /// </summary>
  144. /// <remarks>Reads up to len bytes of data from this input stream into an array of bytes.
  145. /// </remarks>
  146. /// <exception cref="System.IO.IOException">if a network error occurs</exception>
  147. public override int Read(byte[] b, int off, int len)
  148. {
  149. return ReadDirect(b, off, len);
  150. }
  151. /// <exception cref="System.IO.IOException"></exception>
  152. public virtual int ReadDirect(byte[] b, int off, int len)
  153. {
  154. if (len <= 0)
  155. {
  156. return 0;
  157. }
  158. long start = _fp;
  159. if (_tmp == null)
  160. {
  161. throw new IOException("Bad file descriptor");
  162. }
  163. // ensure file is open
  164. File.Open(_openFlags, _access, SmbFile.AttrNormal, 0);
  165. if (File.Log.Level >= 4)
  166. {
  167. File.Log.WriteLine("read: fid=" + File.Fid + ",off=" + off + ",len=" + len);
  168. }
  169. SmbComReadAndXResponse response = new SmbComReadAndXResponse(b, off);
  170. if (File.Type == SmbFile.TypeNamedPipe)
  171. {
  172. response.ResponseTimeout = 0;
  173. }
  174. int r;
  175. int n;
  176. do
  177. {
  178. r = len > _readSize
  179. ? _readSize
  180. : len;
  181. if (File.Log.Level >= 4)
  182. {
  183. File.Log.WriteLine("read: len=" + len + ",r=" + r + ",fp=" + _fp);
  184. }
  185. try
  186. {
  187. SmbComReadAndX request = new SmbComReadAndX(File.Fid, _fp, r, null);
  188. if (File.Type == SmbFile.TypeNamedPipe)
  189. {
  190. request.MinCount = request.MaxCount = request.Remaining = 1024;
  191. }
  192. //ここで読み込んでいるらしい。
  193. File.Send(request, response);
  194. }
  195. catch (SmbException se)
  196. {
  197. if (File.Type == SmbFile.TypeNamedPipe
  198. && se.GetNtStatus() == NtStatus.NtStatusPipeBroken)
  199. {
  200. return -1;
  201. }
  202. throw SeToIoe(se);
  203. }
  204. if ((n = response.DataLength) <= 0)
  205. {
  206. return (int)((_fp - start) > 0L ? _fp - start : -1);
  207. }
  208. _fp += n;
  209. len -= n;
  210. response.Off += n;
  211. }
  212. while (len > 0 && n == r);
  213. return (int)(_fp - start);
  214. }
  215. /// <summary>This stream class is unbuffered.</summary>
  216. /// <remarks>
  217. /// This stream class is unbuffered. Therefore this method will always
  218. /// return 0 for streams connected to regular files. However, a
  219. /// stream created from a Named Pipe this method will query the server using a
  220. /// "peek named pipe" operation and return the number of available bytes
  221. /// on the server.
  222. /// </remarks>
  223. /// <exception cref="System.IO.IOException"></exception>
  224. public override int Available()
  225. {
  226. SmbNamedPipe pipe;
  227. TransPeekNamedPipe req;
  228. TransPeekNamedPipeResponse resp;
  229. if (File.Type != SmbFile.TypeNamedPipe)
  230. {
  231. return 0;
  232. }
  233. try
  234. {
  235. pipe = (SmbNamedPipe)File;
  236. File.Open(SmbFile.OExcl, pipe.PipeType & 0xFF0000, SmbFile.AttrNormal, 0);
  237. req = new TransPeekNamedPipe(File.Unc, File.Fid);
  238. resp = new TransPeekNamedPipeResponse(pipe);
  239. pipe.Send(req, resp);
  240. if (resp.status == TransPeekNamedPipeResponse.StatusDisconnected
  241. || resp.status == TransPeekNamedPipeResponse.StatusServerEndClosed)
  242. {
  243. File.Opened = false;
  244. return 0;
  245. }
  246. return resp.Available;
  247. }
  248. catch (SmbException se)
  249. {
  250. throw SeToIoe(se);
  251. }
  252. }
  253. /// <summary>Skip n bytes of data on this stream.</summary>
  254. /// <remarks>
  255. /// Skip n bytes of data on this stream. This operation will not result
  256. /// in any IO with the server. Unlink <tt>InputStream</tt> value less than
  257. /// the one provided will not be returned if it exceeds the end of the file
  258. /// (if this is a problem let us know).
  259. /// </remarks>
  260. /// <exception cref="System.IO.IOException"></exception>
  261. public override long Skip(long n)
  262. {
  263. if (n > 0)
  264. {
  265. _fp += n;
  266. return n;
  267. }
  268. return 0;
  269. }
  270. /// <summary>
  271. /// Position in Stream
  272. /// </summary>
  273. /// <remarks>
  274. /// Add by dobes
  275. /// mod interface to WrappedSystemStream readable, for random access.
  276. /// </remarks>
  277. internal override long Position
  278. {
  279. get { return this._fp; }
  280. set
  281. {
  282. var tmpPos = value;
  283. var length = File.Length();
  284. if (tmpPos < 0)
  285. tmpPos = 0;
  286. else if (length < tmpPos)
  287. tmpPos = length;
  288. this._fp = tmpPos;
  289. }
  290. }
  291. /// <summary>
  292. ///
  293. /// </summary>
  294. /// <returns></returns>
  295. /// <remarks>
  296. /// Add by dobes
  297. /// mod interface to WrappedSystemStream readable, for random access.
  298. /// </remarks>
  299. internal override bool CanSeek()
  300. {
  301. return (File.Length() >= 0);
  302. }
  303. /// <summary>
  304. /// Get file length
  305. /// </summary>
  306. public override long Length
  307. {
  308. get { return File.Length(); }
  309. }
  310. }
  311. }