You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2015/03/17 20:15:40 UTC
mina-sshd git commit: [SSHD-428] Add ScpTransferEventListener
Repository: mina-sshd
Updated Branches:
refs/heads/master 4039a11ae -> 2cd0ebbaf
[SSHD-428] Add ScpTransferEventListener
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/2cd0ebba
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/2cd0ebba
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/2cd0ebba
Branch: refs/heads/master
Commit: 2cd0ebbafabe232a483b244dcefb82477ec67580
Parents: 4039a11
Author: Guillaume Nodet <gn...@apache.org>
Authored: Tue Mar 17 18:51:19 2015 +0100
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Tue Mar 17 18:56:14 2015 +0100
----------------------------------------------------------------------
.../java/org/apache/sshd/ClientSession.java | 28 +
.../sshd/client/scp/DefaultScpClient.java | 22 +-
.../sshd/client/session/ClientSessionImpl.java | 23 +-
.../org/apache/sshd/common/scp/ScpHelper.java | 249 ++++---
.../common/scp/ScpTransferEventListener.java | 103 +++
.../org/apache/sshd/common/util/IoUtils.java | 44 +-
.../apache/sshd/server/command/ScpCommand.java | 11 +-
.../sshd/server/command/ScpCommandFactory.java | 59 +-
.../apache/sshd/server/sftp/SftpSubsystem.java | 4 +-
.../src/test/java/org/apache/sshd/ScpTest.java | 703 ++++++++++---------
10 files changed, 796 insertions(+), 450 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2cd0ebba/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/ClientSession.java b/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
index 867dadb..a84534e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
@@ -36,6 +36,7 @@ import org.apache.sshd.common.Session;
import org.apache.sshd.common.SshdSocketAddress;
import org.apache.sshd.common.future.CloseFuture;
import org.apache.sshd.common.future.SshFuture;
+import org.apache.sshd.common.scp.ScpTransferEventListener;
/**
* An authenticated session to a given SSH server
@@ -153,10 +154,37 @@ public interface ClientSession extends Session {
/**
* Create an SCP client from this session.
+ * @return An {@link ScpClient} instance. <B>Note:</B> uses the currently
+ * registered {@link ScpTransferEventListener} if any
+ * @see #setScpTransferEventListener(ScpTransferEventListener)
*/
ScpClient createScpClient();
/**
+ * Create an SCP client from this session.
+ * @param listener A {@link ScpTransferEventListener} that can be used
+ * to receive information about the SCP operations - may be {@code null}
+ * to indicate no more events are required. <B>Note:</B> this listener
+ * is used <U>instead</U> of any listener set via {@link #setScpTransferEventListener(ScpTransferEventListener)}
+ * @return An {@link ScpClient} instance
+ */
+ ScpClient createScpClient(ScpTransferEventListener listener);
+
+ /**
+ * @return The last {@link ScpTransferEventListener} set via
+ * {@link #setScpTransferEventListener(ScpTransferEventListener)}
+ */
+ ScpTransferEventListener getScpTransferEventListener();
+
+ /**
+ * @param listener A default {@link ScpTransferEventListener} that can be used
+ * to receive information about the SCP operations - may be {@code null}
+ * to indicate no more events are required
+ * @see #createScpClient(ScpTransferEventListener)
+ */
+ void setScpTransferEventListener(ScpTransferEventListener listener);
+
+ /**
* Create an SFTP client from this session.
*/
SftpClient createSftpClient() throws IOException;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2cd0ebba/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java
index c0b23a0..bb5019b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java
@@ -23,10 +23,11 @@ import java.io.InterruptedIOException;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.EnumSet;
import java.util.List;
+import java.util.Set;
import org.apache.sshd.ClientSession;
import org.apache.sshd.client.ScpClient;
@@ -34,6 +35,7 @@ import org.apache.sshd.client.channel.ChannelExec;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.file.FileSystemFactory;
import org.apache.sshd.common.scp.ScpHelper;
+import org.apache.sshd.common.scp.ScpTransferEventListener;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
@@ -41,9 +43,15 @@ import org.apache.sshd.common.scp.ScpHelper;
public class DefaultScpClient implements ScpClient {
private final ClientSession clientSession;
+ private final ScpTransferEventListener listener;
public DefaultScpClient(ClientSession clientSession) {
+ this(clientSession, ScpTransferEventListener.EMPTY);
+ }
+
+ public DefaultScpClient(ClientSession clientSession, ScpTransferEventListener eventListener) {
this.clientSession = clientSession;
+ this.listener = (eventListener == null) ? ScpTransferEventListener.EMPTY : eventListener;
}
public void download(String remote, String local, Option... options) throws IOException {
@@ -55,7 +63,7 @@ public class DefaultScpClient implements ScpClient {
public void download(String[] remote, String local, Option... options) throws IOException {
local = checkNotNullAndNotEmpty(local, "Invalid argument local: {}");
remote = checkNotNullAndNotEmpty(remote, "Invalid argument remote: {}");
- List<Option> opts = options(options);
+ Set<Option> opts = options(options);
if (remote.length > 1) {
opts.add(Option.TargetIsDirectory);
}
@@ -100,7 +108,7 @@ public class DefaultScpClient implements ScpClient {
throw (IOException) new InterruptedIOException().initCause(e);
}
- ScpHelper helper = new ScpHelper(channel.getInvertedOut(), channel.getInvertedIn(), fs);
+ ScpHelper helper = new ScpHelper(channel.getInvertedOut(), channel.getInvertedIn(), fs, listener);
helper.receive(target,
options.contains(Option.Recursive),
@@ -127,7 +135,7 @@ public class DefaultScpClient implements ScpClient {
public void upload(String[] local, String remote, Option... options) throws IOException {
local = checkNotNullAndNotEmpty(local, "Invalid argument local: {}");
remote = checkNotNullAndNotEmpty(remote, "Invalid argument remote: {}");
- List<Option> opts = options(options);
+ Set<Option> opts = options(options);
if (local.length > 1) {
opts.add(Option.TargetIsDirectory);
}
@@ -161,7 +169,7 @@ public class DefaultScpClient implements ScpClient {
FileSystemFactory factory = clientSession.getFactoryManager().getFileSystemFactory();
FileSystem fs = factory.createFileSystem(clientSession);
try {
- ScpHelper helper = new ScpHelper(channel.getInvertedOut(), channel.getInvertedIn(), fs);
+ ScpHelper helper = new ScpHelper(channel.getInvertedOut(), channel.getInvertedIn(), fs, listener);
helper.send(Arrays.asList(local),
options.contains(Option.Recursive),
options.contains(Option.PreserveAttributes),
@@ -176,8 +184,8 @@ public class DefaultScpClient implements ScpClient {
channel.close(false);
}
- private List<Option> options(Option... options) {
- List<Option> opts = new ArrayList<>();
+ private Set<Option> options(Option... options) {
+ Set<Option> opts = EnumSet.noneOf(Option.class);
if (options != null) {
opts.addAll(Arrays.asList(options));
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2cd0ebba/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
index a1872b8..492f5f4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
@@ -23,7 +23,6 @@ import java.net.SocketAddress;
import java.nio.file.FileSystem;
import java.security.KeyPair;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -61,6 +60,7 @@ import org.apache.sshd.common.cipher.CipherNone;
import org.apache.sshd.common.future.DefaultSshFuture;
import org.apache.sshd.common.future.SshFuture;
import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.scp.ScpTransferEventListener;
import org.apache.sshd.common.session.AbstractConnectionService;
import org.apache.sshd.common.session.AbstractSession;
import org.apache.sshd.common.session.ConnectionService;
@@ -85,6 +85,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
private ServiceFactory nextServiceFactory;
private final List<Object> identities = new ArrayList<Object>();
private UserInteraction userInteraction;
+ private ScpTransferEventListener scpListener;
protected AuthFuture authFuture;
@@ -164,7 +165,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
public AuthFuture authInteractive(String user, String password) throws IOException {
return tryAuth(user, new UserAuthKeyboardInteractive(this, nextServiceName(), password));
- }
+ }
public AuthFuture authPublicKey(String user, KeyPair key) throws IOException {
return tryAuth(user, new UserAuthPublicKey(this, nextServiceName(), key));
@@ -273,8 +274,20 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
return getService(ConnectionService.class);
}
+ public ScpTransferEventListener getScpTransferEventListener() {
+ return scpListener;
+ }
+
+ public void setScpTransferEventListener(ScpTransferEventListener listener) {
+ scpListener = listener;
+ }
+
public ScpClient createScpClient() {
- return new DefaultScpClient(this);
+ return createScpClient(getScpTransferEventListener());
+ }
+
+ public ScpClient createScpClient(ScpTransferEventListener listener) {
+ return new DefaultScpClient(this, listener);
}
public SftpClient createSftpClient() throws IOException {
@@ -428,7 +441,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
}
public Map<Object, Object> getMetadataMap() {
- return metadataMap;
- }
+ return metadataMap;
+ }
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2cd0ebba/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 c5f6ae6..0583928 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
@@ -33,12 +33,14 @@ 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.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.scp.ScpTransferEventListener.FileOperation;
import org.apache.sshd.common.util.DirectoryScanner;
import org.apache.sshd.common.util.IoUtils;
import org.slf4j.Logger;
@@ -82,11 +84,13 @@ public class ScpHelper {
protected final FileSystem fileSystem;
protected final InputStream in;
protected final OutputStream out;
+ protected final ScpTransferEventListener listener;
- public ScpHelper(InputStream in, OutputStream out, FileSystem fileSystem) {
+ public ScpHelper(InputStream in, OutputStream out, FileSystem fileSystem, ScpTransferEventListener eventListener) {
this.in = in;
this.out = out;
this.fileSystem = fileSystem;
+ this.listener = (eventListener == null) ? ScpTransferEventListener.EMPTY : eventListener;
}
public void receive(Path path, boolean recursive, boolean shouldBeDir, boolean preserve, int bufferSize) throws IOException {
@@ -153,7 +157,7 @@ public class ScpHelper {
throw new IOException("Expected a D message but got '" + header + "'");
}
- String perms = header.substring(1, 5);
+ Set<PosixFilePermission> perms = parseOctalPerms(header.substring(1, 5));
int length = Integer.parseInt(header.substring(6, header.indexOf(' ', 6)));
String name = header.substring(header.indexOf(' ', 6) + 1);
@@ -174,7 +178,7 @@ public class ScpHelper {
}
if (preserve) {
- setOctalPerms(file, perms);
+ IoUtils.setPermissions(path, perms);
if (time != null) {
Files.getFileAttributeView(file, BasicFileAttributeView.class)
.setTimes(FileTime.from(time[0], TimeUnit.SECONDS),
@@ -186,24 +190,32 @@ public class ScpHelper {
ack();
time = null;
- for (;;) {
- header = readLine();
- log.debug("Received header: " + header);
- if (header.startsWith("C")) {
- receiveFile(header, file, time, preserve, bufferSize);
- time = null;
- } else if (header.startsWith("D")) {
- receiveDir(header, file, time, preserve, bufferSize);
- time = null;
- } else if (header.equals("E")) {
- ack();
- break;
- } else if (header.startsWith("T")) {
- time = parseTime(header);
- ack();
- } else {
- throw new IOException("Unexpected message: '" + header + "'");
+ try {
+ listener.startFolderEvent(FileOperation.RECEIVE, path, perms);
+ for (; ; ) {
+ header = readLine();
+ if (log.isDebugEnabled()) {
+ log.debug("Received header: " + header);
+ }
+ if (header.startsWith("C")) {
+ receiveFile(header, file, time, preserve, bufferSize);
+ time = null;
+ } else if (header.startsWith("D")) {
+ receiveDir(header, file, time, preserve, bufferSize);
+ time = null;
+ } else if (header.equals("E")) {
+ ack();
+ break;
+ } else if (header.startsWith("T")) {
+ time = parseTime(header);
+ ack();
+ } else {
+ throw new IOException("Unexpected message: '" + header + "'");
+ }
}
+ } catch (IOException | RuntimeException e) {
+ listener.endFolderEvent(FileOperation.RECEIVE, path, perms, e);
+ throw e;
}
}
@@ -219,7 +231,7 @@ public class ScpHelper {
throw new IOException("receiveFile(" + path + ") buffer size (" + bufferSize + ") below minimum (" + MIN_RECEIVE_BUFFER_SIZE + ")");
}
- String perms = header.substring(1, 5);
+ Set<PosixFilePermission> perms = parseOctalPerms(header.substring(1, 5));
final 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...
@@ -234,7 +246,7 @@ public class ScpHelper {
}
bufSize = MIN_RECEIVE_BUFFER_SIZE;
} else {
- bufSize= (int) Math.min(length, bufferSize);
+ bufSize = (int) Math.min(length, bufferSize);
}
if (bufSize < 0) { // TODO consider throwing an exception
@@ -258,15 +270,25 @@ public class ScpHelper {
} else if (Files.exists(file) && !Files.isWritable(file)) {
throw new IOException("Can not write to file: " + file);
}
-
- try (InputStream is = new LimitInputStream(this.in, length);
- OutputStream os = Files.newOutputStream(file)) {
+
+ try (
+ InputStream is = new LimitInputStream(this.in, length);
+ OutputStream os = Files.newOutputStream(file)
+ ) {
ack();
- IoUtils.copy(is, os, bufSize);
+
+ try {
+ listener.startFileEvent(FileOperation.RECEIVE, file, length, perms);
+ IoUtils.copy(is, os, bufSize);
+ listener.endFileEvent(FileOperation.RECEIVE, file, length, perms, null);
+ } catch (IOException | RuntimeException e) {
+ listener.endFileEvent(FileOperation.RECEIVE, file, length, perms, e);
+ throw e;
+ }
}
if (preserve) {
- setOctalPerms(file, perms);
+ IoUtils.setPermissions(file, perms);
if (time != null) {
Files.getFileAttributeView(file, BasicFileAttributeView.class)
.setTimes(FileTime.from(time[0], TimeUnit.SECONDS),
@@ -285,13 +307,13 @@ public class ScpHelper {
public String readLine(boolean canEof) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- for (;;) {
+ for (; ; ) {
int c = in.read();
if (c == '\n') {
return baos.toString();
} else if (c == -1) {
if (!canEof) {
- throw new EOFException();
+ throw new EOFException("EOF while await end of line");
}
return null;
} else {
@@ -370,7 +392,7 @@ public class ScpHelper {
BasicFileAttributes basic = Files.getFileAttributeView(path, BasicFileAttributeView.class).readAttributes();
if (preserve) {
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
buf.append("T");
buf.append(basic.lastModifiedTime().to(TimeUnit.SECONDS));
buf.append(" ");
@@ -385,9 +407,10 @@ public class ScpHelper {
readAck(false);
}
- StringBuffer buf = new StringBuffer();
+ Set<PosixFilePermission> perms = IoUtils.getPermissions(path);
+ StringBuilder buf = new StringBuilder();
buf.append("C");
- buf.append(preserve ? getOctalPerms(path) : "0644");
+ buf.append(preserve ? getOctalPerms(perms) : "0644");
buf.append(" ");
buf.append(basic.size()); // length
buf.append(" ");
@@ -418,9 +441,15 @@ public class ScpHelper {
bufSize = MIN_SEND_BUFFER_SIZE;
}
- // TODO: use bufSize
try (InputStream in = Files.newInputStream(path)) {
- IoUtils.copy(in, out, bufSize);
+ try {
+ listener.startFileEvent(FileOperation.SEND, path, fileSize, perms);
+ IoUtils.copy(in, out, bufSize);
+ listener.endFileEvent(FileOperation.SEND, path, fileSize, perms, null);
+ } catch (IOException | RuntimeException e) {
+ listener.endFileEvent(FileOperation.SEND, path, fileSize, perms, e);
+ throw e;
+ }
}
ack();
readAck(false);
@@ -432,7 +461,7 @@ public class ScpHelper {
}
BasicFileAttributes basic = Files.getFileAttributeView(path, BasicFileAttributeView.class).readAttributes();
if (preserve) {
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
buf.append("T");
buf.append(basic.lastModifiedTime().to(TimeUnit.SECONDS));
buf.append(" ");
@@ -447,9 +476,10 @@ public class ScpHelper {
readAck(false);
}
- StringBuffer buf = new StringBuffer();
+ Set<PosixFilePermission> perms = IoUtils.getPermissions(path);
+ StringBuilder buf = new StringBuilder();
buf.append("D");
- buf.append(preserve ? getOctalPerms(path) : "0755");
+ buf.append(preserve ? getOctalPerms(perms) : "0755");
buf.append(" ");
buf.append("0"); // length
buf.append(" ");
@@ -460,12 +490,21 @@ public class ScpHelper {
readAck(false);
try (DirectoryStream<Path> children = Files.newDirectoryStream(path)) {
- for (Path child : children) {
- if (Files.isRegularFile(child)) {
- sendFile(child, preserve, bufferSize);
- } else if (Files.isDirectory(child)) {
- sendDir(child, preserve, bufferSize);
+ listener.startFolderEvent(FileOperation.SEND, path, perms);
+
+ try {
+ for (Path child : children) {
+ if (Files.isRegularFile(child)) {
+ sendFile(child, preserve, bufferSize);
+ } else if (Files.isDirectory(child)) {
+ sendDir(child, preserve, bufferSize);
+ }
}
+
+ listener.endFolderEvent(FileOperation.SEND, path, perms, null);
+ } catch (IOException | RuntimeException e) {
+ listener.endFolderEvent(FileOperation.SEND, path, perms, e);
+ throw e;
}
}
@@ -476,61 +515,60 @@ public class ScpHelper {
private long[] parseTime(String line) {
String[] numbers = line.substring(1).split(" ");
- return new long[] { Long.parseLong(numbers[0]), Long.parseLong(numbers[2]) };
+ return new long[]{Long.parseLong(numbers[0]), Long.parseLong(numbers[2])};
}
public static String getOctalPerms(Path path) throws IOException {
+ return getOctalPerms(IoUtils.getPermissions(path));
+ }
+
+ public static String getOctalPerms(Collection<PosixFilePermission> perms) {
int pf = 0;
- if (path.getFileSystem().supportedFileAttributeViews().contains("posix")) {
- Set<PosixFilePermission> perms = Files.getPosixFilePermissions(path);
- for (PosixFilePermission p : perms) {
- switch (p) {
- case OWNER_READ:
- pf |= S_IRUSR;
- break;
- case OWNER_WRITE:
- pf |= S_IWUSR;
- break;
- case OWNER_EXECUTE:
- pf |= S_IXUSR;
- break;
- case GROUP_READ:
- pf |= S_IRGRP;
- break;
- case GROUP_WRITE:
- pf |= S_IWGRP;
- break;
- case GROUP_EXECUTE:
- pf |= S_IXGRP;
- break;
- case OTHERS_READ:
- pf |= S_IROTH;
- break;
- case OTHERS_WRITE:
- pf |= S_IWOTH;
- break;
- case OTHERS_EXECUTE:
- pf |= S_IXOTH;
- break;
- }
- }
- } else {
- if (Files.isReadable(path)) {
- pf |= S_IRUSR | S_IRGRP | S_IROTH;
- }
- if (Files.isWritable(path)) {
- pf |= S_IWUSR | S_IWGRP | S_IWOTH;
- }
- if (Files.isExecutable(path)) {
- pf |= S_IXUSR | S_IXGRP | S_IXOTH;
+
+ for (PosixFilePermission p : perms) {
+ switch (p) {
+ case OWNER_READ:
+ pf |= S_IRUSR;
+ break;
+ case OWNER_WRITE:
+ pf |= S_IWUSR;
+ break;
+ case OWNER_EXECUTE:
+ pf |= S_IXUSR;
+ break;
+ case GROUP_READ:
+ pf |= S_IRGRP;
+ break;
+ case GROUP_WRITE:
+ pf |= S_IWGRP;
+ break;
+ case GROUP_EXECUTE:
+ pf |= S_IXGRP;
+ break;
+ case OTHERS_READ:
+ pf |= S_IROTH;
+ break;
+ case OTHERS_WRITE:
+ pf |= S_IWOTH;
+ break;
+ case OTHERS_EXECUTE:
+ pf |= S_IXOTH;
+ break;
}
}
+
return String.format("%04o", pf);
}
- public static void setOctalPerms(Path path, String str) throws IOException {
+ public static Set<PosixFilePermission> setOctalPerms(Path path, String str) throws IOException {
+ Set<PosixFilePermission> perms = parseOctalPerms(str);
+ IoUtils.setPermissions(path, perms);
+ return perms;
+ }
+
+ public static Set<PosixFilePermission> parseOctalPerms(String str) {
int perms = Integer.parseInt(str, 8);
- EnumSet<PosixFilePermission> p = EnumSet.noneOf(PosixFilePermission.class);
+ Set<PosixFilePermission> p = EnumSet.noneOf(PosixFilePermission.class);
if ((perms & S_IRUSR) != 0) {
p.add(PosixFilePermission.OWNER_READ);
}
@@ -558,11 +596,8 @@ public class ScpHelper {
if ((perms & S_IXOTH) != 0) {
p.add(PosixFilePermission.OTHERS_EXECUTE);
}
- if (path.getFileSystem().supportedFileAttributeViews().contains("posix")) {
- Files.setPosixFilePermissions(path, p);
- } else {
- log.warn("Unable to set file permissions because the underlying file system does not support posix permissions");
- }
+
+ return p;
}
public void ack() throws IOException {
@@ -573,20 +608,20 @@ public class ScpHelper {
public int readAck(boolean canEof) throws IOException {
int c = in.read();
switch (c) {
- case -1:
- if (!canEof) {
- throw new EOFException();
- }
- break;
- case OK:
- break;
- case WARNING:
- log.warn("Received warning: " + readLine());
- break;
- case ERROR:
- throw new IOException("Received nack: " + readLine());
- default:
- break;
+ case -1:
+ if (!canEof) {
+ throw new EOFException("readAck - EOF before ACK");
+ }
+ break;
+ case OK:
+ break;
+ case WARNING:
+ log.warn("Received warning: " + readLine());
+ break;
+ case ERROR:
+ throw new IOException("Received nack: " + readLine());
+ default:
+ break;
}
return c;
}
@@ -605,7 +640,7 @@ public class ScpHelper {
if (remaining > 0) {
remaining--;
return super.read();
- } else{
+ } else {
return -1;
}
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2cd0ebba/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpTransferEventListener.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpTransferEventListener.java b/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpTransferEventListener.java
new file mode 100644
index 0000000..fb82707
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpTransferEventListener.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.scp;
+
+import java.nio.file.Path;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.EventListener;
+import java.util.Set;
+
+/**
+ * Can be registered in order to receive events about SCP transfers
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface ScpTransferEventListener extends EventListener {
+
+ enum FileOperation {
+ SEND,
+ RECEIVE
+ }
+
+ /**
+ * @param op The {@link FileOperation}
+ * @param file The <U>local</U> referenced file {@link Path}
+ * @param length Size (in bytes) of transfered data
+ * @param perms A {@link Set} of {@link PosixFilePermission}s to be applied
+ * once transfer is complete
+ */
+ void startFileEvent(FileOperation op, Path file, long length, Set<PosixFilePermission> perms);
+
+ /**
+ * @param op The {@link FileOperation}
+ * @param file The <U>local</U> referenced file {@link Path}
+ * @param length Size (in bytes) of transfered data
+ * @param perms A {@link Set} of {@link PosixFilePermission}s to be applied
+ * once transfer is complete
+ * @param thrown The result of the operation attempt - if {@code null} then
+ * reception was successful
+ */
+ void endFileEvent(FileOperation op, Path file, long length, Set<PosixFilePermission> perms, Throwable thrown);
+
+ /**
+ * @param op The {@link FileOperation}
+ * @param file The <U>local</U> referenced folder {@link Path}
+ * @param perms A {@link Set} of {@link PosixFilePermission}s to be applied
+ * once transfer is complete
+ */
+ void startFolderEvent(FileOperation op, Path file, Set<PosixFilePermission> perms);
+
+ /**
+ * @param op The {@link FileOperation}
+ * @param file The <U>local</U> referenced file {@link Path}
+ * @param perms A {@link Set} of {@link PosixFilePermission}s to be applied
+ * once transfer is complete
+ * @param thrown The result of the operation attempt - if {@code null} then
+ * reception was successful
+ */
+ void endFolderEvent(FileOperation op, Path file, Set<PosixFilePermission> perms, Throwable thrown);
+
+ /**
+ * An "empty" implementation to be used instead of {@code null}s
+ */
+ ScpTransferEventListener EMPTY = new ScpTransferEventListener() {
+ // TODO in JDK 8.0 implement all methods as default with empty body in the interface itself
+
+ @Override
+ public void startFileEvent(FileOperation op, Path file, long length, Set<PosixFilePermission> perms) {
+ // ignored
+ }
+
+ @Override
+ public void endFileEvent(FileOperation op, Path file, long length, Set<PosixFilePermission> perms, Throwable thrown) {
+ // ignored
+ }
+
+ @Override
+ public void startFolderEvent(FileOperation op, Path file, Set<PosixFilePermission> perms) {
+ // ignored
+ }
+
+ @Override
+ public void endFolderEvent(FileOperation op, Path file, Set<PosixFilePermission> perms, Throwable thrown) {
+ // ignored
+ }
+ };
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2cd0ebba/sshd-core/src/main/java/org/apache/sshd/common/util/IoUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/IoUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/IoUtils.java
index cb21985..e62b231 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/IoUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/IoUtils.java
@@ -23,7 +23,10 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
import java.nio.file.LinkOption;
+import java.nio.file.Path;
import java.nio.file.attribute.PosixFilePermission;
import java.util.Arrays;
import java.util.Collection;
@@ -42,7 +45,7 @@ public class IoUtils {
public static final LinkOption[] EMPTY_OPTIONS = new LinkOption[0];
private static final LinkOption[] NO_FOLLOW_OPTIONS = new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
-
+
public static LinkOption[] getLinkOptions(boolean followLinks) {
if (followLinks) {
return EMPTY_OPTIONS;
@@ -97,6 +100,25 @@ public class IoUtils {
}
/**
+ * If the "posix" view is supported, then it returns
+ * {@link Files#getPosixFilePermissions(Path, LinkOption...)}, otherwise
+ * uses the {@link #getPermissionsFromFile(File)} method
+ * @param path The {@link Path}
+ * @return A {@link Set} of {@link PosixFilePermission}
+ * @throws IOException If failed to access the file system in order to
+ * retrieve the permissions
+ */
+ public static Set<PosixFilePermission> getPermissions(Path path) throws IOException {
+ FileSystem fs = path.getFileSystem();
+ Collection<String> views = fs.supportedFileAttributeViews();
+ if (views.contains("posix")) {
+ return Files.getPosixFilePermissions(path, getLinkOptions(false));
+ } else {
+ return getPermissionsFromFile(path.toFile());
+ }
+ }
+
+ /**
* @param f The {@link File} to be checked
* @return A {@link Set} of {@link PosixFilePermission}s based on whether
* the file is readable/writable/executable. If so, then <U>all</U> the
@@ -124,7 +146,25 @@ public class IoUtils {
return perms;
}
-
+
+ /**
+ * If the "posix" view is supported, then it invokes
+ * {@link Files#setPosixFilePermissions(Path, Set)}, otherwise
+ * uses the {@link #setPermissionsToFile(File, Collection)} method
+ * @param path The {@link Path}
+ * @param perms The {@link Set} of {@link PosixFilePermission}s
+ * @throws IOException If failed to access the file system
+ */
+ public static void setPermissions(Path path, Set<PosixFilePermission> perms) throws IOException {
+ FileSystem fs = path.getFileSystem();
+ Collection<String> views = fs.supportedFileAttributeViews();
+ if (views.contains("posix")) {
+ Files.setPosixFilePermissions(path, perms);
+ } else {
+ setPermissionsToFile(path.toFile(), perms);
+ }
+ }
+
/**
* @param f The {@link File}
* @param perms A {@link Collection} of {@link PosixFilePermission}s to set on it.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2cd0ebba/sshd-core/src/main/java/org/apache/sshd/server/command/ScpCommand.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/command/ScpCommand.java b/sshd-core/src/main/java/org/apache/sshd/server/command/ScpCommand.java
index 381773d..ade3866 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/command/ScpCommand.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/command/ScpCommand.java
@@ -21,14 +21,15 @@ package org.apache.sshd.server.command;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.file.FileSystem;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
-import java.nio.file.FileSystem;
import org.apache.sshd.common.file.FileSystemAware;
import org.apache.sshd.common.scp.ScpHelper;
+import org.apache.sshd.common.scp.ScpTransferEventListener;
import org.apache.sshd.common.util.ThreadUtils;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.Environment;
@@ -65,6 +66,7 @@ public class ScpCommand implements Command, Runnable, FileSystemAware {
protected Future<?> pendingFuture;
protected int sendBufferSize;
protected int receiveBufferSize;
+ protected ScpTransferEventListener listener;
/**
* @param command The command to be executed
@@ -76,11 +78,12 @@ public class ScpCommand implements Command, Runnable, FileSystemAware {
* service, which will be shutdown regardless
* @param sendSize Size (in bytes) of buffer to use when sending files
* @param receiveSize Size (in bytes) of buffer to use when receiving files
+ * @param eventListener An {@link ScpTransferEventListener} - may be {@code null}
* @see ThreadUtils#newSingleThreadExecutor(String)
* @see ScpHelper#MIN_SEND_BUFFER_SIZE
* @see ScpHelper#MIN_RECEIVE_BUFFER_SIZE
*/
- public ScpCommand(String command, ExecutorService executorService, boolean shutdownOnExit, int sendSize, int receiveSize) {
+ public ScpCommand(String command, ExecutorService executorService, boolean shutdownOnExit, int sendSize, int receiveSize, ScpTransferEventListener eventListener) {
name = command;
if ((executors = executorService) == null) {
@@ -99,6 +102,8 @@ public class ScpCommand implements Command, Runnable, FileSystemAware {
throw new IllegalArgumentException("<ScpCommmand>(" + command + ") receive buffer size (" + sendSize + ") below minimum required (" + ScpHelper.MIN_RECEIVE_BUFFER_SIZE + ")");
}
+ listener = (eventListener == null) ? ScpTransferEventListener.EMPTY : eventListener;
+
log.debug("Executing command {}", command);
String[] args = command.split(" ");
for (int i = 1; i < args.length; i++) {
@@ -204,7 +209,7 @@ public class ScpCommand implements Command, Runnable, FileSystemAware {
public void run() {
int exitValue = ScpHelper.OK;
String exitMessage = null;
- ScpHelper helper = new ScpHelper(in, out, fileSystem);
+ ScpHelper helper = new ScpHelper(in, out, fileSystem, listener);
try {
if (optT) {
helper.receive(fileSystem.getPath(path), optR, optD, optP, receiveBufferSize);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2cd0ebba/sshd-core/src/main/java/org/apache/sshd/server/command/ScpCommandFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/command/ScpCommandFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/command/ScpCommandFactory.java
index 2daf2d8..ed3db39 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/command/ScpCommandFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/command/ScpCommandFactory.java
@@ -18,9 +18,13 @@
*/
package org.apache.sshd.server.command;
+import java.util.Collection;
+import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutorService;
import org.apache.sshd.common.scp.ScpHelper;
+import org.apache.sshd.common.scp.ScpTransferEventListener;
+import org.apache.sshd.common.util.EventListenerUtils;
import org.apache.sshd.common.util.ObjectBuilder;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.CommandFactory;
@@ -44,7 +48,6 @@ public class ScpCommandFactory implements CommandFactory, Cloneable {
* A useful {@link ObjectBuilder} for {@link ScpCommandFactory}
*/
public static class Builder implements ObjectBuilder<ScpCommandFactory> {
-
private final ScpCommandFactory factory = new ScpCommandFactory();
public Builder() {
@@ -76,8 +79,17 @@ public class ScpCommandFactory implements CommandFactory, Cloneable {
return this;
}
+ public Builder addEventListener(ScpTransferEventListener listener) {
+ factory.addEventListener(listener);
+ return this;
+ }
+
+ public Builder removeEventListener(ScpTransferEventListener listener) {
+ factory.removeEventListener(listener);
+ return this;
+ }
+
public ScpCommandFactory build() {
- // return a clone so that each invocation returns a different instance - avoid shared instances
return factory.clone();
}
}
@@ -91,9 +103,11 @@ public class ScpCommandFactory implements CommandFactory, Cloneable {
private boolean shutdownExecutor;
private int sendBufferSize = ScpHelper.MIN_SEND_BUFFER_SIZE;
private int receiveBufferSize = ScpHelper.MIN_RECEIVE_BUFFER_SIZE;
+ private Collection<ScpTransferEventListener> listeners = new CopyOnWriteArraySet<>();
+ private ScpTransferEventListener listenerProxy;
public ScpCommandFactory() {
- super();
+ listenerProxy = EventListenerUtils.proxyWrapper(ScpTransferEventListener.class, getClass().getClassLoader(), listeners);
}
public CommandFactory getDelegateCommandFactory() {
@@ -167,6 +181,34 @@ public class ScpCommandFactory implements CommandFactory, Cloneable {
}
/**
+ * @param listener The {@link ScpTransferEventListener} to add
+ * @return {@code true} if this is a <U>new</U> listener instance,
+ * {@code false} if the listener is already registered
+ * @throws IllegalArgumentException if {@code null} listener
+ */
+ public boolean addEventListener(ScpTransferEventListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("No listener instance");
+ }
+
+ return listeners.add(listener);
+ }
+
+ /**
+ * @param listener The {@link ScpTransferEventListener} to remove
+ * @return {@code true} if the listener was registered and removed,
+ * {@code false} if the listener was not registered to begin with
+ * @throws IllegalArgumentException if {@code null} listener
+ */
+ public boolean removeEventListener(ScpTransferEventListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("No listener instance");
+ }
+
+ return listeners.remove(listener);
+ }
+
+ /**
* Parses a command string and verifies that the basic syntax is
* correct. If parsing fails the responsibility is delegated to
* the configured {@link CommandFactory} instance; if one exist.
@@ -179,7 +221,7 @@ public class ScpCommandFactory implements CommandFactory, Cloneable {
*/
public Command createCommand(String command) {
if (command.startsWith(SCP_COMMAND_PREFIX)) {
- return new ScpCommand(command, getExecutorService(), isShutdownOnExit(), getSendBufferSize(), getReceiveBufferSize());
+ return new ScpCommand(command, getExecutorService(), isShutdownOnExit(), getSendBufferSize(), getReceiveBufferSize(), listenerProxy);
}
CommandFactory factory = getDelegateCommandFactory();
@@ -193,7 +235,14 @@ public class ScpCommandFactory implements CommandFactory, Cloneable {
@Override
public ScpCommandFactory clone() {
try {
- return getClass().cast(super.clone()); // shallow clone is good enough
+ ScpCommandFactory other = getClass().cast(super.clone());
+ // clone the listeners set as well
+ other.listeners = this.listeners.isEmpty()
+ ? new CopyOnWriteArraySet<ScpTransferEventListener>()
+ : new CopyOnWriteArraySet<>(this.listeners)
+ ;
+ other.listenerProxy = EventListenerUtils.proxyWrapper(ScpTransferEventListener.class, getClass().getClassLoader(), other.listeners);
+ return other;
} catch(CloneNotSupportedException e) {
throw new RuntimeException(e); // un-expected...
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2cd0ebba/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java b/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
index 77f09b5..1e6d305 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
@@ -806,7 +806,7 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
Path p = resolveFile(path);
if (!Files.exists(p)) {
sendStatus(id, SSH_FX_NO_SUCH_FILE, p.toString());
- } else if (Files.isDirectory(p, LinkOption.NOFOLLOW_LINKS)) {
+ } else if (Files.isDirectory(p, IoUtils.getLinkOptions(false))) {
sendStatus(id, SSH_FX_NO_SUCH_FILE, p.toString());
} else {
Files.delete(p);
@@ -1521,7 +1521,7 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
}
if (view != null && value != null) {
try {
- Files.setAttribute(file, view + ":" + attribute, value, LinkOption.NOFOLLOW_LINKS);
+ Files.setAttribute(file, view + ":" + attribute, value, IoUtils.getLinkOptions(false));
} catch (UnsupportedOperationException e) {
unsupported.add(attribute);
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2cd0ebba/sshd-core/src/test/java/org/apache/sshd/ScpTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/ScpTest.java b/sshd-core/src/test/java/org/apache/sshd/ScpTest.java
index a92c4c7..7b33ca1 100644
--- a/sshd-core/src/test/java/org/apache/sshd/ScpTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/ScpTest.java
@@ -25,17 +25,21 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.FileChannel;
+import java.nio.file.Path;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.Collection;
import java.util.Properties;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.SCPClient;
-
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
-
import org.apache.sshd.client.ScpClient;
+import org.apache.sshd.common.scp.ScpTransferEventListener;
+import org.apache.sshd.common.util.OsUtils;
import org.apache.sshd.server.command.ScpCommandFactory;
import org.apache.sshd.util.BaseTest;
import org.apache.sshd.util.BogusPasswordAuthenticator;
@@ -44,9 +48,12 @@ import org.apache.sshd.util.JSchLogger;
import org.apache.sshd.util.SimpleUserInfo;
import org.apache.sshd.util.Utils;
import org.junit.After;
+import org.junit.Assume;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -101,413 +108,432 @@ public class ScpTest extends BaseTest {
@Test
public void testUploadAbsoluteDriveLetter() throws Exception {
- SshClient client = SshClient.setUpDefaultClient();
- client.start();
- ClientSession session = client.connect("test", "localhost", port).await().getSession();
- session.addPasswordIdentity("test");
- session.auth().verify();
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
- ScpClient scp = session.createScpClient();
+ try {
+ try (ClientSession session = client.connect("test", "localhost", port).await().getSession()) {
+ session.addPasswordIdentity("test");
+ session.auth().verify();
- String data = "0123456789\n";
+ ScpClient scp = createScpClient(session);
- File root = new File("target/scp");
- Utils.deleteRecursive(root);
- root.mkdirs();
- new File(root, "local").mkdirs();
- assertTrue(root.exists());
+ String data = "0123456789\n";
+ File root = new File("target/scp");
+ Utils.deleteRecursive(root);
+ assertHierarchyTargetFolderExists(new File(root, "local"));
+ assertTrue("Root folder not created", root.exists());
- writeFile(new File("target/scp/local/out.txt"), data);
- new File(root, "remote").mkdirs();
- scp.upload(new File("target/scp/local/out.txt").getAbsolutePath(), "/" + new File("target/scp/remote/out.txt").getAbsolutePath().replace(File.separatorChar, '/'));
- assertFileLength(new File("target/scp/remote/out.txt"), data.length(), 5000);
- scp.upload(new File("target/scp/local/out.txt").getAbsolutePath(), new File("target/scp/remote/out2.txt").getAbsolutePath());
- assertFileLength(new File("target/scp/remote/out2.txt"), data.length(), 5000);
+ writeFile(new File("target/scp/local/out.txt"), data);
+ assertHierarchyTargetFolderExists(new File(root, "remote"));
+ scp.upload(new File("target/scp/local/out.txt").getAbsolutePath(), "/" + new File("target/scp/remote/out.txt").getAbsolutePath().replace(File.separatorChar, '/'));
+ assertFileLength(new File("target/scp/remote/out.txt"), data.length(), 5000);
+ scp.upload(new File("target/scp/local/out.txt").getAbsolutePath(), new File("target/scp/remote/out2.txt").getAbsolutePath());
+ assertFileLength(new File("target/scp/remote/out2.txt"), data.length(), 5000);
+ }
+ } finally {
+ client.stop();
+ }
+ }
}
@Test
public void testScpUploadOverwrite() throws Exception {
- SshClient client = SshClient.setUpDefaultClient();
- client.start();
- ClientSession session = client.connect("test", "localhost", port).await().getSession();
- session.addPasswordIdentity("test");
- session.auth().verify();
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
- ScpClient scp = session.createScpClient();
+ try {
+ try (ClientSession session = client.connect("test", "localhost", port).await().getSession()) {
+ session.addPasswordIdentity("test");
+ session.auth().verify();
- String data = "0123456789\n";
+ ScpClient scp = createScpClient(session);
- File root = new File("target/scp");
- Utils.deleteRecursive(root);
- root.mkdirs();
- new File(root, "local").mkdirs();
- assertTrue(root.exists());
+ String data = "0123456789\n";
- new File(root, "remote").mkdirs();
- writeFile(new File("target/scp/remote/out.txt"), data + data);
+ File root = new File("target/scp");
+ Utils.deleteRecursive(root);
+ root.mkdirs();
+ new File(root, "local").mkdirs();
+ assertTrue(root.exists());
- writeFile(new File("target/scp/local/out.txt"), data);
- scp.upload("target/scp/local/out.txt", "target/scp/remote/out.txt");
- assertFileLength(new File("target/scp/remote/out.txt"), data.length(), 5000);
+ new File(root, "remote").mkdirs();
+ writeFile(new File("target/scp/remote/out.txt"), data + data);
- session.close(false).await();
- client.stop();
+ writeFile(new File("target/scp/local/out.txt"), data);
+ scp.upload("target/scp/local/out.txt", "target/scp/remote/out.txt");
+ assertFileLength(new File("target/scp/remote/out.txt"), data.length(), 5000);
+ }
+ } finally {
+ client.stop();
+ }
+ }
}
@Test
public void testScpUploadZeroLengthFile() throws Exception {
- File root=assertHierarchyTargetFolderExists(new File("target/scp"));
- File local=assertHierarchyTargetFolderExists(new File(root, "local"));
- File remote=assertHierarchyTargetFolderExists(new File(root, "remote"));
- File zeroLocal=new File(local, getCurrentTestName());
+ File root = assertHierarchyTargetFolderExists(new File("target/scp"));
+ File local = assertHierarchyTargetFolderExists(new File(root, "local"));
+ File remote = assertHierarchyTargetFolderExists(new File(root, "remote"));
+ File zeroLocal = new File(local, getCurrentTestName());
- FileOutputStream fout=new FileOutputStream(zeroLocal);
- try {
+ try (FileOutputStream fout = new FileOutputStream(zeroLocal)) {
if (zeroLocal.length() > 0L) {
- FileChannel fch=fout.getChannel();
+ FileChannel fch = fout.getChannel();
try {
fch.truncate(0L);
} finally {
fch.close();
}
}
- } finally {
- fout.close();
}
assertEquals("Non-zero size for local file=" + zeroLocal.getAbsolutePath(), 0L, zeroLocal.length());
- File zeroRemote=new File(remote, zeroLocal.getName());
+ File zeroRemote = new File(remote, zeroLocal.getName());
if (zeroRemote.exists()) {
assertTrue("Failed to delete remote target " + zeroRemote.getAbsolutePath(), zeroRemote.delete());
}
- SshClient client = SshClient.setUpDefaultClient();
- try {
- client.start();
-
- ClientSession session = client.connect("test", "localhost", port).await().getSession();
+ try (SshClient client = SshClient.setUpDefaultClient()) {
try {
- session.addPasswordIdentity("test");
- session.auth().verify();
-
- ScpClient scp = session.createScpClient();
- scp.upload("target/scp/local/" + zeroLocal.getName(), "target/scp/remote/" + zeroRemote.getName());
- assertFileLength(zeroRemote, 0L, TimeUnit.SECONDS.toMillis(5L));
+ client.start();
+
+ try (ClientSession session = client.connect("test", "localhost", port).await().getSession()) {
+ session.addPasswordIdentity("test");
+ session.auth().verify();
+
+ ScpClient scp = createScpClient(session);
+ scp.upload("target/scp/local/" + zeroLocal.getName(), "target/scp/remote/" + zeroRemote.getName());
+ assertFileLength(zeroRemote, 0L, TimeUnit.SECONDS.toMillis(5L));
+ }
} finally {
- session.close(false).await();
+ client.stop();
}
- } finally {
- client.stop();
}
}
@Test
public void testScpDownloadZeroLengthFile() throws Exception {
- File root=assertHierarchyTargetFolderExists(new File("target/scp"));
- File local=assertHierarchyTargetFolderExists(new File(root, "local"));
- File remote=assertHierarchyTargetFolderExists(new File(root, "remote"));
- File zeroLocal=new File(local, getCurrentTestName());
+ File root = assertHierarchyTargetFolderExists(new File("target/scp"));
+ File local = assertHierarchyTargetFolderExists(new File(root, "local"));
+ File remote = assertHierarchyTargetFolderExists(new File(root, "remote"));
+ File zeroLocal = new File(local, getCurrentTestName());
if (zeroLocal.exists()) {
assertTrue("Failed to delete local target " + zeroLocal.getAbsolutePath(), zeroLocal.delete());
}
- File zeroRemote=new File(remote, zeroLocal.getName());
- FileOutputStream fout=new FileOutputStream(zeroRemote);
- try {
+ File zeroRemote = new File(remote, zeroLocal.getName());
+ try (FileOutputStream fout = new FileOutputStream(zeroRemote)) {
if (zeroRemote.length() > 0L) {
- FileChannel fch=fout.getChannel();
+ FileChannel fch = fout.getChannel();
try {
fch.truncate(0L);
} finally {
fch.close();
}
}
- } finally {
- fout.close();
}
assertEquals("Non-zero size for remote file=" + zeroRemote.getAbsolutePath(), 0L, zeroRemote.length());
- SshClient client = SshClient.setUpDefaultClient();
- try {
- client.start();
-
- ClientSession session = client.connect("test", "localhost", port).await().getSession();
+ try (SshClient client = SshClient.setUpDefaultClient()) {
try {
- session.addPasswordIdentity("test");
- session.auth().verify();
-
- ScpClient scp = session.createScpClient();
- scp.download("target/scp/remote/" + zeroRemote.getName(), "target/scp/local/" + zeroLocal.getName());
- assertFileLength(zeroLocal, 0L, TimeUnit.SECONDS.toMillis(5L));
+ client.start();
+
+ try (ClientSession session = client.connect("test", "localhost", port).await().getSession()) {
+ session.addPasswordIdentity("test");
+ session.auth().verify();
+
+ ScpClient scp = createScpClient(session);
+ scp.download("target/scp/remote/" + zeroRemote.getName(), "target/scp/local/" + zeroLocal.getName());
+ assertFileLength(zeroLocal, 0L, TimeUnit.SECONDS.toMillis(5L));
+ }
} finally {
- session.close(false).await();
+ client.stop();
}
- } finally {
- client.stop();
}
}
@Test
public void testScpNativeOnSingleFile() throws Exception {
- SshClient client = SshClient.setUpDefaultClient();
- client.start();
- ClientSession session = client.connect("test", "localhost", port).await().getSession();
- session.addPasswordIdentity("test");
- session.auth().verify();
-
- ScpClient scp = session.createScpClient();
-
- String data = "0123456789\n";
-
- File root = new File("target/scp");
- Utils.deleteRecursive(root);
- root.mkdirs();
- new File(root, "local").mkdirs();
- assertTrue(root.exists());
-
-
- writeFile(new File("target/scp/local/out.txt"), data);
- try {
- scp.upload("target/scp/local/out.txt", "target/scp/remote/out.txt");
- fail("Expected IOException");
- } catch (IOException e) {
- // ok
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
+ try {
+ try (ClientSession session = client.connect("test", "localhost", port).await().getSession()) {
+ session.addPasswordIdentity("test");
+ session.auth().verify();
+
+ ScpClient scp = createScpClient(session);
+
+ String data = "0123456789\n";
+
+ File root = new File("target/scp");
+ Utils.deleteRecursive(root);
+ root.mkdirs();
+ new File(root, "local").mkdirs();
+ assertTrue(root.exists());
+
+
+ writeFile(new File("target/scp/local/out.txt"), data);
+ try {
+ scp.upload("target/scp/local/out.txt", "target/scp/remote/out.txt");
+ fail("Expected IOException");
+ } catch (IOException e) {
+ // ok
+ }
+ new File(root, "remote").mkdirs();
+ scp.upload("target/scp/local/out.txt", "target/scp/remote/out.txt");
+ assertFileLength(new File("target/scp/remote/out.txt"), data.length(), 5000);
+
+ scp.download("target/scp/remote/out.txt", "target/scp/local/out2.txt");
+ assertFileLength(new File("target/scp/local/out2.txt"), data.length(), 5000);
+ }
+ } finally {
+ client.stop();
+ }
}
- new File(root, "remote").mkdirs();
- scp.upload("target/scp/local/out.txt", "target/scp/remote/out.txt");
- assertFileLength(new File("target/scp/remote/out.txt"), data.length(), 5000);
-
- scp.download("target/scp/remote/out.txt", "target/scp/local/out2.txt");
- assertFileLength(new File("target/scp/local/out2.txt"), data.length(), 5000);
-
- session.close(false).await();
- client.stop();
}
@Test
public void testScpNativeOnMultipleFiles() throws Exception {
- SshClient client = SshClient.setUpDefaultClient();
- client.start();
- ClientSession session = client.connect("test", "localhost", port).await().getSession();
- session.addPasswordIdentity("test");
- session.auth().verify();
-
- ScpClient scp = session.createScpClient();
-
- String data = "0123456789\n";
-
- File root = new File("target/scp");
- Utils.deleteRecursive(root);
- root.mkdirs();
- new File(root, "local").mkdirs();
- new File(root, "remote").mkdirs();
- assertTrue(root.exists());
-
-
- writeFile(new File("target/scp/local/out1.txt"), data);
- writeFile(new File("target/scp/local/out2.txt"), data);
- try {
- scp.upload(new String[] { "target/scp/local/out1.txt", "target/scp/local/out2.txt" }, "target/scp/remote/out.txt");
- fail("Expected IOException");
- } catch (IOException e) {
- // Ok
- }
- writeFile(new File("target/scp/remote/out.txt"), data);
- try {
- scp.upload(new String[] { "target/scp/local/out1.txt", "target/scp/local/out2.txt" }, "target/scp/remote/out.txt");
- fail("Expected IOException");
- } catch (IOException e) {
- // Ok
- }
- new File(root, "remote/dir").mkdirs();
- scp.upload(new String[] { "target/scp/local/out1.txt", "target/scp/local/out2.txt" }, "target/scp/remote/dir");
- assertFileLength(new File("target/scp/remote/dir/out1.txt"), data.length(), 5000);
- assertFileLength(new File("target/scp/remote/dir/out2.txt"), data.length(), 5000);
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
- try {
- scp.download(new String[] { "target/scp/remote/dir/out1.txt", "target/scp/remote/dir/out2.txt" }, "target/scp/local/out1.txt");
- fail("Expected IOException");
- } catch (IOException e) {
- // Ok
- }
- try {
- scp.download(new String[] { "target/scp/remote/dir/out1.txt", "target/scp/remote/dir/out2.txt" }, "target/scp/local/dir");
- fail("Expected IOException");
- } catch (IOException e) {
- // Ok
+ try {
+ try (ClientSession session = client.connect("test", "localhost", port).await().getSession()) {
+ session.addPasswordIdentity("test");
+ session.auth().verify();
+
+ ScpClient scp = createScpClient(session);
+
+ String data = "0123456789\n";
+
+ File root = new File("target/scp");
+ Utils.deleteRecursive(root);
+ root.mkdirs();
+ new File(root, "local").mkdirs();
+ new File(root, "remote").mkdirs();
+ assertTrue(root.exists());
+
+ writeFile(new File("target/scp/local/out1.txt"), data);
+ writeFile(new File("target/scp/local/out2.txt"), data);
+ try {
+ scp.upload(new String[]{"target/scp/local/out1.txt", "target/scp/local/out2.txt"}, "target/scp/remote/out.txt");
+ fail("Expected IOException");
+ } catch (IOException e) {
+ // Ok
+ }
+ writeFile(new File("target/scp/remote/out.txt"), data);
+ try {
+ scp.upload(new String[]{"target/scp/local/out1.txt", "target/scp/local/out2.txt"}, "target/scp/remote/out.txt");
+ fail("Expected IOException");
+ } catch (IOException e) {
+ // Ok
+ }
+ new File(root, "remote/dir").mkdirs();
+ scp.upload(new String[]{"target/scp/local/out1.txt", "target/scp/local/out2.txt"}, "target/scp/remote/dir");
+ assertFileLength(new File("target/scp/remote/dir/out1.txt"), data.length(), 5000);
+ assertFileLength(new File("target/scp/remote/dir/out2.txt"), data.length(), 5000);
+
+ try {
+ scp.download(new String[]{"target/scp/remote/dir/out1.txt", "target/scp/remote/dir/out2.txt"}, "target/scp/local/out1.txt");
+ fail("Expected IOException");
+ } catch (IOException e) {
+ // Ok
+ }
+ try {
+ scp.download(new String[]{"target/scp/remote/dir/out1.txt", "target/scp/remote/dir/out2.txt"}, "target/scp/local/dir");
+ fail("Expected IOException");
+ } catch (IOException e) {
+ // Ok
+ }
+ new File(root, "local/dir").mkdirs();
+ scp.download(new String[]{"target/scp/remote/dir/out1.txt", "target/scp/remote/dir/out2.txt"}, "target/scp/local/dir");
+ assertFileLength(new File("target/scp/local/dir/out1.txt"), data.length(), 5000);
+ assertFileLength(new File("target/scp/local/dir/out2.txt"), data.length(), 5000);
+ }
+ } finally {
+ client.stop();
+ }
}
- new File(root, "local/dir").mkdirs();
- scp.download(new String[] { "target/scp/remote/dir/out1.txt", "target/scp/remote/dir/out2.txt" }, "target/scp/local/dir");
- assertFileLength(new File("target/scp/local/dir/out1.txt"), data.length(), 5000);
- assertFileLength(new File("target/scp/local/dir/out2.txt"), data.length(), 5000);
-
- session.close(false).await();
- client.stop();
}
@Test
public void testScpNativeOnRecursiveDirs() throws Exception {
- SshClient client = SshClient.setUpDefaultClient();
- client.start();
- ClientSession session = client.connect("test", "localhost", port).await().getSession();
- session.addPasswordIdentity("test");
- session.auth().verify();
-
- ScpClient scp = session.createScpClient();
-
- String data = "0123456789\n";
-
- File root = new File("target/scp");
- Utils.deleteRecursive(root);
- root.mkdirs();
- new File(root, "local").mkdirs();
- new File(root, "remote").mkdirs();
- assertTrue(root.exists());
-
- new File("target/scp/local/dir").mkdirs();
- writeFile(new File("target/scp/local/dir/out1.txt"), data);
- writeFile(new File("target/scp/local/dir/out2.txt"), data);
- scp.upload("target/scp/local/dir", "target/scp/remote/", ScpClient.Option.Recursive);
- assertFileLength(new File("target/scp/remote/dir/out1.txt"), data.length(), 5000);
- assertFileLength(new File("target/scp/remote/dir/out2.txt"), data.length(), 5000);
-
- Utils.deleteRecursive(new File("target/scp/local/dir"));
- scp.download("target/scp/remote/dir", "target/scp/local", ScpClient.Option.Recursive);
- assertFileLength(new File("target/scp/local/dir/out1.txt"), data.length(), 5000);
- assertFileLength(new File("target/scp/local/dir/out2.txt"), data.length(), 5000);
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
- session.close(false).await();
- client.stop();
+ try {
+ try (ClientSession session = client.connect("test", "localhost", port).await().getSession()) {
+ session.addPasswordIdentity("test");
+ session.auth().verify();
+
+ ScpClient scp = createScpClient(session);
+
+ String data = "0123456789\n";
+
+ File root = new File("target/scp");
+ Utils.deleteRecursive(root);
+ root.mkdirs();
+ new File(root, "local").mkdirs();
+ new File(root, "remote").mkdirs();
+ assertTrue(root.exists());
+
+ new File("target/scp/local/dir").mkdirs();
+ writeFile(new File("target/scp/local/dir/out1.txt"), data);
+ writeFile(new File("target/scp/local/dir/out2.txt"), data);
+ scp.upload("target/scp/local/dir", "target/scp/remote/", ScpClient.Option.Recursive);
+ assertFileLength(new File("target/scp/remote/dir/out1.txt"), data.length(), 5000);
+ assertFileLength(new File("target/scp/remote/dir/out2.txt"), data.length(), 5000);
+
+ Utils.deleteRecursive(new File("target/scp/local/dir"));
+ scp.download("target/scp/remote/dir", "target/scp/local", ScpClient.Option.Recursive);
+ assertFileLength(new File("target/scp/local/dir/out1.txt"), data.length(), 5000);
+ assertFileLength(new File("target/scp/local/dir/out2.txt"), data.length(), 5000);
+ }
+ } finally {
+ client.stop();
+ }
+ }
}
@Test
public void testScpNativeOnDirWithPattern() throws Exception {
- SshClient client = SshClient.setUpDefaultClient();
- client.start();
- ClientSession session = client.connect("test", "localhost", port).await().getSession();
- session.addPasswordIdentity("test");
- session.auth().verify();
-
- ScpClient scp = session.createScpClient();
-
- String data = "0123456789\n";
-
- File root = new File("target/scp");
- Utils.deleteRecursive(root);
- root.mkdirs();
- new File(root, "local").mkdirs();
- new File(root, "remote").mkdirs();
- assertTrue(root.exists());
-
- writeFile(new File("target/scp/local/out1.txt"), data);
- writeFile(new File("target/scp/local/out2.txt"), data);
- scp.upload("target/scp/local/*", "target/scp/remote/");
- assertFileLength(new File("target/scp/remote/out1.txt"), data.length(), 5000);
- assertFileLength(new File("target/scp/remote/out2.txt"), data.length(), 5000);
-
- new File("target/scp/local/out1.txt").delete();
- new File("target/scp/local/out2.txt").delete();
- scp.download("target/scp/remote/*", "target/scp/local");
- assertFileLength(new File("target/scp/local/out1.txt"), data.length(), 5000);
- assertFileLength(new File("target/scp/local/out2.txt"), data.length(), 5000);
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
- session.close(false).await();
- client.stop();
+ try {
+ try (ClientSession session = client.connect("test", "localhost", port).await().getSession()) {
+ session.addPasswordIdentity("test");
+ session.auth().verify();
+
+ ScpClient scp = createScpClient(session);
+
+ String data = "0123456789\n";
+
+ File root = new File("target/scp");
+ Utils.deleteRecursive(root);
+ root.mkdirs();
+ new File(root, "local").mkdirs();
+ new File(root, "remote").mkdirs();
+ assertTrue(root.exists());
+
+ writeFile(new File("target/scp/local/out1.txt"), data);
+ writeFile(new File("target/scp/local/out2.txt"), data);
+ scp.upload("target/scp/local/*", "target/scp/remote/");
+ assertFileLength(new File("target/scp/remote/out1.txt"), data.length(), 5000);
+ assertFileLength(new File("target/scp/remote/out2.txt"), data.length(), 5000);
+
+ new File("target/scp/local/out1.txt").delete();
+ new File("target/scp/local/out2.txt").delete();
+ scp.download("target/scp/remote/*", "target/scp/local");
+ assertFileLength(new File("target/scp/local/out1.txt"), data.length(), 5000);
+ assertFileLength(new File("target/scp/local/out2.txt"), data.length(), 5000);
+ }
+ } finally {
+ client.stop();
+ }
+ }
}
@Test
public void testScpNativeOnMixedDirAndFiles() throws Exception {
- SshClient client = SshClient.setUpDefaultClient();
- client.start();
- ClientSession session = client.connect("test", "localhost", port).await().getSession();
- session.addPasswordIdentity("test");
- session.auth().verify();
-
- ScpClient scp = session.createScpClient();
-
- String data = "0123456789\n";
-
- File root = new File("target/scp");
- Utils.deleteRecursive(root);
- root.mkdirs();
- new File(root, "local").mkdirs();
- new File(root, "remote").mkdirs();
- assertTrue(root.exists());
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
- new File("target/scp/local/dir").mkdirs();
- writeFile(new File("target/scp/local/out1.txt"), data);
- writeFile(new File("target/scp/local/dir/out2.txt"), data);
- scp.upload("target/scp/local/*", "target/scp/remote/", ScpClient.Option.Recursive);
- assertFileLength(new File("target/scp/remote/out1.txt"), data.length(), 5000);
- assertFileLength(new File("target/scp/remote/dir/out2.txt"), data.length(), 5000);
-
- Utils.deleteRecursive(new File("target/scp/local/out1.txt"));
- Utils.deleteRecursive(new File("target/scp/local/dir"));
- scp.download("target/scp/remote/*", "target/scp/local");
- assertFileLength(new File("target/scp/local/out1.txt"), data.length(), 5000);
- assertFalse(new File("target/scp/local/dir/out2.txt").exists());
-
- Utils.deleteRecursive(new File("target/scp/local/out1.txt"));
- scp.download("target/scp/remote/*", "target/scp/local", ScpClient.Option.Recursive);
- assertFileLength(new File("target/scp/local/out1.txt"), data.length(), 5000);
- assertFileLength(new File("target/scp/local/dir/out2.txt"), data.length(), 5000);
-
- session.close(false).await();
- client.stop();
+ try {
+ try (ClientSession session = client.connect("test", "localhost", port).await().getSession()) {
+ session.addPasswordIdentity("test");
+ session.auth().verify();
+
+ ScpClient scp = createScpClient(session);
+
+ String data = "0123456789\n";
+
+ File root = new File("target/scp");
+ Utils.deleteRecursive(root);
+ root.mkdirs();
+ new File(root, "local").mkdirs();
+ new File(root, "remote").mkdirs();
+ assertTrue(root.exists());
+
+ new File("target/scp/local/dir").mkdirs();
+ writeFile(new File("target/scp/local/out1.txt"), data);
+ writeFile(new File("target/scp/local/dir/out2.txt"), data);
+ scp.upload("target/scp/local/*", "target/scp/remote/", ScpClient.Option.Recursive);
+ assertFileLength(new File("target/scp/remote/out1.txt"), data.length(), 5000);
+ assertFileLength(new File("target/scp/remote/dir/out2.txt"), data.length(), 5000);
+
+ Utils.deleteRecursive(new File("target/scp/local/out1.txt"));
+ Utils.deleteRecursive(new File("target/scp/local/dir"));
+ scp.download("target/scp/remote/*", "target/scp/local");
+ assertFileLength(new File("target/scp/local/out1.txt"), data.length(), 5000);
+ assertFalse(new File("target/scp/local/dir/out2.txt").exists());
+
+ Utils.deleteRecursive(new File("target/scp/local/out1.txt"));
+ scp.download("target/scp/remote/*", "target/scp/local", ScpClient.Option.Recursive);
+ assertFileLength(new File("target/scp/local/out1.txt"), data.length(), 5000);
+ assertFileLength(new File("target/scp/local/dir/out2.txt"), data.length(), 5000);
+ }
+ } finally {
+ client.stop();
+ }
+ }
}
@Test
public void testScpNativePreserveAttributes() throws Exception {
// Ignore this test if running a Windows system
- if (System.getProperty("os.name").toLowerCase().contains("win")) {
- return;
- }
-
- SshClient client = SshClient.setUpDefaultClient();
- client.start();
- ClientSession session = client.connect("test", "localhost", port).await().getSession();
- session.addPasswordIdentity("test");
- session.auth().verify();
+ Assume.assumeFalse("Skip test for Windows", OsUtils.isWin32());
- ScpClient scp = session.createScpClient();
-
- String data = "0123456789\n";
-
- File root = new File("target/scp");
- Utils.deleteRecursive(root);
- root.mkdirs();
- new File(root, "local").mkdirs();
- new File(root, "remote").mkdirs();
- assertTrue(root.exists());
+ try (SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
- new File("target/scp/local/dir").mkdirs();
- long lastMod = new File("target/scp/local/dir").lastModified() - TimeUnit.DAYS.toMillis(1);
-
- writeFile(new File("target/scp/local/out1.txt"), data);
- writeFile(new File("target/scp/local/dir/out2.txt"), data);
- new File("target/scp/local/out1.txt").setLastModified(lastMod);
- new File("target/scp/local/out1.txt").setExecutable(true, true);
- new File("target/scp/local/out1.txt").setWritable(false, false);
- new File("target/scp/local/dir/out2.txt").setLastModified(lastMod);
- scp.upload("target/scp/local/*", "target/scp/remote/", ScpClient.Option.Recursive, ScpClient.Option.PreserveAttributes);
- assertFileLength(new File("target/scp/remote/out1.txt"), data.length(), 5000);
- assertEquals(lastMod, new File("target/scp/remote/out1.txt").lastModified());
- assertFileLength(new File("target/scp/remote/dir/out2.txt"), data.length(), 5000);
- assertEquals(lastMod, new File("target/scp/remote/dir/out2.txt").lastModified());
-
- Utils.deleteRecursive(new File("target/scp/local"));
- new File("target/scp/local").mkdirs();
- scp.download("target/scp/remote/*", "target/scp/local", ScpClient.Option.Recursive, ScpClient.Option.PreserveAttributes);
- assertFileLength(new File("target/scp/local/out1.txt"), data.length(), 5000);
- assertEquals(lastMod, new File("target/scp/local/out1.txt").lastModified());
- assertFileLength(new File("target/scp/local/dir/out2.txt"), data.length(), 5000);
- assertEquals(lastMod, new File("target/scp/local/dir/out2.txt").lastModified());
-
- session.close(false).await();
- client.stop();
+ try {
+ try (ClientSession session = client.connect("test", "localhost", port).await().getSession()) {
+ session.addPasswordIdentity("test");
+ session.auth().verify();
+
+ ScpClient scp = createScpClient(session);
+
+ String data = "0123456789\n";
+
+ File root = new File("target/scp");
+ Utils.deleteRecursive(root);
+ root.mkdirs();
+ new File(root, "local").mkdirs();
+ new File(root, "remote").mkdirs();
+ assertTrue(root.exists());
+
+ new File("target/scp/local/dir").mkdirs();
+ long lastMod = new File("target/scp/local/dir").lastModified() - TimeUnit.DAYS.toMillis(1);
+
+ writeFile(new File("target/scp/local/out1.txt"), data);
+ writeFile(new File("target/scp/local/dir/out2.txt"), data);
+ new File("target/scp/local/out1.txt").setLastModified(lastMod);
+ new File("target/scp/local/out1.txt").setExecutable(true, true);
+ new File("target/scp/local/out1.txt").setWritable(false, false);
+ new File("target/scp/local/dir/out2.txt").setLastModified(lastMod);
+ scp.upload("target/scp/local/*", "target/scp/remote/", ScpClient.Option.Recursive, ScpClient.Option.PreserveAttributes);
+ assertFileLength(new File("target/scp/remote/out1.txt"), data.length(), 5000);
+ assertEquals(lastMod, new File("target/scp/remote/out1.txt").lastModified());
+ assertFileLength(new File("target/scp/remote/dir/out2.txt"), data.length(), 5000);
+ assertEquals(lastMod, new File("target/scp/remote/dir/out2.txt").lastModified());
+
+ Utils.deleteRecursive(new File("target/scp/local"));
+ new File("target/scp/local").mkdirs();
+ scp.download("target/scp/remote/*", "target/scp/local", ScpClient.Option.Recursive, ScpClient.Option.PreserveAttributes);
+ assertFileLength(new File("target/scp/local/out1.txt"), data.length(), 5000);
+ assertEquals(lastMod, new File("target/scp/local/out1.txt").lastModified());
+ assertFileLength(new File("target/scp/local/dir/out2.txt"), data.length(), 5000);
+ assertEquals(lastMod, new File("target/scp/local/dir/out2.txt").lastModified());
+ }
+ } finally {
+ client.stop();
+ }
+ }
}
private void writeFile(File file, String data) throws IOException {
@@ -598,7 +624,7 @@ public class ScpTest extends BaseTest {
}
}
- protected void assertFileLength(File file, long length, long timeout) throws Exception{
+ protected void assertFileLength(File file, long length, long timeout) throws Exception {
boolean ok = false;
while (timeout > 0) {
if (file.exists() && file.length() == length) {
@@ -694,7 +720,7 @@ public class ScpTest extends BaseTest {
InputStream is = c.getInputStream();
c.connect();
assertEquals(0, is.read());
- os.write(("C7777 "+ data.length() + " " + name + "\n").getBytes());
+ os.write(("C7777 " + data.length() + " " + name + "\n").getBytes());
os.flush();
assertEquals(0, is.read());
os.write(data.getBytes());
@@ -713,7 +739,7 @@ public class ScpTest extends BaseTest {
c.setCommand("scp -t " + path);
c.connect();
assertEquals(0, is.read());
- os.write(("C7777 "+ data.length() + " " + name + "\n").getBytes());
+ os.write(("C7777 " + data.length() + " " + name + "\n").getBytes());
os.flush();
assertEquals(2, is.read());
c.disconnect();
@@ -742,9 +768,9 @@ public class ScpTest extends BaseTest {
assertEquals(0, is.read());
}
- private String readLine(InputStream in) throws IOException {
+ private static String readLine(InputStream in) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- for (;;) {
+ for (; ; ) {
int c = in.read();
if (c == '\n') {
return baos.toString();
@@ -756,4 +782,43 @@ public class ScpTest extends BaseTest {
}
}
+ private ScpClient createScpClient(ClientSession session) {
+ final Logger logger = LoggerFactory.getLogger(getClass().getName() + "[" + getCurrentTestName() + "]");
+ return session.createScpClient(new ScpTransferEventListener() {
+ @Override
+ public void startFolderEvent(FileOperation op, Path file, Set<PosixFilePermission> perms) {
+ logEvent("starFolderEvent", op, file, false, -1L, perms, null);
+ }
+
+ @Override
+ public void startFileEvent(FileOperation op, Path file, long length, Set<PosixFilePermission> perms) {
+ logEvent("startFileEvent", op, file, true, length, perms, null);
+
+ }
+
+ @Override
+ public void endFolderEvent(FileOperation op, Path file, Set<PosixFilePermission> perms, Throwable thrown) {
+ logEvent("endFolderEvent", op, file, false, -1L, perms, thrown);
+ }
+
+ @Override
+ public void endFileEvent(FileOperation op, Path file, long length, Set<PosixFilePermission> perms, Throwable thrown) {
+ logEvent("endFileEvent", op, file, true, length, perms, thrown);
+ }
+
+ private void logEvent(String type, FileOperation op, Path path, boolean isFile, long length, Collection<PosixFilePermission> perms, Throwable t) {
+ StringBuilder sb = new StringBuilder(Byte.MAX_VALUE);
+ sb.append('\t').append(type)
+ .append('[').append(op).append(']')
+ .append(' ').append(isFile ? "File" : "Directory").append('=').append(path)
+ .append(' ').append("length=").append(length)
+ .append(' ').append("perms=").append(perms)
+ ;
+ if (t != null) {
+ sb.append(' ').append("ERROR=").append(t.getClass().getSimpleName()).append(": ").append(t.getMessage());
+ }
+ logger.info(sb.toString());
+ }
+ });
+ }
}