CoreFile.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. /*
  2. * Copyright (C) 2006-2010 Alfresco Software Limited.
  3. *
  4. * This file is part of Alfresco
  5. *
  6. * Alfresco is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Alfresco is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. package org.alfresco.jlan.client;
  20. import java.io.IOException;
  21. import org.alfresco.jlan.client.info.FileInfo;
  22. import org.alfresco.jlan.smb.DataType;
  23. import org.alfresco.jlan.smb.PacketType;
  24. import org.alfresco.jlan.smb.SMBDate;
  25. import org.alfresco.jlan.smb.SMBException;
  26. import org.alfresco.jlan.util.DataPacker;
  27. /**
  28. * SMB core file class
  29. *
  30. * @author gkspencer
  31. */
  32. public class CoreFile extends SMBFile {
  33. // Size of protocol packet to allocate
  34. private static final int DataSize = 4000;
  35. private static final int PacketSize = DataSize + 64;
  36. // Offset that the write data is placed within the write SMB packet
  37. private static final int WriteDataOffset = 52;
  38. /**
  39. * Class constructor
  40. *
  41. * @param sess Session that this file is associated with
  42. * @param finfo File information for the new file
  43. * @param fid File identifier for this file
  44. */
  45. protected CoreFile(Session sess, FileInfo finfo, int fid) {
  46. super(sess, finfo, fid);
  47. }
  48. /**
  49. * Close the remote file.
  50. *
  51. * @param wrDateTime Set the last write date/time, or null to let the server set the date/time
  52. * @exception java.io.IOException If an I/O error occurs
  53. * @exception SMBException If an SMB level error occurs
  54. */
  55. public void Close(SMBDate wrDateTime)
  56. throws java.io.IOException, SMBException {
  57. // Flush any buffered write data
  58. if ( m_txlen > 0)
  59. Flush();
  60. // Determine which packet to use to send the close file SMB
  61. SMBPacket pkt = new SMBPacket();
  62. pkt.setUserId(m_sess.getUserId());
  63. pkt.setTreeId(m_sess.getTreeId());
  64. // Close the remote file.
  65. pkt.setCommand(PacketType.CloseFile);
  66. pkt.setParameterCount(3);
  67. pkt.setParameter(0, m_FID);
  68. // Check if the last write date/time should be set
  69. if ( wrDateTime != null) {
  70. // Set the last write date/time for the file
  71. pkt.setParameter(1, wrDateTime.asSMBTime());
  72. pkt.setParameter(2, wrDateTime.asSMBDate());
  73. }
  74. else {
  75. // Let the server set the last write date/time
  76. pkt.setParameter(1, 0);
  77. pkt.setParameter(2, 0);
  78. }
  79. // Indicate that the file has been closed
  80. this.setStateFlag(SMBFile.Closed, true);
  81. // Exchange the close file SMB packet with the file server
  82. try {
  83. pkt.ExchangeSMB(m_sess, pkt);
  84. }
  85. catch (java.io.IOException ex) {
  86. return;
  87. }
  88. // Release the transmit/receive packets
  89. m_rxpkt = null;
  90. m_txpkt = null;
  91. return;
  92. }
  93. /**
  94. * Flush data to the remote file.
  95. *
  96. * @exception java.io.IOException If an I/O error occurs
  97. * @exception SMBException If an SMB level error occurs
  98. */
  99. public void Flush()
  100. throws java.io.IOException, SMBException {
  101. // Check if there is any buffered write data
  102. if ( m_txlen > 0)
  103. WriteData();
  104. }
  105. /**
  106. * Read a block of data from the file.
  107. *
  108. * @param buf Byte buffer to receive the data.
  109. * @param siz Maximum length of data to receive.
  110. * @param offset Offset within buffer to place received data.
  111. * @return Actual length of data received.
  112. * @exception java.io.IOException If an I/O error occurs
  113. * @exception SMBException If an SMB level error occurs
  114. */
  115. public int Read(byte[] buf, int siz, int offset)
  116. throws java.io.IOException, SMBException {
  117. // Check if the file has been closed
  118. if ( this.isClosed())
  119. return 0;
  120. // Copy data into the users receive buffer
  121. int retlen = 0;
  122. int bufidx = offset;
  123. while (retlen < siz && !this.atEndOfFile()) {
  124. // Check if there is any data buffered
  125. if ( m_rxlen == 0) {
  126. // Read a packet of data from the remote file
  127. if ( ReadData() == false)
  128. return -1;
  129. }
  130. // Check if enough data is buffered
  131. int rxlen = siz;
  132. if ( rxlen > m_rxlen)
  133. rxlen = m_rxlen;
  134. // Copy data to the users buffer
  135. byte[] pktbuf = m_rxpkt.getBuffer();
  136. for (int idx = 0; idx < rxlen; idx++)
  137. buf[bufidx + idx] = pktbuf[m_rxoffset + idx];
  138. // Update the buffered data offset/length
  139. m_rxlen -= rxlen;
  140. m_rxoffset += rxlen;
  141. bufidx += rxlen;
  142. // Update the returned data length
  143. retlen += rxlen;
  144. } // end while
  145. // Return the actual data received
  146. return retlen;
  147. }
  148. /**
  149. * Read a packet of data from the remote file.
  150. *
  151. * @return true if a valid data packet has been received, else false
  152. */
  153. private final boolean ReadData() {
  154. // Allocate and initialize a receive packet, if not already allocated
  155. if ( m_rxpkt == null) {
  156. // Allocate a receive packet
  157. m_rxpkt = new SMBPacket();
  158. // Initialize the packet
  159. m_rxpkt.setUserId(m_sess.getUserId());
  160. m_rxpkt.setTreeId(m_sess.getTreeId());
  161. }
  162. // Read a packet of data from the remote file.
  163. // Initialize the read packet.
  164. m_rxpkt.setCommand(PacketType.ReadFile);
  165. m_rxpkt.setParameterCount(5);
  166. m_rxpkt.setParameter(0, m_FID);
  167. if ( (m_rxpos + DataSize) > getFileSize())
  168. m_rxpkt.setParameter(1, (int) (getFileSize() - m_rxpos));
  169. else
  170. m_rxpkt.setParameter(1, DataSize);
  171. m_rxpkt.setParameter(2, (int) m_rxpos & 0xFFFF);
  172. m_rxpkt.setParameter(3, (int) (m_rxpos & 0xFFFF0000) >> 16);
  173. m_rxpkt.setParameter(4, DataSize);
  174. // Exchange the read data SMB packet with the file server
  175. try {
  176. m_rxpkt.ExchangeSMB(m_sess, m_rxpkt);
  177. }
  178. catch (SMBException ex) {
  179. return false;
  180. }
  181. catch (java.io.IOException ex) {
  182. return false;
  183. }
  184. // Check if a valid response was received
  185. if ( m_rxpkt.isValidResponse()) {
  186. // Set the received data length and offset within the received data
  187. int rxlen = m_rxpkt.getParameter(0);
  188. m_rxoffset = m_rxpkt.getByteOffset();
  189. byte[] buf = m_rxpkt.getBuffer();
  190. if ( buf[m_rxoffset++] != DataType.DataBlock)
  191. return false;
  192. // Get the received data block length
  193. m_rxlen = DataPacker.getIntelShort(buf, m_rxoffset);
  194. m_rxoffset += 2;
  195. // Update the current receive file position
  196. m_rxpos += m_rxlen;
  197. // Check if we have reached the end of file, indicated by a zero length
  198. // read.
  199. if ( m_rxlen == 0)
  200. setStateFlag(SMBFile.EndOfFile, true);
  201. return true;
  202. }
  203. // Return a failure status
  204. return false;
  205. }
  206. /**
  207. * Write a block of data to the file.
  208. *
  209. * @param buf Byte buffer containing data to be written.
  210. * @param siz Length of data to be written.
  211. * @param offset Offset within buffer to start writing data from.
  212. * @return Actual length of data written.
  213. * @exception java.io.IOException If an I/O error occurs
  214. * @exception SMBException If an SMB level error occurs
  215. */
  216. public int Write(byte[] buf, int siz, int offset)
  217. throws java.io.IOException, SMBException {
  218. // Check if the file has been closed
  219. if ( this.isClosed())
  220. return 0;
  221. // Allocate and initialize a transmit packet, if not already allocated
  222. if ( m_txpkt == null) {
  223. // Allocate a transmit packet
  224. m_txpkt = new SMBPacket();
  225. // Initialize the packet
  226. m_txpkt.setUserId(m_sess.getUserId());
  227. m_txpkt.setTreeId(m_sess.getTreeId());
  228. // Set the write SMB parameter count now, so that we can calculate the
  229. // offset of the byte buffer within the packet.
  230. m_txpkt.setParameterCount(5);
  231. // Clear the write packet length and initialize the write packet offset.
  232. m_txlen = 0;
  233. m_txoffset = WriteDataOffset;
  234. }
  235. // Move the data to the write packet and send write requests until the
  236. // user write has been done.
  237. int txlen = 0;
  238. byte[] pktbuf = m_txpkt.getBuffer();
  239. while (txlen < siz) {
  240. // Determine if the current write request can be buffered in full
  241. int len = pktbuf.length - m_txoffset;
  242. if ( len > (siz - txlen))
  243. len = (siz - txlen);
  244. // Move the user data to the write packet
  245. for (int idx = 0; idx < len; idx++)
  246. pktbuf[m_txoffset++] = buf[offset++];
  247. // Update the written data length
  248. txlen += len;
  249. m_txlen += len;
  250. // Check if the write packet is full, if so then send the write packet
  251. if ( m_txoffset >= pktbuf.length)
  252. WriteData();
  253. } // end while writing
  254. // Return the length of the data that was written
  255. return txlen;
  256. }
  257. /**
  258. * Write a packet of data to the remote file.
  259. *
  260. * @return true if the write was successful, else false
  261. */
  262. private final boolean WriteData() {
  263. // Write a packet of data to the remote file.
  264. // Initialize the write packet.
  265. m_txpkt.setCommand(PacketType.WriteFile);
  266. m_txpkt.setParameterCount(5);
  267. m_txpkt.setParameter(0, m_FID);
  268. m_txpkt.setParameter(1, m_txlen);
  269. m_txpkt.setParameter(2, (int) m_txpos & 0xFFFF);
  270. m_txpkt.setParameter(3, (int) (m_txpos & 0xFFFF0000) >> 16);
  271. m_txpkt.setParameter(4, m_txlen);
  272. // Set the byte count
  273. m_txpkt.setByteCount(m_txlen + 3);
  274. // Initialize the write data block
  275. byte[] buf = m_txpkt.getBuffer();
  276. int bytoff = m_txpkt.getByteOffset();
  277. buf[bytoff++] = (byte) DataType.DataBlock;
  278. DataPacker.putIntelShort(m_txlen, buf, bytoff);
  279. // Exchange the write data SMB packet with the file server
  280. try {
  281. m_txpkt.ExchangeSMB(m_sess, m_txpkt);
  282. }
  283. catch (SMBException ex) {
  284. return false;
  285. }
  286. catch (java.io.IOException ex) {
  287. return false;
  288. }
  289. // Check if a valid response was received
  290. if ( m_txpkt.isValidResponse()) {
  291. // Set the write data length
  292. int txlen = m_txpkt.getParameter(0);
  293. // Update the current write file position
  294. m_txpos += txlen;
  295. // Reset the write packet and write length
  296. m_txlen = 0;
  297. m_txoffset = WriteDataOffset;
  298. return true;
  299. }
  300. // Return a failure status
  301. return false;
  302. }
  303. /**
  304. * Seek to the specified point in the file. The seek may be relative to the start of file,
  305. * current file position or end of file.
  306. *
  307. * @param pos Relative offset
  308. * @param typ Seek type (@see org.alfresco.jlan.smb.SeekType)
  309. * @return New file offset from start of file
  310. * @exception IOException
  311. * @exception SMBException If an SMB level error occurs
  312. */
  313. public long Seek(long pos, int typ)
  314. throws IOException, SMBException {
  315. // Check if the file has been closed
  316. if ( this.isClosed())
  317. throw new IOException("Seek on closed file");
  318. // Flush any buffered data
  319. Flush();
  320. // Initialize the file seek packet.
  321. m_txpkt.setCommand(PacketType.SeekFile);
  322. m_txpkt.setParameterCount(4);
  323. m_txpkt.setParameter(0, m_FID);
  324. m_txpkt.setParameter(1, typ);
  325. m_txpkt.setParameterLong(2, (int) pos & 0xFFFFFFFF);
  326. m_txpkt.setByteCount(0);
  327. // Exchange the seek file SMB packet with the file server
  328. m_txpkt.ExchangeSMB(m_sess, m_txpkt);
  329. // Check if a valid response was received
  330. if ( m_txpkt.isValidResponse()) {
  331. // Get the new file position, relative to the start of the file
  332. int filePos = m_txpkt.getParameter(0) + (m_txpkt.getParameter(1) << 16);
  333. // Reset the file read/write offsets
  334. m_txpos = filePos;
  335. m_rxpos = filePos;
  336. // Indicate that there is no buffered data
  337. m_txlen = 0;
  338. m_rxlen = 0;
  339. // Return the new file offset
  340. return filePos;
  341. }
  342. // Return a failure status
  343. return -1;
  344. }
  345. /**
  346. * Lock a range of bytes within the file
  347. *
  348. * @param offset Offset within the file to start lock
  349. * @param len Number of bytes to lock
  350. * @exception IOException
  351. * @exception SMBException If an SMB level error occurs
  352. */
  353. public void Lock(long offset, long len)
  354. throws IOException, SMBException {
  355. }
  356. /**
  357. * Unlock a range of bytes within the file
  358. *
  359. * @param offset Offset within the file to unlock
  360. * @param len Number of bytes to unlock
  361. * @exception IOException
  362. * @exception SMBException If an SMB level error occurs
  363. */
  364. public void Unlock(long offset, long len)
  365. throws IOException, SMBException {
  366. }
  367. }