diff --git a/releng/org.eclipse.rse.updatesite/site.xml b/releng/org.eclipse.rse.updatesite/site.xml
index 1e187ce70f5..e31649a6a55 100644
--- a/releng/org.eclipse.rse.updatesite/site.xml
+++ b/releng/org.eclipse.rse.updatesite/site.xml
@@ -596,7 +596,7 @@
-
+
@@ -608,7 +608,7 @@
-
+
diff --git a/rse/features/org.eclipse.rse.ssh-feature/feature.xml b/rse/features/org.eclipse.rse.ssh-feature/feature.xml
index da7027b2cf6..1db1d4d7903 100644
--- a/rse/features/org.eclipse.rse.ssh-feature/feature.xml
+++ b/rse/features/org.eclipse.rse.ssh-feature/feature.xml
@@ -12,7 +12,7 @@
diff --git a/rse/plugins/org.eclipse.rse.services.ssh/META-INF/MANIFEST.MF b/rse/plugins/org.eclipse.rse.services.ssh/META-INF/MANIFEST.MF
index b27e8d3428b..14c854871b8 100644
--- a/rse/plugins/org.eclipse.rse.services.ssh/META-INF/MANIFEST.MF
+++ b/rse/plugins/org.eclipse.rse.services.ssh/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.rse.services.ssh;singleton:=true
-Bundle-Version: 3.0.0.qualifier
+Bundle-Version: 3.0.1.qualifier
Bundle-Activator: org.eclipse.rse.internal.services.ssh.Activator
Bundle-Vendor: %providerName
Bundle-Localization: plugin
diff --git a/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/internal/services/ssh/files/SftpFileService.java b/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/internal/services/ssh/files/SftpFileService.java
index 91d8a4ea229..90cfddc7139 100644
--- a/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/internal/services/ssh/files/SftpFileService.java
+++ b/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/internal/services/ssh/files/SftpFileService.java
@@ -39,6 +39,7 @@
* David McKnight (IBM) - [271244] [sftp files] "My Home" filter not working
* David McKnight (IBM) - [272882] [api] Handle exceptions in IService.initService()
* Martin Oberhuber (Wind River) - [274568] Dont use SftpMonitor for Streams transfer
+ * Patrick Tassé (Ericsson) - [285226] Empty directory shown as an error message
*******************************************************************************/
package org.eclipse.rse.internal.services.ssh.files;
@@ -87,6 +88,7 @@ import org.eclipse.rse.services.clientserver.messages.SystemMessage;
import org.eclipse.rse.services.clientserver.messages.SystemMessageException;
import org.eclipse.rse.services.clientserver.messages.SystemOperationCancelledException;
import org.eclipse.rse.services.clientserver.messages.SystemOperationFailedException;
+import org.eclipse.rse.services.clientserver.messages.SystemRemoteSecurityException;
import org.eclipse.rse.services.clientserver.messages.SystemUnexpectedErrorException;
import org.eclipse.rse.services.files.AbstractFileService;
import org.eclipse.rse.services.files.HostFilePermissions;
@@ -95,8 +97,8 @@ import org.eclipse.rse.services.files.IFileService;
import org.eclipse.rse.services.files.IHostFile;
import org.eclipse.rse.services.files.IHostFilePermissions;
import org.eclipse.rse.services.files.IHostFilePermissionsContainer;
+import org.eclipse.rse.services.files.RemoteFileException;
import org.eclipse.rse.services.files.RemoteFileIOException;
-import org.eclipse.rse.services.files.RemoteFileSecurityException;
public class SftpFileService extends AbstractFileService implements ISshService, IFilePermissionsService
{
@@ -438,7 +440,7 @@ public class SftpFileService extends AbstractFileService implements ISshService,
SystemMessageException messageException;
SftpException sftpe = (SftpException)e;
if (sftpe.id == ChannelSftp.SSH_FX_PERMISSION_DENIED) {
- messageException = new RemoteFileSecurityException(e);
+ messageException = new SystemRemoteSecurityException(Activator.PLUGIN_ID, e.getLocalizedMessage(), e);
} else if (sftpe.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
//TODO better throw SENFE at the place where we know what element and operation is done
messageException = new SystemElementNotFoundException("", ""); //$NON-NLS-1$ //$NON-NLS-2$
@@ -548,6 +550,15 @@ public class SftpFileService extends AbstractFileService implements ISshService,
//don't show the trivial names
continue;
}
+ if (vv.size() == 1 && fileName.equals(parentPath.substring(parentPath.lastIndexOf('/') + 1))) {
+ //If there is only one entry and it has the same name as the parent path, the parentPath could be a file.
+ //Check if the parentPath is a directory.
+ SftpATTRS attrs = getChannel("SftpFileService.internalFetch: " + parentPath).stat(parentPath); //$NON-NLS-1$
+ if (!attrs.isDir()) {
+ // parent was a file and not a folder
+ throw new RemoteFileException("Not a folder: " + parentPath); //$NON-NLS-1$
+ }
+ }
if (filematcher.matches(fileName) || (lsEntry.getAttrs().isDir() && fileType!=IFileService.FILE_TYPE_FOLDERS)) {
//get ALL directory names (unless looking for folders only)
SftpHostFile node = makeHostFile(parentPath, fileName, lsEntry.getAttrs());
@@ -560,6 +571,22 @@ public class SftpFileService extends AbstractFileService implements ISshService,
}
Activator.trace("SftpFileService.internalFetch <--"); //$NON-NLS-1$
} catch(Exception e) {
+ if ( (e instanceof SftpException) && ((SftpException)e).id==ChannelSftp.SSH_FX_NO_SUCH_FILE) {
+ //We can get a "2: No such file" exception when the directory is empty.
+ try {
+ // Check if the parentPath exists and is a folder
+ SftpATTRS attrs = getChannel("SftpFileService.internalFetch: " + parentPath).stat(parentPath); //$NON-NLS-1$
+ if (attrs.isDir()) {
+ // We MUST NOT throw an exception here. Just return
+ // an empty IHostFile array.
+ return new IHostFile[0];
+ }
+ // else, fall through to exception handling -- will send
+ // SystemRemoteFileIOException
+ } catch (Exception ee) {
+ //Can't get the folder attributes so let the first exception be handled.
+ }
+ }
//TODO throw new SystemMessageException.
//We get a "2: No such file" exception when we try to get contents
//of a symbolic link that turns out to point to a file rather than
@@ -881,7 +908,7 @@ public class SftpFileService extends AbstractFileService implements ISshService,
public IHostFile[] getRoots(IProgressMonitor monitor) {
IHostFile root = null;
try {
- root = getFile(null, "/", monitor);
+ root = getFile(null, "/", monitor); //$NON-NLS-1$
}
catch (SystemMessageException e){
}
@@ -957,7 +984,7 @@ public class SftpFileService extends AbstractFileService implements ISshService,
try {
getChannel("SftpFileService.delete.rm").rm(fullPathRecoded); //$NON-NLS-1$
} catch (Exception e2) {
- throw new SystemElementNotFoundException(Activator.PLUGIN_ID, fullPath, "delete");
+ throw new SystemElementNotFoundException(Activator.PLUGIN_ID, fullPath, "delete"); //$NON-NLS-1$
}
} else {
//Security exception, or similar: will be wrapped in makeSystemMessageException()
@@ -1184,7 +1211,7 @@ public class SftpFileService extends AbstractFileService implements ISshService,
} catch (Exception e) {
Activator.trace("SftpFileService.setReadOnly "+path+" failed: "+e.toString()); //$NON-NLS-1$ //$NON-NLS-2$
if ((e instanceof SftpException) && ((SftpException) e).id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
- throw new SystemElementNotFoundException(Activator.PLUGIN_ID, path, "setReadOnly");
+ throw new SystemElementNotFoundException(Activator.PLUGIN_ID, path, "setReadOnly"); //$NON-NLS-1$
}
throw makeSystemMessageException(e);
} finally {
@@ -1298,7 +1325,7 @@ public class SftpFileService extends AbstractFileService implements ISshService,
} catch (Exception e) {
Activator.trace("SftpFileService.setFilePermissions " + path + " failed: " + e.toString()); //$NON-NLS-1$ //$NON-NLS-2$
if ((e instanceof SftpException) && ((SftpException) e).id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
- throw new SystemElementNotFoundException(Activator.PLUGIN_ID, path, "setFilePermissions");
+ throw new SystemElementNotFoundException(Activator.PLUGIN_ID, path, "setFilePermissions"); //$NON-NLS-1$
}
throw makeSystemMessageException(e);
} finally {
diff --git a/rse/tests/org.eclipse.rse.tests-feature/feature.xml b/rse/tests/org.eclipse.rse.tests-feature/feature.xml
index c79f9473ac1..83ce051c1e2 100644
--- a/rse/tests/org.eclipse.rse.tests-feature/feature.xml
+++ b/rse/tests/org.eclipse.rse.tests-feature/feature.xml
@@ -12,7 +12,7 @@
diff --git a/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/subsystems/files/FileServiceTest.java b/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/subsystems/files/FileServiceTest.java
index 5c9995e4ebf..de0a6f95627 100644
--- a/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/subsystems/files/FileServiceTest.java
+++ b/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/subsystems/files/FileServiceTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2008 Wind River Systems, Inc. and others.
+ * Copyright (c) 2006, 2009 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -12,6 +12,7 @@
* Martin Oberhuber (Wind River) - [186640] Add IRSESystemType.testProperty()
* Martin Oberhuber (Wind River) - organize, enable and tag test cases
* Martin Oberhuber (Wind River) - [235360][ftp][ssh] Return proper "Root" IHostFile
+ * Patrick Tassé (Ericsson) - [285226] Empty directory shown as an error message
*******************************************************************************/
package org.eclipse.rse.tests.subsystems.files;
@@ -24,13 +25,22 @@ import junit.framework.TestSuite;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.rse.core.model.IHost;
+import org.eclipse.rse.core.subsystems.ISubSystem;
+import org.eclipse.rse.services.IService;
+import org.eclipse.rse.services.clientserver.PathUtility;
+import org.eclipse.rse.services.clientserver.messages.SystemElementNotFoundException;
import org.eclipse.rse.services.clientserver.messages.SystemMessageException;
import org.eclipse.rse.services.files.IFileService;
import org.eclipse.rse.services.files.IHostFile;
+import org.eclipse.rse.services.files.RemoteFileException;
+import org.eclipse.rse.services.shells.IHostOutput;
+import org.eclipse.rse.services.shells.IHostShell;
+import org.eclipse.rse.services.shells.IShellService;
import org.eclipse.rse.subsystems.files.core.model.RemoteFileUtility;
import org.eclipse.rse.subsystems.files.core.servicesubsystem.IFileServiceSubSystem;
import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFile;
import org.eclipse.rse.tests.core.connection.RSEBaseConnectionTestCase;
+import org.eclipse.rse.tests.subsystems.shells.ShellOutputListener;
public class FileServiceTest extends RSEBaseConnectionTestCase {
@@ -75,7 +85,8 @@ public class FileServiceTest extends RSEBaseConnectionTestCase {
TestSuite suite = new TestSuite(baseName);
// // Add a test suite for each connection type
- String[] connTypes = { "local", "ssh", "ftpWindows", "ftp", "linux", "windows" };
+ String[] connTypes = { "local", "ssh", "ftpWindows", "ftpSsh", "linux", "windows", "unix" };
+ //String[] connTypes = { "unix" };
//String[] connTypes = { "local" };
// String[] connTypes = { "ssh" };
@@ -121,7 +132,12 @@ public class FileServiceTest extends RSEBaseConnectionTestCase {
//Return a filename for testing that exposes all characters valid on the file system
if (!isWindows()) {
//UNIX TODO: test embedded newlines
- return "a !@#${a}\"\' fi\tle\b\\%^&*()?_ =[]~+-'`;:,.|<>"; //$NON-NLS-1$
+ String testName = "a !@#${a}\"\' fi\tle\b\\%^&*()?_ =[]~+-'`;:,.|<>"; //$NON-NLS-1$
+ // Bug 235492: DStore is designed to treat '\' and '/' the same way, so do not
+ // test this.
+ if (fss.getSubSystemConfiguration().getServiceImplType().getName().equals("org.eclipse.rse.services.dstore.IDStoreService")) { //$NON-NLS-1$
+ testName.replace('\\', ' ');
+ }
}
//Fallback: Windows TODO: test unicode
//Note: The trailing dot ('.') is really unfair on Windows because the file
@@ -130,6 +146,32 @@ public class FileServiceTest extends RSEBaseConnectionTestCase {
return "a !@#${a}'` file%^&()_ =[]~+-;.,"; //$NON-NLS-1$
}
+ /**
+ * Find the first IShellServiceSubSystem service associated with the host.
+ *
+ * @return shell service subsystem, or null
if not found.
+ */
+ public IShellService getRelatedShellService() {
+ IHost host = fss.getHost();
+ ISubSystem[] subSystems = host.getSubSystems();
+ IShellService ssvc = null;
+ for (int i = 0; subSystems != null && i < subSystems.length; i++) {
+ IService svc = subSystems[i].getSubSystemConfiguration().getService(host);
+ if (svc != null) {
+ ssvc = (IShellService) svc.getAdapter(IShellService.class);
+ if (ssvc != null) {
+ try {
+ subSystems[i].checkIsConnected(getDefaultProgressMonitor());
+ return ssvc;
+ } catch (SystemMessageException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ return null;
+ }
+
public void testGetRootProperties() throws Exception {
//-test-author-:MartinOberhuber
if (isTestDisabled()) return;
@@ -139,11 +181,10 @@ public class FileServiceTest extends RSEBaseConnectionTestCase {
for (int i = 0; i < roots.length; i++) {
assertTrue(roots[i].isRoot());
assertTrue(roots[i].exists());
- assertNull(roots[i].getParentPath()); //dstore: bug 235471
+ assertNull(roots[i].getParentPath());
String rootName = roots[i].getName();
assertNotNull(rootName);
System.out.println(rootName);
- // DStore: NPE, bug 240710
IHostFile newHf = fs.getFile(null, rootName, new NullProgressMonitor());
assertTrue(newHf.isRoot());
assertTrue(newHf.exists());
@@ -175,7 +216,7 @@ public class FileServiceTest extends RSEBaseConnectionTestCase {
if (isTestDisabled()) return;
String testName = getTestFileName();
- IHostFile hf = fs.createFile(tempDirPath, testName, mon); //dstore-linux: bug 235492
+ IHostFile hf = fs.createFile(tempDirPath, testName, mon);
assertTrue(hf.exists());
assertTrue(hf.canRead());
assertTrue(hf.canWrite());
@@ -231,4 +272,162 @@ public class FileServiceTest extends RSEBaseConnectionTestCase {
}
}
+ public String[] runRemoteCommand(IShellService shellService, String workingDirectory, String cmd) throws SystemMessageException, InterruptedException {
+ IHostShell hostShell = null;
+ hostShell = shellService.runCommand(workingDirectory, cmd, null, mon);
+ ShellOutputListener outputListener = new ShellOutputListener();
+ hostShell.addOutputListener(outputListener);
+ hostShell.writeToShell("exit");
+ assertNotNull(hostShell);
+ assertNotNull(hostShell.getStandardOutputReader());
+ while (hostShell.isActive()) {
+ Thread.sleep(1000);
+ }
+ Object[] allOutput = outputListener.getAllOutput();
+ if (allOutput!=null) {
+ String[] sOutput = new String[allOutput.length];
+ for (int i = 0; i < allOutput.length; i++) {
+ if (allOutput[i] instanceof IHostOutput) {
+ sOutput[i] = ((IHostOutput) allOutput[i]).getString();
+ } else {
+ sOutput[i] = allOutput[i].toString();
+ }
+ }
+ return sOutput;
+ }
+ return null;
+ }
+
+ /**
+ * Create a symbolic link in the context of tempDirPath.
+ *
+ * @param source source file to link from
+ * @param target target file to link to
+ * @return true
if link was successfully created.
+ */
+ public boolean mkSymLink(String source, String target) {
+ if (!fss.getHost().getSystemType().isWindows()) {
+ IShellService ss = getRelatedShellService();
+ if (ss != null) {
+ String[] allOutput;
+ try {
+ String src = PathUtility.enQuoteUnix(source);
+ String tgt = PathUtility.enQuoteUnix(target);
+ String cmd = "ln -s " + src + " " + tgt;
+ allOutput = runRemoteCommand(ss, tempDirPath, cmd);
+ IHostFile hf = fs.getFile(tempDirPath, target, mon);
+ if (hf.exists()) {
+ return true;
+ }
+ allOutput = new String[] { "Failed to symlink: " + cmd };
+ } catch (Exception e) {
+ allOutput = new String[] { "Exception thrown: " + e };
+ }
+ System.out.println("WARNING: Could not create symlink");
+ if (allOutput != null) {
+ for (int i = 0; i < allOutput.length; i++) {
+ System.out.println(allOutput[i]);
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public void testListEmptyFolder() throws SystemMessageException {
+ // -test-author-:PatrickTassé
+ if (isTestDisabled()) return;
+
+ String testName = "empty";
+ IHostFile hf = fs.createFolder(tempDirPath, testName, mon);
+ assertTrue(hf.exists());
+ assertTrue(hf.isDirectory());
+ assertTrue(hf.canRead());
+ assertTrue(hf.canWrite());
+ assertEquals(testName, hf.getName());
+ assertEquals(tempDirPath, hf.getParentPath());
+ long modDate = hf.getModifiedDate();
+ assertTrue(modDate > 0);
+ if (fss.getHost().getSystemType().isLocal()) {
+ File theFile = new File(remoteTempDir.getAbsolutePath(), testName);
+ assertTrue(theFile.exists());
+ assertTrue(modDate == theFile.lastModified());
+ }
+ IHostFile[] hfa = fs.list(hf.getAbsolutePath(), "*", IFileService.FILE_TYPE_FILES_AND_FOLDERS, mon);
+ assertEquals(0, hfa.length);
+ // check for symlink-to-empty-folder case
+ if (mkSymLink(testName, "lto" + testName)) {
+ IHostFile hf2 = fs.getFile(tempDirPath, "lto" + testName, mon);
+ assertTrue(hf2.isDirectory());
+ hfa = fs.list(hf2.getAbsolutePath(), "*", IFileService.FILE_TYPE_FILES_AND_FOLDERS, mon);
+ assertEquals(0, hfa.length);
+ }
+ }
+
+ public void testListNonExistentFolder() throws SystemMessageException, InterruptedException {
+ // -test-author-:PatrickTassé
+ if (isTestDisabled()) return;
+
+ String testPath = tempDirPath + "/non/existent";
+ try {
+ IHostFile[] hfa = fs.list(testPath, "*", IFileService.FILE_TYPE_FILES_AND_FOLDERS, mon);
+ // Bug 285942: LocalFileService and DStoreFileService return empty array today
+ // Assert something impossible since an exception is expected
+ assertEquals("Exception expected on list nonexistent", -1, hfa.length);
+ } catch (SystemMessageException e) {
+ assertTrue(e instanceof SystemElementNotFoundException);
+ }
+ // check for symlink-to-non-existent case
+ if (mkSymLink("non/existent", "ltononex")) {
+ IHostFile hf2 = fs.getFile(tempDirPath, "ltononex", mon);
+ try {
+ IHostFile[] hfa = fs.list(hf2.getAbsolutePath(), "*", IFileService.FILE_TYPE_FILES_AND_FOLDERS, mon);
+ assertEquals("Exception expected on list broken symlink", -1, hfa.length);
+ } catch (SystemMessageException e) {
+ assertTrue(e instanceof SystemElementNotFoundException);
+ }
+ }
+ }
+
+ public void testListNotAFolder() throws SystemMessageException {
+ // -test-author-:PatrickTassé
+ if (isTestDisabled()) return;
+
+ String testName = getTestFileName();
+ IHostFile hf = fs.createFile(tempDirPath, testName, mon);
+ assertTrue(hf.exists());
+ assertTrue(hf.canRead());
+ assertTrue(hf.canWrite());
+ assertEquals(hf.getName(), testName);
+ assertEquals(hf.getParentPath(), tempDirPath);
+ assertEquals(hf.getSize(), 0);
+ long modDate = hf.getModifiedDate();
+ assertTrue(modDate > 0);
+ if (fss.getHost().getSystemType().isLocal()) {
+ File theFile = new File(remoteTempDir.getAbsolutePath(), testName);
+ assertTrue(theFile.exists());
+ assertTrue(modDate == theFile.lastModified());
+ }
+ try {
+ IHostFile[] hfa = fs.list(hf.getAbsolutePath(), "*", IFileService.FILE_TYPE_FILES_AND_FOLDERS, mon);
+ // Bug 285942: LocalFileService and DStoreFileService return empty array today
+ // Assert something impossible since an exception is expected
+ assertEquals("Exception expected on list not-a-folder", -1, hfa.length);
+ } catch (SystemMessageException e) {
+ assertTrue(e instanceof RemoteFileException);
+ }
+ // check for symlink-to-not-a-folder case
+ if (mkSymLink(testName, "lto" + testName)) {
+ try {
+ IHostFile hf2 = fs.getFile(tempDirPath, "lto" + testName, mon);
+ assertTrue(hf2.isFile());
+ IHostFile[] hfa = fs.list(hf2.getAbsolutePath(), "*", IFileService.FILE_TYPE_FILES_AND_FOLDERS, mon);
+ // Assert something impossible since an exception is expected
+ assertEquals("Exception expected on list symlink-to-folder", -1, hfa.length);
+ } catch (SystemMessageException e) {
+ assertTrue(e instanceof RemoteFileException);
+ }
+ }
+ }
+
}