mina-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From lgoldst...@apache.org
Subject mina-sshd git commit: Fixed SFTP handling of links - symbolic (especially) and hard ones (untested)
Date Sun, 19 Jul 2015 12:58:09 GMT
Repository: mina-sshd
Updated Branches:
  refs/heads/master 318a7ff4f -> 54b56b844


Fixed SFTP handling of links - symbolic (especially) and hard ones (untested)


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/54b56b84
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/54b56b84
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/54b56b84

Branch: refs/heads/master
Commit: 54b56b844bc057c36ef7d8ebebd0df14e8b44fc7
Parents: 318a7ff
Author: Lyor Goldstein <lgoldstein@vmware.com>
Authored: Sun Jul 19 15:57:58 2015 +0300
Committer: Lyor Goldstein <lgoldstein@vmware.com>
Committed: Sun Jul 19 15:57:58 2015 +0300

----------------------------------------------------------------------
 .../subsystem/sftp/SftpFileSystemProvider.java  |   2 +-
 .../file/root/RootedFileSystemProvider.java     |  77 ++++++++-----
 .../sshd/server/subsystem/sftp/SftpHelper.java  |   3 +-
 .../server/subsystem/sftp/SftpSubsystem.java    | 111 +++++++++++++------
 .../subsystem/sftp/SftpFileSystemTest.java      |  24 ++--
 .../sshd/client/subsystem/sftp/SftpTest.java    |  35 ++++--
 6 files changed, 161 insertions(+), 91 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/54b56b84/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemProvider.java
