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)) {