You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2011/08/30 19:40:22 UTC
svn commit: r1163306 - in /mina/sshd/trunk/sshd-core/src:
main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
test/java/org/apache/sshd/SftpTest.java
Author: gnodet
Date: Tue Aug 30 17:40:22 2011
New Revision: 1163306
URL: http://svn.apache.org/viewvc?rev=1163306&view=rev
Log:
[SSHD-135] Improve performance of SFTP transfers
Modified:
mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/SftpTest.java
Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java?rev=1163306&r1=1163305&r2=1163306&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java Tue Aug 30 17:40:22 2011
@@ -23,6 +23,7 @@ import java.util.*;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.util.Buffer;
+import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.SelectorUtils;
import org.apache.sshd.server.*;
import org.apache.sshd.server.FileSystemView;
@@ -266,6 +267,10 @@ public class SftpSubsystem implements Co
protected static class FileHandle extends Handle {
int flags;
+ OutputStream output;
+ long outputPos;
+ InputStream input;
+ long inputPos;
public FileHandle(SshFile sshFile, int flags) {
super(sshFile);
@@ -275,6 +280,40 @@ public class SftpSubsystem implements Co
public int getFlags() {
return flags;
}
+
+ public int read(byte[] data, long offset) throws IOException {
+ if (input != null && offset != inputPos) {
+ IoUtils.closeQuietly(input);
+ input = null;
+ }
+ if (input == null) {
+ input = file.createInputStream(offset);
+ inputPos = offset;
+ }
+ int read = input.read(data);
+ inputPos += read;
+ return read;
+ }
+
+ public void write(byte[] data, long offset) throws IOException {
+ if (output != null && offset != outputPos) {
+ IoUtils.closeQuietly(output);
+ output = null;
+ }
+ if (output == null) {
+ output = file.createOutputStream(offset);
+ }
+ output.write(data);
+ outputPos += data.length;
+ }
+
+ @Override
+ public void close() throws IOException {
+ IoUtils.closeQuietly(output, input);
+ output = null;
+ input = null;
+ super.close();
+ }
}
public SftpSubsystem() {}
@@ -519,27 +558,20 @@ public class SftpSubsystem implements Co
if (!(p instanceof FileHandle)) {
sendStatus(id, SSH_FX_INVALID_HANDLE, handle);
} else {
- SshFile ssh = ((FileHandle) p).getFile();
- InputStream is = ssh.createInputStream(offset);
- try {
- byte[] b = new byte[Math.min(len, 1024 * 32)];
- len = is.read(b);
- if (len >= 0) {
- Buffer buf = new Buffer(len + 5);
- buf.putByte((byte) SSH_FXP_DATA);
- buf.putInt(id);
- buf.putBytes(b, 0, len);
- if (version >= 6) {
- buf.putBoolean(len == 0);
- }
- send(buf);
- } else {
- sendStatus(id, SSH_FX_EOF, "");
- }
- } finally {
- if (is != null) {
- is.close();
+ FileHandle fh = (FileHandle) p;
+ byte[] b = new byte[Math.min(len, 1024 * 32)];
+ len = fh.read(b, offset);
+ if (len >= 0) {
+ Buffer buf = new Buffer(len + 5);
+ buf.putByte((byte) SSH_FXP_DATA);
+ buf.putInt(id);
+ buf.putBytes(b, 0, len);
+ if (version >= 6) {
+ buf.putBoolean(len == 0);
}
+ send(buf);
+ } else {
+ sendStatus(id, SSH_FX_EOF, "");
}
}
} catch (IOException e) {
@@ -556,16 +588,9 @@ public class SftpSubsystem implements Co
if (!(p instanceof FileHandle)) {
sendStatus(id, SSH_FX_INVALID_HANDLE, handle);
} else {
- SshFile sshFile = ((FileHandle) p).getFile();
- OutputStream os = sshFile.createOutputStream(offset);
-
- try {
- os.write(data); // TODO: handle append flags
- } finally {
- if (os != null) {
- os.close();
- }
- }
+ FileHandle fh = (FileHandle) p;
+ fh.write(data, offset);
+ SshFile sshFile = fh.getFile();
sshFile.setLastModified(new Date().getTime());
Modified: mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/SftpTest.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/SftpTest.java?rev=1163306&r1=1163305&r2=1163306&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/SftpTest.java (original)
+++ mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/SftpTest.java Tue Aug 30 17:40:22 2011
@@ -22,25 +22,29 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
+import java.io.OutputStream;
import java.net.ServerSocket;
-import java.util.ArrayList;
import java.util.Arrays;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.server.Command;
-import org.apache.sshd.server.sftp.SftpSubsystem;
-import org.junit.*;
-
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Logger;
import com.jcraft.jsch.UserInfo;
+import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
+import org.apache.sshd.server.Command;
import org.apache.sshd.server.command.ScpCommandFactory;
+import org.apache.sshd.server.sftp.SftpSubsystem;
import org.apache.sshd.util.BogusPasswordAuthenticator;
import org.apache.sshd.util.EchoShellFactory;
-
-import static org.junit.Assert.*;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
public class SftpTest {
@@ -140,6 +144,33 @@ public class SftpTest {
root.delete();
}
+ @Test
+ public void testReadWriteWithOffset() throws Exception {
+ File root = new File("target/scp");
+ File target = new File("target/scp/out.txt");
+ root.mkdirs();
+ assertTrue(root.exists());
+
+ ChannelSftp c = (ChannelSftp) session.openChannel("sftp");
+ c.connect();
+ c.put(new ByteArrayInputStream("0123456789".getBytes()), target.getPath());
+
+ assertTrue(target.exists());
+ assertEquals("0123456789", readFile("target/scp/out.txt"));
+
+ OutputStream os = c.put(target.getPath(), null, ChannelSftp.APPEND, -5);
+ os.write("a".getBytes());
+ os.close();
+ c.disconnect();
+
+ assertTrue(target.exists());
+ assertEquals("01234a", readFile("target/scp/out.txt"));
+
+ target.delete();
+ assertFalse(target.exists());
+ root.delete();
+ }
+
protected void assertFileLength(File file, long length, long timeout) throws Exception {
boolean ok = false;
while (timeout > 0) {