removed some more libssh2_ prefixes from private functions
Made the libssh2_sftp_open_ex() deal with servers that first responds with STATUS OK and then sends the actual HANDLE. It seems openssh does this at times and it screwed things up. To me it seems like a spec violation...
This commit is contained in:
parent
197a26ef8c
commit
2535c5c2ee
106
src/sftp.c
106
src/sftp.c
@ -82,18 +82,18 @@
|
||||
/* S_IFDIR */
|
||||
#define LIBSSH2_SFTP_ATTR_PFILETYPE_DIR 0040000
|
||||
|
||||
/* {{{ libssh2_sftp_packet_add
|
||||
/* {{{ sftp_packet_add
|
||||
* Add a packet to the SFTP packet brigade
|
||||
*/
|
||||
static int
|
||||
libssh2_sftp_packet_add(LIBSSH2_SFTP * sftp, unsigned char *data,
|
||||
sftp_packet_add(LIBSSH2_SFTP * sftp, unsigned char *data,
|
||||
unsigned long data_len)
|
||||
{
|
||||
LIBSSH2_SESSION *session = sftp->channel->session;
|
||||
LIBSSH2_PACKET *packet;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Received packet %d",
|
||||
(int) data[0]);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Received packet %d (len %d)",
|
||||
(int) data[0], data_len);
|
||||
packet = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
@ -139,16 +139,24 @@ sftp_packet_read(LIBSSH2_SFTP * sftp)
|
||||
|
||||
/* If there was a previous partial, start using it */
|
||||
if (sftp->partial_packet) {
|
||||
|
||||
packet = sftp->partial_packet;
|
||||
packet_len = sftp->partial_len;
|
||||
packet_received = sftp->partial_received;
|
||||
sftp->partial_packet = NULL;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
|
||||
"partial read cont, len: %lu", packet_len);
|
||||
}
|
||||
else {
|
||||
rc = libssh2_channel_read_ex(channel, 0, (char *) buffer, 4);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
} else if (4 != rc) {
|
||||
}
|
||||
else if (4 != rc) {
|
||||
/* TODO: this is stupid since we can in fact get 1-3 bytes in a
|
||||
legitimate working case as well if the connection happens to be
|
||||
super slow or something */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
"Timeout waiting for FXP packet", 0);
|
||||
return -1;
|
||||
@ -201,7 +209,7 @@ sftp_packet_read(LIBSSH2_SFTP * sftp)
|
||||
packet_received += bytes_received;
|
||||
}
|
||||
|
||||
if (libssh2_sftp_packet_add(sftp, packet, packet_len)) {
|
||||
if (sftp_packet_add(sftp, packet, packet_len)) {
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
@ -211,11 +219,11 @@ sftp_packet_read(LIBSSH2_SFTP * sftp)
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_sftp_packet_ask
|
||||
/* {{{ sftp_packet_ask
|
||||
* A la libssh2_packet_ask()
|
||||
*/
|
||||
static int
|
||||
libssh2_sftp_packet_ask(LIBSSH2_SFTP * sftp, unsigned char packet_type,
|
||||
sftp_packet_ask(LIBSSH2_SFTP * sftp, unsigned char packet_type,
|
||||
unsigned long request_id, unsigned char **data,
|
||||
unsigned long *data_len, int poll_channel)
|
||||
{
|
||||
@ -271,11 +279,11 @@ libssh2_sftp_packet_ask(LIBSSH2_SFTP * sftp, unsigned char packet_type,
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_sftp_packet_require
|
||||
/* {{{ sftp_packet_require
|
||||
* A la libssh2_packet_require
|
||||
*/
|
||||
static int
|
||||
libssh2_sftp_packet_require(LIBSSH2_SFTP * sftp, unsigned char packet_type,
|
||||
sftp_packet_require(LIBSSH2_SFTP * sftp, unsigned char packet_type,
|
||||
unsigned long request_id, unsigned char **data,
|
||||
unsigned long *data_len)
|
||||
{
|
||||
@ -285,8 +293,8 @@ libssh2_sftp_packet_require(LIBSSH2_SFTP * sftp, unsigned char packet_type,
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Requiring %d packet",
|
||||
(int) packet_type);
|
||||
|
||||
if (libssh2_sftp_packet_ask
|
||||
(sftp, packet_type, request_id, data, data_len, 0) == 0) {
|
||||
if (sftp_packet_ask(sftp, packet_type, request_id, data,
|
||||
data_len, 0) == 0) {
|
||||
/* The right packet was available in the packet brigade */
|
||||
return 0;
|
||||
}
|
||||
@ -301,7 +309,7 @@ libssh2_sftp_packet_require(LIBSSH2_SFTP * sftp, unsigned char packet_type,
|
||||
|
||||
if (packet_type == ret) {
|
||||
/* Be lazy, let packet_ask pull it out of the brigade */
|
||||
return libssh2_sftp_packet_ask(sftp, packet_type, request_id, data,
|
||||
return sftp_packet_ask(sftp, packet_type, request_id, data,
|
||||
data_len, 0);
|
||||
}
|
||||
}
|
||||
@ -313,7 +321,7 @@ libssh2_sftp_packet_require(LIBSSH2_SFTP * sftp, unsigned char packet_type,
|
||||
/* }}} */
|
||||
|
||||
/* {{{ sftp_packet_requirev
|
||||
* Requie one of N possible reponses
|
||||
* Require one of N possible reponses
|
||||
*/
|
||||
static int
|
||||
sftp_packet_requirev(LIBSSH2_SFTP * sftp, int num_valid_responses,
|
||||
@ -331,7 +339,7 @@ sftp_packet_requirev(LIBSSH2_SFTP * sftp, int num_valid_responses,
|
||||
|
||||
while (sftp->channel->session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
|
||||
for(i = 0; i < num_valid_responses; i++) {
|
||||
if (libssh2_sftp_packet_ask(sftp, valid_responses[i], request_id,
|
||||
if (sftp_packet_ask(sftp, valid_responses[i], request_id,
|
||||
data, data_len, 0) == 0) {
|
||||
/*
|
||||
* Set to zero before all returns to say
|
||||
@ -633,7 +641,7 @@ libssh2_sftp_init(LIBSSH2_SESSION * session)
|
||||
}
|
||||
|
||||
/* For initiallization we are requiring blocking, probably reasonable */
|
||||
rc = libssh2_sftp_packet_require(session->sftpInit_sftp, SSH_FXP_VERSION,
|
||||
rc = sftp_packet_require(session->sftpInit_sftp, SSH_FXP_VERSION,
|
||||
0, &data, &data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
@ -788,7 +796,8 @@ libssh2_sftp_open_ex(LIBSSH2_SFTP * sftp, const char *filename,
|
||||
int rc;
|
||||
|
||||
if (sftp->open_state == libssh2_NB_state_idle) {
|
||||
/* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) + flags(4) */
|
||||
/* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) +
|
||||
flags(4) */
|
||||
sftp->open_packet_len = filename_len + 13 +
|
||||
((open_type ==
|
||||
LIBSSH2_SFTP_OPENFILE) ? (4 +
|
||||
@ -797,7 +806,8 @@ libssh2_sftp_open_ex(LIBSSH2_SFTP * sftp, const char *filename,
|
||||
s = sftp->open_packet = LIBSSH2_ALLOC(session, sftp->open_packet_len);
|
||||
if (!sftp->open_packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for FXP_OPEN or FXP_OPENDIR packet",
|
||||
"Unable to allocate memory for FXP_OPEN or "
|
||||
"FXP_OPENDIR packet",
|
||||
0);
|
||||
return NULL;
|
||||
}
|
||||
@ -840,7 +850,11 @@ libssh2_sftp_open_ex(LIBSSH2_SFTP * sftp, const char *filename,
|
||||
"Would block sending FXP_OPEN or FXP_OPENDIR command",
|
||||
0);
|
||||
return NULL;
|
||||
} else if (sftp->open_packet_len != rc) {
|
||||
}
|
||||
else if (sftp->open_packet_len != rc) {
|
||||
/* TODO: partial writes should be fine too and is not a sign of
|
||||
an error when in non-blocking mode! */
|
||||
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send FXP_OPEN or FXP_OPENDIR command", 0);
|
||||
LIBSSH2_FREE(session, sftp->open_packet);
|
||||
@ -862,7 +876,8 @@ libssh2_sftp_open_ex(LIBSSH2_SFTP * sftp, const char *filename,
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block waiting for status message", 0);
|
||||
return NULL;
|
||||
} else if (rc) {
|
||||
}
|
||||
else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
"Timeout waiting for status message", 0);
|
||||
sftp->open_state = libssh2_NB_state_idle;
|
||||
@ -872,13 +887,39 @@ libssh2_sftp_open_ex(LIBSSH2_SFTP * sftp, const char *filename,
|
||||
|
||||
sftp->open_state = libssh2_NB_state_idle;
|
||||
|
||||
/* OPEN can basically get STATUS or HANDLE back, where HANDLE implies a
|
||||
fine response while STATUS means error. It seems though that at times
|
||||
we get an SSH_FX_OK back in a STATUS, followed the "real" HANDLE so
|
||||
we need to properly deal with that. */
|
||||
if (data[0] == SSH_FXP_STATUS) {
|
||||
int badness = 1;
|
||||
sftp->last_errno = libssh2_ntohu32(data + 5);
|
||||
|
||||
if(LIBSSH2_FX_OK == sftp->last_errno) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "got HANDLE FXOK!");
|
||||
|
||||
/* silly situation, but check for a HANDLE */
|
||||
rc = sftp_packet_require(sftp, SSH_FXP_HANDLE,
|
||||
sftp->open_request_id, &data, &data_len);
|
||||
if(rc == PACKET_EAGAIN) {
|
||||
/* go back to sent state and wait for something else */
|
||||
sftp->open_state = libssh2_NB_state_sent;
|
||||
return NULL;
|
||||
}
|
||||
else if(!rc)
|
||||
/* we got the handle so this is not a bad situation */
|
||||
badness = 0;
|
||||
}
|
||||
|
||||
if(badness) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
|
||||
"Failed opening remote file", 0);
|
||||
sftp->last_errno = libssh2_ntohu32(data + 5);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "got FXP_STATUS %d",
|
||||
sftp->last_errno);
|
||||
LIBSSH2_FREE(session, data);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
fp = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP_HANDLE));
|
||||
if (!fp) {
|
||||
@ -935,7 +976,8 @@ libssh2_sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned long data_len, request_id = 0;
|
||||
/* 25 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) + offset(8) + length(4) */
|
||||
/* 25 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) +
|
||||
offset(8) + length(4) */
|
||||
ssize_t packet_len = handle->handle_len + 25;
|
||||
unsigned char *packet, *s, *data;
|
||||
static const unsigned char read_responses[2] =
|
||||
@ -970,7 +1012,8 @@ libssh2_sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
|
||||
* So we request data by pieces.
|
||||
*/
|
||||
bytes_requested = buffer_maxlen - total_read;
|
||||
/* 10 = packet_type(1)+request_id(4)+data_length(4)+end_of_line_flag(1) */
|
||||
/* 10 = packet_type(1) + request_id(4) + data_length(4) +
|
||||
end_of_line_flag(1) */
|
||||
if (bytes_requested > LIBSSH2_SFTP_PACKET_MAXLEN - 10) {
|
||||
bytes_requested = LIBSSH2_SFTP_PACKET_MAXLEN - 10;
|
||||
}
|
||||
@ -1012,6 +1055,8 @@ libssh2_sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
|
||||
sftp->read_total_read = total_read;
|
||||
return PACKET_EAGAIN;
|
||||
} else if (packet_len != retcode) {
|
||||
/* TODO: a partial write is not a critical error when in
|
||||
non-blocking mode! */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send FXP_READ command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
@ -1359,7 +1404,7 @@ libssh2_sftp_write(LIBSSH2_SFTP_HANDLE * handle, const char *buffer,
|
||||
sftp->write_state = libssh2_NB_state_sent;
|
||||
}
|
||||
|
||||
rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS,
|
||||
rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
|
||||
sftp->write_request_id, &data, &data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
@ -1585,7 +1630,7 @@ libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE * handle)
|
||||
}
|
||||
|
||||
if (handle->close_state == libssh2_NB_state_sent) {
|
||||
rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS,
|
||||
rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
|
||||
handle->close_request_id, &data,
|
||||
&data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
@ -1696,12 +1741,13 @@ libssh2_sftp_unlink_ex(LIBSSH2_SFTP * sftp, const char *filename,
|
||||
sftp->unlink_state = libssh2_NB_state_sent;
|
||||
}
|
||||
|
||||
rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS,
|
||||
rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
|
||||
sftp->unlink_request_id, &data,
|
||||
&data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
} else if (rc) {
|
||||
}
|
||||
else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
"Timeout waiting for status message", 0);
|
||||
sftp->unlink_state = libssh2_NB_state_idle;
|
||||
@ -1805,7 +1851,7 @@ libssh2_sftp_rename_ex(LIBSSH2_SFTP * sftp, const char *source_filename,
|
||||
sftp->rename_state = libssh2_NB_state_sent;
|
||||
}
|
||||
|
||||
rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS,
|
||||
rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
|
||||
sftp->rename_request_id, &data,
|
||||
&data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
@ -1921,7 +1967,7 @@ libssh2_sftp_mkdir_ex(LIBSSH2_SFTP * sftp, const char *path,
|
||||
sftp->mkdir_packet = NULL;
|
||||
}
|
||||
|
||||
rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data,
|
||||
rc = sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data,
|
||||
&data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
@ -2008,7 +2054,7 @@ libssh2_sftp_rmdir_ex(LIBSSH2_SFTP * sftp, const char *path,
|
||||
sftp->rmdir_state = libssh2_NB_state_sent;
|
||||
}
|
||||
|
||||
rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS,
|
||||
rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
|
||||
sftp->rmdir_request_id, &data, &data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
|
Loading…
x
Reference in New Issue
Block a user