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 2017/12/20 10:08:12 UTC

mina-sshd git commit: [SSHD-787] Moved some more hardcoded logic to ScpFileOpener to allow user override of default behavior

Repository: mina-sshd
Updated Branches:
  refs/heads/master 8136bf615 -> 65d7f65d1


[SSHD-787] Moved some more hardcoded logic to ScpFileOpener to allow user override of default behavior


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

Branch: refs/heads/master
Commit: 65d7f65d1bb1b1b4545386c24ccbc33129066737
Parents: 8136bf6
Author: Goldstein Lyor <ly...@c-b4.com>
Authored: Wed Dec 20 12:07:29 2017 +0200
Committer: Goldstein Lyor <ly...@c-b4.com>
Committed: Wed Dec 20 12:08:05 2017 +0200

----------------------------------------------------------------------
 .../apache/sshd/common/scp/ScpFileOpener.java   | 131 +++++++++++++++++++
 .../org/apache/sshd/common/scp/ScpHelper.java   |  92 +------------
 2 files changed, 138 insertions(+), 85 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/65d7f65d/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 887d649..3ef8c28 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
@@ -19,13 +19,24 @@
 
 package org.apache.sshd.common.scp;
 
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.nio.file.AccessDeniedException;
+import java.nio.file.Files;
+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.FileTime;
+import java.nio.file.attribute.PosixFilePermission;
+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.io.IoUtils;
 
 /**
  * Plug-in mechanism for users to intervene in the SCP process - e.g.,
@@ -36,6 +47,115 @@ import org.apache.sshd.common.session.Session;
  */
 public interface ScpFileOpener {
     /**
+     * Invoked when receiving a new file to via a directory command
+     *
+     * @param localPath The target local path
+     * @param name The target file name
+     * @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
+     * @throws IOException If failed to resolve the file path
+     * @see #updateFileProperties(Path, Set, ScpTimestamp) updateFileProperties
+     */
+    default Path resolveIncomingFilePath(
+            Path localPath, String name, boolean preserve, Set<PosixFilePermission> permissions, ScpTimestamp time)
+                    throws IOException {
+        LinkOption[] options = IoUtils.getLinkOptions(true);
+        Boolean status = IoUtils.checkFileExists(localPath, options);
+        if (status == null) {
+            throw new AccessDeniedException("Receive directory existence status cannot be determined: " + localPath);
+        }
+
+        Path file = null;
+        if (status && Files.isDirectory(localPath, options)) {
+            String localName = name.replace('/', File.separatorChar);
+            file = localPath.resolve(localName);
+        } else if (!status) {
+            Path parent = localPath.getParent();
+
+            status = IoUtils.checkFileExists(parent, options);
+            if (status == null) {
+                throw new AccessDeniedException("Receive directory parent (" + parent + ") existence status cannot be determined for " + localPath);
+            }
+
+            if (status && Files.isDirectory(parent, options)) {
+                file = localPath;
+            }
+        }
+
+        if (file == null) {
+            throw new IOException("Cannot write to " + localPath);
+        }
+
+        status = IoUtils.checkFileExists(file, options);
+        if (status == null) {
+            throw new AccessDeniedException("Receive directory file existence status cannot be determined: " + file);
+        }
+
+        if (!(status && Files.isDirectory(file, options))) {
+            Files.createDirectory(file);
+        }
+
+        if (preserve) {
+            updateFileProperties(file, permissions, time);
+        }
+
+        return file;
+    }
+
+    /**
+     * Invoked when a request to receive something is processed
+     *
+     * @param path The local target {@link Path} of the request
+     * @param recursive Whether the request is recursive
+     * @param shouldBeDir Whether target path is expected to be a directory
+     * @param preserve Whether target path is expected to preserve attributes (permissions, times)
+     * @return The effective target path - default=same as input
+     * @throws IOException If failed to resolve target location
+     */
+    default Path resolveIncomingReceiveLocation(
+            Path path, boolean recursive, boolean shouldBeDir, boolean preserve)
+                throws IOException {
+        if (!shouldBeDir) {
+            return path;
+        }
+        LinkOption[] options = IoUtils.getLinkOptions(true);
+        Boolean status = IoUtils.checkFileExists(path, options);
+        if (status == null) {
+            throw new SshException("Target directory " + path + " is most like inaccessible");
+        }
+        if (!status) {
+            throw new SshException("Target directory " + path + " does not exist");
+        }
+        if (!Files.isDirectory(path, options)) {
+            throw new SshException("Target directory " + path + " is not a directory");
+        }
+
+        return path;
+    }
+
+    /**
+     * Called when there is a candidate file/folder for sending
+     *
+     * @param localPath The original file/folder {@link Path} for sending
+     * @param options The {@link LinkOption}-s to use for validation
+     * @return The effective outgoing file path (default=same as input)
+     * @throws IOException If failed to resolve
+     */
+    default Path resolveOutgoingFilePath(Path localPath, LinkOption... options) throws IOException {
+        Boolean status = IoUtils.checkFileExists(localPath, options);
+        if (status == null) {
+            throw new AccessDeniedException("Send file existence status cannot be determined: " + localPath);
+        }
+        if (!status) {
+            throw new IOException(localPath + ": no such file or directory");
+        }
+
+        return localPath;
+    }
+
+    /**
      * Create an input stream to read from a file
      *
      * @param session The {@link Session} requesting the access
@@ -56,4 +176,15 @@ public interface ScpFileOpener {
      * @throws IOException If failed to open the file
      */
     OutputStream openWrite(Session session, Path file, OpenOption... options) throws IOException;
+
+    static void updateFileProperties(Path file, Set<PosixFilePermission> perms, ScpTimestamp time) throws IOException {
+        IoUtils.setPermissions(file, perms);
+
+        if (time != null) {
+            BasicFileAttributeView view = Files.getFileAttributeView(file, BasicFileAttributeView.class);
+            FileTime lastModified = FileTime.from(time.getLastModifiedTime(), TimeUnit.MILLISECONDS);
+            FileTime lastAccess = FileTime.from(time.getLastAccessTime(), TimeUnit.MILLISECONDS);
+            view.setTimes(lastModified, lastAccess, null);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/65d7f65d/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 0e75e83..6075234 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
@@ -26,7 +26,6 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.StreamCorruptedException;
 import java.nio.charset.StandardCharsets;
-import java.nio.file.AccessDeniedException;
 import java.nio.file.DirectoryStream;
 import java.nio.file.FileSystem;
 import java.nio.file.Files;
@@ -44,7 +43,6 @@ import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.file.util.MockPath;
 import org.apache.sshd.common.scp.ScpTransferEventListener.FileOperation;
 import org.apache.sshd.common.scp.helpers.DefaultScpFileOpener;
@@ -167,21 +165,8 @@ public class ScpHelper extends AbstractLoggingBean implements SessionHolder<Sess
     }
 
     public void receive(Path local, boolean recursive, boolean shouldBeDir, boolean preserve, int bufferSize) throws IOException {
-        Path path = Objects.requireNonNull(local, "No local path").normalize().toAbsolutePath();
-        if (shouldBeDir) {
-            LinkOption[] options = IoUtils.getLinkOptions(true);
-            Boolean status = IoUtils.checkFileExists(path, options);
-            if (status == null) {
-                throw new SshException("Target directory " + path + " is most like inaccessible");
-            }
-            if (!status) {
-                throw new SshException("Target directory " + path + " does not exist");
-            }
-            if (!Files.isDirectory(path, options)) {
-                throw new SshException("Target directory " + path + " is not a directory");
-            }
-        }
-
+        Path localPath = Objects.requireNonNull(local, "No local path").normalize().toAbsolutePath();
+        Path path = opener.resolveIncomingReceiveLocation(localPath, recursive, shouldBeDir, preserve);
         receive((line, isDir, time) -> {
             if (recursive && isDir) {
                 receiveDir(line, path, time, preserve, bufferSize);
@@ -255,50 +240,11 @@ public class ScpHelper extends AbstractLoggingBean implements SessionHolder<Sess
         Set<PosixFilePermission> perms = parseOctalPermissions(header.substring(1, 5));
         int length = Integer.parseInt(header.substring(6, header.indexOf(' ', 6)));
         String name = header.substring(header.indexOf(' ', 6) + 1);
-
         if (length != 0) {
-            throw new IOException("Expected 0 length for directory but got " + length);
-        }
-
-        LinkOption[] options = IoUtils.getLinkOptions(true);
-        Boolean status = IoUtils.checkFileExists(path, options);
-        if (status == null) {
-            throw new AccessDeniedException("Receive directory existence status cannot be determined: " + path);
-        }
-
-        Path file = null;
-        if (status && Files.isDirectory(path, options)) {
-            String localName = name.replace('/', File.separatorChar);
-            file = path.resolve(localName);
-        } else if (!status) {
-            Path parent = path.getParent();
-
-            status = IoUtils.checkFileExists(parent, options);
-            if (status == null) {
-                throw new AccessDeniedException("Receive directory parent (" + parent + ") existence status cannot be determined for " + path);
-            }
-
-            if (status && Files.isDirectory(parent, options)) {
-                file = path;
-            }
-        }
-
-        if (file == null) {
-            throw new IOException("Cannot write to " + path);
+            throw new IOException("Expected 0 length for directory=" + name + " but got " + length);
         }
 
-        status = IoUtils.checkFileExists(file, options);
-        if (status == null) {
-            throw new AccessDeniedException("Receive directory file existence status cannot be determined: " + file);
-        }
-
-        if (!(status && Files.isDirectory(file, options))) {
-            Files.createDirectory(file);
-        }
-
-        if (preserve) {
-            updateFileProperties(file, perms, time);
-        }
+        Path file = opener.resolveIncomingFilePath(path, name, preserve, perms, time);
 
         ack();
 
@@ -353,7 +299,7 @@ public class ScpHelper extends AbstractLoggingBean implements SessionHolder<Sess
         }
 
         Set<PosixFilePermission> perms = parseOctalPermissions(header.substring(1, 5));
-        final long length = Long.parseLong(header.substring(6, header.indexOf(' ', 6)));
+        long length = Long.parseLong(header.substring(6, header.indexOf(' ', 6)));
         String name = header.substring(header.indexOf(' ', 6) + 1);
         if (length < 0L) { // TODO consider throwing an exception...
             log.warn("receiveStream({})[{}] bad length in header: {}", this, resolver, header);
@@ -405,23 +351,6 @@ public class ScpHelper extends AbstractLoggingBean implements SessionHolder<Sess
         validateAckReplyCode("receiveStream", resolver, replyCode, false);
     }
 
-    protected void updateFileProperties(Path file, Set<PosixFilePermission> perms, ScpTimestamp time) throws IOException {
-        if (log.isTraceEnabled()) {
-            log.trace("updateFileProperties({}) {} permissions={}, time={}", this, file, perms, time);
-        }
-        IoUtils.setPermissions(file, perms);
-
-        if (time != null) {
-            BasicFileAttributeView view = Files.getFileAttributeView(file, BasicFileAttributeView.class);
-            FileTime lastModified = FileTime.from(time.getLastModifiedTime(), TimeUnit.MILLISECONDS);
-            FileTime lastAccess = FileTime.from(time.getLastAccessTime(), TimeUnit.MILLISECONDS);
-            if (log.isTraceEnabled()) {
-                log.trace("updateFileProperties({}) {} last-modified={}, last-access={}", this, file, lastModified, lastAccess);
-            }
-            view.setTimes(lastModified, lastAccess, null);
-        }
-    }
-
     public String readLine() throws IOException {
         return readLine(false);
     }
@@ -506,15 +435,8 @@ public class ScpHelper extends AbstractLoggingBean implements SessionHolder<Sess
     }
 
     protected void send(Path local, boolean recursive, boolean preserve, int bufferSize, LinkOption... options) throws IOException {
-        Path file = Objects.requireNonNull(local, "No local path").normalize().toAbsolutePath();
-        Boolean status = IoUtils.checkFileExists(file, options);
-        if (status == null) {
-            throw new AccessDeniedException("Send file existence status cannot be determined: " + file);
-        }
-        if (!status) {
-            throw new IOException(file + ": no such file or directory");
-        }
-
+        Path localPath = Objects.requireNonNull(local, "No local path").normalize().toAbsolutePath();
+        Path file = opener.resolveOutgoingFilePath(localPath, options);
         if (Files.isRegularFile(file, options)) {
             sendFile(file, preserve, bufferSize);
         } else if (Files.isDirectory(file, options)) {