Repository: mina-sshd Updated Branches: refs/heads/master 3b1342efc -> d5ce26836
[SSHD-697] Added support for reset and skip for SftpInputStreamWithChannel Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/d5ce2683 Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/d5ce2683 Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/d5ce2683 Branch: refs/heads/master Commit: d5ce26836fac879ab55915f0cf9096fa978fd02f Parents: 3b1342e Author: Goldstein Lyor <[email protected]> Authored: Thu Sep 29 16:42:45 2016 +0300 Committer: Goldstein Lyor <[email protected]> Committed: Thu Sep 29 16:42:45 2016 +0300 ---------------------------------------------------------------------- .../sftp/SftpInputStreamWithChannel.java | 51 +++++++++++++++++++ .../sshd/server/subsystem/sftp/FileHandle.java | 29 +++++------ .../sshd/client/subsystem/sftp/SftpTest.java | 53 ++++++++++++++++++++ 3 files changed, 119 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d5ce2683/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpInputStreamWithChannel.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpInputStreamWithChannel.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpInputStreamWithChannel.java index adf2cc5..af208ad 100644 --- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpInputStreamWithChannel.java +++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpInputStreamWithChannel.java @@ -73,6 +73,57 @@ public class SftpInputStreamWithChannel extends InputStreamWithChannel { } @Override + public boolean markSupported() { + return false; + } + + @Override + public synchronized void mark(int readlimit) { + throw new UnsupportedOperationException("mark(" + readlimit + ") N/A"); + } + + @Override + public long skip(long n) throws IOException { + long skipLen; + long newIndex = index + n; + long bufLen = Math.max(0L, available); + if (newIndex > bufLen) { + // exceeded current buffer + long extraLen = newIndex - bufLen; + offset += extraLen; + skipLen = Math.max(0, bufLen - index) + extraLen; + // force re-fill of read buffer + index = 0; + available = 0; + } else if (newIndex < 0) { + // went back - check how far back + long startOffset = offset - bufLen; + long newOffset = startOffset + newIndex; // actually a subtraction since newIndex is negative + newOffset = Math.max(0L, newOffset); + skipLen = index - newIndex; // actually a adding it since newIndex is negative + offset = newOffset; + // force re-fill of read buffer + index = 0; + available = 0; + } else { + // still within current buffer + index = (int) newIndex; + // need to use absolute value since skip size may have been negative + skipLen = Math.abs(n); + } + + return skipLen; + } + + @Override + public synchronized void reset() throws IOException { + offset = 0L; + // force re-fill of read buffer + index = 0; + available = 0; + } + + @Override public int read() throws IOException { int read = read(bb, 0, 1); if (read > 0) { http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d5ce2683/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/FileHandle.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/FileHandle.java b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/FileHandle.java index e27fddd..075665a 100644 --- a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/FileHandle.java +++ b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/FileHandle.java @@ -47,7 +47,6 @@ public class FileHandle extends Handle { private final int access; private final FileChannel fileChannel; - private long pos; private final List<FileLock> locks = new ArrayList<>(); public FileHandle(SftpSubsystem sftpSubsystem, Path file, int flags, int access, Map<String, Object> attrs) throws IOException { @@ -108,7 +107,6 @@ public class FileHandle extends Handle { sftpSubsystem.doSetAttributes(file, attrs); } this.fileChannel = channel; - this.pos = 0; } public final FileChannel getFileChannel() { @@ -129,13 +127,21 @@ public class FileHandle extends Handle { public int read(byte[] data, int doff, int length, long offset) throws IOException { FileChannel channel = getFileChannel(); - if (pos != offset) { - channel.position(offset); - pos = offset; + channel.position(offset); + + long size = channel.size(); + long curPos = channel.position(); + long available = size - curPos; + if (available <= 0) { + return -1; + } + + int bufLen = length; + if (bufLen > available) { + bufLen = (int) available; // debug breakpoint } - int read = channel.read(ByteBuffer.wrap(data, doff, length)); - pos += read; - return read; + + return channel.read(ByteBuffer.wrap(data, doff, bufLen)); } public void append(byte[] data) throws IOException { @@ -153,13 +159,8 @@ public class FileHandle extends Handle { public void write(byte[] data, int doff, int length, long offset) throws IOException { FileChannel channel = getFileChannel(); - if (pos != offset) { - channel.position(offset); - pos = offset; - } - + channel.position(offset); channel.write(ByteBuffer.wrap(data, doff, length)); - pos += length; } @Override http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d5ce2683/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java index 58ae35d..d2633d3 100644 --- a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java +++ b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java @@ -463,6 +463,59 @@ public class SftpTest extends AbstractSftpClientTestSupport { } @Test + public void testInputStreamSkipAndReset() throws Exception { + Path targetPath = detectTargetFolder(); + Path parentPath = targetPath.getParent(); + Path localFile = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); + Files.createDirectories(localFile.getParent()); + byte[] data = (getClass().getName() + "#" + getCurrentTestName() + "[" + localFile + "]").getBytes(StandardCharsets.UTF_8); + Files.write(localFile, data, StandardOpenOption.CREATE); + try (ClientSession session = client.connect(getCurrentTestName(), TEST_LOCALHOST, port).verify(7L, TimeUnit.SECONDS).getSession()) { + session.addPasswordIdentity(getCurrentTestName()); + session.auth().verify(5L, TimeUnit.SECONDS); + + try (SftpClient sftp = session.createSftpClient(); + InputStream stream = sftp.read(Utils.resolveRelativeRemotePath(parentPath, localFile), OpenMode.Read)) { + assertFalse("Stream reported mark supported", stream.markSupported()); + try { + stream.mark(data.length); + fail("Unexpected success to mark the read limit"); + } catch (UnsupportedOperationException e) { + // expected - ignored + } + + byte[] expected = new byte[data.length / 4]; + int readLen = stream.read(expected); + assertEquals("Failed to read fully initial data", expected.length, readLen); + + byte[] actual = new byte[readLen]; + stream.reset(); + readLen = stream.read(actual); + assertEquals("Failed to read fully reset data", actual.length, readLen); + assertArrayEquals("Mismatched re-read data contents", expected, actual); + + System.arraycopy(data, 0, expected, 0, expected.length); + assertArrayEquals("Mismatched original data contents", expected, actual); + + long skipped = stream.skip(readLen); + assertEquals("Mismatched skipped forward size", readLen, skipped); + + readLen = stream.read(actual); + assertEquals("Failed to read fully skipped forward data", actual.length, readLen); + + System.arraycopy(data, expected.length + readLen, expected, 0, expected.length); + assertArrayEquals("Mismatched skipped forward data contents", expected, actual); + + skipped = stream.skip(0 - readLen); + assertEquals("Mismatched backward skip size", readLen, skipped); + readLen = stream.read(actual); + assertEquals("Failed to read fully skipped backward data", actual.length, readLen); + assertArrayEquals("Mismatched skipped backward data contents", expected, actual); + } + } + } + + @Test @SuppressWarnings({"checkstyle:anoninnerlength", "checkstyle:methodlength"}) public void testClient() throws Exception { List<NamedFactory<Command>> factories = sshd.getSubsystemFactories();
