You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2015/05/26 13:28:07 UTC
mina-sshd git commit: [SSHD-472] Create a Closeable SFTP Handle
Repository: mina-sshd
Updated Branches:
refs/heads/master 8009a89f9 -> d7939e253
[SSHD-472] Create a Closeable SFTP Handle
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/d7939e25
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/d7939e25
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/d7939e25
Branch: refs/heads/master
Commit: d7939e2530d009f62ee6595f5f26c4c4ac58fe25
Parents: 8009a89
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Tue May 26 14:27:56 2015 +0300
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Tue May 26 14:27:56 2015 +0300
----------------------------------------------------------------------
.../java/org/apache/sshd/ClientSession.java | 2 +-
.../java/org/apache/sshd/client/SftpClient.java | 275 ------------------
.../sshd/client/session/ClientSessionImpl.java | 2 +-
.../sshd/client/sftp/AbstractSftpClient.java | 93 ++++++
.../client/sftp/DefaultCloseableHandle.java | 55 ++++
.../sshd/client/sftp/DefaultSftpClient.java | 232 ++++++++-------
.../org/apache/sshd/client/sftp/SftpClient.java | 289 +++++++++++++++++++
.../sshd/client/sftp/SftpFileChannel.java | 1 -
.../apache/sshd/client/sftp/SftpFileSystem.java | 14 +-
.../client/sftp/SftpFileSystemProvider.java | 6 +-
.../apache/sshd/common/sftp/SftpConstants.java | 2 +-
.../sshd/server/sftp/SftpSubsystemFactory.java | 3 +-
.../test/java/org/apache/sshd/ClientTest.java | 3 +-
.../client/sftp/DefaultCloseableHandleTest.java | 87 ++++++
.../sshd/client/sftp/SftpFileSystemTest.java | 5 +-
.../org/apache/sshd/client/sftp/SftpTest.java | 111 +++----
16 files changed, 704 insertions(+), 476 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d7939e25/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 fca6b4a..822e072 100644
--- a/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
@@ -25,13 +25,13 @@ import java.util.Map;
import org.apache.sshd.client.ClientFactoryManager;
import org.apache.sshd.client.ScpClient;
-import org.apache.sshd.client.SftpClient;
import org.apache.sshd.client.UserInteraction;
import org.apache.sshd.client.channel.ChannelDirectTcpip;
import org.apache.sshd.client.channel.ChannelExec;
import org.apache.sshd.client.channel.ChannelShell;
import org.apache.sshd.client.channel.ChannelSubsystem;
import org.apache.sshd.client.future.AuthFuture;
+import org.apache.sshd.client.sftp.SftpClient;
import org.apache.sshd.common.Session;
import org.apache.sshd.common.SshdSocketAddress;
import org.apache.sshd.common.future.CloseFuture;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d7939e25/sshd-core/src/main/java/org/apache/sshd/client/SftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/SftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/SftpClient.java
deleted file mode 100644
index 3b8840c..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/SftpClient.java
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * 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.client;
-
-import static org.apache.sshd.common.sftp.SftpConstants.S_IFDIR;
-import static org.apache.sshd.common.sftp.SftpConstants.S_IFLNK;
-import static org.apache.sshd.common.sftp.SftpConstants.S_IFMT;
-import static org.apache.sshd.common.sftp.SftpConstants.S_IFREG;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.file.attribute.FileTime;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-/**
- * @author <a href="http://mina.apache.org">Apache MINA Project</a>
- */
-public interface SftpClient extends Closeable {
-
- enum OpenMode {
- Read,
- Write,
- Append,
- Create,
- Truncate,
- Exclusive
- }
-
- enum CopyMode {
- Atomic,
- Overwrite
- }
-
- enum Attribute {
- Size,
- UidGid,
- Perms,
- AcModTime,
- OwnerGroup,
- AccessTime,
- ModifyTime,
- CreateTime,
- }
-
- public static class Handle {
- public final String id;
- public Handle(String id) {
- this.id = id;
- }
-
- @Override
- public String toString() {
- return id;
- }
- }
-
- public static class Attributes {
- public final Set<Attribute> flags = EnumSet.noneOf(Attribute.class);
- public long size;
- public byte type;
- public int uid;
- public int gid;
- public int perms;
- public int atime;
- public int ctime;
- public int mtime;
- public String owner;
- public String group;
- public FileTime accessTime;
- public FileTime createTime;
- public FileTime modifyTime;
-
- @Override
- public String toString() {
- return "type=" + type
- + ";size=" + size
- + ";uid=" + uid
- + ";gid=" + gid
- + ";perms=0x" + Integer.toHexString(perms)
- + ";flags=" + flags
- + ";owner=" + owner
- + ";group=" + group
- + ";aTime=(" + atime + ")[" + accessTime + "]"
- + ";cTime=(" + ctime + ")[" + createTime + "]"
- + ";mTime=(" + mtime + ")[" + modifyTime + "]"
- ;
- }
-
- public Attributes size(long size) {
- flags.add(Attribute.Size);
- this.size = size;
- return this;
- }
- public Attributes owner(String owner) {
- flags.add(Attribute.OwnerGroup);
- this.owner = owner;
- if (group == null) {
- group = "GROUP@";
- }
- return this;
- }
- public Attributes group(String group) {
- flags.add(Attribute.OwnerGroup);
- this.group = group;
- if (owner == null) {
- owner = "OWNER@";
- }
- return this;
- }
- public Attributes owner(int uid, int gid) {
- flags.add(Attribute.UidGid);
- this.uid = uid;
- this.gid = gid;
- return this;
- }
- public Attributes perms(int perms) {
- flags.add(Attribute.Perms);
- this.perms = perms;
- return this;
- }
- public Attributes atime(int atime) {
- flags.add(Attribute.AccessTime);
- this.atime = atime;
- this.accessTime = FileTime.from(atime, TimeUnit.SECONDS);
- return this;
- }
- public Attributes ctime(int ctime) {
- flags.add(Attribute.CreateTime);
- this.ctime = ctime;
- this.createTime = FileTime.from(atime, TimeUnit.SECONDS);
- return this;
- }
- public Attributes mtime(int mtime) {
- flags.add(Attribute.ModifyTime);
- this.mtime = mtime;
- this.modifyTime = FileTime.from(atime, TimeUnit.SECONDS);
- return this;
- }
- public Attributes time(int atime, int mtime) {
- flags.add(Attribute.AcModTime);
- this.atime = atime;
- this.mtime = mtime;
- return this;
- }
- public Attributes accessTime(FileTime atime) {
- flags.add(Attribute.AccessTime);
- this.atime = (int) atime.to(TimeUnit.SECONDS);
- this.accessTime = atime;
- return this;
- }
- public Attributes createTime(FileTime ctime) {
- flags.add(Attribute.CreateTime);
- this.ctime = (int) ctime.to(TimeUnit.SECONDS);
- this.createTime = ctime;
- return this;
- }
- public Attributes modifyTime(FileTime mtime) {
- flags.add(Attribute.ModifyTime);
- this.mtime = (int) mtime.to(TimeUnit.SECONDS);
- this.modifyTime = mtime;
- return this;
- }
- public boolean isRegularFile() {
- return (perms & S_IFMT) == S_IFREG;
- }
- public boolean isDirectory() {
- return (perms & S_IFMT) == S_IFDIR;
- }
- public boolean isSymbolicLink() {
- return (perms & S_IFMT) == S_IFLNK;
- }
- public boolean isOther() {
- return !isRegularFile() && !isDirectory() && !isSymbolicLink();
- }
- }
-
- public static class DirEntry {
- public String filename;
- public String longFilename;
- public Attributes attributes;
- public DirEntry(String filename, String longFilename, Attributes attributes) {
- this.filename = filename;
- this.longFilename = longFilename;
- this.attributes = attributes;
- }
- }
-
- int getVersion();
-
- boolean isClosing();
-
- //
- // Low level API
- //
-
- Handle open(String path, Collection<OpenMode> options) throws IOException;
-
- void close(Handle handle) throws IOException;
-
- void remove(String path) throws IOException;
-
- void rename(String oldPath, String newPath) throws IOException;
-
- void rename(String oldPath, String newPath, CopyMode... options) throws IOException;
-
- int read(Handle handle, long fileOffset, byte[] dst, int dstoff, int len) throws IOException;
-
- void write(Handle handle, long fileOffset, byte[] src, int srcoff, int len) throws IOException;
-
- void mkdir(String path) throws IOException;
-
- void rmdir(String path) throws IOException;
-
- Handle openDir(String path) throws IOException;
-
- DirEntry[] readDir(Handle handle) throws IOException;
-
- String canonicalPath(String canonical) throws IOException;
-
- Attributes stat(String path) throws IOException;
-
- Attributes lstat(String path) throws IOException;
-
- Attributes stat(Handle handle) throws IOException;
-
- void setStat(String path, Attributes attributes) throws IOException;
-
- void setStat(Handle handle, Attributes attributes) throws IOException;
-
- String readLink(String path) throws IOException;
-
- void symLink(String linkPath, String targetPath) throws IOException;
-
- void link(String linkPath, String targetPath, boolean symbolic) throws IOException;
-
- void lock(Handle handle, long offset, long length, int mask) throws IOException;
-
- void unlock(Handle handle, long offset, long length) throws IOException;
-
- //
- // High level API
- //
-
- Iterable<DirEntry> readDir(String path) throws IOException;
-
- InputStream read(String path) throws IOException;
-
- InputStream read(String path, Collection<OpenMode> mode) throws IOException;
-
- OutputStream write(String path) throws IOException;
-
- OutputStream write(String path, Collection<OpenMode> mode) throws IOException;
-
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d7939e25/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 6761a88..c9a1656 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
@@ -32,7 +32,6 @@ import org.apache.sshd.ClientSession;
import org.apache.sshd.client.ClientFactoryManager;
import org.apache.sshd.client.ScpClient;
import org.apache.sshd.client.ServerKeyVerifier;
-import org.apache.sshd.client.SftpClient;
import org.apache.sshd.client.UserInteraction;
import org.apache.sshd.client.channel.ChannelDirectTcpip;
import org.apache.sshd.client.channel.ChannelExec;
@@ -42,6 +41,7 @@ import org.apache.sshd.client.future.AuthFuture;
import org.apache.sshd.client.future.DefaultAuthFuture;
import org.apache.sshd.client.scp.DefaultScpClient;
import org.apache.sshd.client.sftp.DefaultSftpClient;
+import org.apache.sshd.client.sftp.SftpClient;
import org.apache.sshd.client.sftp.SftpFileSystem;
import org.apache.sshd.client.sftp.SftpFileSystemProvider;
import org.apache.sshd.common.NamedResource;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d7939e25/sshd-core/src/main/java/org/apache/sshd/client/sftp/AbstractSftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/AbstractSftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/AbstractSftpClient.java
new file mode 100644
index 0000000..b1533c1
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/sftp/AbstractSftpClient.java
@@ -0,0 +1,93 @@
+/*
+ * 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.client.sftp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.EnumSet;
+
+import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.GenericUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractSftpClient extends AbstractLoggingBean implements SftpClient {
+ protected AbstractSftpClient() {
+ super();
+ }
+
+ @Override
+ public CloseableHandle open(String path) throws IOException {
+ return open(path, Collections.<OpenMode>emptySet());
+ }
+
+ @Override
+ public CloseableHandle open(String path, OpenMode ... options) throws IOException {
+ return open(path, GenericUtils.of(options));
+ }
+
+ @Override
+ public void rename(String oldPath, String newPath) throws IOException {
+ rename(oldPath, newPath, Collections.<CopyMode>emptySet());
+ }
+
+ @Override
+ public void rename(String oldPath, String newPath, CopyMode ... options) throws IOException {
+ rename(oldPath, newPath, GenericUtils.of(options));
+ }
+
+ @Override
+ public InputStream read(final String path) throws IOException {
+ return read(path, EnumSet.of(OpenMode.Read));
+ }
+
+ @Override
+ public InputStream read(String path, OpenMode ... mode) throws IOException {
+ return read(path, GenericUtils.of(mode));
+ }
+
+ @Override
+ public int read(Handle handle, long fileOffset, byte[] dst) throws IOException {
+ return read(handle, fileOffset, dst, 0, dst.length);
+ }
+
+ @Override
+ public OutputStream write(final String path) throws IOException {
+ return write(path, EnumSet.of(OpenMode.Write, OpenMode.Create, OpenMode.Truncate));
+ }
+
+ @Override
+ public OutputStream write(String path, OpenMode ... mode) throws IOException {
+ return write(path, GenericUtils.of(mode));
+ }
+
+ @Override
+ public void write(Handle handle, long fileOffset, byte[] src) throws IOException {
+ write(handle, fileOffset, src, 0, src.length);
+ }
+
+ @Override
+ public void symLink(String linkPath, String targetPath) throws IOException {
+ link(linkPath, targetPath, true);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d7939e25/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultCloseableHandle.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultCloseableHandle.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultCloseableHandle.java
new file mode 100644
index 0000000..f86c47e
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultCloseableHandle.java
@@ -0,0 +1,55 @@
+/*
+ * 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.client.sftp;
+
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.sshd.client.sftp.SftpClient.CloseableHandle;
+import org.apache.sshd.common.util.ValidateUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class DefaultCloseableHandle extends CloseableHandle {
+ private final AtomicBoolean open = new AtomicBoolean(true);
+ private final SftpClient client;
+
+ public DefaultCloseableHandle(SftpClient client, String id) {
+ super(id);
+ this.client = ValidateUtils.checkNotNull(client, "No client for id=%s", id);
+ }
+
+ public final SftpClient getSftpClient() {
+ return client;
+ }
+
+ @Override
+ public boolean isOpen() {
+ return open.get();
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (open.getAndSet(false)) {
+ client.close(this);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d7939e25/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java
index 19e37b6..3ee81c2 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java
@@ -97,7 +97,6 @@ import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.attribute.FileTime;
import java.util.Collection;
-import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@@ -105,20 +104,23 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.sshd.ClientSession;
-import org.apache.sshd.client.SftpClient;
import org.apache.sshd.client.SftpException;
import org.apache.sshd.client.channel.ChannelSubsystem;
import org.apache.sshd.common.SshException;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.sftp.SftpConstants;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
import org.apache.sshd.common.util.io.InputStreamWithChannel;
+import org.apache.sshd.common.util.io.NoCloseInputStream;
+import org.apache.sshd.common.util.io.NoCloseOutputStream;
import org.apache.sshd.common.util.io.OutputStreamWithChannel;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient {
+public class DefaultSftpClient extends AbstractSftpClient {
private final ClientSession clientSession;
private final ChannelSubsystem channel;
private final Map<Integer, Buffer> messages;
@@ -130,7 +132,7 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
public DefaultSftpClient(ClientSession clientSession) throws IOException {
this.clientSession = clientSession;
- this.channel = clientSession.createSubsystemChannel("sftp");
+ this.channel = clientSession.createSubsystemChannel(SftpConstants.SFTP_SUBSYSTEM_NAME);
this.messages = new HashMap<>();
try {
this.channel.setOut(new OutputStream() {
@@ -146,7 +148,7 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
this.channel.setErr(new ByteArrayOutputStream());
this.channel.open().await();
} catch (InterruptedException e) {
- throw (IOException) new InterruptedIOException().initCause(e);
+ throw (IOException) new InterruptedIOException("Interrupted while await channel open").initCause(e);
}
this.channel.onClose(new Runnable() {
@SuppressWarnings("synthetic-access")
@@ -173,7 +175,9 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
@Override
public void close() throws IOException {
- this.channel.close(false);
+ if (this.channel.isOpen()) {
+ this.channel.close(false);
+ }
}
/**
@@ -238,15 +242,17 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
}
}
-
protected int send(int cmd, Buffer buffer) throws IOException {
int id = cmdId.incrementAndGet();
- DataOutputStream dos = new DataOutputStream(channel.getInvertedIn());
- dos.writeInt(5 + buffer.available());
- dos.writeByte(cmd);
- dos.writeInt(id);
- dos.write(buffer.array(), buffer.rpos(), buffer.available());
- dos.flush();
+
+ try(DataOutputStream dos = new DataOutputStream(new NoCloseOutputStream(channel.getInvertedIn()))) {
+ dos.writeInt(5 + buffer.available());
+ dos.writeByte(cmd);
+ dos.writeInt(id);
+ dos.write(buffer.array(), buffer.rpos(), buffer.available());
+ dos.flush();
+ }
+
return id;
}
@@ -270,32 +276,36 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
}
protected Buffer read() throws IOException {
- DataInputStream dis = new DataInputStream(channel.getInvertedOut());
- int length = dis.readInt();
- if (length < 5) {
- throw new IllegalArgumentException("Bad length: " + length);
- }
- Buffer buffer = new ByteArrayBuffer(length + 4);
- buffer.putInt(length);
- int nb = length;
- while (nb > 0) {
- int l = dis.read(buffer.array(), buffer.wpos(), nb);
- if (l < 0) {
- throw new IllegalArgumentException("Premature EOF while read " + length + " bytes - remaining=" + nb);
- }
- buffer.wpos(buffer.wpos() + l);
- nb -= l;
+ try(DataInputStream dis=new DataInputStream(new NoCloseInputStream(channel.getInvertedOut()))) {
+ int length = dis.readInt();
+ if (length < 5) {
+ throw new IllegalArgumentException("Bad length: " + length);
+ }
+ Buffer buffer = new ByteArrayBuffer(length + 4);
+ buffer.putInt(length);
+ int nb = length;
+ while (nb > 0) {
+ int readLen = dis.read(buffer.array(), buffer.wpos(), nb);
+ if (readLen < 0) {
+ throw new IllegalArgumentException("Premature EOF while read " + length + " bytes - remaining=" + nb);
+ }
+ buffer.wpos(buffer.wpos() + readLen);
+ nb -= readLen;
+ }
+
+ return buffer;
}
- return buffer;
}
protected void init() throws IOException {
// Init packet
- DataOutputStream dos = new DataOutputStream(channel.getInvertedIn());
- dos.writeInt(5);
- dos.writeByte(SSH_FXP_INIT);
- dos.writeInt(SFTP_V6);
- dos.flush();
+ try(DataOutputStream dos = new DataOutputStream(new NoCloseOutputStream(channel.getInvertedIn()))) {
+ dos.writeInt(5);
+ dos.writeByte(SSH_FXP_INIT);
+ dos.writeInt(SFTP_V6);
+ dos.flush();
+ }
+
Buffer buffer;
synchronized (messages) {
while (messages.isEmpty()) {
@@ -355,7 +365,7 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
}
}
- protected Handle checkHandle(Buffer buffer) throws IOException {
+ protected String checkHandle(Buffer buffer) throws IOException {
int length = buffer.getInt();
int type = buffer.getByte();
int id = buffer.getInt();
@@ -368,8 +378,8 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
}
throw new SftpException(substatus, msg);
} else if (type == SSH_FXP_HANDLE) {
- String handle = buffer.getString();
- return new Handle(handle);
+ String handle = ValidateUtils.checkNotNullAndNotEmpty(buffer.getString(), "Null/empty handle in buffer", GenericUtils.EMPTY_OBJECT_ARRAY);
+ return handle;
} else {
throw new SshException("Unexpected SFTP packet received: type=" + type + ", id=" + id + ", length=" + length);
}
@@ -508,7 +518,6 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
return FileTime.from(millis, TimeUnit.MILLISECONDS);
}
-
protected void writeAttributes(Buffer buffer, Attributes attributes) throws IOException {
if (version == SFTP_V3) {
int flags = 0;
@@ -615,8 +624,8 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
}
@Override
- public Handle open(String path, Collection<OpenMode> options) throws IOException {
- Buffer buffer = new ByteArrayBuffer();
+ public CloseableHandle open(String path, Collection<OpenMode> options) throws IOException {
+ Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */);
buffer.putString(path);
if (version == SFTP_V3) {
int mode = 0;
@@ -673,56 +682,56 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
buffer.putInt(mode);
}
writeAttributes(buffer, new Attributes());
- return checkHandle(receive(send(SSH_FXP_OPEN, buffer)));
+ return new DefaultCloseableHandle(this, checkHandle(receive(send(SSH_FXP_OPEN, buffer))));
}
@Override
public void close(Handle handle) throws IOException {
- Buffer buffer = new ByteArrayBuffer();
+ Buffer buffer = new ByteArrayBuffer(handle.id.length() + Long.SIZE /* some extra fields */);
buffer.putString(handle.id);
checkStatus(receive(send(SSH_FXP_CLOSE, buffer)));
}
@Override
public void remove(String path) throws IOException {
- Buffer buffer = new ByteArrayBuffer();
+ Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */);
buffer.putString(path);
checkStatus(receive(send(SSH_FXP_REMOVE, buffer)));
}
@Override
- public void rename(String oldPath, String newPath) throws IOException {
- rename(oldPath, newPath, new CopyMode[0]);
- }
-
- @Override
- public void rename(String oldPath, String newPath, CopyMode... options) throws IOException {
- Buffer buffer = new ByteArrayBuffer();
+ public void rename(String oldPath, String newPath, Collection<CopyMode> options) throws IOException {
+ Buffer buffer = new ByteArrayBuffer(oldPath.length() + newPath.length() + Long.SIZE /* some extra fields */);
buffer.putString(oldPath);
buffer.putString(newPath);
+
+ int numOptions = GenericUtils.size(options);
if (version >= SFTP_V5) {
int opts = 0;
- for (CopyMode opt : options) {
- switch (opt) {
- case Atomic:
- opts |= SSH_FXP_RENAME_ATOMIC;
- break;
- case Overwrite:
- opts |= SSH_FXP_RENAME_OVERWRITE;
- break;
- default: // do nothing
+ if (numOptions > 0) {
+ for (CopyMode opt : options) {
+ switch (opt) {
+ case Atomic:
+ opts |= SSH_FXP_RENAME_ATOMIC;
+ break;
+ case Overwrite:
+ opts |= SSH_FXP_RENAME_OVERWRITE;
+ break;
+ default: // do nothing
+ }
}
}
buffer.putInt(opts);
- } else if (options.length > 0) {
- throw new UnsupportedOperationException("copy options can not be used with this SFTP version");
+ } else if (numOptions > 0) {
+ throw new UnsupportedOperationException("rename(" + oldPath + " => " + newPath + ")"
+ + " - copy options can not be used with this SFTP version: " + options);
}
checkStatus(receive(send(SSH_FXP_RENAME, buffer)));
}
@Override
public int read(Handle handle, long fileOffset, byte[] dst, int dstoff, int len) throws IOException {
- Buffer buffer = new ByteArrayBuffer();
+ Buffer buffer = new ByteArrayBuffer(handle.id.length() + Long.SIZE /* some extra fields */);
buffer.putString(handle.id);
buffer.putLong(fileOffset);
buffer.putInt(len);
@@ -758,13 +767,18 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
@Override
public void write(Handle handle, long fileOffset, byte[] src, int srcoff, int len) throws IOException {
// do some bounds checking first
- if (fileOffset < 0 || srcoff < 0 || len < 0) {
- throw new IllegalArgumentException("please ensure all parameters are non-negative values");
+ if ((fileOffset < 0) || (srcoff < 0) || (len < 0)) {
+ throw new IllegalArgumentException("write(" + handle + ") please ensure all parameters "
+ + " are non-negative values: file-offset=" + fileOffset
+ + ", src-offset=" + srcoff + ", len=" + len);
}
- if (srcoff + len > src.length) {
- throw new IllegalArgumentException("cannot read bytes " + srcoff + " to " + (srcoff + len) + " when array is only of length " + src.length);
+ if ((srcoff + len) > src.length) {
+ throw new IllegalArgumentException("write(" + handle + ")"
+ + " cannot read bytes " + srcoff + " to " + (srcoff + len)
+ + " when array is only of length " + src.length);
}
- Buffer buffer = new ByteArrayBuffer();
+
+ Buffer buffer = new ByteArrayBuffer(handle.id.length() + len + Long.SIZE /* some extra fields */);
buffer.putString(handle.id);
buffer.putLong(fileOffset);
buffer.putBytes(src, srcoff, len);
@@ -773,7 +787,7 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
@Override
public void mkdir(String path) throws IOException {
- Buffer buffer = new ByteArrayBuffer();
+ Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */);
buffer.putString(path, StandardCharsets.UTF_8);
buffer.putInt(0);
if (version != SFTP_V3) {
@@ -784,21 +798,21 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
@Override
public void rmdir(String path) throws IOException {
- Buffer buffer = new ByteArrayBuffer();
+ Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */);
buffer.putString(path);
checkStatus(receive(send(SSH_FXP_RMDIR, buffer)));
}
@Override
- public Handle openDir(String path) throws IOException {
- Buffer buffer = new ByteArrayBuffer();
+ public CloseableHandle openDir(String path) throws IOException {
+ Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */);
buffer.putString(path);
- return checkHandle(receive(send(SSH_FXP_OPENDIR, buffer)));
+ return new DefaultCloseableHandle(this, checkHandle(receive(send(SSH_FXP_OPENDIR, buffer))));
}
@Override
public DirEntry[] readDir(Handle handle) throws IOException {
- Buffer buffer = new ByteArrayBuffer();
+ Buffer buffer = new ByteArrayBuffer(handle.id.length() + Long.SIZE /* some extra fields */);
buffer.putString(handle.id);
return checkDir(receive(send(SSH_FXP_READDIR, buffer)));
}
@@ -892,28 +906,22 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
@Override
public String readLink(String path) throws IOException {
- Buffer buffer = new ByteArrayBuffer();
+ Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */);
buffer.putString(path);
return checkOneName(receive(send(SSH_FXP_READLINK, buffer)));
}
@Override
- public void symLink(String linkPath, String targetPath) throws IOException {
- link(linkPath, targetPath, true);
- }
-
- @Override
public void link(String linkPath, String targetPath, boolean symbolic) throws IOException {
+ Buffer buffer = new ByteArrayBuffer(linkPath.length() + targetPath.length() + Long.SIZE /* some extra fields */);
if (version < SFTP_V6) {
if (!symbolic) {
throw new UnsupportedOperationException("Hard links are not supported in sftp v" + version);
}
- Buffer buffer = new ByteArrayBuffer();
buffer.putString(targetPath);
buffer.putString(linkPath);
checkStatus(receive(send(SSH_FXP_SYMLINK, buffer)));
} else {
- Buffer buffer = new ByteArrayBuffer();
buffer.putString(targetPath);
buffer.putString(linkPath);
buffer.putBoolean(symbolic);
@@ -946,17 +954,20 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
@Override
public Iterator<DirEntry> iterator() {
return new Iterator<DirEntry>() {
- Handle handle;
- DirEntry[] entries;
- int index;
+ private CloseableHandle handle;
+ private DirEntry[] entries;
+ private int index;
+
{
open();
load();
}
+
@Override
public boolean hasNext() {
- return entries != null && index < entries.length;
+ return (entries != null) && (index < entries.length);
}
+
@Override
public DirEntry next() {
DirEntry entry = entries[index++];
@@ -965,30 +976,45 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
}
return entry;
}
+
+ @SuppressWarnings("synthetic-access")
private void open() {
try {
handle = openDir(path);
+ if (log.isDebugEnabled()) {
+ log.debug("readDir(" + path + ") handle=" + handle);
+ }
} catch (IOException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("readDir(" + path + ") failed (" + e.getClass().getSimpleName() + ") to open dir: " + e.getMessage());
+ }
throw new RuntimeException(e);
}
}
+
+ @SuppressWarnings("synthetic-access")
private void load() {
try {
entries = readDir(handle);
index = 0;
if (entries == null) {
- close(handle);
+ handle.close();
}
} catch (IOException e) {
entries = null;
try {
- close(handle);
+ handle.close();
} catch (IOException t) {
- // Ignore
+ if (log.isTraceEnabled()) {
+ log.trace(t.getClass().getSimpleName() + " while close handle=" + handle
+ + " due to " + e.getClass().getSimpleName() + " [" + e.getMessage() + "]"
+ + ": " + t.getMessage());
+ }
}
throw new RuntimeException(e);
}
}
+
@Override
public void remove() {
throw new UnsupportedOperationException("readDir(" + path + ") Iterator#remove() N/A");
@@ -999,23 +1025,18 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
}
@Override
- public InputStream read(final String path) throws IOException {
- return read(path, EnumSet.of(OpenMode.Read));
- }
-
- @Override
public InputStream read(final String path, final Collection<OpenMode> mode) throws IOException {
return new InputStreamWithChannel() {
private byte[] bb = new byte[1];
private byte[] buffer = new byte[32 * 1024];
private int index;
private int available;
- private Handle handle = DefaultSftpClient.this.open(path, mode);
+ private CloseableHandle handle = DefaultSftpClient.this.open(path, mode);
private long offset;
@Override
public boolean isOpen() {
- return handle != null;
+ return (handle != null) && handle.isOpen();
}
@Override
@@ -1031,7 +1052,7 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (!isOpen()) {
- throw new IOException("Stream closed");
+ throw new IOException("read(" + path + ") stream closed");
}
int idx = off;
@@ -1064,7 +1085,7 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
public void close() throws IOException {
if (isOpen()) {
try {
- DefaultSftpClient.this.close(handle);
+ handle.close();
} finally {
handle = null;
}
@@ -1074,22 +1095,17 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
}
@Override
- public OutputStream write(final String path) throws IOException {
- return write(path, EnumSet.of(OpenMode.Write, OpenMode.Create, OpenMode.Truncate));
- }
-
- @Override
public OutputStream write(final String path, final Collection<OpenMode> mode) throws IOException {
return new OutputStreamWithChannel() {
private byte[] bb = new byte[1];
private byte[] buffer = new byte[32 * 1024];
private int index;
- private Handle handle = DefaultSftpClient.this.open(path, mode);
+ private CloseableHandle handle = DefaultSftpClient.this.open(path, mode);
private long offset;
@Override
public boolean isOpen() {
- return handle != null;
+ return (handle != null) && handle.isOpen();
}
@Override
@@ -1101,7 +1117,7 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
@Override
public void write(byte[] b, int off, int len) throws IOException {
if (!isOpen()) {
- throw new IOException("write(len=" + len + ") Stream is closed");
+ throw new IOException("write(" + path + ")[len=" + len + "] stream is closed");
}
do {
@@ -1119,7 +1135,7 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
@Override
public void flush() throws IOException {
if (!isOpen()) {
- throw new IOException("flush() Stream is closed");
+ throw new IOException("flush(" + path + ") stream is closed");
}
DefaultSftpClient.this.write(handle, offset, buffer, 0, index);
@@ -1136,7 +1152,7 @@ public class DefaultSftpClient extends AbstractLoggingBean implements SftpClient
flush();
}
} finally {
- DefaultSftpClient.this.close(handle);
+ handle.close();
}
} finally {
handle = null;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d7939e25/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpClient.java
new file mode 100644
index 0000000..75483b7
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpClient.java
@@ -0,0 +1,289 @@
+/*
+ * 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.client.sftp;
+
+import static org.apache.sshd.common.sftp.SftpConstants.S_IFDIR;
+import static org.apache.sshd.common.sftp.SftpConstants.S_IFLNK;
+import static org.apache.sshd.common.sftp.SftpConstants.S_IFMT;
+import static org.apache.sshd.common.sftp.SftpConstants.S_IFREG;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.channels.Channel;
+import java.nio.file.attribute.FileTime;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+
+/**
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public interface SftpClient extends Closeable {
+
+ enum OpenMode {
+ Read,
+ Write,
+ Append,
+ Create,
+ Truncate,
+ Exclusive
+ }
+
+ enum CopyMode {
+ Atomic,
+ Overwrite
+ }
+
+ enum Attribute {
+ Size,
+ UidGid,
+ Perms,
+ AcModTime,
+ OwnerGroup,
+ AccessTime,
+ ModifyTime,
+ CreateTime,
+ }
+
+ public static class Handle {
+ public final String id;
+ public Handle(String id) {
+ this.id = ValidateUtils.checkNotNullAndNotEmpty(id, "No handle ID", GenericUtils.EMPTY_OBJECT_ARRAY);
+ }
+
+ @Override
+ public String toString() {
+ return id;
+ }
+ }
+
+ public static abstract class CloseableHandle extends Handle implements Channel, Closeable {
+ protected CloseableHandle(String id) {
+ super(id);
+ }
+ }
+
+ public static class Attributes {
+ public final Set<Attribute> flags = EnumSet.noneOf(Attribute.class);
+ public long size;
+ public byte type;
+ public int uid;
+ public int gid;
+ public int perms;
+ public int atime;
+ public int ctime;
+ public int mtime;
+ public String owner;
+ public String group;
+ public FileTime accessTime;
+ public FileTime createTime;
+ public FileTime modifyTime;
+
+ @Override
+ public String toString() {
+ return "type=" + type
+ + ";size=" + size
+ + ";uid=" + uid
+ + ";gid=" + gid
+ + ";perms=0x" + Integer.toHexString(perms)
+ + ";flags=" + flags
+ + ";owner=" + owner
+ + ";group=" + group
+ + ";aTime=(" + atime + ")[" + accessTime + "]"
+ + ";cTime=(" + ctime + ")[" + createTime + "]"
+ + ";mTime=(" + mtime + ")[" + modifyTime + "]"
+ ;
+ }
+
+ public Attributes size(long size) {
+ flags.add(Attribute.Size);
+ this.size = size;
+ return this;
+ }
+ public Attributes owner(String owner) {
+ flags.add(Attribute.OwnerGroup);
+ this.owner = owner;
+ if (GenericUtils.isEmpty(group)) {
+ group = "GROUP@";
+ }
+ return this;
+ }
+ public Attributes group(String group) {
+ flags.add(Attribute.OwnerGroup);
+ this.group = group;
+ if (GenericUtils.isEmpty(owner)) {
+ owner = "OWNER@";
+ }
+ return this;
+ }
+ public Attributes owner(int uid, int gid) {
+ flags.add(Attribute.UidGid);
+ this.uid = uid;
+ this.gid = gid;
+ return this;
+ }
+ public Attributes perms(int perms) {
+ flags.add(Attribute.Perms);
+ this.perms = perms;
+ return this;
+ }
+ public Attributes atime(int atime) {
+ flags.add(Attribute.AccessTime);
+ this.atime = atime;
+ this.accessTime = FileTime.from(atime, TimeUnit.SECONDS);
+ return this;
+ }
+ public Attributes ctime(int ctime) {
+ flags.add(Attribute.CreateTime);
+ this.ctime = ctime;
+ this.createTime = FileTime.from(atime, TimeUnit.SECONDS);
+ return this;
+ }
+ public Attributes mtime(int mtime) {
+ flags.add(Attribute.ModifyTime);
+ this.mtime = mtime;
+ this.modifyTime = FileTime.from(atime, TimeUnit.SECONDS);
+ return this;
+ }
+ public Attributes time(int atime, int mtime) {
+ flags.add(Attribute.AcModTime);
+ this.atime = atime;
+ this.mtime = mtime;
+ return this;
+ }
+ public Attributes accessTime(FileTime atime) {
+ flags.add(Attribute.AccessTime);
+ this.atime = (int) atime.to(TimeUnit.SECONDS);
+ this.accessTime = atime;
+ return this;
+ }
+ public Attributes createTime(FileTime ctime) {
+ flags.add(Attribute.CreateTime);
+ this.ctime = (int) ctime.to(TimeUnit.SECONDS);
+ this.createTime = ctime;
+ return this;
+ }
+ public Attributes modifyTime(FileTime mtime) {
+ flags.add(Attribute.ModifyTime);
+ this.mtime = (int) mtime.to(TimeUnit.SECONDS);
+ this.modifyTime = mtime;
+ return this;
+ }
+ public boolean isRegularFile() {
+ return (perms & S_IFMT) == S_IFREG;
+ }
+ public boolean isDirectory() {
+ return (perms & S_IFMT) == S_IFDIR;
+ }
+ public boolean isSymbolicLink() {
+ return (perms & S_IFMT) == S_IFLNK;
+ }
+ public boolean isOther() {
+ return !isRegularFile() && !isDirectory() && !isSymbolicLink();
+ }
+ }
+
+ public static class DirEntry {
+ public String filename;
+ public String longFilename;
+ public Attributes attributes;
+ public DirEntry(String filename, String longFilename, Attributes attributes) {
+ this.filename = filename;
+ this.longFilename = longFilename;
+ this.attributes = attributes;
+ }
+ }
+
+ int getVersion();
+
+ boolean isClosing();
+
+ //
+ // Low level API
+ //
+
+ CloseableHandle open(String path) throws IOException;
+ CloseableHandle open(String path, OpenMode ... options) throws IOException;
+ CloseableHandle open(String path, Collection<OpenMode> options) throws IOException;
+
+ void close(Handle handle) throws IOException;
+
+ void remove(String path) throws IOException;
+
+ void rename(String oldPath, String newPath) throws IOException;
+ void rename(String oldPath, String newPath, CopyMode... options) throws IOException;
+ void rename(String oldPath, String newPath, Collection<CopyMode> options) throws IOException;
+
+ int read(Handle handle, long fileOffset, byte[] dst) throws IOException;
+ int read(Handle handle, long fileOffset, byte[] dst, int dstoff, int len) throws IOException;
+
+ void write(Handle handle, long fileOffset, byte[] src) throws IOException;
+ void write(Handle handle, long fileOffset, byte[] src, int srcoff, int len) throws IOException;
+
+ void mkdir(String path) throws IOException;
+
+ void rmdir(String path) throws IOException;
+
+ CloseableHandle openDir(String path) throws IOException;
+
+ DirEntry[] readDir(Handle handle) throws IOException;
+
+ String canonicalPath(String canonical) throws IOException;
+
+ Attributes stat(String path) throws IOException;
+
+ Attributes lstat(String path) throws IOException;
+
+ Attributes stat(Handle handle) throws IOException;
+
+ void setStat(String path, Attributes attributes) throws IOException;
+
+ void setStat(Handle handle, Attributes attributes) throws IOException;
+
+ String readLink(String path) throws IOException;
+
+ void symLink(String linkPath, String targetPath) throws IOException;
+
+ void link(String linkPath, String targetPath, boolean symbolic) throws IOException;
+
+ void lock(Handle handle, long offset, long length, int mask) throws IOException;
+
+ void unlock(Handle handle, long offset, long length) throws IOException;
+
+ //
+ // High level API
+ //
+
+ Iterable<DirEntry> readDir(String path) throws IOException;
+
+ InputStream read(String path) throws IOException;
+ InputStream read(String path, OpenMode ... mode) throws IOException;
+ InputStream read(String path, Collection<OpenMode> mode) throws IOException;
+
+ OutputStream write(String path) throws IOException;
+ OutputStream write(String path, OpenMode ... mode) throws IOException;
+ OutputStream write(String path, Collection<OpenMode> mode) throws IOException;
+
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d7939e25/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileChannel.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileChannel.java
index dc61005..3d9244c 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileChannel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileChannel.java
@@ -37,7 +37,6 @@ import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
-import org.apache.sshd.client.SftpClient;
import org.apache.sshd.client.SftpException;
public class SftpFileChannel extends FileChannel {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d7939e25/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystem.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystem.java
index 574d282..dfc88f4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystem.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystem.java
@@ -34,7 +34,6 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.sshd.ClientSession;
-import org.apache.sshd.client.SftpClient;
import org.apache.sshd.common.file.util.BaseFileSystem;
import org.apache.sshd.common.file.util.ImmutableList;
@@ -110,7 +109,7 @@ public class SftpFileSystem extends BaseFileSystem<SftpPath> {
return defaultDir;
}
- private class Wrapper implements SftpClient {
+ private class Wrapper extends AbstractSftpClient {
private final SftpClient delegate;
private final AtomicInteger count = new AtomicInteger(1);
@@ -145,7 +144,7 @@ public class SftpFileSystem extends BaseFileSystem<SftpPath> {
}
@Override
- public Handle open(String path, Collection<OpenMode> options) throws IOException {
+ public CloseableHandle open(String path, Collection<OpenMode> options) throws IOException {
return delegate.open(path, options);
}
@@ -160,12 +159,7 @@ public class SftpFileSystem extends BaseFileSystem<SftpPath> {
}
@Override
- public void rename(String oldPath, String newPath) throws IOException {
- delegate.rename(oldPath, newPath);
- }
-
- @Override
- public void rename(String oldPath, String newPath, CopyMode... options) throws IOException {
+ public void rename(String oldPath, String newPath, Collection<CopyMode> options) throws IOException {
delegate.rename(oldPath, newPath, options);
}
@@ -190,7 +184,7 @@ public class SftpFileSystem extends BaseFileSystem<SftpPath> {
}
@Override
- public Handle openDir(String path) throws IOException {
+ public CloseableHandle openDir(String path) throws IOException {
return delegate.openDir(path);
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d7939e25/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java
index 4e3e9b8..fc53d04 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java
@@ -75,14 +75,14 @@ import java.util.concurrent.TimeUnit;
import org.apache.sshd.ClientSession;
import org.apache.sshd.SshBuilder;
import org.apache.sshd.SshClient;
-import org.apache.sshd.client.SftpClient;
-import org.apache.sshd.client.SftpClient.Attributes;
+import org.apache.sshd.client.sftp.SftpClient.Attributes;
import org.apache.sshd.client.SftpException;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.config.SshConfigFileReader;
import org.apache.sshd.common.sftp.SftpConstants;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.IoUtils;
+import org.apache.sshd.server.sftp.SftpSubsystemFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -107,7 +107,7 @@ public class SftpFileSystemProvider extends FileSystemProvider {
@Override
public String getScheme() {
- return "sftp";
+ return SftpConstants.SFTP_SUBSYSTEM_NAME;
}
@Override
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d7939e25/sshd-core/src/main/java/org/apache/sshd/common/sftp/SftpConstants.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/sftp/SftpConstants.java b/sshd-core/src/main/java/org/apache/sshd/common/sftp/SftpConstants.java
index 80d0667..dd54bf3 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/sftp/SftpConstants.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/sftp/SftpConstants.java
@@ -22,6 +22,7 @@ package org.apache.sshd.common.sftp;
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public class SftpConstants {
+ public static String SFTP_SUBSYSTEM_NAME = "sftp";
public static final int SSH_FXP_INIT = 1;
public static final int SSH_FXP_VERSION = 2;
@@ -219,5 +220,4 @@ public class SftpConstants {
public static int SFTP_V4 = 4;
public static int SFTP_V5 = 5;
public static int SFTP_V6 = 6;
-
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d7939e25/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystemFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystemFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystemFactory.java
index e3a59c6..04d0239 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystemFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystemFactory.java
@@ -22,6 +22,7 @@ package org.apache.sshd.server.sftp;
import java.util.concurrent.ExecutorService;
import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.sftp.SftpConstants;
import org.apache.sshd.common.util.ObjectBuilder;
import org.apache.sshd.common.util.threads.ExecutorServiceConfigurer;
import org.apache.sshd.server.Command;
@@ -30,7 +31,7 @@ import org.apache.sshd.server.Command;
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public class SftpSubsystemFactory implements NamedFactory<Command>, Cloneable, ExecutorServiceConfigurer {
- public static final String NAME = "sftp";
+ public static final String NAME = SftpConstants.SFTP_SUBSYSTEM_NAME;
public static final UnsupportedAttributePolicy DEFAULT_POLICY = UnsupportedAttributePolicy.Warn;
public static class Builder implements ObjectBuilder<SftpSubsystemFactory> {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d7939e25/sshd-core/src/test/java/org/apache/sshd/ClientTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/ClientTest.java b/sshd-core/src/test/java/org/apache/sshd/ClientTest.java
index ba0e313..121de96 100644
--- a/sshd-core/src/test/java/org/apache/sshd/ClientTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/ClientTest.java
@@ -66,6 +66,7 @@ import org.apache.sshd.common.io.nio2.Nio2Session;
import org.apache.sshd.common.keyprovider.KeyPairProvider;
import org.apache.sshd.common.session.AbstractSession;
import org.apache.sshd.common.session.ConnectionService;
+import org.apache.sshd.common.sftp.SftpConstants;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
@@ -904,7 +905,7 @@ public class ClientTest extends BaseTestSupport {
session.auth().verify(5L, TimeUnit.SECONDS);
session.switchToNoneCipher().await();
- try(ClientChannel channel = session.createSubsystemChannel("sftp")) {
+ try(ClientChannel channel = session.createSubsystemChannel(SftpConstants.SFTP_SUBSYSTEM_NAME)) {
channel.open().verify(5L, TimeUnit.SECONDS);
}
} finally {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d7939e25/sshd-core/src/test/java/org/apache/sshd/client/sftp/DefaultCloseableHandleTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/sftp/DefaultCloseableHandleTest.java b/sshd-core/src/test/java/org/apache/sshd/client/sftp/DefaultCloseableHandleTest.java
new file mode 100644
index 0000000..43f6913
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/client/sftp/DefaultCloseableHandleTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.client.sftp;
+
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.sshd.client.sftp.SftpClient.CloseableHandle;
+import org.apache.sshd.client.sftp.SftpClient.Handle;
+import org.apache.sshd.util.BaseTestSupport;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class DefaultCloseableHandleTest extends BaseTestSupport {
+ public DefaultCloseableHandleTest() {
+ super();
+ }
+
+ @Test
+ public void testChannelBehavior() throws IOException {
+ final String id = getCurrentTestName();
+ SftpClient client = Mockito.mock(SftpClient.class);
+ Mockito.doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ Handle handle = (Handle) args[0];
+ assertEquals("Mismatched closing handle", id, handle.id);
+ return null;
+ }
+ }).when(client).close(Matchers.any(Handle.class));
+
+ CloseableHandle handle = new DefaultCloseableHandle(client, id);
+ try {
+ assertTrue("Handle not initially open", handle.isOpen());
+ } finally {
+ handle.close();
+ }
+ assertFalse("Handle not marked as closed", handle.isOpen());
+ // make sure close was called
+ Mockito.verify(client).close(handle);
+ }
+
+ @Test
+ public void testCloseIdempotent() throws IOException {
+ SftpClient client = Mockito.mock(SftpClient.class);
+ final AtomicBoolean closeCalled = new AtomicBoolean(false);
+ Mockito.doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ assertFalse("Close already called on handle=" + args[0], closeCalled.getAndSet(true));
+ return null;
+ }
+ }).when(client).close(Matchers.any(Handle.class));
+
+ CloseableHandle handle = new DefaultCloseableHandle(client, getCurrentTestName());
+ for (int index=0; index < Byte.SIZE; index++) {
+ handle.close();
+ }
+
+ assertTrue("Close method not called", closeCalled.get());
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d7939e25/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpFileSystemTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpFileSystemTest.java b/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpFileSystemTest.java
index 3187f63..1acb676 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpFileSystemTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpFileSystemTest.java
@@ -46,6 +46,7 @@ import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.Session;
import org.apache.sshd.common.file.FileSystemFactory;
import org.apache.sshd.common.file.root.RootedFileSystemProvider;
+import org.apache.sshd.common.sftp.SftpConstants;
import org.apache.sshd.common.util.OsUtils;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.command.ScpCommandFactory;
@@ -99,7 +100,7 @@ public class SftpFileSystemTest extends BaseTestSupport {
@Test
public void testFileSystem() throws IOException {
Path targetPath = detectTargetFolder().toPath();
- Path lclSftp = Utils.resolve(targetPath, "sftp", getClass().getSimpleName());
+ Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName());
Utils.deleteRecursive(lclSftp);
try(FileSystem fs = FileSystems.newFileSystem(URI.create("sftp://x:x@localhost:" + port + "/"), Collections.<String,Object>emptyMap())) {
@@ -208,7 +209,7 @@ public class SftpFileSystemTest extends BaseTestSupport {
@Test
public void testAttributes() throws IOException {
Path targetPath = detectTargetFolder().toPath();
- Path lclSftp = Utils.resolve(targetPath, "sftp", getClass().getSimpleName());
+ Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName());
Utils.deleteRecursive(lclSftp);
try (FileSystem fs = FileSystems.newFileSystem(URI.create("sftp://x:x@localhost:" + port + "/"), null)) {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d7939e25/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpTest.java b/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpTest.java
index 9e9207e..fe9e917 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/sftp/SftpTest.java
@@ -43,11 +43,11 @@ import java.util.concurrent.TimeUnit;
import org.apache.sshd.ClientSession;
import org.apache.sshd.SshClient;
import org.apache.sshd.SshServer;
-import org.apache.sshd.client.SftpClient;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.Session;
import org.apache.sshd.common.file.FileSystemFactory;
import org.apache.sshd.common.file.root.RootedFileSystemProvider;
+import org.apache.sshd.common.sftp.SftpConstants;
import org.apache.sshd.common.util.OsUtils;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
import org.apache.sshd.server.Command;
@@ -136,7 +136,7 @@ public class SftpTest extends BaseTestSupport {
Path targetPath = detectTargetFolder().toPath();
Path parentPath = targetPath.getParent();
- Path lclSftp = Utils.resolve(targetPath, "sftp", getClass().getSimpleName());
+ Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName());
Path clientFolder = lclSftp.resolve("client");
Path testFile = clientFolder.resolve(getCurrentTestName() + ".txt");
String file = Utils.resolveRelativeRemotePath(parentPath, testFile);
@@ -148,34 +148,27 @@ public class SftpTest extends BaseTestSupport {
javaFile.setReadable(false, false);
try (SftpClient sftp = session.createSftpClient()) {
- SftpClient.Handle h;
-
boolean isWindows = OsUtils.isWin32();
- try {
- h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read));
+ try(SftpClient.CloseableHandle h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read))) {
// NOTE: on Windows files are always readable
// see https://svn.apache.org/repos/asf/harmony/enhanced/java/branches/java6/classlib/modules/luni/src/test/api/windows/org/apache/harmony/luni/tests/java/io/WinFileTest.java
assertTrue("Empty read should have failed on " + file, isWindows);
- sftp.close(h);
} catch (IOException e) {
if (isWindows) {
throw e;
}
}
- try {
- h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
+ try(SftpClient.CloseableHandle h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write))) {
fail("Empty write should have failed on " + file);
} catch (IOException e) {
// ok
}
- try {
- h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Truncate));
+ try(SftpClient.CloseableHandle h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Truncate))) {
// NOTE: on Windows files are always readable
assertTrue("Empty truncate should have failed on " + file, isWindows);
- sftp.close(h);
} catch (IOException e) {
// ok
}
@@ -187,40 +180,28 @@ public class SftpTest extends BaseTestSupport {
javaFile.setWritable(true, false);
- h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Truncate, SftpClient.OpenMode.Write));
- sftp.close(h);
+ try(SftpClient.CloseableHandle h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Truncate, SftpClient.OpenMode.Write))) {
+ // OK should succeed
+ assertTrue("Handle not marked as open for file=" + file, h.isOpen());
+ }
byte[] d = "0123456789\n".getBytes();
- h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
- try {
+ try(SftpClient.CloseableHandle h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write))) {
sftp.write(h, 0, d, 0, d.length);
sftp.write(h, d.length, d, 0, d.length);
- } finally {
- sftp.close(h);
}
- h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
- try {
+ try(SftpClient.CloseableHandle h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write))) {
sftp.write(h, d.length * 2, d, 0, d.length);
- } finally {
- sftp.close(h);
}
- h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
- try {
+ try(SftpClient.CloseableHandle h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write))) {
sftp.write(h, 3, "-".getBytes(), 0, 1);
- } finally {
- sftp.close(h);
}
- try {
- h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read));
- try {
- // NOTE: on Windows files are always readable
- assertTrue("Data read should have failed on " + file, isWindows);
- } finally {
- sftp.close(h);
- }
+ try(SftpClient.CloseableHandle h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read))) {
+ // NOTE: on Windows files are always readable
+ assertTrue("Data read should have failed on " + file, isWindows);
} catch (IOException e) {
if (isWindows) {
throw e;
@@ -230,12 +211,9 @@ public class SftpTest extends BaseTestSupport {
javaFile.setReadable(true, false);
byte[] buf = new byte[3];
- h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read));
- try {
+ try(SftpClient.CloseableHandle h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read))) {
int l = sftp.read(h, 2l, buf, 0, 3);
assertEquals("Mismatched read data", "2-4", new String(buf, 0, l));
- } finally {
- sftp.close(h);
}
}
} finally {
@@ -254,7 +232,7 @@ public class SftpTest extends BaseTestSupport {
session.auth().verify(5L, TimeUnit.SECONDS);
Path targetPath = detectTargetFolder().toPath();
- Path lclSftp = Utils.resolve(targetPath, "sftp", getClass().getSimpleName());
+ Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName());
Utils.deleteRecursive(lclSftp);
Files.createDirectories(lclSftp);
@@ -266,24 +244,20 @@ public class SftpTest extends BaseTestSupport {
try (SftpClient sftp = session.createSftpClient()) {
sftp.mkdir(dir);
- SftpClient.Handle h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Create));
- byte[] d = "0123456789\n".getBytes();
- sftp.write(h, 0, d, 0, d.length);
- sftp.write(h, d.length, d, 0, d.length);
-
- SftpClient.Attributes attrs = sftp.stat(h);
- assertNotNull("No handle attributes", attrs);
-
- sftp.close(h);
+ try(SftpClient.CloseableHandle h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Create))) {
+ byte[] d = "0123456789\n".getBytes();
+ sftp.write(h, 0, d, 0, d.length);
+ sftp.write(h, d.length, d, 0, d.length);
+
+ SftpClient.Attributes attrs = sftp.stat(h);
+ assertNotNull("No handle attributes", attrs);
+ }
- h = sftp.openDir(dir);
- try {
+ try(SftpClient.CloseableHandle h = sftp.openDir(dir)) {
SftpClient.DirEntry[] dirEntries = sftp.readDir(h);
assertNotNull("No dir entries", dirEntries);
assertEquals("Mismatced number of dir entries", 1, dirEntries.length);
assertNull("Unexpected entry read", sftp.readDir(h));
- } finally {
- sftp.close(h);
}
sftp.remove(file);
@@ -341,7 +315,7 @@ public class SftpTest extends BaseTestSupport {
session.auth().verify(5L, TimeUnit.SECONDS);
Path targetPath = detectTargetFolder().toPath();
- Path lclSftp = Utils.resolve(targetPath, "sftp", getClass().getSimpleName());
+ Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName());
Utils.deleteRecursive(lclSftp);
Files.createDirectories(lclSftp);
@@ -381,8 +355,7 @@ public class SftpTest extends BaseTestSupport {
// generate random file and upload it
String randomData = randomString(5);
byte[] randomBytes = randomData.getBytes();
- SftpClient.Handle handle = sftp.open(filePath, EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Create));
- try {
+ try(SftpClient.CloseableHandle handle = sftp.open(filePath, EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Create))) {
try {
sftp.write(handle, -1, randomBytes, 0, 0);
fail("should not have been able to write file with invalid file offset for " + filePath);
@@ -413,9 +386,6 @@ public class SftpTest extends BaseTestSupport {
} catch (IllegalArgumentException e) {
// expected
}
- } finally {
- // cleanup
- sftp.close(handle);
}
sftp.remove(filePath);
@@ -426,11 +396,8 @@ public class SftpTest extends BaseTestSupport {
// generate random file and upload it
String remotePath = remoteDir + "/" + filename;
String randomData = randomString(size);
- SftpClient.Handle handle = sftp.open(remotePath, EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Create));
- try {
+ try(SftpClient.CloseableHandle handle = sftp.open(remotePath, EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Create))) {
sftp.write(handle, 0, randomData.getBytes(), 0, randomData.length());
- } finally {
- sftp.close(handle);
}
// verify results
@@ -448,7 +415,7 @@ public class SftpTest extends BaseTestSupport {
String d = getCurrentTestName() + "\n";
Path targetPath = detectTargetFolder().toPath();
- Path lclSftp = Utils.resolve(targetPath, "sftp", getClass().getSimpleName());
+ Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName());
Utils.deleteRecursive(lclSftp);
Files.createDirectories(lclSftp);
@@ -475,7 +442,7 @@ public class SftpTest extends BaseTestSupport {
@Test
public void testReadWriteWithOffset() throws Exception {
Path targetPath = detectTargetFolder().toPath();
- Path lclSftp = Utils.resolve(targetPath, "sftp", getClass().getSimpleName());
+ Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName());
Utils.deleteRecursive(lclSftp);
Files.createDirectories(lclSftp);
@@ -485,7 +452,7 @@ public class SftpTest extends BaseTestSupport {
String extraData = "@" + getClass().getSimpleName();
int appendOffset = -5;
- ChannelSftp c = (ChannelSftp) session.openChannel("sftp");
+ ChannelSftp c = (ChannelSftp) session.openChannel(SftpConstants.SFTP_SUBSYSTEM_NAME);
c.connect();
try {
c.put(new ByteArrayInputStream(data.getBytes()), remotePath);
@@ -509,7 +476,7 @@ public class SftpTest extends BaseTestSupport {
@Test
public void testReadDir() throws Exception {
- ChannelSftp c = (ChannelSftp) session.openChannel("sftp");
+ ChannelSftp c = (ChannelSftp) session.openChannel(SftpConstants.SFTP_SUBSYSTEM_NAME);
c.connect();
try {
URI url = getClass().getClassLoader().getResource(SshClient.class.getName().replace('.', '/') + ".class").toURI();
@@ -527,7 +494,7 @@ public class SftpTest extends BaseTestSupport {
@Test
public void testRealPath() throws Exception {
- ChannelSftp c = (ChannelSftp) session.openChannel("sftp");
+ ChannelSftp c = (ChannelSftp) session.openChannel(SftpConstants.SFTP_SUBSYSTEM_NAME);
c.connect();
try {
@@ -559,7 +526,7 @@ public class SftpTest extends BaseTestSupport {
session.auth().verify(5L, TimeUnit.SECONDS);
Path targetPath = detectTargetFolder().toPath();
- Path lclSftp = Utils.resolve(targetPath, "sftp", getClass().getSimpleName());
+ Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName());
Utils.deleteRecursive(lclSftp);
Files.createDirectories(lclSftp);
@@ -609,7 +576,7 @@ public class SftpTest extends BaseTestSupport {
Assume.assumeTrue("Skip non-Unix O/S", OsUtils.isUNIX());
Path targetPath = detectTargetFolder().toPath();
- Path lclSftp = Utils.resolve(targetPath, "sftp", getClass().getSimpleName());
+ Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName());
Utils.deleteRecursive(lclSftp);
Files.createDirectories(lclSftp);
@@ -620,7 +587,7 @@ public class SftpTest extends BaseTestSupport {
String remLinkPath = Utils.resolveRelativeRemotePath(parentPath, linkPath);
String data = getCurrentTestName();
- ChannelSftp c = (ChannelSftp) session.openChannel("sftp");
+ ChannelSftp c = (ChannelSftp) session.openChannel(SftpConstants.SFTP_SUBSYSTEM_NAME);
c.connect();
try {
c.put(new ByteArrayInputStream(data.getBytes()), remSrcPath);
@@ -642,7 +609,7 @@ public class SftpTest extends BaseTestSupport {
}
protected String readFile(String path) throws Exception {
- ChannelSftp c = (ChannelSftp) session.openChannel("sftp");
+ ChannelSftp c = (ChannelSftp) session.openChannel(SftpConstants.SFTP_SUBSYSTEM_NAME);
c.connect();
try(ByteArrayOutputStream bos = new ByteArrayOutputStream();
@@ -661,7 +628,7 @@ public class SftpTest extends BaseTestSupport {
}
protected void sendFile(String path, String data) throws Exception {
- ChannelSftp c = (ChannelSftp) session.openChannel("sftp");
+ ChannelSftp c = (ChannelSftp) session.openChannel(SftpConstants.SFTP_SUBSYSTEM_NAME);
c.connect();
try {
c.put(new ByteArrayInputStream(data.getBytes()), path);