b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemProvider.java
index 9bba23e..87579c5 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemProvider.java
@@ -448,7 +448,7 @@ public class SftpFileSystemProvider extends FileSystemProvider {
         // attributes of source file
         BasicFileAttributes attrs = readAttributes(source, BasicFileAttributes.class, linkOptions);
         if (attrs.isSymbolicLink()) {
-            throw new IOException("Copying of symbolic links not supported");
+            throw new IOException("Moving of source symbolic link not supported: " + source);
         }
 
         // delete target if it exists and REPLACE_EXISTING is specified

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/54b56b84/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
b/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
index 057e112..458667b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
@@ -191,18 +191,32 @@ public class RootedFileSystemProvider extends FileSystemProvider {
 
     @Override
     public void createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs)
throws IOException {
-        Path l = unroot(link);
-        Path t = unroot(target, false);
-        FileSystemProvider p = provider(l);
-        p.createSymbolicLink(l, t, attrs);
+        createLink(link, target, true, attrs);
     }
 
     @Override
     public void createLink(Path link, Path existing) throws IOException {
+        createLink(link, existing, false);
+    }
+
+    protected void createLink(Path link, Path target, boolean symLink, FileAttribute<?>...
attrs) throws IOException {
         Path l = unroot(link);
-        Path e = unroot(existing);
+        Path t = unroot(target);
+        /*
+         * For a symbolic link preserve the relative path
+         */
+        if (symLink && (!target.isAbsolute())) {
+            RootedFileSystem rfs = ((RootedPath) target).getFileSystem();
+            Path root = rfs.getRoot();
+            t = root.relativize(t);
+        }
+
         FileSystemProvider p = provider(l);
-        p.createLink(l, e);
+        if (symLink) {
+            p.createSymbolicLink(l, t, attrs);
+        } else {
+            p.createLink(l, t);
+        }
     }
 
     @Override
@@ -223,7 +237,7 @@ public class RootedFileSystemProvider extends FileSystemProvider {
     public Path readSymbolicLink(Path link) throws IOException {
         Path r = unroot(link);
         FileSystemProvider p = provider(r);
-        return root(link.getFileSystem(), p.readSymbolicLink(r));
+        return root((RootedFileSystem) link.getFileSystem(), p.readSymbolicLink(r));
     }
 
     @Override
@@ -265,7 +279,7 @@ public class RootedFileSystemProvider extends FileSystemProvider {
     }
 
     protected RootedFileSystem getFileSystem(Path path) throws FileSystemNotFoundException
{
-        Path real = unroot(path, false);
+        Path real = unroot(path);
         Path rootInstance = null;
         RootedFileSystem fsInstance = null;
         synchronized (fileSystems) {
@@ -330,13 +344,12 @@ public class RootedFileSystemProvider extends FileSystemProvider {
         p.setAttribute(r, attribute, value, options);
     }
 
-    private static FileSystemProvider provider(Path path) {
+    protected FileSystemProvider provider(Path path) {
         FileSystem fs = path.getFileSystem();
         return fs.provider();
     }
 
-    private static Path root(FileSystem fs, Path nat) {
-        RootedFileSystem rfs = (RootedFileSystem) fs;
+    protected Path root(RootedFileSystem rfs, Path nat) {
         if (nat.isAbsolute()) {
             Path root = rfs.getRoot();
             Path rel = root.relativize(nat);
@@ -346,30 +359,34 @@ public class RootedFileSystemProvider extends FileSystemProvider {
         }
     }
 
-    private static Path unroot(Path path) {
-        return unroot(path, true);
-    }
-
-    private static Path unroot(Path path, boolean absolute) {
+    /**
+     * @param path The original (rooted) {@link Path}
+     * @return The actual <U>absolute <B>local</B></U> {@link Path}
represented
+     * by the rooted one
+     * @see #resolveLocalPath(RootedPath)
+     * @throws IllegalArgumentException if {@code null} path argument
+     * @throws ProviderMismatchException if not a {@link RootedPath}
+     */
+    protected Path unroot(Path path) {
         ValidateUtils.checkNotNull(path, "No path to unroot");
         if (!(path instanceof RootedPath)) {
             throw new ProviderMismatchException("unroot(" + path + ") is not a " + RootedPath.class.getSimpleName()
                     + " but rather a " + path.getClass().getSimpleName());
         }
 
-        RootedPath p = (RootedPath) path;
-        if (absolute || p.isAbsolute()) {
-            Path absPath = p.toAbsolutePath();
-            String r = absPath.toString();
-            RootedFileSystem rfs = p.getFileSystem();
-            Path root = rfs.getRoot();
-            return root.resolve(r.substring(1));
-        } else {
-            RootedPath fileName = p.getFileName();
-            RootedPath root = fileName.getRoot();
-            RootedFileSystem rfs = root.getFileSystem();
-            return rfs.getPath(p.toString());
-        }
+        return resolveLocalPath((RootedPath) path);
+    }
+    
+    /**
+     * @param path The original {@link RootedPath} - never {@code null}
+     * @return The actual <U>absolute <B>local</B></U> {@link Path}
represented
+     * by the rooted one
+     */
+    protected Path resolveLocalPath(RootedPath path) {
+        Path absPath = path.toAbsolutePath();
+        String r = absPath.toString();
+        RootedFileSystem rfs = path.getFileSystem();
+        Path root = rfs.getRoot();
+        return root.resolve(r.substring(1));
     }
-
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/54b56b84/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpHelper.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpHelper.java
b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpHelper.java
index a8a8315..060bb88 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpHelper.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpHelper.java
@@ -125,7 +125,7 @@ import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IXUSR;
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-final class SftpHelper {
+public final class SftpHelper {
     
     private SftpHelper() {
         throw new UnsupportedOperationException("No instance allowed");
@@ -140,6 +140,7 @@ final class SftpHelper {
             throw new IllegalStateException("Unsupported SFTP version: " + version);
         }
     }
+
     public static void writeAttrsV3(Buffer buffer, Map<String, ?> attributes) throws
IOException {
         boolean isReg = getBool((Boolean) attributes.get("isRegularFile"));
         boolean isDir = getBool((Boolean) attributes.get("isDirectory"));

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/54b56b84/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
index 3805b29..fa63181 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
@@ -54,6 +54,7 @@ import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -391,7 +392,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command,
Runna
     public void setFileSystem(FileSystem fileSystem) {
         if (fileSystem != this.fileSystem) {
             this.fileSystem = fileSystem;
-            this.defaultDir = fileSystem.getRootDirectories().iterator().next();
+            
+            Iterable<Path> roots = ValidateUtils.checkNotNull(fileSystem.getRootDirectories(),
"No root directories");
+            Iterator<Path> available = ValidateUtils.checkNotNull(roots.iterator(),
"No roots iterator");
+            ValidateUtils.checkTrue(available.hasNext(), "No available root");
+            this.defaultDir = available.next();
         }
     }
 
@@ -621,17 +626,14 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command,
Runna
     }
 
     protected SpaceAvailableExtensionInfo doSpaceAvailable(int id, String path) throws IOException
{
-        Path file = resolveFile(path);
-        Path abs = file.toAbsolutePath();
-        Path nrm = abs.normalize();
+        Path nrm = resolveNormalizedLocation(path);
         if (log.isDebugEnabled()) {
             log.debug("doSpaceAvailable(id={}) path={}[{}]", id, path, nrm);
         }
 
         FileStore store = Files.getFileStore(nrm);
         if (log.isTraceEnabled()) {
-            log.trace("doSpaceAvailable(id={}) path={}[{}] - {}[{}]",
-                    id, path, nrm, store.name(), store.type());
+            log.trace("doSpaceAvailable(id={}) path={}[{}] - {}[{}]", id, path, nrm, store.name(),
store.type());
         }
 
         return new SpaceAvailableExtensionInfo(store);
@@ -1182,6 +1184,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command,
Runna
         boolean symLink = buffer.getBoolean();
 
         try {
+            if (log.isDebugEnabled()) {
+                log.debug("Received SSH_FXP_LINK id={}, linkpath={}, targetpath={}, symlink={}",
+                          id, linkPath, targetPath, symLink);
+            }
+
             doLink(id, targetPath, linkPath, symLink);
         } catch (IOException | RuntimeException e) {
             sendStatus(BufferUtils.clear(buffer), id, e);
@@ -1192,24 +1199,16 @@ public class SftpSubsystem extends AbstractLoggingBean implements
Command, Runna
     }
 
     protected void doLink(int id, String targetPath, String linkPath, boolean symLink) throws
IOException {
-        if (log.isDebugEnabled()) {
-            log.debug("Received SSH_FXP_LINK (linkpath={}, targetpath={}, symlink={})",
-                    linkPath, targetPath, symLink);
-        }
-
-        Path link = resolveFile(linkPath);
-        Path target = fileSystem.getPath(targetPath);
-        if (symLink) {
-            Files.createSymbolicLink(link, target);
-        } else {
-            Files.createLink(link, target);
-        }
+        createLink(id, targetPath, linkPath, symLink);
     }
 
     protected void doSymLink(Buffer buffer, int id) throws IOException {
         String targetPath = buffer.getString();
         String linkPath = buffer.getString();
         try {
+            if (log.isDebugEnabled()) {
+                log.debug("Received SSH_FXP_SYMLINK id={}, linkpath={}, targetpath={}", id,
targetPath, linkPath);
+            }
             doSymLink(id, targetPath, linkPath);
         } catch (IOException | RuntimeException e) {
             sendStatus(BufferUtils.clear(buffer), id, e);
@@ -1220,16 +1219,31 @@ public class SftpSubsystem extends AbstractLoggingBean implements
Command, Runna
     }
 
     protected void doSymLink(int id, String targetPath, String linkPath) throws IOException
{
-        log.debug("Received SSH_FXP_SYMLINK (linkpath={}, targetpath={})", targetPath, linkPath);
+        createLink(id, targetPath, linkPath, true);
+    }
+
+    protected void createLink(int id, String targetPath, String linkPath, boolean symLink)
throws IOException {
         Path link = resolveFile(linkPath);
         Path target = fileSystem.getPath(targetPath);
-        Files.createSymbolicLink(link, target);
+        if (log.isDebugEnabled()) {
+            log.debug("createLink(id={}), linkpath={}[{}], targetpath={}[{}], symlink={})",
+                      id, linkPath, link, targetPath, target, symLink);
+        }
+
+        if (symLink) {
+            Files.createSymbolicLink(link, target);
+        } else {
+            Files.createLink(link, target);
+        }
     }
 
     protected void doReadLink(Buffer buffer, int id) throws IOException {
         String path = buffer.getString();
         String l;
         try {
+            if (log.isDebugEnabled()) {
+                log.debug("Received SSH_FXP_READLINK id={} path={}", id, path);
+            }
             l = doReadLink(id, path);
         } catch (IOException | RuntimeException e) {
             sendStatus(BufferUtils.clear(buffer), id, e);
@@ -1241,9 +1255,10 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command,
Runna
 
     protected String doReadLink(int id, String path) throws IOException {
         Path f = resolveFile(path);
-        log.debug("Received SSH_FXP_READLINK (path={}[{}])", path, f);
-
         Path t = Files.readSymbolicLink(f);
+        if (log.isDebugEnabled()) {
+            log.debug("doReadLink(id={}) path={}[{}]: {}", id, path, f, t);
+        }
         return t.toString();
     }
 
@@ -1546,8 +1561,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command,
Runna
      * @see IoUtils#checkFileExists(Path, LinkOption...)
      */
     protected Pair<Path, Boolean> validateRealPath(int id, String path, Path f, LinkOption...
options) throws IOException {
-        Path abs = f.toAbsolutePath();
-        Path p = abs.normalize();
+        Path p = normalize(f);
         Boolean status = IoUtils.checkFileExists(p, options);
         return new Pair<>(p, status);
     }
@@ -1718,9 +1732,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command,
Runna
     }
 
     protected String doOpenDir(int id, String path, LinkOption... options) throws IOException
{
-        Path f = resolveFile(path);
-        Path abs = f.toAbsolutePath();
-        Path p = abs.normalize();
+        Path p = resolveNormalizedLocation(path);
         log.debug("Received SSH_FXP_OPENDIR (path={})[{}]", path, p);
 
         Boolean status = IoUtils.checkFileExists(p, options);
@@ -2309,13 +2321,24 @@ public class SftpSubsystem extends AbstractLoggingBean implements
Command, Runna
     }
 
     protected void sendLink(Buffer buffer, int id, String link) throws IOException {
+        //in case we are running on Windows
+        String unixPath = link.replace(File.separatorChar, '/');
         buffer.putByte((byte) SSH_FXP_NAME);
         buffer.putInt(id);
-        buffer.putInt(1);
-        //normalize the given path, use *nix style separator
-        buffer.putString(link);
-        buffer.putString(link);
-        buffer.putInt(0);
+        buffer.putInt(1);   // one response
+
+        buffer.putString(unixPath);
+        if (version == SFTP_V3) {
+            buffer.putString(unixPath);
+        }
+
+        /*
+         * As per the spec:
+         * 
+         *      The server will respond with a SSH_FXP_NAME packet containing only
+         *      one name and a dummy attributes value. 
+         */
+        SftpHelper.writeAttrs(version, buffer, Collections.<String, Object>emptyMap());
         send(buffer);
     }
 
@@ -2442,8 +2465,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command,
Runna
     }
 
     protected String getShortName(Path f) throws IOException {
-        Path abs = f.toAbsolutePath();
-        Path nrm = abs.normalize();
+        Path nrm = normalize(f);
         int  count = nrm.getNameCount();
         /*
          * According to the javadoc:
@@ -2890,13 +2912,30 @@ public class SftpSubsystem extends AbstractLoggingBean implements
Command, Runna
         }
     }
 
+    protected Path resolveNormalizedLocation(String remotePath) throws IOException, InvalidPathException
{
+        return normalize(resolveFile(remotePath));
+    }
+
+    protected Path normalize(Path f) {
+        if (f == null) {
+            return null;
+        }
+
+        Path abs = f.isAbsolute() ? f : f.toAbsolutePath();
+        return abs.normalize();
+    }
+
     protected Path resolveFile(String remotePath) throws IOException, InvalidPathException
{
         // In case double slashes and other patterns are used 
         String path = SelectorUtils.normalizePath(remotePath, "/");
         String localPath = SelectorUtils.translateToLocalPath(path);
 
         // In case we are running on Windows
-        return defaultDir.resolve(localPath);
+        Path p = defaultDir.resolve(localPath);
+        if (log.isTraceEnabled()) {
+            log.trace("resolveFile({}) {}", remotePath, p);
+        }
+        
+        return p;
     }
-
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/54b56b84/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemTest.java
b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemTest.java
index 99777b5..1623d98 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemTest.java
@@ -382,18 +382,18 @@ public class SftpFileSystemTest extends BaseTestSupport {
 //        assertTrue(Files.isSymbolicLink(link));
 //        assertEquals("test.txt", Files.readSymbolicLink(link).toString());
 
-        // TODO there are many issues with symbolic links Windows and Linux - for now they
are of a lesser interest
-//        if (OsUtils.isUNIX()) {
-//            Path link = fs.getPath(remFile2Path);
-//            Path linkParent = link.getParent();
-//            Path relPath = linkParent.relativize(file1);
-//            Files.createSymbolicLink(link, relPath);
-//            assertTrue("Not a symbolic link: " + link, Files.isSymbolicLink(link));
-//
-//            Path symLink = Files.readSymbolicLink(link);
-//            assertEquals("mismatched symbolic link name", relPath.toString(), symLink.toString());
-//            Files.delete(link);
-//        }
+        // TODO there are many issues with symbolic links on Windows
+        if (OsUtils.isUNIX()) {
+            Path link = fs.getPath(remFile2Path);
+            Path linkParent = link.getParent();
+            Path relPath = linkParent.relativize(file1);
+            Files.createSymbolicLink(link, relPath);
+            assertTrue("Not a symbolic link: " + link, Files.isSymbolicLink(link));
+
+            Path symLink = Files.readSymbolicLink(link);
+            assertEquals("mismatched symbolic link name", relPath.toString(), symLink.toString());
+            Files.delete(link);
+        }
 
         attrs = Files.readAttributes(file1, "*", LinkOption.NOFOLLOW_LINKS);
         System.out.append(file1.toString()).append(" no-follow attributes: ").println(attrs);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/54b56b84/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
index 70481de..82e5578 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
@@ -18,6 +18,11 @@
  */
 package org.apache.sshd.client.subsystem.sftp;
 
+import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FX_FILE_ALREADY_EXISTS;
+import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FX_NO_SUCH_FILE;
+import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IRUSR;
+import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IWUSR;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -38,8 +43,6 @@ import java.util.Vector;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import com.jcraft.jsch.ChannelSftp;
-import com.jcraft.jsch.JSch;
 import org.apache.sshd.client.SshClient;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.client.subsystem.sftp.extensions.BuiltinSftpClientExtensions;
@@ -68,10 +71,8 @@ import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runners.MethodSorters;
 
-import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FX_FILE_ALREADY_EXISTS;
-import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FX_NO_SUCH_FILE;
-import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IRUSR;
-import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IWUSR;
+import com.jcraft.jsch.ChannelSftp;
+import com.jcraft.jsch.JSch;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 public class SftpTest extends AbstractSftpClientTestSupport {
@@ -775,7 +776,6 @@ public class SftpTest extends AbstractSftpClientTestSupport {
     }
 
     @Test
-    @Ignore("Symlinks via Java + SFTP pose some issues")
     public void testCreateSymbolicLink() throws Exception {
         // Do not execute on windows as the file system does not support symlinks
         Assume.assumeTrue("Skip non-Unix O/S", OsUtils.isUNIX());
@@ -784,18 +784,31 @@ public class SftpTest extends AbstractSftpClientTestSupport {
         Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(),
getCurrentTestName());
         Utils.deleteRecursive(lclSftp);
 
+        /*
+         * NOTE !!! according to Jsch documentation
+         * (see http://epaul.github.io/jsch-documentation/simple.javadoc/com/jcraft/jsch/ChannelSftp.html#current-directory)
+         * 
+         * 
+         * 		This sftp client has the concept of a current local directory and
+         * 		a current remote directory. These are not inherent to the protocol,
+         *  	but are used implicitly for all path-based commands sent to the server
+         *  	for the remote directory) or accessing the local file system (for the local
directory).
+         *  
+         *  Therefore we are using "absolute" remote files for this test
+         */
         Path parentPath = targetPath.getParent();
         Path sourcePath = assertHierarchyTargetFolderExists(lclSftp).resolve("src.txt");
-        String remSrcPath = Utils.resolveRelativeRemotePath(parentPath, sourcePath);
+        String remSrcPath = "/" + Utils.resolveRelativeRemotePath(parentPath, sourcePath);
         Path linkPath = lclSftp.resolve("link-" + sourcePath.getFileName());
-        String remLinkPath = Utils.resolveRelativeRemotePath(parentPath, linkPath);
+        String remLinkPath = "/" + Utils.resolveRelativeRemotePath(parentPath, linkPath);
 
         String data = getCurrentTestName();
         ChannelSftp c = (ChannelSftp) session.openChannel(SftpConstants.SFTP_SUBSYSTEM_NAME);
         c.connect();
         try {
-            c.put(new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)), remSrcPath);
-
+        	try (InputStream dataStream = new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)))
{
+        		c.put(dataStream, remSrcPath);
+        	}
             assertTrue("Source file not created: " + sourcePath, Files.exists(sourcePath));
             assertEquals("Mismatched stored data in " + remSrcPath, data, readFile(remSrcPath));
 


Mime
View raw message