@@ -30,9 +43,16 @@ import java.io.*; * * @author GKSpencer */ -public class FTPDataSession implements Runnable +public class FTPDataSession extends SrvSession implements Runnable { + // Debug logging + private static final Log logger = LogFactory.getLog("org.alfresco.ftp.protocol"); + + // Data session command types + + public enum DataCommand { StoreFile, ReturnFile }; + // FTP session that this data connection is associated with private FTPSrvSession m_cmdSess; @@ -54,10 +74,6 @@ public class FTPDataSession implements Runnable private ServerSocket m_passiveSock; - // Adapter to bind the passive socket to - - private InetAddress m_bindAddr; - // Transfer in progress and abort file transfer flags private boolean m_transfer; @@ -66,7 +82,27 @@ public class FTPDataSession implements Runnable // Send/receive data byte count private long m_bytCount; + + // Data command type + + private DataCommand m_dataCmd; + + // Requested file name + + private String m_reqFileName; + + // Path to the local file + + private FTPPath m_ftpPath; + // Restart position + + private long m_restartPos; + + // Thread that runs the data command + + private Thread m_dataThread; + /** * Class constructor *
@@ -77,7 +113,10 @@ public class FTPDataSession implements Runnable
*/
protected FTPDataSession(FTPSrvSession sess) throws IOException
{
-
+ // Setup the base class
+
+ super( -1, sess.getServer(), "FTPDATA", null);
+
// Set the associated command session
m_cmdSess = sess;
@@ -100,6 +139,9 @@ public class FTPDataSession implements Runnable
*/
protected FTPDataSession(FTPSrvSession sess, int localPort, InetAddress bindAddr) throws IOException
{
+ // Setup the base class
+
+ super( -1, sess.getServer(), "FTPDATA", null);
// Set the associated command session
@@ -124,6 +166,9 @@ public class FTPDataSession implements Runnable
*/
protected FTPDataSession(FTPSrvSession sess, InetAddress bindAddr) throws IOException
{
+ // Setup the base class
+
+ super( -1, sess.getServer(), "FTPDATA", null);
// Set the associated command session
@@ -146,6 +191,9 @@ public class FTPDataSession implements Runnable
*/
protected FTPDataSession(FTPSrvSession sess, InetAddress addr, int port)
{
+ // Setup the base class
+
+ super( -1, sess.getServer(), "FTPDATA", null);
// Set the associated command session
@@ -171,6 +219,9 @@ public class FTPDataSession implements Runnable
*/
protected FTPDataSession(FTPSrvSession sess, int localPort, InetAddress addr, int port)
{
+ // Setup the base class
+
+ super( -1, sess.getServer(), "FTPDATA", null);
// Set the associated command session
@@ -271,6 +322,16 @@ public class FTPDataSession implements Runnable
return m_transfer;
}
+ /**
+ * Determine if the transfer has been aborted
+ *
+ * @return boolean
+ */
+ public final boolean isTransferAborted()
+ {
+ return m_abort;
+ }
+
/**
* Abort an in progress file transfer
*/
@@ -358,12 +419,520 @@ public class FTPDataSession implements Runnable
}
m_passiveSock = null;
}
+
+ // Commit, or rollback, any active user transaction
+
+ try
+ {
+ // Commit or rollback the transaction
+
+ endTransaction();
+ }
+ catch ( Exception ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Error committing transaction", ex);
+ }
}
+ /**
+ * Store a file using a seperate thread to receive the data and write the file
+ *
+ * @param ftpPath FTPPath
+ */
+ public final void doStoreFile( FTPPath ftpPath, long restartPos, String reqFileName)
+ {
+ // Set the transfer details
+
+ m_dataCmd = DataCommand.StoreFile;
+ m_ftpPath = ftpPath;
+ m_restartPos = restartPos;
+ m_reqFileName = reqFileName;
+
+ // Run the transfer in a seperate thread
+
+ m_dataThread = new Thread(this);
+ m_dataThread.setName(m_cmdSess.getUniqueId() + "_DATA_STORE");
+ m_dataThread.start();
+ }
+
+ /**
+ * Return a file using a seperate thread to read the file and send the data
+ *
+ * @param ftpPath FTPPath
+ */
+ public final void doReturnFile( FTPPath ftpPath, long restartPos, String reqFileName)
+ {
+ // Set the transfer details
+
+ m_dataCmd = DataCommand.ReturnFile;
+ m_ftpPath = ftpPath;
+ m_restartPos = restartPos;
+ m_reqFileName = reqFileName;
+
+ // Run the transfer in a seperate thread
+
+ m_dataThread = new Thread(this);
+ m_dataThread.setName(m_cmdSess.getUniqueId() + "_DATA_RETURN");
+ m_dataThread.start();
+ }
+
/**
* Run a file send/receive in a seperate thread
*/
public void run()
{
+ // Setup the authentication context as we are running in a seperate thread from the main FTP session
+
+ try
+ {
+ // Setup the authentication context for the thread
+
+ m_cmdSess.authenticateDataSession();
+
+ // Run the required data command
+
+ switch ( m_dataCmd)
+ {
+ // Store a file
+
+ case StoreFile:
+ runStoreFile();
+ break;
+
+ // Return a file
+
+ case ReturnFile:
+ runReturnFile();
+ break;
+ }
+ }
+ catch ( org.alfresco.repo.security.authentication.AuthenticationException ex)
+ {
+ if ( logger.isErrorEnabled())
+ logger.error("Failed to authenticate FTP data session", ex);
+
+ // Close the data connection to the client
+
+ m_cmdSess.getFTPServer().releaseDataSession(this);
+ closeSession();
+ }
}
+
+ /**
+ * Return a file to the client
+ */
+ private final void runReturnFile()
+ {
+ // Send the file to the client
+
+ OutputStream os = null;
+ DiskInterface disk = null;
+ TreeConnection tree = null;
+ NetworkFile netFile = null;
+ Socket dataSock = null;
+
+ try
+ {
+
+ // Open an output stream to the client
+
+ dataSock = getSocket();
+ os = dataSock.getOutputStream();
+
+ // Create a temporary tree connection
+
+ tree = m_cmdSess.getTreeConnection(m_ftpPath.getSharedDevice());
+
+ // Check if the file exists and it is a file, if so then open the
+ // file
+
+ disk = (DiskInterface) m_ftpPath.getSharedDevice().getInterface();
+
+ // Create the file open parameters
+
+ FileOpenParams params = new FileOpenParams(m_ftpPath.getSharePath(), FileAction.OpenIfExists,
+ AccessMode.ReadOnly, 0);
+
+ // Check if the file exists and it is a file
+
+ int sts = disk.fileExists( this, tree, m_ftpPath.getSharePath());
+
+ if (sts == FileStatus.FileExists)
+ {
+
+ // Open the file
+
+ netFile = disk.openFile( this, tree, params);
+ }
+
+ // Check if the file has been opened
+
+ if (netFile == null)
+ {
+ m_cmdSess.sendFTPResponse(550, "File " + m_reqFileName + " not available");
+ return;
+ }
+
+ // Allocate the buffer for the file data
+
+ byte[] buf = new byte[FTPSrvSession.DEFAULT_BUFFERSIZE];
+ long filePos = m_restartPos;
+
+ int len = -1;
+
+ while (filePos < netFile.getFileSize())
+ {
+
+ // Read another block of data from the file
+
+ len = disk.readFile( this, tree, netFile, buf, 0, buf.length, filePos);
+
+ // DEBUG
+
+ if (logger.isDebugEnabled() && m_cmdSess.hasDebug(FTPSrvSession.DBG_FILEIO))
+ logger.debug(" Write len=" + len + " bytes");
+
+ // Write the current data block to the client, update the file position
+
+ if (len > 0)
+ {
+
+ // Write the data to the client
+
+ os.write(buf, 0, len);
+
+ // Update the file position
+
+ filePos += len;
+
+ // Update the transfer byte count
+
+ m_bytCount += len;
+ }
+
+ // Check if the transfer has been aborted
+
+ if ( isTransferAborted())
+ {
+ // DEBUG
+
+ if (logger.isDebugEnabled() && m_cmdSess.hasDebug(FTPSrvSession.DBG_FILE))
+ logger.debug(" Transfer aborted (RETR)");
+
+ // Send a status to the client
+
+ sendFTPResponse( 226, "Aborted data connection");
+
+ // Finally block will cleanup
+
+ return;
+ }
+ }
+
+ // Close the output stream to the client
+
+ os.close();
+ os = null;
+
+ // Indicate that the file has been transmitted
+
+ sendFTPResponse(226, "Closing data connection");
+
+ // Close the data session
+
+ m_cmdSess.getFTPServer().releaseDataSession(this);
+
+ // Close the network file
+
+ disk.closeFile( this, tree, netFile);
+ netFile = null;
+
+ // DEBUG
+
+ if (logger.isDebugEnabled() && m_cmdSess.hasDebug(FTPSrvSession.DBG_FILEIO))
+ logger.debug(" Transfer complete, file closed");
+ }
+ catch (SocketException ex)
+ {
+
+ // DEBUG
+
+ if (logger.isDebugEnabled() && m_cmdSess.hasDebug(FTPSrvSession.DBG_ERROR))
+ logger.debug(" Error during transfer", ex);
+
+ // Indicate that there was an error during transmission of the file
+ // data
+
+ sendFTPResponse(426, "Data connection closed by client");
+ }
+ catch (Exception ex)
+ {
+
+ // DEBUG
+
+ if (logger.isDebugEnabled() && m_cmdSess.hasDebug(FTPSrvSession.DBG_ERROR))
+ logger.debug(" Error during transfer", ex);
+
+ // Indicate that there was an error during transmission of the file
+ // data
+
+ sendFTPResponse(426, "Error during transmission");
+ }
+ finally
+ {
+ try
+ {
+ // Close the network file
+
+ if (netFile != null && disk != null && tree != null)
+ disk.closeFile(m_cmdSess, tree, netFile);
+
+ // Close the output stream to the client
+
+ if (os != null)
+ os.close();
+
+ // Close the data connection to the client
+
+ m_cmdSess.getFTPServer().releaseDataSession( this);
+ closeSession();
+ }
+ catch (Exception ex)
+ {
+ if ( logger.isErrorEnabled())
+ logger.error( "Error during FTP data session close", ex);
+ }
+ }
+ }
+
+ /**
+ * Store a file received from the client
+ */
+ private final void runStoreFile()
+ {
+ // Store the file from the client
+
+ InputStream is = null;
+ DiskInterface disk = null;
+ TreeConnection tree = null;
+ NetworkFile netFile = null;
+ Socket dataSock = null;
+
+ try
+ {
+
+ // Create a temporary tree connection
+
+ tree = m_cmdSess.getTreeConnection(m_ftpPath.getSharedDevice());
+
+ // Check if the session has the required access to the filesystem
+
+ if (tree == null || tree.hasWriteAccess() == false)
+ {
+
+ // Session does not have write access to the filesystem
+
+ sendFTPResponse(550, "Access denied");
+ return;
+ }
+
+ // Check if the file exists
+
+ disk = (DiskInterface) m_ftpPath.getSharedDevice().getInterface();
+ int sts = disk.fileExists(this, tree, m_ftpPath.getSharePath());
+
+ if (sts == FileStatus.DirectoryExists)
+ {
+
+ // Return an error status
+
+ sendFTPResponse(500, "Invalid path (existing directory)");
+ return;
+ }
+
+ // Create the file open parameters
+
+ FileOpenParams params = new FileOpenParams(m_ftpPath.getSharePath(),
+ sts == FileStatus.FileExists ? FileAction.TruncateExisting : FileAction.CreateNotExist,
+ AccessMode.ReadWrite, 0);
+
+ // Create a new file to receive the data
+
+ if (sts == FileStatus.FileExists)
+ {
+
+ // Overwrite the existing file
+
+ netFile = disk.openFile(this, tree, params);
+ }
+ else
+ {
+
+ // Create a new file
+
+ netFile = disk.createFile(this, tree, params);
+ }
+
+ // Notify change listeners that a new file has been created
+
+ DiskDeviceContext diskCtx = (DiskDeviceContext) tree.getContext();
+
+ if (diskCtx.hasChangeHandler())
+ diskCtx.getChangeHandler().notifyFileChanged(NotifyChange.ActionAdded, m_ftpPath.getSharePath());
+
+ // Send the intermediate response
+
+ sendFTPResponse(150, "File status okay, about to open data connection");
+
+ // Get the data connection socket
+
+ try
+ {
+ dataSock = getSocket();
+ }
+ catch (Exception ex)
+ {
+ }
+
+ if (dataSock == null)
+ {
+ sendFTPResponse(426, "Connection closed; transfer aborted");
+ return;
+ }
+
+ // Open an input stream from the client
+
+ is = dataSock.getInputStream();
+
+ // DEBUG
+
+ if (logger.isDebugEnabled() && m_cmdSess.hasDebug(FTPSrvSession.DBG_FILE))
+ logger.debug("Storing ftp="
+ + m_ftpPath.getFTPPath() + ", share=" + m_ftpPath.getShareName() + ", path="
+ + m_ftpPath.getSharePath());
+
+ // Allocate the buffer for the file data
+
+ byte[] buf = new byte[FTPSrvSession.DEFAULT_BUFFERSIZE];
+ long filePos = 0;
+ int len = is.read(buf, 0, buf.length);
+
+ while (len > 0)
+ {
+
+ // DEBUG
+
+ if (logger.isDebugEnabled() && m_cmdSess.hasDebug(FTPSrvSession.DBG_FILEIO))
+ logger.debug(" Receive len=" + len + " bytes");
+
+ // Write the current data block to the file, update the file
+ // position
+
+ disk.writeFile(this, tree, netFile, buf, 0, len, filePos);
+ filePos += len;
+
+ // Read another block of data from the client
+
+ len = is.read(buf, 0, buf.length);
+ }
+
+ // Close the input stream from the client
+
+ is.close();
+ is = null;
+
+ // Close the network file
+
+ disk.closeFile(this, tree, netFile);
+ netFile = null;
+
+ // Indicate that the file has been received
+
+ sendFTPResponse(226, "Closing data connection");
+
+ // DEBUG
+
+ if (logger.isDebugEnabled() && m_cmdSess.hasDebug(FTPSrvSession.DBG_FILEIO))
+ logger.debug(" Transfer complete, file closed");
+ }
+ catch (SocketException ex)
+ {
+
+ // DEBUG
+
+ if (logger.isDebugEnabled() && m_cmdSess.hasDebug(FTPSrvSession.DBG_ERROR))
+ logger.debug(" Error during transfer", ex);
+
+ // Indicate that there was an error during transmission of the file data
+
+ sendFTPResponse(426, "Data connection closed by client");
+ }
+ catch (Exception ex)
+ {
+
+ // DEBUG
+
+ if (logger.isDebugEnabled() && m_cmdSess.hasDebug(FTPSrvSession.DBG_ERROR))
+ logger.debug(" Error during transfer", ex);
+
+ // Indicate that there was an error during transmission of the file
+ // data
+
+ sendFTPResponse(426, "Error during transmission");
+ }
+ finally
+ {
+ try
+ {
+ // Close the network file
+
+ if (netFile != null && disk != null && tree != null)
+ disk.closeFile( this, tree, netFile);
+
+ // Close the input stream to the client
+
+ if (is != null)
+ is.close();
+
+ // Close the data connection to the client
+
+ m_cmdSess.getFTPServer().releaseDataSession(this);
+ closeSession();
+ }
+ catch (Exception ex)
+ {
+ if ( logger.isErrorEnabled())
+ logger.error( "Error during FTP data session close", ex);
+ }
+ }
+ }
+
+ /**
+ * Send an FTP response to the client via the command session
+ *
+ * @param stsCode int
+ * @param msg String
+ */
+ protected final void sendFTPResponse(int stsCode, String msg)
+ {
+ try
+ {
+ m_cmdSess.sendFTPResponse( stsCode, msg);
+ }
+ catch (Exception ex)
+ {
+ }
+ }
+
+ /**
+ * Return the client address
+ *
+ * @return InetAddress
+ */
+ public InetAddress getRemoteAddress() {
+ return m_cmdSess.getRemoteAddress();
+ }
}
diff --git a/source/java/org/alfresco/filesys/ftp/FTPDate.java b/source/java/org/alfresco/filesys/ftp/FTPDate.java
index 6e68d691eb..7436de2880 100644
--- a/source/java/org/alfresco/filesys/ftp/FTPDate.java
+++ b/source/java/org/alfresco/filesys/ftp/FTPDate.java
@@ -98,10 +98,10 @@ public class FTPDate
buf.append(hr);
buf.append(":");
- int sec = cal.get(Calendar.SECOND);
- if (sec < 10)
+ int min = cal.get(Calendar.MINUTE);
+ if (min < 10)
buf.append("0");
- buf.append(sec);
+ buf.append(min);
}
}
}
diff --git a/source/java/org/alfresco/filesys/ftp/FTPSrvSession.java b/source/java/org/alfresco/filesys/ftp/FTPSrvSession.java
index ee7993f36e..b47c2fb724 100644
--- a/source/java/org/alfresco/filesys/ftp/FTPSrvSession.java
+++ b/source/java/org/alfresco/filesys/ftp/FTPSrvSession.java
@@ -127,7 +127,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
// File transfer buffer size
- private static final int DEFAULT_BUFFERSIZE = 64000;
+ public static final int DEFAULT_BUFFERSIZE = 64000;
// Carriage return/line feed combination required for response messages
@@ -137,6 +137,10 @@ public class FTPSrvSession extends SrvSession implements Runnable
protected final static String LIST_OPTION_HIDDEN = "-a";
+ // Flag to control whether data transfers use a seperate thread
+
+ private static boolean UseThreadedDataTransfer = true;
+
// Session socket
private Socket m_sock;
@@ -235,14 +239,18 @@ public class FTPSrvSession extends SrvSession implements Runnable
if (m_dataSess != null)
{
+ // Abort any active transfer
+
+ m_dataSess.abortTransfer();
+
+ // Remove the data session
+
getFTPServer().releaseDataSession(m_dataSess);
m_dataSess = null;
}
// Close the socket first, if the client is still connected this should
- // allow the
- // input/output streams
- // to be closed
+ // allow the input/output streams to be closed
if (m_sock != null)
{
@@ -335,8 +343,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Set the default path for the session
*
- * @param rootPath
- * FTPPath
+ * @param rootPath FTPPath
*/
public final void setRootPath(FTPPath rootPath)
{
@@ -353,10 +360,8 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Get the path details for the current request
*
- * @param req
- * FTPRequest
- * @param filePath
- * boolean
+ * @param req FTPRequest
+ * @param filePath boolean
* @return FTPPath
*/
protected final FTPPath generatePathForRequest(FTPRequest req, boolean filePath)
@@ -367,12 +372,9 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Get the path details for the current request
*
- * @param req
- * FTPRequest
- * @param filePath
- * boolean
- * @param checkExists
- * boolean
+ * @param req FTPRequest
+ * @param filePath boolean
+ * @param checkExists boolean
* @return FTPPath
*/
protected final FTPPath generatePathForRequest(FTPRequest req, boolean filePath, boolean checkExists)
@@ -583,8 +585,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Convert a path string from share path seperators to FTP path seperators
*
- * @param path
- * String
+ * @param path String
* @return String
*/
protected final String convertToFTPSeperators(String path)
@@ -603,8 +604,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Find the required disk shared device
*
- * @param name
- * String
+ * @param name String
* @return DiskSharedDevice
*/
protected final DiskSharedDevice findShare(String name)
@@ -630,8 +630,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Set the binary mode flag
*
- * @param bin
- * boolean
+ * @param bin boolean
*/
protected final void setBinary(boolean bin)
{
@@ -641,10 +640,8 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Send an FTP command response
*
- * @param stsCode
- * int
- * @param msg
- * String
+ * @param stsCode int
+ * @param msg String
* @exception IOException
*/
protected final void sendFTPResponse(int stsCode, String msg) throws IOException
@@ -680,8 +677,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Send an FTP command response
*
- * @param msg
- * StringBuffer
+ * @param msg StringBuffer
* @exception IOException
*/
protected final void sendFTPResponse(StringBuffer msg) throws IOException
@@ -700,8 +696,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a user command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procUser(FTPRequest req) throws IOException
@@ -750,8 +745,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a password command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procPassword(FTPRequest req) throws IOException
@@ -827,6 +821,10 @@ public class FTPSrvSession extends SrvSession implements Runnable
sendFTPResponse(230, "User logged in, proceed");
setLoggedOn(true);
+ // Save the client info
+
+ setClientInformation( cInfo);
+
// DEBUG
if (logger.isDebugEnabled() && hasDebug(DBG_STATE))
@@ -909,8 +907,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a port command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procPort(FTPRequest req) throws IOException
@@ -990,8 +987,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a passive command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procPassive(FTPRequest req) throws IOException
@@ -1049,8 +1045,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a print working directory command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procPrintWorkDir(FTPRequest req) throws IOException
@@ -1078,8 +1073,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a change working directory command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procChangeWorkDir(FTPRequest req) throws IOException
@@ -1128,8 +1122,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a change directory up command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procCdup(FTPRequest req) throws IOException
@@ -1177,8 +1170,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a long directory listing command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procList(FTPRequest req) throws IOException
@@ -1380,8 +1372,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a short directory listing command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procNList(FTPRequest req) throws IOException
@@ -1532,8 +1523,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a system status command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procSystemStatus(FTPRequest req) throws IOException
@@ -1547,8 +1537,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a server status command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procServerStatus(FTPRequest req) throws IOException
@@ -1562,8 +1551,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a help command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procHelp(FTPRequest req) throws IOException
@@ -1577,8 +1565,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a no-op command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procNoop(FTPRequest req) throws IOException
@@ -1592,8 +1579,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a quit command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procQuit(FTPRequest req) throws IOException
@@ -1616,8 +1602,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a type command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procType(FTPRequest req) throws IOException
@@ -1660,8 +1645,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a restart command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procRestart(FTPRequest req) throws IOException
@@ -1708,8 +1692,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a return file command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procReturnFile(FTPRequest req) throws IOException
@@ -1760,198 +1743,215 @@ public class FTPSrvSession extends SrvSession implements Runnable
return;
}
- // Get the data connection socket
-
- Socket dataSock = null;
-
- try
+ // Check if a seperate thread should be used for the data transfer
+
+ if ( UseThreadedDataTransfer == true)
{
- dataSock = m_dataSess.getSocket();
+ // DEBUG
+
+ if (logger.isDebugEnabled() && hasDebug(DBG_FILE))
+ logger.debug("Returning (threaded) ftp="
+ + ftpPath.getFTPPath() + ", share=" + ftpPath.getShareName() + ", path=" + ftpPath.getSharePath());
+
+ // Start the transfer in a seperate thread
+
+ m_dataSess.doReturnFile( ftpPath, m_restartPos, req.getArgument());
}
- catch (Exception ex)
+ else
{
- }
-
- if (dataSock == null)
- {
- sendFTPResponse(426, "Connection closed; transfer aborted");
- return;
- }
-
- // DEBUG
-
- if (logger.isDebugEnabled() && hasDebug(DBG_FILE))
- logger.debug("Returning ftp="
- + ftpPath.getFTPPath() + ", share=" + ftpPath.getShareName() + ", path=" + ftpPath.getSharePath());
-
- // Send the file to the client
-
- OutputStream os = null;
- DiskInterface disk = null;
- TreeConnection tree = null;
- NetworkFile netFile = null;
-
- try
- {
-
- // Open an output stream to the client
-
- os = dataSock.getOutputStream();
-
- // Create a temporary tree connection
-
- tree = getTreeConnection(ftpPath.getSharedDevice());
-
- // Check if the file exists and it is a file, if so then open the
- // file
-
- disk = (DiskInterface) ftpPath.getSharedDevice().getInterface();
-
- // Create the file open parameters
-
- FileOpenParams params = new FileOpenParams(ftpPath.getSharePath(), FileAction.OpenIfExists,
- AccessMode.ReadOnly, 0);
-
- // Check if the file exists and it is a file
-
- int sts = disk.fileExists(this, tree, ftpPath.getSharePath());
-
- if (sts == FileStatus.FileExists)
- {
-
- // Open the file
-
- netFile = disk.openFile(this, tree, params);
- }
-
- // Check if the file has been opened
-
- if (netFile == null)
- {
- sendFTPResponse(550, "File " + req.getArgument() + " not available");
- return;
- }
-
- // Allocate the buffer for the file data
-
- byte[] buf = new byte[DEFAULT_BUFFERSIZE];
- long filePos = m_restartPos;
-
- int len = -1;
-
- while (filePos < netFile.getFileSize())
- {
-
- // Read another block of data from the file
-
- len = disk.readFile(this, tree, netFile, buf, 0, buf.length, filePos);
-
- // DEBUG
-
- if (logger.isDebugEnabled() && hasDebug(DBG_FILEIO))
- logger.debug(" Write len=" + len + " bytes");
-
- // Write the current data block to the client, update the file
- // position
-
- if (len > 0)
- {
-
- // Write the data to the client
-
- os.write(buf, 0, len);
-
- // Update the file position
-
- filePos += len;
- }
- }
-
- // Close the output stream to the client
-
- os.close();
- os = null;
-
- // Indicate that the file has been transmitted
-
- sendFTPResponse(226, "Closing data connection");
-
- // Close the data session
-
- getFTPServer().releaseDataSession(m_dataSess);
- m_dataSess = null;
-
- // Close the network file
-
- disk.closeFile(this, tree, netFile);
- netFile = null;
-
- // DEBUG
-
- if (logger.isDebugEnabled() && hasDebug(DBG_FILEIO))
- logger.debug(" Transfer complete, file closed");
- }
- catch (SocketException ex)
- {
-
- // DEBUG
-
- if (logger.isDebugEnabled() && hasDebug(DBG_ERROR))
- logger.debug(" Error during transfer", ex);
-
- // Close the data socket to the client
-
- if (m_dataSess != null)
- {
- m_dataSess.closeSession();
- m_dataSess = null;
- }
-
- // Indicate that there was an error during transmission of the file
- // data
-
- sendFTPResponse(426, "Data connection closed by client");
- }
- catch (Exception ex)
- {
-
- // DEBUG
-
- if (logger.isDebugEnabled() && hasDebug(DBG_ERROR))
- logger.debug(" Error during transfer", ex);
-
- // Indicate that there was an error during transmission of the file
- // data
-
- sendFTPResponse(426, "Error during transmission");
- } finally
- {
-
- // Close the network file
-
- if (netFile != null && disk != null && tree != null)
- disk.closeFile(this, tree, netFile);
-
- // Close the output stream to the client
-
- if (os != null)
- os.close();
-
- // Close the data connection to the client
-
- if (m_dataSess != null)
- {
- getFTPServer().releaseDataSession(m_dataSess);
- m_dataSess = null;
- }
+ // Get the data connection socket
+
+ Socket dataSock = null;
+
+ try
+ {
+ dataSock = m_dataSess.getSocket();
+ }
+ catch (Exception ex)
+ {
+ }
+
+ if (dataSock == null)
+ {
+ sendFTPResponse(426, "Connection closed; transfer aborted");
+ return;
+ }
+
+ // DEBUG
+
+ if (logger.isDebugEnabled() && hasDebug(DBG_FILE))
+ logger.debug("Returning ftp="
+ + ftpPath.getFTPPath() + ", share=" + ftpPath.getShareName() + ", path=" + ftpPath.getSharePath());
+
+ // Send the file to the client
+
+ OutputStream os = null;
+ DiskInterface disk = null;
+ TreeConnection tree = null;
+ NetworkFile netFile = null;
+
+ try
+ {
+
+ // Open an output stream to the client
+
+ os = dataSock.getOutputStream();
+
+ // Create a temporary tree connection
+
+ tree = getTreeConnection(ftpPath.getSharedDevice());
+
+ // Check if the file exists and it is a file, if so then open the
+ // file
+
+ disk = (DiskInterface) ftpPath.getSharedDevice().getInterface();
+
+ // Create the file open parameters
+
+ FileOpenParams params = new FileOpenParams(ftpPath.getSharePath(), FileAction.OpenIfExists,
+ AccessMode.ReadOnly, 0);
+
+ // Check if the file exists and it is a file
+
+ int sts = disk.fileExists(this, tree, ftpPath.getSharePath());
+
+ if (sts == FileStatus.FileExists)
+ {
+
+ // Open the file
+
+ netFile = disk.openFile(this, tree, params);
+ }
+
+ // Check if the file has been opened
+
+ if (netFile == null)
+ {
+ sendFTPResponse(550, "File " + req.getArgument() + " not available");
+ return;
+ }
+
+ // Allocate the buffer for the file data
+
+ byte[] buf = new byte[DEFAULT_BUFFERSIZE];
+ long filePos = m_restartPos;
+
+ int len = -1;
+
+ while (filePos < netFile.getFileSize())
+ {
+
+ // Read another block of data from the file
+
+ len = disk.readFile(this, tree, netFile, buf, 0, buf.length, filePos);
+
+ // DEBUG
+
+ if (logger.isDebugEnabled() && hasDebug(DBG_FILEIO))
+ logger.debug(" Write len=" + len + " bytes");
+
+ // Write the current data block to the client, update the file
+ // position
+
+ if (len > 0)
+ {
+
+ // Write the data to the client
+
+ os.write(buf, 0, len);
+
+ // Update the file position
+
+ filePos += len;
+ }
+ }
+
+ // Close the output stream to the client
+
+ os.close();
+ os = null;
+
+ // Indicate that the file has been transmitted
+
+ sendFTPResponse(226, "Closing data connection");
+
+ // Close the data session
+
+ getFTPServer().releaseDataSession(m_dataSess);
+ m_dataSess = null;
+
+ // Close the network file
+
+ disk.closeFile(this, tree, netFile);
+ netFile = null;
+
+ // DEBUG
+
+ if (logger.isDebugEnabled() && hasDebug(DBG_FILEIO))
+ logger.debug(" Transfer complete, file closed");
+ }
+ catch (SocketException ex)
+ {
+
+ // DEBUG
+
+ if (logger.isDebugEnabled() && hasDebug(DBG_ERROR))
+ logger.debug(" Error during transfer", ex);
+
+ // Close the data socket to the client
+
+ if (m_dataSess != null)
+ {
+ m_dataSess.closeSession();
+ m_dataSess = null;
+ }
+
+ // Indicate that there was an error during transmission of the file
+ // data
+
+ sendFTPResponse(426, "Data connection closed by client");
+ }
+ catch (Exception ex)
+ {
+
+ // DEBUG
+
+ if (logger.isDebugEnabled() && hasDebug(DBG_ERROR))
+ logger.debug(" Error during transfer", ex);
+
+ // Indicate that there was an error during transmission of the file
+ // data
+
+ sendFTPResponse(426, "Error during transmission");
+ }
+ finally
+ {
+
+ // Close the network file
+
+ if (netFile != null && disk != null && tree != null)
+ disk.closeFile(this, tree, netFile);
+
+ // Close the output stream to the client
+
+ if (os != null)
+ os.close();
+
+ // Close the data connection to the client
+
+ if (m_dataSess != null)
+ {
+ getFTPServer().releaseDataSession(m_dataSess);
+ m_dataSess = null;
+ }
+ }
}
}
/**
* Process a store file command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procStoreFile(FTPRequest req) throws IOException
@@ -1982,252 +1982,269 @@ public class FTPSrvSession extends SrvSession implements Runnable
return;
}
- // Send the file to the client
-
- InputStream is = null;
- DiskInterface disk = null;
- TreeConnection tree = null;
- NetworkFile netFile = null;
-
- try
+ // Check if a seperate thread should be used for the data transfer
+
+ if ( UseThreadedDataTransfer == true)
{
-
- // Create a temporary tree connection
-
- tree = getTreeConnection(ftpPath.getSharedDevice());
-
- // Check if the session has the required access to the filesystem
-
- if (tree == null || tree.hasWriteAccess() == false)
- {
-
- // Session does not have write access to the filesystem
-
- sendFTPResponse(550, "Access denied");
- return;
- }
-
- // Check if the file exists
-
- disk = (DiskInterface) ftpPath.getSharedDevice().getInterface();
- int sts = disk.fileExists(this, tree, ftpPath.getSharePath());
-
- if (sts == FileStatus.DirectoryExists)
- {
-
- // Return an error status
-
- sendFTPResponse(500, "Invalid path (existing directory)");
- return;
- }
-
- // Create the file open parameters
-
- FileOpenParams params = new FileOpenParams(ftpPath.getSharePath(),
- sts == FileStatus.FileExists ? FileAction.TruncateExisting : FileAction.CreateNotExist,
- AccessMode.ReadWrite, 0);
-
- // Create a new file to receive the data
-
- if (sts == FileStatus.FileExists)
- {
-
- // Overwrite the existing file
-
- netFile = disk.openFile(this, tree, params);
- }
- else
- {
-
- // Create a new file
-
- netFile = disk.createFile(this, tree, params);
- }
-
- // Notify change listeners that a new file has been created
-
- DiskDeviceContext diskCtx = (DiskDeviceContext) tree.getContext();
-
- if (diskCtx.hasChangeHandler())
- diskCtx.getChangeHandler().notifyFileChanged(NotifyChange.ActionAdded, ftpPath.getSharePath());
-
- // Send the intermediate response
-
- sendFTPResponse(150, "File status okay, about to open data connection");
-
- // Check if there is an active data session
-
- if (m_dataSess == null)
- {
- sendFTPResponse(425, "Can't open data connection");
- return;
- }
-
- // Get the data connection socket
-
- Socket dataSock = null;
-
- try
- {
- dataSock = m_dataSess.getSocket();
- }
- catch (Exception ex)
- {
- }
-
- if (dataSock == null)
- {
- sendFTPResponse(426, "Connection closed; transfer aborted");
- return;
- }
-
- // Open an input stream from the client
-
- is = dataSock.getInputStream();
-
// DEBUG
-
+
if (logger.isDebugEnabled() && hasDebug(DBG_FILE))
- logger.debug("Storing ftp="
+ logger.debug("Storing (threaded) ftp="
+ ftpPath.getFTPPath() + ", share=" + ftpPath.getShareName() + ", path="
+ ftpPath.getSharePath());
- // Allocate the buffer for the file data
-
- byte[] buf = new byte[DEFAULT_BUFFERSIZE];
- long filePos = 0;
- int len = is.read(buf, 0, buf.length);
-
- while (len > 0)
- {
-
- // DEBUG
-
- if (logger.isDebugEnabled() && hasDebug(DBG_FILEIO))
- logger.debug(" Receive len=" + len + " bytes");
-
- // Write the current data block to the file, update the file
- // position
-
- disk.writeFile(this, tree, netFile, buf, 0, len, filePos);
- filePos += len;
-
- // Read another block of data from the client
-
- len = is.read(buf, 0, buf.length);
- }
-
- // Close the input stream from the client
-
- is.close();
- is = null;
-
- // Close the network file
-
- disk.closeFile(this, tree, netFile);
- netFile = null;
-
- // Indicate that the file has been received
-
- sendFTPResponse(226, "Closing data connection");
-
- // DEBUG
-
- if (logger.isDebugEnabled() && hasDebug(DBG_FILEIO))
- logger.debug(" Transfer complete, file closed");
+ // Start the transfer in a seperate thread
+
+ m_dataSess.doStoreFile( ftpPath, m_restartPos, req.getArgument());
}
- catch( AccessDeniedException ex)
+ else
{
- // DEBUG
-
- if (logger.isDebugEnabled() && hasDebug(DBG_ERROR))
- logger.debug(" Access denied", ex);
-
- // Session does not have write access to the filesystem
-
- sendFTPResponse(550, "Access denied");
- }
- catch (SocketException ex)
- {
- // DEBUG
-
- if (logger.isDebugEnabled() && hasDebug(DBG_ERROR))
- logger.debug(" Error during transfer", ex);
-
- // Close the data socket to the client
-
- if (m_dataSess != null)
- {
- getFTPServer().releaseDataSession(m_dataSess);
- m_dataSess = null;
- }
-
- // Indicate that there was an error during transmission of the file
- // data
-
- sendFTPResponse(426, "Data connection closed by client");
- }
- catch (DiskFullException ex)
- {
-
- // DEBUG
-
- if (logger.isDebugEnabled() && hasDebug(DBG_ERROR))
- logger.debug(" Error during transfer", ex);
-
- // Close the data socket to the client
-
- if (m_dataSess != null)
- {
- getFTPServer().releaseDataSession(m_dataSess);
- m_dataSess = null;
- }
-
- // Indicate that there was an error during writing of the file
-
- sendFTPResponse(451, "Disk full");
- }
- catch (Exception ex)
- {
-
- // DEBUG
-
- if (logger.isDebugEnabled() && hasDebug(DBG_ERROR))
- logger.debug(" Error during transfer", ex);
-
- // Indicate that there was an error during transmission of the file
- // data
-
- sendFTPResponse(426, "Error during transmission");
- }
- finally
- {
-
- // Close the network file
-
- if (netFile != null && disk != null && tree != null)
- disk.closeFile(this, tree, netFile);
-
- // Close the input stream to the client
-
- if (is != null)
- is.close();
-
- // Close the data connection to the client
-
- if (m_dataSess != null)
- {
- getFTPServer().releaseDataSession(m_dataSess);
- m_dataSess = null;
- }
+ // Send the file to the client
+
+ InputStream is = null;
+ DiskInterface disk = null;
+ TreeConnection tree = null;
+ NetworkFile netFile = null;
+
+ try
+ {
+
+ // Create a temporary tree connection
+
+ tree = getTreeConnection(ftpPath.getSharedDevice());
+
+ // Check if the session has the required access to the filesystem
+
+ if (tree == null || tree.hasWriteAccess() == false)
+ {
+
+ // Session does not have write access to the filesystem
+
+ sendFTPResponse(550, "Access denied");
+ return;
+ }
+
+ // Check if the file exists
+
+ disk = (DiskInterface) ftpPath.getSharedDevice().getInterface();
+ int sts = disk.fileExists(this, tree, ftpPath.getSharePath());
+
+ if (sts == FileStatus.DirectoryExists)
+ {
+
+ // Return an error status
+
+ sendFTPResponse(500, "Invalid path (existing directory)");
+ return;
+ }
+
+ // Create the file open parameters
+
+ FileOpenParams params = new FileOpenParams(ftpPath.getSharePath(),
+ sts == FileStatus.FileExists ? FileAction.TruncateExisting : FileAction.CreateNotExist,
+ AccessMode.ReadWrite, 0);
+
+ // Create a new file to receive the data
+
+ if (sts == FileStatus.FileExists)
+ {
+
+ // Overwrite the existing file
+
+ netFile = disk.openFile(this, tree, params);
+ }
+ else
+ {
+
+ // Create a new file
+
+ netFile = disk.createFile(this, tree, params);
+ }
+
+ // Notify change listeners that a new file has been created
+
+ DiskDeviceContext diskCtx = (DiskDeviceContext) tree.getContext();
+
+ if (diskCtx.hasChangeHandler())
+ diskCtx.getChangeHandler().notifyFileChanged(NotifyChange.ActionAdded, ftpPath.getSharePath());
+
+ // Send the intermediate response
+
+ sendFTPResponse(150, "File status okay, about to open data connection");
+
+ // Check if there is an active data session
+
+ if (m_dataSess == null)
+ {
+ sendFTPResponse(425, "Can't open data connection");
+ return;
+ }
+
+ // Get the data connection socket
+
+ Socket dataSock = null;
+
+ try
+ {
+ dataSock = m_dataSess.getSocket();
+ }
+ catch (Exception ex)
+ {
+ }
+
+ if (dataSock == null)
+ {
+ sendFTPResponse(426, "Connection closed; transfer aborted");
+ return;
+ }
+
+ // Open an input stream from the client
+
+ is = dataSock.getInputStream();
+
+ // DEBUG
+
+ if (logger.isDebugEnabled() && hasDebug(DBG_FILE))
+ logger.debug("Storing ftp="
+ + ftpPath.getFTPPath() + ", share=" + ftpPath.getShareName() + ", path="
+ + ftpPath.getSharePath());
+
+ // Allocate the buffer for the file data
+
+ byte[] buf = new byte[DEFAULT_BUFFERSIZE];
+ long filePos = 0;
+ int len = is.read(buf, 0, buf.length);
+
+ while (len > 0)
+ {
+
+ // DEBUG
+
+ if (logger.isDebugEnabled() && hasDebug(DBG_FILEIO))
+ logger.debug(" Receive len=" + len + " bytes");
+
+ // Write the current data block to the file, update the file
+ // position
+
+ disk.writeFile(this, tree, netFile, buf, 0, len, filePos);
+ filePos += len;
+
+ // Read another block of data from the client
+
+ len = is.read(buf, 0, buf.length);
+ }
+
+ // Close the input stream from the client
+
+ is.close();
+ is = null;
+
+ // Close the network file
+
+ disk.closeFile(this, tree, netFile);
+ netFile = null;
+
+ // Indicate that the file has been received
+
+ sendFTPResponse(226, "Closing data connection");
+
+ // DEBUG
+
+ if (logger.isDebugEnabled() && hasDebug(DBG_FILEIO))
+ logger.debug(" Transfer complete, file closed");
+ }
+ catch( AccessDeniedException ex)
+ {
+ // DEBUG
+
+ if (logger.isDebugEnabled() && hasDebug(DBG_ERROR))
+ logger.debug(" Access denied", ex);
+
+ // Session does not have write access to the filesystem
+
+ sendFTPResponse(550, "Access denied");
+ }
+ catch (SocketException ex)
+ {
+ // DEBUG
+
+ if (logger.isDebugEnabled() && hasDebug(DBG_ERROR))
+ logger.debug(" Error during transfer", ex);
+
+ // Close the data socket to the client
+
+ if (m_dataSess != null)
+ {
+ getFTPServer().releaseDataSession(m_dataSess);
+ m_dataSess = null;
+ }
+
+ // Indicate that there was an error during transmission of the file
+ // data
+
+ sendFTPResponse(426, "Data connection closed by client");
+ }
+ catch (DiskFullException ex)
+ {
+
+ // DEBUG
+
+ if (logger.isDebugEnabled() && hasDebug(DBG_ERROR))
+ logger.debug(" Error during transfer", ex);
+
+ // Close the data socket to the client
+
+ if (m_dataSess != null)
+ {
+ getFTPServer().releaseDataSession(m_dataSess);
+ m_dataSess = null;
+ }
+
+ // Indicate that there was an error during writing of the file
+
+ sendFTPResponse(451, "Disk full");
+ }
+ catch (Exception ex)
+ {
+
+ // DEBUG
+
+ if (logger.isDebugEnabled() && hasDebug(DBG_ERROR))
+ logger.debug(" Error during transfer", ex);
+
+ // Indicate that there was an error during transmission of the file
+ // data
+
+ sendFTPResponse(426, "Error during transmission");
+ }
+ finally
+ {
+
+ // Close the network file
+
+ if (netFile != null && disk != null && tree != null)
+ disk.closeFile(this, tree, netFile);
+
+ // Close the input stream to the client
+
+ if (is != null)
+ is.close();
+
+ // Close the data connection to the client
+
+ if (m_dataSess != null)
+ {
+ getFTPServer().releaseDataSession(m_dataSess);
+ m_dataSess = null;
+ }
+ }
}
}
/**
* Process a delete file command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procDeleteFile(FTPRequest req) throws IOException
@@ -2342,8 +2359,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a rename from command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procRenameFrom(FTPRequest req) throws IOException
@@ -2445,8 +2461,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a rename to command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procRenameTo(FTPRequest req) throws IOException
@@ -2573,8 +2588,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a create directory command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procCreateDirectory(FTPRequest req) throws IOException
@@ -2682,8 +2696,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a delete directory command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procRemoveDirectory(FTPRequest req) throws IOException
@@ -2800,8 +2813,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a modify date/time command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procModifyDateTime(FTPRequest req) throws IOException
@@ -2815,8 +2827,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a file size command
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procFileSize(FTPRequest req) throws IOException
@@ -2892,8 +2903,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a structure command. This command is obsolete.
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procStructure(FTPRequest req) throws IOException
@@ -2912,8 +2922,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
/**
* Process a mode command. This command is obsolete.
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procMode(FTPRequest req) throws IOException
@@ -2929,11 +2938,45 @@ public class FTPSrvSession extends SrvSession implements Runnable
sendFTPResponse(504, "Obsolete");
}
+ /**
+ * Abort an active file transfer
+ *
+ * @param req FTPRequest
+ * @exception IOException
+ */
+ protected final void procAbort(FTPRequest req) throws IOException
+ {
+ // Check if threaded transfers are enabled
+
+ if ( UseThreadedDataTransfer == true)
+ {
+ // Check if there is an active data connection
+
+ if ( m_dataSess != null)
+ {
+ // Abort the data transfer
+
+ m_dataSess.abortTransfer();
+ }
+ else
+ {
+ // Send an error status, no transfer in progress
+
+ sendFTPResponse( 226, "Data connection not active");
+ }
+ }
+ else
+ {
+ // Abort not implemented for inline transfers
+
+ sendFTPResponse( 502, "Abort not implemented");
+ }
+ }
+
/**
* Process an allocate command. This command is obsolete.
*
- * @param req
- * FTPRequest
+ * @param req FTPRequest
* @exception IOException
*/
protected final void procAllocate(FTPRequest req) throws IOException
@@ -2948,12 +2991,9 @@ public class FTPSrvSession extends SrvSession implements Runnable
* Build a list of file name or file information objects for the specified
* server path
*
- * @param path
- * FTPPath
- * @param nameOnly
- * boolean
- * @param hidden
- * boolean
+ * @param path FTPPath
+ * @param nameOnly boolean
+ * @param hidden boolean
* @return Vector