Repository: mina-sshd
Updated Branches:
  refs/heads/master 3d5a8e70f -> ba91a674d


[SSHD-787] Delegated all SCP java.nio file related actions to ScpFileOpener


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

Branch: refs/heads/master
Commit: ba91a674d4dd76c4516bfb421145630288e4aad7
Parents: 3d5a8e7
Author: Goldstein Lyor <[email protected]>
Authored: Sun Dec 24 11:25:26 2017 +0200
Committer: Lyor Goldstein <[email protected]>
Committed: Tue Dec 26 20:30:17 2017 +0200

----------------------------------------------------------------------
 .../apache/sshd/common/scp/ScpFileOpener.java   | 92 +++++++++++++++++++-
 .../org/apache/sshd/common/scp/ScpHelper.java   | 44 +++-------
 .../sshd/common/util/io/DirectoryScanner.java   |  8 +-
 3 files changed, 108 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ba91a674/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpFileOpener.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpFileOpener.java 
b/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpFileOpener.java
index 5b78fda..3e1f408 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpFileOpener.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpFileOpener.java
@@ -24,18 +24,27 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.file.AccessDeniedException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystem;
 import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
 import java.nio.file.LinkOption;
 import java.nio.file.OpenOption;
 import java.nio.file.Path;
 import java.nio.file.attribute.BasicFileAttributeView;
+import java.nio.file.attribute.BasicFileAttributes;
 import java.nio.file.attribute.FileTime;
 import java.nio.file.attribute.PosixFilePermission;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.SelectorUtils;
+import org.apache.sshd.common.util.io.DirectoryScanner;
 import org.apache.sshd.common.util.io.IoUtils;
 
 /**
@@ -54,7 +63,7 @@ public interface ScpFileOpener {
      * @param boolean preserve Whether requested to preserve the permissions 
and timestamp
      * @param permissions The requested file permissions
      * @param time The requested {@link ScpTimestamp} - may be {@code null} if 
nothing to update
-     * @return The actual target file path
+     * @return The actual target file path for the incoming file/directory
      * @throws IOException If failed to resolve the file path
      * @see #updateFileProperties(Path, Set, ScpTimestamp) updateFileProperties
      */
