You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2015/07/27 09:39:44 UTC
mina-sshd git commit: [SSHD-544] Take into account target file system
separator when resolving "local" paths
Repository: mina-sshd
Updated Branches:
refs/heads/master 8b9024e4d -> 622889259
[SSHD-544] Take into account target file system separator when resolving "local" paths
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/62288925
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/62288925
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/62288925
Branch: refs/heads/master
Commit: 62288925936ce7f0e6d1744e92af2d53a54db3f6
Parents: 8b9024e
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Mon Jul 27 10:39:33 2015 +0300
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Mon Jul 27 10:39:33 2015 +0300
----------------------------------------------------------------------
.../sshd/common/file/util/BaseFileSystem.java | 4 +-
.../apache/sshd/common/file/util/BasePath.java | 26 +++---
.../org/apache/sshd/common/scp/ScpHelper.java | 8 +-
.../apache/sshd/common/util/SelectorUtils.java | 88 ++++++++++++++++++++
.../server/subsystem/sftp/SftpSubsystem.java | 7 +-
.../subsystem/sftp/SftpFileSystemTest.java | 4 +-
.../sshd/client/subsystem/sftp/SftpTest.java | 2 +-
.../sshd/common/util/SelectorUtilsTest.java | 59 +++++++++----
8 files changed, 157 insertions(+), 41 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/62288925/sshd-core/src/main/java/org/apache/sshd/common/file/util/BaseFileSystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/file/util/BaseFileSystem.java b/sshd-core/src/main/java/org/apache/sshd/common/file/util/BaseFileSystem.java
index 386df6f..4c4a0df 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/file/util/BaseFileSystem.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/file/util/BaseFileSystem.java
@@ -101,7 +101,7 @@ public abstract class BaseFileSystem<T extends Path> extends FileSystem {
return create(root, names);
}
- private void appendDedupSep(StringBuilder sb, String s) {
+ protected void appendDedupSep(StringBuilder sb, CharSequence s) {
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if ((ch != '/') || (sb.length() == 0) || (sb.charAt(sb.length() - 1) != '/')) {
@@ -140,7 +140,7 @@ public abstract class BaseFileSystem<T extends Path> extends FileSystem {
};
}
- private String globToRegex(String pattern) {
+ protected String globToRegex(String pattern) {
StringBuilder sb = new StringBuilder(pattern.length());
int inGroup = 0;
int inClass = 0;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/62288925/sshd-core/src/main/java/org/apache/sshd/common/file/util/BasePath.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/file/util/BasePath.java b/sshd-core/src/main/java/org/apache/sshd/common/file/util/BasePath.java
index 3a795da..a7e6dad 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/file/util/BasePath.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/file/util/BasePath.java
@@ -42,12 +42,12 @@ import org.apache.sshd.common.util.ValidateUtils;
public abstract class BasePath<T extends BasePath<T, FS>, FS extends BaseFileSystem<T>> implements Path {
- protected final FS fileSystem;
protected final String root;
protected final ImmutableList<String> names;
+ private final FS fileSystem;
public BasePath(FS fileSystem, String root, ImmutableList<String> names) {
- this.fileSystem = fileSystem;
+ this.fileSystem = ValidateUtils.checkNotNull(fileSystem, "No file system provided");
this.root = root;
this.names = names;
}
@@ -126,7 +126,7 @@ public abstract class BasePath<T extends BasePath<T, FS>, FS extends BaseFileSys
return create(null, names.subList(beginIndex, endIndex));
}
- private static boolean startsWith(List<?> list, List<?> other) {
+ protected boolean startsWith(List<?> list, List<?> other) {
return list.size() >= other.size() && list.subList(0, other.size()).equals(other);
}
@@ -144,7 +144,7 @@ public abstract class BasePath<T extends BasePath<T, FS>, FS extends BaseFileSys
return startsWith(getFileSystem().getPath(other));
}
- private static boolean endsWith(List<?> list, List<?> other) {
+ protected boolean endsWith(List<?> list, List<?> other) {
return other.size() <= list.size() && list.subList(list.size() - other.size(), list.size()).equals(other);
}
@@ -163,7 +163,7 @@ public abstract class BasePath<T extends BasePath<T, FS>, FS extends BaseFileSys
return endsWith(getFileSystem().getPath(other));
}
- private boolean isNormal() {
+ protected boolean isNormal() {
int count = getNameCount();
if ((count == 0) || ((count == 1) && !isAbsolute())) {
return true;
@@ -346,7 +346,7 @@ public abstract class BasePath<T extends BasePath<T, FS>, FS extends BaseFileSys
return p1.names.size() - p2.names.size();
}
- private int compare(String s1, String s2) {
+ protected int compare(String s1, String s2) {
if (s1 == null) {
return s2 == null ? 0 : -1;
} else {
@@ -355,7 +355,7 @@ public abstract class BasePath<T extends BasePath<T, FS>, FS extends BaseFileSys
}
@SuppressWarnings("unchecked")
- private T checkPath(Path paramPath) {
+ protected T checkPath(Path paramPath) {
ValidateUtils.checkNotNull(paramPath, "Missing path argument");
if (paramPath.getClass() != getClass()) {
throw new ProviderMismatchException("Path is not of this class: " + paramPath + "[" + paramPath.getClass().getSimpleName() + "]");
@@ -371,11 +371,11 @@ public abstract class BasePath<T extends BasePath<T, FS>, FS extends BaseFileSys
@Override
public int hashCode() {
- int hash = getFileSystem().hashCode();
+ int hash = Objects.hashCode(getFileSystem());
// use hash codes from toString() form of names
- hash = 31 * hash + (root == null ? 0 : root.hashCode());
+ hash = 31 * hash + Objects.hashCode(root);
for (String name : names) {
- hash = 31 * hash + name.hashCode();
+ hash = 31 * hash + Objects.hashCode(name);
}
return hash;
}
@@ -392,9 +392,11 @@ public abstract class BasePath<T extends BasePath<T, FS>, FS extends BaseFileSys
if (root != null) {
sb.append(root);
}
+
+ String separator = getFileSystem().getSeparator();
for (String name : names) {
- if (sb.length() > 0 && sb.charAt(sb.length() - 1) != '/') {
- sb.append(fileSystem.getSeparator());
+ if ((sb.length() > 0) && (sb.charAt(sb.length() - 1) != '/')) {
+ sb.append(separator);
}
sb.append(name);
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/62288925/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java b/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java
index 0829d69..276f5ed 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java
@@ -482,16 +482,14 @@ public class ScpHelper extends AbstractLoggingBean {
}
/**
- * @param commandPath The original command path using <U>local</U> separator
+ * @param commandPath The command path using the <U>local</U> file separator
* @return The resolved absolute and normalized local path {@link Path}
* @throws IOException If failed to resolve the path
* @throws InvalidPathException If invalid local path value
*/
public Path resolveLocalPath(String commandPath) throws IOException, InvalidPathException {
- // In case double slashes and other patterns are used
- String path = SelectorUtils.applySlashifyRules(commandPath, File.separatorChar);
- String localPath = SelectorUtils.translateToLocalPath(path);
- Path lcl = fileSystem.getPath(localPath);
+ String path = SelectorUtils.translateToLocalFileSystemPath(commandPath, File.separatorChar, fileSystem);
+ Path lcl = fileSystem.getPath(path);
Path abs = lcl.isAbsolute() ? lcl : lcl.toAbsolutePath();
Path p = abs.normalize();
if (log.isTraceEnabled()) {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/62288925/sshd-core/src/main/java/org/apache/sshd/common/util/SelectorUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/SelectorUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/SelectorUtils.java
index 00af8b2..e7319c8 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/SelectorUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/SelectorUtils.java
@@ -20,8 +20,10 @@ package org.apache.sshd.common.util;
import java.io.File;
import java.io.IOException;
+import java.nio.file.FileSystem;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.StringTokenizer;
/**
@@ -593,6 +595,42 @@ public final class SelectorUtils {
}
/**
+ * Converts a path to one matching the target file system by applying the
+ * "slashification" rules, converting it to a local path and
+ * then translating its separator to the target file system one (if different
+ * than local one)
+ * @param path The input path
+ * @param pathSeparator The separator used to build the input path
+ * @param fs The target {@link FileSystem} - may not be {@code null}
+ * @return The transformed path
+ * @see #translateToLocalFileSystemPath(String, char, String)
+ */
+ public static String translateToLocalFileSystemPath(String path, char pathSeparator, FileSystem fs) {
+ return translateToLocalFileSystemPath(path, pathSeparator, ValidateUtils.checkNotNull(fs, "No target file system").getSeparator());
+ }
+
+ /**
+ * Converts a path to one matching the target file system by applying the
+ * "slashification" rules, converting it to a local path and
+ * then translating its separator to the target file system one (if different
+ * than local one)
+ * @param path The input path
+ * @param pathSeparator The separator used to build the input path
+ * @param fsSeparator The target file system separator
+ * @return The transformed path
+ * @see #applySlashifyRules(String, char)
+ * @see #translateToLocalPath(String)
+ * @see #translateToFileSystemPath(String, String, String)
+ */
+ public static String translateToLocalFileSystemPath(String path, char pathSeparator, String fsSeparator) {
+ // In case double slashes and other patterns are used
+ String slashified = applySlashifyRules(path, pathSeparator);
+ // In case we are running on Windows
+ String localPath = translateToLocalPath(slashified);
+ return translateToFileSystemPath(localPath, File.separator, fsSeparator);
+ }
+
+ /**
* Applies the "slashification" rules as specified in
* <A HREF="http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_266">Single Unix Specification version 3, section 3.266</A>
* and <A HREF="http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_11">section 4.11 - Pathname resolution</A>
@@ -727,6 +765,56 @@ public final class SelectorUtils {
}
/**
+ * Converts a path containing a specific separator to one using the
+ * specified file-system one
+ * @param path The input path - ignored if {@code null}/empty
+ * @param pathSeparator The separator used to build the input path - may not
+ * be {@code null}/empty
+ * @param fs The target {@link FileSystem} - may not be {@code null}
+ * @return The path where the separator used to build it is replaced by
+ * the file-system one (if different)
+ * @see FileSystem#getSeparator()
+ * @see #translateToFileSystemPath(String, String, String)
+ */
+ public static String translateToFileSystemPath(String path, String pathSeparator, FileSystem fs) {
+ return translateToFileSystemPath(path, pathSeparator, ValidateUtils.checkNotNull(fs, "No target file system").getSeparator());
+ }
+
+ /**
+ * Converts a path containing a specific separator to one using the
+ * specified file-system one
+ * @param path The input path - ignored if {@code null}/empty
+ * @param pathSeparator The separator used to build the input path - may not
+ * be {@code null}/empty
+ * @param fsSeparator The target file system separator - may not be {@code null}/empty
+ * @return The path where the separator used to build it is replaced by
+ * the file-system one (if different)
+ * @throws IllegalArgumentException if path or file-system separator are {@code null}/empty
+ * or if the separators are different and the path contains the target
+ * file-system separator as it would create an ambiguity
+ */
+ public static String translateToFileSystemPath(String path, String pathSeparator, String fsSeparator) {
+ ValidateUtils.checkNotNullAndNotEmpty(pathSeparator, "Missing path separator");
+ ValidateUtils.checkNotNullAndNotEmpty(fsSeparator, "Missing file-system separator");
+
+ if (GenericUtils.isEmpty(path) || Objects.equals(pathSeparator, fsSeparator)) {
+ return path;
+ }
+
+ // make sure path does not contain the target separator
+ if (path.indexOf(fsSeparator) >= 0) {
+ ValidateUtils.throwIllegalArgumentException("File system replacement may yield ambiguous result for %s with separator=%s", path, fsSeparator);
+ }
+
+ // check most likely case
+ if ((pathSeparator.length() == 1) && (fsSeparator.length() == 1)) {
+ return path.replace(pathSeparator.charAt(0), fsSeparator.charAt(0));
+ } else {
+ return path.replace(pathSeparator, fsSeparator);
+ }
+ }
+
+ /**
* Returns dependency information on these two files. If src has been
* modified later than target, it returns true. If target doesn't exist,
* it likewise returns true. Otherwise, target is newer than src and
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/62288925/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 1160d57..54acc9a 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
@@ -2932,11 +2932,8 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
* @throws InvalidPathException If bad local path specification
*/
protected Path resolveFile(String remotePath) throws IOException, InvalidPathException {
- // In case double slashes and other patterns are used
- String path = SelectorUtils.applySlashifyRules(remotePath, '/');
- // In case we are running on Windows
- String localPath = SelectorUtils.translateToLocalPath(path);
- Path p = defaultDir.resolve(localPath);
+ String path = SelectorUtils.translateToLocalFileSystemPath(remotePath, '/', defaultDir.getFileSystem());
+ Path p = defaultDir.resolve(path);
if (log.isTraceEnabled()) {
log.trace("resolveFile({}) {}", remotePath, p);
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/62288925/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 1623d98..7578df5 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
@@ -374,7 +374,7 @@ public class SftpFileSystemTest extends BaseTestSupport {
Files.move(file2, file1);
Map<String, Object> attrs = Files.readAttributes(file1, "*");
- System.out.append(file1.toString()).append(" attributes: ").println(attrs);
+ System.out.append('\t').append(file1.toString()).append(" attributes: ").println(attrs);
// TODO: symbolic links only work for absolute files
// Path link = fs.getPath("target/sftp/client/test2.txt");
@@ -396,7 +396,7 @@ public class SftpFileSystemTest extends BaseTestSupport {
}
attrs = Files.readAttributes(file1, "*", LinkOption.NOFOLLOW_LINKS);
- System.out.append(file1.toString()).append(" no-follow attributes: ").println(attrs);
+ System.out.append('\t').append(file1.toString()).append(" no-follow attributes: ").println(attrs);
assertEquals("Mismatched symlink data", expected, new String(Files.readAllBytes(file1)));
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/62288925/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 e7af9ee..c5fb7c4 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
@@ -537,7 +537,7 @@ public class SftpTest extends AbstractSftpClientTestSupport {
path = path.replace('\\', '/');
Vector<?> res = c.ls(path);
for (Object f : res) {
- System.out.println(f.toString());
+ System.out.append('\t').println(f.toString());
}
} finally {
c.disconnect();
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/62288925/sshd-core/src/test/java/org/apache/sshd/common/util/SelectorUtilsTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/util/SelectorUtilsTest.java b/sshd-core/src/test/java/org/apache/sshd/common/util/SelectorUtilsTest.java
index 82d6367..4b557f5 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/util/SelectorUtilsTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/util/SelectorUtilsTest.java
@@ -18,6 +18,7 @@
*/
package org.apache.sshd.common.util;
+import java.io.File;
import java.util.Random;
import org.apache.sshd.util.BaseTestSupport;
@@ -35,12 +36,23 @@ public class SelectorUtilsTest extends BaseTestSupport {
}
@Test
- public void testApplySlashifyRules() {
+ public void testApplyLinuxSeparatorSlashifyRules() {
+ testApplySlashifyRules('/');
+ }
+
+ @Test
+ public void testApplyWindowsSeparatorSlashifyRules() {
+ testApplySlashifyRules('\\');
+ }
+
+ private void testApplySlashifyRules(char slash) {
for (String expected : new String[] {
- null, "", getCurrentTestName(), getClass().getSimpleName() + "/" + getCurrentTestName(),
- "/" + getClass().getSimpleName(), "/" + getClass().getSimpleName() + "/" + getCurrentTestName()
+ null, "", getCurrentTestName(),
+ getClass().getSimpleName() + String.valueOf(slash) + getCurrentTestName(),
+ String.valueOf(slash) + getClass().getSimpleName(),
+ String.valueOf(slash) + getClass().getSimpleName() + String.valueOf(slash) + getCurrentTestName()
}) {
- String actual = SelectorUtils.applySlashifyRules(expected, '/');
+ String actual = SelectorUtils.applySlashifyRules(expected, slash);
assertSame("Mismatched results for '" + expected + "'", expected, actual);
}
@@ -54,49 +66,68 @@ public class SelectorUtilsTest extends BaseTestSupport {
boolean prepend = rnd.nextBoolean();
if (prepend) {
- slashify(sb, rnd);
+ slashify(sb, rnd, slash);
}
sb.append(comps[0]);
for (int j = 1; j < comps.length; j++) {
- slashify(sb, rnd);
+ slashify(sb, rnd, slash);
sb.append(comps[j]);
}
boolean append = rnd.nextBoolean();
if (append) {
- slashify(sb, rnd);
+ slashify(sb, rnd, slash);
}
String path = sb.toString();
sb.setLength(0);
if (prepend) {
- sb.append('/');
+ sb.append(slash);
}
sb.append(comps[0]);
for (int j = 1; j < comps.length; j++) {
- sb.append('/').append(comps[j]);
+ sb.append(slash).append(comps[j]);
}
if (append) {
- sb.append('/').append('.');
+ sb.append(slash).append('.');
}
String expected = sb.toString();
- String actual = SelectorUtils.applySlashifyRules(path, '/');
+ String actual = SelectorUtils.applySlashifyRules(path, slash);
assertEquals("Mismatched results for path=" + path, expected, actual);
}
}
-
- private static int slashify(StringBuilder sb, Random rnd) {
+ private static int slashify(StringBuilder sb, Random rnd, char slash) {
int slashes = 1 /* at least one slash */ + rnd.nextInt(Byte.SIZE);
for (int k = 0; k < slashes; k++) {
- sb.append('/');
+ sb.append(slash);
}
return slashes;
}
+ @Test
+ public void testTranslateToFileSystemPath() {
+ String path = getClass().getPackage().getName().replace('.', File.separatorChar)
+ + File.separator + getClass().getSimpleName()
+ + File.separator + getCurrentTestName()
+ ;
+ for (String expected : new String[] { null, "", path }) {
+ String actual = SelectorUtils.translateToFileSystemPath(expected, File.separator, File.separator);
+ assertSame("Mismatched instance for translated result", expected, actual);
+ }
+
+ for (String fsSeparator : new String[] { String.valueOf('.'), "##" }) {
+ String expected = path.replace(File.separator, fsSeparator);
+ String actual = SelectorUtils.translateToFileSystemPath(path, File.separator, fsSeparator);
+ assertEquals("Mismatched translation result for separator='" + fsSeparator + "'", expected, actual);
+
+ actual = SelectorUtils.translateToFileSystemPath(actual, fsSeparator, File.separator);
+ assertEquals("Mismatched translation revert for separator='" + fsSeparator + "'", path, actual);
+ }
+ }
}