123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793 |
- /*
- * Copyright (C) 2006-2010 Alfresco Software Limited.
- *
- * This file is part of Alfresco
- *
- * Alfresco 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 3 of the License, or
- * (at your option) any later version.
- *
- * Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
- */
- package org.alfresco.jlan.client;
- import java.io.*;
- import java.net.SocketTimeoutException;
- import org.alfresco.jlan.client.info.FileInfo;
- import org.alfresco.jlan.netbios.RFCNetBIOSProtocol;
- import org.alfresco.jlan.smb.Dialect;
- import org.alfresco.jlan.smb.LockingAndX;
- import org.alfresco.jlan.smb.PacketType;
- import org.alfresco.jlan.smb.SMBDate;
- import org.alfresco.jlan.smb.SMBException;
- import org.alfresco.jlan.smb.SMBStatus;
- import org.alfresco.jlan.smb.SeekType;
- /**
- * SMB CIFS Data Pipe File Class
- *
- * <p>An SMB file provides read and/or write access to a remote named pipe.
- *
- * @author gkspencer
- */
- public final class DataPipeFile extends SMBFile {
- // Size of protocol packet to allocate
- private static final int DataSize = 4000;
- private static final int PacketSize = DataSize + 128;
- // Offset that the write data is placed within the write SMB packet, including protocol header of 4 bytes, and
- // padding byte count to word align the data
- private static final int WriteDataOffset = 64;
- private static final int WriteDataPadding = 1;
-
- // Maximum file offset for 32bit files
-
- private static final long Maximum32BitOffset = 0x0FFFFFFFFL;
- // state flag to indicate that the pipe is broken
-
- private static final int PipeBroken = 0x1000;
-
- // No timeout for read
-
- public static final int NoTimeout = 0;
-
- // Flag to indicate we are using NT dialect SMBs
-
- private boolean m_NTdialect;
-
- /**
- * Class constructor
- *
- * @param sess Session that this file is associated with
- * @param finfo File information for the new file
- * @param fid File identifier for this file
- */
- protected DataPipeFile(Session sess, FileInfo finfo, int fid) {
- super(sess, finfo, fid);
- // Set the NT dialect flag
- if ( sess.getDialect() == Dialect.NT)
- m_NTdialect = true;
- else
- m_NTdialect = false;
- }
- /**
- * Close the remote file.
- *
- * @param wrDateTime Set the last write date/time, or null to let the server set the date/time
- * @exception java.io.IOException If an I/O error occurs
- * @exception SMBException If an SMB level error occurs
- */
- public final void Close(SMBDate wrDateTime)
- throws java.io.IOException, SMBException {
- // Flush any buffered write data
- if ( m_txlen > 0)
- Flush();
- // Determine which packet to use to send the close file SMB
- SMBPacket pkt = new SMBPacket();
- pkt.setUserId(m_sess.getUserId());
- pkt.setTreeId(m_sess.getTreeId());
- // Close the remote file.
- pkt.setCommand(PacketType.CloseFile);
- pkt.setParameterCount(3);
- pkt.setParameter(0, m_FID);
- // Do not set a modified date/time
- pkt.setParameter(1, 0);
- pkt.setParameter(2, 0);
- // Indicate that the file has been closed
- this.setStateFlag(SMBFile.Closed, true);
- // Exchange the close file SMB packet with the file server
- try {
- pkt.ExchangeSMB(m_sess, pkt);
- }
- catch (java.io.IOException ex) {
- return;
- }
- // Release the transmit/receive packets
- m_rxpkt = null;
- m_txpkt = null;
- // Close the associated session
- getSession().CloseSession();
- return;
- }
- /**
- * Flush data to the remote file.
- *
- * @exception java.io.IOException If an I/O error occurs
- * @exception SMBException If an SMB level error occurs
- */
- public final void Flush()
- throws java.io.IOException, SMBException {
- // Check if there is any buffered write data
- if ( m_txlen > 0)
- WriteData();
- }
- /**
- * Read a block of data from the file.
- *
- * @param buf Byte buffer to receive the data.
- * @param siz Maximum length of data to receive.
- * @param offset Offset within buffer to place received data.
- * @return Actual length of data received.
- * @exception java.io.IOException If an I/O error occurs
- * @exception SMBException If an SMB level error occurs
- */
- public final int Read(byte[] buf, int siz, int offset)
- throws java.io.IOException, SMBException {
- // Read from the pipe
- return Read(buf, siz, offset, NoTimeout, siz);
- }
- /**
- * Read a block of data from the file.
- *
- * @param buf Byte buffer to receive the data.
- * @param siz Maximum length of data to receive.
- * @param offset Offset within buffer to place received data.
- * @param minSiz Minimum read size, zero will return immediately if there is no data
- * @return Actual length of data received.
- * @exception java.io.IOException If an I/O error occurs
- * @exception SMBException If an SMB level error occurs
- */
- public final int Read(byte[] buf, int siz, int offset, int minSiz)
- throws java.io.IOException, SMBException {
- // Read from the pipe
- return Read(buf, siz, offset, NoTimeout, minSiz);
- }
- /**
- * Read a block of data from the file.
- *
- * @param buf Byte buffer to receive the data.
- * @param siz Maximum length of data to receive.
- * @param offset Offset within buffer to place received data.
- * @param tmo Read timeout
- * @param minSiz Mimimum read size, zero will return immediately if there is no data
- * @return Actual length of data received.
- * @exception java.io.IOException If an I/O error occurs
- * @exception SMBException If an SMB level error occurs
- */
- private final int Read(byte[] buf, int siz, int offset, int tmo, int minSiz)
- throws java.io.IOException, SMBException {
- // Check if the file has been closed
- if ( this.isClosed())
- return -1;
- // Check if there is any data buffered
- if ( m_rxlen == 0) {
- // Read a packet of data from the remote pipe
- if ( ReadData(tmo, minSiz) == false)
- return -1;
- // Check if there is any buffered data
- if ( m_rxlen == 0)
- return 0;
- }
- // Copy data to the users buffer
- int retlen = m_rxlen;
- if ( retlen > siz)
- retlen = siz;
- byte[] pktbuf = m_rxpkt.getBuffer();
- System.arraycopy(pktbuf, m_rxoffset, buf, offset, retlen);
- // Update the buffered data offset/length
- m_rxlen -= retlen;
- m_rxoffset += retlen;
- // Return the amount of data read
- return retlen;
- }
- /**
- * Read a packet of data from the remote file.
- *
- * @param tmo Read timeout, zero for no timeout
- * @param minSiz Minimum read size, zero will return imeediately if there is no data
- * @return true if a valid data packet has been received, else false
- * @exception SMBException If an SMB level error occurs
- * @exception IOException If an I/O error occurs
- */
- private final boolean ReadData(int tmo, int minSiz)
- throws SMBException, IOException {
- // Check if the file offset requires large file support (64bit offsets)
- if ( isNTDialect() == false && m_rxpos > Maximum32BitOffset)
- throw new SMBException(SMBStatus.JLANErr, SMBStatus.JLANLargeFilesNotSupported);
- // If the pipe is broken then return an error
- if ( isPipeBroken())
- throw new SMBException(SMBStatus.NTErr, SMBStatus.NTPipeBroken);
- // Allocate and initialize a receive packet, if not already allocated
- if ( m_rxpkt == null) {
- // Allocate a receive packet
- m_rxpkt = m_sess.allocatePacket(PacketSize);
- // Initialize the packet
- m_rxpkt.setUserId(m_sess.getUserId());
- m_rxpkt.setTreeId(m_sess.getTreeId());
- }
- // Read a packet of data from the remote file
- m_rxpkt.setCommand(PacketType.ReadAndX);
- m_rxpkt.setParameterCount(isNTDialect() ? 12 : 10);
- m_rxpkt.setAndXCommand(PacketType.NoChainedCommand);
- m_rxpkt.setFlags(m_sess.getDefaultFlags());
- m_rxpkt.setFlags2(m_sess.getDefaultFlags2());
- m_rxpkt.setProcessId(m_sess.getProcessId());
- // Set the file id and read offset
- m_rxpkt.setParameter(2, getFileId());
- m_rxpkt.setParameterLong(3, (int) (m_rxpos & 0xFFFFFFFF));
- // Set the maximum read size
- int maxCount = m_rxpkt.getBuffer().length - 64;
- m_rxpkt.setParameter(5, maxCount);
- // Set the minimum read size
- m_rxpkt.setParameter(6, minSiz);
- // Read timeout, zero for no timeout
- m_rxpkt.setParameterLong(7, tmo);
- // Bytes remaining to satisfy request
- m_rxpkt.setParameter(9, maxCount);
- // Set the top 32bits of the file offset for NT dialect
- if ( isNTDialect())
- m_rxpkt.setParameterLong(10, (int) ((m_rxpos >> 32) & 0x0FFFFFFFFL));
- // No byte data
- m_rxpkt.setByteCount(0);
- // Exchange the read data SMB packet with the file server
- try {
- m_rxpkt.ExchangeSMB(m_sess, m_rxpkt, true);
- }
- catch (SocketTimeoutException ex) {
- return false;
- }
- catch (SMBException ex) {
- // Check for a pipe empty status
- if ( ex.getErrorClass() == SMBStatus.NTErr && ex.getErrorCode() == SMBStatus.NTPipeEmpty) {
- // Indicate success, but no data received so receive length will still be zero
- return true;
- }
- else if ( ex.getErrorClass() == SMBStatus.NTErr
- && (ex.getErrorCode() == SMBStatus.NTPipeBroken || ex.getErrorCode() == SMBStatus.NTPipeDisconnected)) {
- // Indicate end of file, and set the pipe broken state
- setStateFlag(SMBFile.EndOfFile, true);
- setStateFlag(PipeBroken, true);
- return false;
- }
- else {
- // Rethrow the exception
- throw ex;
- }
- }
- // Check if a valid response was received
- if ( m_rxpkt.isValidResponse()) {
- // Set the received data length and offset within the received data
- m_rxlen = m_rxpkt.getParameter(5);
- m_rxoffset = m_rxpkt.getParameter(6) + RFCNetBIOSProtocol.HEADER_LEN;
- // Update the current receive file position
- m_rxpos += m_rxlen;
- // Check if we have reached the end of file, indicated by a zero length
- // read.
- // if (m_rxlen == 0)
- // setStateFlag(SMBFile.EndOfFile, true);
- return true;
- }
- // Return a failure status
- return false;
- }
- /**
- * Write a block of data to the file.
- *
- * @param buf Byte buffer containing data to be written.
- * @param siz Length of data to be written.
- * @param offset Offset within buffer to start writing data from.
- * @return Actual length of data written.
- * @exception java.io.IOException If an I/O error occurs
- * @exception SMBException If an SMB level error occurs
- */
- public final int Write(byte[] buf, int siz, int offset)
- throws java.io.IOException, SMBException {
- // Check if the file has been closed
- if ( this.isClosed())
- return 0;
- // Allocate and initialize a transmit packet, if not already allocated
- if ( m_txpkt == null) {
- // Allocate a transmit packet
- m_txpkt = m_sess.allocatePacket(PacketSize);
- // Initialize the packet
- m_txpkt.setUserId(m_sess.getUserId());
- m_txpkt.setTreeId(m_sess.getTreeId());
- m_txpkt.setProcessId(m_sess.getProcessId());
- // Set the write SMB parameter count now, so that we can calculate the
- // offset of the byte buffer within the packet.
- m_txpkt.setParameterCount(isNTDialect() ? 14 : 12);
- // Clear the write packet length and initialize the write packet offset.
- m_txlen = 0;
- m_txoffset = WriteDataOffset;
- if ( isNTDialect())
- m_txoffset += 4;
- }
- // Move the data to the write packet and send write requests until the
- // user write has been done.
- int txlen = 0;
- while (txlen < siz) {
- // Determine if the current write request can be buffered in full
- byte[] pktbuf = m_txpkt.getBuffer();
- int len = pktbuf.length - m_txoffset;
- if ( len > (siz - txlen))
- len = siz - txlen;
- // Move the user data to the write packet
- System.arraycopy(buf, offset, pktbuf, m_txoffset, len);
- m_txoffset += len;
- offset += len;
- // Update the written data length
- txlen += len;
- m_txlen += len;
- // Write the data immediately for pipes
- WriteData();
- } // end while writing
- // Return the length of the data that was written
- return txlen;
- }
- /**
- * Write a packet of data to the remote file.
- *
- * @return true if the write was successful, else false
- * @exception SMBException If an SMB level error occurs
- * @exception IOException If an I/O error occurs
- */
- private final boolean WriteData()
- throws SMBException, IOException {
- // Check if the file offset requires large file support (64bit offsets)
- if ( isNTDialect() == false && m_txpos > Maximum32BitOffset)
- throw new SMBException(SMBStatus.JLANErr, SMBStatus.JLANLargeFilesNotSupported);
- // Write a packet of data to the remote file
- m_txpkt.setCommand(PacketType.WriteAndX);
- m_txpkt.setAndXCommand(PacketType.NoChainedCommand);
- m_txpkt.setFlags(m_sess.getDefaultFlags());
- m_txpkt.setFlags2(m_sess.getDefaultFlags2());
- m_txpkt.setParameterCount(isNTDialect() ? 14 : 12);
- // Set the file id and file offset
- m_txpkt.setParameter(2, getFileId());
- m_txpkt.setParameterLong(3, (int) (m_txpos & 0xFFFFFFFF));
- m_txpkt.setParameterLong(5, 0);
- // Set the write mode
- m_txpkt.setParameter(7, 0x0008); // pipe message start
- // Set the bytes remaining for request and reserved area
- m_txpkt.setParameter(8, m_txlen);
- m_txpkt.setParameter(9, 0);
- // Set the data length and offset from start of packet
- m_txpkt.setParameter(10, m_txlen);
- int offset = WriteDataOffset - RFCNetBIOSProtocol.HEADER_LEN;
- if ( isNTDialect())
- offset += 4;
- m_txpkt.setParameter(11, offset);
- // Add the top 32bits of the file offset, for NT dialect. Set the byte count, includes any
- // padding
- // bytes
- if ( isNTDialect()) {
- // Set the top 32bits of the file offset
- m_txpkt.setParameterLong(12, (int) ((m_txpos >> 32) & 0xFFFFFFFFL));
- }
- // Set the byte count, includes any padding bytes
- m_txpkt.setByteCount(m_txlen + WriteDataPadding);
- // Exchange the write data SMB packet with the file server
- m_txpkt.ExchangeSMB(m_sess, m_txpkt, false);
- // Check if a valid response was received
- if ( m_txpkt.isValidResponse()) {
- // Set the write data length
- int txlen = m_txpkt.getParameter(2);
- // Update the current write file position
- m_txpos += txlen;
- // Reset the write packet and write length
- m_txlen = 0;
- m_txoffset = WriteDataOffset;
- if ( isNTDialect())
- m_txoffset += 4;
- return true;
- }
- else {
- // Reset the write packet and write length
- m_txlen = 0;
- m_txoffset = WriteDataOffset;
- if ( isNTDialect())
- m_txoffset += 4;
- // Throw an exception
- m_txpkt.checkForError();
- }
- // Return a failure status
- return false;
- }
- /**
- * Seek to the specified point in the file. The seek may be relative to the start of file,
- * current file position or end of file.
- *
- * @param pos Relative offset
- * @param typ Seek type (@see org.alfresco.jlan.smb.SeekType)
- * @return New file offset from start of file
- * @exception IOException
- * @exception SMBException If an SMB level error occurs
- */
- public long Seek(long pos, int typ)
- throws IOException, SMBException {
- // Check if the file has been closed
- if ( this.isClosed())
- throw new IOException("Seek on closed file");
- // Flush any buffered data
- Flush();
- // Reset the read/write offsets to the new file position
- switch (typ) {
- // Seek relative to the start of file
- case SeekType.StartOfFile:
- m_txpos = m_rxpos = pos;
- break;
- // Seek realtive to the current file position
- case SeekType.CurrentPos:
- m_txpos = m_rxpos + pos;
- m_rxpos = m_txpos;
- break;
- // Seek relative to end of file
- case SeekType.EndOfFile:
- m_txpos = m_rxpos = getFileSize() + pos;
- break;
- }
- // Indicate that there is no buffered data
- m_txlen = 0;
- m_rxlen = 0;
- // Return the new file offset
- return m_rxpos;
- }
- /**
- * Lock a range of bytes within the file
- *
- * @param offset Offset within the file to start lock
- * @param len Number of bytes to lock
- * @exception IOException
- * @exception SMBException If an SMB level error occurs
- */
- public void Lock(long offset, long len)
- throws IOException, SMBException {
- // Check if the file offset requires large file support (64bit offsets)
- if ( isNTDialect() == false && offset > Maximum32BitOffset)
- throw new SMBException(SMBStatus.JLANErr, SMBStatus.JLANLargeFilesNotSupported);
- // Create the lock request packet
- SMBPacket pkt = new SMBPacket();
- pkt.setUserId(m_sess.getUserId());
- pkt.setTreeId(m_sess.getTreeId());
- pkt.setCommand(PacketType.LockingAndX);
- pkt.setProcessId(m_sess.getProcessId());
- // Set the parameters
- pkt.setParameterCount(8);
- pkt.setAndXCommand(PacketType.NoChainedCommand);
- pkt.setParameter(2, m_FID);
- pkt.setParameter(3, m_sess.supportsLargeFiles() ? LockingAndX.LargeFiles : 0);
- pkt.setParameterLong(4, 0); // timeout, for unlock
- pkt.setParameter(6, 0); // number of unlock structures
- pkt.setParameter(7, 1); // number of lock structures
- // Pack the lock structure
- pkt.resetBytePointer();
- if ( m_sess.supportsLargeFiles()) {
- // Pack a large file (64bit) format structure
- pkt.packWord(m_sess.getProcessId());
- pkt.packWord(0);
- pkt.packInt((int) ((offset >> 32) & 0xFFFFFFFFL));
- pkt.packInt((int) (offset & 0xFFFFFFFFL));
- pkt.packInt((int) ((len >> 32) & 0xFFFFFFFFL));
- pkt.packInt((int) (len & 0xFFFFFFFFL));
- }
- else {
- // Pack a normal (32bit) format structure
- pkt.packWord(m_sess.getProcessId());
- pkt.packInt((int) (offset & 0xFFFFFFFFL));
- pkt.packInt((int) (len & 0xFFFFFFFFL));
- }
- // Set the byte count
- pkt.setByteCount();
- // Send the lock request
- pkt.ExchangeSMB(m_sess, pkt, true);
- }
- /**
- * Unlock a range of bytes within the file
- *
- * @param offset Offset within the file to unlock
- * @param len Number of bytes to unlock
- * @exception IOException
- * @exception SMBException If an SMB level error occurs
- */
- public void Unlock(long offset, long len)
- throws IOException, SMBException {
- // Check if the file offset requires large file support (64bit offsets)
- if ( isNTDialect() == false && offset > Maximum32BitOffset)
- throw new SMBException(SMBStatus.JLANErr, SMBStatus.JLANLargeFilesNotSupported);
- // Create the unlock request packet
- SMBPacket pkt = new SMBPacket();
- pkt.setUserId(m_sess.getUserId());
- pkt.setTreeId(m_sess.getTreeId());
- pkt.setCommand(PacketType.LockingAndX);
- pkt.setProcessId(m_sess.getProcessId());
- // Set the parameters
- pkt.setParameterCount(8);
- pkt.setAndXCommand(PacketType.NoChainedCommand);
- pkt.setParameter(2, m_FID);
- pkt.setParameter(3, m_sess.supportsLargeFiles() ? LockingAndX.LargeFiles : 0);
- pkt.setParameterLong(4, 0); // timeout, for unlock
- pkt.setParameter(6, 1); // number of unlock structures
- pkt.setParameter(7, 0); // number of lock structures
- // Pack the unlock structure
- pkt.resetBytePointer();
- if ( m_sess.supportsLargeFiles()) {
- // Pack a large file (64bit) format structure
- pkt.packWord(m_sess.getProcessId());
- pkt.packWord(0);
- pkt.packInt((int) ((offset >> 32) & 0xFFFFFFFFL));
- pkt.packInt((int) (offset & 0xFFFFFFFFL));
- pkt.packInt((int) ((len >> 32) & 0xFFFFFFFFL));
- pkt.packInt((int) (len & 0xFFFFFFFFL));
- }
- else {
- // Pack a normal (32bit) format structure
- pkt.packWord(m_sess.getProcessId());
- pkt.packInt((int) (offset & 0xFFFFFFFFL));
- pkt.packInt((int) (len & 0xFFFFFFFFL));
- }
- // Set the byte count
- pkt.setByteCount();
- // Send the unlock request
- pkt.ExchangeSMB(m_sess, pkt, true);
- }
- /**
- * Check if NT dialect SMBs should be used
- *
- * @return boolean
- */
- protected final boolean isNTDialect() {
- return m_NTdialect;
- }
- /**
- * Check if the pipe is broken
- *
- * @return boolean
- */
- public final boolean isPipeBroken() {
- return hasStateFlag(PipeBroken);
- }
- }
|