http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/17f2d627/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java index 8f92951..db7afc5 100644 --- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java +++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java @@ -19,6 +19,34 @@ package org.apache.sshd.client.subsystem.sftp; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.attribute.FileTime; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import org.apache.sshd.client.subsystem.sftp.extensions.BuiltinSftpClientExtensions; +import org.apache.sshd.client.subsystem.sftp.extensions.SftpClientExtension; +import org.apache.sshd.client.subsystem.sftp.extensions.SftpClientExtensionFactory; +import org.apache.sshd.common.SshException; +import org.apache.sshd.common.subsystem.sftp.SftpConstants; +import org.apache.sshd.common.subsystem.sftp.extensions.ParserUtils; +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.OutputStreamWithChannel; +import org.apache.sshd.common.util.logging.AbstractLoggingBean; + import static org.apache.sshd.common.subsystem.sftp.SftpConstants.ACE4_APPEND_DATA; import static org.apache.sshd.common.subsystem.sftp.SftpConstants.ACE4_READ_ATTRIBUTES; import static org.apache.sshd.common.subsystem.sftp.SftpConstants.ACE4_READ_DATA; @@ -86,44 +114,17 @@ import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IFDIR; import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IFLNK; import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IFREG; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.attribute.FileTime; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -import org.apache.sshd.client.subsystem.sftp.extensions.BuiltinSftpClientExtensions; -import org.apache.sshd.client.subsystem.sftp.extensions.SftpClientExtension; -import org.apache.sshd.client.subsystem.sftp.extensions.SftpClientExtensionFactory; -import org.apache.sshd.common.SshException; -import org.apache.sshd.common.subsystem.sftp.SftpConstants; -import org.apache.sshd.common.subsystem.sftp.extensions.ParserUtils; -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.OutputStreamWithChannel; -import org.apache.sshd.common.util.logging.AbstractLoggingBean; - /** * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> */ public abstract class AbstractSftpClient extends AbstractLoggingBean implements SftpClient, RawSftpClient { - private final AtomicReference<Map<String,Object>> parsedExtensionsHolder = new AtomicReference<Map<String,Object>>(null); + + private final AtomicReference<Map<String, Object>> parsedExtensionsHolder = new AtomicReference<>(null); protected AbstractSftpClient() { super(); } - + @Override public String getName() { return SftpConstants.SFTP_SUBSYSTEM_NAME; @@ -133,9 +134,9 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements public CloseableHandle open(String path) throws IOException { return open(path, Collections.<OpenMode>emptySet()); } - + @Override - public CloseableHandle open(String path, OpenMode ... options) throws IOException { + public CloseableHandle open(String path, OpenMode... options) throws IOException { return open(path, GenericUtils.of(options)); } @@ -143,9 +144,9 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements 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 { + public void rename(String oldPath, String newPath, CopyMode... options) throws IOException { rename(oldPath, newPath, GenericUtils.of(options)); } @@ -160,17 +161,17 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements } @Override - public InputStream read(String path, OpenMode ... mode) throws IOException { + public InputStream read(String path, OpenMode... mode) throws IOException { return read(path, DEFAULT_READ_BUFFER_SIZE, mode); } @Override - public InputStream read(String path, int bufferSize, OpenMode ... mode) throws IOException { + public InputStream read(String path, int bufferSize, OpenMode... mode) throws IOException { return read(path, bufferSize, GenericUtils.of(mode)); } @Override - public InputStream read(String path, Collection<OpenMode> mode) throws IOException { + public InputStream read(String path, Collection<OpenMode> mode) throws IOException { return read(path, DEFAULT_READ_BUFFER_SIZE, mode); } @@ -190,7 +191,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements } @Override - public OutputStream write(String path, OpenMode ... mode) throws IOException { + public OutputStream write(String path, OpenMode... mode) throws IOException { return write(path, DEFAULT_WRITE_BUFFER_SIZE, mode); } @@ -200,7 +201,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements } @Override - public OutputStream write(String path, int bufferSize, OpenMode ... mode) throws IOException { + public OutputStream write(String path, int bufferSize, OpenMode... mode) throws IOException { return write(path, bufferSize, GenericUtils.of(mode)); } @@ -216,7 +217,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements @Override public <E extends SftpClientExtension> E getExtension(Class<? extends E> extensionType) { - Object instance = getExtension(BuiltinSftpClientExtensions.fromType(extensionType)); + Object instance = getExtension(BuiltinSftpClientExtensions.fromType(extensionType)); if (instance == null) { return null; } else { @@ -228,30 +229,31 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements public SftpClientExtension getExtension(String extensionName) { return getExtension(BuiltinSftpClientExtensions.fromName(extensionName)); } - + protected SftpClientExtension getExtension(SftpClientExtensionFactory factory) { if (factory == null) { return null; } - Map<String,byte[]> extensions = getServerExtensions(); - Map<String,Object> parsed = getParsedServerExtensions(extensions); + Map<String, byte[]> extensions = getServerExtensions(); + Map<String, Object> parsed = getParsedServerExtensions(extensions); return factory.create(this, this, extensions, parsed); } - protected Map<String,Object> getParsedServerExtensions() { + protected Map<String, Object> getParsedServerExtensions() { return getParsedServerExtensions(getServerExtensions()); } - protected Map<String,Object> getParsedServerExtensions(Map<String,byte[]> extensions) { - Map<String,Object> parsed = parsedExtensionsHolder.get(); + protected Map<String, Object> getParsedServerExtensions(Map<String, byte[]> extensions) { + Map<String, Object> parsed = parsedExtensionsHolder.get(); if (parsed == null) { - if ((parsed=ParserUtils.parse(extensions)) == null) { - parsed = Collections.<String,Object>emptyMap(); + parsed = ParserUtils.parse(extensions); + if (parsed == null) { + parsed = Collections.emptyMap(); } parsedExtensionsHolder.set(parsed); } - + return parsed; } @@ -302,7 +304,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements */ protected void checkStatus(int id, int substatus, String msg, String lang) throws IOException { if (log.isTraceEnabled()) { - log.trace("checkStatus(id=" + id + ") status: " + substatus + " [" + lang + "]" + msg ); + log.trace("checkStatus(id=" + id + ") status: " + substatus + " [" + lang + "]" + msg); } if (substatus != SSH_FX_OK) { @@ -410,7 +412,8 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements if (len != 1) { throw new SshException("SFTP error: received " + len + " names instead of 1"); } - String name = buffer.getString(), longName = null; + String name = buffer.getString(); + String longName = null; int version = getVersion(); if (version == SFTP_V3) { longName = buffer.getString(); @@ -474,7 +477,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements attrs.flags.add(Attribute.Perms); attrs.perms = buffer.getInt(); } - + // update the permissions according to the type switch (attrs.type) { case SSH_FILEXFER_TYPE_REGULAR: @@ -515,7 +518,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements long secs = buffer.getLong(); long millis = secs * 1000; if ((flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) != 0) { - millis += buffer.getInt() / 1000000l; + millis += buffer.getInt() / 1000000L; } return FileTime.from(millis, TimeUnit.MILLISECONDS); } @@ -641,7 +644,8 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */); buffer.putString(path); - int version = getVersion(), mode = 0; + int version = getVersion(); + int mode = 0; if (version == SFTP_V3) { for (OpenMode m : options) { switch (m) { @@ -730,7 +734,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements Buffer buffer = new ByteArrayBuffer(oldPath.length() + newPath.length() + Long.SIZE /* some extra fields */); buffer.putString(oldPath); buffer.putString(newPath); - + int numOptions = GenericUtils.size(options); int version = getVersion(); if (version >= SFTP_V5) { @@ -751,7 +755,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements buffer.putInt(opts); } else if (numOptions > 0) { throw new UnsupportedOperationException("rename(" + oldPath + " => " + newPath + ")" - + " - copy options can not be used with this SFTP version: " + options); + + " - copy options can not be used with this SFTP version: " + options); } checkStatus(SSH_FXP_RENAME, buffer); } @@ -809,13 +813,13 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements // do some bounds checking first if ((fileOffset < 0) || (srcOffset < 0) || (len < 0)) { throw new IllegalArgumentException("write(" + handle + ") please ensure all parameters " - + " are non-negative values: file-offset=" + fileOffset - + ", src-offset=" + srcOffset + ", len=" + len); + + " are non-negative values: file-offset=" + fileOffset + + ", src-offset=" + srcOffset + ", len=" + len); } if ((srcOffset + len) > src.length) { throw new IllegalArgumentException("write(" + handle + ")" - + " cannot read bytes " + srcOffset + " to " + (srcOffset + len) - + " when array is only of length " + src.length); + + " cannot read bytes " + srcOffset + " to " + (srcOffset + len) + + " when array is only of length " + src.length); } if (!isOpen()) { throw new IOException("write(" + handle + "/" + fileOffset + ")[" + srcOffset + "/" + len + "] client is closed"); @@ -835,7 +839,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements throw new IOException("mkdir(" + path + ") client is closed"); } - Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */); + Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */); buffer.putString(path); buffer.putInt(0); @@ -853,7 +857,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements throw new IOException("rmdir(" + path + ") client is closed"); } - Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */); + Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */); buffer.putString(path); checkStatus(SSH_FXP_RMDIR, buffer); } @@ -1076,79 +1080,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements if (!isOpen()) { throw new IOException("readDir(" + path + ") client is closed"); } - - return new Iterable<DirEntry>() { - @Override - public Iterator<DirEntry> iterator() { - return new Iterator<DirEntry>() { - private CloseableHandle handle; - private List<DirEntry> entries; - private int index; - - { - open(); - load(); - } - - @Override - public boolean hasNext() { - return (entries != null) && (index < entries.size()); - } - - @Override - public DirEntry next() { - DirEntry entry = entries.get(index++); - if (index >= entries.size()) { - load(); - } - 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) { - handle.close(); - } - } catch (IOException e) { - entries = null; - try { - handle.close(); - } catch (IOException t) { - 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"); - } - }; - } - }; + return new DirEntryIterable(path); } @Override @@ -1161,147 +1093,249 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements throw new IOException("read(" + path + ")[" + mode + "] size=" + bufferSize + ": client is closed"); } - return new InputStreamWithChannel() { - private byte[] bb = new byte[1]; - private byte[] buffer = new byte[bufferSize]; + return new SftpInputStreamWithChannel(bufferSize, path, mode); + } + + @Override + public OutputStream write(final String path, final int bufferSize, final Collection<OpenMode> mode) throws IOException { + if (bufferSize < MIN_WRITE_BUFFER_SIZE) { + throw new IllegalArgumentException("Insufficient write buffer size: " + bufferSize + ", min.=" + MIN_WRITE_BUFFER_SIZE); + } + + if (!isOpen()) { + throw new IOException("write(" + path + ")[" + mode + "] size=" + bufferSize + ": client is closed"); + } + + return new SftpOutputStreamWithChannel(bufferSize, path, mode); + } + + private class DirEntryIterable implements Iterable<DirEntry> { + + private final String path; + + public DirEntryIterable(String path) { + this.path = path; + } + + @Override + public Iterator<DirEntry> iterator() { + return new DirEntryIterator(); + } + + private class DirEntryIterator implements Iterator<DirEntry> { + private CloseableHandle handle; + private List<DirEntry> entries; private int index; - private int available; - private CloseableHandle handle = AbstractSftpClient.this.open(path, mode); - private long offset; - @Override - public boolean isOpen() { - return (handle != null) && handle.isOpen(); + public DirEntryIterator() { + open(); + load(); } @Override - public int read() throws IOException { - int read = read(bb, 0, 1); - if (read > 0) { - return bb[0]; - } - - return read; + public boolean hasNext() { + return (entries != null) && (index < entries.size()); } @Override - public int read(byte[] b, int off, int len) throws IOException { - if (!isOpen()) { - throw new IOException("read(" + path + ") stream closed"); + public DirEntry next() { + DirEntry entry = entries.get(index++); + if (index >= entries.size()) { + load(); } + return entry; + } - int idx = off; - while (len > 0) { - if (index >= available) { - available = AbstractSftpClient.this.read(handle, offset, buffer, 0, buffer.length); - if (available < 0) { - if (idx == off) { - return -1; - } else { - break; - } - } - offset += available; - index = 0; + @SuppressWarnings("synthetic-access") + private void open() { + try { + handle = openDir(path); + if (log.isDebugEnabled()) { + log.debug("readDir(" + path + ") handle=" + handle); } - if (index >= available) { - break; + } catch (IOException e) { + if (log.isDebugEnabled()) { + log.debug("readDir(" + path + ") failed (" + e.getClass().getSimpleName() + ") to open dir: " + e.getMessage()); } - int nb = Math.min(len, available - index); - System.arraycopy(buffer, index, b, idx, nb); - index += nb; - idx += nb; - len -= nb; + throw new RuntimeException(e); } - return idx - off; } - @Override - public void close() throws IOException { - if (isOpen()) { + @SuppressWarnings("synthetic-access") + private void load() { + try { + entries = readDir(handle); + index = 0; + if (entries == null) { + handle.close(); + } + } catch (IOException e) { + entries = null; try { handle.close(); - } finally { - handle = null; + } catch (IOException t) { + 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"); + } + } } - @Override - public OutputStream write(final String path, final int bufferSize, final Collection<OpenMode> mode) throws IOException { - if (bufferSize < MIN_WRITE_BUFFER_SIZE) { - throw new IllegalArgumentException("Insufficient write buffer size: " + bufferSize + ", min.=" + MIN_WRITE_BUFFER_SIZE); + private class SftpOutputStreamWithChannel extends OutputStreamWithChannel { + private final String path; + private byte[] bb; + private byte[] buffer; + private int index; + private CloseableHandle handle; + private long offset; + + public SftpOutputStreamWithChannel(int bufferSize, String path, Collection<OpenMode> mode) throws IOException { + this.path = path; + bb = new byte[1]; + buffer = new byte[bufferSize]; + handle = AbstractSftpClient.this.open(path, mode); } - if (!isOpen()) { - throw new IOException("write(" + path + ")[" + mode + "] size=" + bufferSize + ": client is closed"); + @Override + public boolean isOpen() { + return (handle != null) && handle.isOpen(); } - return new OutputStreamWithChannel() { - private byte[] bb = new byte[1]; - private byte[] buffer = new byte[bufferSize]; - private int index; - private CloseableHandle handle = AbstractSftpClient.this.open(path, mode); - private long offset; + @Override + public void write(int b) throws IOException { + bb[0] = (byte) b; + write(bb, 0, 1); + } - @Override - public boolean isOpen() { - return (handle != null) && handle.isOpen(); + @Override + public void write(byte[] b, int off, int len) throws IOException { + if (!isOpen()) { + throw new IOException("write(" + path + ")[len=" + len + "] stream is closed"); } - @Override - public void write(int b) throws IOException { - bb[0] = (byte) b; - write(bb, 0, 1); + do { + int nb = Math.min(len, buffer.length - index); + System.arraycopy(b, off, buffer, index, nb); + index += nb; + if (index == buffer.length) { + flush(); + } + off += nb; + len -= nb; + } while (len > 0); + } + + @Override + public void flush() throws IOException { + if (!isOpen()) { + throw new IOException("flush(" + path + ") stream is closed"); } - @Override - public void write(byte[] b, int off, int len) throws IOException { - if (!isOpen()) { - throw new IOException("write(" + path + ")[len=" + len + "] stream is closed"); - } + AbstractSftpClient.this.write(handle, offset, buffer, 0, index); + offset += index; + index = 0; + } - do { - int nb = Math.min(len, buffer.length - index); - System.arraycopy(b, off, buffer, index, nb); - index += nb; - if (index == buffer.length) { - flush(); + @Override + public void close() throws IOException { + if (isOpen()) { + try { + try { + if (index > 0) { + flush(); + } + } finally { + handle.close(); } - off += nb; - len -= nb; - } while (len > 0); + } finally { + handle = null; + } + } + } + } + + private class SftpInputStreamWithChannel extends InputStreamWithChannel { + private final String path; + private byte[] bb; + private byte[] buffer; + private int index; + private int available; + private CloseableHandle handle; + private long offset; + + public SftpInputStreamWithChannel(int bufferSize, String path, Collection<OpenMode> mode) throws IOException { + this.path = path; + bb = new byte[1]; + buffer = new byte[bufferSize]; + handle = AbstractSftpClient.this.open(path, mode); + } + + @Override + public boolean isOpen() { + return (handle != null) && handle.isOpen(); + } + + @Override + public int read() throws IOException { + int read = read(bb, 0, 1); + if (read > 0) { + return bb[0]; } - @Override - public void flush() throws IOException { - if (!isOpen()) { - throw new IOException("flush(" + path + ") stream is closed"); - } + return read; + } - AbstractSftpClient.this.write(handle, offset, buffer, 0, index); - offset += index; - index = 0; + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (!isOpen()) { + throw new IOException("read(" + path + ") stream closed"); } - @Override - public void close() throws IOException { - if (isOpen()) { - try { - try { - if (index > 0) { - flush(); - } - } finally { - handle.close(); + int idx = off; + while (len > 0) { + if (index >= available) { + available = AbstractSftpClient.this.read(handle, offset, buffer, 0, buffer.length); + if (available < 0) { + if (idx == off) { + return -1; + } else { + break; } - } finally { - handle = null; } + offset += available; + index = 0; + } + if (index >= available) { + break; } + int nb = Math.min(len, available - index); + System.arraycopy(buffer, index, b, idx, nb); + index += nb; + idx += nb; + len -= nb; } - }; + return idx - off; + } + + @Override + public void close() throws IOException { + if (isOpen()) { + try { + handle.close(); + } finally { + handle = null; + } + } + } } }
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/17f2d627/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/DefaultSftpClient.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/DefaultSftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/DefaultSftpClient.java index dd313db..feb156a 100644 --- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/DefaultSftpClient.java +++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/DefaultSftpClient.java @@ -18,12 +18,6 @@ */ package org.apache.sshd.client.subsystem.sftp; -import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SFTP_V3; -import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SFTP_V6; -import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FXP_INIT; -import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FXP_STATUS; -import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FXP_VERSION; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -52,6 +46,12 @@ import org.apache.sshd.common.util.buffer.Buffer; import org.apache.sshd.common.util.buffer.BufferUtils; import org.apache.sshd.common.util.buffer.ByteArrayBuffer; +import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SFTP_V3; +import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SFTP_V6; +import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FXP_INIT; +import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FXP_STATUS; +import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FXP_VERSION; + /** * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> */ @@ -64,8 +64,8 @@ public class DefaultSftpClient extends AbstractSftpClient { private final byte[] workBuf = new byte[Integer.SIZE / Byte.SIZE]; // TODO in JDK-8 use Integer.BYTES private boolean closing; private int version; - private final Map<String,byte[]> extensions = new TreeMap<String,byte[]>(String.CASE_INSENSITIVE_ORDER); - private final Map<String,byte[]> exposedExtensions = Collections.unmodifiableMap(extensions); + private final Map<String, byte[]> extensions = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + private final Map<String, byte[]> exposedExtensions = Collections.unmodifiableMap(extensions); public DefaultSftpClient(ClientSession clientSession) throws IOException { this.clientSession = ValidateUtils.checkNotNull(clientSession, "No client session", GenericUtils.EMPTY_OBJECT_ARRAY); @@ -73,8 +73,9 @@ public class DefaultSftpClient extends AbstractSftpClient { this.channel.setOut(new OutputStream() { @Override public void write(int b) throws IOException { - write(new byte[] { (byte) b }, 0, 1); + write(new byte[]{(byte) b}, 0, 1); } + @Override public void write(byte[] b, int off, int len) throws IOException { data(b, off, len); @@ -131,7 +132,7 @@ public class DefaultSftpClient extends AbstractSftpClient { * Receive binary data */ protected int data(byte[] buf, int start, int len) throws IOException { - Buffer incoming = new ByteArrayBuffer(buf, start, len); + Buffer incoming = new ByteArrayBuffer(buf, start, len); // If we already have partial data, we need to append it to the buffer and use it if (receiveBuffer.available() > 0) { receiveBuffer.putBuffer(incoming); @@ -139,7 +140,7 @@ public class DefaultSftpClient extends AbstractSftpClient { } // Process commands int rpos = incoming.rpos(); - for (int count=0; receive(incoming); count++) { + for (int count = 0; receive(incoming); count++) { if (log.isTraceEnabled()) { log.trace("Processed " + count + " data messages"); } @@ -189,17 +190,18 @@ public class DefaultSftpClient extends AbstractSftpClient { int id = buffer.getInt(); buffer.rpos(0); synchronized (messages) { - messages.put(Integer.valueOf(id), buffer); + messages.put(id, buffer); messages.notifyAll(); } } @Override public int send(int cmd, Buffer buffer) throws IOException { - int id = cmdId.incrementAndGet(), len = buffer.available(); + int id = cmdId.incrementAndGet(); + int len = buffer.available(); if (log.isTraceEnabled()) { log.trace("send(cmd={}, len={}) id = {}", - Integer.valueOf(cmd), Integer.valueOf(len), Integer.valueOf(id)); + cmd, len, id); } OutputStream dos = channel.getInvertedIn(); @@ -213,9 +215,9 @@ public class DefaultSftpClient extends AbstractSftpClient { @Override public Buffer receive(int id) throws IOException { - Integer reqId = Integer.valueOf(id); + Integer reqId = id; synchronized (messages) { - for (int count=1; ; count++) { + for (int count = 1;; count++) { if (closing) { throw new SshException("Channel has been closed"); } @@ -313,10 +315,10 @@ public class DefaultSftpClient extends AbstractSftpClient { */ public int negotiateVersion(SftpVersionSelector selector) throws IOException { int current = getVersion(); - Set<Integer> available = GenericUtils.asSortedSet(Collections.singleton(Integer.valueOf(current))); - Map<String,?> parsed = getParsedServerExtensions(); + Set<Integer> available = GenericUtils.asSortedSet(Collections.singleton(current)); + Map<String, ?> parsed = getParsedServerExtensions(); Collection<String> extensions = ParserUtils.supportedExtensions(parsed); - if ((GenericUtils.size(extensions) > 0) && extensions.contains(SftpConstants.EXT_VERSELECT)) { + if ((GenericUtils.size(extensions) > 0) && extensions.contains(SftpConstants.EXT_VERSION_SELECT)) { Versions vers = GenericUtils.isEmpty(parsed) ? null : (Versions) parsed.get(SftpConstants.EXT_VERSIONS); Collection<String> reported = (vers == null) ? null : vers.versions; if (GenericUtils.size(reported) > 0) { @@ -328,9 +330,9 @@ public class DefaultSftpClient extends AbstractSftpClient { } } - int selected = selector.selectVersion(current, new ArrayList<Integer>(available)); + int selected = selector.selectVersion(current, new ArrayList<>(available)); if (log.isDebugEnabled()) { - log.debug("negotiateVersion({}) {} -> {}", Integer.valueOf(current), available, Integer.valueOf(selected)); + log.debug("negotiateVersion({}) {} -> {}", current, available, selected); } if (selected == current) { @@ -342,9 +344,9 @@ public class DefaultSftpClient extends AbstractSftpClient { } String verVal = String.valueOf(selected); - Buffer buffer = new ByteArrayBuffer((Integer.SIZE / Byte.SIZE) + SftpConstants.EXT_VERSELECT.length() // extension name - + (Integer.SIZE / Byte.SIZE) + verVal.length()); - buffer.putString(SftpConstants.EXT_VERSELECT); + Buffer buffer = new ByteArrayBuffer((Integer.SIZE / Byte.SIZE) + SftpConstants.EXT_VERSION_SELECT.length() // extension name + + (Integer.SIZE / Byte.SIZE) + verVal.length()); + buffer.putString(SftpConstants.EXT_VERSION_SELECT); buffer.putString(verVal); checkStatus(SftpConstants.SSH_FXP_EXTENDED, buffer); version = selected; http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/17f2d627/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/RawSftpClient.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/RawSftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/RawSftpClient.java index ab80812..bd283a9 100644 --- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/RawSftpClient.java +++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/RawSftpClient.java @@ -28,13 +28,13 @@ import org.apache.sshd.common.util.buffer.Buffer; */ public interface RawSftpClient { /** - * @param cmd Command to send - <B>Note:</B> only lower 8-bits are used + * @param cmd Command to send - <B>Note:</B> only lower 8-bits are used * @param buffer The {@link Buffer} containing the command data * @return The assigned request id * @throws IOException if failed to send command */ int send(int cmd, Buffer buffer) throws IOException; - + /** * @param id The expected request id * @return The received response {@link Buffer} containing the request id http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/17f2d627/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClient.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClient.java index 598a2fe..0c7032c 100644 --- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClient.java +++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClient.java @@ -18,11 +18,6 @@ */ package org.apache.sshd.client.subsystem.sftp; -import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IFDIR; -import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IFLNK; -import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IFMT; -import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IFREG; - import java.io.Closeable; import java.io.IOException; import java.io.InputStream; @@ -43,6 +38,11 @@ import org.apache.sshd.common.util.ValidateUtils; import org.apache.sshd.common.util.buffer.BufferUtils; import org.bouncycastle.util.Arrays; +import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IFDIR; +import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IFLNK; +import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IFMT; +import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IFREG; + /** * @author <a href="http://mina.apache.org">Apache MINA Project</a> */ @@ -103,7 +103,7 @@ public interface SftpClient extends SubsystemClient { if (obj == null) { return false; } - + if (obj == this) { return true; } @@ -112,12 +112,8 @@ public interface SftpClient extends SubsystemClient { if (!(obj instanceof Handle)) { return false; } - - if (Arrays.areEqual(id, ((Handle) obj).id)) { - return true; - } else { - return false; - } + + return Arrays.areEqual(id, ((Handle) obj).id); } @Override @@ -133,6 +129,7 @@ public interface SftpClient extends SubsystemClient { } class Attributes { + // CHECKSTYLE:OFF public final Set<Attribute> flags = EnumSet.noneOf(Attribute.class); public long size; public int type; @@ -147,21 +144,21 @@ public interface SftpClient extends SubsystemClient { public FileTime accessTime; public FileTime createTime; public FileTime modifyTime; + // CHECKSTYLE:ON @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 + "]" - ; + + ";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) { @@ -169,6 +166,7 @@ public interface SftpClient extends SubsystemClient { this.size = size; return this; } + public Attributes owner(String owner) { flags.add(Attribute.OwnerGroup); this.owner = owner; @@ -177,6 +175,7 @@ public interface SftpClient extends SubsystemClient { } return this; } + public Attributes group(String group) { flags.add(Attribute.OwnerGroup); this.group = group; @@ -185,77 +184,93 @@ public interface SftpClient extends SubsystemClient { } 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(); } } class DirEntry { + // CHECKSTYLE:OFF public String filename; public String longFilename; public Attributes attributes; + // CHECKSTYLE:ON + public DirEntry(String filename, String longFilename, Attributes attributes) { this.filename = filename; this.longFilename = longFilename; @@ -263,12 +278,30 @@ public interface SftpClient extends SubsystemClient { } } + // default values used if none specified + int MIN_BUFFER_SIZE = Byte.MAX_VALUE; + int MIN_READ_BUFFER_SIZE = MIN_BUFFER_SIZE; + int MIN_WRITE_BUFFER_SIZE = MIN_BUFFER_SIZE; + int IO_BUFFER_SIZE = 32 * 1024; + int DEFAULT_READ_BUFFER_SIZE = IO_BUFFER_SIZE; + int DEFAULT_WRITE_BUFFER_SIZE = IO_BUFFER_SIZE; + long DEFAULT_WAIT_TIMEOUT = TimeUnit.SECONDS.toMillis(30L); + + /** + * Property that can be used on the {@link org.apache.sshd.common.FactoryManager} + * to control the internal timeout used by the client to open a channel. + * If not specified then {@link #DEFAULT_CHANNEL_OPEN_TIMEOUT} value + * is used + */ + String SFTP_CHANNEL_OPEN_TIMEOUT = "sftp-channel-open-timeout"; + long DEFAULT_CHANNEL_OPEN_TIMEOUT = DEFAULT_WAIT_TIMEOUT; + int getVersion(); /** * @return An (unmodifiable) {@link Map} of the reported server extensions. */ - Map<String,byte[]> getServerExtensions(); + Map<String, byte[]> getServerExtensions(); boolean isClosing(); @@ -278,6 +311,7 @@ public interface SftpClient extends SubsystemClient { /** * Opens a remote file for read + * * @param path The remote path * @return The file's {@link CloseableHandle} * @throws IOException If failed to open the remote file @@ -286,19 +320,21 @@ public interface SftpClient extends SubsystemClient { /** * Opens a remote file with the specified mode(s) - * @param path The remote path + * + * @param path The remote path * @param options The desired mode - if none specified - * then {@link OpenMode#Read} is assumed + * then {@link OpenMode#Read} is assumed * @return The file's {@link CloseableHandle} * @throws IOException If failed to open the remote file */ - CloseableHandle open(String path, OpenMode ... options) throws IOException; + CloseableHandle open(String path, OpenMode... options) throws IOException; /** * Opens a remote file with the specified mode(s) - * @param path The remote path + * + * @param path The remote path * @param options The desired mode - if none specified - * then {@link OpenMode#Read} is assumed + * then {@link OpenMode#Read} is assumed * @return The file's {@link CloseableHandle} * @throws IOException If failed to open the remote file */ @@ -309,13 +345,17 @@ public interface SftpClient extends SubsystemClient { 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 dstOffset, int len) throws IOException; void write(Handle handle, long fileOffset, byte[] src) throws IOException; + void write(Handle handle, long fileOffset, byte[] src, int srcOffset, int len) throws IOException; void mkdir(String path) throws IOException; @@ -371,32 +411,28 @@ public interface SftpClient extends SubsystemClient { */ Iterable<DirEntry> readDir(String path) throws IOException; - // default values used if none specified - int MIN_BUFFER_SIZE=Byte.MAX_VALUE, MIN_READ_BUFFER_SIZE=MIN_BUFFER_SIZE, MIN_WRITE_BUFFER_SIZE=MIN_BUFFER_SIZE; - int IO_BUFFER_SIZE=32 * 1024, DEFAULT_READ_BUFFER_SIZE=IO_BUFFER_SIZE, DEFAULT_WRITE_BUFFER_SIZE=IO_BUFFER_SIZE; - long DEFAULT_WAIT_TIMEOUT=TimeUnit.SECONDS.toMillis(30L); - - /** - * Property that can be used on the {@link org.apache.sshd.common.FactoryManager} - * to control the internal timeout used by the client to open a channel. - * If not specified then {@link #DEFAULT_CHANNEL_OPEN_TIMEOUT} value - * is used - */ - String SFTP_CHANNEL_OPEN_TIMEOUT = "sftp-channel-open-timeout"; - long DEFAULT_CHANNEL_OPEN_TIMEOUT = DEFAULT_WAIT_TIMEOUT; - InputStream read(String path) throws IOException; + InputStream read(String path, int bufferSize) throws IOException; - InputStream read(String path, OpenMode ... mode) throws IOException; - InputStream read(String path, int bufferSize, OpenMode ... mode) throws IOException; + + InputStream read(String path, OpenMode... mode) throws IOException; + + InputStream read(String path, int bufferSize, OpenMode... mode) throws IOException; + InputStream read(String path, Collection<OpenMode> mode) throws IOException; + InputStream read(String path, int bufferSize, Collection<OpenMode> mode) throws IOException; OutputStream write(String path) throws IOException; + OutputStream write(String path, int bufferSize) throws IOException; - OutputStream write(String path, OpenMode ... mode) throws IOException; - OutputStream write(String path, int bufferSize, OpenMode ... mode) throws IOException; + + OutputStream write(String path, OpenMode... mode) throws IOException; + + OutputStream write(String path, int bufferSize, OpenMode... mode) throws IOException; + OutputStream write(String path, Collection<OpenMode> mode) throws IOException; + OutputStream write(String path, int bufferSize, Collection<OpenMode> mode) throws IOException; /** http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/17f2d627/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java index fea2b6b..d132fe3 100644 --- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java +++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java @@ -45,248 +45,35 @@ import org.apache.sshd.common.util.io.NoCloseInputStream; /** * Implements a simple command line SFTP client similar to the Linux one + * * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> */ public class SftpCommand implements Channel { private final SftpClient client; + private final Map<String, CommandExecutor> commandsMap; private String cwdRemote; - private final Map<String,CommandExecutor> commandsMap = - Collections.unmodifiableMap(new TreeMap<String,CommandExecutor>() { - private static final long serialVersionUID = 1L; // we're not serializing it - - { - for (CommandExecutor e : Arrays.asList( - new CommandExecutor() { - @Override - public String getName() { - return "exit"; - } - - @Override - public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { - ValidateUtils.checkTrue(GenericUtils.isEmpty(args), "Unexpected arguments: %s", args); - stdout.println("Exiting"); - return true; - } - }, - new CommandExecutor() { - @Override - public String getName() { - return "pwd"; - } - - @Override - public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { - ValidateUtils.checkTrue(GenericUtils.isEmpty(args), "Unexpected arguments: %s", args); - stdout.append('\t').println(getCurrentRemoteDirectory()); - return false; - } - }, - new CommandExecutor() { - @Override - public String getName() { - return "info"; - } - - @Override - public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { - ValidateUtils.checkTrue(GenericUtils.isEmpty(args), "Unexpected arguments: %s", args); - SftpClient sftp = getClient(); - Map<String,byte[]> extensions = sftp.getServerExtensions(); - Map<String,?> parsed = ParserUtils.parse(extensions); - for (Map.Entry<String,byte[]> ee : extensions.entrySet()) { - String name = ee.getKey(); - byte[] value = ee.getValue(); - Object info = parsed.get(name); - - stdout.append('\t').append(name).append(": "); - if (info == null) { - stdout.println(BufferUtils.printHex(value)); - } else { - stdout.println(info); - } - } - return false; - } - }, - new CommandExecutor() { - @Override - public String getName() { - return "version"; - } - - @Override - public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { - ValidateUtils.checkTrue(GenericUtils.isEmpty(args), "Unexpected arguments: %s", args); - SftpClient sftp = getClient(); - stdout.append('\t').println(sftp.getVersion()); - return false; - } - }, - new CommandExecutor() { - @Override - public String getName() { - return "cd"; - } - - @Override - public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { - ValidateUtils.checkNotNullAndNotEmpty(args, "No remote directory specified", args); - - String newPath = resolveRemotePath(args); - SftpClient sftp = getClient(); - setCurrentRemoteDirectory(sftp.canonicalPath(newPath)); - return false; - } - }, - new CommandExecutor() { - @Override - public String getName() { - return "mkdir"; - } - - @Override - public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { - ValidateUtils.checkNotNullAndNotEmpty(args, "No remote directory specified", args); - - String path = resolveRemotePath(args); - SftpClient sftp = getClient(); - sftp.mkdir(path); - return false; - } - }, - new CommandExecutor() { - @Override - public String getName() { - return "ls"; - } - - @Override - public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { - String[] comps = GenericUtils.split(args, ' '); - // ignore all flag - String pathArg = GenericUtils.isEmpty(comps) ? null : GenericUtils.trimToEmpty(comps[comps.length - 1]); - String cwd = getCurrentRemoteDirectory(); - if (GenericUtils.isEmpty(pathArg) || (pathArg.charAt(0) == '-')) { - pathArg = cwd; - } - - String path = resolveRemotePath(pathArg); - SftpClient sftp = getClient(); - for (SftpClient.DirEntry entry : sftp.readDir(path)) { - SftpClient.Attributes attrs = entry.attributes; - stdout.append('\t').append(entry.filename) - .append('\t').append(Long.toString(attrs.size)) - .append('\t').println(SftpFileSystemProvider.getRWXPermissions(attrs.perms)); - } - return false; - } - }, - new CommandExecutor() { - @Override - public String getName() { - return "rm"; - } - - @Override - public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { - ValidateUtils.checkNotNullAndNotEmpty(args, "No remote directory specified", args); - - String path = resolveRemotePath(args); - SftpClient sftp = getClient(); - sftp.remove(path); - return false; - } - }, - new CommandExecutor() { - @Override - public String getName() { - return "rmdir"; - } - - @Override - public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { - ValidateUtils.checkNotNullAndNotEmpty(args, "No remote directory specified", args); - - String path = resolveRemotePath(args); - SftpClient sftp = getClient(); - sftp.rmdir(path); - return false; - } - }, - new CommandExecutor() { - @Override - public String getName() { - return "rename"; - } - - @Override - public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { - String[] comps = GenericUtils.split(args, ' '); - ValidateUtils.checkTrue(GenericUtils.length(comps) == 2, "Invalid number of arguments: %s", args); - - String oldPath = resolveRemotePath(GenericUtils.trimToEmpty(comps[0])); - String newPath = resolveRemotePath(GenericUtils.trimToEmpty(comps[1])); - SftpClient sftp = getClient(); - sftp.rename(oldPath, newPath); - return false; - } - }, - new CommandExecutor() { - @Override - public String getName() { - return StatVfsExtensionParser.NAME; - } - - @Override - public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { - String[] comps = GenericUtils.split(args, ' '); - ValidateUtils.checkTrue(GenericUtils.length(comps) == 1, "Invalid number of arguments: %s", args); - - SftpClient sftp = getClient(); - OpenSSHStatPathExtension ext = sftp.getExtension(OpenSSHStatPathExtension.class); - ValidateUtils.checkTrue(ext.isSupported(), "Extension not supported by server: %s", ext.getName()); - - OpenSSHStatExtensionInfo info = ext.stat(GenericUtils.trimToEmpty(comps[0])); - Field[] fields = info.getClass().getFields(); - for (Field f : fields) { - String name = f.getName(); - int mod = f.getModifiers(); - if (Modifier.isStatic(mod)) { - continue; - } - - Object value = f.get(info); - stdout.append('\t').append(name).append(": ").println(value); - } - - return false; - } - }, - new CommandExecutor() { - @Override - public String getName() { - return "help"; - } - - @Override - @SuppressWarnings("synthetic-access") - public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { - ValidateUtils.checkTrue(GenericUtils.isEmpty(args), "Unexpected arguments: %s", args); - for (String cmd : commandsMap.keySet()) { - stdout.append('\t').println(cmd); - } - return false; - } - } - )) { - put(e.getName(), e); - } - } - }); public SftpCommand(SftpClient client) { this.client = ValidateUtils.checkNotNull(client, "No client"); + + Map<String, CommandExecutor> map = new TreeMap<>(); + for (CommandExecutor e : Arrays.asList( + new ExitCommandExecutor(), + new PwdCommandExecutor(), + new InfoCommandExecutor(), + new VersionCommandExecutor(), + new CdCommandExecutor(), + new MkdirCommandExecutor(), + new LsCommandExecutor(), + new RmCommandExecutor(), + new RmdirCommandExecutor(), + new RenameCommandExecutor(), + new StatVfsCommandExecutor(), + new HelpCommandExecutor() + )) { + map.put(e.getName(), e); + } + commandsMap = Collections.unmodifiableMap(map); } public final SftpClient getClient() { @@ -296,19 +83,20 @@ public class SftpCommand implements Channel { public void doInteractive(BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { SftpClient sftp = getClient(); setCurrentRemoteDirectory(sftp.canonicalPath(".")); - while(true) { + while (true) { stdout.append(getCurrentRemoteDirectory()).append(" > ").flush(); String line = stdin.readLine(); if (line == null) { // EOF break; } - + line = line.trim(); if (GenericUtils.isEmpty(line)) { continue; } - - String cmd, args; + + String cmd; + String args; int pos = line.indexOf(' '); if (pos > 0) { cmd = line.substring(0, pos); @@ -317,7 +105,7 @@ public class SftpCommand implements Channel { cmd = line; args = ""; } - + CommandExecutor exec = commandsMap.get(cmd); try { if (exec == null) { @@ -327,7 +115,7 @@ public class SftpCommand implements Channel { if (exec.executeCommand(args, stdin, stdout, stderr)) { break; } - } catch(Exception e) { + } catch (Exception e) { stderr.append(e.getClass().getSimpleName()).append(": ").println(e.getMessage()); } finally { stdout.flush(); @@ -344,13 +132,14 @@ public class SftpCommand implements Channel { if (GenericUtils.isEmpty(pathArg)) { return cwd; } - + if (pathArg.charAt(0) == '/') { return pathArg; } else { return cwd + "/" + pathArg; } } + public String getCurrentRemoteDirectory() { return cwdRemote; } @@ -373,23 +162,24 @@ public class SftpCommand implements Channel { public interface CommandExecutor extends NamedResource { // return value is whether to stop running - boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception; + boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception; } ////////////////////////////////////////////////////////////////////////// public static void main(String[] args) throws Exception { - PrintStream stdout=System.out, stderr=System.err; - try(BufferedReader stdin = new BufferedReader(new InputStreamReader(new NoCloseInputStream(System.in)))) { - ClientSession session=SshClient.setupClientSession("-P", stdin, stdout, stderr, args); + PrintStream stdout = System.out; + PrintStream stderr = System.err; + try (BufferedReader stdin = new BufferedReader(new InputStreamReader(new NoCloseInputStream(System.in)))) { + ClientSession session = SshClient.setupClientSession("-P", stdin, stdout, stderr, args); if (session == null) { System.err.println("usage: sftp [-l login] [-P port] [-o option=value] hostname/user@host"); System.exit(-1); return; } - - try(SshClient client = (SshClient) session.getFactoryManager()) { - try(SftpCommand sftp = new SftpCommand(session.createSftpClient())) { + + try { + try (SftpCommand sftp = new SftpCommand(session.createSftpClient())) { sftp.doInteractive(stdin, stdout, stderr); } } finally { @@ -397,4 +187,239 @@ public class SftpCommand implements Channel { } } } + + private static class ExitCommandExecutor implements CommandExecutor { + @Override + public String getName() { + return "exit"; + } + + @Override + public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { + ValidateUtils.checkTrue(GenericUtils.isEmpty(args), "Unexpected arguments: %s", args); + stdout.println("Exiting"); + return true; + } + } + + private class PwdCommandExecutor implements CommandExecutor { + @Override + public String getName() { + return "pwd"; + } + + @Override + public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { + ValidateUtils.checkTrue(GenericUtils.isEmpty(args), "Unexpected arguments: %s", args); + stdout.append('\t').println(getCurrentRemoteDirectory()); + return false; + } + } + + private class InfoCommandExecutor implements CommandExecutor { + @Override + public String getName() { + return "info"; + } + + @Override + public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { + ValidateUtils.checkTrue(GenericUtils.isEmpty(args), "Unexpected arguments: %s", args); + SftpClient sftp = getClient(); + Map<String, byte[]> extensions = sftp.getServerExtensions(); + Map<String, ?> parsed = ParserUtils.parse(extensions); + for (Map.Entry<String, byte[]> ee : extensions.entrySet()) { + String name = ee.getKey(); + byte[] value = ee.getValue(); + Object info = parsed.get(name); + + stdout.append('\t').append(name).append(": "); + if (info == null) { + stdout.println(BufferUtils.printHex(value)); + } else { + stdout.println(info); + } + } + return false; + } + } + + private class VersionCommandExecutor implements CommandExecutor { + @Override + public String getName() { + return "version"; + } + + @Override + public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { + ValidateUtils.checkTrue(GenericUtils.isEmpty(args), "Unexpected arguments: %s", args); + SftpClient sftp = getClient(); + stdout.append('\t').println(sftp.getVersion()); + return false; + } + } + + private class CdCommandExecutor implements CommandExecutor { + @Override + public String getName() { + return "cd"; + } + + @Override + public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { + ValidateUtils.checkNotNullAndNotEmpty(args, "No remote directory specified", args); + + String newPath = resolveRemotePath(args); + SftpClient sftp = getClient(); + setCurrentRemoteDirectory(sftp.canonicalPath(newPath)); + return false; + } + } + + private class MkdirCommandExecutor implements CommandExecutor { + @Override + public String getName() { + return "mkdir"; + } + + @Override + public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { + ValidateUtils.checkNotNullAndNotEmpty(args, "No remote directory specified", args); + + String path = resolveRemotePath(args); + SftpClient sftp = getClient(); + sftp.mkdir(path); + return false; + } + } + + private class LsCommandExecutor implements CommandExecutor { + @Override + public String getName() { + return "ls"; + } + + @Override + public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { + String[] comps = GenericUtils.split(args, ' '); + // ignore all flag + String pathArg = GenericUtils.isEmpty(comps) ? null : GenericUtils.trimToEmpty(comps[comps.length - 1]); + String cwd = getCurrentRemoteDirectory(); + if (GenericUtils.isEmpty(pathArg) || (pathArg.charAt(0) == '-')) { + pathArg = cwd; + } + + String path = resolveRemotePath(pathArg); + SftpClient sftp = getClient(); + for (SftpClient.DirEntry entry : sftp.readDir(path)) { + SftpClient.Attributes attrs = entry.attributes; + stdout.append('\t').append(entry.filename) + .append('\t').append(Long.toString(attrs.size)) + .append('\t').println(SftpFileSystemProvider.getRWXPermissions(attrs.perms)); + } + return false; + } + } + + private class RmCommandExecutor implements CommandExecutor { + @Override + public String getName() { + return "rm"; + } + + @Override + public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { + ValidateUtils.checkNotNullAndNotEmpty(args, "No remote directory specified", args); + + String path = resolveRemotePath(args); + SftpClient sftp = getClient(); + sftp.remove(path); + return false; + } + } + + private class RmdirCommandExecutor implements CommandExecutor { + @Override + public String getName() { + return "rmdir"; + } + + @Override + public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { + ValidateUtils.checkNotNullAndNotEmpty(args, "No remote directory specified", args); + + String path = resolveRemotePath(args); + SftpClient sftp = getClient(); + sftp.rmdir(path); + return false; + } + } + + private class RenameCommandExecutor implements CommandExecutor { + @Override + public String getName() { + return "rename"; + } + + @Override + public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { + String[] comps = GenericUtils.split(args, ' '); + ValidateUtils.checkTrue(GenericUtils.length(comps) == 2, "Invalid number of arguments: %s", args); + + String oldPath = resolveRemotePath(GenericUtils.trimToEmpty(comps[0])); + String newPath = resolveRemotePath(GenericUtils.trimToEmpty(comps[1])); + SftpClient sftp = getClient(); + sftp.rename(oldPath, newPath); + return false; + } + } + + private class StatVfsCommandExecutor implements CommandExecutor { + @Override + public String getName() { + return StatVfsExtensionParser.NAME; + } + + @Override + public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { + String[] comps = GenericUtils.split(args, ' '); + ValidateUtils.checkTrue(GenericUtils.length(comps) == 1, "Invalid number of arguments: %s", args); + + SftpClient sftp = getClient(); + OpenSSHStatPathExtension ext = sftp.getExtension(OpenSSHStatPathExtension.class); + ValidateUtils.checkTrue(ext.isSupported(), "Extension not supported by server: %s", ext.getName()); + + OpenSSHStatExtensionInfo info = ext.stat(GenericUtils.trimToEmpty(comps[0])); + Field[] fields = info.getClass().getFields(); + for (Field f : fields) { + String name = f.getName(); + int mod = f.getModifiers(); + if (Modifier.isStatic(mod)) { + continue; + } + + Object value = f.get(info); + stdout.append('\t').append(name).append(": ").println(value); + } + + return false; + } + } + + private class HelpCommandExecutor implements CommandExecutor { + @Override + public String getName() { + return "help"; + } + + @Override + @SuppressWarnings("synthetic-access") + public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception { + ValidateUtils.checkTrue(GenericUtils.isEmpty(args), "Unexpected arguments: %s", args); + for (String cmd : commandsMap.keySet()) { + stdout.append('\t').println(cmd); + } + return false; + } + } } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/17f2d627/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileChannel.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileChannel.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileChannel.java index 19ded8c..ee2671f 100644 --- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileChannel.java +++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileChannel.java @@ -18,8 +18,6 @@ */ package org.apache.sshd.client.subsystem.sftp; -import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FX_LOCK_CONFLICT; - import java.io.IOException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; @@ -46,9 +44,18 @@ import org.apache.sshd.common.util.GenericUtils; import org.apache.sshd.common.util.ValidateUtils; import org.apache.sshd.common.util.io.IoUtils; +import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FX_LOCK_CONFLICT; + public class SftpFileChannel extends FileChannel { public static final String COPY_BUFSIZE_PROP = "sftp-channel-copy-buf-size"; - public static final int DEFAULT_TRANSFER_BUFFER_SIZE = IoUtils.DEFAULT_COPY_SIZE; + public static final int DEFAULT_TRANSFER_BUFFER_SIZE = IoUtils.DEFAULT_COPY_SIZE; + + public static final Set<SftpClient.OpenMode> READ_MODES = + Collections.unmodifiableSet(EnumSet.of(SftpClient.OpenMode.Read)); + + public static final Set<SftpClient.OpenMode> WRITE_MODES = + Collections.unmodifiableSet( + EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Append, SftpClient.OpenMode.Create, SftpClient.OpenMode.Truncate)); private final SftpPath p; private final Collection<SftpClient.OpenMode> modes; @@ -61,8 +68,8 @@ public class SftpFileChannel extends FileChannel { public SftpFileChannel(SftpPath p, Collection<SftpClient.OpenMode> modes) throws IOException { this.p = ValidateUtils.checkNotNull(p, "No target path"); this.modes = ValidateUtils.checkNotNull(modes, "No channel modes specified"); - - SftpFileSystem fs=p.getFileSystem(); + + SftpFileSystem fs = p.getFileSystem(); sftp = fs.getClient(); handle = sftp.open(p.toString(), modes); } @@ -86,9 +93,6 @@ public class SftpFileChannel extends FileChannel { return doRead(buffers, -1); } - public static final Set<SftpClient.OpenMode> READ_MODES= - Collections.unmodifiableSet(EnumSet.of(SftpClient.OpenMode.Read)); - protected long doRead(List<ByteBuffer> buffers, long position) throws IOException { ensureOpen(READ_MODES); synchronized (lock) { @@ -124,9 +128,9 @@ public class SftpFileChannel extends FileChannel { if (totalRead > 0) { return totalRead; } - + if (eof) { - return (-1); + return -1; } else { return 0; } @@ -158,10 +162,6 @@ public class SftpFileChannel extends FileChannel { return doWrite(buffers, -1); } - public static final Set<SftpClient.OpenMode> WRITE_MODES= - Collections.unmodifiableSet( - EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Append, SftpClient.OpenMode.Create, SftpClient.OpenMode.Truncate)); - protected long doWrite(List<ByteBuffer> buffers, long position) throws IOException { ensureOpen(WRITE_MODES); synchronized (lock) { @@ -280,9 +280,9 @@ public class SftpFileChannel extends FileChannel { boolean completed = false; long curPos = (position >= 0L) ? position : posTracker.get(); long totalRead = 0L; - byte[] buffer = new byte[(int) Math.min(copySize,count)]; + byte[] buffer = new byte[(int) Math.min(copySize, count)]; - synchronized(lock) { + synchronized (lock) { try { beginBlocking(); @@ -375,22 +375,23 @@ public class SftpFileChannel extends FileChannel { /** * Checks that the channel is open and that its current mode contains * at least one of the required ones + * * @param reqModes The required modes - ignored if {@code null}/empty * @throws IOException If channel not open or the required modes are not - * satisfied + * satisfied */ private void ensureOpen(Collection<SftpClient.OpenMode> reqModes) throws IOException { if (!isOpen()) { throw new ClosedChannelException(); } - + if (GenericUtils.size(reqModes) > 0) { for (SftpClient.OpenMode m : reqModes) { if (this.modes.contains(m)) { return; } } - + throw new IOException("ensureOpen(" + p + ") current channel modes (" + this.modes + ") do contain any of the required: " + reqModes); } }