@@ -105,6 +114,87 @@ public interface ScpFileOpener {
     }
 
     /**
+     * Invoked when required to send a pattern of files
+     *
+     * @param basedir The base directory - may be {@code null}/empty to 
indicate CWD
+     * @param pattern The required pattern
+     * @return The matching <U>relative paths</U> of the children to send
+     */
+    default Iterable<String> getMatchingFilesToSend(String basedir, String 
pattern) {
+        String[] matches = new DirectoryScanner(basedir, pattern).scan();
+        if (GenericUtils.isEmpty(matches)) {
+            return Collections.emptyList();
+        }
+
+        return Arrays.asList(matches);
+    }
+
+    /**
+     * Invoked on a local path in order to decide whether it should be sent
+     * as a file or as a directory
+     *
+     * @param path The local {@link Path}
+     * @param options The {@link LinkOption}-s
+     * @return Whether to send the file as a regular one - <B>Note:</B> if 
{@code false}
+     * then the {@link #sendAsDirectory(Path, LinkOption...)} is consulted.
+     * @throws IOException If failed to decide
+     */
+    default boolean sendAsRegularFile(Path path, LinkOption... options) throws 
IOException {
+        return Files.isRegularFile(path, options);
+    }
+
+    /**
+     * Invoked on a local path in order to decide whether it should be sent
+     * as a file or as a directory
+     *
+     * @param path The local {@link Path}
+     * @param options The {@link LinkOption}-s
+     * @return Whether to send the file as a directory - <B>Note:</B> if 
{@code true}
+     * then {@link #getLocalFolderChildren(Path)} is consulted
+     * @throws IOException If failed to decide
+     */
+    default boolean sendAsDirectory(Path path, LinkOption... options) throws 
IOException {
+        return Files.isDirectory(path, options);
+    }
+
+    /**
+     * Invoked when required to send all children of a local directory
+     *
+     * @param path The local folder {@link Path}{
+     * @return The {@link DirectoryStream} of children to send - <B>Note:</B> 
for each child
+     * the decision whether to send it as a file or a directory will be 
reached by consulting
+     * the respective {@link #sendAsRegularFile(Path, LinkOption...) 
sendAsRegularFile} and
+     * {@link #sendAsDirectory(Path, LinkOption...) sendAsDirectory} methods
+     * @throws IOException If failed to provide the children stream
+     * @see #sendAsDirectory(Path, LinkOption...) sendAsDirectory
+     */
+    default DirectoryStream<Path> getLocalFolderChildren(Path path) throws 
IOException {
+        return Files.newDirectoryStream(path);
+    }
+
+    default BasicFileAttributes getLocalBasicFileAttributes(Path path, 
LinkOption... options) throws IOException {
+        return Files.getFileAttributeView(path, BasicFileAttributeView.class, 
options).readAttributes();
+    }
+
+    default Set<PosixFilePermission> getLocalFilePermissions(Path path, 
LinkOption... options) throws IOException {
+        return IoUtils.getPermissions(path, options);
+    }
+
+    /**
+     * @param fileSystem The <U>local</U> {@link FileSystem} on which local 
file should reside
+     * @param commandPath The command path using the <U>local</U> file 
separator
+     * @return The resolved absolute and normalized local {@link Path}
+     * @throws IOException If failed to resolve the path
+     * @throws InvalidPathException If invalid local path value
+     */
+    default Path resolveLocalPath(FileSystem fileSystem, String commandPath) 
throws IOException, InvalidPathException {
+        String path = 
SelectorUtils.translateToLocalFileSystemPath(commandPath, File.separatorChar, 
fileSystem);
+        Path lcl = fileSystem.getPath(path);
+        Path abs = lcl.isAbsolute() ? lcl : lcl.toAbsolutePath();
+        return abs.normalize();
+    }
+
+    /**
      * Invoked when a request to receive something is processed
      *
      * @param path The local target {@link Path} of the request

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ba91a674/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 e8183c8..ba8eb11 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
@@ -28,12 +28,10 @@ import java.io.StreamCorruptedException;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.DirectoryStream;
 import java.nio.file.FileSystem;
-import java.nio.file.Files;
 import java.nio.file.InvalidPathException;
 import java.nio.file.LinkOption;
 import java.nio.file.OpenOption;
 import java.nio.file.Path;
-import java.nio.file.attribute.BasicFileAttributeView;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.nio.file.attribute.FileTime;
 import java.nio.file.attribute.PosixFilePermission;
@@ -49,8 +47,6 @@ import 
org.apache.sshd.common.scp.helpers.DefaultScpFileOpener;
 import org.apache.sshd.common.session.Session;
 import org.apache.sshd.common.session.SessionHolder;
 import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.SelectorUtils;
-import org.apache.sshd.common.util.io.DirectoryScanner;
 import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.common.util.io.LimitInputStream;
 import org.apache.sshd.common.util.logging.AbstractLoggingBean;
@@ -390,12 +386,12 @@ public class ScpHelper extends AbstractLoggingBean 
implements SessionHolder<Sess
                     pattern = pattern.substring(lastSep + 1);
                 }
 
-                String[] included = new DirectoryScanner(basedir, 
pattern).scan();
+                Iterable<String> included = 
opener.getMatchingFilesToSend(basedir, pattern);
                 for (String path : included) {
                     Path file = resolveLocalPath(basedir, path);
-                    if (Files.isRegularFile(file, options)) {
+                    if (opener.sendAsRegularFile(file, options)) {
                         sendFile(file, preserve, bufferSize);
-                    } else if (Files.isDirectory(file, options)) {
+                    } else if (opener.sendAsDirectory(file, options)) {
                         if (!recursive) {
                             if (log.isDebugEnabled()) {
                                 log.debug("send({}) {}: not a regular file", 
this, path);
@@ -433,9 +429,9 @@ public class ScpHelper extends AbstractLoggingBean 
implements SessionHolder<Sess
     protected void send(Path local, boolean recursive, boolean preserve, int 
bufferSize, LinkOption... options) throws IOException {
         Path localPath = Objects.requireNonNull(local, "No local 
path").normalize().toAbsolutePath();
         Path file = opener.resolveOutgoingFilePath(localPath, options);
-        if (Files.isRegularFile(file, options)) {
+        if (opener.sendAsRegularFile(file, options)) {
             sendFile(file, preserve, bufferSize);
-        } else if (Files.isDirectory(file, options)) {
+        } else if (opener.sendAsDirectory(file, options)) {
             if (!recursive) {
                 throw new IOException(file + " not a regular file");
             } else {
@@ -456,15 +452,12 @@ public class ScpHelper extends AbstractLoggingBean 
implements SessionHolder<Sess
 
     /**
      * @param commandPath The command path using the <U>local</U> file 
separator
-     * @return The resolved absolute and normalized local path {@link Path}
+     * @return The resolved absolute and normalized local {@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 {
-        String path = 
SelectorUtils.translateToLocalFileSystemPath(commandPath, File.separatorChar, 
fileSystem);
-        Path lcl = fileSystem.getPath(path);
-        Path abs = lcl.isAbsolute() ? lcl : lcl.toAbsolutePath();
-        Path p = abs.normalize();
+        Path p = opener.resolveLocalPath(fileSystem, commandPath);
         if (log.isTraceEnabled()) {
             log.trace("resolveLocalPath({}) {}: {}", this, commandPath, p);
         }
@@ -593,8 +586,9 @@ public class ScpHelper extends AbstractLoggingBean 
implements SessionHolder<Sess
                       this, path, preserve, bufferSize);
         }
 
-        BasicFileAttributes basic = Files.getFileAttributeView(path, 
BasicFileAttributeView.class).readAttributes();
+        LinkOption[] options = IoUtils.getLinkOptions(true);
         if (preserve) {
+            BasicFileAttributes basic = 
opener.getLocalBasicFileAttributes(path, options);
             FileTime lastModified = basic.lastModifiedTime();
             FileTime lastAccess = basic.lastAccessTime();
             String cmd = "T" + lastModified.to(TimeUnit.SECONDS) + " "
@@ -618,8 +612,7 @@ public class ScpHelper extends AbstractLoggingBean 
implements SessionHolder<Sess
             validateAckReplyCode(cmd, path, readyCode, false);
         }
 
-        LinkOption[] options = IoUtils.getLinkOptions(true);
-        Set<PosixFilePermission> perms = IoUtils.getPermissions(path, options);
+        Set<PosixFilePermission> perms = opener.getLocalFilePermissions(path, 
options);
         String octalPerms = (preserve || GenericUtils.isEmpty(perms)) ? 
DEFAULT_DIR_OCTAL_PERMISSIONS : getOctalPermissions(perms);
         String cmd = "D" + octalPerms + " " + "0" + " " + 
Objects.toString(path.getFileName(), null);
         if (log.isDebugEnabled()) {
@@ -636,14 +629,14 @@ public class ScpHelper extends AbstractLoggingBean 
implements SessionHolder<Sess
         }
         validateAckReplyCode(cmd, path, readyCode, false);
 
-        try (DirectoryStream<Path> children = Files.newDirectoryStream(path)) {
+        try (DirectoryStream<Path> children = 
opener.getLocalFolderChildren(path)) {
             listener.startFolderEvent(FileOperation.SEND, path, perms);
 
             try {
                 for (Path child : children) {
-                    if (Files.isRegularFile(child, options)) {
+                    if (opener.sendAsRegularFile(child, options)) {
                         sendFile(child, preserve, bufferSize);
-                    } else if (Files.isDirectory(child, options)) {
+                    } else if (opener.sendAsDirectory(child, options)) {
                         sendDir(child, preserve, bufferSize);
                     }
                 }
@@ -668,11 +661,6 @@ public class ScpHelper extends AbstractLoggingBean 
implements SessionHolder<Sess
         validateAckReplyCode("E", path, readyCode, false);
     }
 
-    public static String getOctalPermissions(Path path, LinkOption... options) 
throws IOException {
-        Collection<PosixFilePermission> perms = IoUtils.getPermissions(path, 
options);
-        return getOctalPermissions(perms);
-    }
-
     public static String getOctalPermissions(Collection<PosixFilePermission> 
perms) {
         int pf = 0;
 
@@ -712,12 +700,6 @@ public class ScpHelper extends AbstractLoggingBean 
implements SessionHolder<Sess
         return String.format("%04o", pf);
     }
 
-    public static Set<PosixFilePermission> setOctalPermissions(Path path, 
String str) throws IOException {
-        Set<PosixFilePermission> perms = parseOctalPermissions(str);
-        IoUtils.setPermissions(path, perms);
-        return perms;
-    }
-
     public static Set<PosixFilePermission> parseOctalPermissions(String str) {
         int perms = Integer.parseInt(str, 8);
         Set<PosixFilePermission> p = EnumSet.noneOf(PosixFilePermission.class);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ba91a674/sshd-core/src/main/java/org/apache/sshd/common/util/io/DirectoryScanner.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/util/io/DirectoryScanner.java 
b/sshd-core/src/main/java/org/apache/sshd/common/util/io/DirectoryScanner.java
index 6cd8ad9..8b4e9ba 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/common/util/io/DirectoryScanner.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/common/util/io/DirectoryScanner.java
@@ -22,6 +22,7 @@ import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.SelectorUtils;
 
 /**
@@ -250,8 +251,8 @@ public class DirectoryScanner {
      */
     protected void scandir(File dir, String vpath) {
         String[] newfiles = dir.list();
-        if (newfiles == null) {
-            newfiles = new String[0];
+        if (GenericUtils.isEmpty(newfiles)) {
+            newfiles = GenericUtils.EMPTY_STRING_ARRAY;
         }
 
         for (String newfile : newfiles) {
@@ -282,8 +283,7 @@ public class DirectoryScanner {
      */
     public String[] getIncludedFiles() {
         String[] files = new String[filesIncluded.size()];
-        filesIncluded.toArray(files);
-        return files;
+        return filesIncluded.toArray(files);
     }
 
     /**

Reply via email to