2
0

SmbFileInputStream.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  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, file.Tree.Session
  86. .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 ? _readSize : len;
  179. if (File.Log.Level >= 4)
  180. {
  181. File.Log.WriteLine("read: len=" + len + ",r=" + r + ",fp=" + _fp);
  182. }
  183. try
  184. {
  185. SmbComReadAndX request = new SmbComReadAndX(File.Fid, _fp, r, null);
  186. if (File.Type == SmbFile.TypeNamedPipe)
  187. {
  188. request.MinCount = request.MaxCount = request.Remaining = 1024;
  189. }
  190. //ここで読み込んでいるらしい。
  191. File.Send(request, response);
  192. }
  193. catch (SmbException se)
  194. {
  195. if (File.Type == SmbFile.TypeNamedPipe && se.GetNtStatus() == NtStatus.NtStatusPipeBroken)
  196. {
  197. return -1;
  198. }
  199. throw SeToIoe(se);
  200. }
  201. if ((n = response.DataLength) <= 0)
  202. {
  203. return (int)((_fp - start) > 0L ? _fp - start : -1);
  204. }
  205. _fp += n;
  206. len -= n;
  207. response.Off += n;
  208. }
  209. while (len > 0 && n == r);
  210. return (int)(_fp - start);
  211. }
  212. /// <summary>This stream class is unbuffered.</summary>
  213. /// <remarks>
  214. /// This stream class is unbuffered. Therefore this method will always
  215. /// return 0 for streams connected to regular files. However, a
  216. /// stream created from a Named Pipe this method will query the server using a
  217. /// "peek named pipe" operation and return the number of available bytes
  218. /// on the server.
  219. /// </remarks>
  220. /// <exception cref="System.IO.IOException"></exception>
  221. public override int Available()
  222. {
  223. SmbNamedPipe pipe;
  224. TransPeekNamedPipe req;
  225. TransPeekNamedPipeResponse resp;
  226. if (File.Type != SmbFile.TypeNamedPipe)
  227. {
  228. return 0;
  229. }
  230. try
  231. {
  232. pipe = (SmbNamedPipe)File;
  233. File.Open(SmbFile.OExcl, pipe.PipeType & 0xFF0000, SmbFile.AttrNormal
  234. , 0);
  235. req = new TransPeekNamedPipe(File.Unc, File.Fid);
  236. resp = new TransPeekNamedPipeResponse(pipe);
  237. pipe.Send(req, resp);
  238. if (resp.status == TransPeekNamedPipeResponse.StatusDisconnected || resp.status
  239. == TransPeekNamedPipeResponse.StatusServerEndClosed)
  240. {
  241. File.Opened = false;
  242. return 0;
  243. }
  244. return resp.Available;
  245. }
  246. catch (SmbException se)
  247. {
  248. throw SeToIoe(se);
  249. }
  250. }
  251. /// <summary>Skip n bytes of data on this stream.</summary>
  252. /// <remarks>
  253. /// Skip n bytes of data on this stream. This operation will not result
  254. /// in any IO with the server. Unlink <tt>InputStream</tt> value less than
  255. /// the one provided will not be returned if it exceeds the end of the file
  256. /// (if this is a problem let us know).
  257. /// </remarks>
  258. /// <exception cref="System.IO.IOException"></exception>
  259. public override long Skip(long n)
  260. {
  261. if (n > 0)
  262. {
  263. _fp += n;
  264. return n;
  265. }
  266. return 0;
  267. }
  268. /// <summary>
  269. /// Position in Stream
  270. /// </summary>
  271. /// <remarks>
  272. /// Add by dobes
  273. /// mod interface to WrappedSystemStream readable, for random access.
  274. /// </remarks>
  275. internal override long Position {
  276. get { return this._fp; }
  277. set
  278. {
  279. var tmpPos = value;
  280. var length = File.Length();
  281. if (tmpPos < 0)
  282. tmpPos = 0;
  283. else if (length < tmpPos)
  284. tmpPos = length;
  285. this._fp = tmpPos;
  286. }
  287. }
  288. /// <summary>
  289. ///
  290. /// </summary>
  291. /// <returns></returns>
  292. /// <remarks>
  293. /// Add by dobes
  294. /// mod interface to WrappedSystemStream readable, for random access.
  295. /// </remarks>
  296. internal override bool CanSeek()
  297. {
  298. return (File.Length() >= 0);
  299. }
  300. /// <summary>
  301. /// Get file length
  302. /// </summary>
  303. public override long Length
  304. {
  305. get { return File.Length(); }
  306. }
  307. }
  308. }