mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-03 07:05:24 +02:00
[203500] Support encodings for SSH Sftp and FTP paths
This commit is contained in:
parent
48a344793d
commit
a46672968f
5 changed files with 274 additions and 39 deletions
|
@ -13,6 +13,7 @@
|
|||
* Martin Oberhuber (Wind River) - [186773] split ISystemRegistryUI from ISystemRegistry
|
||||
* Martin Oberhuber (Wind River) - [186761] make the port setting configurable
|
||||
* Martin Oberhuber (Wind River) - [198790] make SSH createSession() protected
|
||||
* Martin Oberhuber (Wind River) - [203500] Support encodings for SSH Sftp paths
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.rse.internal.connectorservice.ssh;
|
||||
|
@ -61,6 +62,8 @@ public class SshConnectorService extends StandardConnectorService implements ISs
|
|||
private static final int CONNECT_DEFAULT_TIMEOUT = 60; //seconds
|
||||
private Session session;
|
||||
private SessionLostHandler fSessionLostHandler;
|
||||
/** Indicates the default string encoding on this platform */
|
||||
private static String _defaultEncoding = new java.io.InputStreamReader(new java.io.ByteArrayInputStream(new byte[0])).getEncoding();
|
||||
|
||||
public SshConnectorService(IHost host) {
|
||||
super(SshConnectorResources.SshConnectorService_Name, SshConnectorResources.SshConnectorService_Description, host, SSH_DEFAULT_PORT);
|
||||
|
@ -209,6 +212,15 @@ public class SshConnectorService extends StandardConnectorService implements ISs
|
|||
public Session getSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
public String getControlEncoding() {
|
||||
//TODO this code should be in IHost
|
||||
String encoding = getHost().getDefaultEncoding(false);
|
||||
if (encoding==null) encoding = getHost().getDefaultEncoding(true);
|
||||
if (encoding==null) encoding = _defaultEncoding;
|
||||
//</code to be in IHost>
|
||||
return encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle session-lost events.
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
* Javier Montalvo Orus (Symbian) - Fixing 168120 - [ftp] root filter resolves to home dir
|
||||
* Javier Montalvo Orus (Symbian) - Fixing 169680 - [ftp] FTP files subsystem and service should use passive mode
|
||||
* Javier Montalvo Orus (Symbian) - Fixing 174828 - [ftp] Folders are attempted to be removed as files
|
||||
* Javier Montalvo Orus (Symbian) - Fixing 176216 - [api] FTP sould provide API to allow clients register their own FTPListingParser
|
||||
* Javier Montalvo Orus (Symbian) - Fixing 176216 - [api] FTP should provide API to allow clients register their own FTPListingParser
|
||||
* Martin Oberhuber (Wind River) - [186128] Move IProgressMonitor last in all API
|
||||
* Javier Montalvo Orus (Symbian) - improved autodetection of FTPListingParser
|
||||
* Javier Montalvo Orus (Symbian) - [187096] Drag&Drop + Copy&Paste shows error message on FTP connection
|
||||
|
@ -61,6 +61,7 @@
|
|||
* Martin Oberhuber (Wind River) - [203306] Fix Deadlock comparing two files on FTP
|
||||
* Martin Oberhuber (Wind River) - [204669] Fix ftp path concatenation on systems using backslash separator
|
||||
* Martin Oberhuber (Wind River) - [203490] Fix NPE in FTPService.getUserHome()
|
||||
* Martin Oberhuber (Wind River) - [203500] Support encodings for FTP paths
|
||||
********************************************************************************/
|
||||
|
||||
package org.eclipse.rse.internal.services.files.ftp;
|
||||
|
@ -74,6 +75,7 @@ import java.io.FileOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
@ -96,6 +98,8 @@ import org.eclipse.rse.services.clientserver.FileTypeMatcher;
|
|||
import org.eclipse.rse.services.clientserver.IMatcher;
|
||||
import org.eclipse.rse.services.clientserver.NamePatternMatcher;
|
||||
import org.eclipse.rse.services.clientserver.PathUtility;
|
||||
import org.eclipse.rse.services.clientserver.messages.IndicatorException;
|
||||
import org.eclipse.rse.services.clientserver.messages.SystemMessage;
|
||||
import org.eclipse.rse.services.clientserver.messages.SystemMessageException;
|
||||
import org.eclipse.rse.services.files.AbstractFileService;
|
||||
import org.eclipse.rse.services.files.IFileService;
|
||||
|
@ -117,6 +121,7 @@ public class FTPService extends AbstractFileService implements IFileService, IFT
|
|||
private transient String _userId;
|
||||
private transient String _password;
|
||||
private transient int _portNumber;
|
||||
private transient String _controlEncoding; //Encoding to be used for file and path names
|
||||
|
||||
private OutputStream _ftpLoggingOutputStream;
|
||||
private IPropertySet _ftpPropertySet;
|
||||
|
@ -273,13 +278,69 @@ public class FTPService extends AbstractFileService implements IFileService, IFT
|
|||
{
|
||||
_entryParserFactory = entryParserFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the character encoding to be used on the FTP command channel.
|
||||
* The encoding must be compatible with ASCII since FTP commands will
|
||||
* be sent with the same encoding. Therefore, wide
|
||||
* (16-bit) encodings are not supported.
|
||||
* @param encoding Encoding to set
|
||||
*/
|
||||
public void setControlEncoding(String encoding)
|
||||
{
|
||||
_controlEncoding = encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given Unicode String can be properly represented with the
|
||||
* specified control encoding. Throw a SystemMessageException if it turns out
|
||||
* that information would be lost.
|
||||
* @param s String to check
|
||||
* @return the original String or a quoted or re-coded version if possible
|
||||
* @throws SystemMessageException if information is lost
|
||||
*/
|
||||
protected String checkEncoding(String s) throws SystemMessageException {
|
||||
String encoding = _controlEncoding!=null ? _controlEncoding : getFTPClient().getControlEncoding();
|
||||
try {
|
||||
byte[] bytes = s.getBytes(encoding);
|
||||
String decoded = new String(bytes, encoding);
|
||||
if (!s.equals(decoded)) {
|
||||
int i=0;
|
||||
int lmax = Math.min(s.length(), decoded.length());
|
||||
while( (i<lmax) && (s.charAt(i)==decoded.charAt(i))) {
|
||||
i++;
|
||||
}
|
||||
//String sbad=s.substring(Math.max(i-2,0), Math.min(i+2,lmax));
|
||||
char sbad = s.charAt(i);
|
||||
//FIXME Need to externalize this message in 3.0
|
||||
String msg = "Cannot express character \'"+sbad+"\'(0x"+Integer.toHexString(sbad) +") with " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
+ "encoding \""+encoding+"\". "; //$NON-NLS-1$ //$NON-NLS-2$
|
||||
msg += "Please specify a different encoding in host properties."; //$NON-NLS-1$
|
||||
throw new UnsupportedEncodingException(msg);
|
||||
}
|
||||
return s;
|
||||
} catch(UnsupportedEncodingException e) {
|
||||
try {
|
||||
//SystemMessage msg = new SystemMessage("RSE","F","9999",'E',e.getMessage(),"Please specify a different encoding in host properties."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
|
||||
SystemMessage msg = new SystemMessage("RSE","F","9999",'E',e.getMessage(),""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
|
||||
//throw new RemoteFileIOException(new SystemMessageException(msg));
|
||||
throw new SystemMessageException(msg);
|
||||
} catch(IndicatorException ind) {
|
||||
throw new RemoteFileIOException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void connect() throws RemoteFileSecurityException,IOException
|
||||
{
|
||||
|
||||
if (_ftpClient == null)
|
||||
{
|
||||
_ftpClient = new FTPClient();
|
||||
// Encoding of control connection
|
||||
if(_controlEncoding!=null) {
|
||||
_ftpClient.setControlEncoding(_controlEncoding);
|
||||
}
|
||||
}
|
||||
|
||||
if(_ftpLoggingOutputStream!=null)
|
||||
|
@ -403,6 +464,10 @@ public class FTPService extends AbstractFileService implements IFileService, IFT
|
|||
if (_ftpClient == null)
|
||||
{
|
||||
_ftpClient = new FTPClient();
|
||||
// Encoding of control connection
|
||||
if(_controlEncoding!=null) {
|
||||
_ftpClient.setControlEncoding(_controlEncoding);
|
||||
}
|
||||
}
|
||||
|
||||
if(_hostName!=null)
|
||||
|
@ -433,6 +498,7 @@ public class FTPService extends AbstractFileService implements IFileService, IFT
|
|||
FTPClient ftpClient = new FTPClient();
|
||||
boolean ok=false;
|
||||
try {
|
||||
ftpClient.setControlEncoding(_ftpClient.getControlEncoding());
|
||||
ftpClient.connect(_ftpClient.getRemoteAddress());
|
||||
ftpClient.login(_userId,_password);
|
||||
|
||||
|
@ -485,6 +551,8 @@ public class FTPService extends AbstractFileService implements IFileService, IFT
|
|||
*/
|
||||
protected FTPHostFile getFileInternal(String remoteParent, String fileName, IProgressMonitor monitor) throws SystemMessageException
|
||||
{
|
||||
remoteParent = checkEncoding(remoteParent);
|
||||
fileName = checkEncoding(fileName);
|
||||
if (monitor!=null){
|
||||
if (monitor.isCanceled()) {
|
||||
throw new RemoteFileCancelledException();
|
||||
|
@ -584,6 +652,7 @@ public class FTPService extends AbstractFileService implements IFileService, IFT
|
|||
*/
|
||||
protected IHostFile[] internalFetch(String parentPath, String fileFilter, int fileType, IProgressMonitor monitor) throws SystemMessageException
|
||||
{
|
||||
parentPath = checkEncoding(parentPath);
|
||||
if (monitor!=null){
|
||||
if (monitor.isCanceled()) {
|
||||
throw new RemoteFileCancelledException();
|
||||
|
@ -676,6 +745,8 @@ public class FTPService extends AbstractFileService implements IFileService, IFT
|
|||
public boolean upload(File localFile, String remoteParent, String remoteFile, boolean isBinary, String srcEncoding, String hostEncoding, IProgressMonitor monitor) throws SystemMessageException
|
||||
{
|
||||
boolean retValue = true;
|
||||
remoteParent = checkEncoding(remoteParent);
|
||||
remoteFile = checkEncoding(remoteFile);
|
||||
|
||||
if (monitor!=null){
|
||||
if (monitor.isCanceled()) {
|
||||
|
@ -758,6 +829,8 @@ public class FTPService extends AbstractFileService implements IFileService, IFT
|
|||
public boolean upload(InputStream stream, String remoteParent, String remoteFile, boolean isBinary, String hostEncoding, IProgressMonitor monitor) throws SystemMessageException
|
||||
{
|
||||
boolean retValue = true;
|
||||
remoteParent = checkEncoding(remoteParent);
|
||||
remoteFile = checkEncoding(remoteFile);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -897,7 +970,6 @@ public class FTPService extends AbstractFileService implements IFileService, IFT
|
|||
return new FTPHostFile("",_userHome,true,true,0,0,true); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.eclipse.rse.services.files.IFileService#getRoots(org.eclipse.core.runtime.IProgressMonitor)
|
||||
|
@ -924,7 +996,9 @@ public class FTPService extends AbstractFileService implements IFileService, IFT
|
|||
*/
|
||||
public boolean delete(String remoteParent, String fileName, IProgressMonitor monitor) throws SystemMessageException {
|
||||
boolean hasSucceeded = false;
|
||||
|
||||
remoteParent = checkEncoding(remoteParent);
|
||||
fileName = checkEncoding(fileName);
|
||||
|
||||
MyProgressMonitor progressMonitor = new MyProgressMonitor(monitor);
|
||||
progressMonitor.init(FTPServiceResources.FTP_File_Service_Deleting_Task+fileName, 1);
|
||||
|
||||
|
@ -980,8 +1054,10 @@ public class FTPService extends AbstractFileService implements IFileService, IFT
|
|||
* @see org.eclipse.rse.services.files.IFileService#rename(org.eclipse.core.runtime.IProgressMonitor, java.lang.String, java.lang.String, java.lang.String)
|
||||
*/
|
||||
public boolean rename(String remoteParent, String oldName, String newName, IProgressMonitor monitor) throws SystemMessageException {
|
||||
|
||||
boolean success = false;
|
||||
remoteParent = checkEncoding(remoteParent);
|
||||
oldName = checkEncoding(oldName);
|
||||
newName = checkEncoding(newName);
|
||||
|
||||
if(_commandMutex.waitForLock(monitor, Long.MAX_VALUE))
|
||||
{
|
||||
|
@ -1026,8 +1102,11 @@ public class FTPService extends AbstractFileService implements IFileService, IFT
|
|||
* @see org.eclipse.rse.services.files.IFileService#move(org.eclipse.core.runtime.IProgressMonitor, java.lang.String, java.lang.String, java.lang.String, java.lang.String)
|
||||
*/
|
||||
public boolean move(String srcParent, String srcName, String tgtParent, String tgtName, IProgressMonitor monitor) throws SystemMessageException{
|
||||
|
||||
boolean success = false;
|
||||
srcParent = checkEncoding(srcParent);
|
||||
srcName = checkEncoding(srcName);
|
||||
tgtParent = checkEncoding(tgtParent);
|
||||
tgtName = checkEncoding(tgtName);
|
||||
|
||||
if(_commandMutex.waitForLock(monitor, Long.MAX_VALUE))
|
||||
{
|
||||
|
@ -1061,6 +1140,8 @@ public class FTPService extends AbstractFileService implements IFileService, IFT
|
|||
*/
|
||||
public IHostFile createFolder(String remoteParent, String folderName, IProgressMonitor monitor) throws SystemMessageException
|
||||
{
|
||||
remoteParent = checkEncoding(remoteParent);
|
||||
folderName = checkEncoding(folderName);
|
||||
if(_commandMutex.waitForLock(monitor, Long.MAX_VALUE))
|
||||
{
|
||||
try
|
||||
|
@ -1093,7 +1174,8 @@ public class FTPService extends AbstractFileService implements IFileService, IFT
|
|||
* @see org.eclipse.rse.services.files.IFileService#createFile(org.eclipse.core.runtime.IProgressMonitor, java.lang.String, java.lang.String)
|
||||
*/
|
||||
public IHostFile createFile(String remoteParent, String fileName, IProgressMonitor monitor) throws SystemMessageException{
|
||||
|
||||
remoteParent = checkEncoding(remoteParent);
|
||||
fileName = checkEncoding(fileName);
|
||||
try {
|
||||
File tempFile = File.createTempFile("ftp", "temp"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
tempFile.deleteOnExit();
|
||||
|
@ -1385,7 +1467,9 @@ public class FTPService extends AbstractFileService implements IFileService, IFT
|
|||
* @see org.eclipse.rse.services.files.AbstractFileService#getOutputStream(java.lang.String, java.lang.String, boolean, org.eclipse.core.runtime.IProgressMonitor)
|
||||
*/
|
||||
public OutputStream getOutputStream(String remoteParent, String remoteFile, boolean isBinary, IProgressMonitor monitor) throws SystemMessageException {
|
||||
|
||||
remoteParent = checkEncoding(remoteParent);
|
||||
remoteFile = checkEncoding(remoteFile);
|
||||
|
||||
if (monitor != null && monitor.isCanceled()){
|
||||
throw new RemoteFileCancelledException();
|
||||
}
|
||||
|
@ -1435,4 +1519,4 @@ public class FTPService extends AbstractFileService implements IFileService, IFT
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
* Emily Bruner, Mazen Faraj, Adrian Storisteanu, Li Ding, and Kent Hawley.
|
||||
*
|
||||
* Contributors:
|
||||
* {Name} (company) - description of contribution.
|
||||
* Martin Oberhuber (Wind River) - [203500] Support encodings for SSH Sftp paths
|
||||
*******************************************************************************/
|
||||
package org.eclipse.rse.internal.services.ssh;
|
||||
|
||||
|
@ -26,4 +26,7 @@ public interface ISshSessionProvider
|
|||
/* Inform the connectorService that a session has been lost. */
|
||||
public void handleSessionLost();
|
||||
|
||||
/* Return the encoding to be used for file and directory names */
|
||||
public String getControlEncoding();
|
||||
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
* Martin Oberhuber (Wind River) - [199548] Avoid touching files on setReadOnly() if unnecessary
|
||||
* Benjamin Muskalla (b.muskalla@gmx.net) - [174690][ssh] cannot delete symbolic links on remote systems
|
||||
* Martin Oberhuber (Wind River) - [203490] Fix NPE in SftpService.getUserHome()
|
||||
* Martin Oberhuber (Wind River) - [203500] Support encodings for SSH Sftp paths
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.rse.internal.services.ssh.files;
|
||||
|
@ -26,10 +27,12 @@ import java.io.FileOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
|
@ -53,6 +56,8 @@ import org.eclipse.rse.services.clientserver.FileTypeMatcher;
|
|||
import org.eclipse.rse.services.clientserver.IMatcher;
|
||||
import org.eclipse.rse.services.clientserver.NamePatternMatcher;
|
||||
import org.eclipse.rse.services.clientserver.PathUtility;
|
||||
import org.eclipse.rse.services.clientserver.messages.IndicatorException;
|
||||
import org.eclipse.rse.services.clientserver.messages.SystemMessage;
|
||||
import org.eclipse.rse.services.clientserver.messages.SystemMessageException;
|
||||
import org.eclipse.rse.services.files.AbstractFileService;
|
||||
import org.eclipse.rse.services.files.IFileService;
|
||||
|
@ -139,7 +144,11 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
private ChannelSftp fChannelSftp;
|
||||
private String fUserHome;
|
||||
private Mutex fDirChannelMutex = new Mutex();
|
||||
private long fDirChannelTimeout = 5000; //max.5 seconds to obtain dir channel
|
||||
private long fDirChannelTimeout = 5000; //max.5 seconds to obtain dir channel
|
||||
/** Client-desired encoding for file and path names */
|
||||
private String fControlEncoding = null;
|
||||
/** Indicates the default string encoding on this platform */
|
||||
private static String defaultEncoding = new java.io.InputStreamReader(new java.io.ByteArrayInputStream(new byte[0])).getEncoding();
|
||||
|
||||
// public SftpFileService(SshConnectorService conn) {
|
||||
// fConnector = conn;
|
||||
|
@ -149,6 +158,121 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
fSessionProvider = sessionProvider;
|
||||
}
|
||||
|
||||
public void setControlEncoding(String encoding) {
|
||||
fControlEncoding = encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode String with requested user encoding, in case it differs from Platform default encoding.
|
||||
* @param s String to encode
|
||||
* @return encoded String
|
||||
* @throws SystemMessageException
|
||||
*/
|
||||
protected String recode(String s) throws SystemMessageException {
|
||||
if (fControlEncoding==null) {
|
||||
return s;
|
||||
} else if (fControlEncoding.equals(defaultEncoding)) {
|
||||
return s;
|
||||
}
|
||||
try {
|
||||
byte[] bytes = s.getBytes(fControlEncoding); //what we want on the wire
|
||||
return new String(bytes); //what we need to tell Jsch to get this on the wire
|
||||
} catch(UnsupportedEncodingException e) {
|
||||
throw makeSystemMessageException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recode String, and check that no information is lost.
|
||||
* Throw an exception in case the desired Unicode String can not be expressed
|
||||
* by the current encodings. Also enquotes result characters '?' and '*' for
|
||||
* Jsch if necessary.
|
||||
* @param s String to recode
|
||||
* @return recoded String
|
||||
* @throws SystemMessageException if information is lost
|
||||
*/
|
||||
protected String recodeSafe(String s) throws SystemMessageException {
|
||||
try {
|
||||
String recoded = recode(s);
|
||||
byte[] bytes = recoded.getBytes(defaultEncoding);
|
||||
String decoded = decode(new String(bytes));
|
||||
if (!s.equals(decoded)) {
|
||||
int i=0;
|
||||
int lmax = Math.min(s.length(), decoded.length());
|
||||
while( (i<lmax) && (s.charAt(i)==decoded.charAt(i))) {
|
||||
i++;
|
||||
}
|
||||
//String sbad=s.substring(Math.max(i-2,0), Math.min(i+2,lmax));
|
||||
char sbad = s.charAt(i);
|
||||
String msg = "Cannot express character \'"+sbad+"\'(0x"+Integer.toHexString(sbad) +") with "; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
if (fControlEncoding==null || fControlEncoding.equals(defaultEncoding)) {
|
||||
msg += "default encoding \""+defaultEncoding+"\". "; //$NON-NLS-1$ //$NON-NLS-2$
|
||||
} else {
|
||||
msg += "encoding \""+fControlEncoding+"\" over local default encoding \""+defaultEncoding+"\". "; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
}
|
||||
msg += "Please specify a different encoding in host properties."; //$NON-NLS-1$
|
||||
throw new UnsupportedEncodingException(msg);
|
||||
}
|
||||
//Quote ? and * characters for Jsch
|
||||
//FIXME bug 204705: this does not work properly for commands like ls(), due to a Jsch bug
|
||||
return quoteForJsch(recoded);
|
||||
} catch(UnsupportedEncodingException e) {
|
||||
try {
|
||||
//SystemMessage msg = new SystemMessage("RSE","F","9999",'E',e.getMessage(),"Please specify a different encoding in host properties."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
|
||||
SystemMessage msg = new SystemMessage("RSE","F","9999",'E',e.getMessage(),""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
|
||||
//throw new RemoteFileIOException(new SystemMessageException(msg));
|
||||
throw new SystemMessageException(msg);
|
||||
} catch(IndicatorException ind) {
|
||||
throw makeSystemMessageException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode String (sftp result) with requested user encoding, in case it differs from Platform default encoding.
|
||||
* @param s String to decode
|
||||
* @return decoded String
|
||||
* @throws SystemMessageException
|
||||
*/
|
||||
protected String decode(String s) throws SystemMessageException {
|
||||
if (fControlEncoding==null) {
|
||||
return s;
|
||||
} else if (fControlEncoding.equals(defaultEncoding)) {
|
||||
return s;
|
||||
}
|
||||
try {
|
||||
byte[] bytes = s.getBytes(); //original bytes sent by SSH
|
||||
return new String(bytes, fControlEncoding);
|
||||
} catch(UnsupportedEncodingException e) {
|
||||
throw makeSystemMessageException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Regular expression pattern to know when Jsch needs quoting. */
|
||||
private static Pattern quoteForJschPattern = Pattern.compile("[*?\\\\]"); //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* Quote characters '?' and '*' for Jsch because it would otherwise
|
||||
* use them as patterns for globbing.
|
||||
* @param s String to enquote
|
||||
* @return String with '?' and '*' quoted.
|
||||
*/
|
||||
protected String quoteForJsch(String s) {
|
||||
if(quoteForJschPattern.matcher(s).find()) {
|
||||
StringBuffer buf = new StringBuffer(s.length()+8);
|
||||
for(int i=0; i<s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
// if(c=='?' || c=='*' || c=='\\') {
|
||||
if(c=='?' || c=='*') {
|
||||
buf.append('\\');
|
||||
}
|
||||
buf.append(c);
|
||||
}
|
||||
s = buf.toString();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return SshServiceResources.SftpFileService_Name;
|
||||
}
|
||||
|
@ -164,7 +288,8 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
Channel channel=session.openChannel("sftp"); //$NON-NLS-1$
|
||||
channel.connect();
|
||||
fChannelSftp=(ChannelSftp)channel;
|
||||
fUserHome = fChannelSftp.pwd();
|
||||
setControlEncoding(fSessionProvider.getControlEncoding());
|
||||
fUserHome = decode(fChannelSftp.pwd());
|
||||
Activator.trace("SftpFileService.connected"); //$NON-NLS-1$
|
||||
} catch(Exception e) {
|
||||
Activator.trace("SftpFileService.connecting failed: "+e.toString()); //$NON-NLS-1$
|
||||
|
@ -256,7 +381,7 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
SftpATTRS attrs = null;
|
||||
if (fDirChannelMutex.waitForLock(monitor, fDirChannelTimeout)) {
|
||||
try {
|
||||
attrs = getChannel("SftpFileService.getFile: "+fileName).stat(remoteParent+'/'+fileName); //$NON-NLS-1$
|
||||
attrs = getChannel("SftpFileService.getFile: "+fileName).stat(recodeSafe(remoteParent+'/'+fileName)); //$NON-NLS-1$
|
||||
Activator.trace("SftpFileService.getFile <--"); //$NON-NLS-1$
|
||||
node = makeHostFile(remoteParent, fileName, attrs);
|
||||
} catch(Exception e) {
|
||||
|
@ -304,12 +429,12 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
List results = new ArrayList();
|
||||
if (fDirChannelMutex.waitForLock(monitor, fDirChannelTimeout)) {
|
||||
try {
|
||||
Vector vv=getChannel("SftpFileService.internalFetch: "+parentPath).ls(parentPath); //$NON-NLS-1$
|
||||
Vector vv=getChannel("SftpFileService.internalFetch: "+parentPath).ls(recodeSafe(parentPath)); //$NON-NLS-1$
|
||||
for(int ii=0; ii<vv.size(); ii++) {
|
||||
Object obj=vv.elementAt(ii);
|
||||
if(obj instanceof ChannelSftp.LsEntry){
|
||||
ChannelSftp.LsEntry lsEntry = (ChannelSftp.LsEntry)obj;
|
||||
String fileName = lsEntry.getFilename();
|
||||
String fileName = decode(lsEntry.getFilename());
|
||||
if (".".equals(fileName) || "..".equals(fileName)) { //$NON-NLS-1$ //$NON-NLS-2$
|
||||
//don't show the trivial names
|
||||
continue;
|
||||
|
@ -353,15 +478,15 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
// try {
|
||||
// //Note: readlink() is supported only with jsch-0.1.29 or higher.
|
||||
// //By catching the exception we remain backward compatible.
|
||||
// linkTarget=getChannel("makeHostFile.readlink").readlink(node.getAbsolutePath()); //$NON-NLS-1$
|
||||
// linkTarget=getChannel("makeHostFile.readlink").readlink(recode(node.getAbsolutePath())); //$NON-NLS-1$
|
||||
// //TODO: Classify the type of resource linked to as file, folder or broken link
|
||||
// } catch(Exception e) {}
|
||||
//check if the link points to a directory
|
||||
try {
|
||||
getChannel("makeHostFile.chdir").cd(parentPath+'/'+fileName); //$NON-NLS-1$
|
||||
linkTarget=getChannel("makeHostFile.chdir").pwd(); //$NON-NLS-1$
|
||||
getChannel("makeHostFile.chdir").cd(recode(parentPath+'/'+fileName)); //$NON-NLS-1$
|
||||
linkTarget=decode(getChannel("makeHostFile.chdir").pwd()); //$NON-NLS-1$
|
||||
if (linkTarget!=null && !linkTarget.equals(parentPath+'/'+fileName)) {
|
||||
attrsTarget = getChannel("SftpFileService.getFile").stat(linkTarget); //$NON-NLS-1$
|
||||
attrsTarget = getChannel("SftpFileService.getFile").stat(recode(linkTarget)); //$NON-NLS-1$
|
||||
} else {
|
||||
linkTarget=null;
|
||||
}
|
||||
|
@ -421,6 +546,7 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
}
|
||||
dst += remoteFile;
|
||||
}
|
||||
dst = recodeSafe(dst);
|
||||
getChannel("SftpFileService.upload "+remoteFile); //check the session is healthy //$NON-NLS-1$
|
||||
channel=(ChannelSftp)fSessionProvider.getSession().openChannel("sftp"); //$NON-NLS-1$
|
||||
channel.connect();
|
||||
|
@ -439,7 +565,7 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
if (attr.getSize() != localFile.length()) {
|
||||
//Error: file truncated? - Inform the user!!
|
||||
//TODO test if this works
|
||||
throw makeSystemMessageException(new IOException(NLS.bind(SshServiceResources.SftpFileService_Error_upload_size,dst)));
|
||||
throw makeSystemMessageException(new IOException(NLS.bind(SshServiceResources.SftpFileService_Error_upload_size,remoteFile)));
|
||||
//return false;
|
||||
}
|
||||
}
|
||||
|
@ -532,7 +658,7 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
//localFile.createNewFile();
|
||||
}
|
||||
//TODO Ascii/binary?
|
||||
String remotePath = remoteParent+'/'+remoteFile;
|
||||
String remotePath = recode(remoteParent+'/'+remoteFile);
|
||||
int mode=ChannelSftp.OVERWRITE;
|
||||
MyProgressMonitor sftpMonitor = new MyProgressMonitor(monitor);
|
||||
getChannel("SftpFileService.download "+remoteFile); //check the session is healthy //$NON-NLS-1$
|
||||
|
@ -550,7 +676,7 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
if (attr.getSize() != localFile.length()) {
|
||||
//Error: file truncated? - Inform the user!!
|
||||
//TODO test if this works
|
||||
throw makeSystemMessageException(new IOException(NLS.bind(SshServiceResources.SftpFileService_Error_download_size,remotePath)));
|
||||
throw makeSystemMessageException(new IOException(NLS.bind(SshServiceResources.SftpFileService_Error_download_size,remoteFile)));
|
||||
//return false;
|
||||
}
|
||||
}
|
||||
|
@ -603,7 +729,7 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
IHostFile result = null;
|
||||
if (fDirChannelMutex.waitForLock(monitor, fDirChannelTimeout)) {
|
||||
try {
|
||||
String fullPath = remoteParent + '/' + fileName;
|
||||
String fullPath = recodeSafe(remoteParent + '/' + fileName);
|
||||
OutputStream os = getChannel("SftpFileService.createFile").put(fullPath); //$NON-NLS-1$
|
||||
//TODO workaround bug 153118: write a single space
|
||||
//since jsch hangs when trying to close the stream without writing
|
||||
|
@ -629,7 +755,7 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
IHostFile result = null;
|
||||
if (fDirChannelMutex.waitForLock(monitor, fDirChannelTimeout)) {
|
||||
try {
|
||||
String fullPath = remoteParent + '/' + folderName;
|
||||
String fullPath = recodeSafe(remoteParent + '/' + folderName);
|
||||
getChannel("SftpFileService.createFolder").mkdir(fullPath); //$NON-NLS-1$
|
||||
SftpATTRS attrs = getChannel("SftpFileService.createFolder.stat").stat(fullPath); //$NON-NLS-1$
|
||||
result = makeHostFile(remoteParent, folderName, attrs);
|
||||
|
@ -652,7 +778,7 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
Activator.trace("SftpFileService.delete.waitForLock"); //$NON-NLS-1$
|
||||
if (fDirChannelMutex.waitForLock(monitor, fDirChannelTimeout)) {
|
||||
try {
|
||||
String fullPath = remoteParent + '/' + fileName;
|
||||
String fullPath = recodeSafe(remoteParent + '/' + fileName);
|
||||
SftpATTRS attrs = null;
|
||||
try {
|
||||
attrs = getChannel("SftpFileService.delete").lstat(fullPath); //$NON-NLS-1$
|
||||
|
@ -705,7 +831,7 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
try {
|
||||
String fullPathOld = remoteParent + '/' + oldName;
|
||||
String fullPathNew = remoteParent + '/' + newName;
|
||||
getChannel("SftpFileService.rename").rename(fullPathOld, fullPathNew); //$NON-NLS-1$
|
||||
getChannel("SftpFileService.rename").rename(recode(fullPathOld), recodeSafe(fullPathNew)); //$NON-NLS-1$
|
||||
ok=true;
|
||||
Activator.trace("SftpFileService.rename ok"); //$NON-NLS-1$
|
||||
} catch (Exception e) {
|
||||
|
@ -794,8 +920,8 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
// TODO Interpret some error messages like "command not found" (use ren instead of mv on windows)
|
||||
// TODO mimic by copy if the remote does not support copying between file systems?
|
||||
Activator.trace("SftpFileService.move "+srcName); //$NON-NLS-1$
|
||||
String fullPathOld = PathUtility.enQuoteUnix(srcParent + '/' + srcName);
|
||||
String fullPathNew = PathUtility.enQuoteUnix(tgtParent + '/' + tgtName);
|
||||
String fullPathOld = PathUtility.enQuoteUnix(recode(srcParent + '/' + srcName));
|
||||
String fullPathNew = PathUtility.enQuoteUnix(recodeSafe(tgtParent + '/' + tgtName));
|
||||
int rv = runCommand("mv "+fullPathOld+' '+fullPathNew, monitor); //$NON-NLS-1$
|
||||
return (rv==0);
|
||||
}
|
||||
|
@ -805,8 +931,8 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
// TODO check if newer versions of sftp support copy directly
|
||||
// TODO Interpret some error messages like "command not found" (use (x)copy instead of cp on windows)
|
||||
Activator.trace("SftpFileService.copy "+srcName); //$NON-NLS-1$
|
||||
String fullPathOld = PathUtility.enQuoteUnix(srcParent + '/' + srcName);
|
||||
String fullPathNew = PathUtility.enQuoteUnix(tgtParent + '/' + tgtName);
|
||||
String fullPathOld = PathUtility.enQuoteUnix(recode(srcParent + '/' + srcName));
|
||||
String fullPathNew = PathUtility.enQuoteUnix(recodeSafe(tgtParent + '/' + tgtName));
|
||||
int rv = runCommand("cp -Rp "+fullPathOld+' '+fullPathNew, monitor); //$NON-NLS-1$
|
||||
return (rv==0);
|
||||
}
|
||||
|
@ -852,7 +978,7 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
if (fDirChannelMutex.waitForLock(monitor, fDirChannelTimeout)) {
|
||||
try {
|
||||
String path = parent + '/' + name;
|
||||
getChannel("SftpFileService.setLastModified").setMtime(path, (int)(timestamp/1000)); //$NON-NLS-1$
|
||||
getChannel("SftpFileService.setLastModified").setMtime(recode(path), (int)(timestamp/1000)); //$NON-NLS-1$
|
||||
ok=true;
|
||||
Activator.trace("SftpFileService.setLastModified ok"); //$NON-NLS-1$
|
||||
} catch (Exception e) {
|
||||
|
@ -871,7 +997,7 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
if (fDirChannelMutex.waitForLock(monitor, fDirChannelTimeout)) {
|
||||
try {
|
||||
String path = parent + '/' + name;
|
||||
SftpATTRS attr = getChannel("SftpFileService.setReadOnly").stat(path); //$NON-NLS-1$
|
||||
SftpATTRS attr = getChannel("SftpFileService.setReadOnly").stat(recode(path)); //$NON-NLS-1$
|
||||
int permOld = attr.getPermissions();
|
||||
int permNew = permOld;
|
||||
if (readOnly) {
|
||||
|
@ -882,7 +1008,7 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
if (permNew != permOld) {
|
||||
//getChannel("SftpFileService.setReadOnly").chmod(permNew, path); //$NON-NLS-1$
|
||||
attr.setPERMISSIONS(permNew);
|
||||
getChannel("SftpFileService.setReadOnly").setStat(path, attr); //$NON-NLS-1$
|
||||
getChannel("SftpFileService.setReadOnly").setStat(recode(path), attr); //$NON-NLS-1$
|
||||
ok=true;
|
||||
Activator.trace("SftpFileService.setReadOnly ok"); //$NON-NLS-1$
|
||||
} else {
|
||||
|
@ -909,7 +1035,7 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
InputStream stream = null;
|
||||
|
||||
try {
|
||||
String remotePath = remoteParent + '/' + remoteFile;
|
||||
String remotePath = recode(remoteParent + '/' + remoteFile);
|
||||
getChannel("SftpFileService.getInputStream " + remoteFile); //check the session is healthy //$NON-NLS-1$
|
||||
ChannelSftp channel = (ChannelSftp)fSessionProvider.getSession().openChannel("sftp"); //$NON-NLS-1$
|
||||
channel.connect();
|
||||
|
@ -954,7 +1080,7 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
getChannel("SftpFileService.getOutputStream " + remoteFile); //check the session is healthy //$NON-NLS-1$
|
||||
ChannelSftp channel = (ChannelSftp)fSessionProvider.getSession().openChannel("sftp"); //$NON-NLS-1$
|
||||
channel.connect();
|
||||
stream = new SftpBufferedOutputStream(channel.put(dst, sftpMonitor, mode), channel);
|
||||
stream = new SftpBufferedOutputStream(channel.put(recodeSafe(dst), sftpMonitor, mode), channel);
|
||||
Activator.trace("SftpFileService.getOutputStream " + remoteFile + " ok"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
@ -966,4 +1092,4 @@ public class SftpFileService extends AbstractFileService implements IFileService
|
|||
}
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
* David Dykstal (IBM) - added RESID_FTP_SETTINGS_LABEL
|
||||
* David McKnight (IBM) - [196632] [ftp] Passive mode setting does not work
|
||||
* Martin Oberhuber (Wind River) - [204669] Fix ftp path concatenation on systems using backslash separator
|
||||
* Martin Oberhuber (Wind River) - [203500] Support encodings for FTP paths
|
||||
********************************************************************************/
|
||||
|
||||
package org.eclipse.rse.internal.subsystems.files.ftp.connectorservice;
|
||||
|
@ -52,6 +53,9 @@ public class FTPConnectorService extends StandardConnectorService
|
|||
{
|
||||
protected FTPService _ftpService;
|
||||
|
||||
/** Indicates the default string encoding on this platform */
|
||||
private static String _defaultEncoding = new java.io.InputStreamReader(new java.io.ByteArrayInputStream(new byte[0])).getEncoding();
|
||||
|
||||
public FTPConnectorService(IHost host, int port)
|
||||
{
|
||||
super(FTPSubsystemResources.RESID_FTP_CONNECTORSERVICE_NAME,FTPSubsystemResources.RESID_FTP_CONNECTORSERVICE_DESCRIPTION, host, port);
|
||||
|
@ -105,11 +109,17 @@ public class FTPConnectorService extends StandardConnectorService
|
|||
_ftpService.setLoggingStream(getLoggingStream(info.getHostname(),getPort()));
|
||||
_ftpService.setPropertySet(propertySet);
|
||||
_ftpService.setFTPClientConfigFactory(FTPClientConfigFactory.getParserFactory());
|
||||
|
||||
//TODO this code should be in IHost
|
||||
String encoding = getHost().getDefaultEncoding(false);
|
||||
if (encoding==null) encoding = getHost().getDefaultEncoding(true);
|
||||
//TODO Here, we set the FTP default encoding same as the local encoding.
|
||||
//Another alternative would be to set ISO-8859-1, which is the
|
||||
//default-default internal to FTP, or keep it "null".
|
||||
if (encoding==null) encoding = _defaultEncoding;
|
||||
//</code to be in IHost>
|
||||
_ftpService.setControlEncoding(encoding);
|
||||
|
||||
_ftpService.connect();
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
@ -163,4 +173,4 @@ public class FTPConnectorService extends StandardConnectorService
|
|||
return (_ftpService != null && _ftpService.isConnected());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue