Greg Watson
2015-10-09 14:24:16 UTC
I’m using 0.1.53 and recently came across the following problem. As a background, the SFTP protocol uses a command-response mechanism for communication between the client and server. It does not put any restrictions on the interleaving of commands, as each command is issued with a request ID number that is meant to be used to match to the corresponding reply. However the JSch implementation does not use the request ID for some commands (such as lstat()) so interleaving commands results in invalid responses.
Here’s an example:
InputStream in = sftpChannel.get(“/path/to/file");
byte[] b = new byte[100];
int n = in.read(b);
sftpChannel.lstat(“/path/to/another/file”);
At this point, lstat() throws an SftpException with message “End of file”.
The operation of this code is as follows. First, the call to get() results in an SSH_FXP_OPEN being sent to the server, along with the corresponding reply containing the file handle. The in.read(b) then causes JSch to issue an SSH_FXP_READ command, which for small files will read the whole file contents. The in.read(b) will return with the first 100 bytes at this point. Next, because the server is version 3, the only way to determine end of file is to issue another SSH_FXP_READ to see if the end of file has been reached. Since it has (the first READ read the whole file), the server returns a result of SSH_FXP_STATUS with error code SSH_FX_EOF, but this is not read by JSch yet. Now the call to lstat() sends a SSH_FXP_LSTAT command to the server. Because the server previously replied with an SSH_FXP_STATUS, and JSch does not check the request ID, it thinks the SSH_FXP_STATUS reply is the result of the SSH_FXP_LSTAT command. At this point lstat() fails with “End of file”.
To verify this is what is happening, insert “in.close()” between the read() and the lstat(). This flushes the last SSH_FXP_STATUS, so the response to the LSTAT command is correctly interpreted.
The only work around for this problem currently is to close all streams before issuing any other commands, or use a second sftp channel to issue interleaved commands.
Although this would not affect a command-line implementation of an sftp client (since interleaved commands are not possible), it does prevent JSch from fully utilizing the SFTP protocol.
Regards,
Greg
------------------------------------------------------------------------------
Here’s an example:
InputStream in = sftpChannel.get(“/path/to/file");
byte[] b = new byte[100];
int n = in.read(b);
sftpChannel.lstat(“/path/to/another/file”);
At this point, lstat() throws an SftpException with message “End of file”.
The operation of this code is as follows. First, the call to get() results in an SSH_FXP_OPEN being sent to the server, along with the corresponding reply containing the file handle. The in.read(b) then causes JSch to issue an SSH_FXP_READ command, which for small files will read the whole file contents. The in.read(b) will return with the first 100 bytes at this point. Next, because the server is version 3, the only way to determine end of file is to issue another SSH_FXP_READ to see if the end of file has been reached. Since it has (the first READ read the whole file), the server returns a result of SSH_FXP_STATUS with error code SSH_FX_EOF, but this is not read by JSch yet. Now the call to lstat() sends a SSH_FXP_LSTAT command to the server. Because the server previously replied with an SSH_FXP_STATUS, and JSch does not check the request ID, it thinks the SSH_FXP_STATUS reply is the result of the SSH_FXP_LSTAT command. At this point lstat() fails with “End of file”.
To verify this is what is happening, insert “in.close()” between the read() and the lstat(). This flushes the last SSH_FXP_STATUS, so the response to the LSTAT command is correctly interpreted.
The only work around for this problem currently is to close all streams before issuing any other commands, or use a second sftp channel to issue interleaved commands.
Although this would not affect a command-line implementation of an sftp client (since interleaved commands are not possible), it does prevent JSch from fully utilizing the SFTP protocol.
Regards,
Greg
------------------------------------------------------------------------------