Author: gnodet
Date: Mon May 21 11:41:46 2012
New Revision: 1340976
URL: http://svn.apache.org/viewvc?rev=1340976&view=rev
Log:
[SSHD-120] Listing lots of files in a directory through SFTP does not work with
some clients
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=1340976&r1=1340975&r2=1340976&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
Mon May 21 11:41:46 2012
@@ -63,7 +63,7 @@ public class SftpSubsystem implements Co
public static final int LOWER_SFTP_IMPL = 3; // Working implementation
from v3
public static final int HIGHER_SFTP_IMPL = 3; // .. up to
public static final String ALL_SFTP_IMPL = "3";
-
+ public static final int MAX_PACKET_LENGTH = 1024 * 16;
public static final int SSH_FXP_INIT = 1;
public static final int SSH_FXP_VERSION = 2;
@@ -249,11 +249,16 @@ public class SftpSubsystem implements Co
}
- protected static class DirectoryHandle extends Handle {
+ protected static class DirectoryHandle extends Handle implements
Iterator<SshFile> {
boolean done;
+ // the directory should be read once at "open directory"
+ List<SshFile> fileList = null;
+ int fileIndex;
public DirectoryHandle(SshFile file) {
super(file);
+ fileList = file.listSshFiles();
+ fileIndex = 0;
}
public boolean isDone() {
@@ -263,6 +268,25 @@ public class SftpSubsystem implements Co
public void setDone(boolean done) {
this.done = done;
}
+
+ public boolean hasNext() {
+ return fileIndex < fileList.size();
+ }
+
+ public SshFile next() {
+ SshFile f = fileList.get(fileIndex);
+ fileIndex++;
+ return f;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void clearFileList() {
+ // allow the garbage collector to do the job
+ fileList = null;
+ }
}
protected static class FileHandle extends Handle {
@@ -665,8 +689,23 @@ public class SftpSubsystem implements Co
} else if (!p.getFile().isReadable()) {
sendStatus(id, SSH_FX_PERMISSION_DENIED,
p.getFile().getAbsolutePath());
} else {
- sendName(id, p.getFile().listSshFiles());
- ((DirectoryHandle) p).setDone(true);
+ DirectoryHandle dh = (DirectoryHandle) p;
+ if (dh.hasNext()) {
+ // There is at least one file in the directory.
+ // Send only a few files at a time to not create
packets of a too
+ // large size or have a timeout to occur.
+ sendName(id, dh);
+ if (!dh.hasNext()) {
+ // if no more files to send
+ dh.setDone(true);
+ dh.clearFileList();
+ }
+ } else {
+ // empty directory
+ dh.setDone(true);
+ dh.clearFileList();
+ sendStatus(id, SSH_FX_EOF, "", "");
+ }
}
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
@@ -846,12 +885,15 @@ public class SftpSubsystem implements Co
send(buffer);
}
- protected void sendName(int id, Collection<SshFile> files) throws
IOException {
+ protected void sendName(int id, Iterator<SshFile> files) throws
IOException {
Buffer buffer = new Buffer();
buffer.putByte((byte) SSH_FXP_NAME);
buffer.putInt(id);
- buffer.putInt(files.size());
- for (SshFile f : files) {
+ int wpos = buffer.wpos();
+ buffer.putInt(0);
+ int nb = 0;
+ while (files.hasNext() && buffer.wpos() < MAX_PACKET_LENGTH) {
+ SshFile f = files.next();
buffer.putString(f.getName());
if (version <= 3) {
buffer.putString(getLongName(f)); // Format specified in the
specs
@@ -859,7 +901,12 @@ public class SftpSubsystem implements Co
buffer.putString(f.getName()); // Supposed to be UTF-8
}
writeAttrs(buffer, f);
+ nb++;
}
+ int oldpos = buffer.wpos();
+ buffer.wpos(wpos);
+ buffer.putInt(nb);
+ buffer.wpos(oldpos);
send(buffer);
}
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=1340976&r1=1340975&r2=1340976&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 Mon
May 21 11:41:46 2012
@@ -25,6 +25,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.util.Arrays;
+import java.util.Vector;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
@@ -172,6 +173,16 @@ public class SftpTest {
root.delete();
}
+ @Test
+ public void testReadDir() throws Exception {
+ ChannelSftp c = (ChannelSftp) session.openChannel("sftp");
+ c.connect();
+ Vector res = c.ls("target/classes/org/apache/sshd/");
+ for (Object f : res) {
+ System.out.println(f.toString());
+ }
+ }
+
protected void assertFileLength(File file, long length, long timeout)
throws Exception {
boolean ok = false;
while (timeout > 0) {