/**
* Aptana Studio
* Copyright (c) 2005-2012 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions).
* Please see the license.html included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
// $codepro.audit.disable closeWhereCreated
// $codepro.audit.disable reusableImmutables
// $codepro.audit.disable disallowSleepInsideWhile
// $codepro.audit.disable questionableAssignment
// $codepro.audit.disable variableDeclaredInLoop
// $codepro.audit.disable unnecessaryExceptions
// $codepro.audit.disable exceptionUsage.exceptionCreation
// $codepro.audit.disable declaredExceptions
package com.aptana.filesystem.secureftp.internal;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import com.aptana.core.io.vfs.ExtendedFileInfo;
import com.aptana.core.io.vfs.IExtendedFileStore;
import com.aptana.core.util.ExpiringMap;
import com.aptana.filesystem.ftp.Policy;
import com.aptana.filesystem.ftp.internal.BaseFTPConnectionFileManager;
import com.aptana.filesystem.secureftp.ISFTPConnectionFileManager;
import com.aptana.filesystem.secureftp.ISFTPConstants;
import com.aptana.ide.core.io.ConnectionContext;
import com.aptana.ide.core.io.CoreIOPlugin;
import com.aptana.ide.core.io.PermissionDeniedException;
import com.aptana.ide.core.io.preferences.PermissionDirection;
import com.aptana.ide.core.io.preferences.PreferenceUtils;
import com.enterprisedt.net.ftp.FTPException;
import com.enterprisedt.net.ftp.FTPFile;
import com.enterprisedt.net.ftp.FTPTransferType;
import com.enterprisedt.net.ftp.ssh.SSHFTPAlgorithm;
import com.enterprisedt.net.ftp.ssh.SSHFTPClient;
import com.enterprisedt.net.ftp.ssh.SSHFTPException;
import com.enterprisedt.net.ftp.ssh.SSHFTPInputStream;
import com.enterprisedt.net.ftp.ssh.SSHFTPOutputStream;
import com.enterprisedt.net.j2ssh.configuration.SshConnectionProperties;
import com.enterprisedt.net.j2ssh.sftp.SshFxpStatus;
import com.enterprisedt.net.j2ssh.transport.publickey.InvalidSshKeyException;
import com.enterprisedt.net.j2ssh.transport.publickey.SshPrivateKeyFile;
/**
* @author Max Stepanov
*/
public class SFTPConnectionFileManager extends BaseFTPConnectionFileManager implements ISFTPConnectionFileManager
{
private SSHFTPClient ftpClient;
private IPath keyFilePath;
private String transferType;
private IPath cwd;
private Map<IPath, FTPFile> ftpFileCache = new ExpiringMap<IPath, FTPFile>(CACHE_TTL);
private Thread keepaliveThread;
/*
* (non-Javadoc)
* @see com.aptana.filesystem.secureftp.ISFTPConnectionFileManager#init(java.lang.String, int,
* org.eclipse.core.runtime.IPath, org.eclipse.core.runtime.IPath, java.lang.String, char[], java.lang.String,
* java.lang.String, java.lang.String)
*/
public void init(String host, int port, IPath basePath, IPath keyFilePath, String login, char[] password,
String transferType, String encoding, String compression)
{
Assert.isTrue(ftpClient == null, Messages.SFTPConnectionFileManager_ConnectionHasBeenInitialized);
try
{
ftpClient = new SSHFTPClient();
this.host = host;
this.port = port;
this.keyFilePath = keyFilePath;
this.login = login;
this.password = (password == null) ? new char[0] : password;
this.basePath = (basePath != null) ? basePath : Path.ROOT;
if (keyFilePath != null)
{
this.authId = Policy.generateAuthId("SFTP/PUBLICKEY", login, host, port); //$NON-NLS-1$
}
else
{
this.authId = Policy.generateAuthId("SFTP", login, host, port); //$NON-NLS-1$
}
this.transferType = transferType;
initFTPClient(ftpClient, encoding, compression);
}
catch (Exception e)
{
SecureFTPPlugin.log(new Status(IStatus.WARNING, SecureFTPPlugin.PLUGIN_ID,
Messages.SFTPConnectionFileManager_InitializationFailed, e));
ftpClient = null;
}
}
@SuppressWarnings("deprecation")
private static void initFTPClient(SSHFTPClient ftpClient, String encoding, String compression) throws IOException,
FTPException
{
ftpClient.setTimeout(TIMEOUT);
ftpClient.setControlEncoding(encoding);
ftpClient.setMonitorInterval(1024);
ftpClient.setSleepEnabled(false);
if (ISFTPConstants.COMPRESSION_NONE.equals(compression))
{
ftpClient.disableAllAlgorithms(SSHFTPAlgorithm.COMPRESSION);
ftpClient.setAlgorithmEnabled(SSHFTPAlgorithm.COMPRESSION_NONE, true);
}
else if (ISFTPConstants.COMPRESSION_ZLIB.equals(compression))
{
ftpClient.disableAllAlgorithms(SSHFTPAlgorithm.COMPRESSION);
ftpClient.setAlgorithmEnabled(SSHFTPAlgorithm.COMPRESSION_ZLIB, true);
}
ftpClient.setTransportProvider(SshConnectionProperties.USE_STANDARD_SOCKET);
ftpClient.setConfigFlags(0);
ftpClient.setTransferBufferSize(TRANSFER_BUFFER_SIZE);
ftpClient.setValidator(new SSHHostValidator());
}
/*
* (non-Javadoc)
* @see com.aptana.core.io.vfs.IConnectionFileManager#connect(org.eclipse.core.runtime.IProgressMonitor)
*/
public void connect(IProgressMonitor monitor) throws CoreException
{
Assert.isTrue(ftpClient != null, Messages.SFTPConnectionFileManager_ConnectionNotInitialized);
monitor = Policy.monitorFor(monitor);
try
{
cwd = null;
cleanup();
ConnectionContext context = CoreIOPlugin.getConnectionContext(this);
monitor.beginTask(Messages.SFTPConnectionFileManager_EstablishingConnection, IProgressMonitor.UNKNOWN);
ftpClient.setRemoteHost(host);
ftpClient.setRemotePort(port);
while (true)
{
if (keyFilePath != null)
{
SshPrivateKeyFile privateKeyFile;
try
{
privateKeyFile = SshPrivateKeyFile.parse(keyFilePath.toFile());
}
catch (InvalidSshKeyException e)
{
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
MessageFormat.format(Messages.SFTPConnectionFileManager_InvalidPrivateKey,
keyFilePath.toOSString()), e));
}
catch (IOException e)
{
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
MessageFormat.format(Messages.SFTPConnectionFileManager_UnableToReadPrivateKey,
keyFilePath.toOSString())));
}
if (privateKeyFile.isPassphraseProtected() && password.length == 0)
{
if (context != null && context.getBoolean(ConnectionContext.NO_PASSWORD_PROMPT))
{
password = new char[0];
}
else
{
getOrPromptPassword(MessageFormat.format(
Messages.SFTPConnectionFileManager_PublicKeyAuthentication, new Object[] { host,
keyFilePath.toOSString() }),
Messages.SFTPConnectionFileManager_SpecifyPassphrase);
while (true)
{
try
{
privateKeyFile.toPrivateKey(String.copyValueOf(password));
}
catch (InvalidSshKeyException e)
{
if (e.getCause() instanceof NoSuchAlgorithmException)
{
SecureFTPPlugin.log(new Status(IStatus.WARNING, SecureFTPPlugin.PLUGIN_ID, e
.getCause().getMessage()));
}
promptPassword(MessageFormat.format(
Messages.SFTPConnectionFileManager_PublicKeyAuthentication, new Object[] {
host, keyFilePath.toOSString() }),
Messages.SFTPConnectionFileManager_PassphraseNotAccepted);
continue;
}
break;
}
}
}
else if (password == null)
{
password = new char[0];
}
try
{
ftpClient.setAuthentication(keyFilePath.toOSString(), login, String.copyValueOf(password));
}
catch (InvalidSshKeyException e)
{
if (password.length == 0)
{
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
MessageFormat.format(Messages.SFTPConnectionFileManager_KeyRequirePassphrase,
keyFilePath.toOSString()), e));
}
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
MessageFormat.format(Messages.SFTPConnectionFileManager_InvalidPassphrase,
keyFilePath.toOSString()), e));
}
}
else
{
if (password.length == 0 && !ISFTPConstants.LOGIN_ANONYMOUS.equals(login)
&& (context == null || !context.getBoolean(ConnectionContext.NO_PASSWORD_PROMPT)))
{
getOrPromptPassword(
MessageFormat.format(Messages.SFTPConnectionFileManager_SFTPAuthentication, host),
Messages.SFTPConnectionFileManager_SpecifyPassword);
}
ftpClient.setAuthentication(login, String.copyValueOf(password));
}
Policy.checkCanceled(monitor);
monitor.subTask(Messages.SFTPConnectionFileManager_Authenticating);
try
{
ftpClient.connect();
}
catch (SSHFTPException e)
{
Policy.checkCanceled(monitor);
if (keyFilePath != null)
{
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
MessageFormat.format(Messages.SFTPConnectionFileManager_FailedAuthenticatePublicKey,
e.getLocalizedMessage()), e));
}
if (context != null && context.getBoolean(ConnectionContext.NO_PASSWORD_PROMPT))
{
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
MessageFormat.format(Messages.SFTPConnectionFileManager_FailedAuthenticate,
Messages.SFTPConnectionFileManager_IncorrectLogin), e));
}
promptPassword(MessageFormat.format(Messages.SFTPConnectionFileManager_SFTPAuthentication, host),
Messages.SFTPConnectionFileManager_PasswordNotAccepted);
safeQuit();
continue;
}
break;
}
Policy.checkCanceled(monitor);
changeCurrentDir(basePath);
ftpClient.setType(ISFTPConstants.TRANSFER_TYPE_ASCII.equals(transferType) ? FTPTransferType.ASCII
: FTPTransferType.BINARY);
initKeepAlive();
}
catch (OperationCanceledException e)
{
safeQuit();
throw e;
}
catch (CoreException e)
{
safeQuit();
throw e;
}
catch (UnknownHostException e)
{
safeQuit();
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
Messages.SFTPConnectionFileManager_HostNameNotFound + e.getLocalizedMessage(), e));
}
catch (FileNotFoundException e)
{
safeQuit();
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
Messages.SFTPConnectionFileManager_RemoteFolderNotFound + e.getLocalizedMessage(), e));
}
catch (Exception e)
{
safeQuit();
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
Messages.SFTPConnectionFileManager_FailedEstablishConnection + e.getLocalizedMessage(), e));
}
finally
{
monitor.done();
}
}
private void safeQuit()
{
try
{
if (ftpClient.connected())
{
ftpClient.quit();
}
}
catch (Exception e)
{
try
{
ftpClient.quitImmediately();
}
catch (Exception ignore)
{
ignore.getCause();
}
}
}
private void initKeepAlive()
{
Thread thread = keepaliveThread;
if (thread != null && thread.isAlive())
{
thread.interrupt();
try
{
thread.join();
}
catch (InterruptedException e)
{
return;
}
}
keepaliveThread = new Thread()
{
@Override
public void run()
{
while (ftpClient != null && ftpClient.connected())
{
try
{
ftpClient.keepAlive();
}
catch (IOException e)
{
if (ftpClient.connected())
{
try
{
ftpClient.quitImmediately();
}
catch (Exception ignore)
{
ignore.getCause();
}
}
}
catch (Exception e)
{
SecureFTPPlugin.log(new Status(IStatus.ERROR, SecureFTPPlugin.PLUGIN_ID,
Messages.SFTPConnectionFileManager_ErrorSendKeepAlive, e));
}
try
{
Thread.sleep(KEEPALIVE_INTERVAL);
}
catch (InterruptedException e)
{
break;
}
}
keepaliveThread = null;
}
};
keepaliveThread.start();
}
/*
* (non-Javadoc)
* @see com.aptana.core.io.vfs.IConnectionFileManager#disconnect(org.eclipse.core.runtime.IProgressMonitor)
*/
public void disconnect(IProgressMonitor monitor) throws CoreException
{
try
{
checkConnected();
}
catch (Exception ignore)
{
ignore.getCause();
}
if (!isConnected())
{
return;
}
monitor = Policy.monitorFor(monitor);
monitor.beginTask(Messages.SFTPConnectionFileManager_ClosingConnection, IProgressMonitor.UNKNOWN);
try
{
ftpClient.quit();
}
catch (Exception e)
{
try
{
ftpClient.quitImmediately();
}
catch (Exception ignore)
{
ignore.getCause();
}
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
Messages.SFTPConnectionFileManager_FailedDisconnectConnection, e));
}
finally
{
cwd = null;
cleanup();
monitor.done();
}
}
/*
* (non-Javadoc)
* @see com.aptana.core.io.vfs.IConnectionFileManager#isConnected()
*/
public boolean isConnected()
{
return ftpClient != null && ftpClient.connected();
}
protected void changeCurrentDir(IPath path) throws FTPException, IOException, PermissionDeniedException
{
try
{
if (cwd == null)
{
cwd = new Path(ftpClient.pwd());
}
if (!cwd.equals(path))
{
ftpClient.chdir(path.toPortableString());
cwd = path;
}
}
catch (FTPException e)
{
throwWrappedException(e, path, SshFxpStatus.STATUS_FX_FAILURE);
}
catch (IOException e)
{
cwd = null;
throw e;
}
}
private static void throwWrappedException(FTPException e, IPath path) throws FileNotFoundException, FTPException,
PermissionDeniedException
{
throwWrappedException(e, path, -1);
}
private static void throwWrappedException(FTPException e, IPath path, int fileNotFoundErrorCode)
throws FileNotFoundException, FTPException, PermissionDeniedException
{
int reply = e.getReplyCode();
if (reply == -1 && e.getCause() instanceof FTPException)
{
reply = ((FTPException) e.getCause()).getReplyCode();
}
if (reply == -1 || reply == SshFxpStatus.STATUS_FX_NO_SUCH_FILE || reply == SshFxpStatus.STATUS_FX_NO_SUCH_PATH
|| reply == fileNotFoundErrorCode)
{
throw initFileNotFoundException(path, e);
}
if (reply == SshFxpStatus.STATUS_FX_PERMISSION_DENIED)
{
throw new PermissionDeniedException(path.toPortableString(), e);
}
throw e;
}
private static void fillFileInfo(ExtendedFileInfo fileInfo, FTPFile ftpFile)
{
fileInfo.setExists(true);
fileInfo.setName(ftpFile.getName());
fileInfo.setDirectory(ftpFile.isDir());
fileInfo.setLength(ftpFile.size());
fileInfo.setLastModified((ftpFile.lastModified() != null) ? ftpFile.lastModified().getTime() : 0);
fileInfo.setOwner(ftpFile.getOwner());
fileInfo.setGroup(ftpFile.getGroup());
fileInfo.setPermissions(Policy.permissionsFromString(ftpFile.getPermissions()));
if (ftpFile.isLink())
{
fileInfo.setAttribute(EFS.ATTRIBUTE_SYMLINK, true);
fileInfo.setStringAttribute(EFS.ATTRIBUTE_LINK_TARGET, ftpFile.getLinkedName().trim());
}
}
private static ExtendedFileInfo createFileInfo(FTPFile ftpFile)
{
ExtendedFileInfo fileInfo = new ExtendedFileInfo(ftpFile.getName());
fillFileInfo(fileInfo, ftpFile);
return fileInfo;
}
/*
* (non-Javadoc)
* @see com.aptana.filesystem.ftp.BaseFTPConnectionFileManager#clearCache(org.eclipse.core.runtime.IPath)
*/
@Override
protected void clearCache(IPath path)
{
super.clearCache(path);
clearCacheAbsolute(basePath.append(path));
}
private void clearCacheAbsolute(IPath path)
{
int segments = path.segmentCount();
for (IPath p : new ArrayList<IPath>(ftpFileCache.keySet()))
{
if (p.segmentCount() >= segments && path.matchingFirstSegments(p) == segments)
{
ftpFileCache.remove(p);
}
}
}
/*
* (non-Javadoc)
* @see com.aptana.filesystem.ftp.BaseFTPConnectionFileManager#checkConnected()
*/
@Override
protected void checkConnected() throws Exception
{
if (ftpClient.connected())
{
try
{
ftpClient.keepAlive();
return;
}
catch (FTPException e)
{
return;
}
catch (IOException ignore)
{
ignore.getCause();
}
ftpClient.quitImmediately();
}
}
/*
* (non-Javadoc)
* @see com.aptana.filesystem.ftp.BaseFTPConnectionFileManager#getRootCanonicalURI()
*/
@Override
protected URI getRootCanonicalURI()
{
try
{
return new URI(
"sftp", login, host, (port != ISFTPConstants.SFTP_PORT_DEFAULT) ? port : -1, Path.ROOT.toPortableString(), null, null); //$NON-NLS-1$
}
catch (URISyntaxException e)
{
return null;
}
}
/*
* (non-Javadoc)
* @see com.aptana.filesystem.ftp.BaseFTPConnectionFileManager#fetchFile(org.eclipse.core.runtime.IPath, int,
* org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected ExtendedFileInfo fetchFile(IPath path, int options, IProgressMonitor monitor) throws CoreException,
FileNotFoundException, PermissionDeniedException
{
try
{
IPath dirPath = path.removeLastSegments(1);
String name = path.lastSegment();
FTPFile result = ftpFileCache.get(path);
if (result == null)
{
if ((options & IExtendedFileStore.EXISTENCE) != 0)
{
ExtendedFileInfo fileInfo = new ExtendedFileInfo(path.lastSegment());
try
{
fileInfo.setExists(ftpClient.exists(path.toPortableString()));
ftpClient.chdir(path.toPortableString());
fileInfo.setDirectory(true);
}
catch (FTPException e)
{
try
{
throwWrappedException(e, path, SshFxpStatus.STATUS_FX_FAILURE);
}
catch (FileNotFoundException ignore)
{
ignore.getCause();
}
}
return fileInfo;
}
FTPFile[] ftpFiles = listFiles(dirPath, monitor);
for (FTPFile ftpFile : ftpFiles)
{
String fileName = ftpFile.getName();
if (fileName == null || ".".equals(fileName) || "..".equals(fileName)) { //$NON-NLS-1$ //$NON-NLS-2$
if (Path.ROOT.equals(path) && ".".equals(fileName)) { //$NON-NLS-1$
ftpFile.setName(path.toPortableString());
ftpFileCache.put(path, ftpFile);
result = ftpFile;
}
continue;
}
ftpFileCache.put(dirPath.append(fileName), ftpFile);
if (name != null && name.equals(fileName))
{
result = ftpFile;
}
}
}
if (result != null)
{
return createFileInfo(result);
}
}
catch (FileNotFoundException e)
{
throw e;
}
catch (PermissionDeniedException e)
{
throw e;
}
catch (OperationCanceledException e)
{
throw e;
}
catch (Exception e)
{
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
Messages.SFTPConnectionFileManager_FailedFetchFileInfo, e));
}
ExtendedFileInfo fileInfo = new ExtendedFileInfo(path.lastSegment());
fileInfo.setExists(false);
return fileInfo;
}
/*
* (non-Javadoc)
* @see com.aptana.filesystem.ftp.BaseFTPConnectionFileManager#fetchFiles(org.eclipse.core.runtime.IPath, int,
* org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected ExtendedFileInfo[] fetchFiles(IPath path, int options, IProgressMonitor monitor) throws CoreException,
FileNotFoundException, PermissionDeniedException
{
monitor = Policy.subMonitorFor(monitor, 1);
try
{
FTPFile[] ftpFiles = listFiles(path, monitor);
monitor.beginTask(Messages.SFTPConnectionFileManager_GatheringFileDetails, ftpFiles.length);
List<ExtendedFileInfo> list = new ArrayList<ExtendedFileInfo>();
for (FTPFile ftpFile : ftpFiles)
{
String fileName = ftpFile.getName();
if (fileName != null && ".".equals(fileName) || "..".equals(fileName)) { //$NON-NLS-1$ //$NON-NLS-2$
monitor.worked(1);
continue;
}
IPath filePath = path.append(fileName);
ftpFileCache.put(filePath, ftpFile);
ExtendedFileInfo fileInfo = createFileInfo(ftpFile);
list.add(fileInfo);
monitor.worked(1);
}
return list.toArray(new ExtendedFileInfo[list.size()]);
}
catch (FileNotFoundException e)
{
throw e;
}
catch (PermissionDeniedException e)
{
throw e;
}
catch (OperationCanceledException e)
{
throw e;
}
catch (Exception e)
{
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
Messages.SFTPConnectionFileManager_FailedFetchDirectory, e));
}
finally
{
monitor.done();
}
}
/*
* (non-Javadoc)
* @see com.aptana.filesystem.ftp.BaseFTPConnectionFileManager#createDirectory(org.eclipse.core.runtime.IPath,
* org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected void createDirectory(IPath path, IProgressMonitor monitor) throws CoreException, FileNotFoundException
{
try
{
try
{
try
{
changeCurrentDir(path);
return; // directory exists - return
}
catch (FileNotFoundException ignore)
{
ignore.getCause();
}
ftpClient.mkdir(path.toPortableString());
if (PreferenceUtils.getUpdatePermissions(PermissionDirection.UPLOAD)
&& PreferenceUtils.getSpecificPermissions(PermissionDirection.UPLOAD))
{
changeFilePermissions(path, PreferenceUtils.getFolderPermissions(PermissionDirection.UPLOAD),
monitor);
}
}
catch (FTPException e)
{
throwWrappedException(e, path);
}
}
catch (FileNotFoundException e)
{
throw e;
}
catch (CoreException e)
{
throw e;
}
catch (Exception e)
{
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
Messages.SFTPConnectionFileManager_FailedCreateDirectory, e));
}
}
/*
* (non-Javadoc)
* @see com.aptana.filesystem.ftp.BaseFTPConnectionFileManager#deleteDirectory(org.eclipse.core.runtime.IPath,
* org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected void deleteDirectory(IPath path, IProgressMonitor monitor) throws CoreException, FileNotFoundException
{
MultiStatus status = new MultiStatus(SecureFTPPlugin.PLUGIN_ID, 0, null, null);
try
{
IPath dirPath = path.removeLastSegments(1);
changeCurrentDir(dirPath);
Policy.checkCanceled(monitor);
recursiveDeleteTree(path, monitor, status);
changeCurrentDir(dirPath);
ftpClient.rmdir(path.lastSegment());
}
catch (FileNotFoundException e)
{
throw e;
}
catch (OperationCanceledException e)
{
throw e;
}
catch (Exception e)
{
if (!status.isOK())
{
MultiStatus multiStatus = new MultiStatus(SecureFTPPlugin.PLUGIN_ID, 0,
Messages.SFTPConnectionFileManager_FailedDeleteDirectory, e);
multiStatus.addAll(status);
}
else
{
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
Messages.SFTPConnectionFileManager_FailedDeleteDirectory, e));
}
}
finally
{
monitor.done();
}
}
/*
* (non-Javadoc)
* @see com.aptana.filesystem.ftp.internal.BaseFTPConnectionFileManager#createFile(org.eclipse.core.runtime.IPath,
* org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected void createFile(IPath path, IProgressMonitor monitor) throws CoreException, FileNotFoundException,
PermissionDeniedException
{
try
{
IPath dirPath = path.removeLastSegments(1);
changeCurrentDir(dirPath);
Policy.checkCanceled(monitor);
try
{
ftpClient.put(new ByteArrayInputStream(new byte[] {}), path.lastSegment());
}
catch (FTPException e)
{
throwWrappedException(e, path);
throw e;
}
}
catch (FileNotFoundException e)
{
throw e;
}
catch (OperationCanceledException e)
{
throw e;
}
catch (PermissionDeniedException e)
{
throw e;
}
catch (Exception e)
{
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID, MessageFormat.format(
Messages.SFTPConnectionFileManager_FailedDeletingFile, path), e));
}
finally
{
monitor.done();
}
}
/*
* (non-Javadoc)
* @see com.aptana.filesystem.ftp.BaseFTPConnectionFileManager#deleteFile(org.eclipse.core.runtime.IPath,
* org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected void deleteFile(IPath path, IProgressMonitor monitor) throws CoreException, FileNotFoundException
{
try
{
IPath dirPath = path.removeLastSegments(1);
changeCurrentDir(dirPath);
Policy.checkCanceled(monitor);
try
{
ftpClient.delete(path.lastSegment());
}
catch (FTPException e)
{
throwWrappedException(e, path);
throw e;
}
}
catch (FileNotFoundException e)
{
throw e;
}
catch (OperationCanceledException e)
{
throw e;
}
catch (Exception e)
{
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID, MessageFormat.format(
Messages.SFTPConnectionFileManager_FailedDeletingFile, path), e));
}
finally
{
monitor.done();
}
}
/*
* (non-Javadoc)
* @see com.aptana.filesystem.ftp.BaseFTPConnectionFileManager#renameFile(org.eclipse.core.runtime.IPath,
* org.eclipse.core.runtime.IPath, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected void renameFile(IPath sourcePath, IPath destinationPath, IProgressMonitor monitor) throws CoreException,
FileNotFoundException
{
try
{
changeCurrentDir(sourcePath.removeLastSegments(1));
Policy.checkCanceled(monitor);
if (ftpClient.exists(destinationPath.toPortableString()))
{
ftpClient.delete(destinationPath.toPortableString());
}
try
{
ftpClient.rename(sourcePath.toPortableString(), destinationPath.toPortableString());
}
catch (FTPException e)
{
throwWrappedException(e, sourcePath);
SecureFTPPlugin.log(new Status(IStatus.ERROR, SecureFTPPlugin.PLUGIN_ID, MessageFormat.format(
Messages.SFTPConnectionFileManager_FailedRename, new Object[] { sourcePath, destinationPath }),
e));
throw e;
}
}
catch (FileNotFoundException e)
{
throw e;
}
catch (PermissionDeniedException e)
{
throw new CoreException(new Status(IStatus.ERROR, SecureFTPPlugin.PLUGIN_ID, MessageFormat.format(
Messages.SFTPConnectionFileManager_PermissionDenied0, sourcePath.toPortableString()), e));
}
catch (OperationCanceledException e)
{
throw e;
}
catch (Exception e)
{
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
Messages.SFTPConnectionFileManager_FailedRenaming, e));
}
finally
{
monitor.done();
}
}
/*
* (non-Javadoc)
* @see com.aptana.core.io.vfs.BaseConnectionFileManager#renameDirectory(org.eclipse.core.runtime.IPath,
* org.eclipse.core.runtime.IPath, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected void renameDirectory(IPath sourcePath, IPath destinationPath, IProgressMonitor monitor)
throws CoreException, FileNotFoundException
{
try
{
changeCurrentDir(sourcePath.removeLastSegments(1));
Policy.checkCanceled(monitor);
if (ftpClient.exists(destinationPath.toPortableString()))
{
changeCurrentDir(destinationPath.removeLastSegments(1));
ftpClient.rmdir(destinationPath.lastSegment());
}
try
{
ftpClient.rename(sourcePath.toPortableString(), destinationPath.toPortableString());
}
catch (FTPException e)
{
throwWrappedException(e, sourcePath);
SecureFTPPlugin.log(new Status(IStatus.ERROR, SecureFTPPlugin.PLUGIN_ID, MessageFormat.format(
Messages.SFTPConnectionFileManager_FailedRename, new Object[] { sourcePath, destinationPath }),
e));
throw e;
}
}
catch (FileNotFoundException e)
{
throw e;
}
catch (PermissionDeniedException e)
{
throw new CoreException(new Status(IStatus.ERROR, SecureFTPPlugin.PLUGIN_ID, MessageFormat.format(
Messages.SFTPConnectionFileManager_PermissionDenied0, sourcePath.toPortableString()), e));
}
catch (OperationCanceledException e)
{
throw e;
}
catch (Exception e)
{
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
Messages.SFTPConnectionFileManager_FailedRenaming, e));
}
finally
{
monitor.done();
}
}
/*
* (non-Javadoc)
* @see com.aptana.filesystem.ftp.BaseFTPConnectionFileManager#listDirectory(org.eclipse.core.runtime.IPath,
* org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected String[] listDirectory(IPath path, IProgressMonitor monitor) throws CoreException, FileNotFoundException
{
try
{
FTPFile[] ftpFiles = listFiles(path, monitor);
List<String> list = new ArrayList<String>();
for (FTPFile ftpFile : ftpFiles)
{
String name = ftpFile.getName();
if (name == null || ".".equals(name) || "..".equals(name)) { //$NON-NLS-1$ //$NON-NLS-2$
continue;
}
ftpFileCache.put(path.append(name), ftpFile);
list.add(name);
}
return list.toArray(new String[list.size()]);
}
catch (FileNotFoundException e)
{
throw e;
}
catch (OperationCanceledException e)
{
throw e;
}
catch (Exception e)
{
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
Messages.SFTPConnectionFileManager_FailedListDirectory, e));
}
finally
{
monitor.done();
}
}
/*
* (non-Javadoc)
* @see com.aptana.filesystem.ftp.BaseFTPConnectionFileManager#readFile(org.eclipse.core.runtime.IPath,
* org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected InputStream readFile(IPath path, IProgressMonitor monitor) throws CoreException, FileNotFoundException
{
monitor.beginTask(Messages.SFTPConnectionFileManager_InitiatingFileDownload, 4);
try
{
Policy.checkCanceled(monitor);
changeCurrentDir(path.removeLastSegments(1));
monitor.worked(1);
Policy.checkCanceled(monitor);
try
{
return new SFTPFileDownloadInputStream(new SSHFTPInputStream(ftpClient, path.toPortableString()));
}
catch (FTPException e)
{
throwWrappedException(e, path);
return null;
}
}
catch (Exception e)
{
if (e instanceof OperationCanceledException)
{
throw (OperationCanceledException) e;
}
else if (e instanceof FileNotFoundException)
{
throw (FileNotFoundException) e;
}
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
Messages.SFTPConnectionFileManager_FailedOpeningFile, e));
}
finally
{
monitor.done();
}
}
/*
* (non-Javadoc)
* @see com.aptana.filesystem.ftp.internal.BaseFTPConnectionFileManager#writeFile(org.eclipse.core.runtime.IPath,
* boolean, long, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected OutputStream writeFile(final IPath path, boolean useTemporary, long permissions, IProgressMonitor monitor)
throws CoreException, FileNotFoundException
{
monitor.beginTask(Messages.SFTPConnectionFileManager_FailedInitiatingFile, 4);
try
{
Policy.checkCanceled(monitor);
changeCurrentDir(path.removeLastSegments(1));
monitor.worked(1);
Policy.checkCanceled(monitor);
return new SFTPFileUploadOutputStream(ftpClient, new SSHFTPOutputStream(ftpClient, useTemporary ? path
.removeLastSegments(1).append(generateTempFileName(path.lastSegment())).toPortableString()
: path.toPortableString()), useTemporary ? path.toPortableString() : null, new Date(), permissions,
new Runnable()
{
public void run()
{
clearCacheAbsolute(path);
}
});
}
catch (Exception e)
{
if (e instanceof OperationCanceledException)
{
throw (OperationCanceledException) e;
}
else if (e instanceof FileNotFoundException)
{
throw (FileNotFoundException) e;
}
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
Messages.SFTPConnectionFileManager_FailedOpeningFile, e));
}
finally
{
monitor.done();
}
}
/*
* (non-Javadoc)
* @see com.aptana.filesystem.ftp.BaseFTPConnectionFileManager#setModificationTime(org.eclipse.core.runtime.IPath,
* long, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected void setModificationTime(IPath path, long modificationTime, IProgressMonitor monitor)
throws CoreException, FileNotFoundException
{
try
{
IPath dirPath = path.removeLastSegments(1);
changeCurrentDir(dirPath);
Policy.checkCanceled(monitor);
try
{
ftpClient.setModTime(path.lastSegment(), new Date(modificationTime));
}
catch (FTPException e)
{
throwWrappedException(e, path);
}
}
catch (FileNotFoundException e)
{
throw e;
}
catch (OperationCanceledException e)
{
throw e;
}
catch (Exception e)
{
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
Messages.SFTPConnectionFileManager_FailedSetModificationTime, e));
}
finally
{
monitor.done();
}
}
/*
* (non-Javadoc)
* @see com.aptana.filesystem.ftp.BaseFTPConnectionFileManager#changeFileGroup(org.eclipse.core.runtime.IPath,
* java.lang.String, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected void changeFileGroup(IPath path, String group, IProgressMonitor monitor) throws CoreException,
FileNotFoundException
{
try
{
IPath dirPath = path.removeLastSegments(1);
changeCurrentDir(dirPath);
Policy.checkCanceled(monitor);
try
{
int gid = Integer.parseInt(group);
ftpClient.changeGroup(gid, path.lastSegment());
}
catch (FTPException e)
{
throwWrappedException(e, path);
}
catch (NumberFormatException e)
{
throw new IllegalArgumentException(Messages.SFTPConnectionFileManager_InvalidGroup);
}
}
catch (FileNotFoundException e)
{
throw e;
}
catch (OperationCanceledException e)
{
throw e;
}
catch (Exception e)
{
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
Messages.SFTPConnectionFileManager_FailedChangeGroup, e));
}
finally
{
monitor.done();
}
}
/*
* (non-Javadoc)
* @see com.aptana.filesystem.ftp.BaseFTPConnectionFileManager#changeFilePermissions(org.eclipse.core.runtime.IPath,
* long, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected void changeFilePermissions(IPath path, long permissions, IProgressMonitor monitor) throws CoreException,
FileNotFoundException
{
try
{
IPath dirPath = path.removeLastSegments(1);
changeCurrentDir(dirPath);
Policy.checkCanceled(monitor);
ftpClient.changeMode((int) (permissions & 0777), path.lastSegment());
}
catch (FileNotFoundException e)
{
throw e;
}
catch (OperationCanceledException e)
{
throw e;
}
catch (Exception e)
{
throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID,
Messages.SFTPConnectionFileManager_FailedSetPermissions, e));
}
finally
{
monitor.done();
}
}
private FTPFile[] listFiles(IPath dirPath, IProgressMonitor monitor) throws IOException, ParseException,
FTPException, PermissionDeniedException
{
Policy.checkCanceled(monitor);
try
{
return ftpClient.dirDetails(dirPath.toPortableString());
}
catch (FTPException e)
{
throwWrappedException(e, dirPath);
return null; // never runs
}
}
private void recursiveDeleteTree(IPath path, IProgressMonitor monitor, MultiStatus status) throws IOException,
ParseException
{
try
{
changeCurrentDir(path);
FTPFile[] ftpFiles = listFiles(path, monitor);
List<String> dirs = new ArrayList<String>();
for (FTPFile ftpFile : ftpFiles)
{
String name = ftpFile.getName();
if (name == null || ".".equals(name) || "..".equals(name)) { //$NON-NLS-1$ //$NON-NLS-2$
continue;
}
if (ftpFile.isDir())
{
dirs.add(name);
continue;
}
Policy.checkCanceled(monitor);
monitor.subTask(path.append(name).toPortableString());
try
{
ftpClient.delete(name);
}
catch (FTPException e)
{
status.add(new Status(IStatus.ERROR, SecureFTPPlugin.PLUGIN_ID, MessageFormat.format(
Messages.SFTPConnectionFileManager_FailedDeleting, path.append(name).toPortableString()), e));
}
monitor.worked(1);
}
for (String name : dirs)
{
monitor.subTask(path.append(name).toPortableString());
recursiveDeleteTree(path.append(name), monitor, status);
Policy.checkCanceled(monitor);
changeCurrentDir(path);
Policy.checkCanceled(monitor);
ftpClient.rmdir(name);
monitor.worked(1);
}
}
catch (IOException e)
{
throw e;
}
catch (Exception e)
{
status.add(new Status(IStatus.ERROR, SecureFTPPlugin.PLUGIN_ID, MessageFormat.format(
Messages.SFTPConnectionFileManager_FailedDeleting, path.toPortableString()), e));
}
}
private static String generateTempFileName(String base)
{
StringBuilder sb = new StringBuilder();
sb.append(base).append(TMP_UPLOAD_SUFFIX);
String ext = Path.fromPortableString(base).getFileExtension();
if (ext != null)
{
sb.append(ext);
}
return sb.toString();
}
}